]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #485 in SNORT/snort3 from dce_smb to master
authorRuss Combs (rucombs) <rucombs@cisco.com>
Wed, 25 May 2016 21:37:32 +0000 (17:37 -0400)
committerRuss Combs (rucombs) <rucombs@cisco.com>
Wed, 25 May 2016 21:37:32 +0000 (17:37 -0400)
Squashed commit of the following:

commit 4f07d0b1f5c6d2fc5347c880272d44634fdfdecf
Author: mdagon <mdagon@cisco.com>
Date:   Wed May 25 13:07:13 2016 -0400

    Code review comments - fix for attr read only

commit 2e7b4d50df5f194872ec774c0fdda7b26f256601
Author: mdagon <mdagon@cisco.com>
Date:   Wed May 25 10:23:06 2016 -0400

    Code review: delete #if 0

commit 6a89d70677259c72296cb984cce4b89f8cb371df
Author: mdagon <mdagon@cisco.com>
Date:   Tue May 24 16:17:27 2016 -0400

    Code review comments: remove WIN32

commit d3b22b60cd0c820ca9a887d4948998aedd0e86a6
Author: mdagon <mdagon@cisco.com>
Date:   Mon May 23 04:12:18 2016 -0400

    1. Ported large portion of smb header processing, including required infrastructure.
    2. Replaced usage of ntohs, ntohl with smb version (now in packet.h).

src/protocols/packet.h
src/service_inspectors/dce_rpc/dce_common.h
src/service_inspectors/dce_rpc/dce_list.cc
src/service_inspectors/dce_rpc/dce_list.h
src/service_inspectors/dce_rpc/dce_smb.cc
src/service_inspectors/dce_rpc/dce_smb.h
src/service_inspectors/dce_rpc/dce_smb_module.cc
src/service_inspectors/dce_rpc/dce_smb_module.h

index 7b3d79a9fedb4a0d9ab369a31b3d1034c0b6060c..81a8da0c37c402596efd934e01d7a82771f535af 100644 (file)
@@ -315,5 +315,74 @@ inline uint32_t extract_32bits(const uint8_t* p)
 { return ntohl(*(uint32_t*)p); }
 
 #endif
+
+inline uint16_t alignedNtohs(const uint16_t* ptr)
+{
+    uint16_t value;
+
+    if (ptr == nullptr)
+        return 0;
+
+#ifdef WORDS_MUSTALIGN
+    value = *((uint8_t*)ptr) << 8 | *((uint8_t*)ptr + 1);
+#else
+    value = *ptr;
+#endif
+
+#ifdef WORDS_BIGENDIAN
+    return ((value & 0xff00) >> 8) | ((value & 0x00ff) << 8);
+#else
+    return value;
+#endif  /* WORDS_BIGENDIAN */
+}
+
+inline uint32_t alignedNtohl(const uint32_t* ptr)
+{
+    uint32_t value;
+
+    if (ptr == nullptr)
+        return 0;
+
+#ifdef WORDS_MUSTALIGN
+    value = *((uint8_t*)ptr) << 24 | *((uint8_t*)ptr + 1) << 16 |
+        *((uint8_t*)ptr + 2) << 8  | *((uint8_t*)ptr + 3);
+#else
+    value = *ptr;
+#endif  /* WORDS_MUSTALIGN */
+
+#ifdef WORDS_BIGENDIAN
+    return ((value & 0xff000000) >> 24) | ((value & 0x00ff0000) >> 8)  |
+           ((value & 0x0000ff00) << 8)  | ((value & 0x000000ff) << 24);
+#else
+    return value;
+#endif  /* WORDS_BIGENDIAN */
+}
+
+inline uint64_t alignedNtohq(const uint64_t* ptr)
+{
+    uint64_t value;
+
+    if (ptr == NULL)
+        return 0;
+
+#ifdef WORDS_MUSTALIGN
+    value = *((uint8_t*)ptr) << 56 | *((uint8_t*)ptr + 1) << 48 |
+        *((uint8_t*)ptr + 2) << 40 | *((uint8_t*)ptr + 3) << 32 |
+        *((uint8_t*)ptr + 4) << 24 | *((uint8_t*)ptr + 5) << 16 |
+        *((uint8_t*)ptr + 6) << 8  | *((uint8_t*)ptr + 7);
+#else
+    value = *ptr;
+#endif  /* WORDS_MUSTALIGN */
+
+#ifdef WORDS_BIGENDIAN
+    return ((value & 0xff00000000000000) >> 56) | ((value & 0x00ff000000000000) >> 40) |
+           ((value & 0x0000ff0000000000) >> 24) | ((value & 0x000000ff00000000) >> 8)  |
+           ((value & 0x00000000ff000000) << 8)  | ((value & 0x0000000000ff0000) << 24) |
+           ((value & 0x000000000000ff00) << 40) | ((value & 0x00000000000000ff) << 56);
+#else
+    return value;
+#endif  /* WORDS_BIGENDIAN */
+}
+
 #endif
 
index cc45f694bd0233372f186e221b28ec7dae04054a..b9f0a3e13ff0d594f1cb47fea214e97c0768c98d 100644 (file)
@@ -329,11 +329,75 @@ inline bool DCE2_SsnIsWindowsPolicy(DCE2_SsnData* sd)
     return false;
 }
 
+/********************************************************************
+ * Function: DCE2_SsnIsSambaPolicy()
+ *
+ * Purpose:
+ *  Convenience function to determine if policy traffic is going to
+ *  is a Samba one.
+ *
+ * Arguments:
+ *  DCE2_SsnData * - pointer to session data
+ *
+ * Returns:
+ *  bool  -  true if Samba, false if not
+ *
+ ********************************************************************/
+inline bool DCE2_SsnIsSambaPolicy(DCE2_SsnData* sd)
+{
+    DCE2_Policy policy = DCE2_SsnGetPolicy(sd);
+
+    switch (policy)
+    {
+    case DCE2_POLICY__SAMBA:
+    case DCE2_POLICY__SAMBA_3_0_37:
+    case DCE2_POLICY__SAMBA_3_0_22:
+    case DCE2_POLICY__SAMBA_3_0_20:
+        return true;
+    default:
+        break;
+    }
+
+    return false;
+}
+
 inline DCE2_Policy DCE2_SsnGetServerPolicy(DCE2_SsnData* sd)
 {
     return sd->server_policy;
 }
 
+/********************************************************************
+ * Function: DCE2_SsnIsServerSambaPolicy()
+ *
+ * Purpose:
+ *  Convenience function to determine if server policy is a
+ *  Samba one.
+ *
+ * Arguments:
+ *  DCE2_SsnData * - pointer to session data
+ *
+ * Returns:
+ *  bool  -  true if Samba, false if not
+ *
+ ********************************************************************/
+inline bool DCE2_SsnIsServerSambaPolicy(DCE2_SsnData* sd)
+{
+    DCE2_Policy policy = DCE2_SsnGetServerPolicy(sd);
+
+    switch (policy)
+    {
+    case DCE2_POLICY__SAMBA:
+    case DCE2_POLICY__SAMBA_3_0_37:
+    case DCE2_POLICY__SAMBA_3_0_22:
+    case DCE2_POLICY__SAMBA_3_0_20:
+        return true;
+    default:
+        break;
+    }
+
+    return false;
+}
+
 inline void dce_alert(uint32_t gid, uint32_t sid, dce2CommonStats* stats)
 {
     SnortEventqAdd(gid,sid);
index b531ac6abbc5af8cd414c1651057e6d1db2546db..28164d388a125605dffad9cfed8907a177bb1a36 100644 (file)
@@ -568,6 +568,124 @@ DCE2_Ret DCE2_ListFindKey(DCE2_List* list, void* key)
     return DCE2_RET__ERROR;
 }
 
+/********************************************************************
+ * Function: DCE2_ListRemove()
+ *
+ * Removes the node in the list with the specified key.  If
+ * data free and key free functions were given with the creation
+ * of the list object, they are called with the data and key
+ * respectively.
+ *
+ * Arguments:
+ *  DCE2_List *
+ *      A pointer to the list object.
+ *  void *
+ *      Pointer to a key.
+ *
+ * Returns:
+ *  DCE2_Ret
+ *      DCE2_RET__ERROR if a node in the list with the specified
+ *          key cannot be found or the list object passed in is NULL.
+ *      DCE2_RET__SUCCESS if the node is successfully removed from
+ *          the list.
+ *
+ ********************************************************************/
+DCE2_Ret DCE2_ListRemove(DCE2_List* list, void* key)
+{
+    DCE2_ListNode* n;
+
+    if (list == nullptr)
+        return DCE2_RET__ERROR;
+
+    for (n = list->head; n != nullptr; n = n->next)
+    {
+        int comp = list->compare(key, n->key);
+        if (comp == 0)
+        {
+            /* Found it */
+            break;
+        }
+        else if ((comp < 0) && (list->type == DCE2_LIST_TYPE__SORTED))
+        {
+            /* Won't find it after this since the list is sorted */
+            return DCE2_RET__ERROR;
+        }
+    }
+
+    if (n == nullptr)
+        return DCE2_RET__ERROR;
+
+    if (n == list->head)
+        list->head = n->next;
+    if (n == list->tail)
+        list->tail = n->prev;
+    if (n->prev != nullptr)
+        n->prev->next = n->next;
+    if (n->next != nullptr)
+        n->next->prev = n->prev;
+
+    if (list->key_free != nullptr)
+        list->key_free(n->key);
+
+    if (list->data_free != nullptr)
+        list->data_free(n->data);
+
+    free((void*)n);
+
+    list->num_nodes--;
+
+    return DCE2_RET__SUCCESS;
+}
+
+/********************************************************************
+ * Function: DCE2_ListRemoveCurrent()
+ *
+ * Removes the current node pointed to in the list.  This is set
+ * when a call to DCE2_ListFirst or DCE2_ListNext is called.  For
+ * either of these if data is returned and the user want to remove
+ * that data from the list, this function should be called.
+ * Sets a next pointer, so a next call to DCE2_ListNext will point
+ * to the node after the deleted one.
+ *
+ * Arguments:
+ *  DCE2_List *
+ *      A pointer to the list object.
+ *
+ * Returns: None
+ *
+ ********************************************************************/
+void DCE2_ListRemoveCurrent(DCE2_List* list)
+{
+    if (list == nullptr)
+        return;
+
+    if (list->current == nullptr)
+        return;
+
+    list->next = list->current->next;
+    list->prev = list->current->prev;
+
+    if (list->current == list->head)
+        list->head = list->current->next;
+    if (list->current == list->tail)
+        list->tail = list->current->prev;
+    if (list->current->prev != nullptr)
+        list->current->prev->next = list->current->next;
+    if (list->current->next != nullptr)
+        list->current->next->prev = list->current->prev;
+
+    if (list->key_free != nullptr)
+        list->key_free(list->current->key);
+
+    if (list->data_free != nullptr)
+        list->data_free(list->current->data);
+
+    free((void*)list->current);
+    list->current = nullptr;
+
+    list->num_nodes--;
+}
+
 /********************************************************************
  * Function: DCE2_QueueNew()
  *
@@ -869,6 +987,38 @@ void DCE2_QueueRemoveCurrent(DCE2_Queue* queue)
     queue->num_nodes--;
 }
 
+/********************************************************************
+ * Function: DCE2_QueueLast()
+ *
+ * Returns a pointer to the data of the last node in the queue.
+ * Sets a current pointer to the last node in the queue for
+ * iterating over the queue backwards.
+ *
+ * Arguments:
+ *  DCE2_Queue *
+ *      A pointer to the queue object.
+ *
+ * Returns:
+ *  void *
+ *      The data in the last node in the queue.
+ *      NULL if the queue object passed in is NULL, or there are
+ *          no items in the queue.
+ *
+ ********************************************************************/
+void* DCE2_QueueLast(DCE2_Queue* queue)
+{
+    if (queue == nullptr)
+        return nullptr;
+
+    queue->current = queue->tail;
+    queue->prev = nullptr;
+
+    if (queue->current != nullptr)
+        return queue->current->data;
+
+    return nullptr;
+}
+
 /********************************************************************
  * Function: DCE2_CStackNew()
  *
index c16538f554f3de8d09d56a35931121ff854d6656..357769a738651c391c7b857cca9846ecb80888b0 100644 (file)
@@ -127,6 +127,8 @@ void DCE2_ListEmpty(DCE2_List*);
 void DCE2_ListDestroy(DCE2_List*);
 void* DCE2_ListFind(DCE2_List*, void*);
 DCE2_Ret DCE2_ListFindKey(DCE2_List*, void*);
+DCE2_Ret DCE2_ListRemove(DCE2_List*, void*);
+void DCE2_ListRemoveCurrent(DCE2_List*);
 
 DCE2_Queue* DCE2_QueueNew(DCE2_QueueDataFree);
 DCE2_Ret DCE2_QueueEnqueue(DCE2_Queue*, void*);
@@ -137,6 +139,7 @@ void* DCE2_QueueFirst(DCE2_Queue*);
 void* DCE2_QueueNext(DCE2_Queue*);
 void DCE2_QueueDestroy(DCE2_Queue*);
 void DCE2_QueueRemoveCurrent(DCE2_Queue*);
+void* DCE2_QueueLast(DCE2_Queue*);
 
 DCE2_CStack* DCE2_CStackNew(int, DCE2_CStackDataFree);
 DCE2_Ret DCE2_CStackPush(DCE2_CStack*, void*);
index 7ec3db3ac9d1e6ef0c177327dab4e756e49e54f0..41a0aa7db776cbb524bf6af53d7fc8ed6699bbf1 100644 (file)
@@ -92,6 +92,73 @@ struct DCE2_SmbComInfo
     uint16_t cmd_size;
 };
 
+// Inline accessor functions for DCE2_SmbComInfo
+
+static inline bool DCE2_ComInfoIsResponse(const DCE2_SmbComInfo* com_info)
+{
+    return (com_info->smb_type == SMB_TYPE__RESPONSE) ? true : false;
+}
+
+static inline bool DCE2_ComInfoIsRequest(const DCE2_SmbComInfo* com_info)
+{
+    return (com_info->smb_type == SMB_TYPE__REQUEST) ? true : false;
+}
+
+static inline uint16_t DCE2_ComInfoByteCount(const DCE2_SmbComInfo* com_info)
+{
+    return com_info->byte_count;
+}
+
+static inline uint8_t DCE2_ComInfoSmbCom(const DCE2_SmbComInfo* com_info)
+{
+    return com_info->smb_com;
+}
+
+static inline uint16_t DCE2_ComInfoCommandSize(const DCE2_SmbComInfo* com_info)
+{
+    return com_info->cmd_size;
+}
+
+static inline bool DCE2_ComInfoIsCommandOK(const DCE2_SmbComInfo* com_info)
+{
+    return (com_info->cmd_error == DCE2_SMB_COM_ERROR__COMMAND_OK) ? true : false;
+}
+
+static inline bool DCE2_ComInfoIsStatusError(const DCE2_SmbComInfo* com_info)
+{
+    return (com_info->cmd_error & DCE2_SMB_COM_ERROR__STATUS_ERROR) ? true : false;
+}
+
+static inline bool DCE2_ComInfoIsInvalidWordCount(const DCE2_SmbComInfo* com_info)
+{
+    return (com_info->cmd_error & DCE2_SMB_COM_ERROR__INVALID_WORD_COUNT) ? true : false;
+}
+
+static inline bool DCE2_ComInfoIsInvalidByteCount(const DCE2_SmbComInfo* com_info)
+{
+    return (com_info->cmd_error & DCE2_SMB_COM_ERROR__INVALID_BYTE_COUNT) ? true : false;
+}
+
+static inline bool DCE2_ComInfoIsBadLength(const DCE2_SmbComInfo* com_info)
+{
+    return (com_info->cmd_error & DCE2_SMB_COM_ERROR__BAD_LENGTH) ? true : false;
+}
+
+static inline uint8_t DCE2_ComInfoWordCount(const DCE2_SmbComInfo* com_info)
+{
+    return com_info->word_count;
+}
+
+// If this returns false, the command should not be processed
+static inline bool DCE2_ComInfoCanProcessCommand(const DCE2_SmbComInfo* com_info)
+{
+    if (DCE2_ComInfoIsBadLength(com_info)
+        || DCE2_ComInfoIsStatusError(com_info)
+        || DCE2_ComInfoIsInvalidWordCount(com_info))
+        return false;
+    return true;
+}
+
 /********************************************************************
  * Global variables
  ********************************************************************/
@@ -366,6 +433,95 @@ const char* smb_com_strings[SMB_MAX_NUM_COMS] =
     "No AndX Command"              // 0xFF
 };
 
+const char* smb_transaction_sub_command_strings[TRANS_SUBCOM_MAX] =
+{
+    "Unknown",                               // 0x0000
+    "TRANS_SET_NMPIPE_STATE",                // 0x0001
+    "Unknown",                               // 0x0002
+    "Unknown",                               // 0x0003
+    "Unknown",                               // 0x0004
+    "Unknown",                               // 0x0005
+    "Unknown",                               // 0x0006
+    "Unknown",                               // 0x0007
+    "Unknown",                               // 0x0008
+    "Unknown",                               // 0x0009
+    "Unknown",                               // 0x000A
+    "Unknown",                               // 0x000B
+    "Unknown",                               // 0x000C
+    "Unknown",                               // 0x000D
+    "Unknown",                               // 0x000E
+    "Unknown",                               // 0x000F
+    "Unknown",                               // 0x0010
+    "TRANS_RAW_READ_NMPIPE",                 // 0x0011
+    "Unknown",                               // 0x0012
+    "Unknown",                               // 0x0013
+    "Unknown",                               // 0x0014
+    "Unknown",                               // 0x0015
+    "Unknown",                               // 0x0016
+    "Unknown",                               // 0x0017
+    "Unknown",                               // 0x0018
+    "Unknown",                               // 0x0019
+    "Unknown",                               // 0x001A
+    "Unknown",                               // 0x001B
+    "Unknown",                               // 0x001C
+    "Unknown",                               // 0x001D
+    "Unknown",                               // 0x001E
+    "Unknown",                               // 0x001F
+    "Unknown",                               // 0x0020
+    "TRANS_QUERY_NMPIPE_STATE",              // 0x0021
+    "TRANS_QUERY_NMPIPE_INFO",               // 0x0022
+    "TRANS_PEEK_NMPIPE",                     // 0x0023
+    "Unknown",                               // 0x0024
+    "Unknown",                               // 0x0025
+    "TRANS_TRANSACT_NMPIPE",                 // 0x0026
+    "Unknown",                               // 0x0027
+    "Unknown",                               // 0x0028
+    "Unknown",                               // 0x0029
+    "Unknown",                               // 0x002A
+    "Unknown",                               // 0x002B
+    "Unknown",                               // 0x002C
+    "Unknown",                               // 0x002D
+    "Unknown",                               // 0x002E
+    "Unknown",                               // 0x002F
+    "Unknown",                               // 0x0030
+    "TRANS_RAW_WRITE_NMPIPE",                // 0x0031
+    "Unknown",                               // 0x0032
+    "Unknown",                               // 0x0033
+    "Unknown",                               // 0x0034
+    "Unknown",                               // 0x0035
+    "TRANS_READ_NMPIPE",                     // 0x0036
+    "TRANS_WRITE_NMPIPE",                    // 0x0037
+    "Unknown",                               // 0x0038
+    "Unknown",                               // 0x0039
+    "Unknown",                               // 0x003A
+    "Unknown",                               // 0x003B
+    "Unknown",                               // 0x003C
+    "Unknown",                               // 0x003D
+    "Unknown",                               // 0x003E
+    "Unknown",                               // 0x003F
+    "Unknown",                               // 0x0040
+    "Unknown",                               // 0x0041
+    "Unknown",                               // 0x0042
+    "Unknown",                               // 0x0043
+    "Unknown",                               // 0x0044
+    "Unknown",                               // 0x0045
+    "Unknown",                               // 0x0046
+    "Unknown",                               // 0x0047
+    "Unknown",                               // 0x0048
+    "Unknown",                               // 0x0049
+    "Unknown",                               // 0x004A
+    "Unknown",                               // 0x004B
+    "Unknown",                               // 0x004C
+    "Unknown",                               // 0x004D
+    "Unknown",                               // 0x004E
+    "Unknown",                               // 0x004F
+    "Unknown",                               // 0x0050
+    "Unknown",                               // 0x0051
+    "Unknown",                               // 0x0052
+    "TRANS_WAIT_NMPIPE",                     // 0x0053
+    "TRANS_CALL_NMPIPE"                      // 0x0054
+};
+
 /********************************************************************
  * Private function prototypes
  ********************************************************************/
@@ -390,6 +546,103 @@ static DCE2_SmbRequestTracker* DCE2_SmbFindRequestTracker(DCE2_SmbSsnData*,
     const SmbNtHdr*);
 static void DCE2_SmbCleanTransactionTracker(DCE2_SmbTransactionTracker*);
 static void DCE2_SmbCleanRequestTracker(DCE2_SmbRequestTracker*);
+static void DCE2_SmbRemoveRequestTracker(DCE2_SmbSsnData*, DCE2_SmbRequestTracker*);
+static DCE2_SmbFileTracker* DCE2_SmbNewFileTracker(DCE2_SmbSsnData*,
+    const uint16_t, const uint16_t, const uint16_t);
+static DCE2_SmbFileTracker* DCE2_SmbGetFileTracker(DCE2_SmbSsnData*,
+    const uint16_t);
+static DCE2_SmbFileTracker* DCE2_SmbGetTmpFileTracker(DCE2_SmbRequestTracker*);
+static void DCE2_SmbRemoveFileTracker(DCE2_SmbSsnData*, DCE2_SmbFileTracker*);
+static void DCE2_SmbCleanFileTracker(DCE2_SmbFileTracker*);
+static int DCE2_SmbUidTidFidCompare(const void*, const void*);
+static DCE2_Ret DCE2_SmbFindUid(DCE2_SmbSsnData*, const uint16_t);
+static void DCE2_SmbInsertUid(DCE2_SmbSsnData*, const uint16_t);
+static void DCE2_SmbRemoveUid(DCE2_SmbSsnData*, const uint16_t);
+static void DCE2_SmbFileTrackerDataFree(void*);
+static void DCE2_SmbCleanSessionFileTracker(DCE2_SmbSsnData*, DCE2_SmbFileTracker*);
+static void DCE2_SmbRemoveFileTrackerFromRequestTrackers(DCE2_SmbSsnData*,
+    DCE2_SmbFileTracker*);
+static DCE2_SmbFileTracker* DCE2_SmbDequeueTmpFileTracker(DCE2_SmbSsnData*,
+    DCE2_SmbRequestTracker*, const uint16_t);
+static char* DCE2_SmbGetString(const uint8_t*, uint32_t, bool, bool);
+static inline DCE2_Ret DCE2_SmbProcessRequestData(DCE2_SmbSsnData*, const uint16_t,
+    const uint8_t*, uint32_t, uint64_t);
+static DCE2_Ret DCE2_SmbProcessResponseData(DCE2_SmbSsnData*,
+    const uint8_t*, uint32_t);
+static inline void DCE2_SmbCheckFmtData(DCE2_SmbSsnData*, const uint32_t,
+    const uint16_t, const uint8_t, const uint16_t, const uint16_t);
+static inline DCE2_Ret DCE2_SmbCheckData(DCE2_SmbSsnData*, const uint8_t*,
+    const uint8_t*, const uint32_t, const uint16_t, const uint32_t, uint16_t);
+static inline bool DCE2_SmbIsTransactionComplete(DCE2_SmbTransactionTracker*);
+static inline DCE2_Ret DCE2_SmbCheckAndXOffset(const uint8_t*,
+    const uint8_t*, const uint32_t);
+static void DCE2_SmbQueueTmpFileTracker(DCE2_SmbSsnData*,
+    DCE2_SmbRequestTracker*, const uint16_t, const uint16_t);
+static DCE2_Ret DCE2_SmbFindTid(DCE2_SmbSsnData*, const uint16_t);
+static void DCE2_SmbRemoveTid(DCE2_SmbSsnData*, const uint16_t);
+static void DCE2_SmbInsertTid(DCE2_SmbSsnData*, const uint16_t, const bool);
+static void DCE2_SmbInvalidShareCheck(DCE2_SmbSsnData*,
+    const SmbNtHdr*, const uint8_t*, uint32_t);
+static DCE2_Ret DCE2_SmbUpdateTransRequest(DCE2_SmbSsnData*, const SmbNtHdr*,
+    const DCE2_SmbComInfo*, const uint8_t*, uint32_t);
+static DCE2_Ret DCE2_SmbUpdateTransResponse(DCE2_SmbSsnData*, const SmbNtHdr*,
+    const DCE2_SmbComInfo*, const uint8_t*, uint32_t);
+static DCE2_Ret DCE2_SmbValidateTransactionFields(const uint8_t*,
+    const uint8_t*, const uint32_t, const uint16_t, const uint32_t,
+    const uint32_t, const uint32_t, const uint32_t, const uint32_t,
+    const uint32_t, const uint32_t, const uint32_t);
+static DCE2_Ret DCE2_SmbCheckTransDataParams(
+    const uint8_t*, const uint8_t*, const uint32_t, const uint16_t,
+    const uint32_t, const uint32_t, const uint32_t, const uint32_t);
+static DCE2_Ret DCE2_SmbCheckTotalCount(
+    const uint32_t, const uint32_t, const uint32_t);
+static DCE2_Ret DCE2_SmbValidateTransactionSent(
+    uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
+static DCE2_Ret DCE2_SmbOpen(DCE2_SmbSsnData*, const SmbNtHdr*,
+    const DCE2_SmbComInfo*, const uint8_t*, uint32_t);
+static DCE2_Ret DCE2_SmbCreate(DCE2_SmbSsnData*, const SmbNtHdr*,
+    const DCE2_SmbComInfo*, const uint8_t*, uint32_t);
+static DCE2_Ret DCE2_SmbClose(DCE2_SmbSsnData*, const SmbNtHdr*,
+    const DCE2_SmbComInfo*, const uint8_t*, uint32_t);
+static DCE2_Ret DCE2_SmbRename(DCE2_SmbSsnData*, const SmbNtHdr*,
+    const DCE2_SmbComInfo*, const uint8_t*, uint32_t);
+static DCE2_Ret DCE2_SmbRead(DCE2_SmbSsnData*, const SmbNtHdr*,
+    const DCE2_SmbComInfo*, const uint8_t*, uint32_t);
+static DCE2_Ret DCE2_SmbWrite(DCE2_SmbSsnData*, const SmbNtHdr*,
+    const DCE2_SmbComInfo*, const uint8_t*, uint32_t);
+static DCE2_Ret DCE2_SmbCreateNew(DCE2_SmbSsnData*, const SmbNtHdr*,
+    const DCE2_SmbComInfo*, const uint8_t*, uint32_t);
+static DCE2_Ret DCE2_SmbLockAndRead(DCE2_SmbSsnData*, const SmbNtHdr*,
+    const DCE2_SmbComInfo*, const uint8_t*, uint32_t);
+static DCE2_Ret DCE2_SmbWriteAndUnlock(DCE2_SmbSsnData*, const SmbNtHdr*,
+    const DCE2_SmbComInfo*, const uint8_t*, uint32_t);
+static DCE2_Ret DCE2_SmbOpenAndX(DCE2_SmbSsnData*, const SmbNtHdr*,
+    const DCE2_SmbComInfo*, const uint8_t*, uint32_t);
+static DCE2_Ret DCE2_SmbReadAndX(DCE2_SmbSsnData*, const SmbNtHdr*,
+    const DCE2_SmbComInfo*, const uint8_t*, uint32_t);
+static DCE2_Ret DCE2_SmbWriteAndX(DCE2_SmbSsnData*, const SmbNtHdr*,
+    const DCE2_SmbComInfo*, const uint8_t*, uint32_t);
+static DCE2_Ret DCE2_SmbWriteAndXRawRequest(DCE2_SmbSsnData*, const SmbNtHdr*,
+    const DCE2_SmbComInfo*, const uint8_t*, uint32_t);
+static DCE2_Ret DCE2_SmbSessionSetupAndX(DCE2_SmbSsnData*, const SmbNtHdr*,
+    const DCE2_SmbComInfo*, const uint8_t*, uint32_t);
+static DCE2_Ret DCE2_SmbNegotiate(DCE2_SmbSsnData*, const SmbNtHdr*,
+    const DCE2_SmbComInfo*, const uint8_t*, uint32_t);
+static DCE2_Ret DCE2_SmbTreeConnectAndX(DCE2_SmbSsnData*, const SmbNtHdr*,
+    const DCE2_SmbComInfo*, const uint8_t*, uint32_t);
+static DCE2_Ret DCE2_SmbTreeConnect(DCE2_SmbSsnData*, const SmbNtHdr*,
+    const DCE2_SmbComInfo*, const uint8_t*, uint32_t);
+static DCE2_Ret DCE2_SmbNtCreateAndX(DCE2_SmbSsnData*, const SmbNtHdr*,
+    const DCE2_SmbComInfo*, const uint8_t*, uint32_t);
+static DCE2_Ret DCE2_SmbTreeDisconnect(DCE2_SmbSsnData*, const SmbNtHdr*,
+    const DCE2_SmbComInfo*, const uint8_t*, uint32_t);
+static DCE2_Ret DCE2_SmbLogoffAndX(DCE2_SmbSsnData*, const SmbNtHdr*,
+    const DCE2_SmbComInfo*, const uint8_t*, uint32_t);
+static DCE2_Ret DCE2_SmbTransactionReq(DCE2_SmbSsnData*,
+    DCE2_SmbTransactionTracker*, const uint8_t*, uint32_t,
+    const uint8_t*, uint32_t);
+static DCE2_Ret DCE2_SmbTransaction(DCE2_SmbSsnData*, const SmbNtHdr*,
+    const DCE2_SmbComInfo*, const uint8_t*, uint32_t);
 
 /********************************************************************
  * Function: DCE2_SmbType()
@@ -577,14 +830,14 @@ static inline uint8_t SmbCom(const SmbNtHdr* hdr)
 
 static bool SmbStatusNtCodes(const SmbNtHdr* hdr)
 {
-    if (ntohs(hdr->smb_flg2) & SMB_FLG2__NT_CODES)
+    if (alignedNtohs(&hdr->smb_flg2) & SMB_FLG2__NT_CODES)
         return true;
     return false;
 }
 
 static inline uint32_t SmbNtStatus(const SmbNtHdr* hdr)
 {
-    return ntohl(hdr->smb_status.nt_status);
+    return alignedNtohl(&hdr->smb_status.nt_status);
 }
 
 static inline uint8_t SmbStatusClass(const SmbNtHdr* hdr)
@@ -594,7 +847,7 @@ static inline uint8_t SmbStatusClass(const SmbNtHdr* hdr)
 
 static inline uint16_t SmbStatusCode(const SmbNtHdr* hdr)
 {
-    return ntohs(hdr->smb_status.smb_status.smb_code);
+    return alignedNtohs(&hdr->smb_status.smb_status.smb_code);
 }
 
 static inline uint8_t SmbNtStatusSeverity(const SmbNtHdr* hdr)
@@ -604,12 +857,12 @@ static inline uint8_t SmbNtStatusSeverity(const SmbNtHdr* hdr)
 
 static inline uint16_t SmbPid(const SmbNtHdr* hdr)
 {
-    return ntohs(hdr->smb_pid);
+    return alignedNtohs(&hdr->smb_pid);
 }
 
 static inline uint16_t SmbMid(const SmbNtHdr* hdr)
 {
-    return ntohs(hdr->smb_mid);
+    return alignedNtohs(&hdr->smb_mid);
 }
 
 // This function is obviously deficient.  Need to do a lot more
@@ -677,12 +930,111 @@ static bool SmbBrokenPipe(const SmbNtHdr* hdr)
 
 static inline uint16_t SmbUid(const SmbNtHdr* hdr)
 {
-    return ntohs(hdr->smb_uid);
+    return alignedNtohs(&hdr->smb_uid);
 }
 
 static inline uint16_t SmbTid(const SmbNtHdr* hdr)
 {
-    return ntohs(hdr->smb_tid);
+    return alignedNtohs(&hdr->smb_tid);
+}
+
+static inline bool SmbUnicode(const SmbNtHdr* hdr)
+{
+    return (alignedNtohs(&hdr->smb_flg2) & SMB_FLG2__UNICODE) ? true : false;
+}
+
+static inline bool SmbExtAttrReadOnly(const uint32_t ext_file_attrs)
+{
+    if (ext_file_attrs & SMB_EXT_FILE_ATTR_READONLY)
+        return true;
+    return false;
+}
+
+static inline bool SmbExtAttrHidden(const uint32_t ext_file_attrs)
+{
+    if (ext_file_attrs & SMB_EXT_FILE_ATTR_HIDDEN)
+        return true;
+    return false;
+}
+
+static inline bool SmbExtAttrSystem(const uint32_t ext_file_attrs)
+{
+    if (ext_file_attrs & SMB_EXT_FILE_ATTR_SYSTEM)
+        return true;
+    return false;
+}
+
+static inline bool SmbEvasiveFileAttrs(const uint32_t ext_file_attrs)
+{
+    return (SmbExtAttrReadOnly(ext_file_attrs)
+           && SmbExtAttrHidden(ext_file_attrs)
+           && SmbExtAttrSystem(ext_file_attrs));
+}
+
+static inline bool SmbErrorInvalidDeviceRequest(const SmbNtHdr* hdr)
+{
+    if (SmbStatusNtCodes(hdr))
+    {
+        if (SmbNtStatus(hdr) == SMB_NT_STATUS__INVALID_DEVICE_REQUEST)
+            return true;
+    }
+    else
+    {
+        if ((SmbStatusClass(hdr) == SMB_ERROR_CLASS__ERRSRV)
+            && (SmbStatusCode(hdr) == SMB_ERRSRV__INVALID_DEVICE))
+            return true;
+    }
+
+    return false;
+}
+
+static inline bool SmbErrorRangeNotLocked(const SmbNtHdr* hdr)
+{
+    if (SmbStatusNtCodes(hdr))
+    {
+        if (SmbNtStatus(hdr) == SMB_NT_STATUS__RANGE_NOT_LOCKED)
+            return true;
+    }
+    else
+    {
+        if ((SmbStatusClass(hdr) == SMB_ERROR_CLASS__ERRDOS)
+            && (SmbStatusCode(hdr) == SMB_ERRDOS__NOT_LOCKED))
+            return true;
+    }
+
+    return false;
+}
+
+/********************************************************************
+ * Function: DCE2_SmbCheckFmtData()
+ *
+ * Purpose:
+ *  Checks the data count in commands with formats, e.g.
+ *  SMB_COM_WRITE, SMB_COM_WRITE_AND_CLOSE, SMB_COM_WRITE_AND_UNLOCK.
+ *
+ * Arguments:
+ *  DCE2_SmbSsnData * - SMB session data structure
+ *  const uint32_t    - remaining NetBIOS PDU length
+ *  const uint16_t    - advertised byte count
+ *  const uint8_t     - data format specifier
+ *  const uint16_t    - data count reported in command
+ *  const uint16_t    - data count reported in format field
+ *
+ * Returns: None
+ *
+ ********************************************************************/
+static inline void DCE2_SmbCheckFmtData(DCE2_SmbSsnData*,
+    const uint32_t nb_len, const uint16_t bcc, const uint8_t fmt,
+    const uint16_t com_dcnt, const uint16_t fmt_dcnt)
+{
+    if (fmt != SMB_FMT__DATA_BLOCK)
+        dce_alert(GID_DCE2, DCE2_SMB_BAD_FORM, (dce2CommonStats*)&dce2_smb_stats);
+    if (com_dcnt != fmt_dcnt)
+        dce_alert(GID_DCE2, DCE2_SMB_DCNT_MISMATCH, (dce2CommonStats*)&dce2_smb_stats);
+    if (com_dcnt != (bcc - 3))
+        dce_alert(GID_DCE2, DCE2_SMB_INVALID_DSIZE, (dce2CommonStats*)&dce2_smb_stats);
+    if (nb_len < com_dcnt)
+        dce_alert(GID_DCE2, DCE2_SMB_NB_LT_DSIZE, (dce2CommonStats*)&dce2_smb_stats);
 }
 
 /********************************************************************
@@ -776,2098 +1128,5496 @@ static bool DCE2_SmbIsTidIPC(DCE2_SmbSsnData* ssd, const uint16_t tid)
     return false;
 }
 
-static void DCE2_SmbCleanTransactionTracker(DCE2_SmbTransactionTracker* ttracker)
+static DCE2_Ret DCE2_SmbInitFileTracker(DCE2_SmbSsnData* ssd,
+    DCE2_SmbFileTracker* ftracker, const bool is_ipc, const uint16_t uid,
+    const uint16_t tid, const int fid)
 {
-    Profile profile(dce2_smb_pstat_smb_req);
+    if (ftracker == nullptr)
+        return DCE2_RET__ERROR;
 
-    if (ttracker == nullptr)
+    ftracker->uid = uid;
+    ftracker->tid = tid;
+    ftracker->fid = fid;
+    ftracker->is_ipc = is_ipc;
+    ftracker->file_name = nullptr;
+    if (is_ipc)
     {
-        return;
+        DCE2_CoTracker* co_tracker = (DCE2_CoTracker*)SnortAlloc(sizeof(DCE2_CoTracker));
+        if (co_tracker == nullptr)
+            return DCE2_RET__ERROR;
+        DCE2_CoInitTracker(co_tracker);
+        ftracker->fp_co_tracker = co_tracker;
+        ftracker->fp_byte_mode = false;
+        ftracker->fp_used = false;
+        ftracker->fp_writex_raw = nullptr;
+    }
+    else
+    {
+        ftracker->ff_file_size = 0;
+        ftracker->ff_file_offset = 0;
+        ftracker->ff_bytes_processed = 0;
+        ftracker->ff_file_direction = DCE2_SMB_FILE_DIRECTION__UNKNOWN;
+        ftracker->ff_file_chunks = nullptr;
+        ftracker->ff_bytes_queued = 0;
+        if ((ssd->fapi_ftracker == nullptr) && (ssd->max_file_depth != -1))
+        {
+            DebugFormat(DEBUG_DCE_SMB, "Designating file tracker "
+                "for file API processing: 0x%04X\n", (uint16_t)fid);
+            ssd->fapi_ftracker = ftracker;
+        }
     }
 
-    if (ttracker->dbuf != nullptr)
-        DCE2_BufferDestroy(ttracker->dbuf);
+    return DCE2_RET__SUCCESS;
+}
 
-    if (ttracker->pbuf != nullptr)
-        DCE2_BufferDestroy(ttracker->pbuf);
+static DCE2_SmbFileTracker* DCE2_SmbNewFileTracker(DCE2_SmbSsnData* ssd,
+    const uint16_t uid, const uint16_t tid, const uint16_t fid)
+{
+    Profile profile(dce2_smb_pstat_smb_fid);
 
-    memset(ttracker, 0, sizeof(*ttracker));
+    // Already have tracker for file API and not setting file data pointer
+    // so don't create new file tracker.
+    bool is_ipc = DCE2_SmbIsTidIPC(ssd, tid);
+    if (!is_ipc && (ssd->fapi_ftracker != nullptr)
+        && (DCE2_ScSmbFileDepth((dce2SmbProtoConf*)ssd->sd.config) == -1))
+        return nullptr;
+
+    DebugFormat(DEBUG_DCE_SMB, "Creating new file tracker "
+        "with Uid: %u, Tid: %u, Fid: 0x%04X\n", uid, tid, fid);
+
+    DCE2_SmbFileTracker* ftracker = nullptr;
+    if (ssd->ftracker.fid == DCE2_SENTINEL)
+    {
+        ftracker = &ssd->ftracker;
+        if (DCE2_SmbInitFileTracker(ssd, ftracker, is_ipc, uid, tid, (int)fid) !=
+            DCE2_RET__SUCCESS)
+        {
+            DCE2_SmbCleanFileTracker(ftracker);
+            return nullptr;
+        }
+    }
+    else
+    {
+        ftracker = (DCE2_SmbFileTracker*)SnortAlloc(sizeof(DCE2_SmbFileTracker));
+
+        if (ftracker == nullptr)
+        {
+            return nullptr;
+        }
+
+        if (DCE2_SmbInitFileTracker(ssd, ftracker, is_ipc, uid, tid, (int)fid) !=
+            DCE2_RET__SUCCESS)
+        {
+            DCE2_SmbCleanFileTracker(ftracker);
+            free((void*)ftracker);
+            return nullptr;
+        }
+
+        if (ssd->ftrackers == nullptr)
+        {
+            ssd->ftrackers = DCE2_ListNew(DCE2_LIST_TYPE__SPLAYED,
+                DCE2_SmbUidTidFidCompare, DCE2_SmbFileTrackerDataFree, nullptr,
+                DCE2_LIST_FLAG__NO_DUPS);
+
+            if (ssd->ftrackers == nullptr)
+            {
+                DCE2_SmbCleanSessionFileTracker(ssd, ftracker);
+                return nullptr;
+            }
+        }
+
+        if (DCE2_ListInsert(ssd->ftrackers, (void*)(uintptr_t)fid,
+            (void*)ftracker) != DCE2_RET__SUCCESS)
+        {
+            DCE2_SmbCleanSessionFileTracker(ssd, ftracker);
+            return nullptr;
+        }
+    }
+
+    return ftracker;
 }
 
-static void DCE2_SmbCleanRequestTracker(DCE2_SmbRequestTracker* rtracker)
+static DCE2_SmbFileTracker* DCE2_SmbFindFileTracker(DCE2_SmbSsnData* ssd,
+    const uint16_t uid, const uint16_t tid, const uint16_t fid)
 {
-    Profile profile(dce2_smb_pstat_smb_req);
+    Profile profile(dce2_smb_pstat_smb_fid);
 
-    if (rtracker == nullptr)
+    DebugFormat(DEBUG_DCE_SMB, "Finding file tracker with "
+        "Uid: %u, Tid: %u, Fid: 0x%04X ... ", uid, tid, fid);
+
+    DCE2_SmbFileTracker* ftracker;
+    if ((ssd->ftracker.fid != DCE2_SENTINEL) && (ssd->ftracker.fid == (int)fid))
     {
-        return;
+        ftracker = &ssd->ftracker;
+    }
+    else
+    {
+        ftracker = (DCE2_SmbFileTracker*)
+            DCE2_ListFind(ssd->ftrackers, (void*)(uintptr_t)fid);
     }
 
-    if (rtracker->mid == DCE2_SENTINEL)
+    if (ftracker == nullptr)
     {
-        return;
+        DebugMessage(DEBUG_DCE_SMB, "Not found.\n");
+        return nullptr;
     }
 
-    rtracker->mid = DCE2_SENTINEL;
-    rtracker->ftracker = nullptr;
-    rtracker->sequential_only = false;
+    // Note IPC Tid has already been validated in initial processing
+    const DCE2_Policy policy = DCE2_SsnGetServerPolicy(&ssd->sd);
+    switch (policy)
+    {
+    case DCE2_POLICY__SAMBA:
+    case DCE2_POLICY__SAMBA_3_0_37:
+        // Only Uid used to open file can be used to make a request
+        if (ftracker->uid != uid)
+        {
+            DebugMessage(DEBUG_DCE_SMB, "Not found.\n");
+            return nullptr;
+        }
 
-    DCE2_SmbCleanTransactionTracker(&rtracker->ttracker);
+        break;
 
-    DCE2_QueueDestroy(rtracker->ft_queue);
-    rtracker->ft_queue = nullptr;
+    case DCE2_POLICY__WIN2000:
+    case DCE2_POLICY__SAMBA_3_0_20:
+    case DCE2_POLICY__SAMBA_3_0_22:
+        // Any valid Uid can be used to make a request to a file ...
+        // except for Windows 2000 on the first use.
+        if ((policy != DCE2_POLICY__WIN2000) || (ftracker->is_ipc && ftracker->fp_used))
+        {
+            // Check that the Uid exists
+            if (DCE2_SmbFindUid(ssd, uid) != DCE2_RET__SUCCESS)
+            {
+                DebugMessage(DEBUG_DCE_SMB, "Not found.\n");
+                return nullptr;
+            }
 
-    if (rtracker->file_name != nullptr)
-    {
-        free((void*)rtracker->file_name);
-        rtracker->file_name = nullptr;
+            break;
+        }
+
+    // Fall through for Windows 2000 for first request to file
+
+    case DCE2_POLICY__WIN2003:
+    case DCE2_POLICY__WINXP:
+    case DCE2_POLICY__WINVISTA:
+    case DCE2_POLICY__WIN2008:
+    case DCE2_POLICY__WIN7:
+        // Both Uid and Tid used to create file must be used to make a request
+        if ((ftracker->uid != uid) || (ftracker->tid != tid))
+        {
+            DebugMessage(DEBUG_DCE_SMB, "Not found.\n");
+            return nullptr;
+        }
+
+        break;
+
+    default:
+        DebugFormat(DEBUG_DCE_SMB, "%s(%d) Invalid policy: %d",
+            __FILE__, __LINE__, policy);
+        break;
     }
+
+    DebugFormat(DEBUG_DCE_SMB, "Found with "
+        "Uid: %u, Tid: %u, Fid: 0x%04X\n",
+        ftracker->uid, ftracker->tid, ftracker->fid);
+    return ftracker;
 }
 
-static void DCE2_SmbRequestTrackerDataFree(void* data)
+static DCE2_SmbFileTracker* DCE2_SmbGetFileTracker(DCE2_SmbSsnData* ssd,
+    const uint16_t fid)
 {
-    DCE2_SmbRequestTracker* rtracker = (DCE2_SmbRequestTracker*)data;
+    DCE2_SmbFileTracker* ftracker = ssd->cur_rtracker->ftracker;
 
-    if (rtracker == nullptr)
-        return;
+    if (ftracker == nullptr)
+    {
+        // Write could've been chained to an OpenAndX or NtCreateAndX so a
+        // temporary file tracker would've been created until we get the
+        // response with the Fid returned from the OpenAndX / NtCreateAndX
+        ftracker = DCE2_SmbGetTmpFileTracker(ssd->cur_rtracker);
+        if (ftracker == nullptr)
+        {
+            // Otherwise find it with the passed in Fid
+            ftracker = DCE2_SmbFindFileTracker(ssd, ssd->cur_rtracker->uid,
+                ssd->cur_rtracker->tid, fid);
+        }
+    }
 
-    DebugFormat(DEBUG_DCE_SMB, "Freeing request tracker: "
-        "Uid: %u, Tid: %u, Pid: %u, Mid: %u\n",
-        rtracker->uid, rtracker->tid, rtracker->pid, rtracker->mid);
+    return ftracker;
+}
 
-    DCE2_SmbCleanRequestTracker(rtracker);
-    free((void*)rtracker);
+static DCE2_SmbFileTracker* DCE2_SmbGetTmpFileTracker(DCE2_SmbRequestTracker* rtracker)
+{
+    if (!DCE2_QueueIsEmpty(rtracker->ft_queue))
+        return (DCE2_SmbFileTracker*)DCE2_QueueLast(rtracker->ft_queue);
+    return nullptr;
 }
 
-static DCE2_SmbRequestTracker* DCE2_SmbFindRequestTracker(DCE2_SmbSsnData* ssd,
-    const SmbNtHdr* smb_hdr)
+static void DCE2_SmbRemoveFileTracker(DCE2_SmbSsnData* ssd, DCE2_SmbFileTracker* ftracker)
 {
-    uint16_t uid = SmbUid(smb_hdr);
-    uint16_t tid = SmbTid(smb_hdr);
-    uint16_t pid = SmbPid(smb_hdr);
-    uint16_t mid = SmbMid(smb_hdr);
+    if (ftracker == nullptr)
+        return;
 
-    Profile profile(dce2_smb_pstat_smb_req);
+    Profile profile(dce2_smb_pstat_smb_fid);
 
-    DebugFormat(DEBUG_DCE_SMB, "Find request tracker => "
-        "Uid: %u, Tid: %u, Pid: %u, Mid: %u ... ", uid, tid, pid, mid);
+    DebugFormat(DEBUG_DCE_SMB,
+        "Removing file tracker with Fid: 0x%04X\n", ftracker->fid);
 
-    DCE2_SmbRequestTracker* tmp_rtracker = &ssd->rtracker;
-    int smb_com = SmbCom(smb_hdr);
-    switch (smb_com)
+    // FIXIT-M uncomment when file api related code is ported
+    /*
+    if (ssd->fapi_ftracker == ftracker)
+        DCE2_SmbFinishFileAPI(ssd);
+    */
+
+    //FIXIT-M port active response related code
+/*
+#ifdef ACTIVE_RESPONSE
+    if (ssd->fb_ftracker == ftracker)
+        DCE2_SmbFinishFileBlockVerdict(ssd);
+#endif
+*/
+    if (ftracker == &ssd->ftracker)
+        DCE2_SmbCleanFileTracker(&ssd->ftracker);
+    else if (ssd->ftrackers != nullptr)
+        DCE2_ListRemove(ssd->ftrackers, (void*)(uintptr_t)ftracker->fid);
+
+    DCE2_SmbRemoveFileTrackerFromRequestTrackers(ssd, ftracker);
+}
+
+static void DCE2_SmbCleanFileTracker(DCE2_SmbFileTracker* ftracker)
+{
+    if (ftracker == nullptr)
+        return;
+
+    Profile profile(dce2_smb_pstat_smb_fid);
+
+    ftracker->fid = DCE2_SENTINEL;
+    if (ftracker->file_name != nullptr)
     {
-    case SMB_COM_TRANSACTION_SECONDARY:
-        smb_com = SMB_COM_TRANSACTION;
-        break;
-    case SMB_COM_TRANSACTION2_SECONDARY:
-        smb_com = SMB_COM_TRANSACTION2;
-        break;
-    case SMB_COM_NT_TRANSACT_SECONDARY:
-        smb_com = SMB_COM_NT_TRANSACT;
-        break;
-    case SMB_COM_WRITE_COMPLETE:
-        smb_com = SMB_COM_WRITE_RAW;
-        break;
-    default:
-        break;
+        free((void*)ftracker->file_name);
+        ftracker->file_name = nullptr;
     }
 
-    DCE2_SmbRequestTracker* first_rtracker = nullptr;
-    DCE2_SmbRequestTracker* win_rtracker = nullptr;
-    DCE2_SmbRequestTracker* first_mid_rtracker = nullptr;
-    DCE2_SmbRequestTracker* ret_rtracker = nullptr;
-    while (tmp_rtracker != nullptr)
+    if (ftracker->is_ipc)
     {
-        if ((tmp_rtracker->mid == (int)mid) && (tmp_rtracker->smb_com == smb_com))
+        ftracker->fp_used = 0;
+        ftracker->fp_byte_mode = 0;
+
+        if (ftracker->fp_writex_raw != nullptr)
         {
-            // This is the normal case except for SessionSetupAndX and
-            // TreeConnect/TreeConnectAndX which will fall into the
-            // default case below.
-            if ((tmp_rtracker->pid == pid) && (tmp_rtracker->uid == uid)
-                && (tmp_rtracker->tid == tid))
-            {
-                ret_rtracker = tmp_rtracker;
-            }
-            else
-            {
-                switch (smb_com)
-                {
-                case SMB_COM_TRANSACTION:
-                case SMB_COM_TRANSACTION2:
-                case SMB_COM_NT_TRANSACT:
-                case SMB_COM_TRANSACTION_SECONDARY:
-                case SMB_COM_TRANSACTION2_SECONDARY:
-                case SMB_COM_NT_TRANSACT_SECONDARY:
-                    // These should conform to above
-                    break;
-                default:
-                    if (tmp_rtracker->pid == pid)
-                        ret_rtracker = tmp_rtracker;
-                    break;
-                }
-            }
+            DCE2_BufferDestroy(ftracker->fp_writex_raw->buf);
+            free((void*)ftracker->fp_writex_raw);
+            ftracker->fp_writex_raw = nullptr;
+        }
 
-            if (ret_rtracker != nullptr)
-            {
-                DebugMessage(DEBUG_DCE_SMB, "Found.\n");
-                return ret_rtracker;
-            }
+        if (ftracker->fp_co_tracker != nullptr)
+        {
+            DCE2_CoCleanTracker(ftracker->fp_co_tracker);
+            free((void*)ftracker->fp_co_tracker);
+            ftracker->fp_co_tracker = nullptr;
+        }
+    }
+    else
+    {
+        ftracker->ff_file_size = 0;
+        ftracker->ff_file_offset = 0;
+        ftracker->ff_bytes_processed = 0;
+        ftracker->ff_file_direction = DCE2_SMB_FILE_DIRECTION__UNKNOWN;
+        ftracker->ff_bytes_queued = 0;
+        ftracker->ff_sequential_only = false;
+        if (ftracker->ff_file_chunks != nullptr)
+        {
+            DCE2_ListDestroy(ftracker->ff_file_chunks);
+            ftracker->ff_file_chunks = nullptr;
+        }
+    }
+}
 
-            // Take the first one where the PIDs also match
-            // in the case of the Transacts above
-            if ((tmp_rtracker->pid == pid) && (win_rtracker == nullptr))
-                win_rtracker = tmp_rtracker;
+static int DCE2_SmbUidTidFidCompare(const void* a, const void* b)
+{
+    int x = (int)(uintptr_t)a;
+    int y = (int)(uintptr_t)b;
 
-            // Set this to the first matching request in the queue
-            // where the Mid matches.  Don't set for Windows if from
-            // client since PID/MID are necessary
-            if (((DCE2_SmbType(ssd) == SMB_TYPE__RESPONSE)
-                || !DCE2_SsnIsWindowsPolicy(&ssd->sd))
-                && first_mid_rtracker == nullptr)
+    if (x == y)
+        return 0;
+
+    /* Only care about equality for finding */
+    return -1;
+}
+
+static DCE2_Ret DCE2_SmbFindUid(DCE2_SmbSsnData* ssd, const uint16_t uid)
+{
+    DCE2_Ret status;
+
+    Profile profile(dce2_smb_pstat_smb_uid);
+
+    if ((ssd->uid != DCE2_SENTINEL) && (ssd->uid == (int)uid))
+        status = DCE2_RET__SUCCESS;
+    else
+        status = DCE2_ListFindKey(ssd->uids, (void*)(uintptr_t)uid);
+
+    return status;
+}
+
+static void DCE2_SmbInsertUid(DCE2_SmbSsnData* ssd, const uint16_t uid)
+{
+    Profile profile(dce2_smb_pstat_smb_uid);
+
+    DebugFormat(DEBUG_DCE_SMB, "Inserting Uid: %u\n", uid);
+
+    if (ssd->uid == DCE2_SENTINEL)
+    {
+        ssd->uid = (int)uid;
+    }
+    else
+    {
+        if (ssd->uids == nullptr)
+        {
+            ssd->uids = DCE2_ListNew(DCE2_LIST_TYPE__SPLAYED, DCE2_SmbUidTidFidCompare,
+                nullptr, nullptr, DCE2_LIST_FLAG__NO_DUPS);
+
+            if (ssd->uids == nullptr)
             {
-                first_mid_rtracker = tmp_rtracker;
+                return;
             }
         }
 
-        // Set the first one we see for early Samba versions
-        if ((first_rtracker == nullptr) && (tmp_rtracker->mid != DCE2_SENTINEL)
-            && (tmp_rtracker->smb_com == smb_com))
-            first_rtracker = tmp_rtracker;
-
-        // Look at the next request in the queue
-        if (tmp_rtracker == &ssd->rtracker)
-            tmp_rtracker = (DCE2_SmbRequestTracker*)DCE2_QueueFirst(ssd->rtrackers);
-        else
-            tmp_rtracker = (DCE2_SmbRequestTracker*)DCE2_QueueNext(ssd->rtrackers);
+        DCE2_ListInsert(ssd->uids, (void*)(uintptr_t)uid, (void*)(uintptr_t)uid);
     }
+}
+
+static void DCE2_SmbRemoveUid(DCE2_SmbSsnData* ssd, const uint16_t uid)
+{
+    const DCE2_Policy policy = DCE2_SsnGetServerPolicy(&ssd->sd);
+
+    Profile profile(dce2_smb_pstat_smb_uid);
+
+    DebugFormat(DEBUG_DCE_SMB,"Removing Uid: %u\n", uid);
+
+    if ((ssd->uid != DCE2_SENTINEL) && (ssd->uid == (int)uid))
+        ssd->uid = DCE2_SENTINEL;
+    else
+        DCE2_ListRemove(ssd->uids, (void*)(uintptr_t)uid);
 
-    DCE2_Policy policy = DCE2_SsnGetPolicy(&ssd->sd);
     switch (policy)
     {
-    case DCE2_POLICY__SAMBA_3_0_20:
-    case DCE2_POLICY__SAMBA_3_0_22:
-        ret_rtracker = first_rtracker;
-        break;
-    case DCE2_POLICY__SAMBA:
-    case DCE2_POLICY__SAMBA_3_0_37:
-        ret_rtracker = first_mid_rtracker;
-        break;
     case DCE2_POLICY__WIN2000:
+    case DCE2_POLICY__WIN2003:
     case DCE2_POLICY__WINXP:
     case DCE2_POLICY__WINVISTA:
-    case DCE2_POLICY__WIN2003:
     case DCE2_POLICY__WIN2008:
     case DCE2_POLICY__WIN7:
-        if (win_rtracker != nullptr)
-            ret_rtracker = win_rtracker;
-        else
-            ret_rtracker = first_mid_rtracker;
+    case DCE2_POLICY__SAMBA:
+    case DCE2_POLICY__SAMBA_3_0_37:
+        // Removing uid invalidates any fid that was created with it */
+        if ((ssd->ftracker.fid != DCE2_SENTINEL) &&
+            (ssd->ftracker.uid == uid))
+        {
+            DCE2_SmbRemoveFileTracker(ssd, &ssd->ftracker);
+        }
+
+        if (ssd->ftrackers != nullptr)
+        {
+            DCE2_SmbFileTracker* ftracker;
+
+            for (ftracker = (DCE2_SmbFileTracker*)DCE2_ListFirst(ssd->ftrackers);
+                ftracker != nullptr;
+                ftracker = (DCE2_SmbFileTracker*)DCE2_ListNext(ssd->ftrackers))
+            {
+                if (ftracker->uid == uid)
+                {
+// FIXIT-M uncomment after file api is ported
+/*
+                        if (ssd->fapi_ftracker == ftracker)
+                            DCE2_SmbFinishFileAPI(ssd);
+
+#ifdef ACTIVE_RESPONSE
+                        if (ssd->fb_ftracker == ftracker)
+                            DCE2_SmbFinishFileBlockVerdict(ssd);
+#endif
+*/
+                    DCE2_ListRemoveCurrent(ssd->ftrackers);
+                    DCE2_SmbRemoveFileTrackerFromRequestTrackers(ssd, ftracker);
+                }
+            }
+        }
+
+        break;
+
+    case DCE2_POLICY__SAMBA_3_0_20:
+    case DCE2_POLICY__SAMBA_3_0_22:
+        // Removing Uid used to create file doesn't invalidate it.
         break;
+
     default:
         DebugFormat(DEBUG_DCE_SMB, "%s(%d) Invalid policy: %d",
             __FILE__, __LINE__, policy);
         break;
     }
+}
 
-    return ret_rtracker;
+static void DCE2_SmbFileTrackerDataFree(void* data)
+{
+    DCE2_SmbFileTracker* ftracker = (DCE2_SmbFileTracker*)data;
+
+    if (ftracker == nullptr)
+        return;
+
+    DebugFormat(DEBUG_DCE_SMB, "Freeing file tracker: "
+        "Uid: %u, Tid: %u, Fid: 0x%04X\n",
+        ftracker->uid, ftracker->tid, ftracker->fid);
+
+    DCE2_SmbCleanFileTracker(ftracker);
+    free((void*)ftracker);
 }
 
-static DCE2_SmbRequestTracker* DCE2_SmbNewRequestTracker(DCE2_SmbSsnData* ssd,
-    const SmbNtHdr* smb_hdr)
+/********************************************************************
+ *
+ * Remove file tracker and associated pointers in session
+ *
+ ********************************************************************/
+static void DCE2_SmbCleanSessionFileTracker(DCE2_SmbSsnData* ssd, DCE2_SmbFileTracker* ftracker)
 {
-    uint16_t pid = SmbPid(smb_hdr);
-    uint16_t mid = SmbMid(smb_hdr);
-    uint16_t uid = SmbUid(smb_hdr);
-    uint16_t tid = SmbTid(smb_hdr);
+    DCE2_SmbCleanFileTracker(ftracker);
+    free((void*)ftracker);
+    if (ssd->fapi_ftracker == ftracker)
+        ssd->fapi_ftracker = nullptr;
+}
 
+static void DCE2_SmbCleanTransactionTracker(DCE2_SmbTransactionTracker* ttracker)
+{
     Profile profile(dce2_smb_pstat_smb_req);
 
-    if (ssd == nullptr)
+    if (ttracker == nullptr)
     {
-        return nullptr;
+        return;
     }
 
-    if (ssd->outstanding_requests >= ssd->max_outstanding_requests)
+    if (ttracker->dbuf != nullptr)
+        DCE2_BufferDestroy(ttracker->dbuf);
+
+    if (ttracker->pbuf != nullptr)
+        DCE2_BufferDestroy(ttracker->pbuf);
+
+    memset(ttracker, 0, sizeof(*ttracker));
+}
+
+static void DCE2_SmbCleanRequestTracker(DCE2_SmbRequestTracker* rtracker)
+{
+    Profile profile(dce2_smb_pstat_smb_req);
+
+    if (rtracker == nullptr)
     {
-        dce_alert(GID_DCE2, DCE2_SMB_MAX_REQS_EXCEEDED, (dce2CommonStats*)&dce2_smb_stats);
+        return;
     }
 
-    // Check for outstanding requests with the same MID
-    DCE2_SmbRequestTracker* tmp_rtracker = &ssd->rtracker;
-    while ((tmp_rtracker != nullptr) && (tmp_rtracker->mid != DCE2_SENTINEL))
+    if (rtracker->mid == DCE2_SENTINEL)
     {
-        if (tmp_rtracker->mid == (int)mid)
-        {
-            // Have yet to see an MID repeatedly used so shouldn't
-            // be any outstanding requests with the same MID.
-            dce_alert(GID_DCE2, DCE2_SMB_REQS_SAME_MID, (dce2CommonStats*)&dce2_smb_stats);
-            break;
-        }
+        return;
+    }
 
-        // Look at the next request in the queue
-        if (tmp_rtracker == &ssd->rtracker)
-            tmp_rtracker = (DCE2_SmbRequestTracker*)DCE2_QueueFirst(ssd->rtrackers);
-        else
-            tmp_rtracker = (DCE2_SmbRequestTracker*)DCE2_QueueNext(ssd->rtrackers);
+    rtracker->mid = DCE2_SENTINEL;
+    rtracker->ftracker = nullptr;
+    rtracker->sequential_only = false;
+
+    DCE2_SmbCleanTransactionTracker(&rtracker->ttracker);
+
+    DCE2_QueueDestroy(rtracker->ft_queue);
+    rtracker->ft_queue = nullptr;
+
+    if (rtracker->file_name != nullptr)
+    {
+        free((void*)rtracker->file_name);
+        rtracker->file_name = nullptr;
     }
+}
 
-    DCE2_SmbRequestTracker* rtracker = nullptr;
-    if (ssd->rtracker.mid == DCE2_SENTINEL)
+static inline void DCE2_SmbRemoveRequestTracker(DCE2_SmbSsnData* ssd,
+    DCE2_SmbRequestTracker* rtracker)
+{
+    Profile profile(dce2_smb_pstat_smb_req);
+
+    if ((ssd == nullptr) || (rtracker == nullptr))
     {
-        rtracker = &ssd->rtracker;
+        return;
     }
-    else
+
+    DebugFormat(DEBUG_DCE_SMB, "Removing request tracker => "
+        "Uid: %u, Tid: %u, Pid: %u, Mid: %u ... ",
+        rtracker->uid, rtracker->tid, rtracker->pid, rtracker->mid);
+
+    if (rtracker == &ssd->rtracker)
     {
-        if (ssd->rtrackers == nullptr)
+        DebugMessage(DEBUG_DCE_SMB, "Removed\n");
+
+        DCE2_SmbCleanRequestTracker(&ssd->rtracker);
+        ssd->outstanding_requests--;
+        return;
+    }
+
+    DCE2_SmbRequestTracker* tmp_node;
+    for (tmp_node = (DCE2_SmbRequestTracker*)DCE2_QueueFirst(ssd->rtrackers);
+        tmp_node != nullptr;
+        tmp_node = (DCE2_SmbRequestTracker*)DCE2_QueueNext(ssd->rtrackers))
+    {
+        if (tmp_node == (void*)rtracker)
         {
-            ssd->rtrackers = DCE2_QueueNew(DCE2_SmbRequestTrackerDataFree);
-            if (ssd->rtrackers == nullptr)
-            {
-                return nullptr;
-            }
+            DebugMessage(DEBUG_DCE_SMB, "Removed\n");
+
+            DCE2_QueueRemoveCurrent(ssd->rtrackers);
+            ssd->outstanding_requests--;
+            return;
         }
+    }
 
-        rtracker = (DCE2_SmbRequestTracker*)SnortAlloc(sizeof(DCE2_SmbRequestTracker));
-        if (rtracker == nullptr)
+    DebugMessage(DEBUG_DCE_SMB, "Not removed.\n");
+}
+
+static void DCE2_SmbRemoveFileTrackerFromRequestTrackers(DCE2_SmbSsnData* ssd,
+    DCE2_SmbFileTracker* ftracker)
+{
+    if (ftracker == nullptr)
+        return;
+
+    // NULL out file trackers of any outstanding requests
+    // that reference this file tracker
+    if (ssd->rtracker.ftracker == ftracker)
+        ssd->rtracker.ftracker = nullptr;
+
+    if ((ssd->cur_rtracker != nullptr) && (ssd->cur_rtracker->ftracker == ftracker))
+        ssd->cur_rtracker->ftracker = nullptr;
+
+    DCE2_SmbRequestTracker* rtracker;
+    for (rtracker = (DCE2_SmbRequestTracker*)DCE2_QueueFirst(ssd->rtrackers);
+        rtracker != nullptr;
+        rtracker = (DCE2_SmbRequestTracker*)DCE2_QueueNext(ssd->rtrackers))
+    {
+        if (rtracker->ftracker == ftracker)
+            rtracker->ftracker = nullptr;
+    }
+}
+
+static DCE2_SmbFileTracker* DCE2_SmbDequeueTmpFileTracker(DCE2_SmbSsnData* ssd,
+    DCE2_SmbRequestTracker* rtracker, const uint16_t fid)
+{
+    Profile profile(dce2_smb_pstat_smb_fid);
+
+    DebugFormat(DEBUG_DCE_SMB, "Dequeueing file tracker "
+        "and binding to fid: 0x%04X\n", fid);
+
+    DCE2_SmbFileTracker* ftracker = (DCE2_SmbFileTracker*)DCE2_QueueDequeue(rtracker->ft_queue);
+    if (ftracker == nullptr)
+    {
+        return nullptr;
+    }
+
+    if (ssd->ftracker.fid == DCE2_SENTINEL)
+    {
+        memcpy(&ssd->ftracker, ftracker, sizeof(DCE2_SmbFileTracker));
+        free((void*)ftracker);
+        if (ssd->fapi_ftracker == ftracker)
+            ssd->fapi_ftracker = &ssd->ftracker;
+        ftracker = &ssd->ftracker;
+    }
+    else
+    {
+        if (ssd->ftrackers == nullptr)
         {
-            return nullptr;
+            ssd->ftrackers = DCE2_ListNew(DCE2_LIST_TYPE__SPLAYED,
+                DCE2_SmbUidTidFidCompare, DCE2_SmbFileTrackerDataFree, nullptr,
+                DCE2_LIST_FLAG__NO_DUPS);
+
+            if (ssd->ftrackers == nullptr)
+            {
+                DCE2_SmbCleanSessionFileTracker(ssd, ftracker);
+                return nullptr;
+            }
         }
 
-        if (DCE2_QueueEnqueue(ssd->rtrackers, (void*)rtracker) != DCE2_RET__SUCCESS)
+        if (DCE2_ListInsert(ssd->ftrackers, (void*)(uintptr_t)fid,
+            (void*)ftracker) != DCE2_RET__SUCCESS)
         {
-            free((void*)rtracker);
+            DCE2_SmbCleanSessionFileTracker(ssd, ftracker);
             return nullptr;
         }
     }
 
-    rtracker->smb_com = SmbCom(smb_hdr);
-    rtracker->uid = uid;
-    rtracker->tid = tid;
-    rtracker->pid = pid;
-    rtracker->mid = (int)mid;
-    memset(&rtracker->ttracker, 0, sizeof(rtracker->ttracker));
-    rtracker->ftracker = nullptr;
-    rtracker->sequential_only = false;
+    // Other values were intialized when queueing.
+    ftracker->fid = (int)fid;
 
-    ssd->outstanding_requests++;
-    if (ssd->outstanding_requests > dce2_smb_stats.smb_max_outstanding_requests)
-        dce2_smb_stats.smb_max_outstanding_requests = ssd->outstanding_requests;
+    return ftracker;
+}
 
-    DebugFormat(DEBUG_DCE_SMB, "Added new request tracker => "
+static void DCE2_SmbRequestTrackerDataFree(void* data)
+{
+    DCE2_SmbRequestTracker* rtracker = (DCE2_SmbRequestTracker*)data;
+
+    if (rtracker == nullptr)
+        return;
+
+    DebugFormat(DEBUG_DCE_SMB, "Freeing request tracker: "
         "Uid: %u, Tid: %u, Pid: %u, Mid: %u\n",
         rtracker->uid, rtracker->tid, rtracker->pid, rtracker->mid);
-    DebugFormat(DEBUG_DCE_SMB,
-        "Current outstanding requests: %u\n", ssd->outstanding_requests);
 
-    return rtracker;
+    DCE2_SmbCleanRequestTracker(rtracker);
+    free((void*)rtracker);
 }
 
-/********************************************************************
- * Function: DCE2_SmbHdrChecks()
- *
- * Checks some relevant fields in the header to make sure they're
- * sane.
- * Side effects are potential alerts for anomolous behavior.
- *
- * Arguments:
- *  DCE2_SmbSsnData *
- *      Pointer to the session data structure.
- *  SmbNtHdr *
- *      Pointer to the header struct layed over the packet data.
- *
- * Returns:
- *  DCE2_Ret
- *      DCE2_RET__IGNORE if we should continue processing, but
- *          ignore data because of the error.
- *      DCE2_RET__SUCCESS if we should continue processing.
- *
- ********************************************************************/
-static DCE2_Ret DCE2_SmbHdrChecks(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr)
+static DCE2_Ret DCE2_SmbFindTid(DCE2_SmbSsnData* ssd, const uint16_t tid)
 {
-    Packet* p = ssd->sd.wire_pkt;
+    DCE2_Ret status;
 
-    if ((DCE2_SsnFromServer(p) && (SmbType(smb_hdr) == SMB_TYPE__REQUEST)) ||
-        (DCE2_SsnFromClient(p) && (SmbType(smb_hdr) == SMB_TYPE__RESPONSE)))
-    {
-        // FIXIT-M port segment check
-        // Same for all cases below
-        dce_alert(GID_DCE2, DCE2_SMB_BAD_TYPE, (dce2CommonStats*)&dce2_smb_stats);
-        // Continue looking at traffic.  Neither Windows nor Samba seem
-        // to care, or even look at this flag
-    }
+    Profile profile(dce2_smb_pstat_smb_tid);
 
-    if ((SmbId(smb_hdr) != DCE2_SMB_ID)
-        && (SmbId(smb_hdr) != DCE2_SMB2_ID))
-    {
-        dce_alert(GID_DCE2, DCE2_SMB_BAD_ID, (dce2CommonStats*)&dce2_smb_stats);
-        return DCE2_RET__IGNORE;
-    }
+    if ((ssd->tid != DCE2_SENTINEL) && ((ssd->tid & 0x0000ffff) == (int)tid))
+        status = DCE2_RET__SUCCESS;
+    else
+        status = DCE2_ListFindKey(ssd->tids, (void*)(uintptr_t)tid);
 
-    return DCE2_RET__SUCCESS;
+    return status;
 }
 
-/********************************************************************
- * Function: DCE2_SmbGetMinByteCount()
- *
- * Purpose:
- *  Returns the minimum byte count for the given command request
- *  or response.
- *
- * Arguments:
- *  uint8_t - the SMB command code
- *  uint8_t - SMB_TYPE__REQUEST or SMB_TYPE__RESPONSE
- *
- * Returns:
- *  uint16_t - the minimum byte count
- *
- ********************************************************************/
-static inline uint16_t DCE2_SmbGetMinByteCount(uint8_t com, uint8_t resp)
+static void DCE2_SmbRemoveTid(DCE2_SmbSsnData* ssd, const uint16_t tid)
 {
-    return smb_bccs[com][resp][0];
-}
+    Profile profile(dce2_smb_pstat_smb_tid);
 
-/********************************************************************
- * Function: DCE2_SmbCheckCommand()
- *
- * Purpose:
- *  Checks basic validity of an SMB command.
- *
- * Arguments:
- *  DCE2_SmbSsnData * - pointer to session data structure
- *  SmbNtHdr *        - pointer to the SMB header structure
- *  uint8_t           - the SMB command code, i.e. SMB_COM_*
- *  uint8_t *         - current pointer to data, i.e. the command
- *  uint32_t          - the remaining length
- *  DCE2_SmbComInfo & -
- *      Populated structure for command processing
- *
- * Returns: None
- *
- ********************************************************************/
-static void DCE2_SmbCheckCommand(DCE2_SmbSsnData* ssd,
-    const SmbNtHdr* smb_hdr, const uint8_t smb_com,
-    const uint8_t* nb_ptr, uint32_t nb_len, DCE2_SmbComInfo& com_info)
-{
-    // Check for server error response
-    if (com_info.smb_type == SMB_TYPE__RESPONSE)
+    DebugFormat(DEBUG_DCE_SMB, "Removing Tid: %u\n", tid);
+
+    if ((ssd->tid != DCE2_SENTINEL) && ((ssd->tid & 0x0000ffff) == (int)tid))
+        ssd->tid = DCE2_SENTINEL;
+    else
+        DCE2_ListRemove(ssd->tids, (void*)(uintptr_t)tid);
+
+    // Removing Tid invalidates files created with it
+    if ((ssd->ftracker.fid != DCE2_SENTINEL)
+        && (ssd->ftracker.tid == tid))
     {
-        const SmbEmptyCom* ec = (SmbEmptyCom*)nb_ptr;
+        DCE2_SmbRemoveFileTracker(ssd, &ssd->ftracker);
+    }
 
-        // Verify there is enough data to do checks
-        if (nb_len < sizeof(SmbEmptyCom))
-        {
-            dce_alert(GID_DCE2, DCE2_SMB_NB_LT_COM, (dce2CommonStats*)&dce2_smb_stats);
-            com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH;
-            return;
-        }
+    if (ssd->ftrackers != nullptr)
+    {
+        DCE2_SmbFileTracker* ftracker;
 
-        // If word and byte counts are zero and there is an error
-        // the server didn't accept client request
-        if ((SmbEmptyComWct(ec) == 0)
-            && (SmbEmptyComBcc(ec) == 0) && SmbError(smb_hdr))
+        for (ftracker = (DCE2_SmbFileTracker*)DCE2_ListFirst(ssd->ftrackers);
+            ftracker != nullptr;
+            ftracker = (DCE2_SmbFileTracker*)DCE2_ListNext(ssd->ftrackers))
         {
-            DebugFormat(DEBUG_DCE_SMB,
-                "Response error: 0x%08X\n", SmbNtStatus(smb_hdr));
-
-            // If broken pipe, clean up data associated with open named pipe
-            if (SmbBrokenPipe(smb_hdr))
+            if (ftracker->tid == (int)tid)
             {
-                DebugMessage(DEBUG_DCE_SMB,"Broken or disconnected pipe.\n");
-                // FIXIT-M uncomment once file tracking is ported
-                // DCE2_SmbRemoveFileTracker(ssd, ssd->cur_rtracker->ftracker);
-            }
+// FIXIT-M uncomment once file api is ported
+/*
+                if (ssd->fapi_ftracker == ftracker)
+                    DCE2_SmbFinishFileAPI(ssd);
 
-            com_info.cmd_error |= DCE2_SMB_COM_ERROR__STATUS_ERROR;
-            return;
+#ifdef ACTIVE_RESPONSE
+                if (ssd->fb_ftracker == ftracker)
+                    DCE2_SmbFinishFileBlockVerdict(ssd);
+#endif
+*/
+                DCE2_ListRemoveCurrent(ssd->ftrackers);
+                DCE2_SmbRemoveFileTrackerFromRequestTrackers(ssd, ftracker);
+            }
         }
     }
+}
 
-    // Set the header size to the minimum size the command can be
-    // without the byte count to make sure there is enough data to
-    // get the word count.
-    SmbAndXCom andx_com = smb_chain_map[smb_com];
-    int chk_com_size;
-    if (andx_com == SMB_ANDX_COM__NONE)
-        chk_com_size = sizeof(SmbCommon);
-    else
-        chk_com_size = sizeof(SmbAndXCommon);
+static void DCE2_SmbInsertTid(DCE2_SmbSsnData* ssd,
+    const uint16_t tid, const bool is_ipc)
+{
+    Profile profile(dce2_smb_pstat_smb_tid);
 
-    // Verify there is enough data to do checks
-    if (nb_len < (uint32_t)chk_com_size)
+    if (!is_ipc && (!DCE2_ScSmbFileInspection((dce2SmbProtoConf*)ssd->sd.config)
+        || ((ssd->max_file_depth == -1) && DCE2_ScSmbFileDepth(
+        (dce2SmbProtoConf*)ssd->sd.config) == -1)))
     {
-        dce_alert(GID_DCE2, DCE2_SMB_NB_LT_COM, (dce2CommonStats*)&dce2_smb_stats);
-        com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH;
+        DebugFormat(DEBUG_DCE_SMB, "Not inserting TID (%u) "
+            "because it's not IPC and not inspecting normal file "
+            "data.", tid);
         return;
     }
 
-    const SmbCommon* sc = (SmbCommon*)nb_ptr;
-    com_info.word_count = SmbWct(sc);
-
-    // Make sure the word count is a valid one for the command.  If not
-    // testing shows an error will be returned.  And command structures
-    // won't lie on data correctly and out of bounds data accesses are possible.
-    if (!DCE2_SmbIsValidWordCount(smb_com, (uint8_t)com_info.smb_type, com_info.word_count))
+    if (is_ipc && DCE2_ScSmbFileInspectionOnly((dce2SmbProtoConf*)ssd->sd.config))
     {
-        dce_alert(GID_DCE2, DCE2_SMB_BAD_WCT, (dce2CommonStats*)&dce2_smb_stats);
-        com_info.cmd_error |= DCE2_SMB_COM_ERROR__INVALID_WORD_COUNT;
+        DebugFormat(DEBUG_DCE_SMB, "Not inserting TID (%u) "
+            "because it's IPC and only inspecting normal file "
+            "data.", tid);
         return;
     }
 
-    // This gets the size of the SMB command from word count through byte count
-    // using the advertised value in the word count field.
-    com_info.cmd_size = (uint16_t)SMB_COM_SIZE(com_info.word_count);
-    if (nb_len < com_info.cmd_size)
+    DebugFormat(DEBUG_DCE_SMB, "Inserting Tid: %u\n", tid);
+    int insert_tid = (int)tid;
+    // Set a bit so as to distinguish between IPC and non-IPC TIDs
+    if (!is_ipc)
+        insert_tid |= (1 << 16);
+
+    if (ssd->tid == DCE2_SENTINEL)
     {
-        dce_alert(GID_DCE2, DCE2_SMB_NB_LT_COM, (dce2CommonStats*)&dce2_smb_stats);
-        com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH;
-        return;
+        ssd->tid = insert_tid;
     }
-
-    uint16_t smb_bcc = SmbBcc(nb_ptr, com_info.cmd_size);
-
-    // SMB_COM_NT_CREATE_ANDX is a special case.  Who know what's going
-    // on with the word count (see MS-CIFS and MS-SMB).  A 42 word count
-    // command seems to actually have 50 words, so who knows where the
-    // byte count is.  Just set to zero since it's not needed.
-    if ((smb_com == SMB_COM_NT_CREATE_ANDX)
-        && (com_info.smb_type == SMB_TYPE__RESPONSE))
-        smb_bcc = 0;
-
-    // If byte count is deemed invalid, alert but continue processing
-    switch (smb_com)
+    else
     {
-    // Interim responses
-    case SMB_COM_TRANSACTION:
-    case SMB_COM_TRANSACTION2:
-    case SMB_COM_NT_TRANSACT:
-        // If word count is 0, byte count must be 0
-        if ((com_info.word_count == 0) && (com_info.smb_type == SMB_TYPE__RESPONSE))
+        if (ssd->tids == nullptr)
         {
-            if (smb_bcc != 0)
+            ssd->tids = DCE2_ListNew(DCE2_LIST_TYPE__SPLAYED, DCE2_SmbUidTidFidCompare,
+                nullptr, nullptr, DCE2_LIST_FLAG__NO_DUPS);
+
+            if (ssd->tids == nullptr)
             {
-                dce_alert(GID_DCE2, DCE2_SMB_BAD_BCC, (dce2CommonStats*)&dce2_smb_stats);
-                com_info.cmd_error |= DCE2_SMB_COM_ERROR__INVALID_BYTE_COUNT;
+                return;
             }
-            break;
-        }
-    // Fall through
-    default:
-        if (!DCE2_SmbIsValidByteCount(smb_com, (uint8_t)com_info.smb_type, smb_bcc))
-        {
-            dce_alert(GID_DCE2, DCE2_SMB_BAD_BCC, (dce2CommonStats*)&dce2_smb_stats);
-            com_info.cmd_error |= DCE2_SMB_COM_ERROR__INVALID_BYTE_COUNT;
         }
-        break;
+
+        DCE2_ListInsert(ssd->tids, (void*)(uintptr_t)tid, (void*)(uintptr_t)insert_tid);
     }
+}
 
-    // Move just past byte count field which is the end of the command
-    DCE2_MOVE(nb_ptr, nb_len, com_info.cmd_size);
+static DCE2_SmbRequestTracker* DCE2_SmbFindRequestTracker(DCE2_SmbSsnData* ssd,
+    const SmbNtHdr* smb_hdr)
+{
+    uint16_t uid = SmbUid(smb_hdr);
+    uint16_t tid = SmbTid(smb_hdr);
+    uint16_t pid = SmbPid(smb_hdr);
+    uint16_t mid = SmbMid(smb_hdr);
 
-    // Validate that there is enough data to be able to process the command
-    if (nb_len < DCE2_SmbGetMinByteCount(smb_com, (uint8_t)com_info.smb_type))
-    {
-        dce_alert(GID_DCE2, DCE2_SMB_NB_LT_BCC, (dce2CommonStats*)&dce2_smb_stats);
-        com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH;
-    }
+    Profile profile(dce2_smb_pstat_smb_req);
 
-    // The byte count seems to be ignored by Windows and current Samba (3.5.4)
-    // as long as it is less than the amount of data left.  If more, an error
-    // is returned.
-    // !!!WARNING!!! the byte count should probably never be used.
-    if (smb_bcc > nb_len)
-    {
-        dce_alert(GID_DCE2, DCE2_SMB_NB_LT_BCC, (dce2CommonStats*)&dce2_smb_stats);
-        // Large byte count doesn't seem to matter for early Samba
-        switch (DCE2_SsnGetPolicy(&ssd->sd))
-        {
-        case DCE2_POLICY__SAMBA_3_0_20:
-        case DCE2_POLICY__SAMBA_3_0_22:
-        case DCE2_POLICY__SAMBA_3_0_37:
-            break;
-        default:
-            com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH;
-            break;
-        }
-    }
-    else if ((smb_bcc == 0) && (SmbCom(smb_hdr) == SMB_COM_TRANSACTION)
-        && (DCE2_SmbType(ssd) == SMB_TYPE__REQUEST)
-        && (DCE2_SsnGetPolicy(&ssd->sd) == DCE2_POLICY__SAMBA))
+    DebugFormat(DEBUG_DCE_SMB, "Find request tracker => "
+        "Uid: %u, Tid: %u, Pid: %u, Mid: %u ... ", uid, tid, pid, mid);
+
+    DCE2_SmbRequestTracker* tmp_rtracker = &ssd->rtracker;
+    int smb_com = SmbCom(smb_hdr);
+    switch (smb_com)
     {
-        // Current Samba errors on a zero byte count Transaction because it
-        // uses it to get the Name string and if zero Name will be NULL and
-        // it won't process it.
-        com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH;
+    case SMB_COM_TRANSACTION_SECONDARY:
+        smb_com = SMB_COM_TRANSACTION;
+        break;
+    case SMB_COM_TRANSACTION2_SECONDARY:
+        smb_com = SMB_COM_TRANSACTION2;
+        break;
+    case SMB_COM_NT_TRANSACT_SECONDARY:
+        smb_com = SMB_COM_NT_TRANSACT;
+        break;
+    case SMB_COM_WRITE_COMPLETE:
+        smb_com = SMB_COM_WRITE_RAW;
+        break;
+    default:
+        break;
     }
 
-    com_info.byte_count = smb_bcc;
-}
+    DCE2_SmbRequestTracker* first_rtracker = nullptr;
+    DCE2_SmbRequestTracker* win_rtracker = nullptr;
+    DCE2_SmbRequestTracker* first_mid_rtracker = nullptr;
+    DCE2_SmbRequestTracker* ret_rtracker = nullptr;
+    while (tmp_rtracker != nullptr)
+    {
+        if ((tmp_rtracker->mid == (int)mid) && (tmp_rtracker->smb_com == smb_com))
+        {
+            // This is the normal case except for SessionSetupAndX and
+            // TreeConnect/TreeConnectAndX which will fall into the
+            // default case below.
+            if ((tmp_rtracker->pid == pid) && (tmp_rtracker->uid == uid)
+                && (tmp_rtracker->tid == tid))
+            {
+                ret_rtracker = tmp_rtracker;
+            }
+            else
+            {
+                switch (smb_com)
+                {
+                case SMB_COM_TRANSACTION:
+                case SMB_COM_TRANSACTION2:
+                case SMB_COM_NT_TRANSACT:
+                case SMB_COM_TRANSACTION_SECONDARY:
+                case SMB_COM_TRANSACTION2_SECONDARY:
+                case SMB_COM_NT_TRANSACT_SECONDARY:
+                    // These should conform to above
+                    break;
+                default:
+                    if (tmp_rtracker->pid == pid)
+                        ret_rtracker = tmp_rtracker;
+                    break;
+                }
+            }
 
-/********************************************************************
- * Function: DCE2_SmbProcessCommand()
- *
- * Purpose:
- *  This is the main function for handling SMB commands and command
- *  chaining.
- *  It does an initial check of the command to determine validity
- *  and gets basic information about the command.  Then it calls the
- *  specific command function (setup in DCE2_SmbInitGlobals).
- *  If there is command chaining, it will do the chaining foo to
- *  get to the next command.
- *
- * Arguments:
- *  DCE2_SmbSsnData * - pointer to session data structure
- *  SmbNtHdr *        - pointer to the SMB header structure
- *  uint8_t *         - current pointer to data, i.e. the command
- *  uint32_t          - the remaining length
- *
- * Returns: None
- *
- ********************************************************************/
-static void DCE2_SmbProcessCommand(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
-    const uint8_t* nb_ptr, uint32_t nb_len)
-{
-    uint8_t smb_com = SmbCom(smb_hdr);
+            if (ret_rtracker != nullptr)
+            {
+                DebugMessage(DEBUG_DCE_SMB, "Found.\n");
+                return ret_rtracker;
+            }
 
-    while (nb_len > 0)
-    {
-        // Break out if command not supported
-        if (smb_com_funcs[smb_com] == nullptr)
-            break;
+            // Take the first one where the PIDs also match
+            // in the case of the Transacts above
+            if ((tmp_rtracker->pid == pid) && (win_rtracker == nullptr))
+                win_rtracker = tmp_rtracker;
 
-        if (smb_deprecated_coms[smb_com])
-        {
-            dce_alert(GID_DCE2, DCE2_SMB_DEPR_COMMAND_USED, (dce2CommonStats*)&dce2_smb_stats);
+            // Set this to the first matching request in the queue
+            // where the Mid matches.  Don't set for Windows if from
+            // client since PID/MID are necessary
+            if (((DCE2_SmbType(ssd) == SMB_TYPE__RESPONSE)
+                || !DCE2_SsnIsWindowsPolicy(&ssd->sd))
+                && first_mid_rtracker == nullptr)
+            {
+                first_mid_rtracker = tmp_rtracker;
+            }
         }
 
-        if (smb_unusual_coms[smb_com])
-        {
-            dce_alert(GID_DCE2, DCE2_SMB_UNUSUAL_COMMAND_USED, (dce2CommonStats*)&dce2_smb_stats);
-        }
+        // Set the first one we see for early Samba versions
+        if ((first_rtracker == nullptr) && (tmp_rtracker->mid != DCE2_SENTINEL)
+            && (tmp_rtracker->smb_com == smb_com))
+            first_rtracker = tmp_rtracker;
 
-        DCE2_SmbComInfo com_info;
-        com_info.smb_type = DCE2_SmbType(ssd);
-        com_info.cmd_error = DCE2_SMB_COM_ERROR__COMMAND_OK;
-        com_info.word_count = 0;
-        com_info.smb_com = smb_com;
-        com_info.cmd_size = 0;
-        com_info.byte_count = 0;
-        DCE2_SmbCheckCommand(ssd, smb_hdr, smb_com, nb_ptr, nb_len, com_info);
+        // Look at the next request in the queue
+        if (tmp_rtracker == &ssd->rtracker)
+            tmp_rtracker = (DCE2_SmbRequestTracker*)DCE2_QueueFirst(ssd->rtrackers);
+        else
+            tmp_rtracker = (DCE2_SmbRequestTracker*)DCE2_QueueNext(ssd->rtrackers);
+    }
 
-        // FIXIT-M port the rest
-        return;
+    DCE2_Policy policy = DCE2_SsnGetPolicy(&ssd->sd);
+    switch (policy)
+    {
+    case DCE2_POLICY__SAMBA_3_0_20:
+    case DCE2_POLICY__SAMBA_3_0_22:
+        ret_rtracker = first_rtracker;
+        break;
+    case DCE2_POLICY__SAMBA:
+    case DCE2_POLICY__SAMBA_3_0_37:
+        ret_rtracker = first_mid_rtracker;
+        break;
+    case DCE2_POLICY__WIN2000:
+    case DCE2_POLICY__WINXP:
+    case DCE2_POLICY__WINVISTA:
+    case DCE2_POLICY__WIN2003:
+    case DCE2_POLICY__WIN2008:
+    case DCE2_POLICY__WIN7:
+        if (win_rtracker != nullptr)
+            ret_rtracker = win_rtracker;
+        else
+            ret_rtracker = first_mid_rtracker;
+        break;
+    default:
+        DebugFormat(DEBUG_DCE_SMB, "%s(%d) Invalid policy: %d",
+            __FILE__, __LINE__, policy);
+        break;
     }
+
+    return ret_rtracker;
 }
 
-/********************************************************************
- * Function: DCE2_SmbInspect()
- *
- * Purpose:
- *  Determines whether the SMB command is something the preprocessor
- *  needs to inspect.
- *  This function returns a DCE2_SmbRequestTracker which tracks command
- *  requests / responses.
- *
- * Arguments:
- *  DCE2_SmbSsnData * - the session data structure.
- *  const SmbNtHdr *  - pointer to the SMB header.
- *
- * Returns:
- *  DCE2_SmbRequestTracker * - nullptr if it's not something we want to or can
- *                     inspect.
- *                     Otherwise an initialized structure if request
- *                     and the found structure if response.
- *
- ********************************************************************/
-static DCE2_SmbRequestTracker* DCE2_SmbInspect(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr)
+static DCE2_SmbRequestTracker* DCE2_SmbNewRequestTracker(DCE2_SmbSsnData* ssd,
+    const SmbNtHdr* smb_hdr)
 {
-    int smb_com = SmbCom(smb_hdr);
+    uint16_t pid = SmbPid(smb_hdr);
+    uint16_t mid = SmbMid(smb_hdr);
+    uint16_t uid = SmbUid(smb_hdr);
+    uint16_t tid = SmbTid(smb_hdr);
 
-    DebugFormat(DEBUG_DCE_SMB, "SMB command: %s (0x%02X)\n",
-        smb_com_strings[smb_com], smb_com);
+    Profile profile(dce2_smb_pstat_smb_req);
 
-    if (smb_com_funcs[smb_com] == nullptr)
+    if (ssd == nullptr)
     {
-        DebugMessage(DEBUG_DCE_SMB, "Command isn't processed "
-            "by preprocessor.\n");
         return nullptr;
     }
 
-    // See if this is something we need to inspect
-    DCE2_Policy policy = DCE2_SsnGetServerPolicy(&ssd->sd);
+    if (ssd->outstanding_requests >= ssd->max_outstanding_requests)
+    {
+        dce_alert(GID_DCE2, DCE2_SMB_MAX_REQS_EXCEEDED, (dce2CommonStats*)&dce2_smb_stats);
+    }
+
+    // Check for outstanding requests with the same MID
+    DCE2_SmbRequestTracker* tmp_rtracker = &ssd->rtracker;
+    while ((tmp_rtracker != nullptr) && (tmp_rtracker->mid != DCE2_SENTINEL))
+    {
+        if (tmp_rtracker->mid == (int)mid)
+        {
+            // Have yet to see an MID repeatedly used so shouldn't
+            // be any outstanding requests with the same MID.
+            dce_alert(GID_DCE2, DCE2_SMB_REQS_SAME_MID, (dce2CommonStats*)&dce2_smb_stats);
+            break;
+        }
+
+        // Look at the next request in the queue
+        if (tmp_rtracker == &ssd->rtracker)
+            tmp_rtracker = (DCE2_SmbRequestTracker*)DCE2_QueueFirst(ssd->rtrackers);
+        else
+            tmp_rtracker = (DCE2_SmbRequestTracker*)DCE2_QueueNext(ssd->rtrackers);
+    }
+
     DCE2_SmbRequestTracker* rtracker = nullptr;
-    if (DCE2_SmbType(ssd) == SMB_TYPE__REQUEST)
+    if (ssd->rtracker.mid == DCE2_SENTINEL)
     {
-        switch (smb_com)
+        rtracker = &ssd->rtracker;
+    }
+    else
+    {
+        if (ssd->rtrackers == nullptr)
         {
-        case SMB_COM_NEGOTIATE:
-            if (ssd->ssn_state_flags & DCE2_SMB_SSN_STATE__NEGOTIATED)
+            ssd->rtrackers = DCE2_QueueNew(DCE2_SmbRequestTrackerDataFree);
+            if (ssd->rtrackers == nullptr)
             {
-                dce_alert(GID_DCE2, DCE2_SMB_MULTIPLE_NEGOTIATIONS,
-                    (dce2CommonStats*)&dce2_smb_stats);
                 return nullptr;
             }
-            break;
-        case SMB_COM_SESSION_SETUP_ANDX:
-            break;
-        case SMB_COM_TREE_CONNECT:
-        case SMB_COM_TREE_CONNECT_ANDX:
-        case SMB_COM_RENAME:
-        case SMB_COM_LOGOFF_ANDX:
-            // FIXIT-M - uncomment after the code to insert uid is ported
-            // till then - will always fail
-            //if (DCE2_SmbFindUid(ssd, SmbUid(smb_hdr)) != DCE2_RET__SUCCESS)
-            //    return nullptr;
-            break;
-        default:
-            // FIXIT-M - uncomment after the code to insert tid is ported
-            // till then - will always fail
-            /*
-            if (DCE2_SmbFindTid(ssd, SmbTid(smb_hdr)) != DCE2_RET__SUCCESS)
-            {
-                DebugFormat(DEBUG_DCE_SMB,
-                    "Couldn't find Tid (%u)\n", SmbTid(smb_hdr));
-                return nullptr;
-            }
-            */
+        }
 
-            if (DCE2_SmbIsTidIPC(ssd, SmbTid(smb_hdr)))
-            {
-                switch (smb_com)
-                {
-                case SMB_COM_OPEN:
-                case SMB_COM_CREATE:
-                case SMB_COM_CREATE_NEW:
-                case SMB_COM_WRITE_AND_CLOSE:
-                case SMB_COM_WRITE_AND_UNLOCK:
-                case SMB_COM_READ:
-                    // Samba doesn't allow these commands under an IPC tree
-                    switch (policy)
-                    {
-                    case DCE2_POLICY__SAMBA:
-                    case DCE2_POLICY__SAMBA_3_0_37:
-                    case DCE2_POLICY__SAMBA_3_0_22:
-                    case DCE2_POLICY__SAMBA_3_0_20:
-                        DebugMessage(DEBUG_DCE_SMB, "Samba doesn't "
-                            "process this command under an IPC tree.\n");
-                        return nullptr;
-                    default:
-                        break;
-                    }
-                    break;
-                case SMB_COM_READ_RAW:
-                case SMB_COM_WRITE_RAW:
-                    // Samba and Windows Vista on don't allow these commands
-                    // under an IPC tree, whether or not the raw read/write
-                    // flag is set in the Negotiate capabilities.
-                    // Windows RSTs the connection and Samba FINs it.
-                    switch (policy)
-                    {
-                    case DCE2_POLICY__WINVISTA:
-                    case DCE2_POLICY__WIN2008:
-                    case DCE2_POLICY__WIN7:
-                    case DCE2_POLICY__SAMBA:
-                    case DCE2_POLICY__SAMBA_3_0_37:
-                    case DCE2_POLICY__SAMBA_3_0_22:
-                    case DCE2_POLICY__SAMBA_3_0_20:
-                        DebugMessage(DEBUG_DCE_SMB, "Samba and "
-                            "Windows Vista on don't process this "
-                            "command under an IPC tree.\n");
-                        return nullptr;
-                    default:
-                        break;
-                    }
-                    break;
-                case SMB_COM_LOCK_AND_READ:
-                    // The lock will fail so the read won't happen
-                    return nullptr;
-                default:
-                    break;
-                }
-            }
-            else      // Not IPC
-            {
-                switch (smb_com)
-                {
-                // These commands are only used for IPC
-                case SMB_COM_TRANSACTION:
-                case SMB_COM_TRANSACTION_SECONDARY:
-                    DebugMessage(DEBUG_DCE_SMB, "secondary transaction not IPC.\n");
-                    return nullptr;
-                case SMB_COM_READ_RAW:
-                case SMB_COM_WRITE_RAW:
-                    // Windows Vista on don't seem to support these
-                    // commands, whether or not the raw read/write
-                    // flag is set in the Negotiate capabilities.
-                    // Windows RSTs the connection.
-                    switch (policy)
-                    {
-                    case DCE2_POLICY__WINVISTA:
-                    case DCE2_POLICY__WIN2008:
-                    case DCE2_POLICY__WIN7:
-                        DebugMessage(DEBUG_DCE_SMB,
-                            "Windows Vista on don't process "
-                            "this command.\n");
-                        return nullptr;
-                    default:
-                        break;
-                    }
-                    break;
-                default:
-                    break;
-                }
-            }
-            break;
+        rtracker = (DCE2_SmbRequestTracker*)SnortAlloc(sizeof(DCE2_SmbRequestTracker));
+        if (rtracker == nullptr)
+        {
+            return nullptr;
         }
 
-        switch (smb_com)
+        if (DCE2_QueueEnqueue(ssd->rtrackers, (void*)rtracker) != DCE2_RET__SUCCESS)
         {
-        case SMB_COM_TRANSACTION_SECONDARY:
-        case SMB_COM_TRANSACTION2_SECONDARY:
-        case SMB_COM_NT_TRANSACT_SECONDARY:
-            rtracker = DCE2_SmbFindRequestTracker(ssd, smb_hdr);
-            break;
-        case SMB_COM_TRANSACTION:
-        case SMB_COM_TRANSACTION2:
-        case SMB_COM_NT_TRANSACT:
-            // If there is already and existing request tracker
-            // and the transaction is not complete, server will
-            // return an error.
-            rtracker = DCE2_SmbFindRequestTracker(ssd, smb_hdr);
-            if (rtracker != nullptr)
-                break;
-        // Fall through
-        default:
-            rtracker = DCE2_SmbNewRequestTracker(ssd, smb_hdr);
-            break;
+            free((void*)rtracker);
+            return nullptr;
         }
     }
-    else
-    {
-        rtracker = DCE2_SmbFindRequestTracker(ssd, smb_hdr);
-    }
+
+    rtracker->smb_com = SmbCom(smb_hdr);
+    rtracker->uid = uid;
+    rtracker->tid = tid;
+    rtracker->pid = pid;
+    rtracker->mid = (int)mid;
+    memset(&rtracker->ttracker, 0, sizeof(rtracker->ttracker));
+    rtracker->ftracker = nullptr;
+    rtracker->sequential_only = false;
+
+    ssd->outstanding_requests++;
+    if (ssd->outstanding_requests > dce2_smb_stats.smb_max_outstanding_requests)
+        dce2_smb_stats.smb_max_outstanding_requests = ssd->outstanding_requests;
+
+    DebugFormat(DEBUG_DCE_SMB, "Added new request tracker => "
+        "Uid: %u, Tid: %u, Pid: %u, Mid: %u\n",
+        rtracker->uid, rtracker->tid, rtracker->pid, rtracker->mid);
+    DebugFormat(DEBUG_DCE_SMB,
+        "Current outstanding requests: %u\n", ssd->outstanding_requests);
 
     return rtracker;
 }
 
-// Temporary command function placeholder, until all of them are ported
-DCE2_Ret DCE2_SmbComFuncPlaceholder(DCE2_SmbSsnData*, const SmbNtHdr*,
-    const DCE2_SmbComInfo*, const uint8_t*, uint32_t)
+static DCE2_Ret DCE2_SmbProcessRequestData(DCE2_SmbSsnData* ssd,
+    const uint16_t fid, const uint8_t* data_ptr, uint32_t data_len, uint64_t offset)
 {
-    return DCE2_RET__SUCCESS;
-}
+    DCE2_SmbFileTracker* ftracker = DCE2_SmbGetFileTracker(ssd, fid);
 
-static bool DCE2_SmbAutodetect(Packet* p)
-{
-    if (p->dsize > (sizeof(NbssHdr) + sizeof(SmbNtHdr)))
-    {
-        NbssHdr* nb_hdr = (NbssHdr*)p->data;
-        SmbNtHdr* smb_hdr = (SmbNtHdr*)(p->data + sizeof(NbssHdr));
+    DebugFormat(DEBUG_DCE_SMB,
+        "Entering Processing request data with Fid: 0x%04X, ftracker ? %s ~~~~~~~~~~~~~~~~~\n",
+        fid,ftracker ? "TRUE" : "FALSE");
+    if (ftracker == nullptr)
+        return DCE2_RET__ERROR;
 
-        if ((SmbId(smb_hdr) != DCE2_SMB_ID)
-            && (SmbId(smb_hdr) != DCE2_SMB2_ID))
-        {
-            return false;
-        }
+    DebugFormat(DEBUG_DCE_SMB,
+        "Processing request data with Fid: 0x%04X, is_ipc ? %s ~~~~~~~~~~~~~~~~~\n", ftracker->fid,
+        ftracker->is_ipc ? "TRUE" : "FALSE");
 
-        switch (NbssType(nb_hdr))
-        {
-        // FIXIT-L currently all ports are treated as autodetect.
-        // On port 139, there is always an initial Session Request / Session Positive/Negative
-        // response.
-        // These message types were added , to make sure port 139 is treated as smb.
-        // Remove once detect/autodetect supported.
-        case NBSS_SESSION_TYPE__REQUEST:
-            if (DCE2_SsnFromClient(p))
-                return true;
-            break;
+    // Set this in case of chained commands or reassembled packet
+    ssd->cur_rtracker->ftracker = ftracker;
 
-        case NBSS_SESSION_TYPE__POS_RESPONSE:
-        case NBSS_SESSION_TYPE__NEG_RESPONSE:
-            if (DCE2_SsnFromServer(p))
-                return true;
-            break;
+    if (ftracker->is_ipc)
+    {
+        // Maximum possible fragment length is 16 bit
+        if (data_len > UINT16_MAX)
+            data_len = UINT16_MAX;
 
-        case NBSS_SESSION_TYPE__MESSAGE:
-            return true;
-            break;
-        default:
-            break;
-        }
+        DCE2_CoProcess(&ssd->sd, ftracker->fp_co_tracker, data_ptr, (uint16_t)data_len);
+
+        if (!ftracker->fp_used)
+            ftracker->fp_used = true;
+    }
+    else
+    {
+        ftracker->ff_file_offset = offset;
+        // FIXIT-M uncomment when file processing is ported
+        // DCE2_SmbProcessFileData(ssd, ftracker, data_ptr, data_len, true);
     }
 
-    return false;
+    DebugMessage(DEBUG_DCE_SMB, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
+
+    return DCE2_RET__SUCCESS;
 }
 
-void DCE2_SmbDataFree(DCE2_SmbSsnData* ssd)
+static DCE2_Ret DCE2_SmbProcessResponseData(DCE2_SmbSsnData* ssd,
+    const uint8_t* data_ptr, uint32_t data_len)
 {
-    if (ssd == nullptr)
-        return;
-
-    // FIXIT This tries to account for the situation where we never knew the file
-    // size and the TCP session was shutdown before an SMB_COM_CLOSE on the file.
-    // Possibly need to add callback to fileAPI since it may have already
-    // released it's resources.
-    //DCE2_SmbFinishFileAPI(ssd);
+    DCE2_SmbFileTracker* ftracker = ssd->cur_rtracker->ftracker;
 
-    if (ssd->uids != nullptr)
-    {
-        DCE2_ListDestroy(ssd->uids);
-        ssd->uids = nullptr;
-    }
-
-    if (ssd->tids != nullptr)
-    {
-        DCE2_ListDestroy(ssd->tids);
-        ssd->tids = nullptr;
-    }
+    if (ftracker == nullptr)
+        return DCE2_RET__ERROR;
 
-    // FIXIT-M uncomment once file tracking is ported
-/*
-    DCE2_SmbCleanFileTracker(&ssd->ftracker);
-    if (ssd->ftrackers != nullptr)
-    {
-        DCE2_ListDestroy(ssd->ftrackers);
-        ssd->ftrackers = nullptr;
-    }
-*/
+    DebugFormat(DEBUG_DCE_SMB,
+        "Processing response data with Fid: 0x%04X ~~~~~~~~~~~~~~~~\n", ftracker->fid);
 
-    DCE2_SmbCleanRequestTracker(&ssd->rtracker);
-    if (ssd->rtrackers != nullptr)
+    if (ftracker->is_ipc)
     {
-        DCE2_QueueDestroy(ssd->rtrackers);
-        ssd->rtrackers = nullptr;
-    }
+        // Maximum possible fragment length is 16 bit
+        if (data_len > UINT16_MAX)
+            data_len = UINT16_MAX;
 
-    if (ssd->cli_seg != nullptr)
-    {
-        DCE2_BufferDestroy(ssd->cli_seg);
-        ssd->cli_seg = nullptr;
+        DCE2_CoProcess(&ssd->sd, ftracker->fp_co_tracker, data_ptr, (uint16_t)data_len);
     }
-
-    if (ssd->srv_seg != nullptr)
+    else
     {
-        DCE2_BufferDestroy(ssd->srv_seg);
-        ssd->srv_seg = nullptr;
+        ftracker->ff_file_offset = ssd->cur_rtracker->file_offset;
+        // FIXIT-M uncomment when file processing is ported
+        //DCE2_SmbProcessFileData(ssd, ftracker, data_ptr, data_len, false);
     }
-}
 
-Dce2SmbFlowData::Dce2SmbFlowData() : FlowData(flow_id)
-{
-}
+    DebugMessage(DEBUG_DCE_SMB, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
 
-Dce2SmbFlowData::~Dce2SmbFlowData()
-{
-    DCE2_SmbDataFree(&dce2_smb_session);
+    return DCE2_RET__SUCCESS;
 }
 
-unsigned Dce2SmbFlowData::flow_id = 0;
-
-DCE2_SmbSsnData* get_dce2_smb_session_data(Flow* flow)
-{
-    Dce2SmbFlowData* fd = (Dce2SmbFlowData*)flow->get_application_data(
-        Dce2SmbFlowData::flow_id);
-
-    return fd ? &fd->dce2_smb_session : nullptr;
-}
-
-static DCE2_SmbSsnData* set_new_dce2_smb_session(Packet* p)
-{
-    Dce2SmbFlowData* fd = new Dce2SmbFlowData;
-
-    memset(&fd->dce2_smb_session,0,sizeof(DCE2_SmbSsnData));
-    p->flow->set_application_data(fd);
-    return(&fd->dce2_smb_session);
-}
-
-static DCE2_SmbSsnData* dce2_create_new_smb_session(Packet* p, dce2SmbProtoConf* config)
+/********************************************************************
+ * Function: DCE2_SmbHdrChecks()
+ *
+ * Checks some relevant fields in the header to make sure they're
+ * sane.
+ * Side effects are potential alerts for anomolous behavior.
+ *
+ * Arguments:
+ *  DCE2_SmbSsnData *
+ *      Pointer to the session data structure.
+ *  SmbNtHdr *
+ *      Pointer to the header struct layed over the packet data.
+ *
+ * Returns:
+ *  DCE2_Ret
+ *      DCE2_RET__IGNORE if we should continue processing, but
+ *          ignore data because of the error.
+ *      DCE2_RET__SUCCESS if we should continue processing.
+ *
+ ********************************************************************/
+static DCE2_Ret DCE2_SmbHdrChecks(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr)
 {
-    DCE2_SmbSsnData* dce2_smb_sess = nullptr;
-    Profile profile(dce2_smb_pstat_new_session);
-
-    //FIXIT-M Re-evaluate after infrastructure/binder support if autodetect here
-    //is necessary
+    Packet* p = ssd->sd.wire_pkt;
 
-    if (DCE2_SmbAutodetect(p))
+    if ((DCE2_SsnFromServer(p) && (SmbType(smb_hdr) == SMB_TYPE__REQUEST)) ||
+        (DCE2_SsnFromClient(p) && (SmbType(smb_hdr) == SMB_TYPE__RESPONSE)))
     {
-        DebugMessage(DEBUG_DCE_SMB, "DCE over SMB packet detected\n");
-        DebugMessage(DEBUG_DCE_SMB, "Creating new session\n");
-
-        dce2_smb_sess = set_new_dce2_smb_session(p);
-        if ( dce2_smb_sess )
-        {
-            dce2_smb_sess->dialect_index = DCE2_SENTINEL;
-            dce2_smb_sess->max_outstanding_requests = 10;  // Until Negotiate/SessionSetupAndX
-            dce2_smb_sess->cli_data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
-            dce2_smb_sess->srv_data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
-            dce2_smb_sess->pdu_state = DCE2_SMB_PDU_STATE__COMMAND;
-            dce2_smb_sess->uid = DCE2_SENTINEL;
-            dce2_smb_sess->tid = DCE2_SENTINEL;
-            dce2_smb_sess->ftracker.fid = DCE2_SENTINEL;
-            dce2_smb_sess->rtracker.mid = DCE2_SENTINEL;
-            dce2_smb_sess->max_file_depth = FileService::get_max_file_depth();
-
-            DCE2_ResetRopts(&dce2_smb_sess->sd.ropts);
-
-            dce2_smb_stats.smb_sessions++;
-            DebugFormat(DEBUG_DCE_SMB,"Created (%p)\n", (void*)dce2_smb_sess);
-
-            dce2_smb_sess->sd.trans = DCE2_TRANS_TYPE__SMB;
-            dce2_smb_sess->sd.server_policy = config->common.policy;
-            dce2_smb_sess->sd.client_policy = DCE2_POLICY__WINXP;
-            dce2_smb_sess->sd.wire_pkt = p;
-            dce2_smb_sess->sd.config = (void*)config;
-
-            DCE2_SsnSetAutodetected(&dce2_smb_sess->sd, p);
-        }
+        // FIXIT-M port segment check
+        // Same for all cases below
+        dce_alert(GID_DCE2, DCE2_SMB_BAD_TYPE, (dce2CommonStats*)&dce2_smb_stats);
+        // Continue looking at traffic.  Neither Windows nor Samba seem
+        // to care, or even look at this flag
     }
 
-    return dce2_smb_sess;
-}
-
-static DCE2_SmbSsnData* dce2_handle_smb_session(Packet* p, dce2SmbProtoConf* config)
-{
-    Profile profile(dce2_smb_pstat_session);
-
-    DCE2_SmbSsnData* dce2_smb_sess =  get_dce2_smb_session_data(p->flow);
-
-    if (dce2_smb_sess == nullptr)
-    {
-        dce2_smb_sess = dce2_create_new_smb_session(p, config);
-    }
-    else
+    if ((SmbId(smb_hdr) != DCE2_SMB_ID)
+        && (SmbId(smb_hdr) != DCE2_SMB2_ID))
     {
-        DCE2_SsnData* sd = (DCE2_SsnData*)dce2_smb_sess;
-        sd->wire_pkt = p;
-
-        if (DCE2_SsnAutodetected(sd) && !(p->packet_flags & sd->autodetect_dir))
-        {
-            /* Try to autodetect in opposite direction */
-            if (!DCE2_SmbAutodetect(p))
-            {
-                DebugMessage(DEBUG_DCE_SMB, "Bad autodetect.\n");
-                DCE2_SsnNoInspect(sd);
-                dce2_smb_stats.sessions_aborted++;
-                dce2_smb_stats.bad_autodetects++;
-                return nullptr;
-            }
-            DCE2_SsnClearAutodetected(sd);
-        }
+        dce_alert(GID_DCE2, DCE2_SMB_BAD_ID, (dce2CommonStats*)&dce2_smb_stats);
+        return DCE2_RET__IGNORE;
     }
-    DebugFormat(DEBUG_DCE_SMB, "Session pointer: %p\n", (void*)dce2_smb_sess);
 
-    // FIXIT-M add remaining session handling logic
+    return DCE2_RET__SUCCESS;
+}
 
-    return dce2_smb_sess;
+/********************************************************************
+ * Function: DCE2_SmbGetMinByteCount()
+ *
+ * Purpose:
+ *  Returns the minimum byte count for the given command request
+ *  or response.
+ *
+ * Arguments:
+ *  uint8_t - the SMB command code
+ *  uint8_t - SMB_TYPE__REQUEST or SMB_TYPE__RESPONSE
+ *
+ * Returns:
+ *  uint16_t - the minimum byte count
+ *
+ ********************************************************************/
+static inline uint16_t DCE2_SmbGetMinByteCount(uint8_t com, uint8_t resp)
+{
+    return smb_bccs[com][resp][0];
 }
 
 /********************************************************************
- * Function: DCE2_NbssHdrChecks()
+ * Function: DCE2_SmbGetString()
  *
  * Purpose:
- *  Does validation of the NetBIOS header.  SMB will only run over
- *  the Session Message type.  On port 139, there is always an
- *  initial Session Request / Session Positive/Negative response
- *  followed by the normal SMB conversation, i.e. Negotiate,
- *  SessionSetupAndX, etc.
- *  Side effects are potential alerts for anomolous behavior.
+ *  Parses data passed in and returns an ASCII string.  True
+ *  unicode characters are replaced with a '.'
  *
  * Arguments:
- *  DCE2_SmbSsnData * - the session data structure.
- *  const NbssHdr *   - pointer to the NetBIOS Session Service
- *                      header structure.  Size is already validated.
+ *  const uint8_t *  - pointer to data
+ *  uint32_t         - data length
+ *  bool             - true if the data is unicode (UTF-16LE)
+ *  bool             - true if the function should only return the
+ *                     file name instead of the entire path
  *
  * Returns:
- *  DCE2_Ret  -  DCE2_RET__SUCCESS if all goes well and processing
- *               should continue.
- *               DCE2_RET__IGNORE if it's not something we need to
- *               look at.
- *               DCE2_RET__ERROR if an invalid NetBIOS Session
- *               Service type is found.
+ *  char *  - NULL terminated ASCII string
  *
  ********************************************************************/
-static DCE2_Ret DCE2_NbssHdrChecks(DCE2_SmbSsnData* ssd, const NbssHdr* nb_hdr)
+static char* DCE2_SmbGetString(const uint8_t* data,
+    uint32_t data_len, bool unicode, bool get_file)
 {
-    Packet* p = ssd->sd.wire_pkt;
+    char* str;
+    uint32_t i, j, k = unicode ? data_len - 1 : data_len;
+    uint8_t inc = unicode ? 2 : 1;
 
-    DebugMessage(DEBUG_DCE_SMB, "NetBIOS Session Service type: ");
+    if (data_len < inc)
+        return nullptr;
 
-    switch (NbssType(nb_hdr))
+    // Move forward.  Don't know if the end of data is actually
+    // the end of the string.
+    for (i = 0, j = 0; i < k; i += inc)
     {
-    case NBSS_SESSION_TYPE__MESSAGE:
-        /* Only want to look at session messages */
-        DebugMessage(DEBUG_DCE_SMB, "Session Message\n");
-
-        if (!DCE2_SmbIsRawData(ssd))
-        {
-            uint32_t nb_len = NbssLen(nb_hdr);
-
-            if (nb_len == 0)
-                return DCE2_RET__IGNORE;
-
-            if (nb_len < sizeof(SmbNtHdr))
-            {
-                DebugFormat(DEBUG_DCE_SMB, "NetBIOS SS len(%u) < SMB header len(%u).\n",
-                    sizeof(SmbNtHdr), sizeof(NbssHdr) + nb_len);
-
-                // FIXIT-M port segment check
-                // Same for all cases below
-                dce_alert(GID_DCE2, DCE2_SMB_NB_LT_SMBHDR, (dce2CommonStats*)&dce2_smb_stats);
-                return DCE2_RET__IGNORE;
-            }
-        }
-
-        return DCE2_RET__SUCCESS;
-
-    case NBSS_SESSION_TYPE__REQUEST:
-        DebugMessage(DEBUG_DCE_SMB, "Session Request\n");
-        if (DCE2_SsnFromServer(p))
-        {
-            dce_alert(GID_DCE2, DCE2_SMB_BAD_NBSS_TYPE, (dce2CommonStats*)&dce2_smb_stats);
-        }
-
-        break;
-
-    case NBSS_SESSION_TYPE__POS_RESPONSE:
-    case NBSS_SESSION_TYPE__NEG_RESPONSE:
-    case NBSS_SESSION_TYPE__RETARGET_RESPONSE:
-        if (DCE2_SsnFromClient(p))
-        {
-            dce_alert(GID_DCE2, DCE2_SMB_BAD_NBSS_TYPE, (dce2CommonStats*)&dce2_smb_stats);
-        }
+        uint16_t uchar = unicode ? extract_16bits(data + i) : data[i];
 
-        break;
+        if (uchar == 0)
+            break;
+        else if (get_file && ((uchar == 0x002F) || (uchar == 0x005C)))  // slash and back-slash
+            j = i + inc;
+    }
 
-    case NBSS_SESSION_TYPE__KEEP_ALIVE:
-        DebugMessage(DEBUG_DCE_SMB, "Session Keep Alive\n");
-        break;
+    // Only got a NULL byte or nothing after slash/back-slash or too big.
+    if ((i == 0) || (j == i)
+        || (get_file && (i > DCE2_SMB_MAX_COMP_LEN))
+        || (i > DCE2_SMB_MAX_PATH_LEN))
+        return nullptr;
 
-    default:
-        DebugFormat(DEBUG_DCE_SMB,
-            "Invalid Session Service type: 0x%02X\n", NbssType(nb_hdr));
-        dce_alert(GID_DCE2, DCE2_SMB_BAD_NBSS_TYPE, (dce2CommonStats*)&dce2_smb_stats);
+    str = (char*)SnortAlloc(((i-j)>>(inc-1))+1);
+    if (str == nullptr)
+        return nullptr;
 
-        return DCE2_RET__ERROR;
+    for (k = 0; j < i; j += inc, k++)
+    {
+        if (isprint((int)data[j]))
+            str[k] = (char)data[j];
+        else
+            str[k] = '.';
     }
 
-    return DCE2_RET__IGNORE;
+    str[k] = 0;
+
+    return str;
 }
 
 /********************************************************************
- * Function: DCE2_SmbProcess()
+ * Function: DCE2_SmbCheckCommand()
  *
  * Purpose:
- *  This is the main entry point for SMB processing.
+ *  Checks basic validity of an SMB command.
  *
  * Arguments:
- *  DCE2_SmbSsnData * - the session data structure.
+ *  DCE2_SmbSsnData * - pointer to session data structure
+ *  SmbNtHdr *        - pointer to the SMB header structure
+ *  uint8_t           - the SMB command code, i.e. SMB_COM_*
+ *  uint8_t *         - current pointer to data, i.e. the command
+ *  uint32_t          - the remaining length
+ *  DCE2_SmbComInfo & -
+ *      Populated structure for command processing
  *
  * Returns: None
  *
  ********************************************************************/
-void DCE2_SmbProcess(DCE2_SmbSsnData* ssd)
+static void DCE2_SmbCheckCommand(DCE2_SmbSsnData* ssd,
+    const SmbNtHdr* smb_hdr, const uint8_t smb_com,
+    const uint8_t* nb_ptr, uint32_t nb_len, DCE2_SmbComInfo& com_info)
 {
-    DebugMessage(DEBUG_DCE_SMB, "Processing SMB packet.\n");
-    dce2_smb_stats.smb_pkts++;
-
-    const Packet* p = ssd->sd.wire_pkt;
-    const uint8_t* data_ptr = p->data;
-    uint16_t data_len = p->dsize;
-
-    /* Have to account for segmentation.  Even though stream will give
-     * us larger chunks, we might end up in the middle of something */
-    while (data_len > 0)
+    // Check for server error response
+    if (com_info.smb_type == SMB_TYPE__RESPONSE)
     {
-        // We are ignoring an entire PDU or junk data so state should be NETBIOS_HEADER
-        // Note that it could be TCP segmented so ignore_bytes could be greater than
-        // the amount of data we have
-        uint32_t* ignore_bytes = DCE2_SmbGetIgnorePtr(ssd);
-        if (*ignore_bytes)
-        {
-            DebugFormat(DEBUG_DCE_SMB, "Ignoring %u bytes\n", *ignore_bytes);
+        const SmbEmptyCom* ec = (SmbEmptyCom*)nb_ptr;
 
-            if (data_len <= *ignore_bytes)
-            {
-                *ignore_bytes -= data_len;
-                return;
-            }
-            else
-            {
-                /* ignore bytes is less than UINT16_MAX */
-                DCE2_MOVE(data_ptr, data_len, (uint16_t)*ignore_bytes);
-                *ignore_bytes = 0;
-            }
+        // Verify there is enough data to do checks
+        if (nb_len < sizeof(SmbEmptyCom))
+        {
+            dce_alert(GID_DCE2, DCE2_SMB_NB_LT_COM, (dce2CommonStats*)&dce2_smb_stats);
+            com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH;
+            return;
         }
 
-        DCE2_SmbDataState* data_state = DCE2_SmbGetDataState(ssd);
-        DCE2_SmbRequestTracker* rtracker = nullptr;
-        switch (*data_state)
-        {
-        // This state is to verify it's a NetBIOS Session Message packet
-        // and to get the length of the SMB PDU.  Also does the SMB junk
-        // data check.  If it's not a Session Message the data isn't
-        // processed since it won't be carrying SMB.
-        case DCE2_SMB_DATA_STATE__NETBIOS_HEADER:
+        // If word and byte counts are zero and there is an error
+        // the server didn't accept client request
+        if ((SmbEmptyComWct(ec) == 0)
+            && (SmbEmptyComBcc(ec) == 0) && SmbError(smb_hdr))
         {
-            uint32_t data_need = sizeof(NbssHdr);
-
-            // See if there is enough data to process the NetBIOS header
-            if (data_len < data_need)
-            {
-                DebugFormat(DEBUG_DCE_SMB, "Data len(%u) < NetBIOS SS header(%u). "
-                    "Queueing data.\n", data_len, data_need);
-
-                // FIXIT-M port segmentation code
-                return;
-            }
-
-            // Set the NetBIOS header structure
-            NbssHdr* nb_hdr = (NbssHdr*)data_ptr;
-            uint32_t nb_len = NbssLen(nb_hdr);
-
-            DebugFormat(DEBUG_DCE_SMB, "NetBIOS PDU length: %u\n", nb_len);
+            DebugFormat(DEBUG_DCE_SMB,
+                "Response error: 0x%08X\n", SmbNtStatus(smb_hdr));
 
-            DCE2_Ret status = DCE2_NbssHdrChecks(ssd, nb_hdr);
-            if (status != DCE2_RET__SUCCESS)
+            // If broken pipe, clean up data associated with open named pipe
+            if (SmbBrokenPipe(smb_hdr))
             {
-                DebugMessage(DEBUG_DCE_SMB, "Not a NetBIOS Session Message.\n");
-
-                if (status == DCE2_RET__IGNORE)
-                {
-                    DebugMessage(DEBUG_DCE_SMB, "Valid NetBIOS header "
-                        "type so ignoring NetBIOS length bytes.\n");
-                    *ignore_bytes = data_need + nb_len;
-                }
-                else      // nb_ret == DCE2_RET__ERROR, i.e. invalid NetBIOS type
-                {
-                    DebugMessage(DEBUG_DCE_SMB, "Not a valid NetBIOS "
-                        "header type so trying to find \\xffSMB to "
-                        "determine how many bytes to ignore.\n");
-                    *ignore_bytes = DCE2_IgnoreJunkData(data_ptr, data_len, data_need + nb_len);
-                }
-
-                dce2_smb_stats.smb_ignored_bytes += *ignore_bytes;
-                continue;
+                DebugMessage(DEBUG_DCE_SMB, "Broken or disconnected pipe.\n");
+                DCE2_SmbRemoveFileTracker(ssd, ssd->cur_rtracker->ftracker);
             }
 
-            switch (ssd->pdu_state)
-            {
-            case DCE2_SMB_PDU_STATE__COMMAND:
-                *data_state = DCE2_SMB_DATA_STATE__SMB_HEADER;
-                break;
-            case DCE2_SMB_PDU_STATE__RAW_DATA:
-                *data_state = DCE2_SMB_DATA_STATE__NETBIOS_PDU;
-                // Continue here because of fall through below
-                continue;
-            default:
-                DebugFormat(DEBUG_DCE_SMB,"%s(%d) Invalid SMB PDU "
-                    "state: %d\n", __FILE__, __LINE__, ssd->pdu_state);
-                return;
-            }
+            com_info.cmd_error |= DCE2_SMB_COM_ERROR__STATUS_ERROR;
+            return;
         }
+    }
 
-        // Fall through for DCE2_SMB_DATA_STATE__SMB_HEADER
-        // This is the normal progression without segmentation.
-
-        // This state is to do validation checks on the SMB header and
-        // more importantly verify it's data that needs to be inspected.
-        // If the TID in the SMB header is not referring to the IPC share
-        // there won't be any DCE/RPC traffic associated with it.
-        case DCE2_SMB_DATA_STATE__SMB_HEADER:
-        {
-            // FIXIT-M add segmentation code path, including seg_buf code to the entire state
-
-            uint32_t data_need = (sizeof(NbssHdr) + sizeof(SmbNtHdr));
-            // See if there is enough data to process the SMB header
-            if (data_len < data_need)
-            {
-                DebugFormat(DEBUG_DCE_SMB, "Data len (%u) < "
-                    "NetBIOS SS header + SMB header (%u). Queueing data.\n",
-                    data_len, data_need);
+    // Set the header size to the minimum size the command can be
+    // without the byte count to make sure there is enough data to
+    // get the word count.
+    SmbAndXCom andx_com = smb_chain_map[smb_com];
+    int chk_com_size;
+    if (andx_com == SMB_ANDX_COM__NONE)
+        chk_com_size = sizeof(SmbCommon);
+    else
+        chk_com_size = sizeof(SmbAndXCommon);
 
-                // FIXIT-M add segmentation code path
-                return;
-            }
+    // Verify there is enough data to do checks
+    if (nb_len < (uint32_t)chk_com_size)
+    {
+        dce_alert(GID_DCE2, DCE2_SMB_NB_LT_COM, (dce2CommonStats*)&dce2_smb_stats);
+        com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH;
+        return;
+    }
 
-            // FIXIT-M add segmentation checks
-            SmbNtHdr* smb_hdr = (SmbNtHdr*)(data_ptr + sizeof(NbssHdr));
+    const SmbCommon* sc = (SmbCommon*)nb_ptr;
+    com_info.word_count = SmbWct(sc);
 
-            // FIXIT-L Don't support SMB2 yet
-            if (SmbId(smb_hdr) == DCE2_SMB2_ID)
-            {
-                ssd->sd.flags |= DCE2_SSN_FLAG__NO_INSPECT;
-                return;
-            }
+    // Make sure the word count is a valid one for the command.  If not
+    // testing shows an error will be returned.  And command structures
+    // won't lie on data correctly and out of bounds data accesses are possible.
+    if (!DCE2_SmbIsValidWordCount(smb_com, (uint8_t)com_info.smb_type, com_info.word_count))
+    {
+        dce_alert(GID_DCE2, DCE2_SMB_BAD_WCT, (dce2CommonStats*)&dce2_smb_stats);
+        com_info.cmd_error |= DCE2_SMB_COM_ERROR__INVALID_WORD_COUNT;
+        return;
+    }
 
-            // See if this is something we need to inspect
-            rtracker = DCE2_SmbInspect(ssd, smb_hdr);
-            if (rtracker == nullptr)
-            {
-                DebugMessage(DEBUG_DCE_SMB, "Not inspecting SMB packet.\n");
+    // This gets the size of the SMB command from word count through byte count
+    // using the advertised value in the word count field.
+    com_info.cmd_size = (uint16_t)SMB_COM_SIZE(com_info.word_count);
+    if (nb_len < com_info.cmd_size)
+    {
+        dce_alert(GID_DCE2, DCE2_SMB_NB_LT_COM, (dce2CommonStats*)&dce2_smb_stats);
+        com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH;
+        return;
+    }
 
-                // FIXIT-M add segmentation
-                *ignore_bytes = sizeof(NbssHdr) + NbssLen((NbssHdr*)data_ptr);
+    uint16_t smb_bcc = SmbBcc(nb_ptr, com_info.cmd_size);
 
-                *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
-                dce2_smb_stats.smb_ignored_bytes += *ignore_bytes;
-                continue;
-            }
+    // SMB_COM_NT_CREATE_ANDX is a special case.  Who know what's going
+    // on with the word count (see MS-CIFS and MS-SMB).  A 42 word count
+    // command seems to actually have 50 words, so who knows where the
+    // byte count is.  Just set to zero since it's not needed.
+    if ((smb_com == SMB_COM_NT_CREATE_ANDX)
+        && (com_info.smb_type == SMB_TYPE__RESPONSE))
+        smb_bcc = 0;
 
-            // Check the SMB header for anomolies
-            if (DCE2_SmbHdrChecks(ssd, smb_hdr) != DCE2_RET__SUCCESS)
+    // If byte count is deemed invalid, alert but continue processing
+    switch (smb_com)
+    {
+    // Interim responses
+    case SMB_COM_TRANSACTION:
+    case SMB_COM_TRANSACTION2:
+    case SMB_COM_NT_TRANSACT:
+        // If word count is 0, byte count must be 0
+        if ((com_info.word_count == 0) && (com_info.smb_type == SMB_TYPE__RESPONSE))
+        {
+            if (smb_bcc != 0)
             {
-                DebugMessage(DEBUG_DCE_SMB, "Bad SMB header.\n");
-
-                *ignore_bytes = sizeof(NbssHdr) + NbssLen((NbssHdr*)data_ptr);
-
-                *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
-
-                dce2_smb_stats.smb_ignored_bytes += *ignore_bytes;
-                continue;
+                dce_alert(GID_DCE2, DCE2_SMB_BAD_BCC, (dce2CommonStats*)&dce2_smb_stats);
+                com_info.cmd_error |= DCE2_SMB_COM_ERROR__INVALID_BYTE_COUNT;
             }
-
-            *data_state = DCE2_SMB_DATA_STATE__NETBIOS_PDU;
+            break;
         }
-
-        // Fall through
-
-        // This state ensures that we have the entire PDU before continuing
-        // to process.
-        case DCE2_SMB_DATA_STATE__NETBIOS_PDU:
+    // Fall through
+    default:
+        if (!DCE2_SmbIsValidByteCount(smb_com, (uint8_t)com_info.smb_type, smb_bcc))
         {
-            uint32_t nb_len = NbssLen((NbssHdr*)data_ptr);
-            uint32_t data_need = sizeof(NbssHdr) + nb_len;
+            dce_alert(GID_DCE2, DCE2_SMB_BAD_BCC, (dce2CommonStats*)&dce2_smb_stats);
+            com_info.cmd_error |= DCE2_SMB_COM_ERROR__INVALID_BYTE_COUNT;
+        }
+        break;
+    }
 
-            /* It's something we want to inspect so make sure we have the full NBSS packet */
-            if (data_len < data_need)
-            {
-                DebugFormat(DEBUG_DCE_SMB, "Data len(%u) < "
-                    "NetBIOS SS header + NetBIOS len(%u). "
-                    "Queueing data.\n", data_len, sizeof(NbssHdr) + nb_len);
+    // Move just past byte count field which is the end of the command
+    DCE2_MOVE(nb_ptr, nb_len, com_info.cmd_size);
 
-                // FIXIT-M add segmentation code
+    // Validate that there is enough data to be able to process the command
+    if (nb_len < DCE2_SmbGetMinByteCount(smb_com, (uint8_t)com_info.smb_type))
+    {
+        dce_alert(GID_DCE2, DCE2_SMB_NB_LT_BCC, (dce2CommonStats*)&dce2_smb_stats);
+        com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH;
+    }
 
-                return;
-            }
+    // The byte count seems to be ignored by Windows and current Samba (3.5.4)
+    // as long as it is less than the amount of data left.  If more, an error
+    // is returned.
+    // !!!WARNING!!! the byte count should probably never be used.
+    if (smb_bcc > nb_len)
+    {
+        dce_alert(GID_DCE2, DCE2_SMB_NB_LT_BCC, (dce2CommonStats*)&dce2_smb_stats);
+        // Large byte count doesn't seem to matter for early Samba
+        switch (DCE2_SsnGetPolicy(&ssd->sd))
+        {
+        case DCE2_POLICY__SAMBA_3_0_20:
+        case DCE2_POLICY__SAMBA_3_0_22:
+        case DCE2_POLICY__SAMBA_3_0_37:
+            break;
+        default:
+            com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH;
+            break;
+        }
+    }
+    else if ((smb_bcc == 0) && (SmbCom(smb_hdr) == SMB_COM_TRANSACTION)
+        && (DCE2_SmbType(ssd) == SMB_TYPE__REQUEST)
+        && (DCE2_SsnGetPolicy(&ssd->sd) == DCE2_POLICY__SAMBA))
+    {
+        // Current Samba errors on a zero byte count Transaction because it
+        // uses it to get the Name string and if zero Name will be NULL and
+        // it won't process it.
+        com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH;
+    }
 
-            // data_len >= data_need which means data_need <= UINT16_MAX
-            // So casts below of data_need to uint16_t are okay.
-
-            *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
-
-            const uint8_t* nb_ptr = data_ptr;
-            nb_len = data_need;
-            DCE2_MOVE(data_ptr, data_len, (uint16_t)data_need);
-
-            switch (ssd->pdu_state)
-            {
-            case DCE2_SMB_PDU_STATE__COMMAND:
-            {
-                SmbNtHdr* smb_hdr = (SmbNtHdr*)(nb_ptr + sizeof(NbssHdr));
-                DCE2_MOVE(nb_ptr, nb_len, (sizeof(NbssHdr) + sizeof(SmbNtHdr)));
-                ssd->cur_rtracker = (rtracker != nullptr)
-                    ? rtracker : DCE2_SmbFindRequestTracker(ssd, smb_hdr);
-                if (ssd->cur_rtracker != nullptr)
-                    DCE2_SmbProcessCommand(ssd, smb_hdr, nb_ptr, nb_len);
-                break;
-            }
-
-            case DCE2_SMB_PDU_STATE__RAW_DATA:
-                //FIXIT-M port raw state
-                break;
-            default:
-                DebugFormat(DEBUG_DCE_SMB, "%s(%d) Invalid SMB PDU "
-                    "state: %d\n", __FILE__, __LINE__, ssd->pdu_state);
-                return;
-            }
-            break;
-        }
-
-        default:
-            DebugFormat(DEBUG_DCE_SMB, "%s(%d) Invalid SMB Data "
-                "state: %d\n", __FILE__, __LINE__, *data_state);
-            return;
-        }
-    }
+    com_info.byte_count = smb_bcc;
 }
 
 /********************************************************************
- * Function: DCE2_SmbInitGlobals()
+ * Function: DCE2_SmbProcessCommand()
  *
  * Purpose:
- *  Initializes global variables for SMB processing.
- *  Sets up the functions and valid word and byte counts for SMB
- *  commands.
- *  Sets up AndX chain mappings and valid command chaining for
- *  supported policies.
+ *  This is the main function for handling SMB commands and command
+ *  chaining.
+ *  It does an initial check of the command to determine validity
+ *  and gets basic information about the command.  Then it calls the
+ *  specific command function (setup in DCE2_SmbInitGlobals).
+ *  If there is command chaining, it will do the chaining foo to
+ *  get to the next command.
  *
- * Arguments: None
+ * Arguments:
+ *  DCE2_SmbSsnData * - pointer to session data structure
+ *  SmbNtHdr *        - pointer to the SMB header structure
+ *  uint8_t *         - current pointer to data, i.e. the command
+ *  uint32_t          - the remaining length
  *
  * Returns: None
  *
  ********************************************************************/
-void DCE2_SmbInitGlobals()
+static void DCE2_SmbProcessCommand(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
+    const uint8_t* nb_ptr, uint32_t nb_len)
 {
-    memset(&smb_wcts, 0, sizeof(smb_wcts));
-    memset(&smb_bccs, 0, sizeof(smb_bccs));
+    uint8_t smb_com = SmbCom(smb_hdr);
+    DCE2_Ret status = DCE2_RET__ERROR;
+    bool sess_chain = false;
+    bool tree_chain = false;
+    bool open_chain = false;
+    int num_chained = 0;
 
-    // Sets up the function to call for the command and valid word and byte
-    // counts for the command.  Ensuring valid word and byte counts is very
-    // important to processing the command as it will assume the command is
-    // legitimate and can access data that is acutally there.  Note that
-    // commands with multiple word counts indicate a different command
-    // structure, however most, if not all just have an extended version
-    // of the structure for which the extended part isn't used.  If the
-    // extended part of a command structure needs to be used, be sure to
-    // check the word count in the command function before accessing data
-    // in the extended version of the command structure.
-    for (int com = 0; com < SMB_MAX_NUM_COMS; com++)
+    while (nb_len > 0)
     {
-        switch (com)
-        {
-        case SMB_COM_OPEN:
-            // FIXIT-M port DCE2_SmbOpen. Same for other smb_com_funcs
-            // smb_com_funcs[com] = DCE2_SmbOpen;
-            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
-
-            smb_deprecated_coms[com] = true;
-            smb_unusual_coms[com] = false;
-
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 2);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 7);
-
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX);
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
+        // Break out if command not supported
+        if (smb_com_funcs[smb_com] == nullptr)
             break;
-        case SMB_COM_CREATE:
-            //smb_com_funcs[com] = DCE2_SmbCreate;
-            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
 
-            smb_deprecated_coms[com] = true;
-            smb_unusual_coms[com] = false;
+        if (smb_deprecated_coms[smb_com])
+        {
+            dce_alert(GID_DCE2, DCE2_SMB_DEPR_COMMAND_USED, (dce2CommonStats*)&dce2_smb_stats);
+        }
 
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 3);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1);
+        if (smb_unusual_coms[smb_com])
+        {
+            dce_alert(GID_DCE2, DCE2_SMB_UNUSUAL_COMMAND_USED, (dce2CommonStats*)&dce2_smb_stats);
+        }
 
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX);
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
-            break;
-        case SMB_COM_CLOSE:
-            //smb_com_funcs[com] = DCE2_SmbClose;
-            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
-            smb_deprecated_coms[com] = false;
-            smb_unusual_coms[com] = false;
+        DCE2_SmbComInfo com_info;
+        com_info.smb_type = DCE2_SmbType(ssd);
+        com_info.cmd_error = DCE2_SMB_COM_ERROR__COMMAND_OK;
+        com_info.word_count = 0;
+        com_info.smb_com = smb_com;
+        com_info.cmd_size = 0;
+        com_info.byte_count = 0;
+        DCE2_SmbCheckCommand(ssd, smb_hdr, smb_com, nb_ptr, nb_len, com_info);
+        DebugFormat(DEBUG_DCE_SMB, "Processing command: %s (0x%02X)\n",
+            smb_com_strings[smb_com], smb_com);
 
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 3);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0);
+        // Note that even if the command shouldn't be processed, some of
+        // the command functions need to know and do cleanup or some other
+        // processing.
+        status = smb_com_funcs[smb_com](ssd, smb_hdr,
+                &com_info, nb_ptr, nb_len);
 
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0);
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
+        if (status != DCE2_RET__SUCCESS)
             break;
-        case SMB_COM_RENAME:
-            //smb_com_funcs[com] = DCE2_SmbRename;
-            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
-            smb_deprecated_coms[com] = false;
-            smb_unusual_coms[com] = false;
 
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 1);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0);
+        // This command is not chainable
+        SmbAndXCom andx_com = smb_chain_map[smb_com];
+        if (andx_com == SMB_ANDX_COM__NONE)
+            break;
 
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 4, UINT16_MAX);
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
+        /**********************************************************
+         * AndX Chaining
+         **********************************************************/
+        const SmbAndXCommon* andx_ptr = (SmbAndXCommon*)nb_ptr;
+        uint8_t smb_com2 = SmbAndXCom2(andx_ptr);
+        if (smb_com2 == SMB_COM_NO_ANDX_COMMAND)
             break;
-        case SMB_COM_READ:
-            //smb_com_funcs[com] = DCE2_SmbRead;
-            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
-            smb_deprecated_coms[com] = true;
-            smb_unusual_coms[com] = false;
 
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 5);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 5);
+        DebugFormat(DEBUG_DCE_SMB, "Chained SMB command: %s\n", smb_com_strings[smb_com2]);
 
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0);
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 3, UINT16_MAX);
-            break;
-        case SMB_COM_WRITE:
-            //smb_com_funcs[com] = DCE2_SmbWrite;
-            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
-            smb_deprecated_coms[com] = true;
-            smb_unusual_coms[com] = false;
+        num_chained++;
+        if (DCE2_ScSmbMaxChain((dce2SmbProtoConf*)ssd->sd.config) &&
+            (num_chained >= DCE2_ScSmbMaxChain((dce2SmbProtoConf*)ssd->sd.config)))
+        {
+            dce_alert(GID_DCE2, DCE2_SMB_EXCESSIVE_CHAINING, (dce2CommonStats*)&dce2_smb_stats);
+        }
 
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 5);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1);
+        // Multiple SessionSetupAndX, TreeConnectAndX, OpenAndX and NtCreateAndX
+        // are only allowed by Samba.
+        if (smb_com == SMB_COM_SESSION_SETUP_ANDX)
+            sess_chain = true;
 
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 3, UINT16_MAX);
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
+        // Check for multiple chained SessionSetupAndX
+        if ((smb_com2 == SMB_COM_SESSION_SETUP_ANDX) && sess_chain)
+        {
+            // There is only one place to return a uid.
+            dce_alert(GID_DCE2, DCE2_SMB_MULT_CHAIN_SS, (dce2CommonStats*)&dce2_smb_stats);
+            // FIXIT-L Should we continue processing?
             break;
-        case SMB_COM_CREATE_NEW:
-            // smb_com_funcs[com] = DCE2_SmbCreateNew;
-            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
-            smb_deprecated_coms[com] = true;
-            smb_unusual_coms[com] = false;
+        }
 
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 3);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1);
+        // Check for chained SessionSetupAndX => .? => LogoffAndX
+        if ((smb_com2 == SMB_COM_LOGOFF_ANDX) && sess_chain)
+        {
+            // This essentially deletes the uid created by the login
+            // and doesn't make any sense.
+            dce_alert(GID_DCE2, DCE2_SMB_CHAIN_SS_LOGOFF, (dce2CommonStats*)&dce2_smb_stats);
+        }
 
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX);
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
+        if (smb_com == SMB_COM_TREE_CONNECT_ANDX)
+            tree_chain = true;
+
+        // Check for multiple chained TreeConnects
+        if (((smb_com2 == SMB_COM_TREE_CONNECT_ANDX)
+            || (smb_com2 == SMB_COM_TREE_CONNECT)) && tree_chain)
+        {
+            // There is only one place to return a tid.
+            dce_alert(GID_DCE2, DCE2_SMB_MULT_CHAIN_TC, (dce2CommonStats*)&dce2_smb_stats);
+            // FIXIT-L Should we continue processing?
             break;
-        case SMB_COM_LOCK_AND_READ:
-            //smb_com_funcs[com] = DCE2_SmbLockAndRead;
-            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
-            smb_deprecated_coms[com] = true;
-            smb_unusual_coms[com] = false;
+        }
 
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 5);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 5);
+        // Check for chained TreeConnectAndX => .? => TreeDisconnect
+        if ((smb_com2 == SMB_COM_TREE_DISCONNECT) && tree_chain)
+        {
+            // This essentially deletes the tid created by the tree connect
+            // and doesn't make any sense.
+            dce_alert(GID_DCE2, DCE2_SMB_CHAIN_TC_TDIS, (dce2CommonStats*)&dce2_smb_stats);
+        }
 
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0);
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 3, UINT16_MAX);
-            break;
-        case SMB_COM_WRITE_AND_UNLOCK:
-            //smb_com_funcs[com] = DCE2_SmbWriteAndUnlock;
-            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
-            smb_deprecated_coms[com] = true;
-            smb_unusual_coms[com] = false;
+        if ((smb_com == SMB_COM_OPEN_ANDX) || (smb_com == SMB_COM_NT_CREATE_ANDX))
+            open_chain = true;
 
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 5);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1);
+        // Check for chained OpenAndX/NtCreateAndX => .? => Close
+        if ((smb_com2 == SMB_COM_CLOSE) && open_chain)
+        {
+            // This essentially deletes the fid created by the open command
+            // and doesn't make any sense.
+            dce_alert(GID_DCE2, DCE2_SMB_CHAIN_OPEN_CLOSE, (dce2CommonStats*)&dce2_smb_stats);
+        }
 
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 3, UINT16_MAX);
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
+        // Check that policy allows for such chaining
+        DCE2_Policy policy = DCE2_SsnGetServerPolicy(&ssd->sd);
+        if (smb_chain_funcs[policy][andx_com][smb_com2] == nullptr)
             break;
-        case SMB_COM_READ_RAW:
-            //smb_com_funcs[com] = DCE2_SmbReadRaw;
-            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
-            smb_deprecated_coms[com] = true;
-            smb_unusual_coms[com] = false;
 
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 8);
-            // With optional OffsetHigh
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 10);
+        DCE2_MOVE(nb_ptr, nb_len, DCE2_ComInfoCommandSize(&com_info));
 
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0);
-            // Response is raw data, i.e. without SMB
+        // FIXIT-L Need to test out of order chaining
+        const uint8_t* off2_ptr = (uint8_t*)smb_hdr + SmbAndXOff2(andx_ptr);
+        if (DCE2_SmbCheckAndXOffset(off2_ptr, nb_ptr, nb_len) != DCE2_RET__SUCCESS)
             break;
-        case SMB_COM_WRITE_RAW:
-            //smb_com_funcs[com] = DCE2_SmbWriteRaw;
-            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
-            smb_deprecated_coms[com] = true;
-            smb_unusual_coms[com] = false;
 
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 12);
-            // With optional OffsetHigh
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 14);
-            // Interim server response
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1);
+        DCE2_MOVE(nb_ptr, nb_len, (off2_ptr - nb_ptr));
 
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX);
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
+        // FIXIT Need to test more.
+        switch (smb_com)
+        {
+        case SMB_COM_SESSION_SETUP_ANDX:
+        case SMB_COM_TREE_CONNECT_ANDX:
+        case SMB_COM_OPEN_ANDX:
+        case SMB_COM_NT_CREATE_ANDX:
+            switch (smb_com2)
+            {
+            case SMB_COM_WRITE:
+            case SMB_COM_WRITE_ANDX:
+            case SMB_COM_TRANSACTION:
+            case SMB_COM_READ_ANDX:
+                if (DCE2_SsnFromClient(ssd->sd.wire_pkt) && open_chain)
+                {
+                    DCE2_SmbQueueTmpFileTracker(ssd, ssd->cur_rtracker,
+                        SmbUid(smb_hdr), SmbTid(smb_hdr));
+                }
+                break;
+            default:
+                break;
+            }
             break;
-        case SMB_COM_WRITE_COMPLETE:
-            // Final server response to SMB_COM_WRITE_RAW
-            //smb_com_funcs[com] = DCE2_SmbWriteComplete;
-            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
-            smb_deprecated_coms[com] = true;
-            smb_unusual_coms[com] = false;
+        default:
+            break;
+        }
 
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1);
+        smb_com = smb_com2;
+    }
 
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
-            break;
+    int smb_type = DCE2_SmbType(ssd);
+    if (smb_type == SMB_TYPE__RESPONSE)
+    {
+        switch (smb_com)
+        {
         case SMB_COM_TRANSACTION:
-            // smb_com_funcs[com] = DCE2_SmbTransaction;
-            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
-            smb_deprecated_coms[com] = false;
-            smb_unusual_coms[com] = false;
+        case SMB_COM_TRANSACTION2:
+        case SMB_COM_NT_TRANSACT:
+        case SMB_COM_TRANSACTION_SECONDARY:
+        case SMB_COM_TRANSACTION2_SECONDARY:
+        case SMB_COM_NT_TRANSACT_SECONDARY:
+            // This case means there was an error with the initial response
+            // so the tracker isn't yet officially in response mode
+            if (ssd->cur_rtracker->ttracker.smb_type == SMB_TYPE__REQUEST)
+            {
+                // Samba throws out entire transaction and Windows just this request
+                if (DCE2_SsnIsServerSambaPolicy(&ssd->sd) && (status != DCE2_RET__SUCCESS))
+                    break;
 
-            // Word count depends on setup count
-            //for (i = 14; i < 256; i++)
-            //    DCE2_SmbSetValidWordCount(com, SMB_TYPE__REQUEST, i);
-            // In reality, all subcommands of SMB_COM_TRANSACTION requests
-            // have a setup count of 2 words.
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 16);
-
-            // \PIPE\LANMAN
-            // Not something the preprocessor is looking at as it
-            // doesn't carry DCE/RPC but don't want to false positive
-            // on the preprocessor event.
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 14);
-
-            // Word count depends on setup count
-            //for (i = 10; i < 256; i++)
-            //    DCE2_SmbSetValidWordCount(com, SMB_TYPE__RESPONSE, i);
-            // In reality, all subcommands of SMB_COM_TRANSACTION responses
-            // have a setup count of 0 words.
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 10);
-
-            // Interim server response
-            // When client sends an incomplete transaction and needs to
-            // send TransactionSecondary requests to complete request.
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0);
-
-            // Exception will be made for Interim responses when
-            // byte count is checked.
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX);
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX);
-            break;
-        case SMB_COM_TRANSACTION_SECONDARY:
-            //smb_com_funcs[com] = DCE2_SmbTransactionSecondary;
-            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
-            smb_deprecated_coms[com] = false;
-            smb_unusual_coms[com] = false;
-
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 8);
-            // Response is an SMB_COM_TRANSACTION
-
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX);
-            break;
-        case SMB_COM_WRITE_AND_CLOSE:
-            // smb_com_funcs[com] = DCE2_SmbWriteAndClose;
-            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
-            smb_deprecated_coms[com] = true;
-            smb_unusual_coms[com] = false;
-
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 6);
-            // For some reason MS-CIFS specifies a version of this command
-            // with 6 extra words (12 bytes) of reserved, i.e. useless data.
-            // Maybe had intentions of extending and defining the data at
-            // some point, but there is no documentation that I could find
-            // that does.
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 12);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1);
-
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 1, UINT16_MAX);
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
-            break;
-        case SMB_COM_OPEN_ANDX:
-            //smb_com_funcs[com] = DCE2_SmbOpenAndX;
-            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
-            smb_deprecated_coms[com] = true;
-            smb_unusual_coms[com] = false;
-
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 15);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 15);
-            // Extended response
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 19);
-
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX);
-            // MS-SMB says that Windows 2000, XP and Vista set this to
-            // some arbitrary value that is ignored on receipt.
-            //DCE2_SmbSetValidByteCount(com, SMB_TYPE__RESPONSE, 0, 0);
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX);
-            break;
-        case SMB_COM_READ_ANDX:
-            // smb_com_funcs[com] = DCE2_SmbReadAndX;
-            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
-            smb_deprecated_coms[com] = false;
-            smb_unusual_coms[com] = false;
-
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 10);
-            // With optional OffsetHigh
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 12);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 12);
-
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0);
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX);
+                if (!DCE2_SmbIsTransactionComplete(&ssd->cur_rtracker->ttracker))
+                    return;
+            }
+            else
+            {
+                if ((status == DCE2_RET__SUCCESS)
+                    && !DCE2_SmbIsTransactionComplete(&ssd->cur_rtracker->ttracker))
+                    return;
+            }
             break;
-        case SMB_COM_WRITE_ANDX:
-            // smb_com_funcs[com] = DCE2_SmbWriteAndX;
-            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
-            smb_deprecated_coms[com] = false;
-            smb_unusual_coms[com] = false;
-
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 12);
-            // With optional OffsetHigh
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 14);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 6);
-
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 1, UINT16_MAX);
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
+        case SMB_COM_WRITE_RAW:
+            if ((status == DCE2_RET__SUCCESS)
+                && (ssd->cur_rtracker->writeraw_remaining != 0))
+                return;
             break;
-        case SMB_COM_TRANSACTION2:
-            //smb_com_funcs[com] = DCE2_SmbTransaction2;
-            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
-            smb_deprecated_coms[com] = false;
-            smb_unusual_coms[com] = false;
-
-            // Word count depends on setup count
-            //for (i = 14; i < 256; i++)
-            //    DCE2_SmbSetValidWordCount(com, SMB_TYPE__REQUEST, i);
-            // In reality, all subcommands of SMB_COM_TRANSACTION2
-            // requests have a setup count of 1 word.
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 15);
-
-            // Word count depends on setup count
-            //for (i = 10; i < 256; i++)
-            //    DCE2_SmbSetValidWordCount(com, SMB_TYPE__RESPONSE, i);
-            // In reality, all subcommands of SMB_COM_TRANSACTION2
-            // responses have a setup count of 0 or 1 word.
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 10);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 11);
-
-            // Interim server response
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0);
-
-            // Exception will be made for Interim responses when
-            // byte count is checked.
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX);
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX);
+        default:
             break;
-        case SMB_COM_TRANSACTION2_SECONDARY:
-            //smb_com_funcs[com] = DCE2_SmbTransaction2Secondary;
-            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
-            smb_deprecated_coms[com] = false;
-            smb_unusual_coms[com] = false;
+        }
+    }
+    else if (status != DCE2_RET__IGNORE)
+    {
+        switch (smb_com)
+        {
+        case SMB_COM_TRANSACTION:
+        case SMB_COM_TRANSACTION_SECONDARY:
+            if (DCE2_SsnIsWindowsPolicy(&ssd->sd))
+            {
+                if (!ssd->cur_rtracker->ttracker.one_way
+                    || !DCE2_SmbIsTransactionComplete(&ssd->cur_rtracker->ttracker))
+                    return;
 
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 9);
-            // Response is an SMB_COM_TRANSACTION2
+                // Remove the request tracker if transaction is one-way and
+                // all data and parameters have been sent
+                break;
+            }
+        default:
+            // Anything else, keep the request tracker
+            return;
+        }
+    }
 
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX);
-            break;
-        case SMB_COM_TREE_CONNECT:
-            //smb_com_funcs[com] = DCE2_SmbTreeConnect;
-            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
-            smb_deprecated_coms[com] = true;
-            smb_unusual_coms[com] = false;
+    DCE2_SmbRemoveRequestTracker(ssd, ssd->cur_rtracker);
+    ssd->cur_rtracker = nullptr;
+}
 
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 0);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 2);
+/********************************************************************
+ * Function: DCE2_SmbInspect()
+ *
+ * Purpose:
+ *  Determines whether the SMB command is something the preprocessor
+ *  needs to inspect.
+ *  This function returns a DCE2_SmbRequestTracker which tracks command
+ *  requests / responses.
+ *
+ * Arguments:
+ *  DCE2_SmbSsnData * - the session data structure.
+ *  const SmbNtHdr *  - pointer to the SMB header.
+ *
+ * Returns:
+ *  DCE2_SmbRequestTracker * - nullptr if it's not something we want to or can
+ *                     inspect.
+ *                     Otherwise an initialized structure if request
+ *                     and the found structure if response.
+ *
+ ********************************************************************/
+static DCE2_SmbRequestTracker* DCE2_SmbInspect(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr)
+{
+    int smb_com = SmbCom(smb_hdr);
 
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 6, UINT16_MAX);
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
-            break;
-        case SMB_COM_TREE_DISCONNECT:
-            //smb_com_funcs[com] = DCE2_SmbTreeDisconnect;
-            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
-            smb_deprecated_coms[com] = false;
-            smb_unusual_coms[com] = false;
+    DebugFormat(DEBUG_DCE_SMB, "SMB command: %s (0x%02X)\n",
+        smb_com_strings[smb_com], smb_com);
 
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 0);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0);
+    if (smb_com_funcs[smb_com] == nullptr)
+    {
+        DebugMessage(DEBUG_DCE_SMB, "Command isn't processed "
+            "by preprocessor.\n");
+        return nullptr;
+    }
 
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0);
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
-            break;
+    // See if this is something we need to inspect
+    DCE2_Policy policy = DCE2_SsnGetServerPolicy(&ssd->sd);
+    DCE2_SmbRequestTracker* rtracker = nullptr;
+    if (DCE2_SmbType(ssd) == SMB_TYPE__REQUEST)
+    {
+        switch (smb_com)
+        {
         case SMB_COM_NEGOTIATE:
-            // Not doing anything with this command right now.
-            // smb_com_funcs[com] = DCE2_SmbNegotiate;
-            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
-            smb_deprecated_coms[com] = false;
-            smb_unusual_coms[com] = false;
-
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 0);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 13);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 17);
-
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX);
-            // This can vary depending on dialect so just set wide.
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX);
+            if (ssd->ssn_state_flags & DCE2_SMB_SSN_STATE__NEGOTIATED)
+            {
+                dce_alert(GID_DCE2, DCE2_SMB_MULTIPLE_NEGOTIATIONS,
+                    (dce2CommonStats*)&dce2_smb_stats);
+                return nullptr;
+            }
             break;
         case SMB_COM_SESSION_SETUP_ANDX:
-            //smb_com_funcs[com] = DCE2_SmbSessionSetupAndX;
-            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
-            smb_deprecated_coms[com] = false;
-            smb_unusual_coms[com] = false;
-
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 10);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 12);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 13);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 3);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 4);
-
-            // These can vary so just set wide.
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX);
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX);
             break;
+        case SMB_COM_TREE_CONNECT:
+        case SMB_COM_TREE_CONNECT_ANDX:
+        case SMB_COM_RENAME:
         case SMB_COM_LOGOFF_ANDX:
-            //smb_com_funcs[com] = DCE2_SmbLogoffAndX;
-            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
-            smb_deprecated_coms[com] = false;
-            smb_unusual_coms[com] = false;
-
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 2);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 2);
-            // Windows responds to a LogoffAndX => SessionSetupAndX with just a
-            // LogoffAndX and with the word count field containing 3, but only
-            // has 2 words
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 3);
-
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0);
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
+            if (DCE2_SmbFindUid(ssd, SmbUid(smb_hdr)) != DCE2_RET__SUCCESS)
+                return nullptr;
             break;
-        case SMB_COM_TREE_CONNECT_ANDX:
-            //smb_com_funcs[com] = DCE2_SmbTreeConnectAndX;
-            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
-            smb_deprecated_coms[com] = false;
-            smb_unusual_coms[com] = false;
+        default:
+            if (DCE2_SmbFindTid(ssd, SmbTid(smb_hdr)) != DCE2_RET__SUCCESS)
+            {
+                DebugFormat(DEBUG_DCE_SMB,
+                    "Couldn't find Tid (%u)\n", SmbTid(smb_hdr));
+                return nullptr;
+            }
 
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 4);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 2);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 3);
-            // Extended response
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 7);
+            if (DCE2_SmbIsTidIPC(ssd, SmbTid(smb_hdr)))
+            {
+                switch (smb_com)
+                {
+                case SMB_COM_OPEN:
+                case SMB_COM_CREATE:
+                case SMB_COM_CREATE_NEW:
+                case SMB_COM_WRITE_AND_CLOSE:
+                case SMB_COM_WRITE_AND_UNLOCK:
+                case SMB_COM_READ:
+                    // Samba doesn't allow these commands under an IPC tree
+                    switch (policy)
+                    {
+                    case DCE2_POLICY__SAMBA:
+                    case DCE2_POLICY__SAMBA_3_0_37:
+                    case DCE2_POLICY__SAMBA_3_0_22:
+                    case DCE2_POLICY__SAMBA_3_0_20:
+                        DebugMessage(DEBUG_DCE_SMB, "Samba doesn't "
+                            "process this command under an IPC tree.\n");
+                        return nullptr;
+                    default:
+                        break;
+                    }
+                    break;
+                case SMB_COM_READ_RAW:
+                case SMB_COM_WRITE_RAW:
+                    // Samba and Windows Vista on don't allow these commands
+                    // under an IPC tree, whether or not the raw read/write
+                    // flag is set in the Negotiate capabilities.
+                    // Windows RSTs the connection and Samba FINs it.
+                    switch (policy)
+                    {
+                    case DCE2_POLICY__WINVISTA:
+                    case DCE2_POLICY__WIN2008:
+                    case DCE2_POLICY__WIN7:
+                    case DCE2_POLICY__SAMBA:
+                    case DCE2_POLICY__SAMBA_3_0_37:
+                    case DCE2_POLICY__SAMBA_3_0_22:
+                    case DCE2_POLICY__SAMBA_3_0_20:
+                        DebugMessage(DEBUG_DCE_SMB, "Samba and "
+                            "Windows Vista on don't process this "
+                            "command under an IPC tree.\n");
+                        return nullptr;
+                    default:
+                        break;
+                    }
+                    break;
+                case SMB_COM_LOCK_AND_READ:
+                    // The lock will fail so the read won't happen
+                    return nullptr;
+                default:
+                    break;
+                }
+            }
+            else      // Not IPC
+            {
+                switch (smb_com)
+                {
+                // These commands are only used for IPC
+                case SMB_COM_TRANSACTION:
+                case SMB_COM_TRANSACTION_SECONDARY:
+                    DebugMessage(DEBUG_DCE_SMB, "secondary transaction not IPC.\n");
+                    return nullptr;
+                case SMB_COM_READ_RAW:
+                case SMB_COM_WRITE_RAW:
+                    // Windows Vista on don't seem to support these
+                    // commands, whether or not the raw read/write
+                    // flag is set in the Negotiate capabilities.
+                    // Windows RSTs the connection.
+                    switch (policy)
+                    {
+                    case DCE2_POLICY__WINVISTA:
+                    case DCE2_POLICY__WIN2008:
+                    case DCE2_POLICY__WIN7:
+                        DebugMessage(DEBUG_DCE_SMB,
+                            "Windows Vista on don't process "
+                            "this command.\n");
+                        return nullptr;
+                    default:
+                        break;
+                    }
+                    break;
+                default:
+                    break;
+                }
+            }
+            break;
+        }
 
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 3, UINT16_MAX);
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 2, UINT16_MAX);
+        switch (smb_com)
+        {
+        case SMB_COM_TRANSACTION_SECONDARY:
+        case SMB_COM_TRANSACTION2_SECONDARY:
+        case SMB_COM_NT_TRANSACT_SECONDARY:
+            rtracker = DCE2_SmbFindRequestTracker(ssd, smb_hdr);
             break;
+        case SMB_COM_TRANSACTION:
+        case SMB_COM_TRANSACTION2:
         case SMB_COM_NT_TRANSACT:
-            //smb_com_funcs[com] = DCE2_SmbNtTransact;
-            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
-            smb_deprecated_coms[com] = false;
-            smb_unusual_coms[com] = false;
+            // If there is already and existing request tracker
+            // and the transaction is not complete, server will
+            // return an error.
+            rtracker = DCE2_SmbFindRequestTracker(ssd, smb_hdr);
+            if (rtracker != nullptr)
+                break;
+        // Fall through
+        default:
+            rtracker = DCE2_SmbNewRequestTracker(ssd, smb_hdr);
+            break;
+        }
+    }
+    else
+    {
+        rtracker = DCE2_SmbFindRequestTracker(ssd, smb_hdr);
+    }
 
-            // Word count depends on setup count
-            // In reality, all subcommands of SMB_COM_NT_TRANSACT
-            // requests have a setup count of 0 or 4 words.
-            //for (i = 19; i < 256; i++)
-            //    DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, i);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 19);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 23);
+    return rtracker;
+}
 
-            // Word count depends on setup count
-            // In reality, all subcommands of SMB_COM_NT_TRANSACT
-            // responses have a setup count of 0 or 1 word.
-            //for (i = 18; i < 256; i++)
-            //    DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, i);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 18);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 19);
+/********************************************************************
+ * Function: DCE2_SmbCheckData()
+ *
+ * Purpose:
+ *  Ensures that the data size reported in an SMB command is kosher.
+ *
+ * Arguments:
+ *  DCE2_SmbSsnData * - SMB session data structure
+ *  const uint8_t *   - pointer to start of SMB header where offset is
+ *                      taken from.
+ *  const uint8_t *   - current pointer - should be right after command
+ *                      structure.
+ *  const uint32_t    - remaining data left in PDU from current pointer.
+ *  const uint16_t    - the byte count from the SMB command
+ *  const uint16_t    - reported data count in SMB command
+ *  const uint16_t    - reported data offset in SMB command
+ *
+ * Returns:
+ *  DCE2_Ret -  DCE2_RET__ERROR if data should not be processed
+ *              DCE2_RET__SUCCESS if data can be processed
+ *
+ ********************************************************************/
+static DCE2_Ret DCE2_SmbCheckData(DCE2_SmbSsnData*,
+    const uint8_t* smb_hdr_ptr, const uint8_t* nb_ptr,
+    const uint32_t nb_len, const uint16_t bcc,
+    const uint32_t dcnt, uint16_t doff)
+{
+    const uint8_t* offset = smb_hdr_ptr + doff;
+    const uint8_t* nb_end = nb_ptr + nb_len;
 
-            // Interim server response
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0);
+    // Byte counts don't usually matter, so no error but still alert
+    // Don't alert in the case where the data count is larger than what the
+    // byte count can handle.  This can happen if CAP_LARGE_READX or
+    // CAP_LARGE_WRITEX were negotiated.
+    if ((dcnt <= UINT16_MAX) && (bcc < dcnt))
+        dce_alert(GID_DCE2, DCE2_SMB_BCC_LT_DSIZE, (dce2CommonStats*)&dce2_smb_stats);
 
-            // Exception will be made for Interim responses when
-            // byte count is checked.
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX);
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX);
-            break;
-        case SMB_COM_NT_TRANSACT_SECONDARY:
-            //smb_com_funcs[com] = DCE2_SmbNtTransactSecondary;
-            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
-            smb_deprecated_coms[com] = false;
-            smb_unusual_coms[com] = false;
+    if (offset > nb_end)
+    {
+        dce_alert(GID_DCE2, DCE2_SMB_BAD_OFF, (dce2CommonStats*)&dce2_smb_stats);
+        // Error if offset is beyond data left
+        return DCE2_RET__ERROR;
+    }
 
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 18);
-            // Response is an SMB_COM_NT_TRANSACT
+    // Only check if the data count is non-zero
+    if ((dcnt != 0) && (offset < nb_ptr))
+    {
+        // Not necessarily and error if the offset puts the data
+        // before or in the command structure.
+        dce_alert(GID_DCE2, DCE2_SMB_BAD_OFF, (dce2CommonStats*)&dce2_smb_stats);
+    }
 
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX);
+    // Not necessarily an error if the addition of the data count goes
+    // beyond the data left
+    if (((offset + dcnt) > nb_end)           // beyond data left
+        || ((offset + dcnt) < offset))       // wrap
+    {
+        dce_alert(GID_DCE2, DCE2_SMB_NB_LT_DSIZE, (dce2CommonStats*)&dce2_smb_stats);
+    }
+
+    return DCE2_RET__SUCCESS;
+}
+
+// Temporary command function placeholder, until all of them are ported
+DCE2_Ret DCE2_SmbComFuncPlaceholder(DCE2_SmbSsnData*, const SmbNtHdr*,
+    const DCE2_SmbComInfo*, const uint8_t*, uint32_t)
+{
+    return DCE2_RET__SUCCESS;
+}
+
+static bool DCE2_SmbAutodetect(Packet* p)
+{
+    if (p->dsize > (sizeof(NbssHdr) + sizeof(SmbNtHdr)))
+    {
+        NbssHdr* nb_hdr = (NbssHdr*)p->data;
+        SmbNtHdr* smb_hdr = (SmbNtHdr*)(p->data + sizeof(NbssHdr));
+
+        if ((SmbId(smb_hdr) != DCE2_SMB_ID)
+            && (SmbId(smb_hdr) != DCE2_SMB2_ID))
+        {
+            return false;
+        }
+
+        switch (NbssType(nb_hdr))
+        {
+        // FIXIT-L currently all ports are treated as autodetect.
+        // On port 139, there is always an initial Session Request / Session Positive/Negative
+        // response.
+        // These message types were added , to make sure port 139 is treated as smb.
+        // Remove once detect/autodetect supported.
+        case NBSS_SESSION_TYPE__REQUEST:
+            if (DCE2_SsnFromClient(p))
+                return true;
             break;
-        case SMB_COM_NT_CREATE_ANDX:
-            //smb_com_funcs[com] = DCE2_SmbNtCreateAndX;
-            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
-            smb_deprecated_coms[com] = false;
-            smb_unusual_coms[com] = false;
 
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 24);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 34);
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 26);
-            // Extended response - though there are actually 50 words
-            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 42);
+        case NBSS_SESSION_TYPE__POS_RESPONSE:
+        case NBSS_SESSION_TYPE__NEG_RESPONSE:
+            if (DCE2_SsnFromServer(p))
+                return true;
+            break;
 
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX);
-            // MS-SMB indicates that this field should be 0 but may be
-            // sent uninitialized so basically ignore it.
-            //DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX);
+        case NBSS_SESSION_TYPE__MESSAGE:
+            return true;
             break;
         default:
-            smb_com_funcs[com] = nullptr;
-            smb_deprecated_coms[com] = false;
-            smb_unusual_coms[com] = false;
-            // Just set to all valid since the specific command won't
-            // be processed.  Don't want to false positive on these.
-            for (int i = 0; i < 256; i++)
-            {
-                DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, (uint8_t)i);
-                DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, (uint8_t)i);
-            }
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX);
-            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX);
             break;
         }
     }
 
-    // Maps commands for use in quickly determining if a command
-    // is chainable and what command it is.
-    for (int com = 0; com < SMB_MAX_NUM_COMS; com++)
-    {
-        switch (com)
-        {
-        case SMB_COM_SESSION_SETUP_ANDX:
-            smb_chain_map[com] = SMB_ANDX_COM__SESSION_SETUP_ANDX;
-            break;
-        case SMB_COM_LOGOFF_ANDX:
-            smb_chain_map[com] = SMB_ANDX_COM__LOGOFF_ANDX;
-            break;
-        case SMB_COM_TREE_CONNECT_ANDX:
-            smb_chain_map[com] = SMB_ANDX_COM__TREE_CONNECT_ANDX;
-            break;
-        case SMB_COM_OPEN_ANDX:
-            smb_chain_map[com] = SMB_ANDX_COM__OPEN_ANDX;
-            break;
-        case SMB_COM_NT_CREATE_ANDX:
-            smb_chain_map[com] = SMB_ANDX_COM__NT_CREATE_ANDX;
-            break;
-        case SMB_COM_WRITE_ANDX:
-            smb_chain_map[com] = SMB_ANDX_COM__WRITE_ANDX;
-            break;
-        case SMB_COM_READ_ANDX:
-            smb_chain_map[com] = SMB_ANDX_COM__READ_ANDX;
-            break;
-        default:
-            smb_chain_map[com] = SMB_ANDX_COM__NONE;
-            break;
+    return false;
+}
+
+void DCE2_SmbDataFree(DCE2_SmbSsnData* ssd)
+{
+    if (ssd == nullptr)
+        return;
+
+    // FIXIT This tries to account for the situation where we never knew the file
+    // size and the TCP session was shutdown before an SMB_COM_CLOSE on the file.
+    // Possibly need to add callback to fileAPI since it may have already
+    // released it's resources.
+    //DCE2_SmbFinishFileAPI(ssd);
+
+    if (ssd->uids != nullptr)
+    {
+        DCE2_ListDestroy(ssd->uids);
+        ssd->uids = nullptr;
+    }
+
+    if (ssd->tids != nullptr)
+    {
+        DCE2_ListDestroy(ssd->tids);
+        ssd->tids = nullptr;
+    }
+
+    DCE2_SmbCleanFileTracker(&ssd->ftracker);
+    if (ssd->ftrackers != nullptr)
+    {
+        DCE2_ListDestroy(ssd->ftrackers);
+        ssd->ftrackers = nullptr;
+    }
+
+    DCE2_SmbCleanRequestTracker(&ssd->rtracker);
+    if (ssd->rtrackers != nullptr)
+    {
+        DCE2_QueueDestroy(ssd->rtrackers);
+        ssd->rtrackers = nullptr;
+    }
+
+    if (ssd->cli_seg != nullptr)
+    {
+        DCE2_BufferDestroy(ssd->cli_seg);
+        ssd->cli_seg = nullptr;
+    }
+
+    if (ssd->srv_seg != nullptr)
+    {
+        DCE2_BufferDestroy(ssd->srv_seg);
+        ssd->srv_seg = nullptr;
+    }
+}
+
+Dce2SmbFlowData::Dce2SmbFlowData() : FlowData(flow_id)
+{
+}
+
+Dce2SmbFlowData::~Dce2SmbFlowData()
+{
+    DCE2_SmbDataFree(&dce2_smb_session);
+}
+
+unsigned Dce2SmbFlowData::flow_id = 0;
+
+DCE2_SmbSsnData* get_dce2_smb_session_data(Flow* flow)
+{
+    Dce2SmbFlowData* fd = (Dce2SmbFlowData*)flow->get_application_data(
+        Dce2SmbFlowData::flow_id);
+
+    return fd ? &fd->dce2_smb_session : nullptr;
+}
+
+static DCE2_SmbSsnData* set_new_dce2_smb_session(Packet* p)
+{
+    Dce2SmbFlowData* fd = new Dce2SmbFlowData;
+
+    memset(&fd->dce2_smb_session,0,sizeof(DCE2_SmbSsnData));
+    p->flow->set_application_data(fd);
+    return(&fd->dce2_smb_session);
+}
+
+static DCE2_SmbSsnData* dce2_create_new_smb_session(Packet* p, dce2SmbProtoConf* config)
+{
+    DCE2_SmbSsnData* dce2_smb_sess = nullptr;
+    Profile profile(dce2_smb_pstat_new_session);
+
+    //FIXIT-M Re-evaluate after infrastructure/binder support if autodetect here
+    //is necessary
+
+    if (DCE2_SmbAutodetect(p))
+    {
+        DebugMessage(DEBUG_DCE_SMB, "DCE over SMB packet detected\n");
+        DebugMessage(DEBUG_DCE_SMB, "Creating new session\n");
+
+        dce2_smb_sess = set_new_dce2_smb_session(p);
+        if ( dce2_smb_sess )
+        {
+            dce2_smb_sess->dialect_index = DCE2_SENTINEL;
+            dce2_smb_sess->max_outstanding_requests = 10;  // Until Negotiate/SessionSetupAndX
+            dce2_smb_sess->cli_data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
+            dce2_smb_sess->srv_data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
+            dce2_smb_sess->pdu_state = DCE2_SMB_PDU_STATE__COMMAND;
+            dce2_smb_sess->uid = DCE2_SENTINEL;
+            dce2_smb_sess->tid = DCE2_SENTINEL;
+            dce2_smb_sess->ftracker.fid = DCE2_SENTINEL;
+            dce2_smb_sess->rtracker.mid = DCE2_SENTINEL;
+            dce2_smb_sess->max_file_depth = FileService::get_max_file_depth();
+
+            DCE2_ResetRopts(&dce2_smb_sess->sd.ropts);
+
+            dce2_smb_stats.smb_sessions++;
+            DebugFormat(DEBUG_DCE_SMB,"Created (%p)\n", (void*)dce2_smb_sess);
+
+            dce2_smb_sess->sd.trans = DCE2_TRANS_TYPE__SMB;
+            dce2_smb_sess->sd.server_policy = config->common.policy;
+            dce2_smb_sess->sd.client_policy = DCE2_POLICY__WINXP;
+            dce2_smb_sess->sd.wire_pkt = p;
+            dce2_smb_sess->sd.config = (void*)config;
+
+            DCE2_SsnSetAutodetected(&dce2_smb_sess->sd, p);
         }
     }
 
-    // Sets up the valid command chaining combinations per policy
-    for (int policy = 0; policy < DCE2_POLICY__MAX; policy++)
+    return dce2_smb_sess;
+}
+
+static DCE2_SmbSsnData* dce2_handle_smb_session(Packet* p, dce2SmbProtoConf* config)
+{
+    Profile profile(dce2_smb_pstat_session);
+
+    DCE2_SmbSsnData* dce2_smb_sess =  get_dce2_smb_session_data(p->flow);
+
+    if (dce2_smb_sess == nullptr)
     {
-        for (int andx = SMB_ANDX_COM__NONE; andx < SMB_ANDX_COM__MAX; andx++)
+        dce2_smb_sess = dce2_create_new_smb_session(p, config);
+    }
+    else
+    {
+        DCE2_SsnData* sd = (DCE2_SsnData*)dce2_smb_sess;
+        sd->wire_pkt = p;
+
+        if (DCE2_SsnAutodetected(sd) && !(p->packet_flags & sd->autodetect_dir))
         {
-            /* com is the chained command or com2 */
-            for (int com = 0; com < SMB_MAX_NUM_COMS; com++)
+            /* Try to autodetect in opposite direction */
+            if (!DCE2_SmbAutodetect(p))
             {
-                DCE2_SmbComFunc com_func = nullptr;
+                DebugMessage(DEBUG_DCE_SMB, "Bad autodetect.\n");
+                DCE2_SsnNoInspect(sd);
+                dce2_smb_stats.sessions_aborted++;
+                dce2_smb_stats.bad_autodetects++;
+                return nullptr;
+            }
+            DCE2_SsnClearAutodetected(sd);
+        }
+    }
+    DebugFormat(DEBUG_DCE_SMB, "Session pointer: %p\n", (void*)dce2_smb_sess);
 
-                switch (policy)
-                {
-                case DCE2_POLICY__WIN2000:
-                case DCE2_POLICY__WINXP:
-                case DCE2_POLICY__WINVISTA:
-                case DCE2_POLICY__WIN2003:
-                case DCE2_POLICY__WIN2008:
-                case DCE2_POLICY__WIN7:
-                    switch (andx)
-                    {
-                    case SMB_ANDX_COM__SESSION_SETUP_ANDX:
-                        switch (com)
-                        {
-                        case SMB_COM_TREE_CONNECT_ANDX:
-                        case SMB_COM_OPEN:
-                        case SMB_COM_OPEN_ANDX:
-                        case SMB_COM_CREATE:
-                        case SMB_COM_CREATE_NEW:
-                            com_func = smb_com_funcs[com];
-                            break;
-                        case SMB_COM_TRANSACTION:
-                            if (policy == DCE2_POLICY__WIN2000)
-                                com_func = smb_com_funcs[com];
-                            break;
-                        default:
-                            break;
-                        }
-                        break;
-                    case SMB_ANDX_COM__LOGOFF_ANDX:
-                        switch (com)
-                        {
-                        case SMB_COM_SESSION_SETUP_ANDX:
-                        case SMB_COM_TREE_CONNECT_ANDX:               // Only for responses
-                            com_func = smb_com_funcs[com];
-                            break;
-                        default:
-                            break;
-                        }
-                        break;
-                    case SMB_ANDX_COM__TREE_CONNECT_ANDX:
-                        switch (com)
-                        {
-                        case SMB_COM_OPEN:
-                        case SMB_COM_CREATE:
-                        case SMB_COM_CREATE_NEW:
-                            com_func = smb_com_funcs[com];
-                            break;
-                        case SMB_COM_TRANSACTION:
-                            if (policy == DCE2_POLICY__WIN2000)
-                                com_func = smb_com_funcs[com];
-                            break;
-                        default:
-                            break;
-                        }
-                        break;
-                    case SMB_ANDX_COM__OPEN_ANDX:
-                        break;
-                    case SMB_ANDX_COM__NT_CREATE_ANDX:
-                        switch (com)
-                        {
-                        case SMB_COM_READ_ANDX:              // Only for normal files
-                            com_func = smb_com_funcs[com];
-                            break;
-                        default:
-                            break;
-                        }
-                        break;
-                    case SMB_ANDX_COM__WRITE_ANDX:
-                        switch (com)
-                        {
-                        case SMB_COM_CLOSE:
-                        case SMB_COM_WRITE_ANDX:
-                        case SMB_COM_READ:
-                        case SMB_COM_READ_ANDX:
-                            com_func = smb_com_funcs[com];
-                            break;
-                        default:
+    // FIXIT-M add remaining session handling logic
+
+    return dce2_smb_sess;
+}
+
+/********************************************************************
+ * Function: DCE2_NbssHdrChecks()
+ *
+ * Purpose:
+ *  Does validation of the NetBIOS header.  SMB will only run over
+ *  the Session Message type.  On port 139, there is always an
+ *  initial Session Request / Session Positive/Negative response
+ *  followed by the normal SMB conversation, i.e. Negotiate,
+ *  SessionSetupAndX, etc.
+ *  Side effects are potential alerts for anomolous behavior.
+ *
+ * Arguments:
+ *  DCE2_SmbSsnData * - the session data structure.
+ *  const NbssHdr *   - pointer to the NetBIOS Session Service
+ *                      header structure.  Size is already validated.
+ *
+ * Returns:
+ *  DCE2_Ret  -  DCE2_RET__SUCCESS if all goes well and processing
+ *               should continue.
+ *               DCE2_RET__IGNORE if it's not something we need to
+ *               look at.
+ *               DCE2_RET__ERROR if an invalid NetBIOS Session
+ *               Service type is found.
+ *
+ ********************************************************************/
+static DCE2_Ret DCE2_NbssHdrChecks(DCE2_SmbSsnData* ssd, const NbssHdr* nb_hdr)
+{
+    Packet* p = ssd->sd.wire_pkt;
+
+    DebugMessage(DEBUG_DCE_SMB, "NetBIOS Session Service type: ");
+
+    switch (NbssType(nb_hdr))
+    {
+    case NBSS_SESSION_TYPE__MESSAGE:
+        /* Only want to look at session messages */
+        DebugMessage(DEBUG_DCE_SMB, "Session Message\n");
+
+        if (!DCE2_SmbIsRawData(ssd))
+        {
+            uint32_t nb_len = NbssLen(nb_hdr);
+
+            if (nb_len == 0)
+                return DCE2_RET__IGNORE;
+
+            if (nb_len < sizeof(SmbNtHdr))
+            {
+                DebugFormat(DEBUG_DCE_SMB, "NetBIOS SS len(%u) < SMB header len(%u).\n",
+                    sizeof(SmbNtHdr), sizeof(NbssHdr) + nb_len);
+
+                // FIXIT-M port segment check
+                // Same for all cases below
+                dce_alert(GID_DCE2, DCE2_SMB_NB_LT_SMBHDR, (dce2CommonStats*)&dce2_smb_stats);
+                return DCE2_RET__IGNORE;
+            }
+        }
+
+        return DCE2_RET__SUCCESS;
+
+    case NBSS_SESSION_TYPE__REQUEST:
+        DebugMessage(DEBUG_DCE_SMB, "Session Request\n");
+        if (DCE2_SsnFromServer(p))
+        {
+            dce_alert(GID_DCE2, DCE2_SMB_BAD_NBSS_TYPE, (dce2CommonStats*)&dce2_smb_stats);
+        }
+
+        break;
+
+    case NBSS_SESSION_TYPE__POS_RESPONSE:
+    case NBSS_SESSION_TYPE__NEG_RESPONSE:
+    case NBSS_SESSION_TYPE__RETARGET_RESPONSE:
+        if (DCE2_SsnFromClient(p))
+        {
+            dce_alert(GID_DCE2, DCE2_SMB_BAD_NBSS_TYPE, (dce2CommonStats*)&dce2_smb_stats);
+        }
+
+        break;
+
+    case NBSS_SESSION_TYPE__KEEP_ALIVE:
+        DebugMessage(DEBUG_DCE_SMB, "Session Keep Alive\n");
+        break;
+
+    default:
+        DebugFormat(DEBUG_DCE_SMB,
+            "Invalid Session Service type: 0x%02X\n", NbssType(nb_hdr));
+        dce_alert(GID_DCE2, DCE2_SMB_BAD_NBSS_TYPE, (dce2CommonStats*)&dce2_smb_stats);
+
+        return DCE2_RET__ERROR;
+    }
+
+    return DCE2_RET__IGNORE;
+}
+
+/********************************************************************
+ * Function: DCE2_SmbProcess()
+ *
+ * Purpose:
+ *  This is the main entry point for SMB processing.
+ *
+ * Arguments:
+ *  DCE2_SmbSsnData * - the session data structure.
+ *
+ * Returns: None
+ *
+ ********************************************************************/
+void DCE2_SmbProcess(DCE2_SmbSsnData* ssd)
+{
+    DebugMessage(DEBUG_DCE_SMB, "Processing SMB packet.\n");
+    dce2_smb_stats.smb_pkts++;
+
+    const Packet* p = ssd->sd.wire_pkt;
+    const uint8_t* data_ptr = p->data;
+    uint16_t data_len = p->dsize;
+
+    /* Have to account for segmentation.  Even though stream will give
+     * us larger chunks, we might end up in the middle of something */
+    while (data_len > 0)
+    {
+        // We are ignoring an entire PDU or junk data so state should be NETBIOS_HEADER
+        // Note that it could be TCP segmented so ignore_bytes could be greater than
+        // the amount of data we have
+        uint32_t* ignore_bytes = DCE2_SmbGetIgnorePtr(ssd);
+        if (*ignore_bytes)
+        {
+            DebugFormat(DEBUG_DCE_SMB, "Ignoring %u bytes\n", *ignore_bytes);
+
+            if (data_len <= *ignore_bytes)
+            {
+                *ignore_bytes -= data_len;
+                return;
+            }
+            else
+            {
+                /* ignore bytes is less than UINT16_MAX */
+                DCE2_MOVE(data_ptr, data_len, (uint16_t)*ignore_bytes);
+                *ignore_bytes = 0;
+            }
+        }
+
+        DCE2_SmbDataState* data_state = DCE2_SmbGetDataState(ssd);
+        DCE2_SmbRequestTracker* rtracker = nullptr;
+        switch (*data_state)
+        {
+        // This state is to verify it's a NetBIOS Session Message packet
+        // and to get the length of the SMB PDU.  Also does the SMB junk
+        // data check.  If it's not a Session Message the data isn't
+        // processed since it won't be carrying SMB.
+        case DCE2_SMB_DATA_STATE__NETBIOS_HEADER:
+        {
+            uint32_t data_need = sizeof(NbssHdr);
+
+            // See if there is enough data to process the NetBIOS header
+            if (data_len < data_need)
+            {
+                DebugFormat(DEBUG_DCE_SMB, "Data len(%u) < NetBIOS SS header(%u). "
+                    "Queueing data.\n", data_len, data_need);
+
+                // FIXIT-M port segmentation code
+                return;
+            }
+
+            // Set the NetBIOS header structure
+            NbssHdr* nb_hdr = (NbssHdr*)data_ptr;
+            uint32_t nb_len = NbssLen(nb_hdr);
+
+            DebugFormat(DEBUG_DCE_SMB, "NetBIOS PDU length: %u\n", nb_len);
+
+            DCE2_Ret status = DCE2_NbssHdrChecks(ssd, nb_hdr);
+            if (status != DCE2_RET__SUCCESS)
+            {
+                DebugMessage(DEBUG_DCE_SMB, "Not a NetBIOS Session Message.\n");
+
+                if (status == DCE2_RET__IGNORE)
+                {
+                    DebugMessage(DEBUG_DCE_SMB, "Valid NetBIOS header "
+                        "type so ignoring NetBIOS length bytes.\n");
+                    *ignore_bytes = data_need + nb_len;
+                }
+                else      // nb_ret == DCE2_RET__ERROR, i.e. invalid NetBIOS type
+                {
+                    DebugMessage(DEBUG_DCE_SMB, "Not a valid NetBIOS "
+                        "header type so trying to find \\xffSMB to "
+                        "determine how many bytes to ignore.\n");
+                    *ignore_bytes = DCE2_IgnoreJunkData(data_ptr, data_len, data_need + nb_len);
+                }
+
+                dce2_smb_stats.smb_ignored_bytes += *ignore_bytes;
+                continue;
+            }
+
+            switch (ssd->pdu_state)
+            {
+            case DCE2_SMB_PDU_STATE__COMMAND:
+                *data_state = DCE2_SMB_DATA_STATE__SMB_HEADER;
+                break;
+            case DCE2_SMB_PDU_STATE__RAW_DATA:
+                *data_state = DCE2_SMB_DATA_STATE__NETBIOS_PDU;
+                // Continue here because of fall through below
+                continue;
+            default:
+                DebugFormat(DEBUG_DCE_SMB,"%s(%d) Invalid SMB PDU "
+                    "state: %d\n", __FILE__, __LINE__, ssd->pdu_state);
+                return;
+            }
+        }
+
+        // Fall through for DCE2_SMB_DATA_STATE__SMB_HEADER
+        // This is the normal progression without segmentation.
+
+        // This state is to do validation checks on the SMB header and
+        // more importantly verify it's data that needs to be inspected.
+        // If the TID in the SMB header is not referring to the IPC share
+        // there won't be any DCE/RPC traffic associated with it.
+        case DCE2_SMB_DATA_STATE__SMB_HEADER:
+        {
+            // FIXIT-M add segmentation code path, including seg_buf code to the entire state
+
+            uint32_t data_need = (sizeof(NbssHdr) + sizeof(SmbNtHdr));
+            // See if there is enough data to process the SMB header
+            if (data_len < data_need)
+            {
+                DebugFormat(DEBUG_DCE_SMB, "Data len (%u) < "
+                    "NetBIOS SS header + SMB header (%u). Queueing data.\n",
+                    data_len, data_need);
+
+                // FIXIT-M add segmentation code path
+                return;
+            }
+
+            // FIXIT-M add segmentation checks
+            SmbNtHdr* smb_hdr = (SmbNtHdr*)(data_ptr + sizeof(NbssHdr));
+
+            // FIXIT-L Don't support SMB2 yet
+            if (SmbId(smb_hdr) == DCE2_SMB2_ID)
+            {
+                ssd->sd.flags |= DCE2_SSN_FLAG__NO_INSPECT;
+                return;
+            }
+
+            // See if this is something we need to inspect
+            rtracker = DCE2_SmbInspect(ssd, smb_hdr);
+            if (rtracker == nullptr)
+            {
+                DebugMessage(DEBUG_DCE_SMB, "Not inspecting SMB packet.\n");
+
+                // FIXIT-M add segmentation
+                *ignore_bytes = sizeof(NbssHdr) + NbssLen((NbssHdr*)data_ptr);
+
+                *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
+                dce2_smb_stats.smb_ignored_bytes += *ignore_bytes;
+                continue;
+            }
+
+            // Check the SMB header for anomolies
+            if (DCE2_SmbHdrChecks(ssd, smb_hdr) != DCE2_RET__SUCCESS)
+            {
+                DebugMessage(DEBUG_DCE_SMB, "Bad SMB header.\n");
+
+                *ignore_bytes = sizeof(NbssHdr) + NbssLen((NbssHdr*)data_ptr);
+
+                *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
+
+                dce2_smb_stats.smb_ignored_bytes += *ignore_bytes;
+                continue;
+            }
+
+            *data_state = DCE2_SMB_DATA_STATE__NETBIOS_PDU;
+        }
+
+        // Fall through
+
+        // This state ensures that we have the entire PDU before continuing
+        // to process.
+        case DCE2_SMB_DATA_STATE__NETBIOS_PDU:
+        {
+            uint32_t nb_len = NbssLen((NbssHdr*)data_ptr);
+            uint32_t data_need = sizeof(NbssHdr) + nb_len;
+
+            /* It's something we want to inspect so make sure we have the full NBSS packet */
+            if (data_len < data_need)
+            {
+                DebugFormat(DEBUG_DCE_SMB, "Data len(%u) < "
+                    "NetBIOS SS header + NetBIOS len(%u). "
+                    "Queueing data.\n", data_len, sizeof(NbssHdr) + nb_len);
+
+                // FIXIT-M add segmentation code
+
+                return;
+            }
+
+            // data_len >= data_need which means data_need <= UINT16_MAX
+            // So casts below of data_need to uint16_t are okay.
+
+            *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
+
+            const uint8_t* nb_ptr = data_ptr;
+            nb_len = data_need;
+            DCE2_MOVE(data_ptr, data_len, (uint16_t)data_need);
+
+            switch (ssd->pdu_state)
+            {
+            case DCE2_SMB_PDU_STATE__COMMAND:
+            {
+                SmbNtHdr* smb_hdr = (SmbNtHdr*)(nb_ptr + sizeof(NbssHdr));
+                DCE2_MOVE(nb_ptr, nb_len, (sizeof(NbssHdr) + sizeof(SmbNtHdr)));
+                ssd->cur_rtracker = (rtracker != nullptr)
+                    ? rtracker : DCE2_SmbFindRequestTracker(ssd, smb_hdr);
+                if (ssd->cur_rtracker != nullptr)
+                    DCE2_SmbProcessCommand(ssd, smb_hdr, nb_ptr, nb_len);
+                break;
+            }
+
+            case DCE2_SMB_PDU_STATE__RAW_DATA:
+                //FIXIT-M port raw state
+                break;
+            default:
+                DebugFormat(DEBUG_DCE_SMB, "%s(%d) Invalid SMB PDU "
+                    "state: %d\n", __FILE__, __LINE__, ssd->pdu_state);
+                return;
+            }
+            break;
+        }
+
+        default:
+            DebugFormat(DEBUG_DCE_SMB, "%s(%d) Invalid SMB Data "
+                "state: %d\n", __FILE__, __LINE__, *data_state);
+            return;
+        }
+    }
+}
+
+/********************************************************************
+ * Function: DCE2_SmbInitGlobals()
+ *
+ * Purpose:
+ *  Initializes global variables for SMB processing.
+ *  Sets up the functions and valid word and byte counts for SMB
+ *  commands.
+ *  Sets up AndX chain mappings and valid command chaining for
+ *  supported policies.
+ *
+ * Arguments: None
+ *
+ * Returns: None
+ *
+ ********************************************************************/
+void DCE2_SmbInitGlobals()
+{
+    memset(&smb_wcts, 0, sizeof(smb_wcts));
+    memset(&smb_bccs, 0, sizeof(smb_bccs));
+
+    // Sets up the function to call for the command and valid word and byte
+    // counts for the command.  Ensuring valid word and byte counts is very
+    // important to processing the command as it will assume the command is
+    // legitimate and can access data that is acutally there.  Note that
+    // commands with multiple word counts indicate a different command
+    // structure, however most, if not all just have an extended version
+    // of the structure for which the extended part isn't used.  If the
+    // extended part of a command structure needs to be used, be sure to
+    // check the word count in the command function before accessing data
+    // in the extended version of the command structure.
+    for (int com = 0; com < SMB_MAX_NUM_COMS; com++)
+    {
+        switch (com)
+        {
+        case SMB_COM_OPEN:
+            // FIXIT-M port DCE2_SmbOpen. Same for other smb_com_funcs
+            smb_com_funcs[com] = DCE2_SmbOpen;
+
+            smb_deprecated_coms[com] = true;
+            smb_unusual_coms[com] = false;
+
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 2);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 7);
+
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX);
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
+            break;
+        case SMB_COM_CREATE:
+            smb_com_funcs[com] = DCE2_SmbCreate;
+
+            smb_deprecated_coms[com] = true;
+            smb_unusual_coms[com] = false;
+
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 3);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1);
+
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX);
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
+            break;
+        case SMB_COM_CLOSE:
+            smb_com_funcs[com] = DCE2_SmbClose;
+            smb_deprecated_coms[com] = false;
+            smb_unusual_coms[com] = false;
+
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 3);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0);
+
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0);
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
+            break;
+        case SMB_COM_RENAME:
+            smb_com_funcs[com] = DCE2_SmbRename;
+            smb_deprecated_coms[com] = false;
+            smb_unusual_coms[com] = false;
+
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 1);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0);
+
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 4, UINT16_MAX);
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
+            break;
+        case SMB_COM_READ:
+            smb_com_funcs[com] = DCE2_SmbRead;
+            smb_deprecated_coms[com] = true;
+            smb_unusual_coms[com] = false;
+
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 5);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 5);
+
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0);
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 3, UINT16_MAX);
+            break;
+        case SMB_COM_WRITE:
+            smb_com_funcs[com] = DCE2_SmbWrite;
+            smb_deprecated_coms[com] = true;
+            smb_unusual_coms[com] = false;
+
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 5);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1);
+
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 3, UINT16_MAX);
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
+            break;
+        case SMB_COM_CREATE_NEW:
+            smb_com_funcs[com] = DCE2_SmbCreateNew;
+            smb_deprecated_coms[com] = true;
+            smb_unusual_coms[com] = false;
+
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 3);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1);
+
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX);
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
+            break;
+        case SMB_COM_LOCK_AND_READ:
+            smb_com_funcs[com] = DCE2_SmbLockAndRead;
+            smb_deprecated_coms[com] = true;
+            smb_unusual_coms[com] = false;
+
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 5);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 5);
+
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0);
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 3, UINT16_MAX);
+            break;
+        case SMB_COM_WRITE_AND_UNLOCK:
+            smb_com_funcs[com] = DCE2_SmbWriteAndUnlock;
+            smb_deprecated_coms[com] = true;
+            smb_unusual_coms[com] = false;
+
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 5);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1);
+
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 3, UINT16_MAX);
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
+            break;
+        case SMB_COM_READ_RAW:
+            //smb_com_funcs[com] = DCE2_SmbReadRaw;
+            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
+            smb_deprecated_coms[com] = true;
+            smb_unusual_coms[com] = false;
+
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 8);
+            // With optional OffsetHigh
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 10);
+
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0);
+            // Response is raw data, i.e. without SMB
+            break;
+        case SMB_COM_WRITE_RAW:
+            //smb_com_funcs[com] = DCE2_SmbWriteRaw;
+            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
+            smb_deprecated_coms[com] = true;
+            smb_unusual_coms[com] = false;
+
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 12);
+            // With optional OffsetHigh
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 14);
+            // Interim server response
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1);
+
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX);
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
+            break;
+        case SMB_COM_WRITE_COMPLETE:
+            // Final server response to SMB_COM_WRITE_RAW
+            //smb_com_funcs[com] = DCE2_SmbWriteComplete;
+            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
+            smb_deprecated_coms[com] = true;
+            smb_unusual_coms[com] = false;
+
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1);
+
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
+            break;
+        case SMB_COM_TRANSACTION:
+            smb_com_funcs[com] = DCE2_SmbTransaction;
+            smb_deprecated_coms[com] = false;
+            smb_unusual_coms[com] = false;
+
+            // Word count depends on setup count
+            //for (i = 14; i < 256; i++)
+            //    DCE2_SmbSetValidWordCount(com, SMB_TYPE__REQUEST, i);
+            // In reality, all subcommands of SMB_COM_TRANSACTION requests
+            // have a setup count of 2 words.
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 16);
+
+            // \PIPE\LANMAN
+            // Not something the preprocessor is looking at as it
+            // doesn't carry DCE/RPC but don't want to false positive
+            // on the preprocessor event.
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 14);
+
+            // Word count depends on setup count
+            //for (i = 10; i < 256; i++)
+            //    DCE2_SmbSetValidWordCount(com, SMB_TYPE__RESPONSE, i);
+            // In reality, all subcommands of SMB_COM_TRANSACTION responses
+            // have a setup count of 0 words.
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 10);
+
+            // Interim server response
+            // When client sends an incomplete transaction and needs to
+            // send TransactionSecondary requests to complete request.
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0);
+
+            // Exception will be made for Interim responses when
+            // byte count is checked.
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX);
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX);
+            break;
+        case SMB_COM_TRANSACTION_SECONDARY:
+            //smb_com_funcs[com] = DCE2_SmbTransactionSecondary;
+            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
+            smb_deprecated_coms[com] = false;
+            smb_unusual_coms[com] = false;
+
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 8);
+            // Response is an SMB_COM_TRANSACTION
+
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX);
+            break;
+        case SMB_COM_WRITE_AND_CLOSE:
+            //smb_com_funcs[com] = DCE2_SmbWriteAndClose;
+            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
+            smb_deprecated_coms[com] = true;
+            smb_unusual_coms[com] = false;
+
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 6);
+            // For some reason MS-CIFS specifies a version of this command
+            // with 6 extra words (12 bytes) of reserved, i.e. useless data.
+            // Maybe had intentions of extending and defining the data at
+            // some point, but there is no documentation that I could find
+            // that does.
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 12);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1);
+
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 1, UINT16_MAX);
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
+            break;
+        case SMB_COM_OPEN_ANDX:
+            smb_com_funcs[com] = DCE2_SmbOpenAndX;
+            smb_deprecated_coms[com] = true;
+            smb_unusual_coms[com] = false;
+
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 15);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 15);
+            // Extended response
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 19);
+
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX);
+            // MS-SMB says that Windows 2000, XP and Vista set this to
+            // some arbitrary value that is ignored on receipt.
+            //DCE2_SmbSetValidByteCount(com, SMB_TYPE__RESPONSE, 0, 0);
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX);
+            break;
+        case SMB_COM_READ_ANDX:
+            smb_com_funcs[com] = DCE2_SmbReadAndX;
+            smb_deprecated_coms[com] = false;
+            smb_unusual_coms[com] = false;
+
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 10);
+            // With optional OffsetHigh
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 12);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 12);
+
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0);
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX);
+            break;
+        case SMB_COM_WRITE_ANDX:
+            smb_com_funcs[com] = DCE2_SmbWriteAndX;
+            smb_deprecated_coms[com] = false;
+            smb_unusual_coms[com] = false;
+
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 12);
+            // With optional OffsetHigh
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 14);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 6);
+
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 1, UINT16_MAX);
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
+            break;
+        case SMB_COM_TRANSACTION2:
+            //smb_com_funcs[com] = DCE2_SmbTransaction2;
+            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
+            smb_deprecated_coms[com] = false;
+            smb_unusual_coms[com] = false;
+
+            // Word count depends on setup count
+            //for (i = 14; i < 256; i++)
+            //    DCE2_SmbSetValidWordCount(com, SMB_TYPE__REQUEST, i);
+            // In reality, all subcommands of SMB_COM_TRANSACTION2
+            // requests have a setup count of 1 word.
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 15);
+
+            // Word count depends on setup count
+            //for (i = 10; i < 256; i++)
+            //    DCE2_SmbSetValidWordCount(com, SMB_TYPE__RESPONSE, i);
+            // In reality, all subcommands of SMB_COM_TRANSACTION2
+            // responses have a setup count of 0 or 1 word.
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 10);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 11);
+
+            // Interim server response
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0);
+
+            // Exception will be made for Interim responses when
+            // byte count is checked.
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX);
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX);
+            break;
+        case SMB_COM_TRANSACTION2_SECONDARY:
+            //smb_com_funcs[com] = DCE2_SmbTransaction2Secondary;
+            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
+            smb_deprecated_coms[com] = false;
+            smb_unusual_coms[com] = false;
+
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 9);
+            // Response is an SMB_COM_TRANSACTION2
+
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX);
+            break;
+        case SMB_COM_TREE_CONNECT:
+            smb_com_funcs[com] = DCE2_SmbTreeConnect;
+            smb_deprecated_coms[com] = true;
+            smb_unusual_coms[com] = false;
+
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 0);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 2);
+
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 6, UINT16_MAX);
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
+            break;
+        case SMB_COM_TREE_DISCONNECT:
+            smb_com_funcs[com] = DCE2_SmbTreeDisconnect;
+            smb_deprecated_coms[com] = false;
+            smb_unusual_coms[com] = false;
+
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 0);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0);
+
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0);
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
+            break;
+        case SMB_COM_NEGOTIATE:
+            smb_com_funcs[com] = DCE2_SmbNegotiate;
+            smb_deprecated_coms[com] = false;
+            smb_unusual_coms[com] = false;
+
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 0);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 13);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 17);
+
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX);
+            // This can vary depending on dialect so just set wide.
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX);
+            break;
+        case SMB_COM_SESSION_SETUP_ANDX:
+            smb_com_funcs[com] = DCE2_SmbSessionSetupAndX;
+            smb_deprecated_coms[com] = false;
+            smb_unusual_coms[com] = false;
+
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 10);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 12);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 13);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 3);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 4);
+
+            // These can vary so just set wide.
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX);
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX);
+            break;
+        case SMB_COM_LOGOFF_ANDX:
+            smb_com_funcs[com] = DCE2_SmbLogoffAndX;
+            smb_deprecated_coms[com] = false;
+            smb_unusual_coms[com] = false;
+
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 2);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 2);
+            // Windows responds to a LogoffAndX => SessionSetupAndX with just a
+            // LogoffAndX and with the word count field containing 3, but only
+            // has 2 words
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 3);
+
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0);
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
+            break;
+        case SMB_COM_TREE_CONNECT_ANDX:
+            smb_com_funcs[com] = DCE2_SmbTreeConnectAndX;
+            smb_deprecated_coms[com] = false;
+            smb_unusual_coms[com] = false;
+
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 4);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 2);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 3);
+            // Extended response
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 7);
+
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 3, UINT16_MAX);
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 2, UINT16_MAX);
+            break;
+        case SMB_COM_NT_TRANSACT:
+            //smb_com_funcs[com] = DCE2_SmbNtTransact;
+            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
+            smb_deprecated_coms[com] = false;
+            smb_unusual_coms[com] = false;
+
+            // Word count depends on setup count
+            // In reality, all subcommands of SMB_COM_NT_TRANSACT
+            // requests have a setup count of 0 or 4 words.
+            //for (i = 19; i < 256; i++)
+            //    DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, i);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 19);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 23);
+
+            // Word count depends on setup count
+            // In reality, all subcommands of SMB_COM_NT_TRANSACT
+            // responses have a setup count of 0 or 1 word.
+            //for (i = 18; i < 256; i++)
+            //    DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, i);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 18);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 19);
+
+            // Interim server response
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0);
+
+            // Exception will be made for Interim responses when
+            // byte count is checked.
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX);
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX);
+            break;
+        case SMB_COM_NT_TRANSACT_SECONDARY:
+            //smb_com_funcs[com] = DCE2_SmbNtTransactSecondary;
+            smb_com_funcs[com] = DCE2_SmbComFuncPlaceholder;
+            smb_deprecated_coms[com] = false;
+            smb_unusual_coms[com] = false;
+
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 18);
+            // Response is an SMB_COM_NT_TRANSACT
+
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX);
+            break;
+        case SMB_COM_NT_CREATE_ANDX:
+            smb_com_funcs[com] = DCE2_SmbNtCreateAndX;
+            smb_deprecated_coms[com] = false;
+            smb_unusual_coms[com] = false;
+
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 24);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 34);
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 26);
+            // Extended response - though there are actually 50 words
+            DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 42);
+
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX);
+            // MS-SMB indicates that this field should be 0 but may be
+            // sent uninitialized so basically ignore it.
+            //DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX);
+            break;
+        default:
+            smb_com_funcs[com] = nullptr;
+            smb_deprecated_coms[com] = false;
+            smb_unusual_coms[com] = false;
+            // Just set to all valid since the specific command won't
+            // be processed.  Don't want to false positive on these.
+            for (int i = 0; i < 256; i++)
+            {
+                DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, (uint8_t)i);
+                DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, (uint8_t)i);
+            }
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX);
+            DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX);
+            break;
+        }
+    }
+
+    // Maps commands for use in quickly determining if a command
+    // is chainable and what command it is.
+    for (int com = 0; com < SMB_MAX_NUM_COMS; com++)
+    {
+        switch (com)
+        {
+        case SMB_COM_SESSION_SETUP_ANDX:
+            smb_chain_map[com] = SMB_ANDX_COM__SESSION_SETUP_ANDX;
+            break;
+        case SMB_COM_LOGOFF_ANDX:
+            smb_chain_map[com] = SMB_ANDX_COM__LOGOFF_ANDX;
+            break;
+        case SMB_COM_TREE_CONNECT_ANDX:
+            smb_chain_map[com] = SMB_ANDX_COM__TREE_CONNECT_ANDX;
+            break;
+        case SMB_COM_OPEN_ANDX:
+            smb_chain_map[com] = SMB_ANDX_COM__OPEN_ANDX;
+            break;
+        case SMB_COM_NT_CREATE_ANDX:
+            smb_chain_map[com] = SMB_ANDX_COM__NT_CREATE_ANDX;
+            break;
+        case SMB_COM_WRITE_ANDX:
+            smb_chain_map[com] = SMB_ANDX_COM__WRITE_ANDX;
+            break;
+        case SMB_COM_READ_ANDX:
+            smb_chain_map[com] = SMB_ANDX_COM__READ_ANDX;
+            break;
+        default:
+            smb_chain_map[com] = SMB_ANDX_COM__NONE;
+            break;
+        }
+    }
+
+    // Sets up the valid command chaining combinations per policy
+    for (int policy = 0; policy < DCE2_POLICY__MAX; policy++)
+    {
+        for (int andx = SMB_ANDX_COM__NONE; andx < SMB_ANDX_COM__MAX; andx++)
+        {
+            /* com is the chained command or com2 */
+            for (int com = 0; com < SMB_MAX_NUM_COMS; com++)
+            {
+                DCE2_SmbComFunc com_func = nullptr;
+
+                switch (policy)
+                {
+                case DCE2_POLICY__WIN2000:
+                case DCE2_POLICY__WINXP:
+                case DCE2_POLICY__WINVISTA:
+                case DCE2_POLICY__WIN2003:
+                case DCE2_POLICY__WIN2008:
+                case DCE2_POLICY__WIN7:
+                    switch (andx)
+                    {
+                    case SMB_ANDX_COM__SESSION_SETUP_ANDX:
+                        switch (com)
+                        {
+                        case SMB_COM_TREE_CONNECT_ANDX:
+                        case SMB_COM_OPEN:
+                        case SMB_COM_OPEN_ANDX:
+                        case SMB_COM_CREATE:
+                        case SMB_COM_CREATE_NEW:
+                            com_func = smb_com_funcs[com];
+                            break;
+                        case SMB_COM_TRANSACTION:
+                            if (policy == DCE2_POLICY__WIN2000)
+                                com_func = smb_com_funcs[com];
+                            break;
+                        default:
+                            break;
+                        }
+                        break;
+                    case SMB_ANDX_COM__LOGOFF_ANDX:
+                        switch (com)
+                        {
+                        case SMB_COM_SESSION_SETUP_ANDX:
+                        case SMB_COM_TREE_CONNECT_ANDX:               // Only for responses
+                            com_func = smb_com_funcs[com];
+                            break;
+                        default:
+                            break;
+                        }
+                        break;
+                    case SMB_ANDX_COM__TREE_CONNECT_ANDX:
+                        switch (com)
+                        {
+                        case SMB_COM_OPEN:
+                        case SMB_COM_CREATE:
+                        case SMB_COM_CREATE_NEW:
+                            com_func = smb_com_funcs[com];
+                            break;
+                        case SMB_COM_TRANSACTION:
+                            if (policy == DCE2_POLICY__WIN2000)
+                                com_func = smb_com_funcs[com];
+                            break;
+                        default:
+                            break;
+                        }
+                        break;
+                    case SMB_ANDX_COM__OPEN_ANDX:
+                        break;
+                    case SMB_ANDX_COM__NT_CREATE_ANDX:
+                        switch (com)
+                        {
+                        case SMB_COM_READ_ANDX:              // Only for normal files
+                            com_func = smb_com_funcs[com];
+                            break;
+                        default:
+                            break;
+                        }
+                        break;
+                    case SMB_ANDX_COM__WRITE_ANDX:
+                        switch (com)
+                        {
+                        case SMB_COM_CLOSE:
+                        case SMB_COM_WRITE_ANDX:
+                        case SMB_COM_READ:
+                        case SMB_COM_READ_ANDX:
+                            com_func = smb_com_funcs[com];
+                            break;
+                        default:
+                            break;
+                        }
+                        break;
+                    case SMB_ANDX_COM__READ_ANDX:
+                        break;
+                    default:
+                        break;
+                    }
+                    break;
+                case DCE2_POLICY__SAMBA:
+                case DCE2_POLICY__SAMBA_3_0_37:
+                case DCE2_POLICY__SAMBA_3_0_22:
+                case DCE2_POLICY__SAMBA_3_0_20:
+                    switch (andx)
+                    {
+                    case SMB_ANDX_COM__SESSION_SETUP_ANDX:
+                        switch (com)
+                        {
+                        case SMB_COM_LOGOFF_ANDX:
+                        case SMB_COM_TREE_CONNECT:
+                        case SMB_COM_TREE_CONNECT_ANDX:
+                        case SMB_COM_TREE_DISCONNECT:
+                        case SMB_COM_OPEN_ANDX:
+                        case SMB_COM_NT_CREATE_ANDX:
+                        case SMB_COM_CLOSE:
+                        case SMB_COM_READ_ANDX:
+                            com_func = smb_com_funcs[com];
+                            break;
+                        case SMB_COM_WRITE:
+                            if ((policy == DCE2_POLICY__SAMBA_3_0_22)
+                                || (policy == DCE2_POLICY__SAMBA_3_0_20))
+                                com_func = smb_com_funcs[com];
+                            break;
+                        default:
+                            break;
+                        }
+                        break;
+                    case SMB_ANDX_COM__LOGOFF_ANDX:
+                        switch (com)
+                        {
+                        case SMB_COM_SESSION_SETUP_ANDX:
+                        case SMB_COM_TREE_DISCONNECT:
+                            com_func = smb_com_funcs[com];
+                            break;
+                        default:
+                            break;
+                        }
+                        break;
+                    case SMB_ANDX_COM__TREE_CONNECT_ANDX:
+                        switch (com)
+                        {
+                        case SMB_COM_SESSION_SETUP_ANDX:
+                        case SMB_COM_LOGOFF_ANDX:
+                        case SMB_COM_TREE_DISCONNECT:
+                        case SMB_COM_OPEN_ANDX:
+                        case SMB_COM_NT_CREATE_ANDX:
+                        case SMB_COM_CLOSE:
+                        case SMB_COM_WRITE:
+                        case SMB_COM_READ_ANDX:
+                            com_func = smb_com_funcs[com];
+                            break;
+                        default:
+                            break;
+                        }
+                        break;
+                    case SMB_ANDX_COM__OPEN_ANDX:
+                        switch (com)
+                        {
+                        case SMB_COM_SESSION_SETUP_ANDX:
+                        case SMB_COM_LOGOFF_ANDX:
+                        case SMB_COM_TREE_CONNECT:
+                        case SMB_COM_TREE_CONNECT_ANDX:
+                        case SMB_COM_TREE_DISCONNECT:
+                        case SMB_COM_OPEN_ANDX:
+                        case SMB_COM_NT_CREATE_ANDX:
+                        case SMB_COM_CLOSE:
+                        case SMB_COM_WRITE:
+                        case SMB_COM_READ_ANDX:
+                            com_func = smb_com_funcs[com];
+                            break;
+                        default:
+                            break;
+                        }
+                        break;
+                    case SMB_ANDX_COM__NT_CREATE_ANDX:
+                        switch (com)
+                        {
+                        case SMB_COM_SESSION_SETUP_ANDX:
+                        case SMB_COM_TREE_CONNECT:
+                        case SMB_COM_TREE_CONNECT_ANDX:
+                        case SMB_COM_OPEN_ANDX:
+                        case SMB_COM_NT_CREATE_ANDX:
+                        case SMB_COM_WRITE:
+                        case SMB_COM_READ_ANDX:
+                            com_func = smb_com_funcs[com];
+                            break;
+                        case SMB_COM_LOGOFF_ANDX:
+                        case SMB_COM_TREE_DISCONNECT:
+                        case SMB_COM_CLOSE:
+                            if ((policy == DCE2_POLICY__SAMBA)
+                                || (policy == DCE2_POLICY__SAMBA_3_0_37))
+                                com_func = smb_com_funcs[com];
+                            break;
+                        default:
+                            break;
+                        }
+                        break;
+                    case SMB_ANDX_COM__WRITE_ANDX:
+                        switch (com)
+                        {
+                        case SMB_COM_SESSION_SETUP_ANDX:
+                        case SMB_COM_LOGOFF_ANDX:
+                        case SMB_COM_TREE_CONNECT:
+                        case SMB_COM_TREE_CONNECT_ANDX:
+                        case SMB_COM_OPEN_ANDX:
+                        case SMB_COM_NT_CREATE_ANDX:
+                        case SMB_COM_CLOSE:
+                        case SMB_COM_WRITE:
+                        case SMB_COM_READ_ANDX:
+                        case SMB_COM_WRITE_ANDX:
+                            com_func = smb_com_funcs[com];
+                            break;
+                        default:
                             break;
                         }
                         break;
                     case SMB_ANDX_COM__READ_ANDX:
+                        switch (com)
+                        {
+                        case SMB_COM_SESSION_SETUP_ANDX:
+                        case SMB_COM_WRITE:
+                            com_func = smb_com_funcs[com];
+                            break;
+                        case SMB_COM_LOGOFF_ANDX:
+                        case SMB_COM_TREE_CONNECT:
+                        case SMB_COM_TREE_CONNECT_ANDX:
+                        case SMB_COM_TREE_DISCONNECT:
+                        case SMB_COM_OPEN_ANDX:
+                        case SMB_COM_NT_CREATE_ANDX:
+                        case SMB_COM_CLOSE:
+                        case SMB_COM_READ_ANDX:
+                            if ((policy == DCE2_POLICY__SAMBA)
+                                || (policy == DCE2_POLICY__SAMBA_3_0_37))
+                                com_func = smb_com_funcs[com];
+                            break;
+                        default:
+                            break;
+                        }
                         break;
                     default:
                         break;
                     }
                     break;
-                case DCE2_POLICY__SAMBA:
-                case DCE2_POLICY__SAMBA_3_0_37:
-                case DCE2_POLICY__SAMBA_3_0_22:
-                case DCE2_POLICY__SAMBA_3_0_20:
-                    switch (andx)
+                default:
+                    break;
+                }
+
+                smb_chain_funcs[policy][andx][com] = com_func;
+            }
+        }
+    }
+}
+
+// Convenience function to determine whether or not the transaction is complete
+// for one side, i.e. all data and parameters sent.
+static inline bool DCE2_SmbIsTransactionComplete(DCE2_SmbTransactionTracker* ttracker)
+{
+    if ((ttracker->tdcnt == ttracker->dsent)
+        && (ttracker->tpcnt == ttracker->psent))
+        return true;
+    return false;
+}
+
+/********************************************************************
+ * Function: DCE2_SmbCheckAndXOffset()
+ *
+ * Purpose:
+ *  Validates that the AndXOffset is within bounds of the remaining
+ *  data we have to work with.
+ *
+ * Arguments:
+ *  uint8_t * - pointer to where the offset would take us.
+ *  uint8_t * - pointer to bound offset
+ *  uint8_t * - length of data where offset should be within
+ *
+ * Returns:
+ *  DCE2_RET__SUCCESS - Offset is okay.
+ *  DCE2_RET__ERROR   - Offset is bad.
+ *
+ ********************************************************************/
+static inline DCE2_Ret DCE2_SmbCheckAndXOffset(const uint8_t* off_ptr, const uint8_t* start_bound,
+    const uint32_t length)
+{
+    /* Offset should not point within data we just looked at or be equal to
+     * or beyond the length of the NBSS length left */
+    if ((off_ptr < start_bound) ||
+        (off_ptr > (start_bound + length)))
+    {
+        dce_alert(GID_DCE2, DCE2_SMB_BAD_OFF, (dce2CommonStats*)&dce2_smb_stats);
+
+        return DCE2_RET__ERROR;
+    }
+
+    return DCE2_RET__SUCCESS;
+}
+
+static void DCE2_SmbQueueTmpFileTracker(DCE2_SmbSsnData* ssd,
+    DCE2_SmbRequestTracker* rtracker, const uint16_t uid, const uint16_t tid)
+{
+    Profile profile(dce2_smb_pstat_smb_fid);
+
+    DebugFormat(DEBUG_DCE_SMB, "Queueing file tracker "
+        "with Uid: %u, Tid: %u\n", uid, tid);
+
+    DCE2_SmbFileTracker* ftracker = (DCE2_SmbFileTracker*)
+        SnortAlloc(sizeof(DCE2_SmbFileTracker));
+
+    if (ftracker == nullptr)
+    {
+        return;
+    }
+
+    bool is_ipc = DCE2_SmbIsTidIPC(ssd, tid);
+    if (DCE2_SmbInitFileTracker(ssd, ftracker, is_ipc, uid, tid, DCE2_SENTINEL) !=
+        DCE2_RET__SUCCESS)
+    {
+        DCE2_SmbCleanFileTracker(ftracker);
+        free((void*)ftracker);
+        return;
+    }
+
+    if (!is_ipc && (ssd->fapi_ftracker == ftracker))
+        ssd->fapi_ftracker = nullptr;
+
+    if (rtracker->ft_queue == nullptr)
+    {
+        rtracker->ft_queue = DCE2_QueueNew(DCE2_SmbFileTrackerDataFree);
+        if (rtracker->ft_queue == nullptr)
+        {
+            DCE2_SmbCleanSessionFileTracker(ssd, ftracker);
+            return;
+        }
+    }
+
+    if (DCE2_QueueEnqueue(rtracker->ft_queue, (void*)ftracker) != DCE2_RET__SUCCESS)
+    {
+        DCE2_SmbCleanSessionFileTracker(ssd, ftracker);
+        return;
+    }
+}
+
+/********************************************************************
+ * Function: DCE2_SmbInvalidShareCheck()
+ *
+ * Purpose:
+ *  Checks the share reported in a TreeConnect or TreeConnectAndX
+ *  against the invalid share list configured in the dcerpc2
+ *  configuration in snort.conf.
+ *
+ * Arguments:
+ *  DCE2_SmbSsnData * - SMB session data structure
+ *  SmbNtHdr *        - pointer to the SMB header structure
+ *  uint8_t *         - current pointer to the share to check
+ *  uint32_t          - the remaining length
+ *
+ * Returns: None
+ *  Alerts if there is an invalid share match.
+ *
+ ********************************************************************/
+static void DCE2_SmbInvalidShareCheck(DCE2_SmbSsnData* ssd,
+    const SmbNtHdr* smb_hdr, const uint8_t* nb_ptr, uint32_t nb_len)
+{
+    DCE2_List* share_list = DCE2_ScSmbInvalidShares((dce2SmbProtoConf*)ssd->sd.config);
+    if (share_list == nullptr)
+        return;
+
+    dce2SmbShare* smb_share;
+    for (smb_share = (dce2SmbShare*)DCE2_ListFirst(share_list);
+        smb_share != nullptr;
+        smb_share = (dce2SmbShare*)DCE2_ListNext(share_list))
+    {
+        unsigned int i;
+        const char* share_str;
+        unsigned int share_str_len;
+
+        if (SmbUnicode(smb_hdr))
+        {
+            share_str = smb_share->unicode_str;
+            share_str_len = smb_share->unicode_str_len;
+        }
+        else
+        {
+            share_str = smb_share->ascii_str;
+            share_str_len = smb_share->ascii_str_len;
+        }
+
+        /* Make sure we have enough data */
+        if (nb_len < share_str_len)
+            continue;
+
+        /* Test for share match */
+        for (i = 0; i < share_str_len; i++)
+        {
+            /* All share strings should have been converted to upper case and
+             * should include null terminating bytes */
+            if ((nb_ptr[i] != share_str[i]) && (nb_ptr[i] != tolower((int)share_str[i])))
+                break;
+        }
+
+        if (i == share_str_len)
+        {
+            /* Should only match one share since no duplicate shares in list */
+            dce_alert(GID_DCE2, DCE2_SMB_INVALID_SHARE, (dce2CommonStats*)&dce2_smb_stats);
+            break;
+        }
+    }
+}
+
+/********************************************************************
+ * Functions:
+ *   DCE2_SmbOpen()
+ *   DCE2_SmbCreate()
+ *   DCE2_SmbClose()
+ *   DCE2_SmbRename()
+ *   DCE2_SmbRead()
+ *   DCE2_SmbWrite()
+ *   DCE2_SmbCreateNew()
+ *   DCE2_SmbLockAndRead()
+ *   DCE2_SmbWriteAndUnlock()
+ *   DCE2_SmbReadRaw()
+ *   DCE2_SmbWriteRaw()
+ *   DCE2_SmbWriteComplete()
+ *   DCE2_SmbTransaction()
+ *   DCE2_SmbTransactionSecondary()
+ *   DCE2_SmbWriteAndClose()
+ *   DCE2_SmbOpenAndX()
+ *   DCE2_SmbReadAndX()
+ *   DCE2_SmbWriteAndX()
+ *   DCE2_SmbTransaction2()
+ *   DCE2_SmbTransaction2Secondary()
+ *   DCE2_SmbTreeConnect()
+ *   DCE2_SmbTreeDisconnect()
+ *   DCE2_SmbNegotiate()
+ *   DCE2_SmbSessionSetupAndX()
+ *   DCE2_SmbLogoffAndX()
+ *   DCE2_SmbTreeConnectAndX()
+ *   DCE2_SmbNtTransact()
+ *   DCE2_SmbNtTransactSecondary()
+ *   DCE2_SmbNtCreateAndX()
+ *
+ * Purpose: Process SMB command
+ *
+ * Arguments:
+ *  DCE2_SmbSsnData *       - SMB session data structure
+ *  const SmbNtHdr *        - SMB header structure (packet pointer)
+ *  const DCE2_SmbComInfo * - Basic command information structure
+ *  uint8_t *               - pointer to start of command (packet pointer)
+ *  uint32_t                - remaining NetBIOS length
+ *
+ * Returns:
+ *  DCE2_Ret - DCE2_RET__ERROR if something went wrong and/or processing
+ *               should stop
+ *             DCE2_RET__SUCCESS if processing should continue
+ *
+ ********************************************************************/
+
+// SMB_COM_OPEN
+static DCE2_Ret DCE2_SmbOpen(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
+    const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
+{
+    if (!DCE2_ComInfoCanProcessCommand(com_info))
+        return DCE2_RET__ERROR;
+
+    if (DCE2_ComInfoIsResponse(com_info))
+    {
+        DCE2_SmbFileTracker* ftracker;
+
+        if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid)
+            && (SmbFileAttrsDirectory(SmbOpenRespFileAttrs((SmbOpenResp*)nb_ptr))
+            || SmbOpenForWriting(SmbOpenRespAccessMode((SmbOpenResp*)nb_ptr))))
+            return DCE2_RET__SUCCESS;
+
+        ftracker = DCE2_SmbNewFileTracker(ssd, ssd->cur_rtracker->uid,
+            ssd->cur_rtracker->tid, SmbOpenRespFid((SmbOpenResp*)nb_ptr));
+        if (ftracker == nullptr)
+            return DCE2_RET__ERROR;
+
+        ftracker->file_name = ssd->cur_rtracker->file_name;
+        ssd->cur_rtracker->file_name = nullptr;
+
+        if (!ftracker->is_ipc)
+        {
+            // This command can only be used to open an existing file
+            ftracker->ff_file_size = SmbOpenRespFileSize((SmbOpenResp*)nb_ptr);
+        }
+    }
+    else
+    {
+        // Have at least 2 bytes of data based on byte count check done earlier
+
+        DCE2_MOVE(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info));
+
+        if (!SmbFmtAscii(*nb_ptr))
+        {
+            dce_alert(GID_DCE2, DCE2_SMB_BAD_FORM, (dce2CommonStats*)&dce2_smb_stats);
+            return DCE2_RET__ERROR;
+        }
+
+        DCE2_MOVE(nb_ptr, nb_len, 1);
+
+        ssd->cur_rtracker->file_name =
+            DCE2_SmbGetString(nb_ptr, nb_len, SmbUnicode(smb_hdr), false);
+    }
+
+    return DCE2_RET__SUCCESS;
+}
+
+// SMB_COM_CREATE
+static DCE2_Ret DCE2_SmbCreate(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
+    const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
+{
+    if (!DCE2_ComInfoCanProcessCommand(com_info))
+        return DCE2_RET__ERROR;
+
+    if (DCE2_ComInfoIsResponse(com_info))
+    {
+        DCE2_SmbFileTracker* ftracker = DCE2_SmbNewFileTracker(
+            ssd, ssd->cur_rtracker->uid, ssd->cur_rtracker->tid,
+            SmbCreateRespFid((SmbCreateResp*)nb_ptr));
+
+        if (ftracker == nullptr)
+            return DCE2_RET__ERROR;
+
+        ftracker->file_name = ssd->cur_rtracker->file_name;
+        ssd->cur_rtracker->file_name = nullptr;
+
+        // Command creates or opens and truncates file to 0 so assume
+        // upload.
+        if (!ftracker->is_ipc)
+            ftracker->ff_file_direction = DCE2_SMB_FILE_DIRECTION__UPLOAD;
+    }
+    else
+    {
+        if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid))
+        {
+            uint16_t file_attrs = SmbCreateReqFileAttrs((SmbCreateReq*)nb_ptr);
+
+            if (SmbAttrDirectory(file_attrs))
+                return DCE2_RET__IGNORE;
+
+            if (SmbEvasiveFileAttrs(file_attrs))
+                dce_alert(GID_DCE2, DCE2_SMB_EVASIVE_FILE_ATTRS,
+                    (dce2CommonStats*)&dce2_smb_stats);
+        }
+
+        // Have at least 2 bytes of data based on byte count check done earlier
+
+        DCE2_MOVE(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info));
+
+        if (!SmbFmtAscii(*nb_ptr))
+        {
+            dce_alert(GID_DCE2, DCE2_SMB_BAD_FORM, (dce2CommonStats*)&dce2_smb_stats);
+            return DCE2_RET__ERROR;
+        }
+
+        DCE2_MOVE(nb_ptr, nb_len, 1);
+
+        ssd->cur_rtracker->file_name =
+            DCE2_SmbGetString(nb_ptr, nb_len, SmbUnicode(smb_hdr), false);
+    }
+
+    return DCE2_RET__SUCCESS;
+}
+
+// SMB_COM_CLOSE
+static DCE2_Ret DCE2_SmbClose(DCE2_SmbSsnData* ssd, const SmbNtHdr*,
+    const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t)
+{
+    if (!DCE2_ComInfoCanProcessCommand(com_info))
+        return DCE2_RET__ERROR;
+
+    if (DCE2_ComInfoIsRequest(com_info))
+    {
+        uint16_t fid = SmbCloseReqFid((SmbCloseReq*)nb_ptr);
+
+        // Set this for response
+        ssd->cur_rtracker->ftracker = DCE2_SmbGetFileTracker(ssd, fid);
+
+        //FIXIT-M port active response related code
+/*
+#ifdef ACTIVE_RESPONSE
+        if ((ssd->fb_ftracker != NULL) && (ssd->fb_ftracker == ssd->cur_rtracker->ftracker))
+        {
+            void *ssnptr = ssd->sd.wire_pkt->stream_session;
+            void *p = (void *)ssd->sd.wire_pkt;
+            File_Verdict verdict = DCE2_SmbGetFileVerdict(p, ssnptr);
+
+            if ((verdict == FILE_VERDICT_BLOCK) || (verdict == FILE_VERDICT_REJECT))
+                ssd->block_pdus = true;
+        }
+#endif
+*/
+    }
+    else
+    {
+        DCE2_SmbRemoveFileTracker(ssd, ssd->cur_rtracker->ftracker);
+    }
+
+    return DCE2_RET__SUCCESS;
+}
+
+// SMB_COM_RENAME
+static DCE2_Ret DCE2_SmbRename(DCE2_SmbSsnData*, const SmbNtHdr* smb_hdr,
+    const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
+{
+    // NOTE: This command is only processed for CVE-2006-4696 where the buffer
+    // formats are invalid and has no bearing on DCE/RPC processing.
+
+    if (!DCE2_ComInfoCanProcessCommand(com_info))
+        return DCE2_RET__ERROR;
+
+    if (DCE2_ComInfoIsRequest(com_info))
+    {
+        // Have at least 4 bytes of data based on byte count check done earlier
+
+        uint32_t i;
+
+        DCE2_MOVE(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info));
+
+        if (!SmbFmtAscii(*nb_ptr))
+        {
+            dce_alert(GID_DCE2, DCE2_SMB_BAD_FORM, (dce2CommonStats*)&dce2_smb_stats);
+            return DCE2_RET__ERROR;
+        }
+
+        DCE2_MOVE(nb_ptr, nb_len, 1);
+
+        if (SmbUnicode(smb_hdr))
+        {
+            for (i = 0; i < (nb_len - 1); i += 2)
+            {
+                if (*((uint16_t*)(nb_ptr + i)) == 0)
+                {
+                    i += 2;  // move past null terminating bytes
+                    break;
+                }
+            }
+        }
+        else
+        {
+            for (i = 0; i < nb_len; i++)
+            {
+                if (nb_ptr[i] == 0)
+                {
+                    i++;  // move past null terminating byte
+                    break;
+                }
+            }
+        }
+
+        // i <= nb_len
+        DCE2_MOVE(nb_ptr, nb_len, i);
+
+        if ((nb_len > 0) && !SmbFmtAscii(*nb_ptr))
+        {
+            dce_alert(GID_DCE2, DCE2_SMB_BAD_FORM, (dce2CommonStats*)&dce2_smb_stats);
+            return DCE2_RET__ERROR;
+        }
+    }
+
+    // Don't care about tracking response
+    return DCE2_RET__ERROR;
+}
+
+// SMB_COM_READ
+static DCE2_Ret DCE2_SmbRead(DCE2_SmbSsnData* ssd, const SmbNtHdr*,
+    const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
+{
+    if (!DCE2_ComInfoCanProcessCommand(com_info))
+        return DCE2_RET__ERROR;
+
+    if (DCE2_ComInfoIsRequest(com_info))
+    {
+        DCE2_SmbFileTracker* ftracker =
+            DCE2_SmbGetFileTracker(ssd, SmbReadReqFid((SmbReadReq*)nb_ptr));
+
+        // Set this for response since response doesn't have the Fid
+        ssd->cur_rtracker->ftracker = ftracker;
+        if ((ftracker != nullptr) && !ftracker->is_ipc)
+            ssd->cur_rtracker->file_offset = SmbReadReqOffset((SmbReadReq*)nb_ptr);
+    }
+    else
+    {
+        // Have at least 3 bytes of data based on byte count check done earlier
+
+        uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
+        uint16_t byte_count = DCE2_ComInfoByteCount(com_info);
+        uint16_t com_dcnt = SmbReadRespCount((SmbReadResp*)nb_ptr);
+        uint8_t fmt = *(nb_ptr + com_size);
+        uint16_t fmt_dcnt = alignedNtohs((uint16_t*)(nb_ptr + com_size + 1));
+
+        DCE2_MOVE(nb_ptr, nb_len, (com_size + 3));
+
+        DCE2_SmbCheckFmtData(ssd, nb_len, byte_count, fmt, com_dcnt, fmt_dcnt);
+
+        if (com_dcnt > nb_len)
+            return DCE2_RET__ERROR;
+
+        return DCE2_SmbProcessResponseData(ssd, nb_ptr, com_dcnt);
+    }
+
+    return DCE2_RET__SUCCESS;
+}
+
+// SMB_COM_WRITE
+static DCE2_Ret DCE2_SmbWrite(DCE2_SmbSsnData* ssd, const SmbNtHdr*,
+    const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
+{
+    if (!DCE2_ComInfoCanProcessCommand(com_info))
+        return DCE2_RET__ERROR;
+
+    if (DCE2_ComInfoIsRequest(com_info))
+    {
+        // Have at least 3 bytes of data based on byte count check done earlier
+
+        uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
+        uint16_t byte_count = DCE2_ComInfoByteCount(com_info);
+        uint8_t fmt = *(nb_ptr + com_size);
+        uint16_t com_dcnt = SmbWriteReqCount((SmbWriteReq*)nb_ptr);
+        uint16_t fmt_dcnt = alignedNtohs((uint16_t*)(nb_ptr + com_size + 1));
+        uint16_t fid = SmbWriteReqFid((SmbWriteReq*)nb_ptr);
+        uint32_t offset = SmbWriteReqOffset((SmbWriteReq*)nb_ptr);
+
+        DCE2_MOVE(nb_ptr, nb_len, (com_size + 3));
+
+        DCE2_SmbCheckFmtData(ssd, nb_len, byte_count, fmt, com_dcnt, fmt_dcnt);
+
+        if (com_dcnt == 0)
+        {
+            dce_alert(GID_DCE2, DCE2_SMB_DCNT_ZERO, (dce2CommonStats*)&dce2_smb_stats);
+            return DCE2_RET__ERROR;
+        }
+
+        if (com_dcnt > nb_len)
+            com_dcnt = (uint16_t)nb_len;
+
+        return DCE2_SmbProcessRequestData(ssd, fid, nb_ptr, com_dcnt, offset);
+    }
+
+    return DCE2_RET__SUCCESS;
+}
+
+// SMB_COM_CREATE_NEW
+static DCE2_Ret DCE2_SmbCreateNew(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
+    const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
+{
+    if (!DCE2_ComInfoCanProcessCommand(com_info))
+        return DCE2_RET__ERROR;
+
+    if (DCE2_ComInfoIsResponse(com_info))
+    {
+        DCE2_SmbFileTracker* ftracker = DCE2_SmbNewFileTracker(
+            ssd, ssd->cur_rtracker->uid, ssd->cur_rtracker->tid,
+            SmbCreateNewRespFid((SmbCreateNewResp*)nb_ptr));
+
+        if (ftracker == nullptr)
+            return DCE2_RET__ERROR;
+
+        ftracker->file_name = ssd->cur_rtracker->file_name;
+        ssd->cur_rtracker->file_name = nullptr;
+
+        // Command creates a new file so assume upload.
+        if (!ftracker->is_ipc)
+            ftracker->ff_file_direction = DCE2_SMB_FILE_DIRECTION__UPLOAD;
+    }
+    else
+    {
+        if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid))
+        {
+            uint16_t file_attrs = SmbCreateNewReqFileAttrs((SmbCreateNewReq*)nb_ptr);
+
+            if (SmbAttrDirectory(file_attrs))
+                return DCE2_RET__IGNORE;
+
+            if (SmbEvasiveFileAttrs(file_attrs))
+                dce_alert(GID_DCE2, DCE2_SMB_EVASIVE_FILE_ATTRS,
+                    (dce2CommonStats*)&dce2_smb_stats);
+        }
+
+        // Have at least 2 bytes of data based on byte count check done earlier
+
+        DCE2_MOVE(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info));
+
+        if (!SmbFmtAscii(*nb_ptr))
+        {
+            dce_alert(GID_DCE2, DCE2_SMB_BAD_FORM, (dce2CommonStats*)&dce2_smb_stats);
+            return DCE2_RET__ERROR;
+        }
+
+        DCE2_MOVE(nb_ptr, nb_len, 1);
+
+        ssd->cur_rtracker->file_name =
+            DCE2_SmbGetString(nb_ptr, nb_len, SmbUnicode(smb_hdr), false);
+    }
+
+    return DCE2_RET__SUCCESS;
+}
+
+// SMB_COM_LOCK_AND_READ
+static DCE2_Ret DCE2_SmbLockAndRead(DCE2_SmbSsnData* ssd, const SmbNtHdr*,
+    const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
+{
+    if (!DCE2_ComInfoCanProcessCommand(com_info))
+        return DCE2_RET__ERROR;
+
+    if (DCE2_ComInfoIsRequest(com_info))
+    {
+        DCE2_SmbFileTracker* ftracker =
+            DCE2_SmbFindFileTracker(ssd, ssd->cur_rtracker->uid,
+            ssd->cur_rtracker->tid, SmbLockAndReadReqFid((SmbLockAndReadReq*)nb_ptr));
+
+        // No sense in tracking response
+        if (ftracker == nullptr)
+            return DCE2_RET__ERROR;
+
+        if (!ftracker->is_ipc)
+            ssd->cur_rtracker->file_offset = SmbLockAndReadReqOffset((SmbLockAndReadReq*)nb_ptr);
+
+        // Set this for response
+        ssd->cur_rtracker->ftracker = ftracker;
+    }
+    else
+    {
+        // Have at least 3 bytes of data based on byte count check done earlier
+
+        uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
+        uint16_t byte_count = DCE2_ComInfoByteCount(com_info);
+        uint8_t fmt = *(nb_ptr + com_size);
+        uint16_t com_dcnt = SmbLockAndReadRespCount((SmbLockAndReadResp*)nb_ptr);
+        uint16_t fmt_dcnt = alignedNtohs((uint16_t*)(nb_ptr + com_size + 1));
+
+        DCE2_MOVE(nb_ptr, nb_len, (com_size + 3));
+
+        DCE2_SmbCheckFmtData(ssd, nb_len, byte_count, fmt, com_dcnt, fmt_dcnt);
+
+        DebugFormat(DEBUG_DCE_SMB," SmbWriteLockAndRead dcnt %d\n", com_dcnt);
+        if (com_dcnt == 0)
+        {
+            dce_alert(GID_DCE2, DCE2_SMB_DCNT_ZERO, (dce2CommonStats*)&dce2_smb_stats);
+            return DCE2_RET__ERROR;
+        }
+
+        if (com_dcnt > nb_len)
+            com_dcnt = (uint16_t)nb_len;
+
+        return DCE2_SmbProcessResponseData(ssd, nb_ptr, com_dcnt);
+    }
+
+    return DCE2_RET__SUCCESS;
+}
+
+// SMB_COM_WRITE_AND_UNLOCK
+static DCE2_Ret DCE2_SmbWriteAndUnlock(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
+    const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
+{
+    if (!DCE2_ComInfoCanProcessCommand(com_info))
+    {
+        if (DCE2_ComInfoIsBadLength(com_info) || DCE2_ComInfoIsInvalidWordCount(com_info))
+            return DCE2_RET__ERROR;
+
+        // These are special cases.  The write succeeds but the unlock fails
+        // so an error reponse is returned but the data was actually written.
+        if (DCE2_ComInfoIsResponse(com_info) && DCE2_ComInfoIsStatusError(com_info))
+        {
+            if (DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid))
+            {
+                if (!SmbErrorInvalidDeviceRequest(smb_hdr))
+                    return DCE2_RET__ERROR;
+            }
+            else if (!SmbErrorRangeNotLocked(smb_hdr))
+            {
+                return DCE2_RET__ERROR;
+            }
+        }
+    }
+
+    if (DCE2_ComInfoIsRequest(com_info))
+    {
+        // Have at least 3 bytes of data based on byte count check done earlier
+
+        uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
+        uint16_t byte_count = DCE2_ComInfoByteCount(com_info);
+        uint8_t fmt = *(nb_ptr + com_size);
+        uint16_t com_dcnt = SmbWriteAndUnlockReqCount((SmbWriteAndUnlockReq*)nb_ptr);
+        uint16_t fmt_dcnt = alignedNtohs((uint16_t*)(nb_ptr + com_size + 1));
+        uint16_t fid = SmbWriteAndUnlockReqFid((SmbWriteAndUnlockReq*)nb_ptr);
+        uint32_t offset = SmbWriteAndUnlockReqOffset((SmbWriteAndUnlockReq*)nb_ptr);
+
+        DCE2_MOVE(nb_ptr, nb_len, (com_size + 3));
+
+        DCE2_SmbCheckFmtData(ssd, nb_len, byte_count, fmt, com_dcnt, fmt_dcnt);
+
+        if (com_dcnt == 0)
+        {
+            dce_alert(GID_DCE2, DCE2_SMB_DCNT_ZERO, (dce2CommonStats*)&dce2_smb_stats);
+            return DCE2_RET__ERROR;
+        }
+
+        if (com_dcnt > nb_len)
+            com_dcnt = (uint16_t)nb_len;
+
+        return DCE2_SmbProcessRequestData(ssd, fid, nb_ptr, com_dcnt, offset);
+    }
+
+    return DCE2_RET__SUCCESS;
+}
+
+// SMB_COM_OPEN_ANDX
+static DCE2_Ret DCE2_SmbOpenAndX(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
+    const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
+{
+    if (!DCE2_ComInfoCanProcessCommand(com_info))
+        return DCE2_RET__ERROR;
+
+    if (DCE2_ComInfoIsResponse(com_info))
+    {
+        const uint16_t fid = SmbOpenAndXRespFid((SmbOpenAndXResp*)nb_ptr);
+        const uint16_t file_attrs = SmbOpenAndXRespFileAttrs((SmbOpenAndXResp*)nb_ptr);
+        const uint16_t resource_type = SmbOpenAndXRespResourceType((SmbOpenAndXResp*)nb_ptr);
+        DCE2_SmbFileTracker* ftracker = nullptr;
+
+        // Set request tracker's current file tracker in case of chained commands
+        switch (SmbAndXCom2((SmbAndXCommon*)nb_ptr))
+        {
+        // This is in case in the request a write was chained to an open
+        // in which case the write will be to the newly opened file
+        case SMB_COM_WRITE:
+        case SMB_COM_WRITE_ANDX:
+        case SMB_COM_TRANSACTION:
+        case SMB_COM_READ_ANDX:
+            ftracker = DCE2_SmbDequeueTmpFileTracker(ssd, ssd->cur_rtracker, fid);
+            break;
+        default:
+            break;
+        }
+
+        if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid)
+            && (SmbFileAttrsDirectory(file_attrs)
+            || !SmbResourceTypeDisk(resource_type)))
+        {
+            if (ftracker != nullptr)
+                DCE2_SmbRemoveFileTracker(ssd, ftracker);
+            return DCE2_RET__SUCCESS;
+        }
+
+        if (ftracker == nullptr)
+        {
+            ftracker = DCE2_SmbNewFileTracker(ssd,
+                ssd->cur_rtracker->uid, ssd->cur_rtracker->tid, fid);
+            if (ftracker == nullptr)
+                return DCE2_RET__ERROR;
+        }
+
+        ftracker->file_name = ssd->cur_rtracker->file_name;
+        ssd->cur_rtracker->file_name = nullptr;
+
+        if (!ftracker->is_ipc)
+        {
+            const uint16_t open_results = SmbOpenAndXRespOpenResults((SmbOpenAndXResp*)nb_ptr);
+
+            if (SmbOpenResultRead(open_results))
+            {
+                ftracker->ff_file_size = SmbOpenAndXRespFileSize((SmbOpenAndXResp*)nb_ptr);
+            }
+            else
+            {
+                ftracker->ff_file_size = ssd->cur_rtracker->file_size;
+                ftracker->ff_file_direction = DCE2_SMB_FILE_DIRECTION__UPLOAD;
+            }
+        }
+
+        ssd->cur_rtracker->ftracker = ftracker;
+    }
+    else
+    {
+        uint32_t pad = 0;
+        const bool unicode = SmbUnicode(smb_hdr);
+        uint8_t null_bytes = unicode ? 2 : 1;
+
+        if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid))
+        {
+            uint16_t file_attrs = SmbOpenAndXReqFileAttrs((SmbOpenAndXReq*)nb_ptr);
+
+            if (SmbEvasiveFileAttrs(file_attrs))
+                dce_alert(GID_DCE2, DCE2_SMB_EVASIVE_FILE_ATTRS,
+                    (dce2CommonStats*)&dce2_smb_stats);
+            ssd->cur_rtracker->file_size = SmbOpenAndXReqAllocSize((SmbOpenAndXReq*)nb_ptr);
+        }
+
+        DCE2_MOVE(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info));
+
+        if (unicode)
+            pad = (nb_ptr - (const uint8_t*)smb_hdr) & 1;
+
+        if (nb_len < (pad + null_bytes))
+            return DCE2_RET__ERROR;
+
+        DCE2_MOVE(nb_ptr, nb_len, pad);
+
+        // Samba allows chaining OpenAndX/NtCreateAndX so might have
+        // already been set.
+        if (ssd->cur_rtracker->file_name == nullptr)
+        {
+            ssd->cur_rtracker->file_name =
+                DCE2_SmbGetString(nb_ptr, nb_len, unicode, false);
+        }
+    }
+
+    return DCE2_RET__SUCCESS;
+}
+
+// SMB_COM_READ_ANDX
+static DCE2_Ret DCE2_SmbReadAndX(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
+    const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
+{
+    if (!DCE2_ComInfoCanProcessCommand(com_info))
+        return DCE2_RET__ERROR;
+
+    if (DCE2_ComInfoIsRequest(com_info))
+    {
+        DCE2_SmbFileTracker* ftracker =
+            DCE2_SmbGetFileTracker(ssd, SmbReadAndXReqFid((SmbReadAndXReq*)nb_ptr));
+
+        // No sense in tracking response
+        if (ftracker == nullptr)
+            return DCE2_RET__ERROR;
+
+        if (!ftracker->is_ipc)
+            ssd->cur_rtracker->file_offset = SmbReadAndXReqOffset((SmbReadAndXExtReq*)nb_ptr);
+
+        // Set this for response
+        ssd->cur_rtracker->ftracker = ftracker;
+    }
+    else
+    {
+        uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
+        uint16_t byte_count = DCE2_ComInfoByteCount(com_info);
+        uint16_t doff = SmbReadAndXRespDataOff((SmbReadAndXResp*)nb_ptr);
+        uint32_t dcnt = SmbReadAndXRespDataCnt((SmbReadAndXResp*)nb_ptr);
+
+        DCE2_MOVE(nb_ptr, nb_len, com_size);
+
+        if (DCE2_SmbCheckData(ssd, (uint8_t*)smb_hdr, nb_ptr, nb_len,
+            byte_count, dcnt, doff) != DCE2_RET__SUCCESS)
+            return DCE2_RET__ERROR;
+
+        // This may move backwards
+        DCE2_MOVE(nb_ptr, nb_len, ((uint8_t*)smb_hdr + doff) - nb_ptr);
+
+        if (dcnt > nb_len)
+            dcnt = nb_len;
+
+        return DCE2_SmbProcessResponseData(ssd, nb_ptr, dcnt);
+    }
+
+    return DCE2_RET__SUCCESS;
+}
+
+// SMB_COM_WRITE_ANDX
+static DCE2_Ret DCE2_SmbWriteAndX(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
+    const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
+{
+    if (!DCE2_ComInfoCanProcessCommand(com_info))
+    {
+        DCE2_SmbFileTracker* ftracker = ssd->cur_rtracker->ftracker;
+
+        if ((ftracker != nullptr) && ftracker->is_ipc
+            && (ftracker->fp_writex_raw != nullptr))
+        {
+            ftracker->fp_writex_raw->remaining = 0;
+            DCE2_BufferEmpty(ftracker->fp_writex_raw->buf);
+        }
+
+        return DCE2_RET__ERROR;
+    }
+
+    if (DCE2_ComInfoIsRequest(com_info)
+        && (SmbWriteAndXReqStartRaw((SmbWriteAndXReq*)nb_ptr)
+        || SmbWriteAndXReqRaw((SmbWriteAndXReq*)nb_ptr)))
+    {
+        DCE2_SmbFileTracker* ftracker =
+            DCE2_SmbGetFileTracker(ssd, SmbWriteAndXReqFid((SmbWriteAndXReq*)nb_ptr));
+
+        // Raw mode is only applicable to named pipes.
+        if ((ftracker != nullptr) && ftracker->is_ipc)
+            return DCE2_SmbWriteAndXRawRequest(ssd, smb_hdr, com_info, nb_ptr, nb_len);
+    }
+
+    if (DCE2_ComInfoIsRequest(com_info))
+    {
+        uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
+        uint16_t byte_count = DCE2_ComInfoByteCount(com_info);
+        uint16_t fid = SmbWriteAndXReqFid((SmbWriteAndXReq*)nb_ptr);
+        uint16_t doff = SmbWriteAndXReqDataOff((SmbWriteAndXReq*)nb_ptr);
+        uint32_t dcnt = SmbWriteAndXReqDataCnt((SmbWriteAndXReq*)nb_ptr);
+        uint64_t offset = SmbWriteAndXReqOffset((SmbWriteAndXExtReq*)nb_ptr);
+
+        DCE2_MOVE(nb_ptr, nb_len, com_size);
+
+        if (DCE2_SmbCheckData(ssd, (uint8_t*)smb_hdr, nb_ptr, nb_len,
+            byte_count, dcnt, doff) != DCE2_RET__SUCCESS)
+            return DCE2_RET__ERROR;
+
+        // This may move backwards
+        DCE2_MOVE(nb_ptr, nb_len, ((uint8_t*)smb_hdr + doff) - nb_ptr);
+
+        if (dcnt > nb_len)
+        {
+            // Current Samba errors if data count is greater than data left
+            if (DCE2_SsnGetPolicy(&ssd->sd) == DCE2_POLICY__SAMBA)
+                return DCE2_RET__ERROR;
+
+            // Windows and early Samba just use what's left
+            dcnt = nb_len;
+        }
+
+        return DCE2_SmbProcessRequestData(ssd, fid, nb_ptr, dcnt, offset);
+    }
+
+    return DCE2_RET__SUCCESS;
+}
+
+// SMB_COM_WRITE_ANDX - raw mode
+static DCE2_Ret DCE2_SmbWriteAndXRawRequest(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
+    const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
+{
+    DebugMessage(DEBUG_DCE_SMB,
+        "Processing WriteAndX with raw mode flags\n");
+
+    // Set this now for possible reassembled packet
+    uint16_t fid = SmbWriteAndXReqFid((SmbWriteAndXReq*)nb_ptr);
+    DCE2_SmbFileTracker* ftracker = DCE2_SmbGetFileTracker(ssd, fid);
+    ssd->cur_rtracker->ftracker = ftracker;
+    if (ftracker == nullptr)
+        return DCE2_RET__ERROR;
+
+    // Got request to write in raw mode without having gotten the initial
+    // raw mode request or got initial raw mode request and then another
+    // without having finished the first.
+    bool start_write_raw = SmbWriteAndXReqStartRaw((SmbWriteAndXReq*)nb_ptr);
+    bool continue_write_raw = SmbWriteAndXReqRaw((SmbWriteAndXReq*)nb_ptr);
+    DCE2_Policy policy = DCE2_SsnGetServerPolicy(&ssd->sd);
+    if ((start_write_raw && (ftracker->fp_writex_raw != nullptr)
+        && (ftracker->fp_writex_raw->remaining != 0))
+        || (continue_write_raw && ((ftracker->fp_writex_raw == nullptr)
+        || (ftracker->fp_writex_raw->remaining == 0))))
+    {
+        switch (policy)
+        {
+        case DCE2_POLICY__WIN2000:
+        case DCE2_POLICY__WINXP:
+        case DCE2_POLICY__WINVISTA:
+        case DCE2_POLICY__WIN2003:
+        case DCE2_POLICY__WIN2008:
+        case DCE2_POLICY__WIN7:
+            if (ftracker->fp_writex_raw != nullptr)
+            {
+                ftracker->fp_writex_raw->remaining = 0;
+                DCE2_BufferEmpty(ftracker->fp_writex_raw->buf);
+            }
+            return DCE2_RET__ERROR;
+        case DCE2_POLICY__SAMBA:
+        case DCE2_POLICY__SAMBA_3_0_37:
+        case DCE2_POLICY__SAMBA_3_0_22:
+        case DCE2_POLICY__SAMBA_3_0_20:
+            // Samba doesn't do anything special here except if the two
+            // flags are set it walks past the two "length" bytes.
+            // See below.
+            break;
+        default:
+            DebugFormat(DEBUG_DCE_SMB, "%s(%d) Invalid policy: %d",
+                __FILE__, __LINE__, policy);
+            break;
+        }
+    }
+
+    uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
+    uint16_t byte_count = DCE2_ComInfoByteCount(com_info);
+    uint16_t doff = SmbWriteAndXReqDataOff((SmbWriteAndXReq*)nb_ptr);
+    uint32_t dcnt = SmbWriteAndXReqDataCnt((SmbWriteAndXReq*)nb_ptr);
+    uint16_t remaining = SmbWriteAndXReqRemaining((SmbWriteAndXReq*)nb_ptr);
+
+    DCE2_MOVE(nb_ptr, nb_len, com_size);
+
+    if (DCE2_SmbCheckData(ssd, (uint8_t*)smb_hdr, nb_ptr, nb_len,
+        byte_count, dcnt, doff) != DCE2_RET__SUCCESS)
+        return DCE2_RET__ERROR;
+
+    // This may move backwards
+    DCE2_MOVE(nb_ptr, nb_len, ((uint8_t*)smb_hdr + doff) - nb_ptr);
+
+    // If a "raw" write is requested there will be two bytes after the
+    // header/pad and before the data which is supposed to represent a
+    // length but everyone ignores it.  However we need to move past it.
+    // This is the one situation where the remaining field matters and
+    // should be equal to the total amount of data to be written.
+    if (start_write_raw)
+    {
+        if (dcnt < 2)
+            return DCE2_RET__ERROR;
+
+        // From data size check above, nb_len >= dsize
+        dcnt -= 2;
+        DCE2_MOVE(nb_ptr, nb_len, 2);
+    }
+
+    if (dcnt > nb_len)
+        dcnt = nb_len;
+
+    // File tracker already validated
+    switch (policy)
+    {
+    case DCE2_POLICY__WIN2000:
+    case DCE2_POLICY__WINXP:
+    case DCE2_POLICY__WINVISTA:
+    case DCE2_POLICY__WIN2003:
+    case DCE2_POLICY__WIN2008:
+    case DCE2_POLICY__WIN7:
+        if (start_write_raw)
+        {
+            if (ftracker->fp_writex_raw == nullptr)
+            {
+                ftracker->fp_writex_raw = (DCE2_SmbWriteAndXRaw*)
+                    SnortAlloc(sizeof(DCE2_SmbWriteAndXRaw));
+                if (ftracker->fp_writex_raw == nullptr)
+                    return DCE2_RET__ERROR;
+
+                ftracker->fp_writex_raw->remaining = (int)remaining;
+            }
+        }
+
+        ftracker->fp_writex_raw->remaining -= (int)dcnt;
+        if (ftracker->fp_writex_raw->remaining < 0)
+        {
+            ftracker->fp_writex_raw->remaining = 0;
+            DCE2_BufferEmpty(ftracker->fp_writex_raw->buf);
+            return DCE2_RET__ERROR;
+        }
+
+        // If the "raw" write isn't finished in the first request
+        // and haven't allocated a buffer yet.
+        if (start_write_raw && (ftracker->fp_writex_raw->remaining != 0)
+            && (ftracker->fp_writex_raw->buf == nullptr))
+        {
+            ftracker->fp_writex_raw->buf =
+                DCE2_BufferNew(remaining, 0);
+            if (ftracker->fp_writex_raw->buf == nullptr)
+            {
+                ftracker->fp_writex_raw->remaining = 0;
+                return DCE2_RET__ERROR;
+            }
+        }
+
+        // If data has to be added to buffer, i.e. not a start raw
+        // or a start raw and more raw requests to come.
+        if (!start_write_raw || (ftracker->fp_writex_raw->remaining != 0))
+        {
+            if (DCE2_BufferAddData(ftracker->fp_writex_raw->buf, nb_ptr,
+                dcnt, DCE2_BufferLength(ftracker->fp_writex_raw->buf),
+                DCE2_BUFFER_MIN_ADD_FLAG__IGNORE) != DCE2_RET__SUCCESS)
+            {
+                ftracker->fp_writex_raw->remaining = 0;
+                DCE2_BufferEmpty(ftracker->fp_writex_raw->buf);
+                return DCE2_RET__ERROR;
+            }
+
+            if (ftracker->fp_writex_raw->remaining == 0)
+            {
+                //FIXIT-M  - port Create reassembled packet
+/*
+                    const uint8_t *data_ptr = DCE2_BufferData(ftracker->fp_writex_raw->buf);
+                    uint32_t data_len = DCE2_BufferLength(ftracker->fp_writex_raw->buf);
+                    SFSnortPacket *rpkt = DCE2_SmbGetRpkt(ssd,
+                            &data_ptr, &data_len, DCE2_RPKT_TYPE__SMB_TRANS);
+
+                    if (rpkt == nullptr)
                     {
-                    case SMB_ANDX_COM__SESSION_SETUP_ANDX:
-                        switch (com)
-                        {
-                        case SMB_COM_LOGOFF_ANDX:
-                        case SMB_COM_TREE_CONNECT:
-                        case SMB_COM_TREE_CONNECT_ANDX:
-                        case SMB_COM_TREE_DISCONNECT:
-                        case SMB_COM_OPEN_ANDX:
-                        case SMB_COM_NT_CREATE_ANDX:
-                        case SMB_COM_CLOSE:
-                        case SMB_COM_READ_ANDX:
-                            com_func = smb_com_funcs[com];
-                            break;
-                        case SMB_COM_WRITE:
-                            if ((policy == DCE2_POLICY__SAMBA_3_0_22)
-                                || (policy == DCE2_POLICY__SAMBA_3_0_20))
-                                com_func = smb_com_funcs[com];
-                            break;
-                        default:
-                            break;
-                        }
-                        break;
-                    case SMB_ANDX_COM__LOGOFF_ANDX:
-                        switch (com)
-                        {
-                        case SMB_COM_SESSION_SETUP_ANDX:
-                        case SMB_COM_TREE_DISCONNECT:
-                            com_func = smb_com_funcs[com];
-                            break;
-                        default:
-                            break;
-                        }
-                        break;
-                    case SMB_ANDX_COM__TREE_CONNECT_ANDX:
-                        switch (com)
-                        {
-                        case SMB_COM_SESSION_SETUP_ANDX:
-                        case SMB_COM_LOGOFF_ANDX:
-                        case SMB_COM_TREE_DISCONNECT:
-                        case SMB_COM_OPEN_ANDX:
-                        case SMB_COM_NT_CREATE_ANDX:
-                        case SMB_COM_CLOSE:
-                        case SMB_COM_WRITE:
-                        case SMB_COM_READ_ANDX:
-                            com_func = smb_com_funcs[com];
-                            break;
-                        default:
-                            break;
-                        }
-                        break;
-                    case SMB_ANDX_COM__OPEN_ANDX:
-                        switch (com)
-                        {
-                        case SMB_COM_SESSION_SETUP_ANDX:
-                        case SMB_COM_LOGOFF_ANDX:
-                        case SMB_COM_TREE_CONNECT:
-                        case SMB_COM_TREE_CONNECT_ANDX:
-                        case SMB_COM_TREE_DISCONNECT:
-                        case SMB_COM_OPEN_ANDX:
-                        case SMB_COM_NT_CREATE_ANDX:
-                        case SMB_COM_CLOSE:
-                        case SMB_COM_WRITE:
-                        case SMB_COM_READ_ANDX:
-                            com_func = smb_com_funcs[com];
-                            break;
-                        default:
-                            break;
-                        }
-                        break;
-                    case SMB_ANDX_COM__NT_CREATE_ANDX:
-                        switch (com)
-                        {
-                        case SMB_COM_SESSION_SETUP_ANDX:
-                        case SMB_COM_TREE_CONNECT:
-                        case SMB_COM_TREE_CONNECT_ANDX:
-                        case SMB_COM_OPEN_ANDX:
-                        case SMB_COM_NT_CREATE_ANDX:
-                        case SMB_COM_WRITE:
-                        case SMB_COM_READ_ANDX:
-                            com_func = smb_com_funcs[com];
-                            break;
-                        case SMB_COM_LOGOFF_ANDX:
-                        case SMB_COM_TREE_DISCONNECT:
-                        case SMB_COM_CLOSE:
-                            if ((policy == DCE2_POLICY__SAMBA)
-                                || (policy == DCE2_POLICY__SAMBA_3_0_37))
-                                com_func = smb_com_funcs[com];
-                            break;
-                        default:
-                            break;
-                        }
-                        break;
-                    case SMB_ANDX_COM__WRITE_ANDX:
-                        switch (com)
-                        {
-                        case SMB_COM_SESSION_SETUP_ANDX:
-                        case SMB_COM_LOGOFF_ANDX:
-                        case SMB_COM_TREE_CONNECT:
-                        case SMB_COM_TREE_CONNECT_ANDX:
-                        case SMB_COM_OPEN_ANDX:
-                        case SMB_COM_NT_CREATE_ANDX:
-                        case SMB_COM_CLOSE:
-                        case SMB_COM_WRITE:
-                        case SMB_COM_READ_ANDX:
-                        case SMB_COM_WRITE_ANDX:
-                            com_func = smb_com_funcs[com];
-                            break;
-                        default:
-                            break;
-                        }
-                        break;
-                    case SMB_ANDX_COM__READ_ANDX:
-                        switch (com)
-                        {
-                        case SMB_COM_SESSION_SETUP_ANDX:
-                        case SMB_COM_WRITE:
-                            com_func = smb_com_funcs[com];
-                            break;
-                        case SMB_COM_LOGOFF_ANDX:
-                        case SMB_COM_TREE_CONNECT:
-                        case SMB_COM_TREE_CONNECT_ANDX:
-                        case SMB_COM_TREE_DISCONNECT:
-                        case SMB_COM_OPEN_ANDX:
-                        case SMB_COM_NT_CREATE_ANDX:
-                        case SMB_COM_CLOSE:
-                        case SMB_COM_READ_ANDX:
-                            if ((policy == DCE2_POLICY__SAMBA)
-                                || (policy == DCE2_POLICY__SAMBA_3_0_37))
-                                com_func = smb_com_funcs[com];
-                            break;
-                        default:
-                            break;
-                        }
-                        break;
-                    default:
-                        break;
+                        DCE2_BufferEmpty(ftracker->fp_writex_raw->buf);
+                        return DCE2_RET__ERROR;
                     }
+
+                    DebugMessage(DEBUG_DCE_SMB,
+                                "Reassembled WriteAndX raw mode request\n"));
+                    DCE2_DEBUG_CODE(DCE2_DEBUG__MAIN, DCE2_PrintPktData(rpkt->payload, rpkt->payload_size););
+
+                    (void)DCE2_SmbProcessRequestData(ssd, fid, data_ptr, data_len, 0);
+
+                    DCE2_SmbReturnRpkt();
+                    DCE2_BufferEmpty(ftracker->fp_writex_raw->buf);
+*/
+            }
+        }
+        else
+        {
+            (void)DCE2_SmbProcessRequestData(ssd, fid, nb_ptr, dcnt, 0);
+        }
+
+        // Windows doesn't process chained commands to raw WriteAndXs
+        // so return error so it exits the loop.
+        return DCE2_RET__ERROR;
+
+    case DCE2_POLICY__SAMBA:
+    case DCE2_POLICY__SAMBA_3_0_37:
+    case DCE2_POLICY__SAMBA_3_0_22:
+    case DCE2_POLICY__SAMBA_3_0_20:
+        // All Samba cares about is skipping the 2 byte "length"
+        // if both flags are set.
+        break;
+    default:
+        DebugFormat(DEBUG_DCE_SMB, "%s(%d) Invalid policy: %d",
+            __FILE__, __LINE__, policy);
+        break;
+    }
+
+    return DCE2_SmbProcessRequestData(ssd, fid, nb_ptr, dcnt, 0);
+}
+
+// SMB_COM_SESSION_SETUP_ANDX
+static DCE2_Ret DCE2_SmbSessionSetupAndX(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
+    const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t)
+{
+    if (!DCE2_ComInfoCanProcessCommand(com_info))
+        return DCE2_RET__ERROR;
+
+    if (DCE2_ComInfoIsRequest(com_info))
+    {
+        uint16_t max_multiplex =
+            SmbSessionSetupAndXReqMaxMultiplex((SmbLm10_SessionSetupAndXReq*)nb_ptr);
+
+        if (max_multiplex < ssd->max_outstanding_requests)
+            ssd->max_outstanding_requests = max_multiplex;
+
+        // FIXIT-M port fingerprint related code
+    }
+    else
+    {
+        uint16_t uid = SmbUid(smb_hdr);
+
+        DCE2_SmbInsertUid(ssd, uid);
+        ssd->cur_rtracker->uid = uid;  // Set this in case there are chained commands
+
+        if (!(ssd->ssn_state_flags & DCE2_SMB_SSN_STATE__NEGOTIATED))
+            ssd->ssn_state_flags |= DCE2_SMB_SSN_STATE__NEGOTIATED;
+
+        // FIXIT-M port fingerprint related code
+    }
+
+    return DCE2_RET__SUCCESS;
+}
+
+// SMB_COM_NEGOTIATE
+static DCE2_Ret DCE2_SmbNegotiate(DCE2_SmbSsnData* ssd, const SmbNtHdr*,
+    const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t)
+{
+    if (!DCE2_ComInfoCanProcessCommand(com_info))
+        return DCE2_RET__ERROR;
+
+    Profile profile(dce2_smb_pstat_smb_negotiate);
+
+    if (DCE2_ComInfoIsRequest(com_info))
+    {
+        // FIXIT-M add dialect related code
+    }
+    else
+    {
+        // FIXIT-M add dialect related code
+
+        ssd->ssn_state_flags |= DCE2_SMB_SSN_STATE__NEGOTIATED;
+
+        if (DCE2_ComInfoWordCount(com_info) == 17)
+        {
+            ssd->max_outstanding_requests =
+                SmbNt_NegotiateRespMaxMultiplex((SmbNt_NegotiateProtocolResp*)nb_ptr);
+        }
+        else if (DCE2_ComInfoWordCount(com_info) == 13)
+        {
+            ssd->max_outstanding_requests =
+                SmbLm_NegotiateRespMaxMultiplex((SmbLm10_NegotiateProtocolResp*)nb_ptr);
+        }
+        else
+        {
+            ssd->max_outstanding_requests = 1;
+        }
+    }
+
+    return DCE2_RET__SUCCESS;
+}
+
+// SMB_COM_TREE_CONNECT_ANDX
+
+#define SERVICE_0     (0)                // IPC start
+#define SERVICE_1     (SERVICE_0+4)      // DISK start
+#define SERVICE_FS    (SERVICE_1+3)      // Failure
+#define SERVICE_IPC   (SERVICE_FS+1)     // IPC service
+#define SERVICE_DISK  (SERVICE_FS+2)     // DISK service
+
+static const DCE2_SmbFsm dce2_smb_service_fsm[] =
+{
+    // IPC
+    { 'I',  SERVICE_0+1, SERVICE_1 },
+    { 'P',  SERVICE_0+2, SERVICE_FS },
+    { 'C',  SERVICE_0+3, SERVICE_FS },
+    { '\0', SERVICE_IPC, SERVICE_FS },
+
+    // DISK
+    { 'A',  SERVICE_1+1, SERVICE_FS },
+    { ':',  SERVICE_1+2, SERVICE_FS },
+    { '\0', SERVICE_DISK, SERVICE_FS },
+
+    { 0, SERVICE_FS, SERVICE_FS }
+};
+
+static DCE2_Ret DCE2_SmbTreeConnectAndX(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
+    const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
+{
+    uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
+
+    if (!DCE2_ComInfoCanProcessCommand(com_info))
+        return DCE2_RET__ERROR;
+
+    if (DCE2_ComInfoIsRequest(com_info))
+    {
+        if (DCE2_ScSmbInvalidShares((dce2SmbProtoConf*)ssd->sd.config) != nullptr)
+        {
+            uint16_t pass_len = SmbTreeConnectAndXReqPassLen((SmbTreeConnectAndXReq*)nb_ptr);
+            DCE2_MOVE(nb_ptr, nb_len, com_size);
+            if (pass_len >= nb_len)
+                return DCE2_RET__ERROR;
+
+            // Move past password length
+            DCE2_MOVE(nb_ptr, nb_len, pass_len);
+
+            const uint8_t* bs = nullptr;
+            // Move past path components
+            while ((bs = (const uint8_t*)memchr(nb_ptr, '\\', nb_len)) != nullptr)
+                DCE2_MOVE(nb_ptr, nb_len, (bs - nb_ptr) + 1);
+
+            // Move past NULL byte if unicode
+            if (SmbUnicode(smb_hdr) && (nb_len != 0))
+                DCE2_MOVE(nb_ptr, nb_len, 1);
+
+            if (nb_len != 0)
+                DCE2_SmbInvalidShareCheck(ssd, smb_hdr, nb_ptr, nb_len);
+        }
+    }
+    else
+    {
+        DCE2_MOVE(nb_ptr, nb_len, com_size);
+
+        int state = SERVICE_0;
+        while ((nb_len > 0) && (state < SERVICE_FS))
+        {
+            if (dce2_smb_service_fsm[state].input == (char)*nb_ptr)
+            {
+                state = dce2_smb_service_fsm[state].next_state;
+                DCE2_MOVE(nb_ptr, nb_len, 1);
+            }
+            else
+            {
+                state = dce2_smb_service_fsm[state].fail_state;
+            }
+        }
+
+        uint16_t tid = SmbTid(smb_hdr);
+        bool is_ipc = true;
+        switch (state)
+        {
+        case SERVICE_IPC:
+            DebugFormat(DEBUG_DCE_SMB,
+                "Tid (%u) is an IPC tree.\n", tid);
+            break;
+        case SERVICE_DISK:
+            is_ipc = false;
+            DebugFormat(DEBUG_DCE_SMB,
+                "Tid (%u) is a DISK tree.\n", tid);
+            break;
+        default:
+            return DCE2_RET__IGNORE;
+        }
+
+        // Insert tid into list
+        DCE2_SmbInsertTid(ssd, tid, is_ipc);
+        ssd->cur_rtracker->tid = tid;  // Set this in case there are chained commands
+    }
+
+    return DCE2_RET__SUCCESS;
+}
+
+#define SHARE_0     (0)
+#define SHARE_FS    (SHARE_0+5)
+#define SHARE_IPC   (SHARE_FS+1)
+
+static const DCE2_SmbFsm dce2_ipc_share_fsm[] =
+{
+    { 'I', SHARE_0+1, SHARE_FS },
+    { 'P', SHARE_0+2, SHARE_FS },
+    { 'C', SHARE_0+3, SHARE_FS },
+    { '$', SHARE_0+4, SHARE_FS },
+    { '\0', SHARE_IPC, SHARE_FS },
+
+    { 0, SHARE_FS, SHARE_FS }
+};
+
+// SMB_COM_TREE_CONNECT
+static DCE2_Ret DCE2_SmbTreeConnect(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
+    const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
+{
+    if (!DCE2_ComInfoCanProcessCommand(com_info))
+        return DCE2_RET__ERROR;
+
+    if (DCE2_ComInfoIsRequest(com_info))
+    {
+        uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
+
+        // Have at least 4 bytes of data based on byte count check done earlier
+
+        DCE2_MOVE(nb_ptr, nb_len, com_size);
+
+        // If unicode flag is set, strings, except possibly the service string
+        // are going to be unicode.  The NT spec specifies that unicode strings
+        // must be word aligned with respect to the beginning of the SMB and that for
+        // type-prefixed strings (this case), the padding byte is found after the
+        // type format byte.
+
+        // This byte will realign things.
+        if (*nb_ptr != SMB_FMT__ASCII)
+        {
+            dce_alert(GID_DCE2, DCE2_SMB_BAD_FORM, (dce2CommonStats*)&dce2_smb_stats);
+            return DCE2_RET__ERROR;
+        }
+
+        DCE2_MOVE(nb_ptr, nb_len, 1);
+
+        // IPC$ does not need to be case sensitive.  And the case sensitivity flag in
+        // the SMB header doesn't seem to have any effect on this.
+        const uint8_t* bs = nullptr;
+        while ((bs = (const uint8_t*)memchr(nb_ptr, '\\', nb_len)) != nullptr)
+            DCE2_MOVE(nb_ptr, nb_len, (bs - nb_ptr) + 1);
+
+        bool unicode = SmbUnicode(smb_hdr);
+        if (unicode && (nb_len > 0))
+            DCE2_MOVE(nb_ptr, nb_len, 1);
+
+        // Check for invalid shares first
+        if ((DCE2_ScSmbInvalidShares((dce2SmbProtoConf*)ssd->sd.config) != nullptr) && (nb_len >
+            0))
+            DCE2_SmbInvalidShareCheck(ssd, smb_hdr, nb_ptr, nb_len);
+
+        int state = SHARE_0;
+        uint8_t increment = unicode ? 2 : 1;
+        while ((nb_len >= increment) && (state < SHARE_FS))
+        {
+            if (dce2_ipc_share_fsm[state].input == toupper((int)nb_ptr[0]))
+            {
+                if (unicode && (nb_ptr[1] != 0))
                     break;
-                default:
-                    break;
-                }
+                state = dce2_ipc_share_fsm[state].next_state;
+                DCE2_MOVE(nb_ptr, nb_len, increment);
+            }
+            else
+            {
+                state = dce2_ipc_share_fsm[state].fail_state;
+            }
+        }
+
+        bool is_ipc = false;
+        switch (state)
+        {
+        case SHARE_IPC:
+            is_ipc = true;
+            break;
+        case SHARE_FS:
+        default:
+            break;
+        }
+
+        ssd->cur_rtracker->is_ipc = is_ipc;
+    }
+    else
+    {
+        // FIXIT-L What if the TID in the SMB header differs from that returned
+        // in the TreeConnect command response?
+        uint16_t tid = SmbTid(smb_hdr);
+        DCE2_SmbInsertTid(ssd, tid, ssd->cur_rtracker->is_ipc);
+
+        DebugFormat(DEBUG_DCE_SMB, "Tid (%u) %s an IPC tree\n", tid,
+            (ssd->cur_rtracker->is_ipc) ? "is" : "is not");
+    }
+
+    return DCE2_RET__SUCCESS;
+}
+
+// SMB_COM_NT_CREATE_ANDX
+static DCE2_Ret DCE2_SmbNtCreateAndX(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
+    const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
+{
+    if (!DCE2_ComInfoCanProcessCommand(com_info))
+        return DCE2_RET__ERROR;
+
+    if (DCE2_ComInfoIsResponse(com_info))
+    {
+        const uint16_t fid = SmbNtCreateAndXRespFid((SmbNtCreateAndXResp*)nb_ptr);
+        DCE2_SmbFileTracker* ftracker = nullptr;
+
+        // Set request tracker's current file tracker in case of chained commands
+        switch (SmbAndXCom2((SmbAndXCommon*)nb_ptr))
+        {
+        // This is in case in the request a write was chained to an open
+        // in which case the write will be to the newly opened file
+        case SMB_COM_WRITE:
+        case SMB_COM_WRITE_ANDX:
+        case SMB_COM_TRANSACTION:
+        case SMB_COM_READ_ANDX:
+            ftracker = DCE2_SmbDequeueTmpFileTracker(ssd, ssd->cur_rtracker, fid);
+            break;
+        default:
+            break;
+        }
+
+        if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid))
+        {
+            const bool is_directory = SmbNtCreateAndXRespDirectory((SmbNtCreateAndXResp*)nb_ptr);
+            const uint16_t resource_type =
+                SmbNtCreateAndXRespResourceType((SmbNtCreateAndXResp*)nb_ptr);
+
+            if (is_directory || !SmbResourceTypeDisk(resource_type))
+            {
+                if (ftracker != nullptr)
+                    DCE2_SmbRemoveFileTracker(ssd, ftracker);
+                return DCE2_RET__SUCCESS;
+            }
+
+            // Give preference to files opened with the sequential only flag set
+// FIXIT-M uncomment once fileApi is ported
+/*
+            if (((ssd->fapi_ftracker == nullptr) || !ssd->fapi_ftracker->ff_sequential_only)
+                    && (ftracker == nullptr) && ssd->cur_rtracker->sequential_only)
+            {
+                DCE2_SmbAbortFileAPI(ssd);
+            }
+*/
+        }
+
+        if (ftracker == nullptr)
+        {
+            ftracker = DCE2_SmbNewFileTracker(ssd,
+                ssd->cur_rtracker->uid, ssd->cur_rtracker->tid, fid);
+            if (ftracker == nullptr)
+                return DCE2_RET__ERROR;
+        }
+
+        ftracker->file_name = ssd->cur_rtracker->file_name;
+        ssd->cur_rtracker->file_name = nullptr;
+
+        DebugFormat(DEBUG_DCE_SMB, "File name: %s\n",
+            (ftracker->file_name == nullptr) ? "nullptr" : ftracker->file_name);
+
+        if (!ftracker->is_ipc)
+        {
+            const uint32_t create_disposition =
+                SmbNtCreateAndXRespCreateDisposition((SmbNtCreateAndXResp*)nb_ptr);
+
+            if (SmbCreateDispositionRead(create_disposition))
+            {
+                ftracker->ff_file_size =
+                    SmbNtCreateAndXRespEndOfFile((SmbNtCreateAndXResp*)nb_ptr);
+            }
+            else
+            {
+                ftracker->ff_file_size = ssd->cur_rtracker->file_size;
+                ftracker->ff_file_direction = DCE2_SMB_FILE_DIRECTION__UPLOAD;
+            }
+
+            ftracker->ff_sequential_only = ssd->cur_rtracker->sequential_only;
+        }
+
+        ssd->cur_rtracker->ftracker = ftracker;
+    }
+    else
+    {
+        bool is_ipc = DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid);
+        uint8_t smb_com2 = SmbAndXCom2((SmbAndXCommon*)nb_ptr);
+        uint16_t file_name_length =
+            SmbNtCreateAndXReqFileNameLen((SmbNtCreateAndXReq*)nb_ptr);
+
+        if (!is_ipc)
+        {
+            uint32_t ext_file_attrs =
+                SmbNtCreateAndXReqFileAttrs((SmbNtCreateAndXReq*)nb_ptr);
+
+            if (SmbEvasiveFileAttrs(ext_file_attrs))
+                dce_alert(GID_DCE2, DCE2_SMB_EVASIVE_FILE_ATTRS,
+                    (dce2CommonStats*)&dce2_smb_stats);
+            // If the file is going to be accessed sequentially, track it.
+            if (SmbNtCreateAndXReqSequentialOnly((SmbNtCreateAndXReq*)nb_ptr))
+                ssd->cur_rtracker->sequential_only = true;
+
+            ssd->cur_rtracker->file_size = SmbNtCreateAndXReqAllocSize(
+                (SmbNtCreateAndXReq*)nb_ptr);
+        }
+
+        DCE2_MOVE(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info));
+
+        if (file_name_length > DCE2_SMB_MAX_PATH_LEN)
+            return DCE2_RET__ERROR;
+
+        uint32_t pad = 0;
+        const bool unicode = SmbUnicode(smb_hdr);
+        if (unicode)
+            pad = (nb_ptr - (const uint8_t*)smb_hdr) & 1;
+
+        if (nb_len < (pad + file_name_length))
+            return DCE2_RET__ERROR;
+
+        DCE2_MOVE(nb_ptr, nb_len, pad);
+
+        // Samba allows chaining OpenAndX/NtCreateAndX so might have
+        // already been set.
+        if (ssd->cur_rtracker->file_name == nullptr)
+        {
+            ssd->cur_rtracker->file_name =
+                DCE2_SmbGetString(nb_ptr, file_name_length, unicode, false);
+        }
+
+        if (is_ipc)
+        {
+            switch (smb_com2)
+            {
+            case SMB_COM_READ_ANDX:
+                if (DCE2_SsnIsWindowsPolicy(&ssd->sd))
+                    return DCE2_RET__ERROR;
+                break;
+            default:
+                break;
+            }
+        }
+    }
+
+    return DCE2_RET__SUCCESS;
+}
+
+// SMB_COM_TREE_DISCONNECT
+static DCE2_Ret DCE2_SmbTreeDisconnect(DCE2_SmbSsnData* ssd, const SmbNtHdr*,
+    const DCE2_SmbComInfo* com_info, const uint8_t*, uint32_t)
+{
+    if (!DCE2_ComInfoCanProcessCommand(com_info))
+        return DCE2_RET__ERROR;
+
+    if (DCE2_ComInfoIsResponse(com_info))
+        DCE2_SmbRemoveTid(ssd, ssd->cur_rtracker->tid);
+
+    return DCE2_RET__SUCCESS;
+}
+
+// SMB_COM_LOGOFF_ANDX
+static DCE2_Ret DCE2_SmbLogoffAndX(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
+    const DCE2_SmbComInfo* com_info, const uint8_t*, uint32_t)
+{
+    if (!DCE2_ComInfoCanProcessCommand(com_info))
+        return DCE2_RET__ERROR;
+
+    if (DCE2_ComInfoIsResponse(com_info))
+    {
+        DCE2_SmbRemoveUid(ssd, ssd->cur_rtracker->uid);
+
+        switch (DCE2_SsnGetServerPolicy(&ssd->sd))
+        {
+        case DCE2_POLICY__WIN2000:
+        case DCE2_POLICY__WINXP:
+        case DCE2_POLICY__WINVISTA:
+        case DCE2_POLICY__WIN2003:
+        case DCE2_POLICY__WIN2008:
+        case DCE2_POLICY__WIN7:
+            /* Windows responds to a chained LogoffAndX => SessionSetupAndX with a
+             * word count 3 LogoffAndX without the chained SessionSetupAndX */
+            if (DCE2_ComInfoWordCount(com_info) == 3)
+            {
+                uint16_t uid = SmbUid(smb_hdr);
+                DCE2_SmbInsertUid(ssd, uid);
+                ssd->cur_rtracker->uid = uid;      // Set this in case there are chained commands
+            }
+            break;
+        default:
+            break;
+        }
+    }
+
+    return DCE2_RET__SUCCESS;
+}
+
+// SMB_COM_TRANSACTION Request
+static DCE2_Ret DCE2_SmbTransactionReq(DCE2_SmbSsnData* ssd,
+    DCE2_SmbTransactionTracker* ttracker,
+    const uint8_t* data_ptr, uint32_t data_len,
+    const uint8_t* param_ptr, uint32_t param_len)
+{
+    switch (ttracker->subcom)
+    {
+    case TRANS_TRANSACT_NMPIPE:
+    case TRANS_WRITE_NMPIPE:
+        if (DCE2_SmbProcessRequestData(ssd, 0,
+            data_ptr, data_len, 0) != DCE2_RET__SUCCESS)
+            return DCE2_RET__ERROR;
+        break;
+
+    case TRANS_SET_NMPIPE_STATE:
+        // Only two parameters but more seems okay
+        if (param_len >= 2)
+        {
+            if ((alignedNtohs((uint16_t*)param_ptr) & PIPE_STATE_MESSAGE_MODE))
+                ttracker->pipe_byte_mode = false;
+            else
+                ttracker->pipe_byte_mode = true;
+
+            // Won't get a response
+            if (DCE2_SsnIsWindowsPolicy(&ssd->sd) && ttracker->one_way)
+            {
+                DebugFormat(DEBUG_DCE_SMB,
+                    "Setting pipe to %s mode\n",
+                    ttracker->pipe_byte_mode ? "byte" : "message");
+
+                ssd->cur_rtracker->ftracker->fp_byte_mode = ttracker->pipe_byte_mode;
+            }
+        }
+        break;
+
+    case TRANS_READ_NMPIPE:
+        break;
+
+    default:
+        return DCE2_RET__IGNORE;
+    }
+
+    if (DCE2_SsnIsWindowsPolicy(&ssd->sd) && ttracker->one_way && ttracker->disconnect_tid)
+        DCE2_SmbRemoveTid(ssd, ssd->cur_rtracker->tid);
+
+    return DCE2_RET__SUCCESS;
+}
+
+// SMB_COM_TRANSACTION
+
+#define TRANS_NM_PIPE_0       (0)
+#define TRANS_NM_PIPE_1       (TRANS_NM_PIPE_0+7)
+#define TRANS_NM_PIPE_2       (TRANS_NM_PIPE_1+1)
+#define TRANS_NM_PIPE_3       (TRANS_NM_PIPE_2+1)
+#define TRANS_NM_PIPE_4       (TRANS_NM_PIPE_3+5)
+#define TRANS_NM_PIPE_5       (TRANS_NM_PIPE_4+5)
+#define TRANS_NM_PIPE_6       (TRANS_NM_PIPE_5+1)
+#define TRANS_NM_PIPE_7       (TRANS_NM_PIPE_6+5)
+#define TRANS_NM_PIPE_8       (TRANS_NM_PIPE_7+3)
+#define TRANS_NM_PIPE_9       (TRANS_NM_PIPE_8+6)
+#define TRANS_NM_PIPE_FS      (TRANS_NM_PIPE_9+1)
+#define TRANS_NM_PIPE_DONE    (TRANS_NM_PIPE_FS+1)
+
+static const DCE2_SmbFsm dce2_samba_pipe_fsm[] =
+{
+    // Normal sequence
+    { '\\', TRANS_NM_PIPE_0+1, TRANS_NM_PIPE_FS },
+    { 'P', TRANS_NM_PIPE_0+2, TRANS_NM_PIPE_FS },
+    { 'I', TRANS_NM_PIPE_0+3, TRANS_NM_PIPE_FS },
+    { 'P', TRANS_NM_PIPE_0+4, TRANS_NM_PIPE_FS },
+    { 'E', TRANS_NM_PIPE_0+5, TRANS_NM_PIPE_FS },
+    { '\\', TRANS_NM_PIPE_0+6, TRANS_NM_PIPE_1 },
+    { '\0', TRANS_NM_PIPE_DONE, TRANS_NM_PIPE_2 },
+
+    // Win98
+    { '\0', TRANS_NM_PIPE_DONE, TRANS_NM_PIPE_FS },
+
+    { 'W', TRANS_NM_PIPE_2+1, TRANS_NM_PIPE_5 },
+
+    { 'K', TRANS_NM_PIPE_3+1, TRANS_NM_PIPE_4 },
+    { 'S', TRANS_NM_PIPE_3+2, TRANS_NM_PIPE_FS },
+    { 'S', TRANS_NM_PIPE_3+3, TRANS_NM_PIPE_FS },
+    { 'V', TRANS_NM_PIPE_3+4, TRANS_NM_PIPE_FS },
+    { 'C', TRANS_NM_PIPE_9, TRANS_NM_PIPE_FS },
+
+    { 'I', TRANS_NM_PIPE_4+1, TRANS_NM_PIPE_FS },
+    { 'N', TRANS_NM_PIPE_4+2, TRANS_NM_PIPE_FS },
+    { 'R', TRANS_NM_PIPE_4+3, TRANS_NM_PIPE_FS },
+    { 'E', TRANS_NM_PIPE_4+4, TRANS_NM_PIPE_FS },
+    { 'G', TRANS_NM_PIPE_9, TRANS_NM_PIPE_FS },
+
+    { 'S', TRANS_NM_PIPE_5+1, TRANS_NM_PIPE_8 },
+
+    { 'R', TRANS_NM_PIPE_6+1, TRANS_NM_PIPE_5 },
+    { 'V', TRANS_NM_PIPE_6+2, TRANS_NM_PIPE_FS },
+    { 'S', TRANS_NM_PIPE_6+3, TRANS_NM_PIPE_FS },
+    { 'V', TRANS_NM_PIPE_6+4, TRANS_NM_PIPE_FS },
+    { 'C', TRANS_NM_PIPE_9, TRANS_NM_PIPE_FS },
+
+    { 'A', TRANS_NM_PIPE_7+1, TRANS_NM_PIPE_FS },
+    { 'M', TRANS_NM_PIPE_7+2, TRANS_NM_PIPE_FS },
+    { 'R', TRANS_NM_PIPE_9, TRANS_NM_PIPE_FS },
+
+    { 'L', TRANS_NM_PIPE_8+1, TRANS_NM_PIPE_FS },
+    { 'S', TRANS_NM_PIPE_8+2, TRANS_NM_PIPE_FS },
+    { 'A', TRANS_NM_PIPE_8+3, TRANS_NM_PIPE_FS },
+    { 'R', TRANS_NM_PIPE_8+4, TRANS_NM_PIPE_FS },
+    { 'P', TRANS_NM_PIPE_8+5, TRANS_NM_PIPE_FS },
+    { 'C', TRANS_NM_PIPE_9, TRANS_NM_PIPE_FS },
+
+    { '\0', TRANS_NM_PIPE_DONE, TRANS_NM_PIPE_FS },
+
+    { 0, TRANS_NM_PIPE_FS, TRANS_NM_PIPE_FS }
+};
+
+// Validates Name for Samba Transaction requests
+static DCE2_Ret DCE2_SmbTransactionGetName(const uint8_t* nb_ptr,
+    uint32_t nb_len, uint16_t bcc, bool unicode)
+{
+    if ((nb_len == 0) || (bcc == 0))
+        return DCE2_RET__ERROR;
+
+    if (bcc < nb_len)
+        nb_len = bcc;
+
+    if (unicode)
+        DCE2_MOVE(nb_ptr, nb_len, 1);  // One byte pad for unicode
+
+    uint8_t increment = unicode ? 2 : 1;
+    int state = TRANS_NM_PIPE_0;
+    while ((nb_len >= increment) && (state < TRANS_NM_PIPE_FS))
+    {
+        if (dce2_samba_pipe_fsm[state].input == toupper((int)nb_ptr[0]))
+        {
+            if (unicode && (nb_ptr[1] != 0))
+                break;
+            state = dce2_samba_pipe_fsm[state].next_state;
+            DCE2_MOVE(nb_ptr, nb_len, increment);
+        }
+        else
+        {
+            state = dce2_samba_pipe_fsm[state].fail_state;
+        }
+    }
+
+    switch (state)
+    {
+    case TRANS_NM_PIPE_DONE:
+        break;
+    case TRANS_NM_PIPE_FS:
+    default:
+        return DCE2_RET__ERROR;
+    }
+
+    return DCE2_RET__SUCCESS;
+}
+
+static DCE2_Ret DCE2_SmbTransaction(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
+    const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
+{
+    uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
+    DCE2_SmbTransactionTracker* ttracker = &ssd->cur_rtracker->ttracker;
+
+    // Got a matching request for an in progress transaction - don't process it,
+    // but don't want to remove tracker.
+    if (DCE2_ComInfoIsRequest(com_info)
+        && !DCE2_SmbIsTransactionComplete(ttracker))
+    {
+        DebugMessage(DEBUG_DCE_SMB, "Got new transaction request "
+            "that matches an in progress transaction - not inspecting.\n");
+        return DCE2_RET__ERROR;
+    }
+
+    // Avoid decoding/tracking \PIPE\LANMAN requests
+    if (DCE2_ComInfoIsRequest(com_info)
+        && (DCE2_ComInfoWordCount(com_info) != 16))
+    {
+        DebugMessage(DEBUG_DCE_SMB, "\\PIPE\\LANMAN request - not inspecting\n");
+        return DCE2_RET__IGNORE;
+    }
+
+    if (!DCE2_ComInfoCanProcessCommand(com_info))
+        return DCE2_RET__ERROR;
+
+    // Interim response is sent if client didn't send all data / parameters
+    // in initial Transaction request and will have to complete the request
+    // with TransactionSecondary commands.
+    if (DCE2_ComInfoIsResponse(com_info)
+        && (com_size == sizeof(SmbTransactionInterimResp)))
+    {
+        DebugMessage(DEBUG_DCE_SMB,
+            "  Server Transaction interim response.\n");
+
+        return DCE2_RET__SUCCESS;
+    }
+
+    if (DCE2_ComInfoIsRequest(com_info))
+    {
+        DCE2_Ret status =
+            DCE2_SmbUpdateTransRequest(ssd, smb_hdr, com_info, nb_ptr, nb_len);
+
+        if (status != DCE2_RET__FULL)
+            return status;
+
+        ttracker->disconnect_tid = SmbTransactionReqDisconnectTid((SmbTransactionReq*)nb_ptr);
+        ttracker->one_way = SmbTransactionReqOneWay((SmbTransactionReq*)nb_ptr);
+
+        uint16_t doff = SmbTransactionReqDataOff((SmbTransactionReq*)nb_ptr);
+        uint16_t dcnt = SmbTransactionReqDataCnt((SmbTransactionReq*)nb_ptr);
+        uint16_t pcnt = SmbTransactionReqParamCnt((SmbTransactionReq*)nb_ptr);
+        uint16_t poff = SmbTransactionReqParamOff((SmbTransactionReq*)nb_ptr);
+
+        DCE2_MOVE(nb_ptr, nb_len, ((uint8_t*)smb_hdr + doff) - nb_ptr);
+        const uint8_t* data_ptr = nb_ptr;
 
-                smb_chain_funcs[policy][andx][com] = com_func;
+        DCE2_MOVE(nb_ptr, nb_len, ((uint8_t*)smb_hdr + poff) - nb_ptr);
+        const uint8_t* param_ptr = nb_ptr;
+
+        status = DCE2_SmbTransactionReq(ssd, ttracker, data_ptr, dcnt, param_ptr, pcnt);
+        if (status != DCE2_RET__SUCCESS)
+            return status;
+    }
+    else
+    {
+        DCE2_Ret status =
+            DCE2_SmbUpdateTransResponse(ssd, smb_hdr, com_info, nb_ptr, nb_len);
+
+        if (status != DCE2_RET__FULL)
+            return status;
+
+        switch (ttracker->subcom)
+        {
+        case TRANS_TRANSACT_NMPIPE:
+        case TRANS_READ_NMPIPE:
+        {
+            // FIXIT-M port reassembly case
+
+            uint16_t dcnt = SmbTransactionRespDataCnt((SmbTransactionResp*)nb_ptr);
+            uint16_t doff = SmbTransactionRespDataOff((SmbTransactionResp*)nb_ptr);
+
+            DCE2_MOVE(nb_ptr, nb_len, ((uint8_t*)smb_hdr + doff) - nb_ptr);
+
+            if (DCE2_SmbProcessResponseData(ssd, nb_ptr, dcnt) != DCE2_RET__SUCCESS)
+                return DCE2_RET__ERROR;
+
+            break;
+        }
+        case TRANS_SET_NMPIPE_STATE:
+            DebugFormat(DEBUG_DCE_SMB, "Setting pipe "
+                "to %s mode\n", ttracker->pipe_byte_mode ? "byte" : "message");
+            ssd->cur_rtracker->ftracker->fp_byte_mode = ttracker->pipe_byte_mode;
+            break;
+
+        case TRANS_WRITE_NMPIPE:
+            break;
+
+        default:
+            return DCE2_RET__ERROR;
+        }
+
+        if (ttracker->disconnect_tid)
+            DCE2_SmbRemoveTid(ssd, ssd->cur_rtracker->tid);
+    }
+
+    return DCE2_RET__SUCCESS;
+}
+
+#define DCE2_SMB_TRANS__NONE    0x00
+#define DCE2_SMB_TRANS__DATA    0x01
+#define DCE2_SMB_TRANS__PARAMS  0x02
+#define DCE2_SMB_TRANS__BOTH    (DCE2_SMB_TRANS__DATA|DCE2_SMB_TRANS__PARAMS)
+
+/********************************************************************
+ * Function: DCE2_SmbUpdateTransRequest()
+ *
+ * Purpose:
+ *  Handles common checks and updates of transaction requests -
+ *  SMB_COM_TRANSACTION, SMB_COM_TRANSACTION2 and SMB_COM_NT_TRANSACT
+ *
+ * Arguments:
+ *  DCE2_SmbSsnData *       - pointer to SMB session data
+ *  const SmbNtHdr *        - pointer to SMB header
+ *  const DCE2_SmbComInfo * - pointer to com info structure
+ *  const uint8_t *         - pointer to data
+ *  uint32_t                - data length
+ *
+ * Returns:
+ *  DCE2_Ret
+ *      DCE2_RET__IGNORE if we don't process the subcommand
+ *      DCE2_RET__FULL if the transaction is complete
+ *      DCE2_RET__ERROR if an error occurred.
+ *      DCE2_RET__SUCCESS if ok (but not complete).
+ *
+ ********************************************************************/
+static DCE2_Ret DCE2_SmbUpdateTransRequest(DCE2_SmbSsnData* ssd,
+    const SmbNtHdr* smb_hdr, const DCE2_SmbComInfo* com_info,
+    const uint8_t* nb_ptr, uint32_t nb_len)
+{
+    uint32_t tpcnt, pcnt, poff;
+    uint32_t tdcnt, dcnt, doff;
+    uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
+    uint16_t byte_count = DCE2_ComInfoByteCount(com_info);
+    uint16_t fid;
+    uint8_t setup_count;
+    DCE2_SmbTransactionTracker* ttracker = &ssd->cur_rtracker->ttracker;
+    uint16_t sub_com =0;
+    int data_params = DCE2_SMB_TRANS__NONE;
+    uint8_t smb_com = DCE2_ComInfoSmbCom(com_info);
+
+    //FIXIT-M init to avoid warnings. can be removed once other commands are supported
+    tpcnt =0; pcnt =0; poff =0;
+    tdcnt =0; dcnt =0; doff =0;
+
+    switch (smb_com)
+    {
+    case SMB_COM_TRANSACTION:
+        sub_com = SmbTransactionReqSubCom((SmbTransactionReq*)nb_ptr);
+        fid = SmbTransactionReqFid((SmbTransactionReq*)nb_ptr);
+        setup_count = SmbTransactionReqSetupCnt((SmbTransactionReq*)nb_ptr);
+        tdcnt = SmbTransactionReqTotalDataCnt((SmbTransactionReq*)nb_ptr);
+        doff = SmbTransactionReqDataOff((SmbTransactionReq*)nb_ptr);
+        dcnt = SmbTransactionReqDataCnt((SmbTransactionReq*)nb_ptr);
+        tpcnt = SmbTransactionReqTotalParamCnt((SmbTransactionReq*)nb_ptr);
+        pcnt = SmbTransactionReqParamCnt((SmbTransactionReq*)nb_ptr);
+        poff = SmbTransactionReqParamOff((SmbTransactionReq*)nb_ptr);
+
+        DebugFormat(DEBUG_DCE_SMB,
+            "Transaction subcommand: %s (0x%04X)\n",
+            (sub_com < TRANS_SUBCOM_MAX)
+            ? smb_transaction_sub_command_strings[sub_com]
+            : "Unknown", sub_com);
+
+        ssd->cur_rtracker->ftracker = DCE2_SmbGetFileTracker(ssd, fid);
+        if (ssd->cur_rtracker->ftracker == nullptr)
+            return DCE2_RET__IGNORE;
+
+        switch (sub_com)
+        {
+        case TRANS_TRANSACT_NMPIPE:
+            if (DCE2_SsnIsWindowsPolicy(&ssd->sd)
+                && ssd->cur_rtracker->ftracker->fp_byte_mode)
+            {
+                DebugMessage(DEBUG_DCE_SMB, "Pipe is in byte "
+                    "mode - TRANS_TRANSACT_NMPIPE won't work\n");
+                return DCE2_RET__ERROR;
             }
+            data_params = DCE2_SMB_TRANS__DATA;
+            break;
+
+        case TRANS_READ_NMPIPE:
+            dce_alert(GID_DCE2, DCE2_SMB_UNUSUAL_COMMAND_USED, (dce2CommonStats*)&dce2_smb_stats);
+            break;
+
+        case TRANS_SET_NMPIPE_STATE:
+            data_params = DCE2_SMB_TRANS__PARAMS;
+            break;
+
+        case TRANS_WRITE_NMPIPE:
+            dce_alert(GID_DCE2, DCE2_SMB_UNUSUAL_COMMAND_USED, (dce2CommonStats*)&dce2_smb_stats);
+            data_params = DCE2_SMB_TRANS__DATA;
+            break;
+
+        // Not implemented according to MS-CIFS
+        case TRANS_RAW_READ_NMPIPE:
+
+        // Can only write 2 NULL bytes and subsequent writes return pipe disconnected
+        case TRANS_RAW_WRITE_NMPIPE:
+
+        // Can at most do a DCE/RPC bind
+        case TRANS_CALL_NMPIPE:
+            dce_alert(GID_DCE2, DCE2_SMB_DEPR_COMMAND_USED, (dce2CommonStats*)&dce2_smb_stats);
+        // Aren't looking at these or the three above
+        case TRANS_QUERY_NMPIPE_STATE:
+        case TRANS_QUERY_NMPIPE_INFO:
+        case TRANS_PEEK_NMPIPE:
+        case TRANS_WAIT_NMPIPE:
+        default:
+            // Don't want to track the response
+            return DCE2_RET__IGNORE;
+        }
+
+        // Servers return error if incorrect setup count
+        if (setup_count != 2)
+        {
+            dce_alert(GID_DCE2, DCE2_SMB_INVALID_SETUP_COUNT, (dce2CommonStats*)&dce2_smb_stats);
+            return DCE2_RET__ERROR;
+        }
+
+        DCE2_MOVE(nb_ptr, nb_len, com_size);
+
+        // Samba validates the Name which should be \PIPE\ and errors
+        // if not.  Windows doesn't care.
+        // And Samba uses the ByteCount to validate
+        if (DCE2_SsnIsSambaPolicy(&ssd->sd)
+            && (DCE2_SmbTransactionGetName(nb_ptr, nb_len,
+            byte_count, SmbUnicode(smb_hdr)) != DCE2_RET__SUCCESS))
+        {
+            DebugMessage(DEBUG_DCE_SMB, "Failed to validate "
+                "pipe name for Samba.\n");
+            return DCE2_RET__ERROR;
+        }
+        break;
+
+    case SMB_COM_TRANSACTION2:
+        // FIXIT-M port together with transaction2
+
+        break;
+
+    case SMB_COM_NT_TRANSACT:
+        // FIXIT-M port together with nt_transact
+        break;
+
+    default:
+        return DCE2_RET__ERROR;
+    }
+
+    if (DCE2_SmbValidateTransactionFields((uint8_t*)smb_hdr, nb_ptr, nb_len,
+        byte_count, tdcnt, tpcnt, dcnt, doff, 0, pcnt, poff, 0) != DCE2_RET__SUCCESS)
+        return DCE2_RET__ERROR;
+
+    ttracker->smb_type = SMB_TYPE__REQUEST;
+    ttracker->subcom = (uint8_t)sub_com;
+    ttracker->tdcnt = tdcnt;
+    ttracker->dsent = dcnt;
+    ttracker->tpcnt = tpcnt;
+    ttracker->psent = pcnt;
+
+    DebugFormat(DEBUG_DCE_SMB, "Data count: %u, "
+        "Total data count: %u, Param count: %u, "
+        "Total param count: %u\n", dcnt, tdcnt, pcnt, tpcnt);
+
+    // Testing shows that Transacts aren't processed until
+    // all of the data and parameters are received, so overlapping
+    // writes to the same FID can occur as long as the pid/mid are
+    // distinct (and that depends on policy).  So we need to buffer
+    // data up for each incomplete Transact so data doesn't get mangled
+    // together with multiple ones intermixing at the same time.
+
+    if (data_params & DCE2_SMB_TRANS__DATA)
+    {
+        // FIXIT-M port
+    }
+
+    if (data_params & DCE2_SMB_TRANS__PARAMS)
+    {
+        // FIXIT-M port
+    }
+
+    if ((dcnt == tdcnt) && (pcnt == tpcnt))
+        return DCE2_RET__FULL;
+
+    return DCE2_RET__SUCCESS;
+}
+
+/********************************************************************
+ * Function: DCE2_SmbUpdateTransResponse()
+ *
+ * Purpose:
+ *  Handles common checks and updates of transaction responses -
+ *  SMB_COM_TRANSACTION, SMB_COM_TRANSACTION2 and SMB_COM_NT_TRANSACT
+ *
+ * Arguments:
+ *  DCE2_SmbSsnData *       - pointer to SMB session data
+ *  const SmbNtHdr *        - pointer to SMB header
+ *  const DCE2_SmbComInfo * - pointer to com info structure
+ *  const uint8_t *         - pointer to data
+ *  uint32_t                - data length
+ *
+ * Returns:
+ *  DCE2_Ret
+ *      DCE2_RET__FULL if the transaction is complete
+ *      DCE2_RET__ERROR if an error occurred.
+ *      DCE2_RET__SUCCESS if ok (but not complete).
+ *
+ ********************************************************************/
+static DCE2_Ret DCE2_SmbUpdateTransResponse(DCE2_SmbSsnData* ssd,
+    const SmbNtHdr* smb_hdr, const DCE2_SmbComInfo* com_info,
+    const uint8_t* nb_ptr, uint32_t nb_len)
+{
+    uint32_t tpcnt, pcnt, poff, pdisp;
+    uint32_t tdcnt, dcnt, doff, ddisp;
+    DCE2_SmbTransactionTracker* ttracker = &ssd->cur_rtracker->ttracker;
+    uint16_t sub_com = ttracker->subcom;
+    int data_params = DCE2_SMB_TRANS__NONE;
+    uint8_t smb_com = DCE2_ComInfoSmbCom(com_info);
+
+    //FIXIT-M init to avoid warnings. can be removed once other commands are supported
+    tpcnt =0; pcnt =0; poff =0; pdisp =0;
+    tdcnt =0; dcnt =0; doff =0; ddisp =0;
+    switch (smb_com)
+    {
+    case SMB_COM_TRANSACTION:
+        tdcnt = SmbTransactionRespTotalDataCnt((SmbTransactionResp*)nb_ptr);
+        doff = SmbTransactionRespDataOff((SmbTransactionResp*)nb_ptr);
+        dcnt = SmbTransactionRespDataCnt((SmbTransactionResp*)nb_ptr);
+        ddisp = SmbTransactionRespDataDisp((SmbTransactionResp*)nb_ptr);
+        tpcnt = SmbTransactionRespTotalParamCnt((SmbTransactionResp*)nb_ptr);
+        pcnt = SmbTransactionRespParamCnt((SmbTransactionResp*)nb_ptr);
+        poff = SmbTransactionRespParamOff((SmbTransactionResp*)nb_ptr);
+        pdisp = SmbTransactionRespParamDisp((SmbTransactionResp*)nb_ptr);
+
+        DebugFormat(DEBUG_DCE_SMB,
+            "Transaction subcommand: %s (0x%04X)\n",
+            (sub_com < TRANS_SUBCOM_MAX)
+            ? smb_transaction_sub_command_strings[sub_com]
+            : "Unknown", sub_com);
+
+        switch (sub_com)
+        {
+        case TRANS_TRANSACT_NMPIPE:
+        case TRANS_READ_NMPIPE:
+            data_params = DCE2_SMB_TRANS__DATA;
+            break;
+        case TRANS_SET_NMPIPE_STATE:
+        case TRANS_WRITE_NMPIPE:
+            data_params = DCE2_SMB_TRANS__PARAMS;
+            break;
+        default:
+            return DCE2_RET__ERROR;
+        }
+
+        break;
+
+    case SMB_COM_TRANSACTION2:
+        // FIXIT-M port along with transaction2
+
+        break;
+
+    case SMB_COM_NT_TRANSACT:
+        // FIXIT-M port along with NT_TRANSACT
+
+        break;
+
+    default:
+        return DCE2_RET__ERROR;
+    }
+
+    DCE2_MOVE(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info));
+
+    // From client request
+    if (ttracker->smb_type == SMB_TYPE__REQUEST)
+    {
+        ttracker->smb_type = SMB_TYPE__RESPONSE;
+        ttracker->tdcnt = tdcnt;
+        ttracker->tpcnt = tpcnt;
+        ttracker->dsent = 0;
+        ttracker->psent = 0;
+        DCE2_BufferDestroy(ttracker->dbuf);
+        ttracker->dbuf = nullptr;
+        DCE2_BufferDestroy(ttracker->pbuf);
+        ttracker->pbuf = nullptr;
+    }
+    else
+    {
+        if (tdcnt < ttracker->tdcnt)
+            ttracker->tdcnt = tdcnt;
+        if (tpcnt < ttracker->tpcnt)
+            ttracker->tpcnt = pcnt;
+    }
+
+    if (DCE2_SmbValidateTransactionFields((uint8_t*)smb_hdr, nb_ptr, nb_len,
+        DCE2_ComInfoByteCount(com_info), tdcnt, tpcnt, dcnt, doff, ddisp,
+        pcnt, poff, pdisp) != DCE2_RET__SUCCESS)
+        return DCE2_RET__ERROR;
+
+    if (DCE2_SmbValidateTransactionSent(ttracker->dsent, dcnt, ttracker->tdcnt,
+        ttracker->psent, pcnt, ttracker->tpcnt) != DCE2_RET__SUCCESS)
+        return DCE2_RET__ERROR;
+
+    ttracker->dsent += dcnt;
+    ttracker->psent += pcnt;
+
+    DebugFormat(DEBUG_DCE_SMB, "Data displacement: %u, "
+        "Data count: %u, Total data count: %u\n"
+        "Parameter displacement: %u, "
+        "Parameter count: %u, Total parameter count: %u\n",
+        ddisp, dcnt, tdcnt, pdisp, pcnt, tpcnt);
+
+    if (data_params & DCE2_SMB_TRANS__DATA)
+    {
+        // FIXIT-M port
+    }
+
+    if (data_params & DCE2_SMB_TRANS__PARAMS)
+    {
+        // FIXIT-M port
+    }
+
+    if ((ttracker->dsent == ttracker->tdcnt)
+        && (ttracker->psent == ttracker->tpcnt))
+    {
+        return DCE2_RET__FULL;
+    }
+
+    return DCE2_RET__SUCCESS;
+}
+
+/********************************************************************
+ * Function: DCE2_SmbCheckTotalCount()
+ *
+ * Purpose:
+ *  Validates the advertised total data/param count.  Makes sure the
+ *  current count isn't greater than total count, that the
+ *  displacement + count isn't greater than the total data count and
+ *  that the total data count isn't zero.  Mainly relevant to Write Raw,
+ *  Transaction and Transaction Secondary commands.
+ *
+ * Arguments:
+ *  const uint32_t    - total data count
+ *  const uint32_t    - data count/size
+ *  const uint32_t    - data displacement
+ *
+ * Returns:
+ *  DCE2_Ret - DCE2_RET__SUCCESS if all is ok
+ *             DCE2_RET__ERROR if any of the checks fail.
+ *
+ ********************************************************************/
+static DCE2_Ret DCE2_SmbCheckTotalCount(const uint32_t tcnt, const uint32_t cnt, const uint32_t
+    disp)
+{
+    DCE2_Ret ret = DCE2_RET__SUCCESS;
+
+    if (cnt > tcnt)
+    {
+        dce_alert(GID_DCE2, DCE2_SMB_TDCNT_LT_DSIZE, (dce2CommonStats*)&dce2_smb_stats);
+        ret = DCE2_RET__ERROR;
+    }
+
+    if (((uint64_t)disp + cnt) > tcnt)
+    {
+        dce_alert(GID_DCE2, DCE2_SMB_DSENT_GT_TDCNT, (dce2CommonStats*)&dce2_smb_stats);
+        ret = DCE2_RET__ERROR;
+    }
+
+    return ret;
+}
+
+/********************************************************************
+ * Function: DCE2_SmbCheckTransDataParams()
+ *
+ * Purpose:
+ *  Ensures that the data size reported in an SMB command is kosher.
+ *  Note the 32 bit values are because of the NtTransact command
+ *  though it's currently not checked.
+ *
+ * Arguments:
+ *  const uint8_t *   - pointer to start of SMB header where offset is
+ *                      taken from.
+ *  const uint8_t *   - current pointer - should be right after command
+ *                      structure.
+ *  const uint32_t    - remaining data left in PDU from current pointer.
+ *  const uint16_t    - the byte count
+ *  const uint32_t    - reported data count
+ *  const uint32_t    - reported data offset
+ *  const uint32_t    - reported parameter count
+ *  const uint32_t    - reported parameter offset
+ *
+ * Returns:
+ *  DCE2_Ret -  DCE2_RET__ERROR if data should not be processed
+ *              DCE2_RET__SUCCESS if data can be processed
+ *
+ ********************************************************************/
+static DCE2_Ret DCE2_SmbCheckTransDataParams(
+    const uint8_t* smb_hdr_ptr, const uint8_t* nb_ptr, const uint32_t nb_len,
+    const uint16_t bcc, const uint32_t dcnt, const uint32_t doff,
+    const uint32_t pcnt, const uint32_t poff)
+{
+    const uint8_t* doffset = smb_hdr_ptr + doff;
+    const uint8_t* poffset = smb_hdr_ptr + poff;
+    const uint8_t* nb_end = nb_ptr + nb_len;
+
+    if (bcc < ((uint64_t)dcnt + pcnt))
+        dce_alert(GID_DCE2, DCE2_SMB_BCC_LT_DSIZE, (dce2CommonStats*)&dce2_smb_stats);
+
+    // Check data offset out of bounds
+    if ((doffset > nb_end) || (doffset < smb_hdr_ptr))
+    {
+        // Beyond data left or wrap
+        dce_alert(GID_DCE2, DCE2_SMB_BAD_OFF, (dce2CommonStats*)&dce2_smb_stats);
+        return DCE2_RET__ERROR;
+    }
+
+    // Check data offset in bounds but backwards
+    // Only check if the data count is non-zero
+    if ((dcnt != 0) && (doffset < nb_ptr))
+    {
+        // Not necessarily and error if the offset puts the data
+        // before or in the command structure.
+        dce_alert(GID_DCE2, DCE2_SMB_BAD_OFF, (dce2CommonStats*)&dce2_smb_stats);
+    }
+
+    // Check the data offset + data count
+    if (((doffset + dcnt) > nb_end)            // beyond data left
+        || ((doffset + dcnt) < doffset))       // wrap
+    {
+        dce_alert(GID_DCE2, DCE2_SMB_NB_LT_DSIZE, (dce2CommonStats*)&dce2_smb_stats);
+        return DCE2_RET__ERROR;
+    }
+
+    // Check parameter offset out of bounds
+    if ((poffset > nb_end) || (poffset < smb_hdr_ptr))
+    {
+        // Beyond data left or wrap
+        dce_alert(GID_DCE2, DCE2_SMB_BAD_OFF, (dce2CommonStats*)&dce2_smb_stats);
+        return DCE2_RET__ERROR;
+    }
+
+    // Check parameter offset in bounds but backwards
+    // Only check if the parameter count is non-zero
+    if ((pcnt != 0) && (poffset < nb_ptr))
+    {
+        // Not necessarily and error if the offset puts the data
+        // before or in the command structure.
+        dce_alert(GID_DCE2, DCE2_SMB_BAD_OFF, (dce2CommonStats*)&dce2_smb_stats);
+    }
+
+    // Check the parameter offset + parameter count
+    if (((poffset + pcnt) > nb_end)            // beyond data left
+        || ((poffset + pcnt) < poffset))       // wrap
+    {
+        dce_alert(GID_DCE2, DCE2_SMB_NB_LT_DSIZE, (dce2CommonStats*)&dce2_smb_stats);
+        return DCE2_RET__ERROR;
+    }
+
+    return DCE2_RET__SUCCESS;
+}
+
+/********************************************************************
+ * Function: DCE2_SmbValidateTransactionSent()
+ *
+ * Purpose:
+ *  Checks that amount sent plus current amount is not greater than
+ *  the total count expected.
+ *
+ * Arguments:
+ *  const uint32_t    - amount of data sent so far
+ *  const uint32_t    - reported total data count
+ *  const uint32_t    - reported data count
+ *  const uint32_t    - amount of parameters sent so far
+ *  const uint32_t    - reported total parameter count
+ *  const uint32_t    - reported parameter count
+ *
+ * Returns:
+ *  DCE2_Ret -  DCE2_RET__ERROR if data should not be processed
+ *              DCE2_RET__SUCCESS if data can be processed
+ *
+ ********************************************************************/
+static DCE2_Ret DCE2_SmbValidateTransactionSent(
+    uint32_t dsent, uint32_t dcnt, uint32_t tdcnt,
+    uint32_t psent, uint32_t pcnt, uint32_t tpcnt)
+{
+    if (((dsent + dcnt) > tdcnt) || ((psent + pcnt) > tpcnt))
+    {
+        if ((dsent + dcnt) > tdcnt)
+        {
+            dce_alert(GID_DCE2, DCE2_SMB_DSENT_GT_TDCNT, (dce2CommonStats*)&dce2_smb_stats);
+        }
+
+        if ((psent + pcnt) > tpcnt)
+        {
+            dce_alert(GID_DCE2, DCE2_SMB_DSENT_GT_TDCNT, (dce2CommonStats*)&dce2_smb_stats);
         }
+
+        // Samba throws out entire transaction and Windows seems to hang in
+        // limbo forever and never responds, so stop looking
+        return DCE2_RET__ERROR;
     }
+
+    return DCE2_RET__SUCCESS;
+}
+
+/********************************************************************
+ * Function: DCE2_SmbValidateTransactionFields()
+ *
+ * Purpose:
+ *  Wrapper that calls DCE2_SmbCheckTotalCount() for total parameter
+ *  count and total data count and DCE2_SmbCheckTransDataParams()
+ *
+ * Arguments:
+ *  const uint8_t *   - pointer to start of SMB header where offset is
+ *                      taken from.
+ *  const uint8_t *   - current pointer - should be right after command
+ *                      structure.
+ *  const uint32_t    - remaining data left in PDU from current pointer.
+ *  const uint16_t    - the byte count
+ *  const uint32_t    - reported total data count
+ *  const uint32_t    - reported total parameter count
+ *  const uint32_t    - reported data count
+ *  const uint32_t    - reported data offset
+ *  const uint32_t    - reported data displacement
+ *  const uint32_t    - reported parameter count
+ *  const uint32_t    - reported parameter offset
+ *  const uint32_t    - reported parameter displacement
+ *
+ * Returns:
+ *  DCE2_Ret -  DCE2_RET__ERROR if data should not be processed
+ *              DCE2_RET__SUCCESS if data can be processed
+ *
+ ********************************************************************/
+static inline DCE2_Ret DCE2_SmbValidateTransactionFields(
+    const uint8_t* smb_hdr_ptr,
+    const uint8_t* nb_ptr, const uint32_t nb_len, const uint16_t bcc,
+    const uint32_t tdcnt, const uint32_t tpcnt,
+    const uint32_t dcnt, const uint32_t doff, const uint32_t ddisp,
+    const uint32_t pcnt, const uint32_t poff, const uint32_t pdisp)
+{
+    if (DCE2_SmbCheckTotalCount(tdcnt, dcnt, ddisp) != DCE2_RET__SUCCESS)
+        return DCE2_RET__ERROR;
+
+    if (DCE2_SmbCheckTotalCount(tpcnt, pcnt, pdisp) != DCE2_RET__SUCCESS)
+        return DCE2_RET__ERROR;
+
+    if (DCE2_SmbCheckTransDataParams(smb_hdr_ptr,
+        nb_ptr, nb_len, bcc, dcnt, doff, pcnt, poff) != DCE2_RET__SUCCESS)
+        return DCE2_RET__ERROR;
+
+    return DCE2_RET__SUCCESS;
 }
 
 //-------------------------------------------------------------------------
index 769dfaa762d9cdb10fafa0b959faaf8f7286c6e0..471989b6c9295777d6cc15fce69a1e80a3d6402d 100644 (file)
 
 #define SMB_MAX_NUM_COMS   256
 
+#define SMB_FILE_TYPE_DISK               0x0000
+#define SMB_FILE_TYPE_BYTE_MODE_PIPE     0x0001
+#define SMB_FILE_TYPE_MESSAGE_MODE_PIPE  0x0002
+#define SMB_FILE_TYPE_PRINTER            0x0003
+#define SMB_FILE_TYPE_COMMON_DEVICE      0x0004
+
+#define SMB_FILE_ATTRIBUTE_NORMAL       0x0000
+#define SMB_FILE_ATTRIBUTE_READONLY     0x0001
+#define SMB_FILE_ATTRIBUTE_HIDDEN       0x0002
+#define SMB_FILE_ATTRIBUTE_SYSTEM       0x0004
+#define SMB_FILE_ATTRIBUTE_VOLUME       0x0008
+#define SMB_FILE_ATTRIBUTE_DIRECTORY    0x0010
+#define SMB_FILE_ATTRIBUTE_ARCHIVE      0x0020
+#define SMB_SEARCH_ATTRIBUTE_READONLY   0x0100
+#define SMB_SEARCH_ATTRIBUTE_HIDDEN     0x0200
+#define SMB_SEARCH_ATTRIBUTE_SYSTEM     0x0400
+#define SMB_SEARCH_ATTRIBUTE_DIRECTORY  0x1000
+#define SMB_SEARCH_ATTRIBUTE_ARCHIVE    0x2000
+#define SMB_FILE_ATTRIBUTE_OTHER        0xC8C0   // Reserved
+
+#define SMB_EXT_FILE_ATTR_READONLY    0x00000001
+#define SMB_EXT_FILE_ATTR_HIDDEN      0x00000002
+#define SMB_EXT_FILE_ATTR_SYSTEM      0x00000004
+#define SMB_EXT_FILE_ATTR_DIRECTORY   0x00000010
+#define SMB_EXT_FILE_ATTR_ARCHIVE     0x00000020
+#define SMB_EXT_FILE_ATTR_NORMAL      0x00000080
+#define SMB_EXT_FILE_ATTR_TEMPORARY   0x00000100
+#define SMB_EXT_FILE_ATTR_COMPRESSED  0x00000800
+#define SMB_EXT_FILE_POSIX_SEMANTICS  0x01000000
+#define SMB_EXT_FILE_BACKUP_SEMANTICS 0x02000000
+#define SMB_EXT_FILE_DELETE_ON_CLOSE  0x04000000
+#define SMB_EXT_FILE_SEQUENTIAL_SCAN  0x08000000
+#define SMB_EXT_FILE_RANDOM_ACCESS    0x10000000
+#define SMB_EXT_FILE_NO_BUFFERING     0x20000000
+#define SMB_EXT_FILE_WRITE_THROUGH    0x80000000
+
 struct dce2SmbStats
 {
 /*  FIXIT-M
@@ -214,6 +250,10 @@ extern THREAD_LOCAL ProfileStats dce2_smb_pstat_smb_negotiate;
 #define DCE2_SMB_ID   0xff534d42  /* \xffSMB */
 #define DCE2_SMB2_ID  0xfe534d42  /* \xfeSMB */
 
+// MS-FSCC Section 2.1.5 - Pathname
+#define DCE2_SMB_MAX_PATH_LEN  32760
+#define DCE2_SMB_MAX_COMP_LEN    255
+
 /* SMB command codes */
 #define SMB_COM_CREATE_DIRECTORY 0x00
 #define SMB_COM_DELETE_DIRECTORY 0x01
@@ -365,43 +405,6 @@ struct SmbNtHdr
     uint16_t smb_mid;               /* multiplex id */
 };
 
-struct SmbWriteAndXReq   /* smb_wct = 12 */
-{
-    uint8_t smb_wct;         /* count of 16-bit words that follow */
-    uint8_t smb_com2;        /* secondary (X) command, 0xFF = none */
-    uint8_t smb_reh2;        /* reserved (must be zero) */
-    uint16_t smb_off2;       /* offset (from SMB hdr start) to next cmd (@smb_wct) */
-    uint16_t smb_fid;        /* file handle */
-    uint32_t smb_offset;     /* offset in file to begin write */
-    uint32_t smb_timeout;    /* number of milliseconds to wait for completion */
-    uint16_t smb_wmode;      /* write mode:
-                                bit0 - complete write before return (write through)
-                                bit1 - return smb_remaining (pipes/devices only)
-                                bit2 - use WriteRawNamedPipe (pipes only)
-                                bit3 - this is the start of a message (pipes only) */
-    uint16_t smb_countleft;  /* bytes remaining to write to satisfy user’s request */
-    uint16_t smb_dsize_high; /* high bytes of data size */
-    uint16_t smb_dsize;      /* number of data bytes in buffer (min value = 0) */
-    uint16_t smb_doff;       /* offset (from start of SMB hdr) to data bytes */
-    uint16_t smb_bcc;        /* total bytes (including pad bytes) following */
-};
-
-struct SmbReadAndXResp    /* smb_wct = 12 */
-{
-    uint8_t smb_wct;         /* count of 16-bit words that follow */
-    uint8_t smb_com2;        /* secondary (X) command, 0xFF = none */
-    uint8_t smb_res2;        /* reserved (pad to word) */
-    uint16_t smb_off2;       /* offset (from SMB hdr start) to next cmd (@smb_wct) */
-    uint16_t smb_remaining;  /* bytes remaining to be read (pipes/devices only) */
-    uint32_t smb_rsvd;       /* reserved */
-    uint16_t smb_dsize;      /* number of data bytes (minimum value = 0) */
-    uint16_t smb_doff;       /* offset (from start of SMB hdr) to data bytes */
-    uint16_t smb_dsize_high; /* high bytes of data size */
-    uint32_t smb_rsvd1;      /* reserved */
-    uint32_t smb_rsvd2;      /* reserved */
-    uint16_t smb_bcc;        /* total bytes (including pad bytes) following */
-};
-
 /* For server empty respones indicating client error or interim response */
 struct SmbEmptyCom
 {
@@ -409,7 +412,6 @@ struct SmbEmptyCom
     uint16_t smb_bcc;    /* value = 0 */
 };
 
-#pragma pack()
 enum DCE2_SmbSsnState
 {
     DCE2_SMB_SSN_STATE__START         = 0x00,
@@ -451,6 +453,96 @@ enum SmbAndXCom
     SMB_ANDX_COM__MAX
 };
 
+enum SmbTransactionSubcommand
+{
+    TRANS_UNKNOWN_0000             = 0x0000,
+    TRANS_SET_NMPIPE_STATE         = 0x0001,
+    TRANS_UNKNOWN_0002             = 0x0002,
+    TRANS_UNKNOWN_0003             = 0x0003,
+    TRANS_UNKNOWN_0004             = 0x0004,
+    TRANS_UNKNOWN_0005             = 0x0005,
+    TRANS_UNKNOWN_0006             = 0x0006,
+    TRANS_UNKNOWN_0007             = 0x0007,
+    TRANS_UNKNOWN_0008             = 0x0008,
+    TRANS_UNKNOWN_0009             = 0x0009,
+    TRANS_UNKNOWN_000A             = 0x000A,
+    TRANS_UNKNOWN_000B             = 0x000B,
+    TRANS_UNKNOWN_000C             = 0x000C,
+    TRANS_UNKNOWN_000D             = 0x000D,
+    TRANS_UNKNOWN_000E             = 0x000E,
+    TRANS_UNKNOWN_000F             = 0x000F,
+    TRANS_UNKNOWN_0010             = 0x0010,
+    TRANS_RAW_READ_NMPIPE          = 0x0011,
+    TRANS_UNKNOWN_0012             = 0x0012,
+    TRANS_UNKNOWN_0013             = 0x0013,
+    TRANS_UNKNOWN_0014             = 0x0014,
+    TRANS_UNKNOWN_0015             = 0x0015,
+    TRANS_UNKNOWN_0016             = 0x0016,
+    TRANS_UNKNOWN_0017             = 0x0017,
+    TRANS_UNKNOWN_0018             = 0x0018,
+    TRANS_UNKNOWN_0019             = 0x0019,
+    TRANS_UNKNOWN_001A             = 0x001A,
+    TRANS_UNKNOWN_001B             = 0x001B,
+    TRANS_UNKNOWN_001C             = 0x001C,
+    TRANS_UNKNOWN_001D             = 0x001D,
+    TRANS_UNKNOWN_001E             = 0x001E,
+    TRANS_UNKNOWN_001F             = 0x001F,
+    TRANS_UNKNOWN_0020             = 0x0020,
+    TRANS_QUERY_NMPIPE_STATE       = 0x0021,
+    TRANS_QUERY_NMPIPE_INFO        = 0x0022,
+    TRANS_PEEK_NMPIPE              = 0x0023,
+    TRANS_UNKNOWN_0024             = 0x0024,
+    TRANS_UNKNOWN_0025             = 0x0025,
+    TRANS_TRANSACT_NMPIPE          = 0x0026,
+    TRANS_UNKNOWN_0027             = 0x0027,
+    TRANS_UNKNOWN_0028             = 0x0028,
+    TRANS_UNKNOWN_0029             = 0x0029,
+    TRANS_UNKNOWN_002A             = 0x002A,
+    TRANS_UNKNOWN_002B             = 0x002B,
+    TRANS_UNKNOWN_002C             = 0x002C,
+    TRANS_UNKNOWN_002D             = 0x002D,
+    TRANS_UNKNOWN_002E             = 0x002E,
+    TRANS_UNKNOWN_002F             = 0x002F,
+    TRANS_UNKNOWN_0030             = 0x0030,
+    TRANS_RAW_WRITE_NMPIPE         = 0x0031,
+    TRANS_UNKNOWN_0032             = 0x0032,
+    TRANS_UNKNOWN_0033             = 0x0033,
+    TRANS_UNKNOWN_0034             = 0x0034,
+    TRANS_UNKNOWN_0035             = 0x0035,
+    TRANS_READ_NMPIPE              = 0x0036,
+    TRANS_WRITE_NMPIPE             = 0x0037,
+    TRANS_UNKNOWN_0038             = 0x0038,
+    TRANS_UNKNOWN_0039             = 0x0039,
+    TRANS_UNKNOWN_003A             = 0x003A,
+    TRANS_UNKNOWN_003B             = 0x003B,
+    TRANS_UNKNOWN_003C             = 0x003C,
+    TRANS_UNKNOWN_003D             = 0x003D,
+    TRANS_UNKNOWN_003E             = 0x003E,
+    TRANS_UNKNOWN_003F             = 0x003F,
+    TRANS_UNKNOWN_0040             = 0x0040,
+    TRANS_UNKNOWN_0041             = 0x0041,
+    TRANS_UNKNOWN_0042             = 0x0042,
+    TRANS_UNKNOWN_0043             = 0x0043,
+    TRANS_UNKNOWN_0044             = 0x0044,
+    TRANS_UNKNOWN_0045             = 0x0045,
+    TRANS_UNKNOWN_0046             = 0x0046,
+    TRANS_UNKNOWN_0047             = 0x0047,
+    TRANS_UNKNOWN_0048             = 0x0048,
+    TRANS_UNKNOWN_0049             = 0x0049,
+    TRANS_UNKNOWN_004A             = 0x004A,
+    TRANS_UNKNOWN_004B             = 0x004B,
+    TRANS_UNKNOWN_004C             = 0x004C,
+    TRANS_UNKNOWN_004D             = 0x004D,
+    TRANS_UNKNOWN_004E             = 0x004E,
+    TRANS_UNKNOWN_004F             = 0x004F,
+    TRANS_UNKNOWN_0050             = 0x0050,
+    TRANS_UNKNOWN_0051             = 0x0051,
+    TRANS_UNKNOWN_0052             = 0x0052,
+    TRANS_WAIT_NMPIPE              = 0x0053,
+    TRANS_CALL_NMPIPE              = 0x0054,
+    TRANS_SUBCOM_MAX               = 0x0055
+};
+
 struct DCE2_SmbWriteAndXRaw
 {
     int remaining;  // A signed integer so it can be negative
@@ -566,6 +658,8 @@ struct DCE2_SmbRequestTracker
     bool is_ipc;
 };
 
+#pragma pack()
+
 struct DCE2_SmbSsnData
 {
     DCE2_SsnData sd;  // This member must be first
@@ -619,6 +713,12 @@ struct DCE2_SmbSsnData
     int64_t max_file_depth;
 };
 
+/********************************************************************
+ * Structures and inline accessor functions
+ ********************************************************************/
+/* Pack the structs since we'll be laying them on top of packet data */
+#pragma pack(1)
+
 /********************************************************************
  * Common fields to all commands
  ********************************************************************/
@@ -669,12 +769,12 @@ inline uint16_t SmbBcc(const uint8_t* ptr, uint16_t com_size)
     if (com_size < sizeof(SmbEmptyCom))
         return 0;
 
-    return extract_16bits(ptr + com_size - sizeof(uint16_t));
+    return alignedNtohs((uint16_t*)(ptr + com_size - sizeof(uint16_t)));
 }
 
 inline uint16_t SmbEmptyComBcc(const SmbEmptyCom* ec)
 {
-    return ntohs(ec->smb_bcc);
+    return alignedNtohs(&ec->smb_bcc);
 }
 
 inline int SmbType(const SmbNtHdr* hdr)
@@ -685,6 +785,1038 @@ inline int SmbType(const SmbNtHdr* hdr)
     return SMB_TYPE__REQUEST;
 }
 
+inline uint8_t SmbAndXCom2(const SmbAndXCommon* andx)
+{
+    return andx->smb_com2;
+}
+
+inline uint16_t SmbAndXOff2(const SmbAndXCommon* andx)
+{
+    return alignedNtohs(&andx->smb_off2);
+}
+
+/* SMB formats (smb_fmt) Dialect, Pathname and ASCII are all
+ * NULL terminated ASCII strings unless Unicode is specified
+ * in the NT LM 1.0 SMB header in which case they are NULL
+ * terminated unicode strings
+ */
+#define SMB_FMT__DATA_BLOCK  1
+#define SMB_FMT__DIALECT     2
+#define SMB_FMT__ASCII       4
+
+inline bool SmbFmtDataBlock(const uint8_t fmt)
+{
+    return fmt == SMB_FMT__DATA_BLOCK ? true : false;
+}
+
+inline bool SmbFmtDialect(const uint8_t fmt)
+{
+    return fmt == SMB_FMT__DIALECT ? true : false;
+}
+
+inline bool SmbFmtAscii(const uint8_t fmt)
+{
+    return fmt == SMB_FMT__ASCII ? true : false;
+}
+
+/********************************************************************
+ * SMB_COM_OPEN
+ ********************************************************************/
+struct SmbOpenReq   /* smb_wct = 2 */
+{
+    uint8_t smb_wct;      /* count of 16-bit words that follow */
+    uint16_t smb_mode;    /* r/w/share */
+    uint16_t smb_attr;    /* attribute */
+    uint16_t smb_bcc;     /* min = 2 */
+};
+
+struct SmbOpenResp   /* smb_wct = 7 */
+{
+    uint8_t smb_wct;      /* count of 16-bit words that follow */
+    uint16_t smb_fid;     /* file handle */
+    uint16_t smb_attr;    /* attribute */
+    uint32_t smb_time;    /* time1 low */
+    uint32_t smb_file_size;   /* file size low */
+    uint16_t smb_access;  /* access allowed */
+    uint16_t smb_bcc;     /* must be 0 */
+};
+
+#define SMB_OPEN_ACCESS_MODE__READ        0x0000
+#define SMB_OPEN_ACCESS_MODE__WRITE       0x0001
+#define SMB_OPEN_ACCESS_MODE__READ_WRITE  0x0002
+#define SMB_OPEN_ACCESS_MODE__EXECUTE     0x0003
+
+inline uint16_t SmbOpenRespFid(const SmbOpenResp* resp)
+{
+    return alignedNtohs(&resp->smb_fid);
+}
+
+inline uint32_t SmbOpenRespFileSize(const SmbOpenResp* resp)
+{
+    return extract_32bits((uint8_t*)&resp->smb_file_size);
+}
+
+inline uint16_t SmbOpenRespFileAttrs(const SmbOpenResp* resp)
+{
+    return alignedNtohs(&resp->smb_attr);
+}
+
+inline bool SmbFileAttrsDirectory(const uint16_t file_attrs)
+{
+    if (file_attrs & SMB_FILE_ATTRIBUTE_DIRECTORY)
+        return true;
+    return false;
+}
+
+inline uint16_t SmbOpenRespAccessMode(const SmbOpenResp* resp)
+{
+    return alignedNtohs(&resp->smb_access);
+}
+
+inline bool SmbOpenForWriting(const uint16_t access_mode)
+{
+    return access_mode == SMB_OPEN_ACCESS_MODE__WRITE;
+}
+
+/********************************************************************
+ * SMB_COM_CREATE
+ ********************************************************************/
+struct SmbCreateReq   /* smb_wct = 3 */
+{
+    uint8_t smb_wct;
+    uint16_t smb_file_attrs;
+    uint32_t smb_creation_time;
+    uint16_t smb_bcc;
+};
+
+struct SmbCreateResp   /* smb_wct = 1 */
+{
+    uint8_t smb_wct;
+    uint16_t smb_fid;
+    uint16_t smb_bcc;
+};
+
+inline uint16_t SmbCreateReqFileAttrs(const SmbCreateReq* req)
+{
+    return alignedNtohs(&req->smb_file_attrs);
+}
+
+inline bool SmbAttrDirectory(const uint16_t file_attrs)
+{
+    if (file_attrs & SMB_FILE_ATTRIBUTE_DIRECTORY)
+        return true;
+    return false;
+}
+
+inline bool SmbAttrHidden(const uint16_t file_attrs)
+{
+    if (file_attrs & SMB_FILE_ATTRIBUTE_HIDDEN)
+        return true;
+    return false;
+}
+
+inline bool SmbAttrSystem(const uint16_t file_attrs)
+{
+    if (file_attrs & SMB_FILE_ATTRIBUTE_SYSTEM)
+        return true;
+    return false;
+}
+
+inline uint16_t SmbCreateRespFid(const SmbCreateResp* resp)
+{
+    return alignedNtohs(&resp->smb_fid);
+}
+
+/********************************************************************
+ * SMB_COM_CLOSE
+ ********************************************************************/
+struct SmbCloseReq   /* smb_wct = 3 */
+{
+    uint8_t smb_wct;      /* count of 16-bit words that follow */
+    uint16_t smb_fid;     /* file handle */
+    uint16_t smb_tlow;    /* time low */
+    uint16_t smb_thigh;   /* time high */
+    uint16_t smb_bcc;     /* must be 0 */
+};
+
+struct SmbCloseResp   /* smb_wct = 0 */
+{
+    uint8_t smb_wct;      /* count of 16-bit words that follow */
+    uint16_t smb_bcc;     /* must be 0 */
+};
+
+inline uint16_t SmbCloseReqFid(const SmbCloseReq* req)
+{
+    return alignedNtohs(&req->smb_fid);
+}
+
+/********************************************************************
+ * SMB_COM_READ
+ ********************************************************************/
+struct SmbReadReq   /* smb_wct = 5 */
+{
+    uint8_t smb_wct;      /* count of 16-bit words that follow */
+    uint16_t smb_fid;     /* file handle */
+    uint16_t smb_cnt;     /* count of bytes */
+    uint32_t smb_off;     /* offset */
+    uint16_t smb_left;    /* count left */
+    uint16_t smb_bcc;     /* must be 0 */
+};
+
+struct SmbReadResp   /* smb_wct = 5 */
+{
+    uint8_t smb_wct;      /* count of 16-bit words that follow */
+    uint16_t smb_cnt;     /* count */
+    uint16_t smb_res[4];  /* reserved (MBZ) */
+    uint16_t smb_bcc;     /* length of data + 3 */
+};
+
+inline uint16_t SmbReadReqFid(const SmbReadReq* req)
+{
+    return alignedNtohs(&req->smb_fid);
+}
+
+inline uint32_t SmbReadReqOffset(const SmbReadReq* req)
+{
+    return alignedNtohl(&req->smb_off);
+}
+
+inline uint16_t SmbReadRespCount(const SmbReadResp* resp)
+{
+    return alignedNtohs(&resp->smb_cnt);
+}
+
+/********************************************************************
+ * SMB_COM_WRITE
+ ********************************************************************/
+struct SmbWriteReq   /* smb_wct = 5 */
+{
+    uint8_t smb_wct;      /* count of 16-bit words that follow */
+    uint16_t smb_fid;     /* file handle */
+    uint16_t smb_cnt;     /* count of bytes */
+    uint32_t smb_offset;  /* file offset in bytes */
+    uint16_t smb_left;    /* count left */
+    uint16_t smb_bcc;     /* length of data + 3 */
+};
+
+struct SmbWriteResp   /* smb_wct = 1 */
+{
+    uint8_t smb_wct;      /* count of 16-bit words that follow */
+    uint16_t smb_cnt;     /* count */
+    uint16_t smb_bcc;     /* must be 0 */
+};
+
+inline uint16_t SmbWriteReqFid(const SmbWriteReq* req)
+{
+    return alignedNtohs(&req->smb_fid);
+}
+
+inline uint16_t SmbWriteReqCount(const SmbWriteReq* req)
+{
+    return alignedNtohs(&req->smb_cnt);
+}
+
+inline uint32_t SmbWriteReqOffset(const SmbWriteReq* req)
+{
+    return alignedNtohl(&req->smb_offset);
+}
+
+inline uint16_t SmbWriteRespCount(const SmbWriteResp* resp)
+{
+    return alignedNtohs(&resp->smb_cnt);
+}
+
+/********************************************************************
+ * SMB_COM_CREATE_NEW
+ ********************************************************************/
+struct SmbCreateNewReq   /* smb_wct = 3 */
+{
+    uint8_t smb_wct;
+    uint16_t smb_file_attrs;
+    uint32_t smb_creation_time;
+    uint16_t smb_bcc;
+};
+
+struct SmbCreateNewResp   /* smb_wct = 1 */
+{
+    uint8_t smb_wct;
+    uint16_t smb_fid;
+    uint16_t smb_bcc;
+};
+
+inline uint16_t SmbCreateNewReqFileAttrs(const SmbCreateNewReq* req)
+{
+    return alignedNtohs(&req->smb_file_attrs);
+}
+
+inline uint16_t SmbCreateNewRespFid(const SmbCreateNewResp* resp)
+{
+    return alignedNtohs(&resp->smb_fid);
+}
+
+/********************************************************************
+ * SMB_COM_LOCK_AND_READ
+ ********************************************************************/
+struct SmbLockAndReadReq   /* smb_wct = 5 */
+{
+    uint8_t smb_wct;      /* count of 16-bit words that follow */
+    uint16_t smb_fid;
+    uint16_t smb_cnt;
+    uint32_t smb_read_offset;
+    uint16_t smb_remaining;
+    uint16_t smb_bcc;     /* must be 0 */
+};
+
+struct SmbLockAndReadResp   /* smb_wct = 5 */
+{
+    uint8_t smb_wct;
+    uint16_t smb_cnt;
+    uint16_t reserved[4];
+    uint16_t smb_bcc;
+};
+
+inline uint16_t SmbLockAndReadReqFid(const SmbLockAndReadReq* req)
+{
+    return alignedNtohs(&req->smb_fid);
+}
+
+inline uint32_t SmbLockAndReadReqOffset(const SmbLockAndReadReq* req)
+{
+    return alignedNtohl(&req->smb_read_offset);
+}
+
+inline uint16_t SmbLockAndReadRespCount(const SmbLockAndReadResp* resp)
+{
+    return alignedNtohs(&resp->smb_cnt);
+}
+
+/********************************************************************
+ * SMB_COM_WRITE_AND_UNLOCK
+ ********************************************************************/
+struct SmbWriteAndUnlockReq
+{
+    uint8_t smb_wct;
+    uint16_t smb_fid;
+    uint16_t smb_cnt;
+    uint32_t smb_write_offset;
+    uint16_t smb_estimate_of_remaining;
+    uint16_t smb_bcc;
+};
+
+struct SmbWriteAndUnlockResp   /* smb_wct = 1 */
+{
+    uint8_t smb_wct;      /* count of 16-bit words that follow */
+    uint16_t smb_cnt;     /* count */
+    uint16_t smb_bcc;     /* must be 0 */
+};
+
+inline uint16_t SmbWriteAndUnlockReqFid(const SmbWriteAndUnlockReq* req)
+{
+    return alignedNtohs(&req->smb_fid);
+}
+
+inline uint16_t SmbWriteAndUnlockReqCount(const SmbWriteAndUnlockReq* req)
+{
+    return alignedNtohs(&req->smb_cnt);
+}
+
+inline uint32_t SmbWriteAndUnlockReqOffset(const SmbWriteAndUnlockReq* req)
+{
+    return alignedNtohl(&req->smb_write_offset);
+}
+
+/********************************************************************
+ * SMB_COM_OPEN_ANDX
+ ********************************************************************/
+struct SmbOpenAndXReq   /* smb_wct = 15 */
+{
+    uint8_t smb_wct;         /* count of 16-bit words that follow */
+    uint8_t smb_com2;        /* secondary (X) command, 0xFF = none */
+    uint8_t smb_reh2;        /* reserved (must be zero) */
+    uint16_t smb_off2;       /* offset (from SMB hdr start) to next cmd (@smb_wct) */
+    uint16_t smb_flags;      /* additional information:
+                                bit 0 - if set, return additional information
+                                bit 1 - if set, set single user total file lock (if only access)
+                                bit 2 - if set, the server should notify the consumer on any
+                                        action which can modify the file (delete, setattrib,
+                                        rename, etc.). if not set, the server need only notify
+                                        the consumer on another open request. This bit only has
+                                        meaning if bit 1 is set. */
+    uint16_t smb_mode;       /* file open mode */
+    uint16_t smb_sattr;      /* search attributes */
+    uint16_t smb_attr;       /* file attributes (for create) */
+    uint32_t smb_time;       /* create time */
+    uint16_t smb_ofun;       /* open function */
+    uint32_t smb_size;       /* bytes to reserve on "create" or "truncate" */
+    uint32_t smb_timeout;    /* max milliseconds to wait for resource to open */
+    uint32_t smb_rsvd;       /* reserved (must be zero) */
+    uint16_t smb_bcc;        /* minimum value = 1 */
+};
+
+struct SmbOpenAndXResp   /* smb_wct = 15 */
+{
+    uint8_t smb_wct;         /* count of 16-bit words that follow */
+    uint8_t smb_com2;        /* secondary (X) command, 0xFF = none */
+    uint8_t smb_res2;        /* reserved (pad to word) */
+    uint16_t smb_off2;       /* offset (from SMB hdr start) to next cmd (@smb_wct) */
+    uint16_t smb_fid;        /* file handle */
+    uint16_t smb_attribute;  /* attributes of file or device */
+    uint32_t smb_time;       /* last modification time */
+    uint32_t smb_size;       /* current file size */
+    uint16_t smb_access;     /* access permissions actually allowed */
+    uint16_t smb_type;       /* file type */
+    uint16_t smb_state;      /* state of IPC device (e.g. pipe) */
+    uint16_t smb_action;     /* action taken */
+    uint32_t smb_fileid;     /* server unique file id */
+    uint16_t smb_rsvd;       /* reserved */
+    uint16_t smb_bcc;        /* value = 0 */
+};
+
+inline uint32_t SmbOpenAndXReqAllocSize(const SmbOpenAndXReq* req)
+{
+    return alignedNtohl(&req->smb_size);
+}
+
+inline uint16_t SmbOpenAndXReqFileAttrs(const SmbOpenAndXReq* req)
+{
+    return alignedNtohs(&req->smb_attr);
+}
+
+inline uint16_t SmbOpenAndXRespFid(const SmbOpenAndXResp* resp)
+{
+    return alignedNtohs(&resp->smb_fid);
+}
+
+inline uint16_t SmbOpenAndXRespFileAttrs(const SmbOpenAndXResp* resp)
+{
+    return alignedNtohs(&resp->smb_attribute);
+}
+
+inline uint32_t SmbOpenAndXRespFileSize(const SmbOpenAndXResp* resp)
+{
+    return alignedNtohl(&resp->smb_size);
+}
+
+inline uint16_t SmbOpenAndXRespResourceType(const SmbOpenAndXResp* resp)
+{
+    return alignedNtohs(&resp->smb_type);
+}
+
+#define SMB_OPEN_RESULT__EXISTED    0x0001
+#define SMB_OPEN_RESULT__CREATED    0x0002
+#define SMB_OPEN_RESULT__TRUNCATED  0x0003
+
+inline uint16_t SmbOpenAndXRespOpenResults(const SmbOpenAndXResp* resp)
+{
+    return alignedNtohs(&resp->smb_action);
+}
+
+inline bool SmbOpenResultRead(const uint16_t open_results)
+{
+    return ((open_results & 0x00FF) == SMB_OPEN_RESULT__EXISTED);
+}
+
+inline bool SmbResourceTypeDisk(const uint16_t resource_type)
+{
+    return resource_type == SMB_FILE_TYPE_DISK;
+}
+
+/********************************************************************
+ * SMB_COM_READ_ANDX
+ ********************************************************************/
+struct SmbReadAndXReq   /* smb_wct = 10 */
+{
+    uint8_t smb_wct;         /* count of 16-bit words that follow */
+    uint8_t smb_com2;        /* secondary (X) command, 0xFF = none */
+    uint8_t smb_reh2;        /* reserved (must be zero) */
+    uint16_t smb_off2;       /* offset (from SMB hdr start) to next cmd (@smb_wct) */
+    uint16_t smb_fid;        /* file handle */
+    uint32_t smb_offset;     /* offset in file to begin read */
+    uint16_t smb_maxcnt;     /* max number of bytes to return */
+    uint16_t smb_mincnt;     /* min number of bytes to return */
+    uint32_t smb_timeout;    /* number of milliseconds to wait for completion */
+    uint16_t smb_countleft;  /* bytes remaining to satisfy user’s request */
+    uint16_t smb_bcc;        /* value = 0 */
+};
+
+struct SmbReadAndXExtReq   /* smb_wct = 12 */
+{
+    uint8_t smb_wct;         /* count of 16-bit words that follow */
+    uint8_t smb_com2;        /* secondary (X) command, 0xFF = none */
+    uint8_t smb_reh2;        /* reserved (must be zero) */
+    uint16_t smb_off2;       /* offset (from SMB hdr start) to next cmd (@smb_wct) */
+    uint16_t smb_fid;        /* file handle */
+    uint32_t smb_offset;     /* low offset in file to begin read */
+    uint16_t smb_maxcnt;     /* max number of bytes to return */
+    uint16_t smb_mincnt;     /* min number of bytes to return */
+    uint32_t smb_timeout;    /* number of milliseconds to wait for completion */
+    uint16_t smb_countleft;  /* bytes remaining to satisfy user’s request */
+    uint32_t smb_off_high;   /* high offset in file to begin read */
+    uint16_t smb_bcc;        /* value = 0 */
+};
+
+struct SmbReadAndXResp    /* smb_wct = 12 */
+{
+    uint8_t smb_wct;         /* count of 16-bit words that follow */
+    uint8_t smb_com2;        /* secondary (X) command, 0xFF = none */
+    uint8_t smb_res2;        /* reserved (pad to word) */
+    uint16_t smb_off2;       /* offset (from SMB hdr start) to next cmd (@smb_wct) */
+    uint16_t smb_remaining;  /* bytes remaining to be read (pipes/devices only) */
+    uint32_t smb_rsvd;       /* reserved */
+    uint16_t smb_dsize;      /* number of data bytes (minimum value = 0) */
+    uint16_t smb_doff;       /* offset (from start of SMB hdr) to data bytes */
+    uint16_t smb_dsize_high; /* high bytes of data size */
+    uint32_t smb_rsvd1;      /* reserved */
+    uint32_t smb_rsvd2;      /* reserved */
+    uint16_t smb_bcc;        /* total bytes (including pad bytes) following */
+};
+
+inline uint16_t SmbReadAndXReqFid(const SmbReadAndXReq* req)
+{
+    return alignedNtohs(&req->smb_fid);
+}
+
+inline uint64_t SmbReadAndXReqOffset(const SmbReadAndXExtReq* req)
+{
+    if (req->smb_wct == 10)
+        return (uint64_t)alignedNtohl(&req->smb_offset);
+    return (uint64_t)alignedNtohl(&req->smb_off_high) << 32 | (uint64_t)alignedNtohl(
+        &req->smb_offset);
+}
+
+inline uint16_t SmbReadAndXRespDataOff(const SmbReadAndXResp* req)
+{
+    return alignedNtohs(&req->smb_doff);
+}
+
+inline uint32_t SmbReadAndXRespDataCnt(const SmbReadAndXResp* resp)
+{
+    return (uint32_t)alignedNtohs(&resp->smb_dsize_high) << 16 | (uint32_t)alignedNtohs(
+        &resp->smb_dsize);
+}
+
+/********************************************************************
+ * SMB_COM_WRITE_ANDX
+ ********************************************************************/
+struct SmbWriteAndXReq   /* smb_wct = 12 */
+{
+    uint8_t smb_wct;         /* count of 16-bit words that follow */
+    uint8_t smb_com2;        /* secondary (X) command, 0xFF = none */
+    uint8_t smb_reh2;        /* reserved (must be zero) */
+    uint16_t smb_off2;       /* offset (from SMB hdr start) to next cmd (@smb_wct) */
+    uint16_t smb_fid;        /* file handle */
+    uint32_t smb_offset;     /* offset in file to begin write */
+    uint32_t smb_timeout;    /* number of milliseconds to wait for completion */
+    uint16_t smb_wmode;      /* write mode:
+                                bit0 - complete write before return (write through)
+                                bit1 - return smb_remaining (pipes/devices only)
+                                bit2 - use WriteRawNamedPipe (pipes only)
+                                bit3 - this is the start of a message (pipes only) */
+    uint16_t smb_countleft;  /* bytes remaining to write to satisfy user’s request */
+    uint16_t smb_dsize_high; /* high bytes of data size */
+    uint16_t smb_dsize;      /* number of data bytes in buffer (min value = 0) */
+    uint16_t smb_doff;       /* offset (from start of SMB hdr) to data bytes */
+    uint16_t smb_bcc;        /* total bytes (including pad bytes) following */
+};
+
+struct SmbWriteAndXExtReq   /* smb_wct = 14 */
+{
+    uint8_t smb_wct;         /* count of 16-bit words that follow */
+    uint8_t smb_com2;        /* secondary (X) command, 0xFF = none */
+    uint8_t smb_reh2;        /* reserved (must be zero) */
+    uint16_t smb_off2;       /* offset (from SMB hdr start) to next cmd (@smb_wct) */
+    uint16_t smb_fid;        /* file handle */
+    uint32_t smb_offset;     /* low offset in file to begin write */
+    uint32_t smb_timeout;    /* number of milliseconds to wait for completion */
+    uint16_t smb_wmode;      /* write mode:
+                                bit0 - complete write before return (write through)
+                                bit1 - return smb_remaining (pipes/devices only)
+                                bit2 - use WriteRawNamedPipe (pipes only)
+                                bit3 - this is the start of a message (pipes only) */
+    uint16_t smb_countleft;  /* bytes remaining to write to satisfy user’s request */
+    uint16_t smb_dsize_high; /* high bytes of data size */
+    uint16_t smb_dsize;      /* number of data bytes in buffer (min value = 0) */
+    uint16_t smb_doff;       /* offset (from start of SMB hdr) to data bytes */
+    uint32_t smb_off_high;   /* high offset in file to begin write */
+    uint16_t smb_bcc;        /* total bytes (including pad bytes) following */
+};
+
+struct SmbWriteAndXResp   /* smb_wct = 6 */
+{
+    uint8_t smb_wct;         /* count of 16-bit words that follow */
+    uint8_t smb_com2;        /* secondary (X) command, 0xFF = none */
+    uint8_t smb_res2;        /* reserved (pad to word) */
+    uint16_t smb_off2;       /* offset (from SMB hdr start) to next cmd (@smb_wct) */
+    uint16_t smb_count;      /* number of bytes written */
+    uint16_t smb_remaining;  /* bytes remaining to be read (pipes/devices only) */
+    uint16_t smb_count_high; /* high order bytes of data count */
+    uint16_t smb_rsvd;       /* reserved */
+    uint16_t smb_bcc;        /* value = 0 */
+};
+
+inline uint16_t SmbWriteAndXReqFid(const SmbWriteAndXReq* req)
+{
+    return alignedNtohs(&req->smb_fid);
+}
+
+inline uint16_t SmbWriteAndXReqDataOff(const SmbWriteAndXReq* req)
+{
+    return alignedNtohs(&req->smb_doff);
+}
+
+inline uint16_t SmbWriteAndXReqRemaining(const SmbWriteAndXReq* req)
+{
+    return alignedNtohs(&req->smb_countleft);
+}
+
+inline uint64_t SmbWriteAndXReqOffset(const SmbWriteAndXExtReq* req)
+{
+    if (req->smb_wct == 12)
+        return (uint64_t)alignedNtohl(&req->smb_offset);
+    return (uint64_t)alignedNtohl(&req->smb_off_high) << 32 | (uint64_t)alignedNtohl(
+        &req->smb_offset);
+}
+
+inline uint32_t SmbWriteAndXReqDataCnt(const SmbWriteAndXReq* req)
+{
+    return (uint32_t)alignedNtohs(&req->smb_dsize_high) << 16 | (uint32_t)alignedNtohs(
+        &req->smb_dsize);
+}
+
+inline uint16_t SmbWriteAndXReqWriteMode(const SmbWriteAndXReq* req)
+{
+    return alignedNtohs(&req->smb_wmode);
+}
+
+inline bool SmbWriteAndXReqStartRaw(const SmbWriteAndXReq* req)
+{
+    return ((alignedNtohs(&req->smb_wmode) & 0x000c) == 0x000c) ? true : false;
+}
+
+inline bool SmbWriteAndXReqRaw(const SmbWriteAndXReq* req)
+{
+    return ((alignedNtohs(&req->smb_wmode) & 0x000c) == 0x0004) ? true : false;
+}
+
+inline uint16_t SmbWriteAndXRespCnt(const SmbWriteAndXResp* resp)
+{
+    return alignedNtohs(&resp->smb_count);
+}
+
+/********************************************************************
+ * SMB_COM_SESSION_SETUP_ANDX
+ ********************************************************************/
+struct SmbLm10_SessionSetupAndXReq   /* smb_wct = 10 */
+{
+    uint8_t smb_wct;       /* count of 16-bit words that follow */
+    uint8_t smb_com2;      /* secondary (X) command, 0xFF = none */
+    uint8_t smb_reh2;      /* reserved (must be zero) */
+    uint16_t smb_off2;     /* offset (from SMB hdr start) to next cmd (@smb_wct) */
+    uint16_t smb_bufsize;  /* the consumers max buffer size */
+    uint16_t smb_mpxmax;   /* actual maximum multiplexed pending requests */
+    uint16_t smb_vc_num;   /* 0 = first (only), non zero - additional VC number */
+    uint32_t smb_sesskey;  /* Session Key (valid only if smb_vc_num != 0) */
+    uint16_t smb_apasslen; /* size of account password (smb_apasswd) */
+    uint32_t smb_rsvd;     /* reserved */
+    uint16_t smb_bcc;      /* minimum value = 0 */
+};
+
+inline uint16_t SmbSessionSetupAndXReqMaxMultiplex(const SmbLm10_SessionSetupAndXReq* req)
+{
+    return alignedNtohs(&req->smb_mpxmax);
+}
+
+/********************************************************************
+ * SMB_COM_NEGOTIATE
+ ********************************************************************/
+/* This is the Lanman response */
+struct SmbLm10_NegotiateProtocolResp   /* smb_wct = 13 */
+{
+    uint8_t smb_wct;        /* count of 16-bit words that follow */
+    uint16_t smb_index;     /* index identifying dialect selected */
+    uint16_t smb_secmode;   /* security mode:
+                               bit 0, 1 = User level, 0 = Share level
+                               bit 1, 1 = encrypt passwords, 0 = do not encrypt passwords */
+    uint16_t smb_maxxmt;    /* max transmit buffer size server supports, 1K min */
+    uint16_t smb_maxmux;    /* max pending multiplexed requests server supports */
+    uint16_t smb_maxvcs;    /* max VCs per server/consumer session supported */
+    uint16_t smb_blkmode;   /* block read/write mode support:
+                               bit 0, Read Block Raw supported (65535 bytes max)
+                               bit 1, Write Block Raw supported (65535 bytes max) */
+    uint32_t smb_sesskey;   /* Session Key (unique token identifying session) */
+    uint16_t smb_srv_time;  /* server's current time (hhhhh mmmmmm xxxxx) */
+    uint16_t smb_srv_tzone; /* server's current data (yyyyyyy mmmm ddddd) */
+    uint32_t smb_rsvd;      /* reserved */
+    uint16_t smb_bcc;       /* value = (size of smb_cryptkey) */
+};
+
+/* This is the NT response */
+struct SmbNt_NegotiateProtocolResp     /* smb_wct = 17 */
+{
+    uint8_t smb_wct;            /* count of 16-bit words that follow */
+    uint16_t smb_index;         /* index identifying dialect selected */
+    uint8_t smb_secmode;        /* security mode:
+                                   bit 0, 1 = User level, 0 = Share level
+                                   bit 1, 1 = encrypt passwords, 0 = do not encrypt passwords */
+    uint16_t smb_maxmux;        /* max pending multiplexed requests server supports */
+    uint16_t smb_maxvcs;        /* max VCs per server/consumer session supported */
+    uint32_t smb_maxbuf;        /* maximum buffer size supported */
+    uint32_t smb_maxraw;        /* maximum raw buffer size supported */
+    uint32_t smb_sesskey;       /* Session Key (unique token identifying session) */
+    uint32_t smb_cap;           /* capabilities */
+    struct
+    {
+        uint32_t low_time;
+        int32_t high_time;
+    } smb_srv_time;             /* server time */
+    uint16_t smb_srv_tzone;     /* server's current data (yyyyyyy mmmm ddddd) */
+    uint8_t smb_challenge_len;  /* Challenge length */
+    uint16_t smb_bcc;           /* value = (size of smb_cryptkey) */
+};
+
+inline uint16_t SmbLm_NegotiateRespMaxMultiplex(const SmbLm10_NegotiateProtocolResp* resp)
+{
+    return alignedNtohs(&resp->smb_maxmux);
+}
+
+inline uint16_t SmbNt_NegotiateRespMaxMultiplex(const SmbNt_NegotiateProtocolResp* resp)
+{
+    return alignedNtohs(&resp->smb_maxmux);
+}
+
+/*********************************************************************
+ * SMB_COM_TREE_CONNECT_ANDX
+ *********************************************************************/
+struct SmbTreeConnectAndXReq   /* smb_wct = 4 */
+{
+    uint8_t smb_wct;         /* count of 16-bit words that follow */
+    uint8_t smb_com2;        /* secondary (X) command, 0xFF = none */
+    uint8_t smb_reh2;        /* reserved (must be zero) */
+    uint16_t smb_off2;       /* offset (from SMB hdr start) to next cmd (@smb_wct) */
+    uint16_t smb_flags;      /* additional information:
+                                bit 0 - if set, disconnect TID in current smb_tid */
+    uint16_t smb_spasslen;   /* length of smb_spasswd */
+    uint16_t smb_bcc;        /* minimum value = 3 */
+};
+
+inline uint16_t SmbTreeConnectAndXReqPassLen(const SmbTreeConnectAndXReq* req)
+{
+    return alignedNtohs(&req->smb_spasslen);
+}
+
+/********************************************************************
+ * SMB_COM_NT_TRANSACT
+ ********************************************************************/
+#define SMB_CREATE_OPTIONS__FILE_SEQUENTIAL_ONLY     0x00000004
+
+/********************************************************************
+ * SMB_COM_NT_CREATE_ANDX
+ ********************************************************************/
+#define SMB_CREATE_DISPOSITSION__FILE_SUPERCEDE      0x00000000
+#define SMB_CREATE_DISPOSITSION__FILE_OPEN           0x00000001
+#define SMB_CREATE_DISPOSITSION__FILE_CREATE         0x00000002
+#define SMB_CREATE_DISPOSITSION__FILE_OPEN_IF        0x00000003
+#define SMB_CREATE_DISPOSITSION__FILE_OVERWRITE      0x00000004
+#define SMB_CREATE_DISPOSITSION__FILE_OVERWRITE_IF   0x00000005
+
+struct SmbNtCreateAndXReq   /* smb_wct = 24 */
+{
+    uint8_t smb_wct;            /* count of 16-bit words that follow */
+    uint8_t smb_com2;           /* secondary (X) command, 0xFF = none */
+    uint8_t smb_res2;           /* reserved (pad to word) */
+    uint16_t smb_off2;          /* offset (from SMB hdr start) to next cmd (@smb_wct) */
+    uint8_t smb_res;            /* reserved */
+    uint16_t smb_name_len;      /* length of name of file */
+    uint32_t smb_flags;         /* flags */
+    uint32_t smb_root_fid;      /* fid for previously opened directory */
+    uint32_t smb_access;        /* specifies the type of file access */
+    uint64_t smb_alloc_size;    /* initial allocation size of the file */
+    uint32_t smb_file_attrs;    /* specifies the file attributes for the file */
+    uint32_t smb_share_access;  /* the type of share access */
+    uint32_t smb_create_disp;   /* actions to take if file does or does not exist */
+    uint32_t smb_create_opts;   /* options used when creating or opening file */
+    uint32_t smb_impersonation_level;  /* security impersonation level */
+    uint8_t smb_security_flags;   /* security flags */
+    uint16_t smb_bcc;           /* byte count */
+};
+
+struct SmbNtCreateAndXResp    /* smb_wct = 34 */
+{
+    uint8_t smb_wct;
+    uint8_t smb_com2;
+    uint8_t smb_res2;
+    uint16_t smb_off2;
+    uint8_t smb_oplock_level;
+    uint16_t smb_fid;
+    uint32_t smb_create_disposition;
+    uint64_t smb_creation_time;
+    uint64_t smb_last_access_time;
+    uint64_t smb_last_write_time;
+    uint64_t smb_change_time;
+    uint32_t smb_file_attrs;
+    uint64_t smb_alloc_size;
+    uint64_t smb_eof;
+    uint16_t smb_resource_type;
+    uint16_t smb_nm_pipe_state;
+    uint8_t smb_directory;
+    uint16_t smb_bcc;
+};
+
+// Word count is always set to 42 though there are actually 50 words
+struct SmbNtCreateAndXExtResp    /* smb_wct = 42 */
+{
+    uint8_t smb_wct;
+    uint8_t smb_com2;
+    uint8_t smb_res2;
+    uint16_t smb_off2;
+    uint8_t smb_oplock_level;
+    uint16_t smb_fid;
+    uint32_t smb_create_disposition;
+    uint64_t smb_creation_time;
+    uint64_t smb_last_access_time;
+    uint64_t smb_last_write_time;
+    uint64_t smb_change_time;
+    uint32_t smb_file_attrs;
+    uint64_t smb_alloc_size;
+    uint64_t smb_eof;
+    uint16_t smb_resource_type;
+    uint16_t smb_nm_pipe_state;
+    uint8_t smb_directory;
+    uint8_t smb_volume_guid[16];
+    uint64_t smb_fileid;
+    uint32_t smb_max_access_rights;
+    uint32_t smb_guest_access_rights;
+    uint16_t smb_bcc;
+};
+
+inline uint16_t SmbNtCreateAndXReqFileNameLen(const SmbNtCreateAndXReq* req)
+{
+    return alignedNtohs(&req->smb_name_len);
+}
+
+inline uint32_t SmbNtCreateAndXReqCreateDisposition(const SmbNtCreateAndXReq* req)
+{
+    return alignedNtohl(&req->smb_create_disp);
+}
+
+inline bool SmbCreateDispositionRead(const uint32_t create_disposition)
+{
+    return (create_disposition == SMB_CREATE_DISPOSITSION__FILE_OPEN)
+           || (create_disposition > SMB_CREATE_DISPOSITSION__FILE_OVERWRITE_IF);
+}
+
+inline uint64_t SmbNtCreateAndXReqAllocSize(const SmbNtCreateAndXReq* req)
+{
+    return alignedNtohq(&req->smb_alloc_size);
+}
+
+inline bool SmbNtCreateAndXReqSequentialOnly(const SmbNtCreateAndXReq* req)
+{
+    return (alignedNtohl(&req->smb_create_opts) & SMB_CREATE_OPTIONS__FILE_SEQUENTIAL_ONLY);
+}
+
+inline uint32_t SmbNtCreateAndXReqFileAttrs(const SmbNtCreateAndXReq* req)
+{
+    return alignedNtohl(&req->smb_file_attrs);
+}
+
+inline uint16_t SmbNtCreateAndXRespFid(const SmbNtCreateAndXResp* resp)
+{
+    return alignedNtohs(&resp->smb_fid);
+}
+
+inline uint32_t SmbNtCreateAndXRespCreateDisposition(const SmbNtCreateAndXResp* resp)
+{
+    return alignedNtohl(&resp->smb_create_disposition);
+}
+
+inline bool SmbNtCreateAndXRespDirectory(const SmbNtCreateAndXResp* resp)
+{
+    return (resp->smb_directory ? true : false);
+}
+
+inline uint16_t SmbNtCreateAndXRespResourceType(const SmbNtCreateAndXResp* resp)
+{
+    return alignedNtohs(&resp->smb_resource_type);
+}
+
+inline uint64_t SmbNtCreateAndXRespEndOfFile(const SmbNtCreateAndXResp* resp)
+{
+    return alignedNtohq(&resp->smb_eof);
+}
+
+/********************************************************************
+ * SMB_COM_TRANSACTION
+ ********************************************************************/
+struct SmbTransactionReq   /* smb_wct = 14 + value of smb_suwcnt */
+{
+    /* Note all subcommands use a setup count of 2 */
+    uint8_t smb_wct;       /* count of 16-bit words that follow */
+    uint16_t smb_tpscnt;   /* total number of parameter bytes being sent */
+    uint16_t smb_tdscnt;   /* total number of data bytes being sent */
+    uint16_t smb_mprcnt;   /* max number of parameter bytes to return */
+    uint16_t smb_mdrcnt;   /* max number of data bytes to return */
+    uint8_t smb_msrcnt;    /* max number of setup words to return */
+    uint8_t smb_rsvd;      /* reserved (pad above to word) */
+    uint16_t smb_flags;    /* additional information:
+                              bit 0 - if set, also disconnect TID in smb_tid
+                              bit 1 - if set, transaction is one way (no final response) */
+    uint32_t smb_timeout;  /* number of milliseconds to wait for completion */
+    uint16_t smb_rsvd1;    /* reserved */
+    uint16_t smb_pscnt;    /* number of parameter bytes being sent this buffer */
+    uint16_t smb_psoff;    /* offset (from start of SMB hdr) to parameter bytes */
+    uint16_t smb_dscnt;    /* number of data bytes being sent this buffer */
+    uint16_t smb_dsoff;    /* offset (from start of SMB hdr) to data bytes */
+    uint8_t smb_suwcnt;    /* set up word count */
+    uint8_t smb_rsvd2;     /* reserved (pad above to word) */
+    uint16_t smb_setup1;   /* function (see below)
+                                TRANS_SET_NM_PIPE_STATE   = 0x0001
+                                TRANS_RAW_READ_NMPIPE     = 0x0011
+                                TRANS_QUERY_NMPIPE_STATE  = 0x0021
+                                TRANS_QUERY_NMPIPE_INFO   = 0x0022
+                                TRANS_PEEK_NMPIPE         = 0x0023
+                                TRANS_TRANSACT_NMPIPE     = 0x0026
+                                TRANS_RAW_WRITE_NMPIPE    = 0x0031
+                                TRANS_READ_NMPIPE         = 0x0036
+                                TRANS_WRITE_NMPIPE        = 0x0037
+                                TRANS_WAIT_NMPIPE         = 0x0053
+                                TRANS_CALL_NMPIPE         = 0x0054  */
+    uint16_t smb_setup2;   /* FID (handle) of pipe (if needed), or priority */
+    uint16_t smb_bcc;      /* total bytes (including pad bytes) following */
+};
+
+struct SmbTransactionInterimResp    /* smb_wct = 0 */
+{
+    uint8_t smb_wct;        /* count of 16-bit words that follow */
+    uint16_t smb_bcc;       /* must be 0 */
+};
+
+struct SmbTransactionResp   /* smb_wct = 10 + value of smb_suwcnt */
+{
+    /* Note all subcommands use a setup count of 0 */
+    uint8_t smb_wct;       /* count of 16-bit words that follow */
+    uint16_t smb_tprcnt;   /* total number of parameter bytes being returned */
+    uint16_t smb_tdrcnt;   /* total number of data bytes being returned */
+    uint16_t smb_rsvd;     /* reserved */
+    uint16_t smb_prcnt;    /* number of parameter bytes being returned this buf */
+    uint16_t smb_proff;    /* offset (from start of SMB hdr) to parameter bytes */
+    uint16_t smb_prdisp;   /* byte displacement for these parameter bytes */
+    uint16_t smb_drcnt;    /* number of data bytes being returned this buffer */
+    uint16_t smb_droff;    /* offset (from start of SMB hdr) to data bytes */
+    uint16_t smb_drdisp;   /* byte displacement for these data bytes */
+    uint8_t smb_suwcnt;    /* set up return word count */
+    uint8_t smb_rsvd1;     /* reserved (pad above to word) */
+    uint16_t smb_bcc;      /* total bytes (including pad bytes) following */
+};
+
+inline uint16_t SmbTransactionReqSubCom(const SmbTransactionReq* req)
+{
+    return alignedNtohs(&req->smb_setup1);
+}
+
+inline uint16_t SmbTransactionReqFid(const SmbTransactionReq* req)
+{
+    return alignedNtohs(&req->smb_setup2);
+}
+
+inline bool SmbTransactionReqDisconnectTid(const SmbTransactionReq* req)
+{
+    return alignedNtohs(&req->smb_flags) & 0x0001 ? true : false;
+}
+
+inline bool SmbTransactionReqOneWay(const SmbTransactionReq* req)
+{
+    return alignedNtohs(&req->smb_flags) & 0x0002 ? true : false;
+}
+
+inline uint8_t SmbTransactionReqSetupCnt(const SmbTransactionReq* req)
+{
+    return req->smb_suwcnt;
+}
+
+inline uint16_t SmbTransactionReqTotalDataCnt(const SmbTransactionReq* req)
+{
+    return alignedNtohs(&req->smb_tdscnt);
+}
+
+inline uint16_t SmbTransactionReqDataCnt(const SmbTransactionReq* req)
+{
+    return alignedNtohs(&req->smb_dscnt);
+}
+
+inline uint16_t SmbTransactionReqDataOff(const SmbTransactionReq* req)
+{
+    return alignedNtohs(&req->smb_dsoff);
+}
+
+inline uint16_t SmbTransactionReqTotalParamCnt(const SmbTransactionReq* req)
+{
+    return alignedNtohs(&req->smb_tpscnt);
+}
+
+inline uint16_t SmbTransactionReqParamCnt(const SmbTransactionReq* req)
+{
+    return alignedNtohs(&req->smb_pscnt);
+}
+
+inline uint16_t SmbTransactionReqParamOff(const SmbTransactionReq* req)
+{
+    return alignedNtohs(&req->smb_psoff);
+}
+
+inline uint16_t SmbTransactionRespTotalDataCnt(const SmbTransactionResp* resp)
+{
+    return alignedNtohs(&resp->smb_tdrcnt);
+}
+
+inline uint16_t SmbTransactionRespDataCnt(const SmbTransactionResp* resp)
+{
+    return alignedNtohs(&resp->smb_drcnt);
+}
+
+inline uint16_t SmbTransactionRespDataOff(const SmbTransactionResp* resp)
+{
+    return alignedNtohs(&resp->smb_droff);
+}
+
+inline uint16_t SmbTransactionRespDataDisp(const SmbTransactionResp* resp)
+{
+    return alignedNtohs(&resp->smb_drdisp);
+}
+
+inline uint16_t SmbTransactionRespTotalParamCnt(const SmbTransactionResp* resp)
+{
+    return alignedNtohs(&resp->smb_tprcnt);
+}
+
+inline uint16_t SmbTransactionRespParamCnt(const SmbTransactionResp* resp)
+{
+    return alignedNtohs(&resp->smb_prcnt);
+}
+
+inline uint16_t SmbTransactionRespParamOff(const SmbTransactionResp* resp)
+{
+    return alignedNtohs(&resp->smb_proff);
+}
+
+inline uint16_t SmbTransactionRespParamDisp(const SmbTransactionResp* resp)
+{
+    return alignedNtohs(&resp->smb_prdisp);
+}
+
+// Flags for TRANS_SET_NMPIPE_STATE parameters
+#define PIPE_STATE_NON_BLOCKING  0x8000
+#define PIPE_STATE_MESSAGE_MODE  0x0100
+
+#pragma pack()
+
+struct DCE2_SmbFsm
+{
+    char input;
+    int next_state;
+    int fail_state;
+};
+
 class Dce2SmbFlowData : public FlowData
 {
 public:
index 114ca72b3eb5ef87422a7f37ec5a1911bb05715d..61437f0445d8e17f8364771934fcf17de6cc5c22 100644 (file)
@@ -482,7 +482,7 @@ void print_dce2_smb_conf(dce2SmbProtoConf& config)
 
     if (config.smb_max_compound == 0)
         LogMessage("    Maximum SMB compounded requests: Unlimited\n");
-    else if (config.smb_max_chain == 1)
+    else if (config.smb_max_compound == 1)
         LogMessage("    Maximum SMB compounded requests: No compounding allowed\n");
     else
         LogMessage("    Maximum SMB compounded requests: %u\n", config.smb_max_compound);
index 327ddc47ab1e771d36136a12f6e398c73b9326fc..0d592f97ed78d4bb1263f9c2824014aee67d8eb2 100644 (file)
@@ -91,5 +91,41 @@ private:
 
 void print_dce2_smb_conf(dce2SmbProtoConf& config);
 
+inline bool DCE2_ScSmbFileInspection(const dce2SmbProtoConf* sc)
+{
+    if (sc == nullptr)
+        return false;
+    return ((sc->smb_file_inspection == DCE2_SMB_FILE_INSPECTION_ON)
+           || (sc->smb_file_inspection == DCE2_SMB_FILE_INSPECTION_ONLY));
+}
+
+inline bool DCE2_ScSmbFileInspectionOnly(const dce2SmbProtoConf* sc)
+{
+    if (sc == nullptr)
+        return false;
+    return sc->smb_file_inspection == DCE2_SMB_FILE_INSPECTION_ONLY;
+}
+
+inline int64_t DCE2_ScSmbFileDepth(const dce2SmbProtoConf* sc)
+{
+    if (!DCE2_ScSmbFileInspection(sc))
+        return -1;
+    return sc->smb_file_depth;
+}
+
+inline uint8_t DCE2_ScSmbMaxChain(const dce2SmbProtoConf* sc)
+{
+    if (sc == nullptr)
+        return 0;
+    return sc->smb_max_chain;
+}
+
+inline DCE2_List* DCE2_ScSmbInvalidShares(const dce2SmbProtoConf* sc)
+{
+    if (sc == nullptr)
+        return nullptr;
+    return sc->smb_invalid_shares;
+}
+
 #endif