Ethereal-dev: [ethereal-dev] Packet-smb patch

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

From: Mike Hancher <Hanchman@xxxxxxx>
Date: Thu, 18 Nov 1999 16:53:16 -0500
    I patched Packet-smb.c to handle UNICODED data and UNICODE offset
padding, fixed a problem with the password length display in the hex
box, added ASCII text display fields for the PARAMETERS and DATA fields
and added a label to the SERVICE field identifying the type of service.

    Can anyone provice me with a breakdown or documentation of the
PARAMETERS fields.



--

.---------------------------------------------------------------------------------------

     Hear something and it will be forgotten
     See something and it will be remembered

          Mike Hancher

     Email : Hanchman@xxxxxxx
     Homepage: http://www.qis.net/~hanchman

----------------------------------------------------------------------------------------


? patchsmb3.txt
? my.patch
? smb-patch.txt
? patchsmb.txt
? patchsmb2.txt
Index: packet-smb.c
===================================================================
RCS file: /cvsroot/ethereal/packet-smb.c,v
retrieving revision 1.43
diff -u -r1.43 packet-smb.c
--- packet-smb.c	1999/11/18 07:32:46	1.43
+++ packet-smb.c	1999/11/18 17:57:11
@@ -48,7 +48,10 @@
 #include "alignment.h"
 
 static int proto_smb = -1;
+static int Cap_Offset = 113;     /* offset into the packet of the Capabilities flags */
+static int Flags2_Offset=68;     /* offset into the packet of the Flags2 settings */
 
+
 static gint ett_smb = -1;
 static gint ett_smb_fileattributes = -1;
 static gint ett_smb_capabilities = -1;
@@ -432,7 +435,6 @@
 void 
 dissect_unknown_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)
 {
-
   if (tree) {
 
     proto_tree_add_text(tree, offset, END_OF_FRAME, "Data (%u bytes)", 
@@ -550,6 +552,34 @@
   return cur;
 }
 
+
+   /* lookup the service requested. */
+static gchar *
+lookup_service_description(const guint8 *str) {
+
+   gchar  *str2;
+
+   str2="";
+   if (strcmp(str,"A:")==0) {
+       str2 = "Disk Share";
+   }
+   else if (strcmp(str,"LPT1:")==0) {
+       str2 = "Printer";
+   }
+   else if (strcmp(str,"IPC")==0) {
+       str2 = "Named Pipe";
+   }
+   else if (strcmp(str,"COMM")==0) {
+       str2 = "Communications Device";
+   }
+   else if (strcmp(str,"?????")==0) {
+       str2 = "Any Type of Device";
+   }
+  return str2;
+}
+
+
+
 /*
  * Each dissect routine is passed an offset to wct and works from there 
  */
@@ -1772,11 +1802,11 @@
 
     if (tree) {
 
-      proto_tree_add_text(tree, offset, strlen(Password) + 1, "Password: %s", Password);
+      proto_tree_add_text(tree, offset, strlen(Password), "Password: %s", Password);
 
     }
 
-    offset += strlen(Password) + 1; /* Skip Password */
+    offset += strlen(Password); /* Skip Password */
 
     /* Build display for: BufferFormat3 */
 
@@ -1797,6 +1827,7 @@
     if (tree) {
 
       proto_tree_add_text(tree, offset, strlen(Service) + 1, "Service: %s", Service);
+      proto_tree_add_text(tree, offset, strlen(Service) + 1, "Service Description: %s",lookup_service_description(Service));
 
     }
 
@@ -1870,6 +1901,7 @@
   guint8        WordCount;
   guint8        AndXReserved;
   guint8        AndXCommand = 0xFF;
+  guint8        Pad1;
   guint32       SessionKey;
   guint32       Reserved;
   guint32       Capabilities;
@@ -1891,6 +1923,15 @@
   const char    *AccountName;
   const char    *ANSIPassword;
 
+  guint16       Flags2;
+  char          *passstr;
+  char          *ustr;
+  int           ustr_len;
+
+  /* obtain the Flags2 settings */
+  Flags2 = GSHORT(pd, Flags2_Offset);
+
+
   if (dirn == 1) { /* Request(s) dissect code */
 
     WordCount = GBYTE(pd, offset);
@@ -2039,9 +2080,11 @@
         Password = pd + offset;
 
 	if (tree) {
-
-	  proto_tree_add_text(tree, offset, strlen(Password) + 1, "Password: %s", Password);
-
+          passstr=g_malloc(PasswordLen+1);
+          strncpy(passstr, Password, PasswordLen);
+          passstr[PasswordLen+1]='\0';
+          proto_tree_add_text(tree, offset, PasswordLen, "Password: %s", passstr);
+          g_free(passstr);
 	}
 
 	offset += PasswordLen;
@@ -2293,9 +2336,11 @@
 	ANSIPassword = pd + offset;
 
 	if (tree) {
-
-	  proto_tree_add_text(tree, offset, strlen(ANSIPassword) + 1, "ANSI Password: %s", ANSIPassword);
-
+          passstr=g_malloc(ANSIAccountPasswordLength+1);
+          strncpy(passstr, ANSIPassword, ANSIAccountPasswordLength);
+          passstr[ANSIAccountPasswordLength+1]='\0';
+          proto_tree_add_text(tree, offset, ANSIAccountPasswordLength, "ANSI Password: %s", passstr);
+          g_free(passstr);
 	}
 
 	offset += ANSIAccountPasswordLength; /* Skip ANSI Password */
@@ -2308,62 +2353,112 @@
 	if (UNICODEAccountPasswordLength > 0) {
 
 	  if (tree) {
-
-	    proto_tree_add_text(tree, offset, strlen(UNICODEPassword) + 1, "UNICODE Password: %s", UNICODEPassword);
-
+            passstr=g_malloc(UNICODEAccountPasswordLength+1);
+            strncpy(passstr, UNICODEPassword, UNICODEAccountPasswordLength);
+            passstr[UNICODEAccountPasswordLength+1]='\0';
+            proto_tree_add_text(tree, offset, UNICODEAccountPasswordLength, "UNICODE Password: %s", passstr);
+            g_free(passstr);
 	  }
 
-	  offset += strlen(UNICODEPassword) + 1; /* Skip UNICODE Password */
+	  offset += UNICODEAccountPasswordLength; /* Skip UNICODE Password */
 
 	}
-
-	/* Build display for: Account Name */
-
-	AccountName = pd + offset;
-
-	if (tree) {
-
-	  proto_tree_add_text(tree, offset, strlen(AccountName) + 1, "Account Name: %s", AccountName);
-
-	}
-
-	offset += strlen(AccountName) + 1; /* Skip Account Name */
-
-	/* Build display for: Primary Domain */
-
-	PrimaryDomain = pd + offset;
-
-	if (tree) {
-
-	  proto_tree_add_text(tree, offset, strlen(PrimaryDomain) + 1, "Primary Domain: %s", PrimaryDomain);
-
-	}
-
-	offset += strlen(PrimaryDomain) + 1; /* Skip Primary Domain */
-
-	/* Build display for: Native OS */
-
-	NativeOS = pd + offset;
-
-	if (tree) {
-
-	  proto_tree_add_text(tree, offset, strlen(NativeOS) + 1, "Native OS: %s", NativeOS);
-
-	}
-
-	offset += strlen(NativeOS) + 1; /* Skip Native OS */
-
-	/* Build display for: Native LanMan Type */
-
-	NativeLanManType = pd + offset;
-
-	if (tree) {
-
-	  proto_tree_add_text(tree, offset, strlen(NativeLanManType) + 1, "Native LanMan Type: %s", NativeLanManType);
 
-	}
+        if (Capabilities & 0x0004) {
+          if (offset % 2) {
 
-	offset += strlen(NativeLanManType) + 1; /* Skip Native LanMan Type */
+          /* Build display for: Pad1 */
+          /* Need to pad out because of Unicode strings start on a
+             even boundary                                         */
+
+             Pad1 = GBYTE(pd, offset);
+             if (tree) {
+                proto_tree_add_text(tree, offset, 1, "Pad1: %u", Pad1);
+
+             }
+             offset += 1;
+          }
+        }
+
+        /* Build display for: Account Name */
+
+        /* The AccountName, a null terminated string; Unicode if "caps" has
+           the 0x0004 bit set, ASCII (OEM character set) otherwise.
+           XXX - for now, we just handle the ISO 8859-1 subset of Unicode. */
+
+        AccountName = pd + offset;
+        if (tree) {
+          if (Capabilities & 0x0004) {
+            ustr = unicode_to_str(AccountName, &ustr_len);
+            proto_tree_add_text(tree, offset, ustr_len+2, "Account Name: %s", ustr);
+            offset += (strlen(ustr)*2) + 2; /* Skip Account Name */
+          } else {
+            proto_tree_add_text(tree, offset, strlen(AccountName) + 1, "Account Name: %s", AccountName);
+            offset += strlen(AccountName) + 1; /* Skip Account Name */
+          }
+        }
+
+
+        /* Build display for: Primary Domain */
+
+        /* The Primary Domain, a null terminated string; Unicode if "caps" has
+           the 0x0004 bit set, ASCII (OEM character set) otherwise.
+           XXX - for now, we just handle the ISO 8859-1 subset of Unicode. */
+
+          PrimaryDomain = pd + offset;
+
+        if (tree) {
+          if (Capabilities & 0x0004) {
+            ustr = unicode_to_str(PrimaryDomain, &ustr_len);
+            proto_tree_add_text(tree, offset, ustr_len+2, "Primary Domain: %s", ustr);
+            offset += (strlen(ustr)*2) + 2; /* Skip Primary Domain */
+          } else {
+            proto_tree_add_text(tree, offset, strlen(PrimaryDomain) + 1, "Primary Domain: %s", PrimaryDomain);
+            offset += strlen(PrimaryDomain) + 1; /* Skip Primary Domain */
+          }
+        }
+
+
+        /* Build display for: Native OS */
+
+        /* The NativeOS, a null terminated string; Unicode if "caps" has
+           the 0x0004 bit set, ASCII (OEM character set) otherwise.
+           XXX - for now, we just handle the ISO 8859-1 subset of Unicode. */
+
+          NativeOS = pd + offset;
+
+        if (tree) {
+          if (Capabilities & 0x0004) {
+            ustr = unicode_to_str(NativeOS, &ustr_len);
+            proto_tree_add_text(tree, offset, ustr_len+2, "Native OS: %s", ustr);
+            offset += (strlen(ustr)*2) + 2; /* Skip Native OS */
+            offset += 2; /* Skip EXTRA bytes */
+          } else {
+            proto_tree_add_text(tree, offset, strlen(NativeOS) + 1, "Native OS: %s", NativeOS);
+            offset += strlen(NativeOS) + 1; /* Skip Native OS */
+          }
+        }
+
+
+       /* Build display for: Native LanMan Type */
+
+       /* The NativeLanManType, a null terminated string; Unicode if "caps" has
+          the 0x0004 bit set, ASCII (OEM character set) otherwise.
+          XXX - for now, we just handle the ISO 8859-1 subset of Unicode. */
+
+         NativeLanManType = pd + offset;
+
+        if (tree) {
+          if (Capabilities & 0x0004) {
+            ustr = unicode_to_str(NativeLanManType, &ustr_len);
+            proto_tree_add_text(tree, offset, ustr_len+2, "Native LanMan Type: %s", ustr);
+            offset += (strlen(ustr)*2) + 2; /* Skip Native LanMan Type */
+            offset += 2; /* Skip EXTRA bytes */
+          } else {
+            proto_tree_add_text(tree, offset, strlen(NativeLanManType) + 1, "Native LanMan Type: %s", NativeLanManType);
+            offset += strlen(NativeLanManType) + 1; /* Skip Native LanMan Type */
+          }
+        }
 
       }
 
@@ -2463,43 +2558,69 @@
     offset += 2; /* Skip Byte Count (BCC) */
 
     if (ByteCount > 0) {
-
-      /* Build display for: NativeOS */
 
-      NativeOS = pd + offset;
+      /* Build display for: Native OS */
 
-      if (tree) {
+      /* The NativeOS, a null terminated string; Unicode if "Flags" has
+         the 0x8000 bit set, ASCII (OEM character set) otherwise.
+         XXX - for now, we just handle the ISO 8859-1 subset of Unicode. */
+
+       if (Flags2 & 0x8000) {
+          offset += 1; /* Skip EXTRA Byte for unicode only */
+       }
+       NativeOS = pd + offset;
+
+       if (tree) {
+        if (Flags2 & 0x8000) {
+          ustr = unicode_to_str(NativeOS, &ustr_len);
+          proto_tree_add_text(tree, offset, ustr_len+2, "Native OS: %s", ustr);
+          offset += (strlen(ustr)*2) + 2; /* Skip Native OS */
+        } else {
+          proto_tree_add_text(tree, offset, strlen(NativeOS) + 1, "Native OS: %s", NativeOS);
+          offset += strlen(NativeOS) + 1; /* Skip Native OS */
+        }
+       }
 
-	proto_tree_add_text(tree, offset, strlen(NativeOS) + 1, "NativeOS: %s", NativeOS);
 
-      }
-
-      offset += strlen(NativeOS) + 1; /* Skip NativeOS */
-
       /* Build display for: NativeLanMan */
-
-      NativeLanMan = pd + offset;
 
-      if (tree) {
-
-	proto_tree_add_text(tree, offset, strlen(NativeLanMan) + 1, "NativeLanMan: %s", NativeLanMan);
-
-      }
+      /* The NativeLanManType, a null terminated string; Unicode if "Flags" has
+         the 0x8000 bit set, ASCII (OEM character set) otherwise.
+         XXX - for now, we just handle the ISO 8859-1 subset of Unicode. */
+
+        NativeLanManType = pd + offset;
+
+       if (tree) {
+        if (Flags2 & 0x8000) {
+          ustr = unicode_to_str(NativeLanManType, &ustr_len);
+          proto_tree_add_text(tree, offset, ustr_len+2, "NativeLanManType: %s", ustr);
+          offset += (strlen(ustr)*2) + 2; /* Skip Native LanMan Type */
+        } else {
+          proto_tree_add_text(tree, offset, strlen(NativeLanManType) + 1, "Native LanMan Type: %s", NativeLanManType);
+          offset += strlen(NativeLanManType) + 1; /* Skip Native LanMan Type */
+        }
+       }
 
-      offset += strlen(NativeLanMan) + 1; /* Skip NativeLanMan */
 
       /* Build display for: PrimaryDomain */
-
-      PrimaryDomain = pd + offset;
-
-      if (tree) {
 
-	proto_tree_add_text(tree, offset, strlen(PrimaryDomain) + 1, "PrimaryDomain: %s", PrimaryDomain);
+      /* The Primary Domain, a null terminated string; Unicode if "caps" has
+         the 0x8000 bit set, ASCII (OEM character set) otherwise.
+         XXX - for now, we just handle the ISO 8859-1 subset of Unicode. */
+
+        PrimaryDomain = pd + offset;
+
+       if (tree) {
+        if (Flags2 & 0x8000) {
+          ustr = unicode_to_str(PrimaryDomain, &ustr_len);
+          proto_tree_add_text(tree, offset, ustr_len+2, "Primary Domain: %s", ustr);
+          offset += (strlen(ustr)*2) + 2; /* Skip Primary Domain */
+        } else {
+          proto_tree_add_text(tree, offset, strlen(PrimaryDomain) + 1, "Primary Domain: %s", PrimaryDomain);
+          offset += strlen(PrimaryDomain) + 1; /* Skip Primary Domain */
+        }
+       }
 
-      }
-
-      offset += strlen(PrimaryDomain) + 1; /* Skip PrimaryDomain */
-
     }
 
     if (AndXCommand != 0xFF) {
@@ -2522,6 +2643,19 @@
   proto_tree  *flags_tree;
   proto_item  *ti;
 
+  char        *passstr;
+  char        *ustr;
+  int         ustr_len;
+  guint32     Capabilities;
+  guint16     Flags2;
+
+  /* obtain the Flags2 settings */
+  Flags2 = GSHORT(pd, Flags2_Offset);
+
+ /* Obtain Capabilities flags */
+  Capabilities = GWORD(pd, Cap_Offset);
+
+
   wct = pd[offset];
 
   /* Now figure out what format we are talking about, 2, 3, or 4 response
@@ -2633,31 +2767,46 @@
     str = pd + offset;
 
     if (tree) {
-
-      proto_tree_add_text(tree, offset, strlen(str) + 1, "Password: %s", format_text(str, passwdlen));
-
+      passstr=g_malloc(passwdlen+1);
+      strncpy(passstr, str, passwdlen);
+      passstr[passwdlen+1]='\0';
+      proto_tree_add_text(tree, offset, passwdlen, "Password: %s", passstr);
+      g_free(passstr);
     }
 
     offset += passwdlen;
 
-    str = pd + offset;
+    /* Build display for: Path */
 
-    if (tree) {
+    /* The Path, a null terminated string; Unicode if "caps" has
+       the 0x0004 bit set, ASCII (OEM character set) otherwise.
+       XXX - for now, we just handle the ISO 8859-1 subset of Unicode. */
 
-      proto_tree_add_text(tree, offset, strlen(str) + 1, "Path: %s", str);
+     str = pd + offset;
 
-    }
+     if (tree) {
+      if (Capabilities & 0x0004) {
+        ustr = unicode_to_str(str, &ustr_len);
+        proto_tree_add_text(tree, offset, ustr_len+2, "Path: %s", ustr);
+        offset += (strlen(ustr)*2) + 2; /* Skip Path OS */
+      } else {
+        proto_tree_add_text(tree, offset, strlen(str) + 1, "Path: %s", str);
+        offset += strlen(str) + 1; /* Skip Path */
+      }
+     }
 
-    offset += strlen(str) + 1;
 
+    /* Build display for: Service */
+
     str = pd + offset;
 
     if (tree) {
 
       proto_tree_add_text(tree, offset, strlen(str) + 1, "Service: %s", str);
+      proto_tree_add_text(tree, offset, strlen(str) + 1, "Service Description: %s",lookup_service_description(str));
 
     }
-
+    offset += strlen(str) + 1; /* Skip Service */
     break;
 
   case 2:
@@ -2676,8 +2825,8 @@
 
     if (tree) {
 
-      proto_tree_add_text(tree, offset, strlen(str) + 1, "Service Type: %s",
-			  str);
+      proto_tree_add_text(tree, offset, strlen(str) + 1, "Service Type: %s",str);
+      proto_tree_add_text(tree, offset, strlen(str) + 1, "Service Description: %s",lookup_service_description(str));
 
     }
 
@@ -2713,22 +2862,31 @@
     if (tree) {
 
       proto_tree_add_text(tree, offset, strlen(str) + 1, "Service: %s", str);
+      proto_tree_add_text(tree, offset, strlen(str) + 1, "Service Description: %s",lookup_service_description(str));
 
     }
 
     offset += strlen(str) + 1;
 
-    str = pd + offset;
+    /* Build display for: Native File System */
 
-    if (tree) {
+    /* The Native File System, a null terminated string; Unicode if "caps" has
+       the 0x8000 bit set, ASCII (OEM character set) otherwise.
+       XXX - for now, we just handle the ISO 8859-1 subset of Unicode. */
 
-      proto_tree_add_text(tree, offset, strlen(str) + 1, "Native File System: %s", str);
+    str = pd + offset;
 
+    if (tree) {
+      if (Flags2 & 0x8000) {
+        ustr = unicode_to_str(str, &ustr_len);
+        proto_tree_add_text(tree, offset, ustr_len+2, "Native File System: %s", ustr);
+        offset += (strlen(ustr)*2) + 2; /* Skip Native File System */
+      } else {
+        proto_tree_add_text(tree, offset, strlen(str) + 1, "Native File System: %s", str);
+        offset += strlen(str) + 1;
+      }
     }
 
-    offset += strlen(str) + 1;
-
-    
     break;
 
   default:
@@ -3260,6 +3418,15 @@
   guint16       ByteCount;
   const char    *DirectoryName;
 
+  guint16       Flags2;
+  char          *ustr;
+  int           ustr_len;
+
+
+  /* obtain the Flags2 settings */
+  Flags2 = GSHORT(pd, Flags2_Offset);
+
+
   if (dirn == 1) { /* Request(s) dissect code */
 
     /* Build display for: Word Count (WCT) */
@@ -3300,16 +3467,23 @@
 
     /* Build display for: Directory Name */
 
+    /* The Directory Name, a null terminated string; Unicode if "Flags" has
+       the 0x8000 bit set, ASCII (OEM character set) otherwise.
+       XXX - for now, we just handle the ISO 8859-1 subset of Unicode. */
+
     DirectoryName = pd + offset;
 
     if (tree) {
-
-      proto_tree_add_text(tree, offset, strlen(DirectoryName) + 1, "Directory Name: %s", DirectoryName);
-
+      if (Flags2 & 0x8000) {
+          ustr = unicode_to_str(DirectoryName, &ustr_len);
+          proto_tree_add_text(tree, offset, ustr_len+2, "Directory Name: %s", ustr);
+          offset += (strlen(ustr)*2) + 2; /* Skip Directory Name */
+      } else {
+          proto_tree_add_text(tree, offset, strlen(DirectoryName) + 1, "Directory Name: %s", DirectoryName);
+          offset += strlen(DirectoryName) + 1; /* Skip Directory Name */
+      }
     }
 
-    offset += strlen(DirectoryName) + 1; /* Skip Directory Name */
-
   }
 
   if (dirn == 0) { /* Response(s) dissect code */
@@ -3351,6 +3525,15 @@
   guint16       ByteCount;
   const char    *DirectoryName;
 
+  guint16       Flags2;
+  char          *ustr;
+  int           ustr_len;
+
+
+  /* obtain the Flags2 settings */
+  Flags2 = GSHORT(pd, Flags2_Offset);
+
+
   if (dirn == 1) { /* Request(s) dissect code */
 
     /* Build display for: Word Count (WCT) */
@@ -3391,16 +3574,22 @@
 
     /* Build display for: Directory Name */
 
+    /* The Directory Name, a null terminated string; Unicode if "Flags" has
+       the 0x8000 bit set, ASCII (OEM character set) otherwise.
+       XXX - for now, we just handle the ISO 8859-1 subset of Unicode. */
+
     DirectoryName = pd + offset;
 
     if (tree) {
-
-      proto_tree_add_text(tree, offset, strlen(DirectoryName) + 1, "Directory Name: %s", DirectoryName);
-
+      if (Flags2 & 0x8000) {
+          ustr = unicode_to_str(DirectoryName, &ustr_len);
+          proto_tree_add_text(tree, offset, ustr_len+2, "Directory Name: %s", ustr);
+          offset += (strlen(ustr)*2) + 2; /* Skip Directory Name */
+      } else {
+          proto_tree_add_text(tree, offset, strlen(DirectoryName) + 1, "Directory Name: %s", DirectoryName);
+          offset += strlen(DirectoryName) + 1; /* Skip Directory Name */
+      }
     }
-
-    offset += strlen(DirectoryName) + 1; /* Skip Directory Name */
-
   }
 
   if (dirn == 0) { /* Response(s) dissect code */
@@ -3442,6 +3631,15 @@
   guint16       ByteCount;
   const char    *DirectoryName;
 
+  guint16       Flags2;
+  char          *ustr;
+  int           ustr_len;
+
+
+  /* obtain the Flags2 settings */
+  Flags2 = GSHORT(pd, Flags2_Offset);
+
+
   if (dirn == 1) { /* Request(s) dissect code */
 
     /* Build display for: Word Count (WCT) */
@@ -3482,16 +3680,23 @@
 
     /* Build display for: Directory Name */
 
+    /* The Directory Name, a null terminated string; Unicode if "Flags" has
+       the 0x8000 bit set, ASCII (OEM character set) otherwise.
+       XXX - for now, we just handle the ISO 8859-1 subset of Unicode. */
+
     DirectoryName = pd + offset;
 
     if (tree) {
-
-      proto_tree_add_text(tree, offset, strlen(DirectoryName) + 1, "Directory Name: %s", DirectoryName);
-
+      if (Flags2 & 0x8000) {
+          ustr = unicode_to_str(DirectoryName, &ustr_len);
+          proto_tree_add_text(tree, offset, ustr_len+2, "Directory Name: %s", ustr);
+          offset += (strlen(ustr)*2) + 2; /* Skip Directory Name */
+      } else {
+          proto_tree_add_text(tree, offset, strlen(DirectoryName) + 1, "Directory Name: %s", DirectoryName);
+          offset += strlen(DirectoryName) + 1; /* Skip Directory Name */
+      }
     }
 
-    offset += strlen(DirectoryName) + 1; /* Skip Directory Name */
-
   }
 
   if (dirn == 0) { /* Response(s) dissect code */
@@ -6831,6 +7036,15 @@
   const char    *FileName;
   const char    *DirectoryName;
 
+  guint16       Flags2;
+  char          *ustr;
+  int           ustr_len;
+
+
+  /* obtain the Flags2 settings */
+  Flags2 = GSHORT(pd, Flags2_Offset);
+
+
   if (dirn == 1) { /* Request(s) dissect code */
 
     /* Build display for: Word Count (WCT) */
@@ -6907,16 +7121,23 @@
 
     /* Build display for: Directory Name */
 
+    /* The Directory Name, a null terminated string; Unicode if "Flags" has
+       the 0x8000 bit set, ASCII (OEM character set) otherwise.
+       XXX - for now, we just handle the ISO 8859-1 subset of Unicode. */
+
     DirectoryName = pd + offset;
 
     if (tree) {
-
-      proto_tree_add_text(tree, offset, strlen(DirectoryName) + 1, "Directory Name: %s", DirectoryName);
-
+      if (Flags2 & 0x8000) {
+          ustr = unicode_to_str(DirectoryName, &ustr_len);
+          proto_tree_add_text(tree, offset, ustr_len+2, "Directory Name: %s", ustr);
+          offset += (strlen(ustr)*2) + 2; /* Skip Directory Name */
+      } else {
+          proto_tree_add_text(tree, offset, strlen(DirectoryName) + 1, "Directory Name: %s", DirectoryName);
+          offset += strlen(DirectoryName) + 1; /* Skip Directory Name */
+      }
     }
 
-    offset += strlen(DirectoryName) + 1; /* Skip Directory Name */
-
   }
 
   if (dirn == 0) { /* Response(s) dissect code */
@@ -8561,7 +8782,7 @@
 
     if (tree) {
 
-      proto_tree_add_text(tree, offset, 2, "Transact Name: %s", decode_trans2_name(Setup));
+      proto_tree_add_text(tree, offset, 2, "Transact Name 1: %s", decode_trans2_name(Setup));
 
     }
 
@@ -8587,6 +8808,7 @@
 
       if (tree) {
 
+        proto_tree_add_text(tree, SMB_offset + ParameterOffset, ParameterCount, "Parameters: %s", format_text_ASCII(pd + SMB_offset + ParameterOffset, ParameterCount));
 	proto_tree_add_text(tree, SMB_offset + ParameterOffset, ParameterCount, "Parameters: %s", format_text(pd + SMB_offset + ParameterOffset, ParameterCount));
 
       }
@@ -8619,7 +8841,8 @@
 
       if (tree) {
 
-	proto_tree_add_text(tree, SMB_offset + DataOffset, DataCount, "Data: %s", format_text(&pd[offset], DataCount));
+        proto_tree_add_text(tree, SMB_offset + DataOffset, DataCount, "Data: %s", format_text_ASCII(&pd[offset], DataCount));
+        proto_tree_add_text(tree, SMB_offset + DataOffset, DataCount, "Data: %s", format_text(pd + SMB_offset + DataOffset, DataCount));
 
       }
 
@@ -8674,17 +8897,17 @@
 
     offset += 2; /* Skip Total Data Count */
 
-    /* Build display for: Reserved2 */
+    /* Build display for: Reserved1 */
 
-    Reserved2 = GSHORT(pd, offset);
+    Reserved1 = GSHORT(pd, offset);
 
     if (tree) {
 
-      proto_tree_add_text(tree, offset, 2, "Reserved2: %u", Reserved2);
+      proto_tree_add_text(tree, offset, 2, "Reserved1: %u", Reserved1);
 
     }
 
-    offset += 2; /* Skip Reserved2 */
+    offset += 2; /* Skip Reserved */
 
     /* Build display for: Parameter Count */
 
@@ -8770,17 +8993,17 @@
 
     offset += 1; /* Skip Setup Count */
 
-    /* Build display for: Reserved3 */
+    /* Build display for: Reserved2 */
 
-    Reserved3 = GBYTE(pd, offset);
+    Reserved2 = GBYTE(pd, offset);
 
     if (tree) {
 
-      proto_tree_add_text(tree, offset, 1, "Reserved3: %u", Reserved3);
+      proto_tree_add_text(tree, offset, 1, "Reserved2: %u", Reserved2);
 
     }
 
-    offset += 1; /* Skip Reserved3 */
+    offset += 1; /* Skip Reserved2 */
 
     /* Build display for: Setup */
 
@@ -8824,7 +9047,8 @@
 
       if (tree) {
 
-	proto_tree_add_text(tree, offset, ParameterCount, "Parameter: %s", format_text(pd + SMB_offset + ParameterOffset, ParameterCount));
+        proto_tree_add_text(tree, SMB_offset + ParameterOffset, ParameterCount, "Parameters: %s", format_text_ASCII(pd + SMB_offset + ParameterOffset, ParameterCount));
+	proto_tree_add_text(tree, SMB_offset + ParameterOffset, ParameterCount, "Parameters: %s", format_text(pd + SMB_offset + ParameterOffset, ParameterCount));
 
       }
 
@@ -8832,25 +9056,25 @@
 
     }
 
-    /* Build display for: Pad2 */
-
-    Pad2 = GBYTE(pd, offset);
-
-    if (tree) {
-
-      proto_tree_add_text(tree, offset, 1, "Pad2: %u", Pad2);
+   
+    if (offset % 2) {
+      /* Build display for: Pad2 */
 
+      Pad2 = GBYTE(pd, offset);
+      if (tree) {
+        proto_tree_add_text(tree, offset, 1, "Pad2: %u", Pad2);
+      }
+      offset += 1; /* Skip Pad2 */
     }
 
-    offset += 1; /* Skip Pad2 */
-
     /* Build display for: Data */
 
     if (DataCount > 0) {
 
       if (tree) {
 
-	proto_tree_add_text(tree, offset, DataCount, "Data: %s", format_text(pd + SMB_offset + DataOffset, DataCount));
+        proto_tree_add_text(tree, SMB_offset + DataOffset, DataCount, "Data: %s", format_text_ASCII(&pd[offset], DataCount));
+	proto_tree_add_text(tree, SMB_offset + DataOffset, DataCount, "Data: %s", format_text(pd + SMB_offset + DataOffset, DataCount));
 
       }
 
@@ -8896,11 +9120,20 @@
   char          *TransactNameCopy;
   char          *trans_type;
   char          *trans_cmd, *loc_of_slash;
-  guint32       index;
+  guint32       index=0;
   conversation_t *conversation;
   struct smb_request_key   request_key, *new_request_key;
   struct smb_request_val   *request_val;
 
+  char          *ustr;
+  int           ustr_len;
+  guint8        Default_Path; 
+  guint16       Flags2;
+
+  /* obtain the Flags2 settings */
+  Flags2 = GSHORT(pd, Flags2_Offset);
+
+
   /*
    * Find out what conversation this packet is part of
    */
@@ -8937,6 +9170,7 @@
 
   }
 
+
   if (dirn == 1) { /* Request(s) dissect code */
 
     /* Build display for: Word Count (WCT) */
@@ -9172,10 +9406,31 @@
 
     offset += 2; /* Skip Byte Count (BCC) */
 
+
     /* Build display for: Transact Name */
 
+    /* The Transact Name, a null terminated string; Unicode if "Flags" has
+       the 0x8000 bit set, ASCII (OEM character set) otherwise.
+       XXX - for now, we just handle the ISO 8859-1 subset of Unicode. */
+
+
+    if (Flags2 & 0x8000) {
+       offset +=1; /* skip EXTRA bit for unicode alignment */
+    }
     TransactName = pd + offset;
 
+    if (tree) {
+      if (Flags2 & 0x8000) {
+        ustr = unicode_to_str(TransactName, &ustr_len);
+        proto_tree_add_text(tree, offset, ustr_len+2, "Transact Name 2: %s", ustr);
+        offset += (strlen(ustr)*2) + 2; /* Skip Transact Name */
+        TransactName=ustr;
+      } else {
+        proto_tree_add_text(tree, offset, strlen(TransactName) + 1, "Transact Name 2: %s", TransactName);
+        offset += strlen(TransactName) + 1; /* Skip Transact Name */
+      }
+    }
+
     if (request_val -> last_transact_command) g_free(request_val -> last_transact_command);
 
     request_val -> last_transact_command = g_malloc(strlen(TransactName) + 1);
@@ -9189,14 +9444,6 @@
 
     }
 
-    if (tree) {
-
-      proto_tree_add_text(tree, offset, strlen(TransactName) + 1, "Transact Name: %s", TransactName);
-
-    }
-
-    offset += strlen(TransactName) + 1; /* Skip Transact Name */
-
     if (offset % 2) {
 
       /* Build display for: Pad1 */
@@ -9228,17 +9475,25 @@
       trans_type[index] = '\0';
     }
     else
-      trans_cmd = NULL;
+      trans_cmd = NULL; 
+
 
-    if (!strcmp(trans_type, "MAILSLOT") &&
-	!dissect_mailslot_smb(pd, offset, fd, parent, tree, si, max_data, SMB_offset, errcode, dirn, trans_cmd, SMB_offset + DataOffset, DataCount)) {
 
+/*  If trans type != MAILSLOT then process mailslot.  if unsuccessful then default processing */
+
+    Default_Path = 1;
+    if (!strncmp(trans_type, "MAILSLOT",8))  
+       Default_Path = !(dissect_mailslot_smb(pd, offset, fd, parent, tree, si, max_data, SMB_offset, errcode, dirn, trans_cmd, SMB_offset + DataOffset, DataCount));
+    
+    if (Default_Path) {
+
       if (ParameterCount > 0) {
 
 	/* Build display for: Parameters */
 
 	if (tree) {
 
+          proto_tree_add_text(tree, SMB_offset + ParameterOffset, ParameterCount, "Parameters: %s", format_text_ASCII(pd + SMB_offset + ParameterOffset, ParameterCount));
 	  proto_tree_add_text(tree, SMB_offset + ParameterOffset, ParameterCount, "Parameters: %s", format_text(pd + SMB_offset + ParameterOffset, ParameterCount));
 	  
 	}
@@ -9271,6 +9526,7 @@
 
 	if (tree) {
 
+          proto_tree_add_text(tree, SMB_offset + DataOffset, DataCount, "Data: %s", format_text_ASCII(&pd[offset], DataCount));
 	  proto_tree_add_text(tree, SMB_offset + DataOffset, DataCount, "Data: %s", format_text(pd + SMB_offset + DataOffset, DataCount));
 
 	}
@@ -9475,37 +9731,40 @@
 
     offset += 1; /* Skip Pad1 */
 
-    /* Build display for: Parameter */
-
-    Parameter = GBYTE(pd, offset);
-
-    if (tree) {
+    if (ParameterCount > 0) {
 
-      proto_tree_add_text(tree, offset, ParameterCount, "Parameters: %s", format_text(pd + SMB_offset + ParameterOffset, ParameterCount));
+      /* Build display for: Parameter */
 
-    }
+      Parameter = GBYTE(pd, offset);
 
-    offset += 1; /* Skip Parameter */
+      if (tree) {
 
-    /* Build display for: Pad2 */
+        proto_tree_add_text(tree, SMB_offset + ParameterOffset, ParameterCount, "Parameters: %s", format_text_ASCII(pd + SMB_offset + ParameterOffset, ParameterCount));
+        proto_tree_add_text(tree, SMB_offset + ParameterOffset, ParameterCount, "Parameters: %s", format_text(pd + SMB_offset + ParameterOffset, ParameterCount));
 
-    Pad2 = GBYTE(pd, offset);
+      }
 
-    if (tree) {
+      offset += ParameterCount; /* Skip Parameter */
+    }
 
-      proto_tree_add_text(tree, offset, 1, "Pad2: %u", Pad2);
+    if (offset %2) {
+      /* Build display for: Pad2 */
 
+      Pad2 = GBYTE(pd, offset);
+      if (tree) {
+        proto_tree_add_text(tree, offset, 1, "Pad2: %u", Pad2);
+      }
+      offset += 1; /* Skip Pad2 */
     }
 
-    offset += 1; /* Skip Pad2 */
-
     /* Build display for: Data */
 
     if (DataCount > 0) {
 
       if (tree) {
 
-	proto_tree_add_text(tree, offset, DataCount, "Data: %s", format_text(pd + SMB_offset + DataOffset, DataCount));
+        proto_tree_add_text(tree, SMB_offset + DataOffset, DataCount, "Data: %s", format_text_ASCII(&pd[offset], DataCount));
+	proto_tree_add_text(tree, SMB_offset + DataOffset, DataCount, "Data: %s", format_text(pd + SMB_offset + DataOffset, DataCount));
 
       }
 
Index: packet.c
===================================================================
RCS file: /cvsroot/ethereal/packet.c,v
retrieving revision 1.55
diff -u -r1.55 packet.c
--- packet.c	1999/11/17 21:58:32	1.55
+++ packet.c	1999/11/18 17:57:13
@@ -369,7 +369,7 @@
   return lineend;
 }
 
-#define	MAX_COLUMNS_LINE_DETAIL	62
+#define	MAX_COLUMNS_LINE_DETAIL 999	
 
 /*
  * Get the length of the next token in a line, and the beginning of the
@@ -402,6 +402,112 @@
 
   return token_len;
 }
+
+
+
+/*
+ * Given a string, generate a string from it that shows non-printable
+ * characters as C-style escapes, and return a pointer to it.
+ */
+gchar *
+format_text_ASCII(const u_char *string, int len)
+{
+  static gchar fmtbuf[MAX_COLUMNS_LINE_DETAIL + 3 + 4 + 1];
+  gchar *fmtbufp;
+  int column;
+  const u_char *stringend = string + len;
+  u_char c;
+
+  column = 0;
+  fmtbufp = &fmtbuf[0];
+  while (string < stringend) {
+    if (column >= MAX_COLUMNS_LINE_DETAIL) {
+      /*
+       * Put "..." and quit.
+       */
+      strcpy(fmtbufp, " ...");
+      break;
+    }
+    c = *string++;
+    if (isprint(c)) {
+      *fmtbufp++ = c;
+      column++;
+    } else {
+      switch (c) {
+
+      case '\\':
+        *fmtbufp++ =  '\\';
+        column++;
+        *fmtbufp++ = '\\';
+        column++;
+        break;
+
+      case '\a':
+        *fmtbufp++ =  '\\';
+        column++;
+        *fmtbufp++ = 'a';
+        column++;
+        break;
+
+      case '\b':
+        *fmtbufp++ =  '\\';
+        column++;
+        *fmtbufp++ = 'b';
+        column++;
+        break;
+
+      case '\f':
+        *fmtbufp++ =  '\\';
+        column++;
+        *fmtbufp++ = 'f';
+        column++;
+        break;
+
+      case '\n':
+        *fmtbufp++ =  '\\';
+        column++;
+        *fmtbufp++ = 'n';
+        column++;
+        break;
+
+      case '\r':
+        *fmtbufp++ =  '\\';
+        column++;
+        *fmtbufp++ = 'r';
+        column++;
+        break;
+
+      case '\t':
+        *fmtbufp++ =  '\\';
+        column++;
+        *fmtbufp++ = 't';
+        column++;
+        break;
+
+      case '\v':
+        *fmtbufp++ =  '\\';
+        column++;
+        *fmtbufp++ = 'v';
+        column++;
+        break;
+
+      default:
+        *fmtbufp++ = '.';
+        column++;
+        break;
+      }
+    }
+  }
+  *fmtbufp = '\0';
+
+  return fmtbuf;
+}
+
+
+
+
+
+
 
 /*
  * Given a string, generate a string from it that shows non-printable
Index: packet.h
===================================================================
RCS file: /cvsroot/ethereal/packet.h,v
retrieving revision 1.144
diff -u -r1.144 packet.h
--- packet.h	1999/11/17 21:58:32	1.144
+++ packet.h	1999/11/18 17:57:15
@@ -221,6 +221,7 @@
 int        get_token_len(const u_char *linep, const u_char *lineend,
     const u_char **next_token);
 gchar*     format_text(const u_char *line, int len);
+gchar*     format_text_ASCII(const u_char *line, int len);
 gchar*     val_to_str(guint32, const value_string *, const char *);
 gchar*     match_strval(guint32, const value_string*);
 char * decode_bitfield_value(char *buf, guint32 val, guint32 mask, int width);
/* packet.c
 * Routines for packet disassembly
 *
 * $Id: packet.c,v 1.55 1999/11/17 21:58:32 guy Exp $
 *
 * 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

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

#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif

#ifdef HAVE_WINSOCK_H
#include <winsock.h>
#endif

#include <glib.h>

#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <time.h>

#ifdef NEED_SNPRINTF_H
# include "snprintf.h"
#endif

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

#include <arpa/inet.h>

#ifdef NEED_INET_V6DEFS_H
# include "inet_v6defs.h"
#endif

#include "packet.h"
#include "print.h"
#include "file.h"

extern capture_file  cf;

static int proto_frame = -1;
static int hf_frame_arrival_time = -1;
static int hf_frame_time_delta = -1;
static int hf_frame_number = -1;
static int hf_frame_packet_len = -1;
static int hf_frame_capture_len = -1;

static gint ett_frame = -1;

gchar *
ether_to_str(const guint8 *ad) {
  static gchar  str[3][18];
  static gchar *cur;
  gchar        *p;
  int          i;
  guint32      octet;
  static const gchar hex_digits[16] = "0123456789abcdef";

  if (cur == &str[0][0]) {
    cur = &str[1][0];
  } else if (cur == &str[1][0]) {  
    cur = &str[2][0];
  } else {  
    cur = &str[0][0];
  }
  p = &cur[18];
  *--p = '\0';
  i = 5;
  for (;;) {
    octet = ad[i];
    *--p = hex_digits[octet&0xF];
    octet >>= 4;
    *--p = hex_digits[octet&0xF];
    if (i == 0)
      break;
    *--p = ':';
    i--;
  }
  return p;
}

gchar *
ip_to_str(const guint8 *ad) {
  static gchar  str[3][16];
  static gchar *cur;
  gchar        *p;
  int           i;
  guint32       octet;
  guint32       digit;

  if (cur == &str[0][0]) {
    cur = &str[1][0];
  } else if (cur == &str[1][0]) {  
    cur = &str[2][0];
  } else {  
    cur = &str[0][0];
  }
  p = &cur[16];
  *--p = '\0';
  i = 3;
  for (;;) {
    octet = ad[i];
    *--p = (octet%10) + '0';
    octet /= 10;
    digit = octet%10;
    octet /= 10;
    if (digit != 0 || octet != 0)
      *--p = digit + '0';
    if (octet != 0)
      *--p = octet + '0';
    if (i == 0)
      break;
    *--p = '.';
    i--;
  }
  return p;
}

gchar *
ip6_to_str(struct e_in6_addr *ad) {
#ifndef INET6_ADDRSTRLEN
#define INET6_ADDRSTRLEN 46
#endif
  static gchar buf[INET6_ADDRSTRLEN];

  inet_ntop(AF_INET6, (u_char*)ad, (gchar*)buf, sizeof(buf));
  return buf;
}


#define	PLURALIZE(n)	(((n) > 1) ? "s" : "")
#define	COMMA(do_it)	((do_it) ? ", " : "")

gchar *
time_secs_to_str(guint32 time)
{
  static gchar  str[3][8+1+4+2+2+5+2+2+7+2+2+7+1];
  static gchar *cur, *p;
  int hours, mins, secs;
  int do_comma;

  if (cur == &str[0][0]) {
    cur = &str[1][0];
  } else if (cur == &str[1][0]) {  
    cur = &str[2][0];
  } else {  
    cur = &str[0][0];
  }

  secs = time % 60;
  time /= 60;
  mins = time % 60;
  time /= 60;
  hours = time % 24;
  time /= 24;

  p = cur;
  if (time != 0) {
    sprintf(p, "%u day%s", time, PLURALIZE(time));
    p += strlen(p);
    do_comma = 1;
  } else
    do_comma = 0;
  if (hours != 0) {
    sprintf(p, "%s%u hour%s", COMMA(do_comma), hours, PLURALIZE(hours));
    p += strlen(p);
    do_comma = 1;
  } else
    do_comma = 0;
  if (mins != 0) {
    sprintf(p, "%s%u minute%s", COMMA(do_comma), mins, PLURALIZE(mins));
    p += strlen(p);
    do_comma = 1;
  } else
    do_comma = 0;
  if (secs != 0)
    sprintf(p, "%s%u second%s", COMMA(do_comma), secs, PLURALIZE(secs));
  return cur;
}

/* Max string length for displaying byte string.  */
#define	MAX_BYTE_STR_LEN	20

/* Turn an array of bytes into a string showing the bytes in hex. */
gchar *
bytes_to_str(const guint8 *bd, int bd_len) {
  static gchar  str[3][MAX_BYTE_STR_LEN+3+1];
  static gchar *cur;
  gchar        *p;
  int           len;
  static const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
                                '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

  if (cur == &str[0][0]) {
    cur = &str[1][0];
  } else if (cur == &str[1][0]) {  
    cur = &str[2][0];
  } else {  
    cur = &str[0][0];
  }
  p = cur;
  len = MAX_BYTE_STR_LEN;
  while (bd_len > 0 && len > 0) {
    *p++ = hex[(*bd) >> 4];
    *p++ = hex[(*bd) & 0xF];
    len -= 2;
    bd++;
    bd_len--;
  }
  if (bd_len != 0) {
    /* Note that we're not showing the full string.  */
    *p++ = '.';
    *p++ = '.';
    *p++ = '.';
  }
  *p = '\0';
  return cur;
}

static const char *mon_names[12] = {
	"Jan",
	"Feb",
	"Mar",
	"Apr",
	"May",
	"Jun",
	"Jul",
	"Aug",
	"Sep",
	"Oct",
	"Nov",
	"Dec"
};

gchar *
abs_time_to_str(struct timeval *abs_time)
{
        struct tm *tmp;
        static gchar *cur;
        static char str[3][3+1+2+2+4+1+2+1+2+1+2+1+4+1 + 5 /* extra */];

        if (cur == &str[0][0]) {
                cur = &str[1][0];
        } else if (cur == &str[1][0]) {
                cur = &str[2][0];
        } else {
                cur = &str[0][0];
        }

        tmp = localtime(&abs_time->tv_sec);
        sprintf(cur, "%s %2d, %d %02d:%02d:%02d.%04ld",
            mon_names[tmp->tm_mon],
            tmp->tm_mday,
            tmp->tm_year + 1900,
            tmp->tm_hour,
            tmp->tm_min,
            tmp->tm_sec,
            (long)abs_time->tv_usec/100);

        return cur;
}

gchar *
rel_time_to_str(struct timeval *rel_time)
{
        static gchar *cur;
        static char str[3][10+1+6+1];

        if (cur == &str[0][0]) {
                cur = &str[1][0];
        } else if (cur == &str[1][0]) {
                cur = &str[2][0];
        } else {
                cur = &str[0][0];
        }

	sprintf(cur, "%ld.%06ld", (long)rel_time->tv_sec,
		(long)rel_time->tv_usec);

        return cur;
}

/*
 * Given a pointer into a data buffer, and to the end of the buffer,
 * find the end of the (putative) line at that position in the data
 * buffer.
 * Return a pointer to the EOL character(s) in "*eol".
 */
const u_char *
find_line_end(const u_char *data, const u_char *dataend, const u_char **eol)
{
  const u_char *lineend;

  lineend = memchr(data, '\n', dataend - data);
  if (lineend == NULL) {
    /*
     * No LF - line is probably continued in next TCP segment.
     */
    lineend = dataend;
    *eol = dataend;
  } else {
    /*
     * Is the LF at the beginning of the line?
     */
    if (lineend > data) {
      /*
       * No - is it preceded by a carriage return?
       * (Perhaps it's supposed to be, but that's not guaranteed....)
       */
      if (*(lineend - 1) == '\r') {
        /*
	 * Yes.  The EOL starts with the CR.
	 */
        *eol = lineend - 1;
      } else {
        /*
         * No.  The EOL starts with the LF.
         */
        *eol = lineend;

        /*
         * I seem to remember that we once saw lines ending with LF-CR
         * in an HTTP request or response, so check if it's *followed*
         * by a carriage return.
         */
        if (lineend < (dataend - 1) && *(lineend + 1) == '\r') {
          /*
           * It's <non-LF><LF><CR>; say it ends with the CR.
           */
          lineend++;
        }
      }
    }

    /*
     * Point to the character after the last character.
     */
    lineend++;
  }
  return lineend;
}

#define	MAX_COLUMNS_LINE_DETAIL 999	

/*
 * Get the length of the next token in a line, and the beginning of the
 * next token after that (if any).
 * Return 0 if there is no next token.
 */
int
get_token_len(const u_char *linep, const u_char *lineend,
	      const u_char **next_token)
{
  const u_char *tokenp;
  int token_len;

  tokenp = linep;
  
  /*
   * Search for a blank, a CR or an LF, or the end of the buffer.
   */
  while (linep < lineend && *linep != ' ' && *linep != '\r' && *linep != '\n')
      linep++;
  token_len = linep - tokenp;

  /*
   * Skip trailing blanks.
   */
  while (linep < lineend && *linep == ' ')
    linep++;

  *next_token = linep;

  return token_len;
}



/*
 * Given a string, generate a string from it that shows non-printable
 * characters as C-style escapes, and return a pointer to it.
 */
gchar *
format_text_ASCII(const u_char *string, int len)
{
  static gchar fmtbuf[MAX_COLUMNS_LINE_DETAIL + 3 + 4 + 1];
  gchar *fmtbufp;
  int column;
  const u_char *stringend = string + len;
  u_char c;

  column = 0;
  fmtbufp = &fmtbuf[0];
  while (string < stringend) {
    if (column >= MAX_COLUMNS_LINE_DETAIL) {
      /*
       * Put "..." and quit.
       */
      strcpy(fmtbufp, " ...");
      break;
    }
    c = *string++;
    if (isprint(c)) {
      *fmtbufp++ = c;
      column++;
    } else {
      switch (c) {

      case '\\':
        *fmtbufp++ =  '\\';
        column++;
        *fmtbufp++ = '\\';
        column++;
        break;

      case '\a':
        *fmtbufp++ =  '\\';
        column++;
        *fmtbufp++ = 'a';
        column++;
        break;

      case '\b':
        *fmtbufp++ =  '\\';
        column++;
        *fmtbufp++ = 'b';
        column++;
        break;

      case '\f':
        *fmtbufp++ =  '\\';
        column++;
        *fmtbufp++ = 'f';
        column++;
        break;

      case '\n':
        *fmtbufp++ =  '\\';
        column++;
        *fmtbufp++ = 'n';
        column++;
        break;

      case '\r':
        *fmtbufp++ =  '\\';
        column++;
        *fmtbufp++ = 'r';
        column++;
        break;

      case '\t':
        *fmtbufp++ =  '\\';
        column++;
        *fmtbufp++ = 't';
        column++;
        break;

      case '\v':
        *fmtbufp++ =  '\\';
        column++;
        *fmtbufp++ = 'v';
        column++;
        break;

      default:
        *fmtbufp++ = '.';
        column++;
        break;
      }
    }
  }
  *fmtbufp = '\0';

  return fmtbuf;
}







/*
 * Given a string, generate a string from it that shows non-printable
 * characters as C-style escapes, and return a pointer to it.
 */
gchar *
format_text(const u_char *string, int len)
{
  static gchar fmtbuf[MAX_COLUMNS_LINE_DETAIL + 3 + 4 + 1];
  gchar *fmtbufp;
  int column;
  const u_char *stringend = string + len;
  u_char c;
  int i;

  column = 0;
  fmtbufp = &fmtbuf[0];
  while (string < stringend) {
    if (column >= MAX_COLUMNS_LINE_DETAIL) {
      /*
       * Put "..." and quit.
       */
      strcpy(fmtbufp, " ...");
      break;
    }
    c = *string++;
    if (isprint(c)) {
      *fmtbufp++ = c;
      column++;
    } else {
      *fmtbufp++ =  '\\';
      column++;
      switch (c) {

      case '\\':
	*fmtbufp++ = '\\';
	column++;
	break;

      case '\a':
	*fmtbufp++ = 'a';
	column++;
	break;

      case '\b':
	*fmtbufp++ = 'b';
	column++;
	break;

      case '\f':
	*fmtbufp++ = 'f';
	column++;
	break;

      case '\n':
	*fmtbufp++ = 'n';
	column++;
	break;

      case '\r':
	*fmtbufp++ = 'r';
	column++;
	break;

      case '\t':
	*fmtbufp++ = 't';
	column++;
	break;

      case '\v':
	*fmtbufp++ = 'v';
	column++;
	break;

      default:
	i = (c>>6)&03;
	*fmtbufp++ = i + '0';
	column++;
	i = (c>>3)&07;
	*fmtbufp++ = i + '0';
	column++;
	i = (c>>0)&07;
	*fmtbufp++ = i + '0';
	column++;
	break;
      }
    }
  }
  *fmtbufp = '\0';
  return fmtbuf;
}


/* Tries to match val against each element in the value_string array vs.
   Returns the associated string ptr on a match.
   Formats val with fmt, and returns the resulting string, on failure. */
gchar*
val_to_str(guint32 val, const value_string *vs, const char *fmt) {
  gchar *ret;
  static gchar  str[3][64];
  static gchar *cur;

  ret = match_strval(val, vs);
  if (ret != NULL)
    return ret;
  if (cur == &str[0][0]) {
    cur = &str[1][0];
  } else if (cur == &str[1][0]) {  
    cur = &str[2][0];
  } else {  
    cur = &str[0][0];
  }
  snprintf(cur, 64, fmt, val);
  return cur;
}

/* Tries to match val against each element in the value_string array vs.
   Returns the associated string ptr on a match, or NULL on failure. */
gchar*
match_strval(guint32 val, const value_string *vs) {
  gint i = 0;
  
  while (vs[i].strptr) {
    if (vs[i].value == val)
      return(vs[i].strptr);
    i++;
  }

  return(NULL);
}

/* Generate, into "buf", a string showing the bits of a bitfield.
   Return a pointer to the character after that string. */
char *
decode_bitfield_value(char *buf, guint32 val, guint32 mask, int width)
{
  int i;
  guint32 bit;
  char *p;

  i = 0;
  p = buf;
  bit = 1 << (width - 1);
  for (;;) {
    if (mask & bit) {
      /* This bit is part of the field.  Show its value. */
      if (val & bit)
        *p++ = '1';
      else
        *p++ = '0';
    } else {
      /* This bit is not part of the field. */
      *p++ = '.';
    }
    bit >>= 1;
    i++;
    if (i >= width)
      break;
    if (i % 4 == 0)
      *p++ = ' ';
  }
  strcpy(p, " = ");
  p += 3;
  return p;
}

/* Generate a string describing a Boolean bitfield (a one-bit field that
   says something is either true of false). */
const char *
decode_boolean_bitfield(guint32 val, guint32 mask, int width,
    const char *truedesc, const char *falsedesc)
{
  static char buf[1025];
  char *p;

  p = decode_bitfield_value(buf, val, mask, width);
  if (val & mask)
    strcpy(p, truedesc);
  else
    strcpy(p, falsedesc);
  return buf;
}

/* Generate a string describing an enumerated bitfield (an N-bit field
   with various specific values having particular names). */
const char *
decode_enumerated_bitfield(guint32 val, guint32 mask, int width,
    const value_string *tab, const char *fmt)
{
  static char buf[1025];
  char *p;

  p = decode_bitfield_value(buf, val, mask, width);
  sprintf(p, fmt, val_to_str(val & mask, tab, "Unknown"));
  return buf;
}

/* Generate a string describing a numeric bitfield (an N-bit field whose
   value is just a number). */
const char *
decode_numeric_bitfield(guint32 val, guint32 mask, int width,
    const char *fmt)
{
  static char buf[1025];
  char *p;
  int shift = 0;

  /* Compute the number of bits we have to shift the bitfield right
     to extract its value. */
  while ((mask & (1<<shift)) == 0)
    shift++;

  p = decode_bitfield_value(buf, val, mask, width);
  sprintf(p, fmt, (val & mask) >> shift);
  return buf;
}

/* Checks to see if a particular packet information element is needed for
   the packet list */
gint
check_col(frame_data *fd, gint el) {
  int i;

  if (fd->cinfo) {
    for (i = 0; i < fd->cinfo->num_cols; i++) {
      if (fd->cinfo->fmt_matx[i][el])
        return TRUE;
    }
  }
  return FALSE;
}

/* Adds a vararg list to a packet info string. */
void
col_add_fstr(frame_data *fd, gint el, gchar *format, ...) {
  va_list ap;
  int     i;
  size_t  max_len;
  
  va_start(ap, format);
  for (i = 0; i < fd->cinfo->num_cols; i++) {
    if (fd->cinfo->fmt_matx[i][el]) {
      if (el == COL_INFO)
	max_len = COL_MAX_INFO_LEN;
      else
	max_len = COL_MAX_LEN;
      vsnprintf(fd->cinfo->col_data[i], max_len, format, ap);
    }
  }
}

void
col_add_str(frame_data *fd, gint el, const gchar* str) {
  int    i;
  size_t max_len;

  for (i = 0; i < fd->cinfo->num_cols; i++) {
    if (fd->cinfo->fmt_matx[i][el]) {
      if (el == COL_INFO)
	max_len = COL_MAX_INFO_LEN;
      else
	max_len = COL_MAX_LEN;
      strncpy(fd->cinfo->col_data[i], str, max_len);
      fd->cinfo->col_data[i][max_len - 1] = 0;
    }
  }
}

/* Appends a vararg list to a packet info string. */
void
col_append_fstr(frame_data *fd, gint el, gchar *format, ...) {
  va_list ap;
  int     i;
  size_t  len, max_len;
  
  va_start(ap, format);
  for (i = 0; i < fd->cinfo->num_cols; i++) {
    if (fd->cinfo->fmt_matx[i][el]) {
      len = strlen(fd->cinfo->col_data[i]);
      if (el == COL_INFO)
	max_len = COL_MAX_INFO_LEN;
      else
	max_len = COL_MAX_LEN;
      vsnprintf(&fd->cinfo->col_data[i][len], max_len - len, format, ap);
    }
  }
}

void
col_append_str(frame_data *fd, gint el, gchar* str) {
  int    i;
  size_t len, max_len;

  for (i = 0; i < fd->cinfo->num_cols; i++) {
    if (fd->cinfo->fmt_matx[i][el]) {
      len = strlen(fd->cinfo->col_data[i]);
      if (el == COL_INFO)
	max_len = COL_MAX_LEN;
      else
	max_len = COL_MAX_INFO_LEN;
      strncat(fd->cinfo->col_data[i], str, max_len - len);
      fd->cinfo->col_data[i][max_len - 1] = 0;
    }
  }
}
	
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.ptype = PT_NONE;
  pi.srcport  = 0;
  pi.destport = 0;
}

/* Allow protocols to register "init" routines, which are called before
   we make a pass through a capture file and dissect all its packets
   (e.g., when we read in a new capture file, or run a "filter packets"
   or "colorize packets" pass over the current capture file). */
static GSList *init_routines;

void
register_init_routine(void (*func)(void))
{
	init_routines = g_slist_append(init_routines, func);
}

/* Call all the registered "init" routines. */
static void
call_init_routine(gpointer routine, gpointer dummy)
{
	void (*func)(void) = routine;

	(*func)();
}

void
init_all_protocols(void)
{
	g_slist_foreach(init_routines, &call_init_routine, NULL);
}

/* this routine checks the frame type from the cf structure */
void
dissect_packet(const u_char *pd, frame_data *fd, proto_tree *tree)
{
	proto_tree *fh_tree;
	proto_item *ti;
	struct timeval tv;

	/* Put in frame header information. */
	if (tree) {
	  ti = proto_tree_add_item_format(tree, proto_frame, 0, fd->cap_len,
	    NULL, "Frame (%d on wire, %d captured)", fd->pkt_len, fd->cap_len);

	  fh_tree = proto_item_add_subtree(ti, ett_frame);

	  tv.tv_sec = fd->abs_secs;
	  tv.tv_usec = fd->abs_usecs;

	  proto_tree_add_item(fh_tree, hf_frame_arrival_time,
		0, 0, &tv);

	  tv.tv_sec = fd->del_secs;
	  tv.tv_usec = fd->del_usecs;

	  proto_tree_add_item(fh_tree, hf_frame_time_delta,
		0, 0, &tv);

	  proto_tree_add_item(fh_tree, hf_frame_number,
		0, 0, fd->num);

	  proto_tree_add_item_format(fh_tree, hf_frame_packet_len,
		0, 0, fd->pkt_len, "Packet Length: %d byte%s", fd->pkt_len,
		plurality(fd->pkt_len, "", "s"));
		
	  proto_tree_add_item_format(fh_tree, hf_frame_capture_len,
		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
	   reduce them if their headers say they're less). */
	pi.len = fd->pkt_len;
	pi.captured_len = fd->cap_len;

	switch (fd->lnk_t) {
		case WTAP_ENCAP_ETHERNET :
			dissect_eth(pd, 0, fd, tree);
			break;
		case WTAP_ENCAP_FDDI :
			dissect_fddi(pd, fd, tree, FALSE);
			break;
		case WTAP_ENCAP_FDDI_BITSWAPPED :
			dissect_fddi(pd, fd, tree, TRUE);
			break;
		case WTAP_ENCAP_TR :
			dissect_tr(pd, 0, fd, tree);
			break;
		case WTAP_ENCAP_NULL :
			dissect_null(pd, fd, tree);
			break;
		case WTAP_ENCAP_PPP :
			dissect_ppp(pd, fd, tree);
			break;
		case WTAP_ENCAP_LAPB :
			dissect_lapb(pd, fd, tree);
			break;
		case WTAP_ENCAP_RAW_IP :
			dissect_raw(pd, fd, tree);
			break;
		case WTAP_ENCAP_LINUX_ATM_CLIP :
			dissect_clip(pd, fd, tree);
			break;
		case WTAP_ENCAP_ATM_SNIFFER :
			dissect_atm(pd, fd, tree);
			break;
		case WTAP_ENCAP_ASCEND :
			dissect_ascend(pd, fd, tree);
			break;
		case WTAP_ENCAP_LAPD :
			dissect_lapd(pd, fd, tree);
			break;
	}
}

void
proto_register_frame(void)
{
	static hf_register_info hf[] = {
		{ &hf_frame_arrival_time,
		{ "Arrival Time",		"frame.time", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
			""}},

		{ &hf_frame_time_delta,
		{ "Time delta from previous packet",	"frame.time_delta", FT_RELATIVE_TIME, BASE_NONE, NULL,
			0x0,
			"" }},

		{ &hf_frame_number,
		{ "Frame Number",		"frame.number", FT_UINT32, BASE_DEC, NULL, 0x0,
			"" }},

		{ &hf_frame_packet_len,
		{ "Total Frame Length",		"frame.pkt_len", FT_UINT32, BASE_DEC, NULL, 0x0,
			"" }},

		{ &hf_frame_capture_len,
		{ "Capture Frame Length",	"frame.cap_len", FT_UINT32, BASE_DEC, NULL, 0x0,
			"" }},
	};
	static gint *ett[] = {
		&ett_frame,
	};

	proto_frame = proto_register_protocol("Frame", "frame");
	proto_register_field_array(proto_frame, hf, array_length(hf));
	proto_register_subtree_array(ett, array_length(ett));
}
/* packet.h
 * Definitions for packet disassembly structures and routines
 *
 * $Id: packet.h,v 1.144 1999/11/17 21:58:32 guy Exp $
 *
 * 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.
 */


#ifndef __PACKET_H__
#define __PACKET_H__

#ifndef __WTAP_H__
#include "wiretap/wtap.h"
#endif

#ifndef __PROTO_H__
#include "proto.h"
#endif

/* Pointer versions of ntohs and ntohl.  Given a pointer to a member of a
 * byte array, returns the value of the two or four bytes at the pointer.
 * The pletoh[sl] versions return the little-endian representation.
 */

#define pntohs(p)  ((guint16)                       \
                    ((guint16)*((guint8 *)p+0)<<8|  \
                     (guint16)*((guint8 *)p+1)<<0))

#define pntohl(p)  ((guint32)*((guint8 *)p+0)<<24|  \
                    (guint32)*((guint8 *)p+1)<<16|  \
                    (guint32)*((guint8 *)p+2)<<8|   \
                    (guint32)*((guint8 *)p+3)<<0)

#define pletohs(p) ((guint16)                       \
                    ((guint16)*((guint8 *)p+1)<<8|  \
                     (guint16)*((guint8 *)p+0)<<0))

#define pletohl(p) ((guint32)*((guint8 *)p+3)<<24|  \
                    (guint32)*((guint8 *)p+2)<<16|  \
                    (guint32)*((guint8 *)p+1)<<8|   \
                    (guint32)*((guint8 *)p+0)<<0)


#define hi_nibble(b) ((b & 0xf0) >> 4)
#define lo_nibble(b) (b & 0x0f)

/* Useful when you have an array whose size you can tell at compile-time */
#define array_length(x)	(sizeof x / sizeof x[0])


/* Useful when highlighting regions inside a dissect_*() function. With this
 * macro, you can highlight from an arbitrary offset to the end of the
 * packet (which may come before the end of the frame).
 * See dissect_data() for an example.
 */
#define END_OF_FRAME	(pi.captured_len - offset)

/* Check whether the "len" bytes of data starting at "offset" is
 * entirely inside the captured data for this packet. */
#define	BYTES_ARE_IN_FRAME(offset, len)	((offset) + (len) <= pi.captured_len)

/* Check whether there's any data at all starting at "offset". */
#define	IS_DATA_IN_FRAME(offset)	((offset) < pi.captured_len)
		
/* To pass one of two strings, singular or plural */
#define plurality(d,s,p) ((d) == 1 ? (s) : (p))

typedef struct _column_info {
  gint       num_cols;  /* Number of columns */
  gint      *col_fmt;   /* Format of column */
  gboolean **fmt_matx;  /* Specifies which formats apply to a column */
  gint      *col_width; /* Column widths to use during a "-S" capture */
  gchar    **col_title; /* Column titles */
  gchar    **col_data;  /* Column data */
} column_info;

#define COL_MAX_LEN 256
#define COL_MAX_INFO_LEN 4096

typedef struct _packet_counts {
  gint           tcp;
  gint           udp;
  gint           icmp;
  gint           ospf;
  gint           gre;
  gint           netbios;
  gint           other;
  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 */
  struct _frame_data *prev; /* Previous element in list */
  guint32      num;       /* Frame number */
  guint32      pkt_len;   /* Packet length */
  guint32      cap_len;   /* Amount actually captured */
  guint32      rel_secs;  /* Relative seconds */
  guint32      rel_usecs; /* Relative microseconds */
  guint32      abs_secs;  /* Absolute seconds */
  guint32      abs_usecs; /* Absolute microseconds */
  guint32      del_secs;  /* Delta seconds */
  guint32      del_usecs; /* Delta microseconds */
  long         file_off;  /* File offset */
  column_info *cinfo;     /* Column formatting information */
  gint         row;       /* Row number for this packet in the display */
  int          lnk_t;     /* Per-packet encapsulation/data-link type */
  gboolean     passed_dfilter; /* TRUE = display, FALSE = no display */
  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 */
  AT_SNA,		/* SNA */
  AT_ATALK,		/* Appletalk DDP */
  AT_VINES		/* Banyan Vines */
} 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); \
	}

/* Types of port numbers Ethereal knows about. */
typedef enum {
  PT_NONE,		/* no port number */
  PT_TCP,		/* TCP */
  PT_UDP		/* UDP */
} port_type;

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;
  port_type ptype;		/* type of the following two port numbers */
  guint32 srcport;		/* source port */
  guint32 destport;		/* destination port */
  guint32 match_port;
  int     iplen;
  int     iphdrlen;
} packet_info;

extern packet_info pi;

/* Struct for the match_strval function */

typedef struct _value_string {
  guint32  value;
  gchar   *strptr;
} value_string;

/* Struct for boolean enumerations */
typedef struct true_false_string {
	char	*true_string;
	char	*false_string;
} true_false_string;


/* Many of the structs and definitions below and in packet-*.c files
 * were taken from include files in the Linux distribution. */

typedef struct tcp_extra_data {
  int match_port;
  int sport;
  int dport;
} tcp_extra_data;

/* Utility routines used by packet*.c */
gchar*     ether_to_str(const guint8 *);
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);
gchar*     bytes_to_str(const guint8 *, int);
const u_char *find_line_end(const u_char *data, const u_char *dataend,
    const u_char **eol);
int        get_token_len(const u_char *linep, const u_char *lineend,
    const u_char **next_token);
gchar*     format_text(const u_char *line, int len);
gchar*     format_text_ASCII(const u_char *line, int len);
gchar*     val_to_str(guint32, const value_string *, const char *);
gchar*     match_strval(guint32, const value_string*);
char * decode_bitfield_value(char *buf, guint32 val, guint32 mask, int width);
const char *decode_boolean_bitfield(guint32 val, guint32 mask, int width,
  const char *truedesc, const char *falsedesc);
const char *decode_enumerated_bitfield(guint32 val, guint32 mask, int width,
  const value_string *tab, const char *fmt);
const char *decode_numeric_bitfield(guint32 val, guint32 mask, int width,
  const char *fmt);
gint       check_col(frame_data *, gint);
#if __GNUC__ == 2
void       col_add_fstr(frame_data *, gint, gchar *, ...)
    __attribute__((format (printf, 3, 4)));
void       col_append_fstr(frame_data *, gint, gchar *, ...)
    __attribute__((format (printf, 3, 4)));
#else
void       col_add_fstr(frame_data *, gint, gchar *, ...);
void       col_append_fstr(frame_data *, gint, gchar *, ...);
#endif
void       col_add_str(frame_data *, gint, const gchar *);
void       col_append_str(frame_data *, gint, gchar *);

void blank_packetinfo(void);

/* Allow protocols to register "init" routines, which are called before
   we make a pass through a capture file and dissect all its packets
   (e.g., when we read in a new capture file, or run a "filter packets"
   or "colorize packets" pass over the current capture file). */
void register_init_routine(void (*func)(void));

/* Call all the registered "init" routines. */
void init_all_protocols(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 *
 * They should never modify the packet data.
 */
void capture_clip(const u_char *, guint32, packet_counts *);
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_netbios(const u_char *, int, guint32, packet_counts *);
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.
 */
void dissect_ascend(const u_char *, frame_data *, proto_tree *);
void dissect_atm(const u_char *, frame_data *, proto_tree *);
void dissect_clip(const u_char *, frame_data *, proto_tree *);
void dissect_lapb(const u_char *, frame_data *, proto_tree *);
void dissect_lapd(const u_char *, frame_data *, proto_tree *);
void dissect_null(const u_char *, frame_data *, proto_tree *);
void dissect_ppp(const u_char *, frame_data *, proto_tree *);
void dissect_raw(const u_char *, frame_data *, proto_tree *);

/*
 * Routines in packet-*.c
 * Routines should take four args: packet data *, frame_data *, tree *,
 * gboolean
 * They should never modify the packet data.
 */
void dissect_fddi(const u_char *, frame_data *, proto_tree *, gboolean);

typedef void	(*DissectFunc)	(const u_char*, int, frame_data*, proto_tree*);

/*
 * Routines in packet-*.c
 * Routines should take four args: packet data *, offset, frame_data *,
 * tree *
 * They should never modify the packet data.
 */
int dissect_ah(const u_char *, int, frame_data *, proto_tree *);
void dissect_aarp(const u_char *, int, frame_data *, proto_tree *);
void dissect_afs(const u_char *, int, frame_data *, proto_tree *);
void dissect_arp(const u_char *, int, frame_data *, proto_tree *);
void dissect_bgp(const u_char *, int, frame_data *, proto_tree *);
void dissect_bootp(const u_char *, int, frame_data *, proto_tree *);
void dissect_bpdu(const u_char *, int, frame_data *, proto_tree *);
void dissect_cdp(const u_char *, int, frame_data *, proto_tree *);
void dissect_cotp(const u_char *, int, frame_data *, proto_tree *);
void dissect_data(const u_char *, int, frame_data *, proto_tree *);
void dissect_ddp(const u_char *, int, frame_data *, proto_tree *);
void dissect_dns(const u_char *, int, frame_data *, proto_tree *);
void dissect_eigrp(const u_char *, int, frame_data *, proto_tree *);            
void dissect_esp(const u_char *, int, frame_data *, proto_tree *);
void dissect_eth(const u_char *, int, frame_data *, proto_tree *);
void dissect_ftp(const u_char *, int, frame_data *, proto_tree *);
void dissect_ftpdata(const u_char *, int, frame_data *, proto_tree *);
void dissect_giop(const u_char *, int, frame_data *, proto_tree *);
void dissect_http(const u_char *, int, frame_data *, proto_tree *);
void dissect_icmp(const u_char *, int, frame_data *, proto_tree *);
void dissect_icmpv6(const u_char *, int, frame_data *, proto_tree *);
void dissect_igmp(const u_char *, int, frame_data *, proto_tree *);
void dissect_ip(const u_char *, int, frame_data *, proto_tree *);
void dissect_ipcomp(const u_char *, int, frame_data *, proto_tree *);
void dissect_ipp(const u_char *, int, frame_data *, proto_tree *);
void dissect_ipv6(const u_char *, int, frame_data *, proto_tree *);
void dissect_ipx(const u_char *, int, frame_data *, proto_tree *);
void dissect_llc(const u_char *, int, frame_data *, proto_tree *);
void dissect_lpd(const u_char *, int, frame_data *, proto_tree *);
void dissect_mapi(const u_char *, int, frame_data *, proto_tree *);
void dissect_nbdgm(const u_char *, int, frame_data *, proto_tree *);
void dissect_netbios(const u_char *, int, frame_data *, proto_tree *);
void dissect_nbipx(const u_char *, int, frame_data *, proto_tree *);
void dissect_nbns(const u_char *, int, frame_data *, proto_tree *);
void dissect_nbss(const u_char *, int, frame_data *, proto_tree *);
void dissect_ncp(const u_char *, int, frame_data *, proto_tree *);
void dissect_nntp(const u_char *, int, frame_data *, proto_tree *);
void dissect_ntp(const u_char *, int, frame_data *, proto_tree *);
void dissect_nwlink_dg(const u_char *, int, frame_data *, proto_tree *);
void dissect_osi(const u_char *, int, frame_data *, proto_tree *);
void dissect_ospf(const u_char *, int, frame_data *, proto_tree *);
void dissect_ospf_hello(const u_char *, int, frame_data *, proto_tree *);
void dissect_pim(const u_char *, int, frame_data *, proto_tree *);
void dissect_pop(const u_char *, int, frame_data *, proto_tree *);
void dissect_pppoed(const u_char *, int, frame_data *, proto_tree *);
void dissect_pppoes(const u_char *, int, frame_data *, proto_tree *);
void dissect_icp(const u_char *,int, frame_data *, proto_tree *);
void dissect_icq(const u_char *,int, frame_data *, proto_tree *);
void dissect_imap(const u_char *,int, frame_data *, proto_tree *);
void dissect_isakmp(const u_char *, int, frame_data *, proto_tree *);
void dissect_pim(const u_char *, int, frame_data *, proto_tree *);
void dissect_q931(const u_char *, int, frame_data *, proto_tree *);
void dissect_radius(const u_char *, int, frame_data *, proto_tree *);
void dissect_rip(const u_char *, int, frame_data *, proto_tree *);
void dissect_ripng(const u_char *, int, frame_data *, proto_tree *);
void dissect_rsvp(const u_char *, int, frame_data *, proto_tree *);
void dissect_rtsp(const u_char *, int, frame_data *, proto_tree *);
void dissect_rx(const u_char *, int, frame_data *, proto_tree *);
void dissect_sap(const u_char *, int, frame_data *, proto_tree *);
void dissect_sdp(const u_char *, int, frame_data *, proto_tree *);
void dissect_sna(const u_char *, int, frame_data *, proto_tree *);
void dissect_snmp(const u_char *, int, frame_data *, proto_tree *);
void dissect_tcp(const u_char *, int, frame_data *, proto_tree *);
void dissect_telnet(const u_char *, int, frame_data *, proto_tree *);
void dissect_tftp(const u_char *, int, frame_data *, proto_tree *);
void dissect_tr(const u_char *, int, frame_data *, proto_tree *);
void dissect_trmac(const u_char *, int, frame_data *, proto_tree *);
void dissect_udp(const u_char *, int, frame_data *, proto_tree *);
void dissect_vines(const u_char *, int, frame_data *, proto_tree *);
void dissect_vines_arp(const u_char *, int, frame_data *, proto_tree *);
void dissect_vines_frp(const u_char *, int, frame_data *, proto_tree *);
void dissect_vines_icp(const u_char *, int, frame_data *, proto_tree *);
void dissect_vines_ipc(const u_char *, int, frame_data *, proto_tree *);
void dissect_vines_rtp(const u_char *, int, frame_data *, proto_tree *);
void dissect_vines_spp(const u_char *, int, frame_data *, proto_tree *);
void dissect_vlan(const u_char *, int, frame_data *, proto_tree *);
void dissect_payload_ppp(const u_char *, int, frame_data *, proto_tree *);
void dissect_x25(const u_char *, int, frame_data *, proto_tree *);
void dissect_yhoo(const u_char *, int, frame_data *, proto_tree *);

void dissect_smb(const u_char *, int, frame_data *, proto_tree *, int);
void dissect_pptp(const u_char *, int, frame_data *, proto_tree *);
void dissect_gre(const u_char *, int, frame_data *, proto_tree *);

/*
 * Routines in packet-*.c
 * Routines should take four args: packet data *, offset, frame_data *,
 * tree *
 * They should never modify the packet data.
 * They should return TRUE if the packet is of the type the routine would
 * dissect, FALSE otherwise.
 */
gboolean dissect_rpc(const u_char *, int, frame_data *, proto_tree *);

void init_dissect_rpc(void);
void init_dissect_udp(void);
void init_dissect_x25(void);

/* These functions are in ethertype.c */
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, proto_tree *tree,
		proto_tree *fh_tree, int item_id);
extern const value_string etype_vals[];

/* These functions are in packet-arp.c */
gchar *arphrdaddr_to_str(guint8 *ad, int ad_len, guint16 type);
gchar *arphrdtype_to_str(guint16 hwtype, const char *fmt);

/* ipproto.c */
extern const char *ipprotostr(int proto);

/*
 * All of the possible columns in summary listing.
 *
 * NOTE: The SRC and DST entries MUST remain in this order, or else you
 * need to fix the offset #defines before get_column_format!
 */
enum {
  COL_NUMBER,         /* Packet list item number */
  COL_CLS_TIME,       /* Command line-specified time (default relative) */
  COL_REL_TIME,       /* Relative time */
  COL_ABS_TIME,       /* Absolute time */
  COL_DELTA_TIME,     /* Delta time */
  COL_DEF_SRC,        /* Source address */
  COL_RES_SRC,        /* Resolved source */
  COL_UNRES_SRC,      /* Unresolved source */
  COL_DEF_DL_SRC,     /* Data link layer source address */
  COL_RES_DL_SRC,     /* Resolved DL source */
  COL_UNRES_DL_SRC,   /* Unresolved DL source */
  COL_DEF_NET_SRC,    /* Network layer source address */
  COL_RES_NET_SRC,    /* Resolved net source */
  COL_UNRES_NET_SRC,  /* Unresolved net source */
  COL_DEF_DST,        /* Destination address */
  COL_RES_DST,        /* Resolved dest */
  COL_UNRES_DST,      /* Unresolved dest */
  COL_DEF_DL_DST,     /* Data link layer dest address */
  COL_RES_DL_DST,     /* Resolved DL dest */
  COL_UNRES_DL_DST,   /* Unresolved DL dest */
  COL_DEF_NET_DST,    /* Network layer dest address */
  COL_RES_NET_DST,    /* Resolved net dest */
  COL_UNRES_NET_DST,  /* Unresolved net dest */
  COL_DEF_SRC_PORT,   /* Source port */
  COL_RES_SRC_PORT,   /* Resolved source port */
  COL_UNRES_SRC_PORT, /* Unresolved source port */
  COL_DEF_DST_PORT,   /* Destination port */
  COL_RES_DST_PORT,   /* Resolved dest port */
  COL_UNRES_DST_PORT, /* Unresolved dest port */
  COL_PROTOCOL,       /* Protocol */
  COL_INFO,           /* Description */
  COL_PACKET_LENGTH,  /* Packet length in bytes */
  NUM_COL_FMTS        /* Should always be last */
};

#endif /* packet.h */
/* packet-smb.c
 * Routines for smb packet dissection
 * Copyright 1999, Richard Sharpe <rsharpe@xxxxxxxxxx>
 *
 * $Id: packet-smb.c,v 1.43 1999/11/18 07:32:46 sharpe Exp $
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@xxxxxxxxxx>
 * Copyright 1998 Gerald Combs
 *
 * Copied from packet-pop.c
 * 
 * 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 <time.h>
#include <string.h>
#include <glib.h>
#include "packet.h"
#include "conversation.h"
#include "smb.h"
#include "alignment.h"

static int proto_smb = -1;
static int Cap_Offset = 113;     /* offset into the packet of the Capabilities flags */
static int Flags2_Offset=68;     /* offset into the packet of the Flags2 settings */


static gint ett_smb = -1;
static gint ett_smb_fileattributes = -1;
static gint ett_smb_capabilities = -1;
static gint ett_smb_aflags = -1;
static gint ett_smb_dialects = -1;
static gint ett_smb_mode = -1;
static gint ett_smb_rawmode = -1;
static gint ett_smb_flags = -1;
static gint ett_smb_flags2 = -1;
static gint ett_smb_desiredaccess = -1;
static gint ett_smb_search = -1;
static gint ett_smb_file = -1;
static gint ett_smb_openfunction = -1;
static gint ett_smb_filetype = -1;
static gint ett_smb_action = -1;
static gint ett_smb_writemode = -1;
static gint ett_smb_lock_type = -1;

static int proto_browse = -1;

static gint ett_browse = -1;
static gint ett_browse_flags = -1;
static gint ett_browse_election_criteria = -1;
static gint ett_browse_election_os = -1;
static gint ett_browse_election_desire = -1;

/*
 * Struct passed to each SMB decode routine of info it may need
 */

struct smb_info {
  int tid, uid, mid, pid;   /* Any more?  */
};

char *decode_smb_name(unsigned char);

int smb_packet_init_count = 200;

struct smb_request_key {
  guint32 conversation;
  guint16 mid;
};

struct smb_request_val {
  guint16 last_transact2_command;
  gchar *last_transact_command;
  guint16 mid;
};

GHashTable *smb_request_hash = NULL;
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:%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;

  }

  return 0;
}

guint 
smb_hash (gconstpointer v)
{
  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;

}

/*
 * Free up any state information we've saved, and re-initialize the
 * tables of state information.
 */
static 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);
  if (smb_request_keys)
    g_mem_chunk_destroy(smb_request_keys);
  if (smb_request_vals)
    g_mem_chunk_destroy(smb_request_vals);

  smb_request_hash = g_hash_table_new(smb_hash, smb_equal);
  smb_request_keys = g_mem_chunk_new("smb_request_keys",
				     sizeof(struct smb_request_key),
				     smb_packet_init_count * sizeof(struct smb_request_key), G_ALLOC_AND_FREE);
  smb_request_vals = g_mem_chunk_new("smb_request_vals",
				     sizeof(struct smb_request_val),
				     smb_packet_init_count * sizeof(struct smb_request_val), G_ALLOC_AND_FREE);
}

void (*dissect[256])(const u_char *, int, frame_data *, proto_tree *, proto_tree *, struct smb_info si, int, int, int, int);

char *SMB_names[256] = {
  "SMBcreatedirectory",
  "SMBdeletedirectory",
  "SMBopen",
  "SMBcreate",
  "SMBclose",
  "SMBflush",
  "SMBunlink",
  "SMBmv",
  "SMBgetatr",
  "SMBsetatr",
  "SMBread",
  "SMBwrite",
  "SMBlock",
  "SMBunlock",
  "SMBctemp",
  "SMBmknew",
  "SMBchkpth",
  "SMBexit",
  "SMBlseek",
  "SMBlockread",
  "SMBwriteunlock",
  "unknown-0x15",
  "unknown-0x16",
  "unknown-0x17",
  "unknown-0x18",
  "unknown-0x19",
  "SMBreadBraw",
  "SMBreadBmpx",
  "SMBreadBs",
  "SMBwriteBraw",
  "SMBwriteBmpx",
  "SMBwriteBs",
  "SMBwriteC",
  "unknown-0x21",
  "SMBsetattrE",
  "SMBgetattrE",
  "SMBlockingX",
  "SMBtrans",
  "SMBtranss",
  "SMBioctl",
  "SMBioctls",
  "SMBcopy",
  "SMBmove",
  "SMBecho",
  "SMBwriteclose",
  "SMBopenX",
  "SMBreadX",
  "SMBwriteX",
  "unknown-0x30",
  "SMBcloseandtreedisc",
  "SMBtrans2",
  "SMBtrans2secondary",
  "SMBfindclose2",
  "SMBfindnotifyclose",
  "unknown-0x36",
  "unknown-0x37",
  "unknown-0x38",
  "unknown-0x39",
  "unknown-0x3A",
  "unknown-0x3B",
  "unknown-0x3C",
  "unknown-0x3D",
  "unknown-0x3E",
  "unknown-0x3F",
  "unknown-0x40",
  "unknown-0x41",
  "unknown-0x42",
  "unknown-0x43",
  "unknown-0x44",
  "unknown-0x45",
  "unknown-0x46",
  "unknown-0x47",
  "unknown-0x48",
  "unknown-0x49",
  "unknown-0x4A",
  "unknown-0x4B",
  "unknown-0x4C",
  "unknown-0x4D",
  "unknown-0x4E",
  "unknown-0x4F",
  "unknown-0x50",
  "unknown-0x51",
  "unknown-0x52",
  "unknown-0x53",
  "unknown-0x54",
  "unknown-0x55",
  "unknown-0x56",
  "unknown-0x57",
  "unknown-0x58",
  "unknown-0x59",
  "unknown-0x5A",
  "unknown-0x5B",
  "unknown-0x5C",
  "unknown-0x5D",
  "unknown-0x5E",
  "unknown-0x5F",
  "unknown-0x60",
  "unknown-0x61",
  "unknown-0x62",
  "unknown-0x63",
  "unknown-0x64",
  "unknown-0x65",
  "unknown-0x66",
  "unknown-0x67",
  "unknown-0x68",
  "unknown-0x69",
  "unknown-0x6A",
  "unknown-0x6B",
  "unknown-0x6C",
  "unknown-0x6D",
  "unknown-0x6E",
  "unknown-0x6F",
  "SMBtcon",
  "SMBtdis",
  "SMBnegprot",
  "SMBsesssetupX",
  "SMBlogoffX",
  "SMBtconX",
  "unknown-0x76",
  "unknown-0x77",
  "unknown-0x78",
  "unknown-0x79",
  "unknown-0x7A",
  "unknown-0x7B",
  "unknown-0x7C",
  "unknown-0x7D",
  "unknown-0x7E",
  "unknown-0x7F",
  "SMBdskattr",
  "SMBsearch",
  "SMBffirst",
  "SMBfunique",
  "SMBfclose",
  "unknown-0x85",
  "unknown-0x86",
  "unknown-0x87",
  "unknown-0x88",
  "unknown-0x89",
  "unknown-0x8A",
  "unknown-0x8B",
  "unknown-0x8C",
  "unknown-0x8D",
  "unknown-0x8E",
  "unknown-0x8F",
  "unknown-0x90",
  "unknown-0x91",
  "unknown-0x92",
  "unknown-0x93",
  "unknown-0x94",
  "unknown-0x95",
  "unknown-0x96",
  "unknown-0x97",
  "unknown-0x98",
  "unknown-0x99",
  "unknown-0x9A",
  "unknown-0x9B",
  "unknown-0x9C",
  "unknown-0x9D",
  "unknown-0x9E",
  "unknown-0x9F",
  "SMBnttransact",
  "SMBnttransactsecondary",
  "SMBntcreateX",
  "unknown-0xA3",
  "SMBntcancel",
  "unknown-0xA5",
  "unknown-0xA6",
  "unknown-0xA7",
  "unknown-0xA8",
  "unknown-0xA9",
  "unknown-0xAA",
  "unknown-0xAB",
  "unknown-0xAC",
  "unknown-0xAD",
  "unknown-0xAE",
  "unknown-0xAF",
  "unknown-0xB0",
  "unknown-0xB1",
  "unknown-0xB2",
  "unknown-0xB3",
  "unknown-0xB4",
  "unknown-0xB5",
  "unknown-0xB6",
  "unknown-0xB7",
  "unknown-0xB8",
  "unknown-0xB9",
  "unknown-0xBA",
  "unknown-0xBB",
  "unknown-0xBC",
  "unknown-0xBD",
  "unknown-0xBE",
  "unknown-0xBF",
  "SMBsplopen",
  "SMBsplwr",
  "SMBsplclose",
  "SMBsplretq",
  "unknown-0xC4",
  "unknown-0xC5",
  "unknown-0xC6",
  "unknown-0xC7",
  "unknown-0xC8",
  "unknown-0xC9",
  "unknown-0xCA",
  "unknown-0xCB",
  "unknown-0xCC",
  "unknown-0xCD",
  "unknown-0xCE",
  "unknown-0xCF",
  "SMBsends",
  "SMBsendb",
  "SMBfwdname",
  "SMBcancelf",
  "SMBgetmac",
  "SMBsendstrt",
  "SMBsendend",
  "SMBsendtxt",
  "SMBreadbulk",
  "SMBwritebulk",
  "SMBwritebulkdata",
  "unknown-0xDB",
  "unknown-0xDC",
  "unknown-0xDD",
  "unknown-0xDE",
  "unknown-0xDF",
  "unknown-0xE0",
  "unknown-0xE1",
  "unknown-0xE2",
  "unknown-0xE3",
  "unknown-0xE4",
  "unknown-0xE5",
  "unknown-0xE6",
  "unknown-0xE7",
  "unknown-0xE8",
  "unknown-0xE9",
  "unknown-0xEA",
  "unknown-0xEB",
  "unknown-0xEC",
  "unknown-0xED",
  "unknown-0xEE",
  "unknown-0xEF",
  "unknown-0xF0",
  "unknown-0xF1",
  "unknown-0xF2",
  "unknown-0xF3",
  "unknown-0xF4",
  "unknown-0xF5",
  "unknown-0xF6",
  "unknown-0xF7",
  "unknown-0xF8",
  "unknown-0xF9",
  "unknown-0xFA",
  "unknown-0xFB",
  "unknown-0xFC",
  "unknown-0xFD",
  "SMBinvalid",
  "unknown-0xFF"
};

void 
dissect_unknown_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)
{
  if (tree) {

    proto_tree_add_text(tree, offset, END_OF_FRAME, "Data (%u bytes)", 
			END_OF_FRAME); 

  }

}

/* 
 * Dissect a UNIX like date ...
 */

struct tm *gtime;

static char *
dissect_smbu_date(guint16 date, guint16 time)

{
  static char         datebuf[4+2+2+2+1];
  time_t              ltime = (date << 16) + time;

  gtime = gmtime(&ltime);
  sprintf(datebuf, "%04d-%02d-%02d",
	  1900 + (gtime -> tm_year), gtime -> tm_mon, gtime -> tm_mday);

  return datebuf;

}

/*
 * Relies on time
 */
static char *
dissect_smbu_time(guint16 date, guint16 time)

{
  static char timebuf[2+2+2+2+1];

  sprintf(timebuf, "%02d:%02d:%02d",
          gtime -> tm_hour, gtime -> tm_min, gtime -> tm_sec);

  return timebuf;

}

/*
 * Dissect a DOS-format date.
 */
static char *
dissect_dos_date(guint16 date)
{
	static char datebuf[4+2+2+1];

	sprintf(datebuf, "%04d-%02d-%02d",
	    ((date>>9)&0x7F) + 1980, (date>>5)&0x0F, date&0x1F);
	return datebuf;
}

/*
 * Dissect a DOS-format time.
 */
static char *
dissect_dos_time(guint16 time)
{
	static char timebuf[2+2+2+1];

	sprintf(timebuf, "%02d:%02d:%02d",
	    (time>>11)&0x1F, (time>>5)&0x3F, (time&0x1F)*2);
	return timebuf;
}

/* Max string length for displaying Unicode strings.  */
#define	MAX_UNICODE_STR_LEN	256

/* Turn a little-endian Unicode '\0'-terminated string into a string we
   can display.
   XXX - for now, we just handle the ISO 8859-1 characters. */
static gchar *
unicode_to_str(const guint8 *us, int *us_lenp) {
  static gchar  str[3][MAX_UNICODE_STR_LEN+3+1];
  static gchar *cur;
  gchar        *p;
  int           len;
  int           us_len;
  int           overflow = 0;

  if (cur == &str[0][0]) {
    cur = &str[1][0];
  } else if (cur == &str[1][0]) {  
    cur = &str[2][0];
  } else {  
    cur = &str[0][0];
  }
  p = cur;
  len = MAX_UNICODE_STR_LEN;
  us_len = 0;
  while (*us != 0 || *(us + 1) != 0) {
    if (len > 0) {
      *p++ = *us;
      len--;
    } else
      overflow = 1;
    us += 2;
    us_len += 2;
  }
  if (overflow) {
    /* Note that we're not showing the full string.  */
    *p++ = '.';
    *p++ = '.';
    *p++ = '.';
  }
  *p = '\0';
  *us_lenp = us_len;
  return cur;
}


   /* lookup the service requested. */
static gchar *
lookup_service_description(const guint8 *str) {

   gchar  *str2;

   str2="";
   if (strcmp(str,"A:")==0) {
       str2 = "Disk Share";
   }
   else if (strcmp(str,"LPT1:")==0) {
       str2 = "Printer";
   }
   else if (strcmp(str,"IPC")==0) {
       str2 = "Named Pipe";
   }
   else if (strcmp(str,"COMM")==0) {
       str2 = "Communications Device";
   }
   else if (strcmp(str,"?????")==0) {
       str2 = "Any Type of Device";
   }
  return str2;
}



/*
 * Each dissect routine is passed an offset to wct and works from there 
 */

void
dissect_flush_file_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  guint8        WordCount;
  guint16       FID;
  guint16       ByteCount;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: FID */

    FID = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "FID: %u", FID);

    }

    offset += 2; /* Skip FID */

    /* Build display for: Byte Count */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count: %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count */

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

}

void
dissect_get_disk_attr_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  guint8        WordCount;
  guint16       TotalUnits;
  guint16       Reserved;
  guint16       FreeUnits;
  guint16       ByteCount;
  guint16       BlocksPerUnit;
  guint16       BlockSize;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    if (WordCount > 0) {

      /* Build display for: Total Units */

      TotalUnits = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Total Units: %u", TotalUnits);

      }

      offset += 2; /* Skip Total Units */

      /* Build display for: Blocks Per Unit */

      BlocksPerUnit = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Blocks Per Unit: %u", BlocksPerUnit);

      }

      offset += 2; /* Skip Blocks Per Unit */

      /* Build display for: Block Size */

      BlockSize = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Block Size: %u", BlockSize);

      }

      offset += 2; /* Skip Block Size */

      /* Build display for: Free Units */

      FreeUnits = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Free Units: %u", FreeUnits);

      }

      offset += 2; /* Skip Free Units */

      /* Build display for: Reserved */

      Reserved = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Reserved: %u", Reserved);

      }

      offset += 2; /* Skip Reserved */

    }

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

}

void
dissect_set_file_attr_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  proto_tree    *Attributes_tree;
  proto_item    *ti;
  guint8        WordCount;
  guint8        ByteCount;
  guint8        BufferFormat;
  guint16       Reserved5;
  guint16       Reserved4;
  guint16       Reserved3;
  guint16       Reserved2;
  guint16       Reserved1;
  guint16       LastWriteTime;
  guint16       LastWriteDate;
  guint16       Attributes;
  const char    *FileName;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    if (WordCount > 0) {

      /* Build display for: Attributes */

      Attributes = GSHORT(pd, offset);

      if (tree) {

	ti = proto_tree_add_text(tree, offset, 2, "Attributes: 0x%02x", Attributes);
	Attributes_tree = proto_item_add_subtree(ti, ett_smb_fileattributes);
	proto_tree_add_text(Attributes_tree, offset, 2, "%s",
			    decode_boolean_bitfield(Attributes, 0x01, 16, "Read-only file", "Not a read-only file"));
	proto_tree_add_text(Attributes_tree, offset, 2, "%s",
			    decode_boolean_bitfield(Attributes, 0x02, 16, "Hidden file", "Not a hidden file"));
	proto_tree_add_text(Attributes_tree, offset, 2, "%s",
			    decode_boolean_bitfield(Attributes, 0x04, 16, "System file", "Not a system file"));
	proto_tree_add_text(Attributes_tree, offset, 2, "%s",
			    decode_boolean_bitfield(Attributes, 0x08, 16, " Volume", "Not a volume"));
	proto_tree_add_text(Attributes_tree, offset, 2, "%s",
			    decode_boolean_bitfield(Attributes, 0x10, 16, " Directory", "Not a directory"));
	proto_tree_add_text(Attributes_tree, offset, 2, "%s",
			    decode_boolean_bitfield(Attributes, 0x20, 16, " Archived", "Not archived"));
	
      }

      offset += 2; /* Skip Attributes */

      /* Build display for: Last Write Time */

      LastWriteTime = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Last Write Time: %u", dissect_dos_time(LastWriteTime));

      }

      offset += 2; /* Skip Last Write Time */

      /* Build display for: Last Write Date */

      LastWriteDate = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Last Write Date: %u", dissect_dos_date(LastWriteDate));

      }

      offset += 2; /* Skip Last Write Date */

      /* Build display for: Reserved 1 */

      Reserved1 = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Reserved 1: %u", Reserved1);

      }

      offset += 2; /* Skip Reserved 1 */

      /* Build display for: Reserved 2 */

      Reserved2 = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Reserved 2: %u", Reserved2);

      }

      offset += 2; /* Skip Reserved 2 */

      /* Build display for: Reserved 3 */

      Reserved3 = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Reserved 3: %u", Reserved3);

      }

      offset += 2; /* Skip Reserved 3 */

      /* Build display for: Reserved 4 */

      Reserved4 = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Reserved 4: %u", Reserved4);

      }

      offset += 2; /* Skip Reserved 4 */

      /* Build display for: Reserved 5 */

      Reserved5 = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Reserved 5: %u", Reserved5);

      }

      offset += 2; /* Skip Reserved 5 */

    }

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

    /* Build display for: Buffer Format */

    BufferFormat = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Buffer Format: %u", BufferFormat);

    }

    offset += 1; /* Skip Buffer Format */

    /* Build display for: File Name */

    FileName = pd + offset;

    if (tree) {

      proto_tree_add_text(tree, offset, strlen(FileName) + 1, "File Name: %s", FileName);

    }

    offset += strlen(FileName) + 1; /* Skip File Name */

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 1; /* Skip Byte Count (BCC) */

  }

}

void
dissect_write_file_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  guint8        WordCount;
  guint8        BufferFormat;
  guint32       Offset;
  guint16       Remaining;
  guint16       FID;
  guint16       DataLength;
  guint16       Count;
  guint16       ByteCount;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: FID */

    FID = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "FID: %u", FID);

    }

    offset += 2; /* Skip FID */

    /* Build display for: Count */

    Count = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Count: %u", Count);

    }

    offset += 2; /* Skip Count */

    /* Build display for: Offset */

    Offset = GWORD(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 4, "Offset: %u", Offset);

    }

    offset += 4; /* Skip Offset */

    /* Build display for: Remaining */

    Remaining = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Remaining: %u", Remaining);

    }

    offset += 2; /* Skip Remaining */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

    /* Build display for: Buffer Format */

    BufferFormat = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Buffer Format: %u", BufferFormat);

    }

    offset += 1; /* Skip Buffer Format */

    /* Build display for: Data Length */

    DataLength = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Data Length: %u", DataLength);

    }

    offset += 2; /* Skip Data Length */

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Count */

    Count = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Count: %u", Count);

    }

    offset += 2; /* Skip Count */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

}

void
dissect_read_mpx_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *arent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  guint8        WordCount;
  guint8        Pad;
  guint32       Reserved1;
  guint32       Offset;
  guint16       Reserved2;
  guint16       Reserved;
  guint16       MinCount;
  guint16       MaxCount;
  guint16       FID;
  guint16       DataOffset;
  guint16       DataLength;
  guint16       DataCompactionMode;
  guint16       Count;
  guint16       ByteCount;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: FID */

    FID = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "FID: %u", FID);

    }

    offset += 2; /* Skip FID */

    /* Build display for: Offset */

    Offset = GWORD(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 4, "Offset: %u", Offset);

    }

    offset += 4; /* Skip Offset */

    /* Build display for: Max Count */

    MaxCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Max Count: %u", MaxCount);

    }

    offset += 2; /* Skip Max Count */

    /* Build display for: Min Count */

    MinCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Min Count: %u", MinCount);

    }

    offset += 2; /* Skip Min Count */

    /* Build display for: Reserved 1 */

    Reserved1 = GWORD(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 4, "Reserved 1: %u", Reserved1);

    }

    offset += 4; /* Skip Reserved 1 */

    /* Build display for: Reserved 2 */

    Reserved2 = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Reserved 2: %u", Reserved2);

    }

    offset += 2; /* Skip Reserved 2 */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count: %u", WordCount);

    }

    offset += 1; /* Skip Word Count */

    if (WordCount > 0) {

      /* Build display for: Offset */

      Offset = GWORD(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 4, "Offset: %u", Offset);

      }

      offset += 4; /* Skip Offset */

      /* Build display for: Count */

      Count = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Count: %u", Count);

      }

      offset += 2; /* Skip Count */

      /* Build display for: Reserved */

      Reserved = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Reserved: %u", Reserved);

      }

      offset += 2; /* Skip Reserved */

      /* Build display for: Data Compaction Mode */

      DataCompactionMode = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Data Compaction Mode: %u", DataCompactionMode);

      }

      offset += 2; /* Skip Data Compaction Mode */

      /* Build display for: Reserved */

      Reserved = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Reserved: %u", Reserved);

      }

      offset += 2; /* Skip Reserved */

      /* Build display for: Data Length */

      DataLength = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Data Length: %u", DataLength);

      }

      offset += 2; /* Skip Data Length */

      /* Build display for: Data Offset */

      DataOffset = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Data Offset: %u", DataOffset);

      }

      offset += 2; /* Skip Data Offset */

    }

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

    /* Build display for: Pad */

    Pad = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Pad: %u", Pad);

    }

    offset += 1; /* Skip Pad */

  }

}

void
dissect_delete_file_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *paernt, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  guint8        WordCount;
  guint8        BufferFormat;
  guint16       ByteCount;
  const char    *FileName;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

    /* Build display for: Buffer Format */

    BufferFormat = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Buffer Format: %u", BufferFormat);

    }

    offset += 1; /* Skip Buffer Format */

    /* Build display for: File Name */

    FileName = pd + offset;

    if (tree) {

      proto_tree_add_text(tree, offset, strlen(FileName) + 1, "File Name: %s", FileName);

    }

    offset += strlen(FileName) + 1; /* Skip File Name */

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

}

void
dissect_query_info2_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  proto_tree    *Attributes_tree;
  proto_item    *ti;
  guint8        WordCount;
  guint32       FileDataSize;
  guint32       FileAllocationSize;
  guint16       LastWriteTime;
  guint16       LastWriteDate;
  guint16       LastAccessTime;
  guint16       LastAccessDate;
  guint16       FID;
  guint16       CreationTime;
  guint16       CreationDate;
  guint16       ByteCount;
  guint16       Attributes;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: FID */

    FID = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "FID: %u", FID);

    }

    offset += 2; /* Skip FID */

    /* Build display for: Byte Count */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count: %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count */

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    if (WordCount > 0) {

      /* Build display for: Creation Date */

      CreationDate = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Creation Date: %u", dissect_dos_date(CreationDate));

      }

      offset += 2; /* Skip Creation Date */

      /* Build display for: Creation Time */

      CreationTime = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Creation Time: %u", dissect_dos_time(CreationTime));

      }

      offset += 2; /* Skip Creation Time */

      /* Build display for: Last Access Date */

      LastAccessDate = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Last Access Date: %u", dissect_dos_date(LastAccessDate));

      }

      offset += 2; /* Skip Last Access Date */

      /* Build display for: Last Access Time */

      LastAccessTime = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Last Access Time: %u", dissect_dos_time(LastAccessTime));

      }

      offset += 2; /* Skip Last Access Time */

      /* Build display for: Last Write Date */

      LastWriteDate = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Last Write Date: %u", dissect_dos_date(LastWriteDate));

      }

      offset += 2; /* Skip Last Write Date */

      /* Build display for: Last Write Time */

      LastWriteTime = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Last Write Time: %u", dissect_dos_time(LastWriteTime));

      }

      offset += 2; /* Skip Last Write Time */

      /* Build display for: File Data Size */

      FileDataSize = GWORD(pd, offset);

      if (tree) {
	
	proto_tree_add_text(tree, offset, 4, "File Data Size: %u", FileDataSize);

      }

      offset += 4; /* Skip File Data Size */

      /* Build display for: File Allocation Size */

      FileAllocationSize = GWORD(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 4, "File Allocation Size: %u", FileAllocationSize);

      }

      offset += 4; /* Skip File Allocation Size */

      /* Build display for: Attributes */

      Attributes = GSHORT(pd, offset);
      
      if (tree) {

	ti = proto_tree_add_text(tree, offset, 2, "Attributes: 0x%02x", Attributes);
	Attributes_tree = proto_item_add_subtree(ti, ett_smb_fileattributes);
	proto_tree_add_text(Attributes_tree, offset, 2, "%s",
			    decode_boolean_bitfield(Attributes, 0x01, 16, "Read-only file", "Not a read-only file"));
	proto_tree_add_text(Attributes_tree, offset, 2, "%s",
			    decode_boolean_bitfield(Attributes, 0x02, 16, "Hidden file", "Not a hidden file"));
	proto_tree_add_text(Attributes_tree, offset, 2, "%s",
			    decode_boolean_bitfield(Attributes, 0x04, 16, "System file", "Not a system file"));
	proto_tree_add_text(Attributes_tree, offset, 2, "%s",
			    decode_boolean_bitfield(Attributes, 0x08, 16, " Volume", "Not a volume"));
	proto_tree_add_text(Attributes_tree, offset, 2, "%s",
			    decode_boolean_bitfield(Attributes, 0x10, 16, " Directory", "Not a directory"));
	proto_tree_add_text(Attributes_tree, offset, 2, "%s",
			    decode_boolean_bitfield(Attributes, 0x20, 16, " Archived", "Not archived"));
    
      }

      offset += 2; /* Skip Attributes */

    }

    /* Build display for: Byte Count */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count: %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count */

  }

}

void
dissect_treecon_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  guint8        WordCount;
  guint8        BufferFormat3;
  guint8        BufferFormat2;
  guint8        BufferFormat1;
  guint16       TID;
  guint16       MaxBufferSize;
  guint16       ByteCount;
  const char    *SharePath;
  const char    *Service;
  const char    *Password;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

    /* Build display for: BufferFormat1 */

    BufferFormat1 = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "BufferFormat1: %u", BufferFormat1);

    }

    offset += 1; /* Skip BufferFormat1 */

    /* Build display for: Share Path */

    SharePath = pd + offset;

    if (tree) {

      proto_tree_add_text(tree, offset, strlen(SharePath) + 1, "Share Path: %s", SharePath);

    }

    offset += strlen(SharePath) + 1; /* Skip Share Path */

    /* Build display for: BufferFormat2 */

    BufferFormat2 = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "BufferFormat2: %u", BufferFormat2);

    }

    offset += 1; /* Skip BufferFormat2 */

    /* Build display for: Password */

    Password = pd + offset;

    if (tree) {

      proto_tree_add_text(tree, offset, strlen(Password), "Password: %s", Password);

    }

    offset += strlen(Password); /* Skip Password */

    /* Build display for: BufferFormat3 */

    BufferFormat3 = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "BufferFormat3: %u", BufferFormat3);

    }

    offset += 1; /* Skip BufferFormat3 */

    /* Build display for: Service */

    Service = pd + offset;

    if (tree) {

      proto_tree_add_text(tree, offset, strlen(Service) + 1, "Service: %s", Service);
      proto_tree_add_text(tree, offset, strlen(Service) + 1, "Service Description: %s",lookup_service_description(Service));

    }

    offset += strlen(Service) + 1; /* Skip Service */

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    if (errcode != 0) return;

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Max Buffer Size */

    MaxBufferSize = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Max Buffer Size: %u", MaxBufferSize);

    }

    offset += 2; /* Skip Max Buffer Size */

    /* Build display for: TID */

    TID = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "TID: %u", TID);

    }

    offset += 2; /* Skip TID */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

}

/* Generated by build-dissect.pl Vesion 0.6 27-Jun-1999, ACT */
void
dissect_ssetup_andx_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  proto_tree    *Capabilities_tree;
  proto_item    *ti;
  guint8        WordCount;
  guint8        AndXReserved;
  guint8        AndXCommand = 0xFF;
  guint8        Pad1;
  guint32       SessionKey;
  guint32       Reserved;
  guint32       Capabilities;
  guint16       VcNumber;
  guint16       UNICODEAccountPasswordLength;
  guint16       PasswordLen;
  guint16       MaxMpxCount;
  guint16       MaxBufferSize;
  guint16       ByteCount;
  guint16       AndXOffset = 0;
  guint16       Action;
  guint16       ANSIAccountPasswordLength;
  const char    *UNICODEPassword;
  const char    *Password;
  const char    *PrimaryDomain;
  const char    *NativeOS;
  const char    *NativeLanManType;
  const char    *NativeLanMan;
  const char    *AccountName;
  const char    *ANSIPassword;

  guint16       Flags2;
  char          *passstr;
  char          *ustr;
  int           ustr_len;

  /* obtain the Flags2 settings */
  Flags2 = GSHORT(pd, Flags2_Offset);


  if (dirn == 1) { /* Request(s) dissect code */

    WordCount = GBYTE(pd, offset);

    switch (WordCount) {

    case 10:

      /* Build display for: Word Count (WCT) */

      WordCount = GBYTE(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

      }

      offset += 1; /* Skip Word Count (WCT) */

      /* Build display for: AndXCommand */

      AndXCommand = GBYTE(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 1, "AndXCommand: %s", 
			    (AndXCommand == 0xFF ? "No further commands" : decode_smb_name(AndXCommand)));

      }

      offset += 1; /* Skip AndXCommand */

      /* Build display for: AndXReserved */

      AndXReserved = GBYTE(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 1, "AndXReserved: %u", AndXReserved);

      }

      offset += 1; /* Skip AndXReserved */

      /* Build display for: AndXOffset */

      AndXOffset = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "AndXOffset: %u", AndXOffset);

      }

      offset += 2; /* Skip AndXOffset */

      /* Build display for: MaxBufferSize */

      MaxBufferSize = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "MaxBufferSize: %u", MaxBufferSize);

      }

      offset += 2; /* Skip MaxBufferSize */

      /* Build display for: MaxMpxCount */

      MaxMpxCount = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "MaxMpxCount: %u", MaxMpxCount);

      }

      offset += 2; /* Skip MaxMpxCount */

      /* Build display for: VcNumber */

      VcNumber = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "VcNumber: %u", VcNumber);

      }

      offset += 2; /* Skip VcNumber */

      /* Build display for: SessionKey */

      SessionKey = GWORD(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 4, "SessionKey: %u", SessionKey);

      }

      offset += 4; /* Skip SessionKey */

      /* Build display for: PasswordLen */

      PasswordLen = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "PasswordLen: %u", PasswordLen);

      }

      offset += 2; /* Skip PasswordLen */

      /* Build display for: Reserved */

      Reserved = GWORD(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 4, "Reserved: %u", Reserved);

      }

      offset += 4; /* Skip Reserved */

      /* Build display for: Byte Count (BCC) */

      ByteCount = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

      }

      offset += 2; /* Skip Byte Count (BCC) */

      if (ByteCount > 0) {

 	/* Build displat for: Password */

        Password = pd + offset;

	if (tree) {
          passstr=g_malloc(PasswordLen+1);
          strncpy(passstr, Password, PasswordLen);
          passstr[PasswordLen+1]='\0';
          proto_tree_add_text(tree, offset, PasswordLen, "Password: %s", passstr);
          g_free(passstr);
	}

	offset += PasswordLen;

	/* Build display for: AccountName */

	AccountName = pd + offset;

	if (tree) {

	  proto_tree_add_text(tree, offset, strlen(AccountName) + 1, "AccountName: %s", AccountName);

	}

	offset += strlen(AccountName) + 1; /* Skip AccountName */

	/* Build display for: PrimaryDomain */

	PrimaryDomain = pd + offset;

	if (tree) {

	  proto_tree_add_text(tree, offset, strlen(PrimaryDomain) + 1, "PrimaryDomain: %s", PrimaryDomain);

	}

	offset += strlen(PrimaryDomain) + 1; /* Skip PrimaryDomain */

	/* Build display for: NativeOS */

	NativeOS = pd + offset;

	if (tree) {

	  proto_tree_add_text(tree, offset, strlen(NativeOS) + 1, "Native OS: %s", NativeOS);

	}

	offset += strlen(NativeOS) + 1; /* Skip NativeOS */

	/* Build display for: NativeLanMan */

	NativeLanMan = pd + offset;

	if (tree) {

	  proto_tree_add_text(tree, offset, strlen(NativeLanMan) + 1, "Native Lan Manager: %s", NativeLanMan);

	}

	offset += strlen(NativeLanMan) + 1; /* Skip NativeLanMan */

      }

    break;

    case 13:

      /* Build display for: Word Count (WCT) */

      WordCount = GBYTE(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

      }

      offset += 1; /* Skip Word Count (WCT) */

      /* Build display for: AndXCommand */

      AndXCommand = GBYTE(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 1, "AndXCommand: %s", 
			    (AndXCommand == 0xFF ? "No further commands" : decode_smb_name(AndXCommand)));

      }

      offset += 1; /* Skip AndXCommand */

      /* Build display for: AndXReserved */

      AndXReserved = GBYTE(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 1, "AndXReserved: %u", AndXReserved);

      }

      offset += 1; /* Skip AndXReserved */

      /* Build display for: AndXOffset */

      AndXOffset = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "AndXOffset: %u", AndXOffset);

      }

      offset += 2; /* Skip AndXOffset */

      /* Build display for: MaxBufferSize */

      MaxBufferSize = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "MaxBufferSize: %u", MaxBufferSize);

      }

      offset += 2; /* Skip MaxBufferSize */

      /* Build display for: MaxMpxCount */

      MaxMpxCount = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "MaxMpxCount: %u", MaxMpxCount);

      }

      offset += 2; /* Skip MaxMpxCount */

      /* Build display for: VcNumber */

      VcNumber = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "VcNumber: %u", VcNumber);

      }

      offset += 2; /* Skip VcNumber */

      /* Build display for: SessionKey */

      SessionKey = GWORD(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 4, "SessionKey: %u", SessionKey);

      }

      offset += 4; /* Skip SessionKey */

      /* Build display for: ANSI Account Password Length */

      ANSIAccountPasswordLength = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "ANSI Account Password Length: %u", ANSIAccountPasswordLength);


      }

      offset += 2; /* Skip ANSI Account Password Length */

      /* Build display for: UNICODE Account Password Length */

      UNICODEAccountPasswordLength = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "UNICODE Account Password Length: %u", UNICODEAccountPasswordLength);

      }

      offset += 2; /* Skip UNICODE Account Password Length */

      /* Build display for: Reserved */

      Reserved = GWORD(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 4, "Reserved: %u", Reserved);

      }

      offset += 4; /* Skip Reserved */

      /* Build display for: Capabilities */

      Capabilities = GWORD(pd, offset);

      if (tree) {

        ti = proto_tree_add_text(tree, offset, 4, "Capabilities: 0x%04x", Capabilities);
        Capabilities_tree = proto_item_add_subtree(ti, ett_smb_capabilities);
        proto_tree_add_text(Capabilities_tree, offset, 4, "%s",
                            decode_boolean_bitfield(Capabilities, 0x0001, 32, " Raw Mode supported", " Raw Mode not supported"));
        proto_tree_add_text(Capabilities_tree, offset, 4, "%s",
                            decode_boolean_bitfield(Capabilities, 0x0002, 32, " Raw Mode supported", " MPX Mode not supported"));
        proto_tree_add_text(Capabilities_tree, offset, 4, "%s",
                            decode_boolean_bitfield(Capabilities, 0x0004, 32," Unicode supported", " Unicode not supported"));
        proto_tree_add_text(Capabilities_tree, offset, 4, "%s",
                            decode_boolean_bitfield(Capabilities, 0x0008, 32, " Large Files supported", " Large Files not supported"));
        proto_tree_add_text(Capabilities_tree, offset, 4, "%s",
                            decode_boolean_bitfield(Capabilities, 0x0010, 32, " NT LM 0.12 SMBs supported", " NT LM 0.12 SMBs not supported"));
        proto_tree_add_text(Capabilities_tree, offset, 4, "%s",
                            decode_boolean_bitfield(Capabilities, 0x0020, 32, " RPC Remote APIs supported", " RPC Remote APIs not supported"));
        proto_tree_add_text(Capabilities_tree, offset, 4, "%s",
                            decode_boolean_bitfield(Capabilities, 0x0040, 32, " NT Status Codes supported", " NT Status Codes not supported"));
        proto_tree_add_text(Capabilities_tree, offset, 4, "%s",
                            decode_boolean_bitfield(Capabilities, 0x0080, 32, " Level 2 OpLocks supported", " Level 2 OpLocks not supported"));
        proto_tree_add_text(Capabilities_tree, offset, 4, "%s",
                            decode_boolean_bitfield(Capabilities, 0x0100, 32, " Lock&Read supported", " Lock&Read not supported"));
        proto_tree_add_text(Capabilities_tree, offset, 4, "%s",
                            decode_boolean_bitfield(Capabilities, 0x0200, 32, " NT Find supported", " NT Find not supported"));
        proto_tree_add_text(Capabilities_tree, offset, 4, "%s",
                            decode_boolean_bitfield(Capabilities, 0x1000, 32, " DFS supported", " DFS not supported"));
        proto_tree_add_text(Capabilities_tree, offset, 4, "%s",
                            decode_boolean_bitfield(Capabilities, 0x4000, 32, " Large READX supported", " Large READX not supported"));
        proto_tree_add_text(Capabilities_tree, offset, 4, "%s",
                            decode_boolean_bitfield(Capabilities, 0x8000, 32, " Large WRITEX supported", " Large WRITEX not supported"));
        proto_tree_add_text(Capabilities_tree, offset, 4, "%s",
                            decode_boolean_bitfield(Capabilities, 0x80000000, 32, " Extended Security Exchanges supported", " Extended Security Exchanges not supported"));
      
}

      offset += 4; /* Skip Capabilities */

      /* Build display for: Byte Count */

      ByteCount = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "Byte Count: %u", ByteCount);

      }

      offset += 2; /* Skip Byte Count */

      if (ByteCount > 0) {

	/* Build display for: ANSI Password */

	ANSIPassword = pd + offset;

	if (tree) {
          passstr=g_malloc(ANSIAccountPasswordLength+1);
          strncpy(passstr, ANSIPassword, ANSIAccountPasswordLength);
          passstr[ANSIAccountPasswordLength+1]='\0';
          proto_tree_add_text(tree, offset, ANSIAccountPasswordLength, "ANSI Password: %s", passstr);
          g_free(passstr);
	}

	offset += ANSIAccountPasswordLength; /* Skip ANSI Password */
	if (ANSIAccountPasswordLength == 0) offset++;  /* Add 1 */

	/* Build display for: UNICODE Password */

	UNICODEPassword = pd + offset;

	if (UNICODEAccountPasswordLength > 0) {

	  if (tree) {
            passstr=g_malloc(UNICODEAccountPasswordLength+1);
            strncpy(passstr, UNICODEPassword, UNICODEAccountPasswordLength);
            passstr[UNICODEAccountPasswordLength+1]='\0';
            proto_tree_add_text(tree, offset, UNICODEAccountPasswordLength, "UNICODE Password: %s", passstr);
            g_free(passstr);
	  }

	  offset += UNICODEAccountPasswordLength; /* Skip UNICODE Password */

	}

        if (Capabilities & 0x0004) {
          if (offset % 2) {

          /* Build display for: Pad1 */
          /* Need to pad out because of Unicode strings start on a
             even boundary                                         */

             Pad1 = GBYTE(pd, offset);
             if (tree) {
                proto_tree_add_text(tree, offset, 1, "Pad1: %u", Pad1);

             }
             offset += 1;
          }
        }

        /* Build display for: Account Name */

        /* The AccountName, a null terminated string; Unicode if "caps" has
           the 0x0004 bit set, ASCII (OEM character set) otherwise.
           XXX - for now, we just handle the ISO 8859-1 subset of Unicode. */

        AccountName = pd + offset;
        if (tree) {
          if (Capabilities & 0x0004) {
            ustr = unicode_to_str(AccountName, &ustr_len);
            proto_tree_add_text(tree, offset, ustr_len+2, "Account Name: %s", ustr);
            offset += (strlen(ustr)*2) + 2; /* Skip Account Name */
          } else {
            proto_tree_add_text(tree, offset, strlen(AccountName) + 1, "Account Name: %s", AccountName);
            offset += strlen(AccountName) + 1; /* Skip Account Name */
          }
        }


        /* Build display for: Primary Domain */

        /* The Primary Domain, a null terminated string; Unicode if "caps" has
           the 0x0004 bit set, ASCII (OEM character set) otherwise.
           XXX - for now, we just handle the ISO 8859-1 subset of Unicode. */

          PrimaryDomain = pd + offset;

        if (tree) {
          if (Capabilities & 0x0004) {
            ustr = unicode_to_str(PrimaryDomain, &ustr_len);
            proto_tree_add_text(tree, offset, ustr_len+2, "Primary Domain: %s", ustr);
            offset += (strlen(ustr)*2) + 2; /* Skip Primary Domain */
          } else {
            proto_tree_add_text(tree, offset, strlen(PrimaryDomain) + 1, "Primary Domain: %s", PrimaryDomain);
            offset += strlen(PrimaryDomain) + 1; /* Skip Primary Domain */
          }
        }


        /* Build display for: Native OS */

        /* The NativeOS, a null terminated string; Unicode if "caps" has
           the 0x0004 bit set, ASCII (OEM character set) otherwise.
           XXX - for now, we just handle the ISO 8859-1 subset of Unicode. */

          NativeOS = pd + offset;

        if (tree) {
          if (Capabilities & 0x0004) {
            ustr = unicode_to_str(NativeOS, &ustr_len);
            proto_tree_add_text(tree, offset, ustr_len+2, "Native OS: %s", ustr);
            offset += (strlen(ustr)*2) + 2; /* Skip Native OS */
            offset += 2; /* Skip EXTRA bytes */
          } else {
            proto_tree_add_text(tree, offset, strlen(NativeOS) + 1, "Native OS: %s", NativeOS);
            offset += strlen(NativeOS) + 1; /* Skip Native OS */
          }
        }


       /* Build display for: Native LanMan Type */

       /* The NativeLanManType, a null terminated string; Unicode if "caps" has
          the 0x0004 bit set, ASCII (OEM character set) otherwise.
          XXX - for now, we just handle the ISO 8859-1 subset of Unicode. */

         NativeLanManType = pd + offset;

        if (tree) {
          if (Capabilities & 0x0004) {
            ustr = unicode_to_str(NativeLanManType, &ustr_len);
            proto_tree_add_text(tree, offset, ustr_len+2, "Native LanMan Type: %s", ustr);
            offset += (strlen(ustr)*2) + 2; /* Skip Native LanMan Type */
            offset += 2; /* Skip EXTRA bytes */
          } else {
            proto_tree_add_text(tree, offset, strlen(NativeLanManType) + 1, "Native LanMan Type: %s", NativeLanManType);
            offset += strlen(NativeLanManType) + 1; /* Skip Native LanMan Type */
          }
        }

      }

      break;

    }


    if (AndXCommand != 0xFF) {

      (dissect[AndXCommand])(pd, SMB_offset + AndXOffset, fd, parent, tree, si, max_data, SMB_offset, errcode, dirn);

    }

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    if (WordCount > 0) {

      /* Build display for: AndXCommand */

      AndXCommand = GBYTE(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 1, "AndXCommand: %s",
			    (AndXCommand == 0xFF ? "No futher commands" : decode_smb_name(AndXCommand)));

      }

      offset += 1; /* Skip AndXCommand */

      /* Build display for: AndXReserved */

      AndXReserved = GBYTE(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 1, "AndXReserved: %u", AndXReserved);

      }

      offset += 1; /* Skip AndXReserved */

      /* Build display for: AndXOffset */

      AndXOffset = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "AndXOffset: %u", AndXOffset);

      }


      offset += 2; /* Skip AndXOffset */

      /* Build display for: Action */

      Action = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Action: %u", Action);

      }

      offset += 2; /* Skip Action */

    }

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    if (errcode != 0 && WordCount == 0xFF) return;  /* No more here ... */

    offset += 2; /* Skip Byte Count (BCC) */

    if (ByteCount > 0) {

      /* Build display for: Native OS */

      /* The NativeOS, a null terminated string; Unicode if "Flags" has
         the 0x8000 bit set, ASCII (OEM character set) otherwise.
         XXX - for now, we just handle the ISO 8859-1 subset of Unicode. */

       if (Flags2 & 0x8000) {
          offset += 1; /* Skip EXTRA Byte for unicode only */
       }
       NativeOS = pd + offset;

       if (tree) {
        if (Flags2 & 0x8000) {
          ustr = unicode_to_str(NativeOS, &ustr_len);
          proto_tree_add_text(tree, offset, ustr_len+2, "Native OS: %s", ustr);
          offset += (strlen(ustr)*2) + 2; /* Skip Native OS */
        } else {
          proto_tree_add_text(tree, offset, strlen(NativeOS) + 1, "Native OS: %s", NativeOS);
          offset += strlen(NativeOS) + 1; /* Skip Native OS */
        }
       }


      /* Build display for: NativeLanMan */

      /* The NativeLanManType, a null terminated string; Unicode if "Flags" has
         the 0x8000 bit set, ASCII (OEM character set) otherwise.
         XXX - for now, we just handle the ISO 8859-1 subset of Unicode. */

        NativeLanManType = pd + offset;

       if (tree) {
        if (Flags2 & 0x8000) {
          ustr = unicode_to_str(NativeLanManType, &ustr_len);
          proto_tree_add_text(tree, offset, ustr_len+2, "NativeLanManType: %s", ustr);
          offset += (strlen(ustr)*2) + 2; /* Skip Native LanMan Type */
        } else {
          proto_tree_add_text(tree, offset, strlen(NativeLanManType) + 1, "Native LanMan Type: %s", NativeLanManType);
          offset += strlen(NativeLanManType) + 1; /* Skip Native LanMan Type */
        }
       }


      /* Build display for: PrimaryDomain */

      /* The Primary Domain, a null terminated string; Unicode if "caps" has
         the 0x8000 bit set, ASCII (OEM character set) otherwise.
         XXX - for now, we just handle the ISO 8859-1 subset of Unicode. */

        PrimaryDomain = pd + offset;

       if (tree) {
        if (Flags2 & 0x8000) {
          ustr = unicode_to_str(PrimaryDomain, &ustr_len);
          proto_tree_add_text(tree, offset, ustr_len+2, "Primary Domain: %s", ustr);
          offset += (strlen(ustr)*2) + 2; /* Skip Primary Domain */
        } else {
          proto_tree_add_text(tree, offset, strlen(PrimaryDomain) + 1, "Primary Domain: %s", PrimaryDomain);
          offset += strlen(PrimaryDomain) + 1; /* Skip Primary Domain */
        }
       }

    }

    if (AndXCommand != 0xFF) {

      (dissect[AndXCommand])(pd, SMB_offset + AndXOffset, fd, parent, tree, si, max_data, SMB_offset, errcode, dirn);

    }

  }

}

void
dissect_tcon_andx_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  guint8      wct, andxcmd = 0xFF;
  guint16     andxoffs = 0, flags, passwdlen, bcc, optionsup;
  const char  *str;
  proto_tree  *flags_tree;
  proto_item  *ti;

  char        *passstr;
  char        *ustr;
  int         ustr_len;
  guint32     Capabilities;
  guint16     Flags2;

  /* obtain the Flags2 settings */
  Flags2 = GSHORT(pd, Flags2_Offset);

 /* Obtain Capabilities flags */
  Capabilities = GWORD(pd, Cap_Offset);


  wct = pd[offset];

  /* Now figure out what format we are talking about, 2, 3, or 4 response
   * words ...
   */

  if (!((dirn == 1) && (wct == 4)) && !((dirn == 0) && (wct == 2)) &&
      !((dirn == 0) && (wct == 3)) && !(wct == 0)) {

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Invalid TCON_ANDX format. WCT should be 0, 2, 3, or 4 ..., not %u", wct);

      proto_tree_add_text(tree, offset, END_OF_FRAME, "Data");

      return;

    }
    
  }

  if (tree) {

    proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", wct);

  }

  offset += 1;

  if (wct > 0) {

    andxcmd = pd[offset];

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Next Command: %s",
			  (andxcmd == 0xFF) ? "No further commands":
			  decode_smb_name(andxcmd));
		
      proto_tree_add_text(tree, offset + 1, 1, "Reserved (MBZ): %u", pd[offset+1]);

    }

    offset += 2;

    andxoffs = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Offset to next command: %u", andxoffs);

    }

    offset += 2;

  }

  switch (wct) {

  case 0:

    bcc = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", bcc);

    }

    break;

  case 4:

    flags = GSHORT(pd, offset);

    if (tree) {

      ti = proto_tree_add_text(tree, offset, 2, "Additional Flags: 0x%02x", flags);
      flags_tree = proto_item_add_subtree(ti, ett_smb_aflags);
      proto_tree_add_text(flags_tree, offset, 2, "%s", 
			  decode_boolean_bitfield(flags, 0x01, 16,
						  "Disconnect TID",
						  "Don't disconnect TID"));

    }

    offset += 2;

    passwdlen = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Password Length: %u", passwdlen);

    }

    offset += 2;

    bcc = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", bcc);

    }

    offset += 2;

    str = pd + offset;

    if (tree) {
      passstr=g_malloc(passwdlen+1);
      strncpy(passstr, str, passwdlen);
      passstr[passwdlen+1]='\0';
      proto_tree_add_text(tree, offset, passwdlen, "Password: %s", passstr);
      g_free(passstr);
    }

    offset += passwdlen;

    /* Build display for: Path */

    /* The Path, a null terminated string; Unicode if "caps" has
       the 0x0004 bit set, ASCII (OEM character set) otherwise.
       XXX - for now, we just handle the ISO 8859-1 subset of Unicode. */

     str = pd + offset;

     if (tree) {
      if (Capabilities & 0x0004) {
        ustr = unicode_to_str(str, &ustr_len);
        proto_tree_add_text(tree, offset, ustr_len+2, "Path: %s", ustr);
        offset += (strlen(ustr)*2) + 2; /* Skip Path OS */
      } else {
        proto_tree_add_text(tree, offset, strlen(str) + 1, "Path: %s", str);
        offset += strlen(str) + 1; /* Skip Path */
      }
     }


    /* Build display for: Service */

    str = pd + offset;

    if (tree) {

      proto_tree_add_text(tree, offset, strlen(str) + 1, "Service: %s", str);
      proto_tree_add_text(tree, offset, strlen(str) + 1, "Service Description: %s",lookup_service_description(str));

    }
    offset += strlen(str) + 1; /* Skip Service */
    break;

  case 2:

    bcc = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", bcc);

    }

    offset += 2;

    str = pd + offset;

    if (tree) {

      proto_tree_add_text(tree, offset, strlen(str) + 1, "Service Type: %s",str);
      proto_tree_add_text(tree, offset, strlen(str) + 1, "Service Description: %s",lookup_service_description(str));

    }

    offset += strlen(str) + 1;

    break;

  case 3:

    optionsup = GSHORT(pd, offset);

    if (tree) {  /* Should break out the bits */

      proto_tree_add_text(tree, offset, 2, "Optional Support: 0x%04x", 
			  optionsup);

    }

    offset += 2;

    bcc = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", bcc);

    }

    offset += 2;

    str = pd + offset;

    if (tree) {

      proto_tree_add_text(tree, offset, strlen(str) + 1, "Service: %s", str);
      proto_tree_add_text(tree, offset, strlen(str) + 1, "Service Description: %s",lookup_service_description(str));

    }

    offset += strlen(str) + 1;

    /* Build display for: Native File System */

    /* The Native File System, a null terminated string; Unicode if "caps" has
       the 0x8000 bit set, ASCII (OEM character set) otherwise.
       XXX - for now, we just handle the ISO 8859-1 subset of Unicode. */

    str = pd + offset;

    if (tree) {
      if (Flags2 & 0x8000) {
        ustr = unicode_to_str(str, &ustr_len);
        proto_tree_add_text(tree, offset, ustr_len+2, "Native File System: %s", ustr);
        offset += (strlen(ustr)*2) + 2; /* Skip Native File System */
      } else {
        proto_tree_add_text(tree, offset, strlen(str) + 1, "Native File System: %s", str);
        offset += strlen(str) + 1;
      }
    }

    break;

  default:
	; /* nothing */
	break;
  }

  if (andxcmd != 0xFF) /* Process that next command ... ??? */

    (dissect[andxcmd])(pd, SMB_offset + andxoffs, fd, parent, tree, si, max_data - offset, SMB_offset, errcode, dirn);

}

void 
dissect_negprot_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)
{
  guint8        wct, enckeylen;
  guint16       bcc, mode, rawmode, dialect;
  guint32       caps;
  proto_tree    *dialects = NULL, *mode_tree, *caps_tree, *rawmode_tree;
  proto_item    *ti;
  const char    *str;
  char          *ustr;
  int           ustr_len;

  wct = pd[offset];    /* Should be 0, 1 or 13 or 17, I think */

  if (!((wct == 0) && (dirn == 1)) && !((wct == 1) && (dirn == 0)) &&
      !((wct == 13) && (dirn == 0)) && !((wct == 17) && (dirn == 0))) {
    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Invalid Negotiate Protocol format. WCT should be zero or 1 or 13 or 17 ..., not %u", wct);

      proto_tree_add_text(tree, offset, END_OF_FRAME, "Data");

      return;
    }
  }

  if (tree) {

    proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %d", wct);

  }

  if (dirn == 0 && errcode != 0) return;  /* No more info ... */

  offset += 1; 

  /* Now decode the various formats ... */

  switch (wct) {

  case 0:     /* A request */

    bcc = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", bcc);

    }

    offset += 2;

    if (tree) {

      ti = proto_tree_add_text(tree, offset, END_OF_FRAME, "Dialects");
      dialects = proto_item_add_subtree(ti, ett_smb_dialects);

    }

    while (IS_DATA_IN_FRAME(offset)) {
      const char *str;

      if (tree) {

	proto_tree_add_text(dialects, offset, 1, "Dialect Marker: %d", pd[offset]);

      }

      offset += 1;

      str = pd + offset;

      if (tree) {

	proto_tree_add_text(dialects, offset, strlen(str)+1, "Dialect: %s", str);

      }

      offset += strlen(str) + 1;

    }
    break;

  case 1:     /* PC NETWORK PROGRAM 1.0 */

    dialect = GSHORT(pd, offset);

    if (tree) {  /* Hmmmm, what if none of the dialects is recognized */

      if (dialect == 0xFFFF) { /* Server didn't like them dialects */

	proto_tree_add_text(tree, offset, 2, "Supplied dialects not recognized");

      }
      else {

	proto_tree_add_text(tree, offset, 2, "Dialect Index: %u, PC NETWORK PROTGRAM 1.0", dialect);

      }

    }

    offset += 2;

    bcc = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", bcc);

    }

    break;

  case 13:    /* Greater than Core and up to and incl LANMAN2.1  */

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Dialect Index: %u, Greater than CORE PROTOCOL and up to LANMAN2.1", GSHORT(pd, offset));

    }

    /* Much of this is similar to response 17 below */

    offset += 2;

    mode = GSHORT(pd, offset);

    if (tree) {

      ti = proto_tree_add_text(tree, offset, 2, "Security Mode: 0x%04x", mode);
      mode_tree = proto_item_add_subtree(ti, ett_smb_mode);
      proto_tree_add_text(mode_tree, offset, 2, "%s",
			  decode_boolean_bitfield(mode, 0x0001, 16,
						  "Security  = User",
						  "Security  = Share"));
      proto_tree_add_text(mode_tree, offset, 2, "%s",
			  decode_boolean_bitfield(mode, 0x0002, 16,
						  "Passwords = Encrypted",
						  "Passwords = Plaintext"));

    }

    offset += 2;

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Max buffer size:     %u", GSHORT(pd, offset));

    }

    offset += 2;

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Max multiplex count: %u", GSHORT(pd, offset));

    }
    
    offset += 2;

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Max vcs:             %u", GSHORT(pd, offset));

    }

    offset += 2;

    rawmode = GSHORT(pd, offset);

    if (tree) {

      ti = proto_tree_add_text(tree, offset, 2, "Raw Mode: 0x%04x", rawmode);
      rawmode_tree = proto_item_add_subtree(ti, ett_smb_rawmode);
      proto_tree_add_text(rawmode_tree, offset, 2, "%s",
			  decode_boolean_bitfield(rawmode, 0x01, 16,
						  "Read Raw supported",
						  "Read Raw not supported"));
      proto_tree_add_text(rawmode_tree, offset, 2, "%s",
			  decode_boolean_bitfield(rawmode, 0x02, 16,
						  "Write Raw supported",
						  "Write Raw not supported"));

    }

    offset += 2;

    if (tree) {

      proto_tree_add_text(tree, offset, 4, "Session key:         %08x", GWORD(pd, offset));

    }

    offset += 4;

    /* Now the server time, two short parameters ... */

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Server Time: %s",
			dissect_dos_time(GSHORT(pd, offset)));
      proto_tree_add_text(tree, offset + 2, 2, "Server Date: %s",
			dissect_dos_date(GSHORT(pd, offset + 2)));

    }

    offset += 4;

    /* Server Time Zone, SHORT */

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Server time zone: %i min from UTC",
			  (signed)GSSHORT(pd, offset));

    }

    offset += 2;

    /* Challenge Length */

    enckeylen = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Challenge Length: %u", enckeylen);

    }

    offset += 2;

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Reserved: %u (MBZ)", GSHORT(pd, offset));

    }

    offset += 2;

    bcc = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", bcc);

    }

    offset += 2;

    if (enckeylen) { /* only if non-zero key len */

      str = pd + offset;

      if (tree) {

	proto_tree_add_text(tree, offset, enckeylen, "Challenge: %s",
				bytes_to_str(str, enckeylen));
      }

      offset += enckeylen;

    }

    /* Primary Domain ... */

    str = pd + offset;

    if (tree) {

      proto_tree_add_text(tree, offset, strlen(str)+1, "Primary Domain: %s", str);

    }

    break;

  case 17:    /* Greater than LANMAN2.1 */

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Dialect Index: %u, Greater than LANMAN2.1", GSHORT(pd, offset));

    }

    offset += 2;

    mode = GBYTE(pd, offset);

    if (tree) {

      ti = proto_tree_add_text(tree, offset, 1, "Security Mode: 0x%02x", mode);
      mode_tree = proto_item_add_subtree(ti, ett_smb_mode);
      proto_tree_add_text(mode_tree, offset, 1, "%s",
			  decode_boolean_bitfield(mode, 0x01, 8,
						  "Security  = User",
						  "Security  = Share"));
      proto_tree_add_text(mode_tree, offset, 1, "%s",
			  decode_boolean_bitfield(mode, 0x02, 8,
						  "Passwords = Encrypted",
						  "Passwords = Plaintext"));
      proto_tree_add_text(mode_tree, offset, 1, "%s",
			  decode_boolean_bitfield(mode, 0x04, 8,
						  "Security signatures enabled",
						  "Security signatures not enabled"));
      proto_tree_add_text(mode_tree, offset, 1, "%s",
			  decode_boolean_bitfield(mode, 0x08, 8,
						  "Security signatures required",
						  "Security signatures not required"));

    }

    offset += 1;

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Max multiplex count: %u", GSHORT(pd, offset));

    }
    
    offset += 2;

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Max vcs:             %u", GSHORT(pd, offset));

    }

    offset += 2;

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Max buffer size:     %u", GWORD(pd, offset));

    }

    offset += 4;

    if (tree) {

      proto_tree_add_text(tree, offset, 4, "Max raw size:        %u", GWORD(pd, offset));

    }

    offset += 4;

    if (tree) {

      proto_tree_add_text(tree, offset, 4, "Session key:         %08x", GWORD(pd, offset));

    }

    offset += 4;

    caps = GWORD(pd, offset);

    if (tree) {

      ti = proto_tree_add_text(tree, offset, 4, "Capabilities: 0x%04x", caps);
      caps_tree = proto_item_add_subtree(ti, ett_smb_capabilities);
      proto_tree_add_text(caps_tree, offset, 4, "%s",
			  decode_boolean_bitfield(caps, 0x0001, 32,
						  "Raw Mode supported",
						  "Raw Mode not supported"));
      proto_tree_add_text(caps_tree, offset, 4, "%s",
			  decode_boolean_bitfield(caps, 0x0002, 32,
						  "MPX Mode supported",
						  "MPX Mode not supported"));
      proto_tree_add_text(caps_tree, offset, 4, "%s",
			  decode_boolean_bitfield(caps, 0x0004, 32,
						  "Unicode supported",
						  "Unicode not supported"));
      proto_tree_add_text(caps_tree, offset, 4, "%s",
			  decode_boolean_bitfield(caps, 0x0008, 32,
						  "Large files supported",
						  "Large files not supported"));
      proto_tree_add_text(caps_tree, offset, 4, "%s",
			  decode_boolean_bitfield(caps, 0x0010, 32, 
						  "NT LM 0.12 SMBs supported",
						  "NT LM 0.12 SMBs not supported"));
      proto_tree_add_text(caps_tree, offset, 4, "%s",
			  decode_boolean_bitfield(caps, 0x0020, 32,
						  "RPC remote APIs supported",
						  "RPC remote APIs not supported"));
      proto_tree_add_text(caps_tree, offset, 4, "%s",
			  decode_boolean_bitfield(caps, 0x0040, 32,
						  "NT status codes supported",
						  "NT status codes  not supported"));
      proto_tree_add_text(caps_tree, offset, 4, "%s",
			  decode_boolean_bitfield(caps, 0x0080, 32,
						  "Level 2 OpLocks supported",
						  "Level 2 OpLocks not supported"));
      proto_tree_add_text(caps_tree, offset, 4, "%s",
			  decode_boolean_bitfield(caps, 0x0100, 32,
						  "Lock&Read supported",
						  "Lock&Read not supported"));
      proto_tree_add_text(caps_tree, offset, 4, "%s",
			  decode_boolean_bitfield(caps, 0x0200, 32,
						  "NT Find supported",
						  "NT Find not supported"));
      proto_tree_add_text(caps_tree, offset, 4, "%s",
			  decode_boolean_bitfield(caps, 0x1000, 32,
						  "DFS supported",
						  "DFS not supported"));
      proto_tree_add_text(caps_tree, offset, 4, "%s",
			  decode_boolean_bitfield(caps, 0x4000, 32,
						  "Large READX supported",
						  "Large READX not supported"));
      proto_tree_add_text(caps_tree, offset, 4, "%s",
			  decode_boolean_bitfield(caps, 0x8000, 32,
						  "Large WRITEX supported",
						  "Large WRITEX not supported"));
      proto_tree_add_text(caps_tree, offset, 4, "%s",
			  decode_boolean_bitfield(caps, 0x80000000, 32,
						  "Extended security exchanges supported",
						  "Extended security exchanges not supported"));
    }

    offset += 4;

    /* Server time, 2 WORDS */

    if (tree) {

      proto_tree_add_text(tree, offset, 4, "System Time Low: 0x%08x", GWORD(pd, offset));
      proto_tree_add_text(tree, offset + 4, 4, "System Time High: 0x%08x", GWORD(pd, offset + 4)); 

    }

    offset += 8;

    /* Server Time Zone, SHORT */

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Server time zone: %i min from UTC",
			  (signed)GSSHORT(pd, offset));

    }

    offset += 2;

    /* Encryption key len */

    enckeylen = pd[offset];

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Encryption key len: %u", enckeylen);

    }

    offset += 1;

    bcc = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte count (BCC): %u", bcc);

    }

    offset += 2;

    if (enckeylen) { /* only if non-zero key len */

      /* Encryption challenge key */

      str = pd + offset;

      if (tree) {

	proto_tree_add_text(tree, offset, enckeylen, "Challenge encryption key: %s",
				bytes_to_str(str, enckeylen));

      }

      offset += enckeylen;

    }

    /* The domain, a null terminated string; Unicode if "caps" has
       the 0x0004 bit set, ASCII (OEM character set) otherwise.
       XXX - for now, we just handle the ISO 8859-1 subset of Unicode. */

    str = pd + offset;

    if (tree) {

      if (caps & 0x0004) {
      	ustr = unicode_to_str(str, &ustr_len);
	proto_tree_add_text(tree, offset, ustr_len+2, "OEM domain name: %s", ustr);
      } else {
	proto_tree_add_text(tree, offset, strlen(str)+1, "OEM domain name: %s", str);
      }

    }

    break;

  default:    /* Baddd */

    if (tree)
      proto_tree_add_text(tree, offset, 1, "Bad format, should never get here");
    return;

  }

}

void
dissect_deletedir_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  guint8        WordCount;
  guint8        BufferFormat;
  guint16       ByteCount;
  const char    *DirectoryName;

  guint16       Flags2;
  char          *ustr;
  int           ustr_len;


  /* obtain the Flags2 settings */
  Flags2 = GSHORT(pd, Flags2_Offset);


  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

    /* Build display for: Buffer Format */

    BufferFormat = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Buffer Format: %u", BufferFormat);

    }

    offset += 1; /* Skip Buffer Format */

    /* Build display for: Directory Name */

    /* The Directory Name, a null terminated string; Unicode if "Flags" has
       the 0x8000 bit set, ASCII (OEM character set) otherwise.
       XXX - for now, we just handle the ISO 8859-1 subset of Unicode. */

    DirectoryName = pd + offset;

    if (tree) {
      if (Flags2 & 0x8000) {
          ustr = unicode_to_str(DirectoryName, &ustr_len);
          proto_tree_add_text(tree, offset, ustr_len+2, "Directory Name: %s", ustr);
          offset += (strlen(ustr)*2) + 2; /* Skip Directory Name */
      } else {
          proto_tree_add_text(tree, offset, strlen(DirectoryName) + 1, "Directory Name: %s", DirectoryName);
          offset += strlen(DirectoryName) + 1; /* Skip Directory Name */
      }
    }

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

}

void
dissect_createdir_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  guint8        WordCount;
  guint8        BufferFormat;
  guint16       ByteCount;
  const char    *DirectoryName;

  guint16       Flags2;
  char          *ustr;
  int           ustr_len;


  /* obtain the Flags2 settings */
  Flags2 = GSHORT(pd, Flags2_Offset);


  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

    /* Build display for: Buffer Format */

    BufferFormat = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Buffer Format: %u", BufferFormat);

    }

    offset += 1; /* Skip Buffer Format */

    /* Build display for: Directory Name */

    /* The Directory Name, a null terminated string; Unicode if "Flags" has
       the 0x8000 bit set, ASCII (OEM character set) otherwise.
       XXX - for now, we just handle the ISO 8859-1 subset of Unicode. */

    DirectoryName = pd + offset;

    if (tree) {
      if (Flags2 & 0x8000) {
          ustr = unicode_to_str(DirectoryName, &ustr_len);
          proto_tree_add_text(tree, offset, ustr_len+2, "Directory Name: %s", ustr);
          offset += (strlen(ustr)*2) + 2; /* Skip Directory Name */
      } else {
          proto_tree_add_text(tree, offset, strlen(DirectoryName) + 1, "Directory Name: %s", DirectoryName);
          offset += strlen(DirectoryName) + 1; /* Skip Directory Name */
      }
    }
  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

}

void
dissect_checkdir_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  guint8        WordCount;
  guint8        BufferFormat;
  guint16       ByteCount;
  const char    *DirectoryName;

  guint16       Flags2;
  char          *ustr;
  int           ustr_len;


  /* obtain the Flags2 settings */
  Flags2 = GSHORT(pd, Flags2_Offset);


  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

    /* Build display for: Buffer Format */

    BufferFormat = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Buffer Format: %u", BufferFormat);

    }

    offset += 1; /* Skip Buffer Format */

    /* Build display for: Directory Name */

    /* The Directory Name, a null terminated string; Unicode if "Flags" has
       the 0x8000 bit set, ASCII (OEM character set) otherwise.
       XXX - for now, we just handle the ISO 8859-1 subset of Unicode. */

    DirectoryName = pd + offset;

    if (tree) {
      if (Flags2 & 0x8000) {
          ustr = unicode_to_str(DirectoryName, &ustr_len);
          proto_tree_add_text(tree, offset, ustr_len+2, "Directory Name: %s", ustr);
          offset += (strlen(ustr)*2) + 2; /* Skip Directory Name */
      } else {
          proto_tree_add_text(tree, offset, strlen(DirectoryName) + 1, "Directory Name: %s", DirectoryName);
          offset += strlen(DirectoryName) + 1; /* Skip Directory Name */
      }
    }

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

}

void
dissect_open_andx_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  static const value_string OpenFunction_0x10[] = {
	{ 0, "Fail if file does not exist"},
	{ 16, "Create file if it does not exist"},
	{ 0, NULL}
  };
  static const value_string OpenFunction_0x03[] = {
	{ 0, "Fail if file exists"},
	{ 1, "Open file if it exists"},
	{ 2, "Truncate File if it exists"},
	{ 0, NULL}
  };
  static const value_string FileType_0xFFFF[] = {
	{ 0, "Disk file or directory"},
	{ 1, "Named pipe in byte mode"},
	{ 2, "Named pipe in message mode"},
	{ 3, "Spooled printer"},
	{ 0, NULL}
  };
  static const value_string DesiredAccess_0x70[] = {
	{ 00, "Compatibility mode"},
	{ 16, "Deny read/write/execute (exclusive)"},
	{ 32, "Deny write"},
	{ 48, "Deny read/execute"},
	{ 64, "Deny none"},
	{ 0, NULL}
  };
  static const value_string DesiredAccess_0x700[] = {
	{ 0, "Locality of reference unknown"},
	{ 256, "Mainly sequential access"},
	{ 512, "Mainly random access"},
	{ 768, "Random access with some locality"},
	{0, NULL}
  };
  static const value_string DesiredAccess_0x4000[] = {
	{ 0, "Write through mode disabled"},
	{ 16384, "Write through mode enabled"},
	{0, NULL}
  };
  static const value_string DesiredAccess_0x1000[] = {
	{ 0, "Normal file (caching permitted)"},
	{ 4096, "Do not cache this file"},
	{0, NULL}
  };
  static const value_string DesiredAccess_0x07[] = {
	{ 0, "Open for reading"},
	{ 1, "Open for writing"},
	{ 2, "Open for reading and writing"},
	{ 3, "Open for execute"},
	{0, NULL}
  };
  static const value_string Action_0x8000[] = {
	{ 0, "File opened by another user (or mode not supported by server)"},
	{ 32768, "File is opened only by this user at present"},
	{0, NULL}
  };
  static const value_string Action_0x0003[] = {
	{ 0, "No action taken?"},
	{ 1, "The file existed and was opened"},
	{ 2, "The file did not exist but was created"},
	{ 3, "The file existed and was truncated"},
	{0, NULL}
  };
  proto_tree    *Search_tree;
  proto_tree    *OpenFunction_tree;
  proto_tree    *Flags_tree;
  proto_tree    *File_tree;
  proto_tree    *FileType_tree;
  proto_tree    *FileAttributes_tree;
  proto_tree    *DesiredAccess_tree;
  proto_tree    *Action_tree;
  proto_item    *ti;
  guint8        WordCount;
  guint8        AndXReserved;
  guint8        AndXCommand = 0xFF;
  guint32       ServerFID;
  guint32       Reserved2;
  guint32       Reserved1;
  guint32       DataSize;
  guint32       AllocatedSize;
  guint16       Search;
  guint16       Reserved;
  guint16       OpenFunction;
  guint16       LastWriteTime;
  guint16       LastWriteDate;
  guint16       GrantedAccess;
  guint16       Flags;
  guint16       FileType;
  guint16       FileAttributes;
  guint16       File;
  guint16       FID;
  guint16       DeviceState;
  guint16       DesiredAccess;
  guint16       CreationTime;
  guint16       CreationDate;
  guint16       ByteCount;
  guint16       AndXOffset = 0;
  guint16       Action;
  const char    *FileName;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: AndXCommand */

    AndXCommand = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "AndXCommand: %s", 
			  (AndXCommand == 0xFF ? "No further commands" : decode_smb_name(AndXCommand)));

    }

    offset += 1; /* Skip AndXCommand */

    /* Build display for: AndXReserved */

    AndXReserved = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "AndXReserved: %u", AndXReserved);

    }

    offset += 1; /* Skip AndXReserved */

    /* Build display for: AndXOffset */

    AndXOffset = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "AndXOffset: %u", AndXOffset);

    }

    offset += 2; /* Skip AndXOffset */

    /* Build display for: Flags */

    Flags = GSHORT(pd, offset);

    if (tree) {

      ti = proto_tree_add_text(tree, offset, 2, "Flags: 0x%02x", Flags);
      Flags_tree = proto_item_add_subtree(ti, ett_smb_flags);
      proto_tree_add_text(Flags_tree, offset, 2, "%s",
                          decode_boolean_bitfield(Flags, 0x01, 16, "Dont Return Additional Info", "Return Additional Info"));
      proto_tree_add_text(Flags_tree, offset, 2, "%s",
                          decode_boolean_bitfield(Flags, 0x02, 16, "Exclusive OpLock not Requested", "Exclusive OpLock Requested"));
      proto_tree_add_text(Flags_tree, offset, 2, "%s",
                          decode_boolean_bitfield(Flags, 0x04, 16, "Batch OpLock not Requested", "Batch OpLock Requested"));
    
}

    offset += 2; /* Skip Flags */

    /* Build display for: Desired Access */

    DesiredAccess = GSHORT(pd, offset);

    if (tree) {

      ti = proto_tree_add_text(tree, offset, 2, "Desired Access: 0x%02x", DesiredAccess);
      DesiredAccess_tree = proto_item_add_subtree(ti, ett_smb_desiredaccess);
      proto_tree_add_text(DesiredAccess_tree, offset, 2, "%s",
                          decode_enumerated_bitfield(DesiredAccess, 0x07, 16, DesiredAccess_0x07, "%s"));
      proto_tree_add_text(DesiredAccess_tree, offset, 2, "%s",
                          decode_enumerated_bitfield(DesiredAccess, 0x70, 16, DesiredAccess_0x70, "%s"));
      proto_tree_add_text(DesiredAccess_tree, offset, 2, "%s",
                          decode_enumerated_bitfield(DesiredAccess, 0x700, 16, DesiredAccess_0x700, "%s"));
      proto_tree_add_text(DesiredAccess_tree, offset, 2, "%s",
                          decode_enumerated_bitfield(DesiredAccess, 0x1000, 16, DesiredAccess_0x1000, "%s"));
      proto_tree_add_text(DesiredAccess_tree, offset, 2, "%s",
                          decode_enumerated_bitfield(DesiredAccess, 0x4000, 16, DesiredAccess_0x4000, "%s"));
    
}

    offset += 2; /* Skip Desired Access */

    /* Build display for: Search */

    Search = GSHORT(pd, offset);

    if (tree) {

      ti = proto_tree_add_text(tree, offset, 2, "Search: 0x%02x", Search);
      Search_tree = proto_item_add_subtree(ti, ett_smb_search);
      proto_tree_add_text(Search_tree, offset, 2, "%s",
                          decode_boolean_bitfield(Search, 0x01, 16, "Read only file", "Not a read only file"));
      proto_tree_add_text(Search_tree, offset, 2, "%s",
                          decode_boolean_bitfield(Search, 0x02, 16, "Hidden file", "Not a hidden file"));
      proto_tree_add_text(Search_tree, offset, 2, "%s",
                          decode_boolean_bitfield(Search, 0x04, 16, "System file", "Not a system file"));
      proto_tree_add_text(Search_tree, offset, 2, "%s",
                          decode_boolean_bitfield(Search, 0x08, 16, " Volume", "Not a volume"));
      proto_tree_add_text(Search_tree, offset, 2, "%s",
                          decode_boolean_bitfield(Search, 0x10, 16, " Directory", "Not a directory"));
      proto_tree_add_text(Search_tree, offset, 2, "%s",
                          decode_boolean_bitfield(Search, 0x20, 16, "Archive file", "Do not archive file"));
    
}

    offset += 2; /* Skip Search */

    /* Build display for: File */

    File = GSHORT(pd, offset);

    if (tree) {

      ti = proto_tree_add_text(tree, offset, 2, "File: 0x%02x", File);
      File_tree = proto_item_add_subtree(ti, ett_smb_file);
      proto_tree_add_text(File_tree, offset, 2, "%s",
                          decode_boolean_bitfield(File, 0x01, 16, "Read only file", "Not a read only file"));
      proto_tree_add_text(File_tree, offset, 2, "%s",
                          decode_boolean_bitfield(File, 0x02, 16, "Hidden file", "Not a hidden file"));
      proto_tree_add_text(File_tree, offset, 2, "%s",
                          decode_boolean_bitfield(File, 0x04, 16, "System file", "Not a system file"));
      proto_tree_add_text(File_tree, offset, 2, "%s",
                          decode_boolean_bitfield(File, 0x08, 16, " Volume", "Not a volume"));
      proto_tree_add_text(File_tree, offset, 2, "%s",
                          decode_boolean_bitfield(File, 0x10, 16, " Directory", "Not a directory"));
      proto_tree_add_text(File_tree, offset, 2, "%s",
                          decode_boolean_bitfield(File, 0x20, 16, "Archive file", "Do not archive file"));
    
}

    offset += 2; /* Skip File */

    /* Build display for: Creation Time */

    CreationTime = GSHORT(pd, offset);

    if (tree) {


    }

    offset += 2; /* Skip Creation Time */

    /* Build display for: Creation Date */

    CreationDate = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Creation Date: %s", dissect_smbu_date(CreationDate, CreationTime));
      proto_tree_add_text(tree, offset, 2, "Creation Time: %s", dissect_smbu_time(CreationDate, CreationTime));

    }

    offset += 2; /* Skip Creation Date */

    /* Build display for: Open Function */

    OpenFunction = GSHORT(pd, offset);

    if (tree) {

      ti = proto_tree_add_text(tree, offset, 2, "Open Function: 0x%02x", OpenFunction);
      OpenFunction_tree = proto_item_add_subtree(ti, ett_smb_openfunction);
      proto_tree_add_text(OpenFunction_tree, offset, 2, "%s",
                          decode_enumerated_bitfield(OpenFunction, 0x10, 16, OpenFunction_0x10, "%s"));
      proto_tree_add_text(OpenFunction_tree, offset, 2, "%s",
                          decode_enumerated_bitfield(OpenFunction, 0x03, 16, OpenFunction_0x03, "%s"));
    
}

    offset += 2; /* Skip Open Function */

    /* Build display for: Allocated Size */

    AllocatedSize = GWORD(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 4, "Allocated Size: %u", AllocatedSize);

    }

    offset += 4; /* Skip Allocated Size */

    /* Build display for: Reserved1 */

    Reserved1 = GWORD(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 4, "Reserved1: %u", Reserved1);

    }

    offset += 4; /* Skip Reserved1 */

    /* Build display for: Reserved2 */

    Reserved2 = GWORD(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 4, "Reserved2: %u", Reserved2);

    }

    offset += 4; /* Skip Reserved2 */

    /* Build display for: Byte Count */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count: %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count */

    /* Build display for: File Name */

    FileName = pd + offset;

    if (tree) {

      proto_tree_add_text(tree, offset, strlen(FileName) + 1, "File Name: %s", FileName);

    }

    offset += strlen(FileName) + 1; /* Skip File Name */


    if (AndXCommand != 0xFF) {

      (dissect[AndXCommand])(pd, SMB_offset + AndXOffset, fd, parent, tree, si, max_data, SMB_offset, errcode, dirn);

    }

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    if (WordCount > 0) {

      /* Build display for: AndXCommand */

      AndXCommand = GBYTE(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 1, "AndXCommand: %s", 
			    (AndXCommand == 0xFF ? "No further commands" : decode_smb_name(AndXCommand)));

      }

      offset += 1; /* Skip AndXCommand */

      /* Build display for: AndXReserved */

      AndXReserved = GBYTE(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 1, "AndXReserved: %u", AndXReserved);

      }

      offset += 1; /* Skip AndXReserved */

      /* Build display for: AndXOffset */

      AndXOffset = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "AndXOffset: %u", AndXOffset);

      }

      offset += 2; /* Skip AndXOffset */

      /* Build display for: FID */

      FID = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "FID: %u", FID);

      }

      offset += 2; /* Skip FID */

      /* Build display for: FileAttributes */

      FileAttributes = GSHORT(pd, offset);

      if (tree) {

	ti = proto_tree_add_text(tree, offset, 2, "FileAttributes: 0x%02x", FileAttributes);
	FileAttributes_tree = proto_item_add_subtree(ti, ett_smb_fileattributes);
	proto_tree_add_text(FileAttributes_tree, offset, 2, "%s",
			    decode_boolean_bitfield(FileAttributes, 0x01, 16, "Read only file", "Not a read only file"));
	proto_tree_add_text(FileAttributes_tree, offset, 2, "%s",
			    decode_boolean_bitfield(FileAttributes, 0x02, 16, "Hidden file", "Not a hidden file"));
	proto_tree_add_text(FileAttributes_tree, offset, 2, "%s",
			    decode_boolean_bitfield(FileAttributes, 0x04, 16, "System file", "Not a system file"));
	proto_tree_add_text(FileAttributes_tree, offset, 2, "%s",
			    decode_boolean_bitfield(FileAttributes, 0x08, 16, " Volume", "Not a volume"));
	proto_tree_add_text(FileAttributes_tree, offset, 2, "%s",
			    decode_boolean_bitfield(FileAttributes, 0x10, 16, " Directory", "Not a directory"));
	proto_tree_add_text(FileAttributes_tree, offset, 2, "%s",
			    decode_boolean_bitfield(FileAttributes, 0x20, 16, "Archive file", "Do not archive file"));
    
      }

      offset += 2; /* Skip FileAttributes */

      /* Build display for: Last Write Time */

      LastWriteTime = GSHORT(pd, offset);

      if (tree) {

      }

      offset += 2; /* Skip Last Write Time */

      /* Build display for: Last Write Date */

      LastWriteDate = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Last Write Date: %s", dissect_smbu_date(LastWriteDate, LastWriteTime));
	proto_tree_add_text(tree, offset, 2, "Last Write Time: %s", dissect_smbu_time(LastWriteDate, LastWriteTime));


      }

      offset += 2; /* Skip Last Write Date */

      /* Build display for: Data Size */

      DataSize = GWORD(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 4, "Data Size: %u", DataSize);

      }

      offset += 4; /* Skip Data Size */

      /* Build display for: Granted Access */

      GrantedAccess = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Granted Access: %u", GrantedAccess);

      }

      offset += 2; /* Skip Granted Access */

      /* Build display for: File Type */

      FileType = GSHORT(pd, offset);

      if (tree) {

	ti = proto_tree_add_text(tree, offset, 2, "File Type: 0x%02x", FileType);
	FileType_tree = proto_item_add_subtree(ti, ett_smb_filetype);
	proto_tree_add_text(FileType_tree, offset, 2, "%s",
                          decode_enumerated_bitfield(FileType, 0xFFFF, 16, FileType_0xFFFF, "%s"));
    
      }

      offset += 2; /* Skip File Type */

      /* Build display for: Device State */

      DeviceState = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Device State: %u", DeviceState);

      }

      offset += 2; /* Skip Device State */

      /* Build display for: Action */

      Action = GSHORT(pd, offset);

      if (tree) {

	ti = proto_tree_add_text(tree, offset, 2, "Action: 0x%02x", Action);
	Action_tree = proto_item_add_subtree(ti, ett_smb_action);
	proto_tree_add_text(Action_tree, offset, 2, "%s",
			    decode_enumerated_bitfield(Action, 0x8000, 16, Action_0x8000, "%s"));
	proto_tree_add_text(Action_tree, offset, 2, "%s",
			    decode_enumerated_bitfield(Action, 0x0003, 16, Action_0x0003, "%s"));
	
      }
      
      offset += 2; /* Skip Action */

      /* Build display for: Server FID */
      
      ServerFID = GWORD(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 4, "Server FID: %u", ServerFID);

      }

      offset += 4; /* Skip Server FID */

      /* Build display for: Reserved */

      Reserved = GSHORT(pd, offset);

      if (tree) {
	
	proto_tree_add_text(tree, offset, 2, "Reserved: %u", Reserved);

      }

      offset += 2; /* Skip Reserved */

    }

    /* Build display for: Byte Count */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count: %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count */


    if (AndXCommand != 0xFF) {

      (dissect[AndXCommand])(pd, SMB_offset + AndXOffset, fd, parent, tree, si, max_data, SMB_offset, errcode, dirn);

    }

  }

}

void
dissect_write_raw_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  proto_tree    *WriteMode_tree;
  proto_item    *ti;
  guint8        WordCount;
  guint8        Pad;
  guint32       Timeout;
  guint32       Reserved2;
  guint32       Offset;
  guint16       WriteMode;
  guint16       Reserved1;
  guint16       Remaining;
  guint16       FID;
  guint16       DataOffset;
  guint16       DataLength;
  guint16       Count;
  guint16       ByteCount;

  if (dirn == 1) { /* Request(s) dissect code */

    WordCount = GBYTE(pd, offset);

    switch (WordCount) {

    case 12:

      /* Build display for: Word Count (WCT) */

      WordCount = GBYTE(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

      }

      offset += 1; /* Skip Word Count (WCT) */

      /* Build display for: FID */

      FID = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "FID: %u", FID);

      }

      offset += 2; /* Skip FID */

      /* Build display for: Count */

      Count = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "Count: %u", Count);

      }

      offset += 2; /* Skip Count */

      /* Build display for: Reserved 1 */

      Reserved1 = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "Reserved 1: %u", Reserved1);

      }

      offset += 2; /* Skip Reserved 1 */

      /* Build display for: Offset */

      Offset = GWORD(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 4, "Offset: %u", Offset);

      }

      offset += 4; /* Skip Offset */

      /* Build display for: Timeout */

      Timeout = GWORD(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 4, "Timeout: %u", Timeout);

      }

      offset += 4; /* Skip Timeout */

      /* Build display for: WriteMode */

      WriteMode = GSHORT(pd, offset);

      if (tree) {

        ti = proto_tree_add_text(tree, offset, 2, "WriteMode: 0x%02x", WriteMode);
        WriteMode_tree = proto_item_add_subtree(ti, ett_smb_writemode);
        proto_tree_add_text(WriteMode_tree, offset, 2, "%s",
                            decode_boolean_bitfield(WriteMode, 0x01, 16, "Write through requested", "Write through not requested"));
        proto_tree_add_text(WriteMode_tree, offset, 2, "%s",
                            decode_boolean_bitfield(WriteMode, 0x02, 16, "Return Remaining (pipe/dev)", "Dont return Remaining (pipe/dev)"));
      
}

      offset += 2; /* Skip WriteMode */

      /* Build display for: Reserved 2 */

      Reserved2 = GWORD(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 4, "Reserved 2: %u", Reserved2);

      }

      offset += 4; /* Skip Reserved 2 */

      /* Build display for: Data Length */

      DataLength = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "Data Length: %u", DataLength);

      }

      offset += 2; /* Skip Data Length */

      /* Build display for: Data Offset */

      DataOffset = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "Data Offset: %u", DataOffset);

      }

      offset += 2; /* Skip Data Offset */

      /* Build display for: Byte Count (BCC) */

      ByteCount = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

      }

      offset += 2; /* Skip Byte Count (BCC) */

      /* Build display for: Pad */

      Pad = GBYTE(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 1, "Pad: %u", Pad);

      }

      offset += 1; /* Skip Pad */

    break;

    case 14:

      /* Build display for: Word Count (WCT) */

      WordCount = GBYTE(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

      }

      offset += 1; /* Skip Word Count (WCT) */

      /* Build display for: FID */

      FID = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "FID: %u", FID);

      }

      offset += 2; /* Skip FID */

      /* Build display for: Count */

      Count = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "Count: %u", Count);

      }

      offset += 2; /* Skip Count */

      /* Build display for: Reserved 1 */

      Reserved1 = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "Reserved 1: %u", Reserved1);

      }

      offset += 2; /* Skip Reserved 1 */

      /* Build display for: Timeout */

      Timeout = GWORD(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 4, "Timeout: %u", Timeout);

      }

      offset += 4; /* Skip Timeout */

      /* Build display for: WriteMode */

      WriteMode = GSHORT(pd, offset);

      if (tree) {

        ti = proto_tree_add_text(tree, offset, 2, "WriteMode: 0x%02x", WriteMode);
        WriteMode_tree = proto_item_add_subtree(ti, ett_smb_writemode);
        proto_tree_add_text(WriteMode_tree, offset, 2, "%s",
                            decode_boolean_bitfield(WriteMode, 0x01, 16, "Write through requested", "Write through not requested"));
        proto_tree_add_text(WriteMode_tree, offset, 2, "%s",
                            decode_boolean_bitfield(WriteMode, 0x02, 16, "Return Remaining (pipe/dev)", "Dont return Remaining (pipe/dev)"));
      
}

      offset += 2; /* Skip WriteMode */

      /* Build display for: Reserved 2 */

      Reserved2 = GWORD(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 4, "Reserved 2: %u", Reserved2);

      }

      offset += 4; /* Skip Reserved 2 */

      /* Build display for: Data Length */

      DataLength = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "Data Length: %u", DataLength);

      }

      offset += 2; /* Skip Data Length */

      /* Build display for: Data Offset */

      DataOffset = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "Data Offset: %u", DataOffset);

      }

      offset += 2; /* Skip Data Offset */

      /* Build display for: Byte Count (BCC) */

      ByteCount = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

      }

      offset += 2; /* Skip Byte Count (BCC) */

      /* Build display for: Pad */

      Pad = GBYTE(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 1, "Pad: %u", Pad);

      }

      offset += 1; /* Skip Pad */

    break;

    }

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    if (WordCount > 0) {

      /* Build display for: Remaining */

      Remaining = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Remaining: %u", Remaining);

      }

      offset += 2; /* Skip Remaining */

    }

    /* Build display for: Byte Count */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count: %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count */

  }

}

void
dissect_tdis_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  guint8        WordCount;
  guint16       ByteCount;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

}

void
dissect_move_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  static const value_string Flags_0x03[] = {
	{ 0, "Target must be a file"},
	{ 1, "Target must be a directory"},
	{ 2, "Reserved"},
	{ 3, "Reserved"},
	{ 4, "Verify all writes"},
	{ 0, NULL}
};
  proto_tree    *Flags_tree;
  proto_item    *ti;
  guint8        WordCount;
  guint8        ErrorFileFormat;
  guint16       TID2;
  guint16       OpenFunction;
  guint16       Flags;
  guint16       Count;
  guint16       ByteCount;
  const char    *ErrorFileName;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: TID2 */

    TID2 = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "TID2: %u", TID2);

    }

    offset += 2; /* Skip TID2 */

    /* Build display for: Open Function */

    OpenFunction = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Open Function: %u", OpenFunction);

    }

    offset += 2; /* Skip Open Function */

    /* Build display for: Flags */

    Flags = GSHORT(pd, offset);

    if (tree) {

      ti = proto_tree_add_text(tree, offset, 2, "Flags: 0x%02x", Flags);
      Flags_tree = proto_item_add_subtree(ti, ett_smb_flags);
      proto_tree_add_text(Flags_tree, offset, 2, "%s",
                          decode_enumerated_bitfield(Flags, 0x03, 16, Flags_0x03, "%s"));
    
}

    offset += 2; /* Skip Flags */

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    if (WordCount > 0) {

      /* Build display for: Count */

      Count = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Count: %u", Count);

      }

      offset += 2; /* Skip Count */

    }

    /* Build display for: Byte Count */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count: %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count */

    /* Build display for: Error File Format */

    ErrorFileFormat = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Error File Format: %u", ErrorFileFormat);

    }

    offset += 1; /* Skip Error File Format */

    /* Build display for: Error File Name */

    ErrorFileName = pd + offset;

    if (tree) {

      proto_tree_add_text(tree, offset, strlen(ErrorFileName) + 1, "Error File Name: %s", ErrorFileName);

    }

    offset += strlen(ErrorFileName) + 1; /* Skip Error File Name */

  }

}

void
dissect_rename_file_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  guint8        WordCount;
  guint8        BufferFormat2;
  guint8        BufferFormat1;
  guint16       SearchAttributes;
  guint16       ByteCount;
  const char    *OldFileName;
  const char    *NewFileName;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Search Attributes */

    SearchAttributes = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Search Attributes: %u", SearchAttributes);

    }

    offset += 2; /* Skip Search Attributes */

    /* Build display for: Byte Count */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count: %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count */

    /* Build display for: Buffer Format 1 */

    BufferFormat1 = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Buffer Format 1: %u", BufferFormat1);

    }

    offset += 1; /* Skip Buffer Format 1 */

    /* Build display for: Old File Name */

    OldFileName = pd + offset;

    if (tree) {

      proto_tree_add_text(tree, offset, strlen(OldFileName) + 1, "Old File Name: %s", OldFileName);

    }

    offset += strlen(OldFileName) + 1; /* Skip Old File Name */

    /* Build display for: Buffer Format 2 */

    BufferFormat2 = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Buffer Format 2: %u", BufferFormat2);

    }

    offset += 1; /* Skip Buffer Format 2 */

    /* Build display for: New File Name */

    NewFileName = pd + offset;

    if (tree) {

      proto_tree_add_text(tree, offset, strlen(NewFileName) + 1, "New File Name: %s", NewFileName);

    }

    offset += strlen(NewFileName) + 1; /* Skip New File Name */

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

}

void
dissect_open_print_file_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  static const value_string Mode_0x03[] = {
	{ 0, "Text mode (DOS expands TABs)"},
	{ 1, "Graphics mode"},
	{ 0, NULL}
};
  proto_tree    *Mode_tree;
  proto_item    *ti;
  guint8        WordCount;
  guint8        BufferFormat;
  guint16       SetupLength;
  guint16       Mode;
  guint16       FID;
  guint16       ByteCount;
  const char    *IdentifierString;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Setup Length */

    SetupLength = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Setup Length: %u", SetupLength);

    }

    offset += 2; /* Skip Setup Length */

    /* Build display for: Mode */

    Mode = GSHORT(pd, offset);

    if (tree) {

      ti = proto_tree_add_text(tree, offset, 2, "Mode: 0x%02x", Mode);
      Mode_tree = proto_item_add_subtree(ti, ett_smb_mode);
      proto_tree_add_text(Mode_tree, offset, 2, "%s",
                          decode_enumerated_bitfield(Mode, 0x03, 16, Mode_0x03, "%s"));
    
}

    offset += 2; /* Skip Mode */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

    /* Build display for: Buffer Format */

    BufferFormat = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Buffer Format: %u", BufferFormat);

    }

    offset += 1; /* Skip Buffer Format */

    /* Build display for: Identifier String */

    IdentifierString = pd + offset;

    if (tree) {

      proto_tree_add_text(tree, offset, strlen(IdentifierString) + 1, "Identifier String: %s", IdentifierString);

    }

    offset += strlen(IdentifierString) + 1; /* Skip Identifier String */

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: FID */

    FID = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "FID: %u", FID);

    }

    offset += 2; /* Skip FID */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

}

void
dissect_close_print_file_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  guint8        WordCount;
  guint16       FID;
  guint16       ByteCount;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: FID */

    FID = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "FID: %u", FID);

    }

    offset += 2; /* Skip FID */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count: %u", WordCount);

    }

    offset += 1; /* Skip Word Count */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

}

void
dissect_read_raw_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  guint8        WordCount;
  guint32       Timeout;
  guint32       OffsetHigh;
  guint32       Offset;
  guint16       Reserved;
  guint16       MinCount;
  guint16       MaxCount;
  guint16       FID;
  guint16       ByteCount;

  if (dirn == 1) { /* Request(s) dissect code */

    WordCount = GBYTE(pd, offset);

    switch (WordCount) {

    case 8:

      /* Build display for: Word Count (WCT) */

      WordCount = GBYTE(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

      }

      offset += 1; /* Skip Word Count (WCT) */

      /* Build display for: FID */

      FID = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "FID: %u", FID);

      }

      offset += 2; /* Skip FID */

      /* Build display for: Offset */

      Offset = GWORD(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 4, "Offset: %u", Offset);

      }

      offset += 4; /* Skip Offset */

      /* Build display for: Max Count */

      MaxCount = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "Max Count: %u", MaxCount);

      }

      offset += 2; /* Skip Max Count */

      /* Build display for: Min Count */

      MinCount = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "Min Count: %u", MinCount);

      }

      offset += 2; /* Skip Min Count */

      /* Build display for: Timeout */

      Timeout = GWORD(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 4, "Timeout: %u", Timeout);

      }

      offset += 4; /* Skip Timeout */

      /* Build display for: Reserved */

      Reserved = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "Reserved: %u", Reserved);

      }

      offset += 2; /* Skip Reserved */

      /* Build display for: Byte Count (BCC) */

      ByteCount = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

      }

      offset += 2; /* Skip Byte Count (BCC) */

    break;

    case 10:

      /* Build display for: Word Count (WCT) */

      WordCount = GBYTE(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

      }

      offset += 1; /* Skip Word Count (WCT) */

      /* Build display for: FID */

      FID = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "FID: %u", FID);

      }

      offset += 2; /* Skip FID */

      /* Build display for: Offset */

      Offset = GWORD(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 4, "Offset: %u", Offset);

      }

      offset += 4; /* Skip Offset */

      /* Build display for: Max Count */

      MaxCount = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "Max Count: %u", MaxCount);

      }

      offset += 2; /* Skip Max Count */

      /* Build display for: Min Count */

      MinCount = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "Min Count: %u", MinCount);

      }

      offset += 2; /* Skip Min Count */

      /* Build display for: Timeout */

      Timeout = GWORD(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 4, "Timeout: %u", Timeout);

      }

      offset += 4; /* Skip Timeout */

      /* Build display for: Reserved */

      Reserved = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "Reserved: %u", Reserved);

      }

      offset += 2; /* Skip Reserved */

      /* Build display for: Offset High */

      OffsetHigh = GWORD(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 4, "Offset High: %u", OffsetHigh);

      }

      offset += 4; /* Skip Offset High */

      /* Build display for: Byte Count (BCC) */

      ByteCount = GSHORT(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

      }

      offset += 2; /* Skip Byte Count (BCC) */

    break;

    }

  }

  if (dirn == 0) { /* Response(s) dissect code */

  }

}

void
dissect_logoff_andx_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  guint8        WordCount;
  guint8        AndXReserved;
  guint8        AndXCommand = 0xFF;
  guint16       ByteCount;
  guint16       AndXOffset = 0;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: AndXCommand */

    AndXCommand = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "AndXCommand: %u", AndXCommand);

    }

    offset += 1; /* Skip AndXCommand */

    /* Build display for: AndXReserved */

    AndXReserved = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "AndXReserved: %u", AndXReserved);

    }

    offset += 1; /* Skip AndXReserved */

    /* Build display for: AndXOffset */

    AndXOffset = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "AndXOffset: %u", AndXOffset);

    }

    offset += 2; /* Skip AndXOffset */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */


    if (AndXCommand != 0xFF) {

      (dissect[AndXCommand])(pd, SMB_offset + AndXOffset, fd, parent, tree, si, max_data, SMB_offset, errcode, dirn);

    }

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: AndXCommand */

    AndXCommand = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "AndXCommand: %u", AndXCommand);

    }

    offset += 1; /* Skip AndXCommand */

    /* Build display for: AndXReserved */

    AndXReserved = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "AndXReserved: %u", AndXReserved);

    }

    offset += 1; /* Skip AndXReserved */

    /* Build display for: AndXOffset */

    AndXOffset = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "AndXOffset: %u", AndXOffset);

    }

    offset += 2; /* Skip AndXOffset */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */


    if (AndXCommand != 0xFF) {

      (dissect[AndXCommand])(pd, SMB_offset + AndXOffset, fd, parent, tree, si, max_data, SMB_offset, errcode, dirn);

    }

  }

}

void
dissect_seek_file_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  static const value_string Mode_0x03[] = {
	{ 0, "Seek from start of file"},
	{ 1, "Seek from current position"},
	{ 2, "Seek from end of file"},
	{ 0, NULL}
};
  proto_tree    *Mode_tree;
  proto_item    *ti;
  guint8        WordCount;
  guint32       Offset;
  guint16       Mode;
  guint16       FID;
  guint16       ByteCount;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: FID */

    FID = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "FID: %u", FID);

    }

    offset += 2; /* Skip FID */

    /* Build display for: Mode */

    Mode = GSHORT(pd, offset);

    if (tree) {

      ti = proto_tree_add_text(tree, offset, 2, "Mode: 0x%02x", Mode);
      Mode_tree = proto_item_add_subtree(ti, ett_smb_mode);
      proto_tree_add_text(Mode_tree, offset, 2, "%s",
                          decode_enumerated_bitfield(Mode, 0x03, 16, Mode_0x03, "%s"));
    
}

    offset += 2; /* Skip Mode */

    /* Build display for: Offset */

    Offset = GWORD(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 4, "Offset: %u", Offset);

    }

    offset += 4; /* Skip Offset */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Offset */

    Offset = GWORD(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 4, "Offset: %u", Offset);

    }

    offset += 4; /* Skip Offset */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

}

void
dissect_write_and_unlock_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  guint8        WordCount;
  guint8        BufferFormat;
  guint32       Offset;
  guint16       Remaining;
  guint16       FID;
  guint16       DataLength;
  guint16       Count;
  guint16       ByteCount;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: FID */

    FID = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "FID: %u", FID);

    }

    offset += 2; /* Skip FID */

    /* Build display for: Count */

    Count = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Count: %u", Count);

    }

    offset += 2; /* Skip Count */

    /* Build display for: Offset */

    Offset = GWORD(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 4, "Offset: %u", Offset);

    }

    offset += 4; /* Skip Offset */

    /* Build display for: Remaining */

    Remaining = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Remaining: %u", Remaining);

    }

    offset += 2; /* Skip Remaining */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

    /* Build display for: Buffer Format */

    BufferFormat = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Buffer Format: %u", BufferFormat);

    }

    offset += 1; /* Skip Buffer Format */

    /* Build display for: Data Length */

    DataLength = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Data Length: %u", DataLength);

    }

    offset += 2; /* Skip Data Length */

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Count */

    Count = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Count: %u", Count);

    }

    offset += 2; /* Skip Count */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

}

void
dissect_set_info2_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  guint8        WordCount;
  guint16       LastWriteTime;
  guint16       LastWriteDate;
  guint16       LastAccessTime;
  guint16       LastAccessDate;
  guint16       FID;
  guint16       CreationTime;
  guint16       CreationDate;
  guint16       ByteCount;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count: %u", WordCount);

    }

    offset += 1; /* Skip Word Count */

    /* Build display for: FID */

    FID = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "FID: %u", FID);

    }

    offset += 2; /* Skip FID */

    /* Build display for: Creation Date */

    CreationDate = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Creation Date: %u", dissect_dos_date(CreationDate));

    }

    offset += 2; /* Skip Creation Date */

    /* Build display for: Creation Time */

    CreationTime = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Creation Time: %u", dissect_dos_time(CreationTime));

    }

    offset += 2; /* Skip Creation Time */

    /* Build display for: Last Access Date */

    LastAccessDate = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Last Access Date: %u", dissect_dos_date(LastAccessDate));

    }

    offset += 2; /* Skip Last Access Date */

    /* Build display for: Last Access Time */

    LastAccessTime = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Last Access Time: %u", dissect_dos_time(LastAccessTime));

    }

    offset += 2; /* Skip Last Access Time */

    /* Build display for: Last Write Date */

    LastWriteDate = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Last Write Date: %u", dissect_dos_date(LastWriteDate));

    }

    offset += 2; /* Skip Last Write Date */

    /* Build display for: Last Write Time */

    LastWriteTime = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Last Write Time: %u", dissect_dos_time(LastWriteTime));

    }

    offset += 2; /* Skip Last Write Time */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCC) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCC): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCC) */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

}

void
dissect_lock_bytes_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  guint8        WordCount;
  guint32       Offset;
  guint32       Count;
  guint16       FID;
  guint16       ByteCount;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: FID */

    FID = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "FID: %u", FID);

    }

    offset += 2; /* Skip FID */

    /* Build display for: Count */

    Count = GWORD(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 4, "Count: %u", Count);

    }

    offset += 4; /* Skip Count */

    /* Build display for: Offset */

    Offset = GWORD(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 4, "Offset: %u", Offset);

    }

    offset += 4; /* Skip Offset */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

}

void
dissect_get_print_queue_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  guint8        WordCount;
  guint8        BufferFormat;
  guint16       StartIndex;
  guint16       RestartIndex;
  guint16       MaxCount;
  guint16       DataLength;
  guint16       Count;
  guint16       ByteCount;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count: %u", WordCount);

    }

    offset += 1; /* Skip Word Count */

    /* Build display for: Max Count */

    MaxCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Max Count: %u", MaxCount);

    }

    offset += 2; /* Skip Max Count */

    /* Build display for: Start Index */

    StartIndex = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Start Index: %u", StartIndex);

    }

    offset += 2; /* Skip Start Index */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    if (WordCount > 0) {

      /* Build display for: Count */

      Count = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Count: %u", Count);

      }

      offset += 2; /* Skip Count */

      /* Build display for: Restart Index */

      RestartIndex = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Restart Index: %u", RestartIndex);

      }

      offset += 2; /* Skip Restart Index */

      /* Build display for: Byte Count (BCC) */

    }

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

    /* Build display for: Buffer Format */

    BufferFormat = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Buffer Format: %u", BufferFormat);

    }

    offset += 1; /* Skip Buffer Format */

    /* Build display for: Data Length */

    DataLength = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Data Length: %u", DataLength);

    }

    offset += 2; /* Skip Data Length */

  }

}

void
dissect_locking_andx_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  proto_tree    *LockType_tree;
  proto_item    *ti;
  guint8        LockType;
  guint8        WordCount;
  guint8        OplockLevel;
  guint8        AndXReserved;
  guint8        AndXCommand = 0xFF;
  guint32       Timeout;
  guint16       NumberofLocks;
  guint16       NumberOfUnlocks;
  guint16       FID;
  guint16       ByteCount;
  guint16       AndXoffset;
  guint16       AndXOffset = 0;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: AndXCommand */

    AndXCommand = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "AndXCommand: %u", AndXCommand);

    }

    offset += 1; /* Skip AndXCommand */

    /* Build display for: AndXReserved */

    AndXReserved = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "AndXReserved: %u", AndXReserved);

    }

    offset += 1; /* Skip AndXReserved */

    /* Build display for: AndXOffset */

    AndXOffset = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "AndXOffset: %u", AndXOffset);

    }

    offset += 2; /* Skip AndXOffset */

    /* Build display for: FID */

    FID = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "FID: %u", FID);

    }

    offset += 2; /* Skip FID */

    /* Build display for: Lock Type */

    LockType = GBYTE(pd, offset);

    if (tree) {

      ti = proto_tree_add_text(tree, offset, 1, "Lock Type: 0x%01x", LockType);
      LockType_tree = proto_item_add_subtree(ti, ett_smb_lock_type);
      proto_tree_add_text(LockType_tree, offset, 1, "%s",
                          decode_boolean_bitfield(LockType, 0x01, 16, "Read-only lock", "Not a Read-only lock"));
      proto_tree_add_text(LockType_tree, offset, 1, "%s",
                          decode_boolean_bitfield(LockType, 0x02, 16, "Oplock break notification", "Not an Oplock break notification"));
      proto_tree_add_text(LockType_tree, offset, 1, "%s",
                          decode_boolean_bitfield(LockType, 0x04, 16, "Change lock type", "Not a lock type change"));
      proto_tree_add_text(LockType_tree, offset, 1, "%s",
                          decode_boolean_bitfield(LockType, 0x08, 16, "Cancel outstanding request", "Dont cancel outstanding request"));
      proto_tree_add_text(LockType_tree, offset, 1, "%s",
                          decode_boolean_bitfield(LockType, 0x10, 16, "Large file locking format", "Not a large file locking format"));
    
}

    offset += 1; /* Skip Lock Type */

    /* Build display for: OplockLevel */

    OplockLevel = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "OplockLevel: %u", OplockLevel);

    }

    offset += 1; /* Skip OplockLevel */

    /* Build display for: Timeout */

    Timeout = GWORD(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 4, "Timeout: %u", Timeout);

    }

    offset += 4; /* Skip Timeout */

    /* Build display for: Number Of Unlocks */

    NumberOfUnlocks = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Number Of Unlocks: %u", NumberOfUnlocks);

    }

    offset += 2; /* Skip Number Of Unlocks */

    /* Build display for: Number of Locks */

    NumberofLocks = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Number of Locks: %u", NumberofLocks);

    }

    offset += 2; /* Skip Number of Locks */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */


    if (AndXCommand != 0xFF) {

      (dissect[AndXCommand])(pd, SMB_offset + AndXOffset, fd, parent, tree, si, max_data, SMB_offset, errcode, dirn);

    }

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    if (WordCount > 0) {

      /* Build display for: AndXCommand */

      AndXCommand = GBYTE(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 1, "AndXCommand: %s", 
			    (AndXCommand == 0xFF ? "No further commands" : decode_smb_name(AndXCommand)));

      }

      offset += 1; /* Skip AndXCommand */

      /* Build display for: AndXReserved */

      AndXReserved = GBYTE(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 1, "AndXReserved: %u", AndXReserved);

      }

      offset += 1; /* Skip AndXReserved */

      /* Build display for: AndXoffset */

      AndXoffset = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "AndXoffset: %u", AndXoffset);

      }

      offset += 2; /* Skip AndXoffset */

    }

    /* Build display for: Byte Count */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count: %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count */


    if (AndXCommand != 0xFF) {

      (dissect[AndXCommand])(pd, SMB_offset + AndXOffset, fd, parent, tree, si, max_data, SMB_offset, errcode, dirn);

    }

  }

}

void
dissect_unlock_bytes_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  guint8        WordCount;
  guint32       Offset;
  guint32       Count;
  guint16       FID;
  guint16       ByteCount;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: FID */

    FID = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "FID: %u", FID);

    }

    offset += 2; /* Skip FID */

    /* Build display for: Count */

    Count = GWORD(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 4, "Count: %u", Count);

    }

    offset += 4; /* Skip Count */

    /* Build display for: Offset */

    Offset = GWORD(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 4, "Offset: %u", Offset);

    }

    offset += 4; /* Skip Offset */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

}

void
dissect_create_file_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  proto_tree    *Attributes_tree;
  proto_item    *ti;
  guint8        WordCount;
  guint8        BufferFormat;
  guint16       FID;
  guint16       CreationTime;
  guint16       ByteCount;
  guint16       Attributes;
  const char    *FileName;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Attributes */

    Attributes = GSHORT(pd, offset);

    if (tree) {

      ti = proto_tree_add_text(tree, offset, 2, "Attributes: 0x%02x", Attributes);
      Attributes_tree = proto_item_add_subtree(ti, ett_smb_fileattributes);
      proto_tree_add_text(Attributes_tree, offset, 2, "%s",
                          decode_boolean_bitfield(Attributes, 0x01, 16, "Read-only file", "Not a read-only file"));
      proto_tree_add_text(Attributes_tree, offset, 2, "%s",
                          decode_boolean_bitfield(Attributes, 0x02, 16, "Hidden file", "Not a hidden file"));
      proto_tree_add_text(Attributes_tree, offset, 2, "%s",
                          decode_boolean_bitfield(Attributes, 0x04, 16, "System file", "Not a system file"));
      proto_tree_add_text(Attributes_tree, offset, 2, "%s",
                          decode_boolean_bitfield(Attributes, 0x08, 16, " Volume", "Not a volume"));
      proto_tree_add_text(Attributes_tree, offset, 2, "%s",
                          decode_boolean_bitfield(Attributes, 0x10, 16, " Directory", "Not a directory"));
      proto_tree_add_text(Attributes_tree, offset, 2, "%s",
                          decode_boolean_bitfield(Attributes, 0x20, 16, " Archived", "Not archived"));
    
}

    offset += 2; /* Skip Attributes */

    /* Build display for: Creation Time */

    CreationTime = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Creation Time: %u", dissect_dos_time(CreationTime));

    }

    offset += 2; /* Skip Creation Time */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

    /* Build display for: Buffer Format */

    BufferFormat = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Buffer Format: %u", BufferFormat);

    }

    offset += 1; /* Skip Buffer Format */

    /* Build display for: File Name */

    FileName = pd + offset;

    if (tree) {

      proto_tree_add_text(tree, offset, strlen(FileName) + 1, "File Name: %s", FileName);

    }

    offset += strlen(FileName) + 1; /* Skip File Name */

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    if (WordCount > 0) {

      /* Build display for: FID */

      FID = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "FID: %u", FID);

      }

      offset += 2; /* Skip FID */
      
    }
    
    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

}

void
dissect_search_dir_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  guint8        WordCount;
  guint8        BufferFormat2;
  guint8        BufferFormat1;
  guint8        BufferFormat;
  guint16       SearchAttributes;
  guint16       ResumeKeyLength;
  guint16       MaxCount;
  guint16       DataLength;
  guint16       Count;
  guint16       ByteCount;
  const char    *FileName;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Max Count */

    MaxCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Max Count: %u", MaxCount);

    }

    offset += 2; /* Skip Max Count */

    /* Build display for: Search Attributes */

    SearchAttributes = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Search Attributes: %u", SearchAttributes);

    }

    offset += 2; /* Skip Search Attributes */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

    /* Build display for: Buffer Format 1 */

    BufferFormat1 = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Buffer Format 1: %u", BufferFormat1);

    }

    offset += 1; /* Skip Buffer Format 1 */

    /* Build display for: File Name */

    FileName = pd + offset;

    if (tree) {

      proto_tree_add_text(tree, offset, strlen(FileName) + 1, "File Name: %s", FileName);

    }

    offset += strlen(FileName) + 1; /* Skip File Name */

    /* Build display for: Buffer Format 2 */

    BufferFormat2 = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Buffer Format 2: %u", BufferFormat2);

    }

    offset += 1; /* Skip Buffer Format 2 */

    /* Build display for: Resume Key Length */

    ResumeKeyLength = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Resume Key Length: %u", ResumeKeyLength);

    }

    offset += 2; /* Skip Resume Key Length */

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    if (WordCount > 0) {

      /* Build display for: Count */

      Count = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Count: %u", Count);

      }

      offset += 2; /* Skip Count */

    }

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

    /* Build display for: Buffer Format */

    BufferFormat = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Buffer Format: %u", BufferFormat);

    }

    offset += 1; /* Skip Buffer Format */

    /* Build display for: Data Length */

    DataLength = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Data Length: %u", DataLength);

    }

    offset += 2; /* Skip Data Length */

  }

}

void
dissect_create_temporary_file_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  guint8        WordCount;
  guint8        BufferFormat;
  guint16       Reserved;
  guint16       FID;
  guint16       CreationTime;
  guint16       CreationDate;
  guint16       ByteCount;
  const char    *FileName;
  const char    *DirectoryName;

  guint16       Flags2;
  char          *ustr;
  int           ustr_len;


  /* obtain the Flags2 settings */
  Flags2 = GSHORT(pd, Flags2_Offset);


  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Reserved */

    Reserved = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Reserved: %u", Reserved);

    }

    offset += 2; /* Skip Reserved */

    /* Build display for: Creation Time */

    CreationTime = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Creation Time: %u", dissect_dos_time(CreationTime));

    }

    offset += 2; /* Skip Creation Time */

    /* Build display for: Creation Date */

    CreationDate = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Creation Date: %u", dissect_dos_date(CreationDate));

    }

    offset += 2; /* Skip Creation Date */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

    /* Build display for: Buffer Format */

    BufferFormat = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Buffer Format: %u", BufferFormat);

    }

    offset += 1; /* Skip Buffer Format */

    /* Build display for: Directory Name */

    /* The Directory Name, a null terminated string; Unicode if "Flags" has
       the 0x8000 bit set, ASCII (OEM character set) otherwise.
       XXX - for now, we just handle the ISO 8859-1 subset of Unicode. */

    DirectoryName = pd + offset;

    if (tree) {
      if (Flags2 & 0x8000) {
          ustr = unicode_to_str(DirectoryName, &ustr_len);
          proto_tree_add_text(tree, offset, ustr_len+2, "Directory Name: %s", ustr);
          offset += (strlen(ustr)*2) + 2; /* Skip Directory Name */
      } else {
          proto_tree_add_text(tree, offset, strlen(DirectoryName) + 1, "Directory Name: %s", DirectoryName);
          offset += strlen(DirectoryName) + 1; /* Skip Directory Name */
      }
    }

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    if (WordCount > 0) {

      /* Build display for: FID */

      FID = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "FID: %u", FID);

      }

      offset += 2; /* Skip FID */

    }

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

    /* Build display for: Buffer Format */

    BufferFormat = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Buffer Format: %u", BufferFormat);

    }

    offset += 1; /* Skip Buffer Format */

    /* Build display for: File Name */

    FileName = pd + offset;

    if (tree) {

      proto_tree_add_text(tree, offset, strlen(FileName) + 1, "File Name: %s", FileName);

    }

    offset += strlen(FileName) + 1; /* Skip File Name */

  }

}

void
dissect_close_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  guint8        WordCount;
  guint16       LastWriteTime;
  guint16       LastWriteDate;
  guint16       FID;
  guint16       ByteCount;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: FID */

    FID = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "FID: %u", FID);

    }

    offset += 2; /* Skip FID */

    /* Build display for: Last Write Time */

    LastWriteTime = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Last Write Time: %u", dissect_dos_time(LastWriteTime));

    }

    offset += 2; /* Skip Last Write Time */

    /* Build display for: Last Write Date */

    LastWriteDate = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Last Write Date: %u", dissect_dos_date(LastWriteDate));

    }

    offset += 2; /* Skip Last Write Date */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

}

void
dissect_write_print_file_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  guint8        WordCount;
  guint8        BufferFormat;
  guint16       FID;
  guint16       DataLength;
  guint16       ByteCount;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: FID */

    FID = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "FID: %u", FID);

    }

    offset += 2; /* Skip FID */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

    /* Build display for: Buffer Format */

    BufferFormat = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Buffer Format: %u", BufferFormat);

    }

    offset += 1; /* Skip Buffer Format */

    /* Build display for: Data Length */

    DataLength = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Data Length: %u", DataLength);

    }

    offset += 2; /* Skip Data Length */

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

}

void
dissect_lock_and_read_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  guint8        WordCount;
  guint8        BufferFormat;
  guint32       Offset;
  guint16       Reserved4;
  guint16       Reserved3;
  guint16       Reserved2;
  guint16       Reserved1;
  guint16       Remaining;
  guint16       FID;
  guint16       DataLength;
  guint16       Count;
  guint16       ByteCount;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: FID */

    FID = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "FID: %u", FID);

    }

    offset += 2; /* Skip FID */

    /* Build display for: Count */

    Count = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Count: %u", Count);

    }

    offset += 2; /* Skip Count */

    /* Build display for: Offset */

    Offset = GWORD(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 4, "Offset: %u", Offset);

    }

    offset += 4; /* Skip Offset */

    /* Build display for: Remaining */

    Remaining = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Remaining: %u", Remaining);

    }

    offset += 2; /* Skip Remaining */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    if (WordCount > 0) {

      /* Build display for: Count */

      Count = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Count: %u", Count);

      }

      offset += 2; /* Skip Count */

      /* Build display for: Reserved 1 */

      Reserved1 = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Reserved 1: %u", Reserved1);

      }

      offset += 2; /* Skip Reserved 1 */

      /* Build display for: Reserved 2 */

      Reserved2 = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Reserved 2: %u", Reserved2);

      }

      offset += 2; /* Skip Reserved 2 */

      /* Build display for: Reserved 3 */

      Reserved3 = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Reserved 3: %u", Reserved3);

      }

      offset += 2; /* Skip Reserved 3 */

      /* Build display for: Reserved 4 */

      Reserved4 = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Reserved 4: %u", Reserved4);

      }

      offset += 2; /* Skip Reserved 4 */

      /* Build display for: Byte Count (BCC) */

      ByteCount = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

      }

    }

    offset += 2; /* Skip Byte Count (BCC) */

    /* Build display for: Buffer Format */

    BufferFormat = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Buffer Format: %u", BufferFormat);

    }

    offset += 1; /* Skip Buffer Format */

    /* Build display for: Data Length */

    DataLength = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Data Length: %u", DataLength);

    }

    offset += 2; /* Skip Data Length */

  }

}

void
dissect_process_exit_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  guint8        WordCount;
  guint16       ByteCount;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

}

void
dissect_get_file_attr_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  proto_tree    *Attributes_tree;
  proto_item    *ti;
  guint8        WordCount;
  guint8        BufferFormat;
  guint32       FileSize;
  guint16       Reserved5;
  guint16       Reserved4;
  guint16       Reserved3;
  guint16       Reserved2;
  guint16       Reserved1;
  guint16       LastWriteTime;
  guint16       LastWriteDate;
  guint16       ByteCount;
  guint16       Attributes;
  const char    *FileName;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

    /* Build display for: Buffer Format */

    BufferFormat = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Buffer Format: %u", BufferFormat);

    }

    offset += 1; /* Skip Buffer Format */

    /* Build display for: File Name */

    FileName = pd + offset;

    if (tree) {

      proto_tree_add_text(tree, offset, strlen(FileName) + 1, "File Name: %s", FileName);

    }

    offset += strlen(FileName) + 1; /* Skip File Name */

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    if (WordCount > 0) {

      /* Build display for: Attributes */

      Attributes = GSHORT(pd, offset);

      if (tree) {

	ti = proto_tree_add_text(tree, offset, 2, "Attributes: 0x%02x", Attributes);
	Attributes_tree = proto_item_add_subtree(ti, ett_smb_fileattributes);
	proto_tree_add_text(Attributes_tree, offset, 2, "%s",
			    decode_boolean_bitfield(Attributes, 0x01, 16, "Read-only file", "Not a read-only file"));
	proto_tree_add_text(Attributes_tree, offset, 2, "%s",
			    decode_boolean_bitfield(Attributes, 0x02, 16, "Hidden file", "Not a hidden file"));
	proto_tree_add_text(Attributes_tree, offset, 2, "%s",
			    decode_boolean_bitfield(Attributes, 0x04, 16, "System file", "Not a system file"));
	proto_tree_add_text(Attributes_tree, offset, 2, "%s",
			    decode_boolean_bitfield(Attributes, 0x08, 16, " Volume", "Not a volume"));
	proto_tree_add_text(Attributes_tree, offset, 2, "%s",
			    decode_boolean_bitfield(Attributes, 0x10, 16, " Directory", "Not a directory"));
	proto_tree_add_text(Attributes_tree, offset, 2, "%s",
			    decode_boolean_bitfield(Attributes, 0x20, 16, " Archived", "Not archived"));
	
      }

      offset += 2; /* Skip Attributes */

      /* Build display for: Last Write Time */

      LastWriteTime = GSHORT(pd, offset);

      if (tree) {

      }

      offset += 2; /* Skip Last Write Time */

      /* Build display for: Last Write Date */

      LastWriteDate = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Last Write Date: %s", dissect_smbu_date(LastWriteDate, LastWriteTime));

	proto_tree_add_text(tree, offset, 2, "Last Write Time: %s", dissect_smbu_time(LastWriteDate, LastWriteTime));

      }

      offset += 2; /* Skip Last Write Date */

      /* Build display for: File Size */

      FileSize = GWORD(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 4, "File Size: %u", FileSize);

      }

      offset += 4; /* Skip File Size */

      /* Build display for: Reserved 1 */

      Reserved1 = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Reserved 1: %u", Reserved1);

      }

      offset += 2; /* Skip Reserved 1 */

      /* Build display for: Reserved 2 */

      Reserved2 = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Reserved 2: %u", Reserved2);

      }

      offset += 2; /* Skip Reserved 2 */

      /* Build display for: Reserved 3 */

      Reserved3 = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Reserved 3: %u", Reserved3);

      }

      offset += 2; /* Skip Reserved 3 */

      /* Build display for: Reserved 4 */

      Reserved4 = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Reserved 4: %u", Reserved4);

      }

      offset += 2; /* Skip Reserved 4 */

      /* Build display for: Reserved 5 */

      Reserved5 = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Reserved 5: %u", Reserved5);

      }

      offset += 2; /* Skip Reserved 5 */

    }

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

}

void
dissect_read_file_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  guint8        WordCount;
  guint32       Offset;
  guint16       Reserved4;
  guint16       Reserved3;
  guint16       Reserved2;
  guint16       Reserved1;
  guint16       Remaining;
  guint16       FID;
  guint16       DataLength;
  guint16       Count;
  guint16       ByteCount;
  guint16       BufferFormat;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: FID */

    FID = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "FID: %u", FID);

    }

    offset += 2; /* Skip FID */

    /* Build display for: Count */

    Count = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Count: %u", Count);

    }

    offset += 2; /* Skip Count */

    /* Build display for: Offset */

    Offset = GWORD(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 4, "Offset: %u", Offset);

    }

    offset += 4; /* Skip Offset */

    /* Build display for: Remaining */

    Remaining = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Remaining: %u", Remaining);

    }

    offset += 2; /* Skip Remaining */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    if (WordCount > 0) {

      /* Build display for: Count */

      Count = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Count: %u", Count);

      }

      offset += 2; /* Skip Count */

      /* Build display for: Reserved 1 */

      Reserved1 = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Reserved 1: %u", Reserved1);

      }

      offset += 2; /* Skip Reserved 1 */

      /* Build display for: Reserved 2 */

      Reserved2 = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Reserved 2: %u", Reserved2);

      }

      offset += 2; /* Skip Reserved 2 */

      /* Build display for: Reserved 3 */

      Reserved3 = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Reserved 3: %u", Reserved3);

      }

      offset += 2; /* Skip Reserved 3 */

      /* Build display for: Reserved 4 */

      Reserved4 = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Reserved 4: %u", Reserved4);

      }

      offset += 2; /* Skip Reserved 4 */

    }
    
    /* Build display for: Byte Count (BCC) */
    
    ByteCount = GSHORT(pd, offset);
      
    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

    /* Build display for: Buffer Format */

    BufferFormat = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Buffer Format: %u", BufferFormat);

    }

    offset += 2; /* Skip Buffer Format */

    /* Build display for: Data Length */

    DataLength = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Data Length: %u", DataLength);

    }

    offset += 2; /* Skip Data Length */

  }

}

void
dissect_write_mpx_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  proto_tree    *WriteMode_tree;
  proto_item    *ti;
  guint8        WordCount;
  guint8        Pad;
  guint32       Timeout;
  guint32       ResponseMask;
  guint32       RequestMask;
  guint16       WriteMode;
  guint16       Reserved1;
  guint16       FID;
  guint16       DataOffset;
  guint16       DataLength;
  guint16       Count;
  guint16       ByteCount;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: FID */

    FID = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "FID: %u", FID);

    }

    offset += 2; /* Skip FID */

    /* Build display for: Count */

    Count = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Count: %u", Count);

    }

    offset += 2; /* Skip Count */

    /* Build display for: Reserved 1 */

    Reserved1 = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Reserved 1: %u", Reserved1);

    }

    offset += 2; /* Skip Reserved 1 */

    /* Build display for: Timeout */

    Timeout = GWORD(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 4, "Timeout: %u", Timeout);

    }

    offset += 4; /* Skip Timeout */

    /* Build display for: WriteMode */

    WriteMode = GSHORT(pd, offset);

    if (tree) {

      ti = proto_tree_add_text(tree, offset, 2, "WriteMode: 0x%02x", WriteMode);
      WriteMode_tree = proto_item_add_subtree(ti, ett_smb_writemode);
      proto_tree_add_text(WriteMode_tree, offset, 2, "%s",
                          decode_boolean_bitfield(WriteMode, 0x01, 16, "Write through requested", "Write through not requested"));
      proto_tree_add_text(WriteMode_tree, offset, 2, "%s",
                          decode_boolean_bitfield(WriteMode, 0x02, 16, "Return Remaining", "Dont return Remaining"));
      proto_tree_add_text(WriteMode_tree, offset, 2, "%s",
                          decode_boolean_bitfield(WriteMode, 0x40, 16, "Connectionless mode requested", "Connectionless mode not requested"));
    
}

    offset += 2; /* Skip WriteMode */

    /* Build display for: Request Mask */

    RequestMask = GWORD(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 4, "Request Mask: %u", RequestMask);

    }

    offset += 4; /* Skip Request Mask */

    /* Build display for: Data Length */

    DataLength = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Data Length: %u", DataLength);

    }

    offset += 2; /* Skip Data Length */

    /* Build display for: Data Offset */

    DataOffset = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Data Offset: %u", DataOffset);

    }

    offset += 2; /* Skip Data Offset */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

    /* Build display for: Pad */

    Pad = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Pad: %u", Pad);

    }

    offset += 1; /* Skip Pad */

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    if (WordCount > 0) {

      /* Build display for: Response Mask */

      ResponseMask = GWORD(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 4, "Response Mask: %u", ResponseMask);

      }

      offset += 4; /* Skip Response Mask */

      /* Build display for: Byte Count (BCC) */

      ByteCount = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

      }

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

}

void
dissect_find_close2_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  guint8        WordCount;
  guint8        ByteCount;
  guint16       FID;

  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WTC) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WTC): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WTC) */

    /* Build display for: FID */

    FID = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "FID: %u", FID);

    }

    offset += 2; /* Skip FID */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 1; /* Skip Byte Count (BCC) */

  }

}

char *trans2_cmd_names[] = {
  "TRANS2_OPEN",
  "TRANS2_FIND_FIRST2",
  "TRANS2_FIND_NEXT2",
  "TRANS2_QUERY_FS_INFORMATION",
  "TRANS2_QUERY_PATH_INFORMATION",
  "TRANS2_SET_PATH_INFORMATION",
  "TRANS2_QUERY_FILE_INFORMATION",
  "TRANS2_SET_FILE_INFORMATION",
  "TRANS2_FSCTL",
  "TRANS2_IOCTL2",
  "TRANS2_FIND_NOTIFY_FIRST",
  "TRANS2_FIND_NOTIFY_NEXT",
  "TRANS2_CREATE_DIRECTORY",
  "TRANS2_SESSION_SETUP",
  "TRANS2_GET_DFS_REFERRAL",
  "no such command",
  "TRANS2_REPORT_DFS_INCONSISTENCY"};

char *decode_trans2_name(int code)
{

  if (code > 17 || code < 0) {

    return("no such command");

  }

  return trans2_cmd_names[code];

}

guint32 dissect_mailslot_smb(const u_char *, int, frame_data *, proto_tree *, proto_tree *, struct smb_info, int, int, int, int, const u_char *, int, int);

void
dissect_transact2_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  proto_tree    *Flags_tree;
  proto_item    *ti;
  guint8        WordCount;
  guint8        SetupCount;
  guint8        Reserved3;
  guint8        Reserved1;
  guint8        Pad2;
  guint8        Pad1;
  guint8        MaxSetupCount;
  guint8        Data;
  guint32       Timeout;
  guint16       TotalParameterCount;
  guint16       TotalDataCount;
  guint16       Setup = 0;
  guint16       Reserved2;
  guint16       ParameterOffset;
  guint16       ParameterDisplacement;
  guint16       ParameterCount;
  guint16       MaxParameterCount;
  guint16       MaxDataCount;
  guint16       Flags;
  guint16       DataOffset;
  guint16       DataDisplacement;
  guint16       DataCount;
  guint16       ByteCount;
  conversation_t *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.
   * 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 = find_conversation(&pi.src, &pi.dst, pi.ptype,
				pi.srcport, pi.destport);
  if (conversation == NULL) {
    /* It's not part of any conversation - create a new one. */
    conversation = conversation_new(&pi.src, &pi.dst, pi.ptype,
				pi.srcport, pi.destport, NULL);
  }

  /*
   * Check for and insert entry in request hash table if does not exist
   */
  request_key.conversation = conversation->index;
  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->index;
    new_request_key -> mid          = si.mid;

    request_val = g_mem_chunk_alloc(smb_request_vals);
    request_val -> mid = si.mid;
    request_val -> last_transact2_command = 0xFFFF;

    g_hash_table_insert(smb_request_hash, new_request_key, request_val);
    
  }
  else { /* Update the transact request */

    request_val -> mid = si.mid;

  }


  if (dirn == 1) { /* Request(s) dissect code */
  
    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Total Parameter Count */

    TotalParameterCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Total Parameter Count: %u", TotalParameterCount);

    }

    offset += 2; /* Skip Total Parameter Count */

    /* Build display for: Total Data Count */

    TotalDataCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Total Data Count: %u", TotalDataCount);

    }

    offset += 2; /* Skip Total Data Count */

    /* Build display for: Max Parameter Count */

    MaxParameterCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Max Parameter Count: %u", MaxParameterCount);

    }

    offset += 2; /* Skip Max Parameter Count */

    /* Build display for: Max Data Count */

    MaxDataCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Max Data Count: %u", MaxDataCount);

    }

    offset += 2; /* Skip Max Data Count */

    /* Build display for: Max Setup Count */

    MaxSetupCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Max Setup Count: %u", MaxSetupCount);

    }

    offset += 1; /* Skip Max Setup Count */

    /* Build display for: Reserved1 */

    Reserved1 = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Reserved1: %u", Reserved1);

    }

    offset += 1; /* Skip Reserved1 */

    /* Build display for: Flags */

    Flags = GSHORT(pd, offset);

    if (tree) {

      ti = proto_tree_add_text(tree, offset, 2, "Flags: 0x%02x", Flags);
      Flags_tree = proto_item_add_subtree(ti, ett_smb_flags);
      proto_tree_add_text(Flags_tree, offset, 2, "%s",
                          decode_boolean_bitfield(Flags, 0x01, 16, "Also disconnect TID", "Dont disconnect TID"));
      proto_tree_add_text(Flags_tree, offset, 2, "%s",
                          decode_boolean_bitfield(Flags, 0x02, 16, "One way transaction", "Two way transaction"));
    
}

    offset += 2; /* Skip Flags */

    /* Build display for: Timeout */

    Timeout = GWORD(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 4, "Timeout: %u", Timeout);

    }

    offset += 4; /* Skip Timeout */

    /* Build display for: Reserved2 */

    Reserved2 = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Reserved2: %u", Reserved2);

    }

    offset += 2; /* Skip Reserved2 */

    /* Build display for: Parameter Count */

    ParameterCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Parameter Count: %u", ParameterCount);

    }

    offset += 2; /* Skip Parameter Count */

    /* Build display for: Parameter Offset */

    ParameterOffset = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Parameter Offset: %u", ParameterOffset);

    }

    offset += 2; /* Skip Parameter Offset */

    /* Build display for: Data Count */

    DataCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Data Count: %u", DataCount);

    }

    offset += 2; /* Skip Data Count */

    /* Build display for: Data Offset */

    DataOffset = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Data Offset: %u", DataOffset);

    }

    offset += 2; /* Skip Data Offset */

    /* Build display for: Setup Count */

    SetupCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Setup Count: %u", SetupCount);

    }

    offset += 1; /* Skip Setup Count */

    /* Build display for: Reserved3 */

    Reserved3 = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Reserved3: %u", Reserved3);

    }

    offset += 1; /* Skip Reserved3 */

    /* Build display for: Setup */

    if (SetupCount > 0) {

      int i = SetupCount;

      Setup = GSHORT(pd, offset);

      request_val -> last_transact2_command = Setup;  /* Save for later */

      if (check_col(fd, COL_INFO)) {

	col_add_fstr(fd, COL_INFO, "%s %s", decode_trans2_name(Setup), (dirn ? "Request" : "Response"));

      }

      for (i = 1; i <= SetupCount; i++) {
	int Setup1;

	Setup1 = GSHORT(pd, offset);

	if (tree) {

	  proto_tree_add_text(tree, offset, 2, "Setup%i: %u", i, Setup1);

	}

	offset += 2; /* Skip Setup */

      }

    }

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

    /* Build display for: Transact Name */

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Transact Name 1: %s", decode_trans2_name(Setup));

    }

    if (offset % 2) {

      /* Build display for: Pad1 */

      Pad1 = GBYTE(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 1, "Pad1: %u", Pad1);

      }
    
      offset += 1; /* Skip Pad1 */

    }

    if (ParameterCount > 0) {

      /* Build display for: Parameters */

      if (tree) {

        proto_tree_add_text(tree, SMB_offset + ParameterOffset, ParameterCount, "Parameters: %s", format_text_ASCII(pd + SMB_offset + ParameterOffset, ParameterCount));
	proto_tree_add_text(tree, SMB_offset + ParameterOffset, ParameterCount, "Parameters: %s", format_text(pd + SMB_offset + ParameterOffset, ParameterCount));

      }

      offset += ParameterCount; /* Skip Parameters */

    }

    if (offset % 2) {
	
      /* Build display for: Pad2 */

      Pad2 = GBYTE(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 1, "Pad2: %u", Pad2);

      }

      offset += 1; /* Skip Pad2 */

    }

    if (DataCount > 0) {

      /* Build display for: Data */

      Data = GBYTE(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, SMB_offset + DataOffset, DataCount, "Data: %s", format_text_ASCII(&pd[offset], DataCount));
        proto_tree_add_text(tree, SMB_offset + DataOffset, DataCount, "Data: %s", format_text(pd + SMB_offset + DataOffset, DataCount));

      }

      offset += DataCount; /* Skip Data */

    }
  }

  if (dirn == 0) { /* Response(s) dissect code */

    /* Pick up the last transact2 command and put it in the right places */

    if (check_col(fd, COL_INFO)) {

      col_add_fstr(fd, COL_INFO, "%s %s", decode_trans2_name(request_val -> last_transact2_command), "response");

    }

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Total Parameter Count */

    TotalParameterCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Total Parameter Count: %u", TotalParameterCount);

    }

    offset += 2; /* Skip Total Parameter Count */

    /* Build display for: Total Data Count */

    TotalDataCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Total Data Count: %u", TotalDataCount);

    }

    offset += 2; /* Skip Total Data Count */

    /* Build display for: Reserved1 */

    Reserved1 = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Reserved1: %u", Reserved1);

    }

    offset += 2; /* Skip Reserved */

    /* Build display for: Parameter Count */

    ParameterCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Parameter Count: %u", ParameterCount);

    }

    offset += 2; /* Skip Parameter Count */

    /* Build display for: Parameter Offset */

    ParameterOffset = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Parameter Offset: %u", ParameterOffset);

    }

    offset += 2; /* Skip Parameter Offset */

    /* Build display for: Parameter Displacement */

    ParameterDisplacement = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Parameter Displacement: %u", ParameterDisplacement);

    }

    offset += 2; /* Skip Parameter Displacement */

    /* Build display for: Data Count */

    DataCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Data Count: %u", DataCount);

    }

    offset += 2; /* Skip Data Count */

    /* Build display for: Data Offset */

    DataOffset = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Data Offset: %u", DataOffset);

    }

    offset += 2; /* Skip Data Offset */

    /* Build display for: Data Displacement */

    DataDisplacement = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Data Displacement: %u", DataDisplacement);

    }

    offset += 2; /* Skip Data Displacement */

    /* Build display for: Setup Count */

    SetupCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Setup Count: %u", SetupCount);

    }

    offset += 1; /* Skip Setup Count */

    /* Build display for: Reserved2 */

    Reserved2 = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Reserved2: %u", Reserved2);

    }

    offset += 1; /* Skip Reserved2 */

    /* Build display for: Setup */

    Setup = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Setup: %u", Setup);

    }

    offset += 2; /* Skip Setup */

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

    /* Build display for: Pad1 */

    Pad1 = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Pad1: %u", Pad1);

    }

    offset += 1; /* Skip Pad1 */

    /* Build display for: Parameter */

    if (ParameterCount > 0) {

      if (tree) {

        proto_tree_add_text(tree, SMB_offset + ParameterOffset, ParameterCount, "Parameters: %s", format_text_ASCII(pd + SMB_offset + ParameterOffset, ParameterCount));
	proto_tree_add_text(tree, SMB_offset + ParameterOffset, ParameterCount, "Parameters: %s", format_text(pd + SMB_offset + ParameterOffset, ParameterCount));

      }

      offset += ParameterCount; /* Skip Parameter */

    }

   
    if (offset % 2) {
      /* Build display for: Pad2 */

      Pad2 = GBYTE(pd, offset);
      if (tree) {
        proto_tree_add_text(tree, offset, 1, "Pad2: %u", Pad2);
      }
      offset += 1; /* Skip Pad2 */
    }

    /* Build display for: Data */

    if (DataCount > 0) {

      if (tree) {

        proto_tree_add_text(tree, SMB_offset + DataOffset, DataCount, "Data: %s", format_text_ASCII(&pd[offset], DataCount));
	proto_tree_add_text(tree, SMB_offset + DataOffset, DataCount, "Data: %s", format_text(pd + SMB_offset + DataOffset, DataCount));

      }

      offset += DataCount; /* Skip Data */

    }

  }

}

void
dissect_transact_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn)

{
  proto_tree    *Flags_tree;
  proto_item    *ti;
  guint8        WordCount;
  guint8        SetupCount;
  guint8        Reserved3;
  guint8        Reserved1;
  guint8        Parameter;
  guint8        Pad2;
  guint8        Pad1;
  guint8        MaxSetupCount;
  guint8        Data;
  guint32       Timeout;
  guint16       TotalParameterCount;
  guint16       TotalDataCount;
  guint16       Setup = 0;
  guint16       Reserved2;
  guint16       ParameterOffset;
  guint16       ParameterDisplacement;
  guint16       ParameterCount;
  guint16       MaxParameterCount;
  guint16       MaxDataCount;
  guint16       Flags;
  guint16       DataOffset;
  guint16       DataDisplacement;
  guint16       DataCount;
  guint16       ByteCount;
  const char    *TransactName;
  char          *TransactNameCopy;
  char          *trans_type;
  char          *trans_cmd, *loc_of_slash;
  guint32       index=0;
  conversation_t *conversation;
  struct smb_request_key   request_key, *new_request_key;
  struct smb_request_val   *request_val;

  char          *ustr;
  int           ustr_len;
  guint8        Default_Path; 
  guint16       Flags2;

  /* obtain the Flags2 settings */
  Flags2 = GSHORT(pd, Flags2_Offset);


  /*
   * Find out what conversation this packet is part of
   */

  conversation = find_conversation(&pi.src, &pi.dst, pi.ptype,
				   pi.srcport, pi.destport);

  if (conversation == NULL) {  /* Create a new conversation */

    conversation = conversation_new(&pi.src, &pi.dst, pi.ptype,
				    pi.srcport, pi.destport, NULL);

  }

  /*
   * Check for and insert entry in request hash table if does not exist
   */
  request_key.conversation = conversation->index;
  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 -> index;
    new_request_key -> mid          = si.mid;

    request_val = g_mem_chunk_alloc(smb_request_vals);
    request_val -> mid = si.mid;
    request_val -> last_transact_command = NULL;

    g_hash_table_insert(smb_request_hash, new_request_key, request_val);

  }


  if (dirn == 1) { /* Request(s) dissect code */

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Total Parameter Count */

    TotalParameterCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Total Parameter Count: %u", TotalParameterCount);

    }

    offset += 2; /* Skip Total Parameter Count */

    /* Build display for: Total Data Count */

    TotalDataCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Total Data Count: %u", TotalDataCount);

    }

    offset += 2; /* Skip Total Data Count */

    /* Build display for: Max Parameter Count */

    MaxParameterCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Max Parameter Count: %u", MaxParameterCount);

    }

    offset += 2; /* Skip Max Parameter Count */

    /* Build display for: Max Data Count */

    MaxDataCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Max Data Count: %u", MaxDataCount);

    }

    offset += 2; /* Skip Max Data Count */

    /* Build display for: Max Setup Count */

    MaxSetupCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Max Setup Count: %u", MaxSetupCount);

    }

    offset += 1; /* Skip Max Setup Count */

    /* Build display for: Reserved1 */

    Reserved1 = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Reserved1: %u", Reserved1);

    }

    offset += 1; /* Skip Reserved1 */

    /* Build display for: Flags */

    Flags = GSHORT(pd, offset);

    if (tree) {

      ti = proto_tree_add_text(tree, offset, 2, "Flags: 0x%02x", Flags);
      Flags_tree = proto_item_add_subtree(ti, ett_smb_flags);
      proto_tree_add_text(Flags_tree, offset, 2, "%s",
                          decode_boolean_bitfield(Flags, 0x01, 16, "Also disconnect TID", "Dont disconnect TID"));
      proto_tree_add_text(Flags_tree, offset, 2, "%s",
                          decode_boolean_bitfield(Flags, 0x02, 16, "One way transaction", "Two way transaction"));
    
}

    offset += 2; /* Skip Flags */

    /* Build display for: Timeout */

    Timeout = GWORD(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 4, "Timeout: %u", Timeout);

    }

    offset += 4; /* Skip Timeout */

    /* Build display for: Reserved2 */

    Reserved2 = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Reserved2: %u", Reserved2);

    }

    offset += 2; /* Skip Reserved2 */

    /* Build display for: Parameter Count */

    ParameterCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Parameter Count: %u", ParameterCount);

    }

    offset += 2; /* Skip Parameter Count */

    /* Build display for: Parameter Offset */

    ParameterOffset = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Parameter Offset: %u", ParameterOffset);

    }

    offset += 2; /* Skip Parameter Offset */

    /* Build display for: Data Count */

    DataCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Data Count: %u", DataCount);

    }

    offset += 2; /* Skip Data Count */

    /* Build display for: Data Offset */

    DataOffset = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Data Offset: %u", DataOffset);

    }

    offset += 2; /* Skip Data Offset */

    /* Build display for: Setup Count */

    SetupCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Setup Count: %u", SetupCount);

    }

    offset += 1; /* Skip Setup Count */

    /* Build display for: Reserved3 */

    Reserved3 = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Reserved3: %u", Reserved3);

    }

    offset += 1; /* Skip Reserved3 */

    /* Build display for: Setup */

    if (SetupCount > 0) {

      int i = SetupCount;

      Setup = GSHORT(pd, offset);

      for (i = 1; i <= SetupCount; i++) {
	
	Setup = GSHORT(pd, offset);

	if (tree) {

	  proto_tree_add_text(tree, offset, 2, "Setup%i: %u", i, Setup);

	}

	offset += 2; /* Skip Setup */

      }

    }

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */


    /* Build display for: Transact Name */

    /* The Transact Name, a null terminated string; Unicode if "Flags" has
       the 0x8000 bit set, ASCII (OEM character set) otherwise.
       XXX - for now, we just handle the ISO 8859-1 subset of Unicode. */


    if (Flags2 & 0x8000) {
       offset +=1; /* skip EXTRA bit for unicode alignment */
    }
    TransactName = pd + offset;

    if (tree) {
      if (Flags2 & 0x8000) {
        ustr = unicode_to_str(TransactName, &ustr_len);
        proto_tree_add_text(tree, offset, ustr_len+2, "Transact Name 2: %s", ustr);
        offset += (strlen(ustr)*2) + 2; /* Skip Transact Name */
        TransactName=ustr;
      } else {
        proto_tree_add_text(tree, offset, strlen(TransactName) + 1, "Transact Name 2: %s", TransactName);
        offset += strlen(TransactName) + 1; /* Skip Transact Name */
      }
    }

    if (request_val -> last_transact_command) g_free(request_val -> last_transact_command);

    request_val -> last_transact_command = g_malloc(strlen(TransactName) + 1);

    if (request_val -> last_transact_command) 
      strcpy(request_val -> last_transact_command, TransactName);

    if (check_col(fd, COL_INFO)) {

      col_add_fstr(fd, COL_INFO, "%s %s", TransactName, (dirn ? "Request" : "Response"));

    }

    if (offset % 2) {

      /* Build display for: Pad1 */

      Pad1 = GBYTE(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 1, "Pad1: %u", Pad1);

      }
    
      offset += 1; /* Skip Pad1 */

    }

    /* Let's see if we can decode this */

    TransactNameCopy = g_malloc(strlen(TransactName) + 1);

    /* Bad, check for error? */

    strcpy(TransactNameCopy, TransactName);
    trans_type = TransactNameCopy + 1;  /* Skip the slash */
    loc_of_slash = strchr(trans_type, '\\');
    if (loc_of_slash) {
      index = loc_of_slash - trans_type;  /* Make it a real index */
      trans_cmd = trans_type + index + 1;
      trans_type[index] = '\0';
    }
    else
      trans_cmd = NULL; 



/*  If trans type != MAILSLOT then process mailslot.  if unsuccessful then default processing */

    Default_Path = 1;
    if (!strncmp(trans_type, "MAILSLOT",8))  
       Default_Path = !(dissect_mailslot_smb(pd, offset, fd, parent, tree, si, max_data, SMB_offset, errcode, dirn, trans_cmd, SMB_offset + DataOffset, DataCount));
    
    if (Default_Path) {

      if (ParameterCount > 0) {

	/* Build display for: Parameters */

	if (tree) {

          proto_tree_add_text(tree, SMB_offset + ParameterOffset, ParameterCount, "Parameters: %s", format_text_ASCII(pd + SMB_offset + ParameterOffset, ParameterCount));
	  proto_tree_add_text(tree, SMB_offset + ParameterOffset, ParameterCount, "Parameters: %s", format_text(pd + SMB_offset + ParameterOffset, ParameterCount));
	  
	}
	
	offset += ParameterCount; /* Skip Parameters */

      }

      if (offset % 2) {
	
	/* Build display for: Pad2 */

	Pad2 = GBYTE(pd, offset);

	if (tree) {

	  proto_tree_add_text(tree, offset, 1, "Pad2: %u", Pad2);

	}

	offset += 1; /* Skip Pad2 */

      }

      if (DataCount > 0) {

	/* Build display for: Data */

	Data = GBYTE(pd, offset);

	if (tree) {

          proto_tree_add_text(tree, SMB_offset + DataOffset, DataCount, "Data: %s", format_text_ASCII(&pd[offset], DataCount));
	  proto_tree_add_text(tree, SMB_offset + DataOffset, DataCount, "Data: %s", format_text(pd + SMB_offset + DataOffset, DataCount));

	}

	offset += DataCount; /* Skip Data */

      }
    }
  }

  if (dirn == 0) { /* Response(s) dissect code */

    if (check_col(fd, COL_INFO)) {

      col_add_fstr(fd, COL_INFO, "%s %s", request_val -> last_transact_command, "Response");

    }

    /* Build display for: Word Count (WCT) */

    WordCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Word Count (WCT): %u", WordCount);

    }

    offset += 1; /* Skip Word Count (WCT) */

    /* Build display for: Total Parameter Count */

    TotalParameterCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Total Parameter Count: %u", TotalParameterCount);

    }

    offset += 2; /* Skip Total Parameter Count */

    /* Build display for: Total Data Count */

    TotalDataCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Total Data Count: %u", TotalDataCount);

    }

    offset += 2; /* Skip Total Data Count */

    /* Build display for: Reserved2 */

    Reserved2 = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Reserved2: %u", Reserved2);

    }

    offset += 2; /* Skip Reserved2 */

    /* Build display for: Parameter Count */

    ParameterCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Parameter Count: %u", ParameterCount);

    }

    offset += 2; /* Skip Parameter Count */

    /* Build display for: Parameter Offset */

    ParameterOffset = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Parameter Offset: %u", ParameterOffset);

    }

    offset += 2; /* Skip Parameter Offset */

    /* Build display for: Parameter Displacement */

    ParameterDisplacement = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Parameter Displacement: %u", ParameterDisplacement);

    }

    offset += 2; /* Skip Parameter Displacement */

    /* Build display for: Data Count */

    DataCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Data Count: %u", DataCount);

    }

    offset += 2; /* Skip Data Count */

    /* Build display for: Data Offset */

    DataOffset = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Data Offset: %u", DataOffset);

    }

    offset += 2; /* Skip Data Offset */

    /* Build display for: Data Displacement */

    DataDisplacement = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Data Displacement: %u", DataDisplacement);

    }

    offset += 2; /* Skip Data Displacement */

    /* Build display for: Setup Count */

    SetupCount = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Setup Count: %u", SetupCount);

    }

    offset += 1; /* Skip Setup Count */

    /* Build display for: Reserved3 */

    Reserved3 = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Reserved3: %u", Reserved3);

    }

    offset += 1; /* Skip Reserved3 */

    /* Build display for: Setup */

    if (SetupCount > 0) {

      /* Hmmm, should code for all setup words ... */

      Setup = GSHORT(pd, offset);

      if (tree) {

	proto_tree_add_text(tree, offset, 2, "Setup: %u", Setup);

      }

    offset += 2; /* Skip Setup */

    }

    /* Build display for: Byte Count (BCC) */

    ByteCount = GSHORT(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 2, "Byte Count (BCC): %u", ByteCount);

    }

    offset += 2; /* Skip Byte Count (BCC) */

    /* Build display for: Pad1 */

    Pad1 = GBYTE(pd, offset);

    if (tree) {

      proto_tree_add_text(tree, offset, 1, "Pad1: %u", Pad1);

    }

    offset += 1; /* Skip Pad1 */

    if (ParameterCount > 0) {

      /* Build display for: Parameter */

      Parameter = GBYTE(pd, offset);

      if (tree) {

        proto_tree_add_text(tree, SMB_offset + ParameterOffset, ParameterCount, "Parameters: %s", format_text_ASCII(pd + SMB_offset + ParameterOffset, ParameterCount));
        proto_tree_add_text(tree, SMB_offset + ParameterOffset, ParameterCount, "Parameters: %s", format_text(pd + SMB_offset + ParameterOffset, ParameterCount));

      }

      offset += ParameterCount; /* Skip Parameter */
    }

    if (offset %2) {
      /* Build display for: Pad2 */

      Pad2 = GBYTE(pd, offset);
      if (tree) {
        proto_tree_add_text(tree, offset, 1, "Pad2: %u", Pad2);
      }
      offset += 1; /* Skip Pad2 */
    }

    /* Build display for: Data */

    if (DataCount > 0) {

      if (tree) {

        proto_tree_add_text(tree, SMB_offset + DataOffset, DataCount, "Data: %s", format_text_ASCII(&pd[offset], DataCount));
	proto_tree_add_text(tree, SMB_offset + DataOffset, DataCount, "Data: %s", format_text(pd + SMB_offset + DataOffset, DataCount));

      }

      offset += DataCount; /* Skip Data */

    }

  }

}

/*
 * The routines for mailslot and pipe dissecting should be migrated to another 
 * file soon?
 */

char *browse_commands[] = 
{ "Error, No such command!",       /* Value 0 */
  "Host Announcement",             /* Value 1 */
  "Request Announcement",          /* Value 2 */
  "Error, No such command!",       /* Value 3 */
  "Error, No such command!",       /* Value 4 */
  "Error, No such command!",       /* Value 5 */
  "Error, No such command!",       /* Value 6 */
  "Error, No such command!",       /* Value 7 */
  "Browser Election Request",      /* Value 8 */
  "Get Backup List Request",       /* Value 9 */
  "Get Backup List Response",      /* Value 10 */
  "Become Backup Browser",         /* Value 11 */
  "Domain/Workgroup Announcement", /* Value 12 */
  "Master Announcement",           /* Value 13 */
  "Error! No such command",        /* Value 14 */
  "Local Master Announcement"      /* Value 15 */
};

#define HOST_ANNOUNCE        1
#define REQUEST_ANNOUNCE     2
#define BROWSER_ELECTION     8
#define GETBACKUPLISTREQ     9
#define GETBACKUPLISTRESP   10
#define BECOMEBACKUPBROWSER 11
#define DOMAINANNOUNCEMENT  12
#define MASTERANNOUNCEMENT  13
#define LOCALMASTERANNOUNC  15

char *svr_types[32] = {
  "Workstation",
  "Server",
  "SQL Server",
  "Domain Controller",
  "Backup Controller",
  "Time Source",
  "Apple Server",
  "Novell Server",
  "Domain Member Server",
  "Print Queue Server",
  "Dialin Server",
  "Xenix Server",
  "NT Workstation",
  "Windows for Workgroups",
  "Unknown Server - FIXME",
  "NT Server",
  "Potential Browser",
  "Backup Browser",
  "Master Browser",
  "Domain Master Browser",
  "OSF",
  "VMS",
  "Windows 95 or above",
  "Unused",
  "Unused",
  "Unused",
  "Unused",
  "Unused",
  "Unused",
  "Unused",
  "Local List Only",
  "Domain Enum"
};

guint32
dissect_mailslot_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn, const u_char *command, int DataOffset, int DataCount)
{
  guint8               OpCode;
  guint8               UpdateCount;
  guint8               VersionMajor;
  guint8               VersionMinor;
  guint32              Periodicity;
  guint32              ServerType;
  guint16              SigConstant;
  guint32              Token;
  guint8               BackupServerCount;
  guint8               Flags;
  guint32              MBZ;
  guint8               ElectionVersion;
  guint32              ElectionCriteria;
  guint8               ElectionOS;
  guint8               ElectionDesire;
  guint16              ElectionRevision;
  guint32              ServerUpTime;
  const char           *ServerName;
  const char           *ServerComment;
  proto_tree           *browse_tree = NULL, *flags_tree = NULL, 
                       *OSflags = NULL, *DesireFlags = NULL;
  proto_item           *ti, *ec;
  guint32              loc_offset = DataOffset, count = 0;
  int                  i;

  if (strcmp(command, "BROWSE") == 0) { /* Decode a browse */

    if (check_col(fd, COL_PROTOCOL))
      col_add_str(fd, COL_PROTOCOL, "BROWSER");

    if (check_col(fd, COL_INFO)) /* Put in something, and replace it later */
      col_add_str(fd, COL_INFO, "Browse Announcement");

    /*
     * Now, decode the browse request 
     */

    OpCode = GBYTE(pd, loc_offset);

    if (check_col(fd, COL_INFO))
      col_add_fstr(fd, COL_INFO, (OpCode > (sizeof(browse_commands)/sizeof(char *))) ? "Error, No Such Command:%u" : browse_commands[OpCode], OpCode);
    
    if (tree) {  /* Add the browse tree */

      ti = proto_tree_add_item(parent, proto_browse, DataOffset, DataCount, NULL);
      browse_tree = proto_item_add_subtree(ti, ett_browse);

      proto_tree_add_text(browse_tree, loc_offset, 1, "OpCode: %s", (OpCode > (sizeof(browse_commands)/sizeof(char *))) ? "Error, No Such Command" : browse_commands[OpCode]);

    }

    loc_offset += 1;    /* Skip the OpCode */

    switch (OpCode) {

    case DOMAINANNOUNCEMENT:
    case LOCALMASTERANNOUNC:
    case HOST_ANNOUNCE:

      UpdateCount = GBYTE(pd, loc_offset);

      if (tree) {

	proto_tree_add_text(browse_tree, loc_offset, 1, "Update Count: %u", UpdateCount);

      }

      loc_offset += 1;  /* Skip the Update Count */

      Periodicity = GWORD(pd, loc_offset + 2);

      if (tree) {

	proto_tree_add_text(browse_tree, loc_offset, 4, "Update Periodicity: %u mSec", Periodicity >> 16);

      }

      loc_offset += 4;

      ServerName = pd + loc_offset;

      if (tree) {

	proto_tree_add_text(browse_tree, loc_offset, 16, (OpCode == DOMAINANNOUNCEMENT) ? "Domain/WorkGroup: %s": "Host Name: %s", ServerName);

      }

      loc_offset += 16;

      VersionMajor = GBYTE(pd, loc_offset);

      if (tree) {

	proto_tree_add_text(browse_tree, loc_offset, 1, "Major Version: %u", VersionMajor);

      }

      loc_offset += 1;

      VersionMinor = GBYTE(pd, loc_offset);

      if (tree) {

	proto_tree_add_text(browse_tree, loc_offset, 1, "Minor Version: %u", VersionMinor);

      }

      loc_offset += 1;

      ServerType = GWORD(pd, loc_offset);

      if (check_col(fd, COL_INFO)) {

	/* Append the type(s) of the system to the COL_INFO line ... */

	for (i = 1; i <= 32; i++) {

	  if (ServerType & (1 << (i - 1)) && (strcmp("Unused", svr_types[i]) != 0))
	    col_append_fstr(fd, COL_INFO, ", %s", svr_types[i - 1]);

	}

      }

      if (tree) {

	ti = proto_tree_add_text(browse_tree, loc_offset, 4, "Server Type: 0x%04x", ServerType);
	flags_tree = proto_item_add_subtree(ti, ett_browse_flags);
	proto_tree_add_text(flags_tree, loc_offset, 4, "%s",
			    decode_boolean_bitfield(ServerType, 0x0001, 32, "Workstation", "Not Workstation"));
	proto_tree_add_text(flags_tree, loc_offset, 4, "%s",
			    decode_boolean_bitfield(ServerType, 0x0002, 32, "Server", "Not Server"));
	proto_tree_add_text(flags_tree, loc_offset, 4, "%s",
			    decode_boolean_bitfield(ServerType, 0x0004, 32, "SQL Server", "Not SQL Server"));
	proto_tree_add_text(flags_tree, loc_offset, 4, "%s",
			    decode_boolean_bitfield(ServerType, 0x0008, 32, "Domain Controller", "Not Domain Controller"));
	proto_tree_add_text(flags_tree, loc_offset, 4, "%s",
			    decode_boolean_bitfield(ServerType, 0x0010, 32, "Backup Controller", "Not Backup Controller"));
	proto_tree_add_text(flags_tree, loc_offset, 4, "%s",
			    decode_boolean_bitfield(ServerType, 0x0020, 32, "Time Source", "Not Time Source"));
	proto_tree_add_text(flags_tree, loc_offset, 4, "%s",
			    decode_boolean_bitfield(ServerType, 0x0040, 32, "Apple Server", "Not Apple Server"));
	proto_tree_add_text(flags_tree, loc_offset, 4, "%s",
			    decode_boolean_bitfield(ServerType, 0x0080, 32, "Novell Server", "Not Novell Server"));
	proto_tree_add_text(flags_tree, loc_offset, 4, "%s",
			    decode_boolean_bitfield(ServerType, 0x0100, 32, "Domain Member Server", "Not Domain Member Server"));
	proto_tree_add_text(flags_tree, loc_offset, 4, "%s",
			    decode_boolean_bitfield(ServerType, 0x0200, 32, "Print Queue Server", "Not Print Queue Server"));      
	proto_tree_add_text(flags_tree, loc_offset, 4, "%s",
			    decode_boolean_bitfield(ServerType, 0x0400, 32, "Dialin Server", "Not Dialin Server"));
	proto_tree_add_text(flags_tree, loc_offset, 4, "%s",
			    decode_boolean_bitfield(ServerType, 0x0800, 32, "Xenix Server", "Not Xenix Server"));
	proto_tree_add_text(flags_tree, loc_offset, 4, "%s",
			    decode_boolean_bitfield(ServerType, 0x1000, 32, "NT Workstation", "Not NT Workstation"));
	proto_tree_add_text(flags_tree, loc_offset, 4, "%s",
			    decode_boolean_bitfield(ServerType, 0x2000, 32, "Windows for Workgroups", "Not Windows for Workgroups"));
	proto_tree_add_text(flags_tree, loc_offset, 4, "%s",
			    decode_boolean_bitfield(ServerType, 0x8000, 32, "NT Server", "Not NT Server"));
	proto_tree_add_text(flags_tree, loc_offset, 4, "%s",
			    decode_boolean_bitfield(ServerType, 0x10000, 32, "Potential Browser", "Not Potential Browser"));
	proto_tree_add_text(flags_tree, loc_offset, 4, "%s",
			    decode_boolean_bitfield(ServerType, 0x20000, 32, "Backup Browser", "Not Backup Browser"));
	proto_tree_add_text(flags_tree, loc_offset, 4, "%s",
			    decode_boolean_bitfield(ServerType, 0x40000, 32, "Master Browser", "Not Master Browser"));
	proto_tree_add_text(flags_tree, loc_offset, 4, "%s",
			    decode_boolean_bitfield(ServerType, 0x80000, 32, "Domain Master Browser", "Not Domain Master Browser"));
	proto_tree_add_text(flags_tree, loc_offset, 4, "%s",
			    decode_boolean_bitfield(ServerType, 0x100000, 32, "OSF", "Not OSF"));
	proto_tree_add_text(flags_tree, loc_offset, 4, "%s",
			    decode_boolean_bitfield(ServerType, 0x200000, 32, "VMS", "Not VMS"));
	proto_tree_add_text(flags_tree, loc_offset, 4, "%s",
			    decode_boolean_bitfield(ServerType, 0x400000, 32, "Windows 95 or above", "Not Windows 95 or above"));
	proto_tree_add_text(flags_tree, loc_offset, 4, "%s",
			    decode_boolean_bitfield(ServerType, 0x40000000, 32, "Local List Only", "Not Local List Only"));
	proto_tree_add_text(flags_tree, loc_offset, 4, "%s",
			    decode_boolean_bitfield(ServerType, 0x80000000, 32, "Domain Enum", "Not Domain Enum"));
      }
      loc_offset += 4;

      ElectionVersion = GSHORT(pd, loc_offset);

      if (tree) {

	proto_tree_add_text(browse_tree, loc_offset, 2, "Election Version: %u", ElectionVersion);

      }

      loc_offset += 2;

      SigConstant = GSHORT(pd, loc_offset);

      if (tree) {

	proto_tree_add_text(browse_tree, loc_offset, 2, "Signature: %u (0x%04X)", SigConstant, SigConstant);


      }

      loc_offset += 2;

      ServerComment = pd + loc_offset;

      if (tree) {

	proto_tree_add_text(browse_tree, loc_offset, strlen(ServerComment) + 1, "Host Comment: %s", ServerComment);

      }

      break;

    case REQUEST_ANNOUNCE:

      Flags = GBYTE(pd, loc_offset);

      if (tree) {

	proto_tree_add_text(browse_tree, loc_offset, 1, "Unused Flags: %u", Flags);

      }

      loc_offset += 1;

      ServerName = pd + loc_offset;

      if (tree) {

	proto_tree_add_text(browse_tree, loc_offset, strlen(ServerName) + 1, "Send List To: %s", ServerName);

      }

      break;

    case BROWSER_ELECTION:

      ElectionVersion = GBYTE(pd, loc_offset);

      if (tree) {

	proto_tree_add_text(browse_tree, loc_offset, 1, "Election Version = %u", ElectionVersion);

      }

      loc_offset += 1;

      ElectionCriteria = GWORD(pd, loc_offset);
      ElectionOS       = GBYTE(pd, loc_offset + 3);
      ElectionRevision = GSHORT(pd, loc_offset + 1);
      ElectionDesire   = GBYTE(pd, loc_offset);

      if (tree) {

	ti = proto_tree_add_text(browse_tree, loc_offset, 4, "Election Criteria = %u (0x%08X)", ElectionCriteria, ElectionCriteria);

	ec = proto_item_add_subtree(ti, ett_browse_election_criteria);

	ti = proto_tree_add_text(ec, loc_offset + 3, 1, "Election OS Summary: %u (0x%02X)", ElectionOS, ElectionOS);

	OSflags = proto_item_add_subtree(ti, ett_browse_election_os);

	proto_tree_add_text(OSflags, loc_offset + 3, 1, "%s",
			    decode_boolean_bitfield(ElectionOS, 0x01, 8, "Windows for Workgroups", "Not Windows for Workgroups"));

	proto_tree_add_text(OSflags, loc_offset + 3, 1, "%s",
			    decode_boolean_bitfield(ElectionOS, 0x02, 8, "Unknown", "Not used"));

	proto_tree_add_text(OSflags, loc_offset + 3, 1, "%s",
			    decode_boolean_bitfield(ElectionOS, 0x04, 8, "Unknown", "Not used"));

	proto_tree_add_text(OSflags, loc_offset + 3, 1, "%s",
			    decode_boolean_bitfield(ElectionOS, 0x08, 8, "Unknown", "Not used"));

	proto_tree_add_text(OSflags, loc_offset + 3, 1, "%s",
			    decode_boolean_bitfield(ElectionOS, 0x10, 8, "Windows NT Workstation", "Not Windows NT Workstation"));

	proto_tree_add_text(OSflags, loc_offset + 3, 1, "%s",
			    decode_boolean_bitfield(ElectionOS, 0x20, 8, "Windows NT Server", "Not Windows NT Server"));

	proto_tree_add_text(OSflags, loc_offset + 3, 1, "%s",
			    decode_boolean_bitfield(ElectionOS, 0x40, 8, "Unknown", "Not used"));

	proto_tree_add_text(OSflags, loc_offset + 3, 1, "%s",
			    decode_boolean_bitfield(ElectionOS, 0x80, 8, "Unknown", "Not used"));

	proto_tree_add_text(ec, loc_offset + 1, 2, "Election Revision: %u (0x%04X)", ElectionRevision, ElectionRevision);

	ti = proto_tree_add_text(ec, loc_offset, 1, "Election Desire Summary: %u (0x%02X)", ElectionDesire, ElectionDesire);

        DesireFlags = proto_item_add_subtree(ti, ett_browse_election_desire);

	proto_tree_add_text(DesireFlags, loc_offset, 1, "%s",
			     decode_boolean_bitfield(ElectionDesire, 0x01, 8, "Backup Browse Server", "Not Backup Browse Server"));

	proto_tree_add_text(DesireFlags, loc_offset, 1, "%s",
			     decode_boolean_bitfield(ElectionDesire, 0x02, 8, "Standby Browse Server", "Not Standby Browse Server"));

	proto_tree_add_text(DesireFlags, loc_offset, 1, "%s",
			     decode_boolean_bitfield(ElectionDesire, 0x04, 8, "Master Browser", "Not Master Browser"));

	proto_tree_add_text(DesireFlags, loc_offset, 1, "%s",
			     decode_boolean_bitfield(ElectionDesire, 0x08, 8, "Domain Master Browse Server", "Not Domain Master Browse Server"));

	proto_tree_add_text(DesireFlags, loc_offset, 1, "%s",
			     decode_boolean_bitfield(ElectionDesire, 0x10, 8, "Unknown", "Not used"));

	proto_tree_add_text(DesireFlags, loc_offset, 1, "%s",
			     decode_boolean_bitfield(ElectionDesire, 0x20, 8, "WINS Client", "Not WINS Client"));

	proto_tree_add_text(DesireFlags, loc_offset, 1, "%s",
			     decode_boolean_bitfield(ElectionDesire, 0x40, 8, "Unknown", "Not used"));

	proto_tree_add_text(DesireFlags, loc_offset, 1, "%s",
			     decode_boolean_bitfield(ElectionDesire, 0x80, 8, "Windows NT Advanced Server", "Not Windows NT Advanced Server"));

      }

      loc_offset += 4;

      ServerUpTime = GWORD(pd, loc_offset);

      if (tree) {

	proto_tree_add_text(browse_tree, loc_offset, 4, "Server Up Time: %u Sec", ServerUpTime);

      }

      loc_offset += 4;

      MBZ = GWORD(pd, loc_offset);

      loc_offset += 4;

      ServerName = pd + loc_offset;

      if (tree) {

	proto_tree_add_text(browse_tree, loc_offset, strlen(ServerName) + 1, "Election Server Name: %s", ServerName);

      }

      break;

    case GETBACKUPLISTREQ:

      BackupServerCount = GBYTE(pd, loc_offset);

      if (tree) {

	proto_tree_add_text(browse_tree, loc_offset, 1, "Backup List Requested Count: %u", BackupServerCount);

      }

      loc_offset += 1;

      Token = GWORD(pd, loc_offset);

      if (tree) {

	proto_tree_add_text(browse_tree, loc_offset, 4, "Backup Request Token: %u", Token);

      }

      break;

    case GETBACKUPLISTRESP:

      BackupServerCount = GBYTE(pd, loc_offset);

      if (tree) {

	proto_tree_add_text(browse_tree, loc_offset, 1, "Backup Server Count: %u", BackupServerCount);

      }

      loc_offset += 1;

      Token = GWORD(pd, loc_offset);

      if (tree) {

	proto_tree_add_text(browse_tree, loc_offset, 4, "Backup Response Token: %u", Token);

      }

      loc_offset += 4;

      ServerName = pd + loc_offset;

      for (count = 1; count <= BackupServerCount; count++) {

	if (tree) {

	  proto_tree_add_text(browse_tree, loc_offset, strlen(ServerName) + 1, "Backup Server: %s", ServerName);

	}

	loc_offset += strlen(ServerName) + 1;

	ServerName = pd + loc_offset;

      }

      break;

    case BECOMEBACKUPBROWSER:

      ServerName = pd + loc_offset;

      if (tree) {

	proto_tree_add_text(browse_tree, loc_offset, strlen(ServerName) + 1, "Browser to Promote: %s", ServerName);

      }

      break;

    case MASTERANNOUNCEMENT:

      ServerName = pd + loc_offset;

      if (tree) {

	proto_tree_add_text(browse_tree, loc_offset, strlen(ServerName) + 1, "Server Name: %s", ServerName);

      }

      break;

    default:
      break;
    }

    return 1;  /* Success */

  }

  return 0;
}

void (*dissect[256])(const u_char *, int, frame_data *, proto_tree *, proto_tree *, struct smb_info, int, int, int, int) = {

  dissect_unknown_smb,      /* unknown SMB 0x00 */
  dissect_unknown_smb,      /* unknown SMB 0x01 */
  dissect_unknown_smb,      /* SMBopen open a file */
  dissect_create_file_smb,  /* SMBcreate create a file */
  dissect_close_smb,        /* SMBclose close a file */
  dissect_flush_file_smb,   /* SMBflush flush a file */
  dissect_delete_file_smb,  /* SMBunlink delete a file */
  dissect_rename_file_smb,  /* SMBmv rename a file */
  dissect_get_file_attr_smb,/* SMBgetatr get file attributes */
  dissect_set_file_attr_smb,/* SMBsetatr set file attributes */
  dissect_read_file_smb,    /* SMBread read from a file */
  dissect_write_file_smb,   /* SMBwrite write to a file */
  dissect_lock_bytes_smb,   /* SMBlock lock a byte range */
  dissect_unlock_bytes_smb, /* SMBunlock unlock a byte range */
  dissect_create_temporary_file_smb,/* SMBctemp create a temporary file */
  dissect_unknown_smb,      /* SMBmknew make a new file */
  dissect_checkdir_smb,     /* SMBchkpth check a directory path */
  dissect_process_exit_smb,      /* SMBexit process exit */
  dissect_unknown_smb,      /* SMBlseek seek */
  dissect_lock_and_read_smb,/* SMBlockread Lock a range and read it */
  dissect_write_and_unlock_smb,/* SMBwriteunlock Unlock a range and then write */
  dissect_unknown_smb,      /* unknown SMB 0x15 */
  dissect_unknown_smb,      /* unknown SMB 0x16 */
  dissect_unknown_smb,      /* unknown SMB 0x17 */
  dissect_unknown_smb,      /* unknown SMB 0x18 */
  dissect_unknown_smb,      /* unknown SMB 0x19 */
  dissect_read_raw_smb,     /* SMBreadBraw read block raw */
  dissect_read_mpx_smb,     /* SMBreadBmpx read block multiplexed */
  dissect_unknown_smb,      /* SMBreadBs read block (secondary response) */
  dissect_write_raw_smb,    /* SMBwriteBraw write block raw */
  dissect_write_mpx_smb,    /* SMBwriteBmpx write block multiplexed */
  dissect_unknown_smb,      /* SMBwriteBs write block (secondary request) */
  dissect_unknown_smb,      /* SMBwriteC write complete response */
  dissect_unknown_smb,      /* unknown SMB 0x21 */
  dissect_set_info2_smb,    /* SMBsetattrE set file attributes expanded */
  dissect_query_info2_smb,  /* SMBgetattrE get file attributes expanded */
  dissect_locking_andx_smb, /* SMBlockingX lock/unlock byte ranges and X */
  dissect_transact_smb,      /* SMBtrans transaction - name, bytes in/out */
  dissect_unknown_smb,      /* SMBtranss transaction (secondary request/response) */
  dissect_unknown_smb,      /* SMBioctl IOCTL */
  dissect_unknown_smb,      /* SMBioctls IOCTL (secondary request/response) */
  dissect_unknown_smb,      /* SMBcopy copy */
  dissect_move_smb,      /* SMBmove move */
  dissect_unknown_smb,      /* SMBecho echo */
  dissect_unknown_smb,      /* SMBwriteclose write a file and then close it */
  dissect_open_andx_smb,      /* SMBopenX open and X */
  dissect_unknown_smb,      /* SMBreadX read and X */
  dissect_unknown_smb,      /* SMBwriteX write and X */
  dissect_unknown_smb,      /* unknown SMB 0x30 */
  dissect_unknown_smb,      /* unknown SMB 0x31 */
  dissect_transact2_smb,    /* unknown SMB 0x32 */
  dissect_unknown_smb,      /* unknown SMB 0x33 */
  dissect_find_close2_smb,  /* unknown SMB 0x34 */
  dissect_unknown_smb,      /* unknown SMB 0x35 */
  dissect_unknown_smb,      /* unknown SMB 0x36 */
  dissect_unknown_smb,      /* unknown SMB 0x37 */
  dissect_unknown_smb,      /* unknown SMB 0x38 */
  dissect_unknown_smb,      /* unknown SMB 0x39 */
  dissect_unknown_smb,      /* unknown SMB 0x3a */
  dissect_unknown_smb,      /* unknown SMB 0x3b */
  dissect_unknown_smb,      /* unknown SMB 0x3c */
  dissect_unknown_smb,      /* unknown SMB 0x3d */
  dissect_unknown_smb,      /* unknown SMB 0x3e */
  dissect_unknown_smb,      /* unknown SMB 0x3f */
  dissect_unknown_smb,      /* unknown SMB 0x40 */
  dissect_unknown_smb,      /* unknown SMB 0x41 */
  dissect_unknown_smb,      /* unknown SMB 0x42 */
  dissect_unknown_smb,      /* unknown SMB 0x43 */
  dissect_unknown_smb,      /* unknown SMB 0x44 */
  dissect_unknown_smb,      /* unknown SMB 0x45 */
  dissect_unknown_smb,      /* unknown SMB 0x46 */
  dissect_unknown_smb,      /* unknown SMB 0x47 */
  dissect_unknown_smb,      /* unknown SMB 0x48 */
  dissect_unknown_smb,      /* unknown SMB 0x49 */
  dissect_unknown_smb,      /* unknown SMB 0x4a */
  dissect_unknown_smb,      /* unknown SMB 0x4b */
  dissect_unknown_smb,      /* unknown SMB 0x4c */
  dissect_unknown_smb,      /* unknown SMB 0x4d */
  dissect_unknown_smb,      /* unknown SMB 0x4e */
  dissect_unknown_smb,      /* unknown SMB 0x4f */
  dissect_unknown_smb,      /* unknown SMB 0x50 */
  dissect_unknown_smb,      /* unknown SMB 0x51 */
  dissect_unknown_smb,      /* unknown SMB 0x52 */
  dissect_unknown_smb,      /* unknown SMB 0x53 */
  dissect_unknown_smb,      /* unknown SMB 0x54 */
  dissect_unknown_smb,      /* unknown SMB 0x55 */
  dissect_unknown_smb,      /* unknown SMB 0x56 */
  dissect_unknown_smb,      /* unknown SMB 0x57 */
  dissect_unknown_smb,      /* unknown SMB 0x58 */
  dissect_unknown_smb,      /* unknown SMB 0x59 */
  dissect_unknown_smb,      /* unknown SMB 0x5a */
  dissect_unknown_smb,      /* unknown SMB 0x5b */
  dissect_unknown_smb,      /* unknown SMB 0x5c */
  dissect_unknown_smb,      /* unknown SMB 0x5d */
  dissect_unknown_smb,      /* unknown SMB 0x5e */
  dissect_unknown_smb,      /* unknown SMB 0x5f */
  dissect_unknown_smb,      /* unknown SMB 0x60 */
  dissect_unknown_smb,      /* unknown SMB 0x61 */
  dissect_unknown_smb,      /* unknown SMB 0x62 */
  dissect_unknown_smb,      /* unknown SMB 0x63 */
  dissect_unknown_smb,      /* unknown SMB 0x64 */
  dissect_unknown_smb,      /* unknown SMB 0x65 */
  dissect_unknown_smb,      /* unknown SMB 0x66 */
  dissect_unknown_smb,      /* unknown SMB 0x67 */
  dissect_unknown_smb,      /* unknown SMB 0x68 */
  dissect_unknown_smb,      /* unknown SMB 0x69 */
  dissect_unknown_smb,      /* unknown SMB 0x6a */
  dissect_unknown_smb,      /* unknown SMB 0x6b */
  dissect_unknown_smb,      /* unknown SMB 0x6c */
  dissect_unknown_smb,      /* unknown SMB 0x6d */
  dissect_unknown_smb,      /* unknown SMB 0x6e */
  dissect_unknown_smb,      /* unknown SMB 0x6f */
  dissect_treecon_smb,      /* SMBtcon tree connect */
  dissect_tdis_smb,         /* SMBtdis tree disconnect */
  dissect_negprot_smb,      /* SMBnegprot negotiate a protocol */
  dissect_ssetup_andx_smb,  /* SMBsesssetupX Session Set Up & X (including User Logon) */
  dissect_logoff_andx_smb,  /* SMBlogof Logoff & X */
  dissect_tcon_andx_smb,    /* SMBtconX tree connect and X */
  dissect_unknown_smb,      /* unknown SMB 0x76 */
  dissect_unknown_smb,      /* unknown SMB 0x77 */
  dissect_unknown_smb,      /* unknown SMB 0x78 */
  dissect_unknown_smb,      /* unknown SMB 0x79 */
  dissect_unknown_smb,      /* unknown SMB 0x7a */
  dissect_unknown_smb,      /* unknown SMB 0x7b */
  dissect_unknown_smb,      /* unknown SMB 0x7c */
  dissect_unknown_smb,      /* unknown SMB 0x7d */
  dissect_unknown_smb,      /* unknown SMB 0x7e */
  dissect_unknown_smb,      /* unknown SMB 0x7f */
  dissect_get_disk_attr_smb,/* SMBdskattr get disk attributes */
  dissect_search_dir_smb,   /* SMBsearch search a directory */
  dissect_unknown_smb,      /* SMBffirst find first */
  dissect_unknown_smb,      /* SMBfunique find unique */
  dissect_unknown_smb,      /* SMBfclose find close */
  dissect_unknown_smb,      /* unknown SMB 0x85 */
  dissect_unknown_smb,      /* unknown SMB 0x86 */
  dissect_unknown_smb,      /* unknown SMB 0x87 */
  dissect_unknown_smb,      /* unknown SMB 0x88 */
  dissect_unknown_smb,      /* unknown SMB 0x89 */
  dissect_unknown_smb,      /* unknown SMB 0x8a */
  dissect_unknown_smb,      /* unknown SMB 0x8b */
  dissect_unknown_smb,      /* unknown SMB 0x8c */
  dissect_unknown_smb,      /* unknown SMB 0x8d */
  dissect_unknown_smb,      /* unknown SMB 0x8e */
  dissect_unknown_smb,      /* unknown SMB 0x8f */
  dissect_unknown_smb,      /* unknown SMB 0x90 */
  dissect_unknown_smb,      /* unknown SMB 0x91 */
  dissect_unknown_smb,      /* unknown SMB 0x92 */
  dissect_unknown_smb,      /* unknown SMB 0x93 */
  dissect_unknown_smb,      /* unknown SMB 0x94 */
  dissect_unknown_smb,      /* unknown SMB 0x95 */
  dissect_unknown_smb,      /* unknown SMB 0x96 */
  dissect_unknown_smb,      /* unknown SMB 0x97 */
  dissect_unknown_smb,      /* unknown SMB 0x98 */
  dissect_unknown_smb,      /* unknown SMB 0x99 */
  dissect_unknown_smb,      /* unknown SMB 0x9a */
  dissect_unknown_smb,      /* unknown SMB 0x9b */
  dissect_unknown_smb,      /* unknown SMB 0x9c */
  dissect_unknown_smb,      /* unknown SMB 0x9d */
  dissect_unknown_smb,      /* unknown SMB 0x9e */
  dissect_unknown_smb,      /* unknown SMB 0x9f */
  dissect_unknown_smb,      /* unknown SMB 0xa0 */
  dissect_unknown_smb,      /* unknown SMB 0xa1 */
  dissect_unknown_smb,      /* unknown SMB 0xa2 */
  dissect_unknown_smb,      /* unknown SMB 0xa3 */
  dissect_unknown_smb,      /* unknown SMB 0xa4 */
  dissect_unknown_smb,      /* unknown SMB 0xa5 */
  dissect_unknown_smb,      /* unknown SMB 0xa6 */
  dissect_unknown_smb,      /* unknown SMB 0xa7 */
  dissect_unknown_smb,      /* unknown SMB 0xa8 */
  dissect_unknown_smb,      /* unknown SMB 0xa9 */
  dissect_unknown_smb,      /* unknown SMB 0xaa */
  dissect_unknown_smb,      /* unknown SMB 0xab */
  dissect_unknown_smb,      /* unknown SMB 0xac */
  dissect_unknown_smb,      /* unknown SMB 0xad */
  dissect_unknown_smb,      /* unknown SMB 0xae */
  dissect_unknown_smb,      /* unknown SMB 0xaf */
  dissect_unknown_smb,      /* unknown SMB 0xb0 */
  dissect_unknown_smb,      /* unknown SMB 0xb1 */
  dissect_unknown_smb,      /* unknown SMB 0xb2 */
  dissect_unknown_smb,      /* unknown SMB 0xb3 */
  dissect_unknown_smb,      /* unknown SMB 0xb4 */
  dissect_unknown_smb,      /* unknown SMB 0xb5 */
  dissect_unknown_smb,      /* unknown SMB 0xb6 */
  dissect_unknown_smb,      /* unknown SMB 0xb7 */
  dissect_unknown_smb,      /* unknown SMB 0xb8 */
  dissect_unknown_smb,      /* unknown SMB 0xb9 */
  dissect_unknown_smb,      /* unknown SMB 0xba */
  dissect_unknown_smb,      /* unknown SMB 0xbb */
  dissect_unknown_smb,      /* unknown SMB 0xbc */
  dissect_unknown_smb,      /* unknown SMB 0xbd */
  dissect_unknown_smb,      /* unknown SMB 0xbe */
  dissect_unknown_smb,      /* unknown SMB 0xbf */
  dissect_unknown_smb,      /* SMBsplopen open a print spool file */
  dissect_write_print_file_smb,/* SMBsplwr write to a print spool file */
  dissect_close_print_file_smb,/* SMBsplclose close a print spool file */
  dissect_get_print_queue_smb, /* SMBsplretq return print queue */
  dissect_unknown_smb,      /* unknown SMB 0xc4 */
  dissect_unknown_smb,      /* unknown SMB 0xc5 */
  dissect_unknown_smb,      /* unknown SMB 0xc6 */
  dissect_unknown_smb,      /* unknown SMB 0xc7 */
  dissect_unknown_smb,      /* unknown SMB 0xc8 */
  dissect_unknown_smb,      /* unknown SMB 0xc9 */
  dissect_unknown_smb,      /* unknown SMB 0xca */
  dissect_unknown_smb,      /* unknown SMB 0xcb */
  dissect_unknown_smb,      /* unknown SMB 0xcc */
  dissect_unknown_smb,      /* unknown SMB 0xcd */
  dissect_unknown_smb,      /* unknown SMB 0xce */
  dissect_unknown_smb,      /* unknown SMB 0xcf */
  dissect_unknown_smb,      /* SMBsends send a single block message */
  dissect_unknown_smb,      /* SMBsendb send a broadcast message */
  dissect_unknown_smb,      /* SMBfwdname forward user name */
  dissect_unknown_smb,      /* SMBcancelf cancel forward */
  dissect_unknown_smb,      /* SMBgetmac get a machine name */
  dissect_unknown_smb,      /* SMBsendstrt send start of multi-block message */
  dissect_unknown_smb,      /* SMBsendend send end of multi-block message */
  dissect_unknown_smb,      /* SMBsendtxt send text of multi-block message */
  dissect_unknown_smb,      /* unknown SMB 0xd8 */
  dissect_unknown_smb,      /* unknown SMB 0xd9 */
  dissect_unknown_smb,      /* unknown SMB 0xda */
  dissect_unknown_smb,      /* unknown SMB 0xdb */
  dissect_unknown_smb,      /* unknown SMB 0xdc */
  dissect_unknown_smb,      /* unknown SMB 0xdd */
  dissect_unknown_smb,      /* unknown SMB 0xde */
  dissect_unknown_smb,      /* unknown SMB 0xdf */
  dissect_unknown_smb,      /* unknown SMB 0xe0 */
  dissect_unknown_smb,      /* unknown SMB 0xe1 */
  dissect_unknown_smb,      /* unknown SMB 0xe2 */
  dissect_unknown_smb,      /* unknown SMB 0xe3 */
  dissect_unknown_smb,      /* unknown SMB 0xe4 */
  dissect_unknown_smb,      /* unknown SMB 0xe5 */
  dissect_unknown_smb,      /* unknown SMB 0xe6 */
  dissect_unknown_smb,      /* unknown SMB 0xe7 */
  dissect_unknown_smb,      /* unknown SMB 0xe8 */
  dissect_unknown_smb,      /* unknown SMB 0xe9 */
  dissect_unknown_smb,      /* unknown SMB 0xea */
  dissect_unknown_smb,      /* unknown SMB 0xeb */
  dissect_unknown_smb,      /* unknown SMB 0xec */
  dissect_unknown_smb,      /* unknown SMB 0xed */
  dissect_unknown_smb,      /* unknown SMB 0xee */
  dissect_unknown_smb,      /* unknown SMB 0xef */
  dissect_unknown_smb,      /* unknown SMB 0xf0 */
  dissect_unknown_smb,      /* unknown SMB 0xf1 */
  dissect_unknown_smb,      /* unknown SMB 0xf2 */
  dissect_unknown_smb,      /* unknown SMB 0xf3 */
  dissect_unknown_smb,      /* unknown SMB 0xf4 */
  dissect_unknown_smb,      /* unknown SMB 0xf5 */
  dissect_unknown_smb,      /* unknown SMB 0xf6 */
  dissect_unknown_smb,      /* unknown SMB 0xf7 */
  dissect_unknown_smb,      /* unknown SMB 0xf8 */
  dissect_unknown_smb,      /* unknown SMB 0xf9 */
  dissect_unknown_smb,      /* unknown SMB 0xfa */
  dissect_unknown_smb,      /* unknown SMB 0xfb */
  dissect_unknown_smb,      /* unknown SMB 0xfc */
  dissect_unknown_smb,      /* unknown SMB 0xfd */
  dissect_unknown_smb,      /* SMBinvalid invalid command */
  dissect_unknown_smb       /* unknown SMB 0xff */

};

static const value_string errcls_types[] = {
  { SMB_SUCCESS, "Success"},
  { SMB_ERRDOS, "DOS Error"},
  { SMB_ERRSRV, "Server Error"},
  { SMB_ERRHRD, "Hardware Error"},
  { SMB_ERRCMD, "Command Error - Not an SMB format command"},
  { 0, 0}
};

char *decode_smb_name(unsigned char cmd)
{

  return(SMB_names[cmd]);

}

static const value_string DOS_errors[] = {
  {SMBE_badfunc, "Invalid function (or system call)"},
  {SMBE_badfile, "File not found (pathname error)"},
  {SMBE_badpath, "Directory not found"},
  {SMBE_nofids, "Too many open files"},
  {SMBE_noaccess, "Access denied"},
  {SMBE_badfid, "Invalid fid"},
  {SMBE_nomem,  "Out of memory"},
  {SMBE_badmem, "Invalid memory block address"},
  {SMBE_badenv, "Invalid environment"},
  {SMBE_badaccess, "Invalid open mode"},
  {SMBE_baddata, "Invalid data (only from ioctl call)"},
  {SMBE_res, "Reserved error code?"}, 
  {SMBE_baddrive, "Invalid drive"},
  {SMBE_remcd, "Attempt to delete current directory"},
  {SMBE_diffdevice, "Rename/move across different filesystems"},
  {SMBE_nofiles, "no more files found in file search"},
  {SMBE_badshare, "Share mode on file conflict with open mode"},
  {SMBE_lock, "Lock request conflicts with existing lock"},
  {SMBE_unsup, "Request unsupported, returned by Win 95"},
  {SMBE_filexists, "File in operation already exists"},
  {SMBE_cannotopen, "Cannot open the file specified"},
  {SMBE_unknownlevel, "Unknown level??"},
  {SMBE_badpipe, "Named pipe invalid"},
  {SMBE_pipebusy, "All instances of pipe are busy"},
  {SMBE_pipeclosing, "Named pipe close in progress"},
  {SMBE_notconnected, "No process on other end of named pipe"},
  {SMBE_moredata, "More data to be returned"},
  {SMBE_baddirectory,  "Invalid directory name in a path."},
  {SMBE_eas_didnt_fit, "Extended attributes didn't fit"},
  {SMBE_eas_nsup, "Extended attributes not supported"},
  {SMBE_notify_buf_small, "Buffer too small to return change notify."},
  {SMBE_unknownipc, "Unknown IPC Operation"},
  {SMBE_noipc, "Don't support ipc"},
  {0, 0}
  };

/* Error codes for the ERRSRV class */

static const value_string SRV_errors[] = {
  {SMBE_error, "Non specific error code"},
  {SMBE_badpw, "Bad password"},
  {SMBE_badtype, "Reserved"},
  {SMBE_access, "No permissions to perform the requested operation"},
  {SMBE_invnid, "TID invalid"},
  {SMBE_invnetname, "Invalid network name. Service not found"},
  {SMBE_invdevice, "Invalid device"},
  {SMBE_unknownsmb, "Unknown SMB, from NT 3.5 response"},
  {SMBE_qfull, "Print queue full"},
  {SMBE_qtoobig, "Queued item too big"},
  {SMBE_qeof, "EOF on print queue dump"},
  {SMBE_invpfid, "Invalid print file in smb_fid"},
  {SMBE_smbcmd, "Unrecognised command"},
  {SMBE_srverror, "SMB server internal error"},
  {SMBE_filespecs, "Fid and pathname invalid combination"},
  {SMBE_badlink, "Bad link in request ???"},
  {SMBE_badpermits, "Access specified for a file is not valid"},
  {SMBE_badpid, "Bad process id in request"},
  {SMBE_setattrmode, "Attribute mode invalid"},
  {SMBE_paused, "Message server paused"},
  {SMBE_msgoff, "Not receiving messages"},
  {SMBE_noroom, "No room for message"},
  {SMBE_rmuns, "Too many remote usernames"},
  {SMBE_timeout, "Operation timed out"},
  {SMBE_noresource, "No resources currently available for request."},
  {SMBE_toomanyuids, "Too many userids"},
  {SMBE_baduid, "Bad userid"},
  {SMBE_useMPX, "Temporarily unable to use raw mode, use MPX mode"},
  {SMBE_useSTD, "Temporarily unable to use raw mode, use standard mode"},
  {SMBE_contMPX, "Resume MPX mode"},
  {SMBE_badPW, "Bad Password???"},
  {SMBE_nosupport, "Operation not supported???"},
  { 0, 0}
};

/* Error codes for the ERRHRD class */

static const value_string HRD_errors[] = {
  {SMBE_nowrite, "read only media"},
  {SMBE_badunit, "Unknown device"},
  {SMBE_notready, "Drive not ready"},
  {SMBE_badcmd, "Unknown command"},
  {SMBE_data, "Data (CRC) error"},
  {SMBE_badreq, "Bad request structure length"},
  {SMBE_seek, "Seek error???"},
  {SMBE_badmedia, "Bad media???"},
  {SMBE_badsector, "Bad sector???"},
  {SMBE_nopaper, "No paper in printer???"},
  {SMBE_write, "Write error???"},
  {SMBE_read, "Read error???"},
  {SMBE_general, "General error???"},
  {SMBE_badshare, "A open conflicts with an existing open"},
  {SMBE_lock, "Lock/unlock error"},
  {SMBE_wrongdisk,  "Wrong disk???"},
  {SMBE_FCBunavail, "FCB unavailable???"},
  {SMBE_sharebufexc, "Share buffer excluded???"},
  {SMBE_diskfull, "Disk full???"},
  {0, 0}
};

char *decode_smb_error(guint8 errcls, guint8 errcode)
{

  switch (errcls) {

  case SMB_SUCCESS:

    return("No Error");   /* No error ??? */
    break;

  case SMB_ERRDOS:

    return(val_to_str(errcode, DOS_errors, "Unknown DOS error (%x)"));
    break;

  case SMB_ERRSRV:

    return(val_to_str(errcode, SRV_errors, "Unknown SRV error (%x)"));
    break;

  case SMB_ERRHRD:

    return(val_to_str(errcode, HRD_errors, "Unknown HRD error (%x)"));
    break;

  default:

    return("Unknown error class!");

  }

}

#define SMB_FLAGS_DIRN 0x80

void
dissect_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int max_data)
{
        proto_tree      *smb_tree = tree, *flags_tree, *flags2_tree;
	proto_item      *ti, *tf;
	guint8          cmd, errcls, errcode1, flags;
	guint16         flags2, errcode, tid, pid, uid, mid;
	int             SMB_offset = offset;
	struct smb_info si;

	cmd = pd[offset + SMB_hdr_com_offset];

	if (check_col(fd, COL_PROTOCOL))
		col_add_str(fd, COL_PROTOCOL, "SMB");

	/* Hmmm, poor coding here ... Also, should check the type */

	if (check_col(fd, COL_INFO)) {

	  col_add_fstr(fd, COL_INFO, "%s %s", decode_smb_name(cmd), (pi.match_port == pi.destport)? "Request" : "Response");

	}

	if (tree) {

	  ti = proto_tree_add_item(tree, proto_smb, offset, END_OF_FRAME, NULL);
	  smb_tree = proto_item_add_subtree(ti, ett_smb);

	  /* 0xFFSMB is actually a 1 byte msg type and 3 byte server
	   * component ... SMB is only one used
	   */

	  proto_tree_add_text(smb_tree, offset, 1, "Message Type: 0xFF");
	  proto_tree_add_text(smb_tree, offset+1, 3, "Server Component: SMB");

	}

	offset += 4;  /* Skip the marker */

	if (tree) {

	  proto_tree_add_text(smb_tree, offset, 1, "Command: %s", decode_smb_name(cmd));

	}

	offset += 1;

	/* Next, look at the error class, SMB_RETCLASS */

	errcls = pd[offset];

	if (tree) {

	  proto_tree_add_text(smb_tree, offset, 1, "Error Class: %s", 
			      val_to_str((guint8)pd[offset], errcls_types, "Unknown Error Class (%x)"));
	}

	offset += 1;

	/* Error code, SMB_HEINFO ... */

	errcode1 = pd[offset];

	if (tree) {

	  proto_tree_add_text(smb_tree, offset, 1, "Reserved: %i", errcode1); 

	}

	offset += 1;

	errcode = GSHORT(pd, offset); 

	if (tree) {

	  proto_tree_add_text(smb_tree, offset, 2, "Error Code: %s",
			      decode_smb_error(errcls, errcode));

	}

	offset += 2;

	/* Now for the flags: Bit 0 = 0 means cmd, 0 = 1 means resp */

	flags = pd[offset];

	if (tree) {

	  tf = proto_tree_add_text(smb_tree, offset, 1, "Flags: 0x%02x", flags);

	  flags_tree = proto_item_add_subtree(tf, ett_smb_flags);
	  proto_tree_add_text(flags_tree, offset, 1, "%s",
			      decode_boolean_bitfield(flags, 0x01, 8,
						      "Lock&Read, Write&Unlock supported",
						      "Lock&Read, Write&Unlock not supported"));
	  proto_tree_add_text(flags_tree, offset, 1, "%s",
			      decode_boolean_bitfield(flags, 0x02, 8,
						      "Receive buffer posted",
						      "Receive buffer not posted"));
	  proto_tree_add_text(flags_tree, offset, 1, "%s",
			      decode_boolean_bitfield(flags, 0x08, 8, 
						      "Path names caseless",
						      "Path names case sensitive"));
	  proto_tree_add_text(flags_tree, offset, 1, "%s",
			      decode_boolean_bitfield(flags, 0x10, 8,
						      "Pathnames canonicalized",
						      "Pathnames not canonicalized"));
	  proto_tree_add_text(flags_tree, offset, 1, "%s",
			      decode_boolean_bitfield(flags, 0x20, 8,
						      "OpLocks requested/granted",
						      "OpLocks not requested/granted"));
	  proto_tree_add_text(flags_tree, offset, 1, "%s",
			      decode_boolean_bitfield(flags, 0x40, 8, 
						      "Notify all",
						      "Notify open only"));

	  proto_tree_add_text(flags_tree, offset, 1, "%s",
			      decode_boolean_bitfield(flags, SMB_FLAGS_DIRN,
						      8, "Response to client/redirector", "Request to server"));

	}

	offset += 1;

	flags2 = GSHORT(pd, offset);

	if (tree) {

	  tf = proto_tree_add_text(smb_tree, offset, 1, "Flags2: 0x%04x", flags2);

	  flags2_tree = proto_item_add_subtree(tf, ett_smb_flags2);
	  proto_tree_add_text(flags2_tree, offset, 1, "%s",
			      decode_boolean_bitfield(flags2, 0x0001, 16,
						      "Long file names supported",
						      "Long file names not supported"));
	  proto_tree_add_text(flags2_tree, offset, 1, "%s",
			      decode_boolean_bitfield(flags2, 0x0002, 16,
						      "Extended attributes supported",
						      "Extended attributes not supported"));
	  proto_tree_add_text(flags2_tree, offset, 1, "%s",
			      decode_boolean_bitfield(flags2, 0x0004, 16,
						      "Security signatures supported",
						      "Security signatures not supported"));
	  proto_tree_add_text(flags2_tree, offset, 1, "%s",
			      decode_boolean_bitfield(flags2, 0x0800, 16,
						      "Extended security negotiation supported",
						      "Extended security negotiation not supported"));
	  proto_tree_add_text(flags2_tree, offset, 1, "%s",
			      decode_boolean_bitfield(flags2, 0x1000, 16, 
						      "Resolve pathnames with DFS",
						      "Don't resolve pathnames with DFS"));
	  proto_tree_add_text(flags2_tree, offset, 1, "%s",
			      decode_boolean_bitfield(flags2, 0x2000, 16,
						      "Permit reads if execute-only",
						      "Don't permit reads if execute-only"));
	  proto_tree_add_text(flags2_tree, offset, 1, "%s",
			      decode_boolean_bitfield(flags2, 0x4000, 16,
						      "Error codes are NT error codes",
						      "Error codes are DOS error codes"));
	  proto_tree_add_text(flags2_tree, offset, 1, "%s",
			      decode_boolean_bitfield(flags2, 0x8000, 16, 
						      "Strings are Unicode",
						      "Strings are ASCII"));

	}

	offset += 2;

	if (tree) {

	  proto_tree_add_text(smb_tree, offset, 12, "Reserved: 6 WORDS");

	}

	offset += 12;

	/* Now the TID, tree ID */

	tid = GSHORT(pd, offset);
	si.tid = tid;

	if (tree) {

	  proto_tree_add_text(smb_tree, offset, 2, "Network Path/Tree ID (TID): %i (%04x)", tid, tid); 

	}

	offset += 2;

	/* Now the PID, Process ID */

	pid = GSHORT(pd, offset);
	si.pid = pid;

	if (tree) {

	  proto_tree_add_text(smb_tree, offset, 2, "Process ID (PID): %i (%04x)", pid, pid); 

	}

	offset += 2;

        /* Now the UID, User ID */

	uid = GSHORT(pd, offset);
	si.uid = uid;

	if (tree) {

	  proto_tree_add_text(smb_tree, offset, 2, "User ID (UID): %i (%04x)", uid, uid); 

	}
	
	offset += 2;

        /* Now the MID, Multiplex ID */

	mid = GSHORT(pd, offset);
	si.mid = mid;

	if (tree) {

	  proto_tree_add_text(smb_tree, offset, 2, "Multiplex ID (MID): %i (%04x)", mid, mid); 

	}

	offset += 2;

	/* Now vector through the table to dissect them */

	(dissect[cmd])(pd, offset, fd, tree, smb_tree, si, max_data, SMB_offset, errcode,
		       ((flags & 0x80) == 0));


}

void
proto_register_smb(void)
{
/*        static hf_register_info hf[] = {
                { &variable,
                { "Name",           "smb.abbreviation", TYPE, VALS_POINTER }},
        };*/
	static gint *ett[] = {
		&ett_smb,
		&ett_smb_fileattributes,
		&ett_smb_capabilities,
		&ett_smb_aflags,
		&ett_smb_dialects,
		&ett_smb_mode,
		&ett_smb_rawmode,
		&ett_smb_flags,
		&ett_smb_flags2,
		&ett_smb_desiredaccess,
		&ett_smb_search,
		&ett_smb_file,
		&ett_smb_openfunction,
		&ett_smb_filetype,
		&ett_smb_action,
		&ett_smb_writemode,
		&ett_smb_lock_type,
		&ett_browse,
		&ett_browse_flags,
		&ett_browse_election_criteria,
		&ett_browse_election_os,
		&ett_browse_election_desire
	};

        proto_smb = proto_register_protocol("Server Message Block Protocol", "smb");
	proto_browse = proto_register_protocol("Microsoft Windows Browser Protocol", "browser");
 /*       proto_register_field_array(proto_smb, hf, array_length(hf));*/
	proto_register_subtree_array(ett, array_length(ett));
	register_init_routine(&smb_init_protocol);
}