diff options
author | david-aggeler <david_aggeler@yahoo.com> | 2019-02-11 12:27:19 +0100 |
---|---|---|
committer | Peter Wu <peter@lekensteyn.nl> | 2019-02-12 13:42:36 +0000 |
commit | 975e73939a770124a6f1125116ace142ad689dd6 (patch) | |
tree | fb61b8cc6522378271048d7093d375fefb56306e /epan/dissectors/packet-dcm.c | |
parent | 089d432040e99cce190e5473f0cc4c9b88cd5e1f (diff) |
packet-dcm.c: fix reassembly and export
- Fixed re-assembly and export (consolidated duplicate code)
- Fixed random COL_INFO issues
- Spellings
Change-Id: Ic78fd65e740dd850a6b6250b7715cd5f7ca72353
Reviewed-on: https://code.wireshark.org/review/31973
Petri-Dish: Peter Wu <peter@lekensteyn.nl>
Tested-by: Petri Dish Buildbot
Reviewed-by: Peter Wu <peter@lekensteyn.nl>
Diffstat (limited to 'epan/dissectors/packet-dcm.c')
-rw-r--r-- | epan/dissectors/packet-dcm.c | 376 |
1 files changed, 202 insertions, 174 deletions
diff --git a/epan/dissectors/packet-dcm.c b/epan/dissectors/packet-dcm.c index 6056511042..65279643f0 100644 --- a/epan/dissectors/packet-dcm.c +++ b/epan/dissectors/packet-dcm.c @@ -1,7 +1,7 @@ /* packet-dcm.c * Routines for DICOM dissection * Copyright 2003, Rich Coe <richcoe2@gmail.com> - * Copyright 2008-2018, David Aggeler <david_aggeler@hispeed.ch> + * Copyright 2008-2019, David Aggeler <david_aggeler@hispeed.ch> * * DICOM communication protocol: http://www.dicomstandard.org/current/ * @@ -25,12 +25,26 @@ * * - Implement value multiplicity (VM) consistently in dissect_dcm_tag_value() * - Better concatenate COL_INFO for multiple PDU in one packet - * - Update tag list * - Syntax detection, in case an association request is missing in capture * - Read private tags from configuration and parse in capture * * History * + * Feb 2019 - David Aggeler + * + * - Fixed re-assembly and export (consolidated duplicate code) + * - Fixed random COL_INFO issues + * + * Feb 2019 - Rickard Holmberg + * + * - Updated DICOM definitions to 2019a + * + * Oct 2018 - Rickard Holmberg + * + * - Moved DICOM definitions to packet-dcm.h + * - Generate definitions from docbook with Phyton script + * - Updated DICOM definitions to 2018e + * * June 2018 - David Aggeler * * - Fixed initial COL_INFO for associations. It used to 'append' instead of 'set'. @@ -60,7 +74,7 @@ * * February 2013 - Stefan Allers * - * - Support for dissection of Extended Negotiation (Query/Retrieve + * - Support for dissection of Extended Negotiation (Query/Retrieve) * - Support for dissection of SCP/SCU Role Selection * - Support for dissection of Async Operations Window Negotiation * - Fixed: Improper calculation of length for Association Header @@ -105,10 +119,6 @@ * * - Support remaining DICOM/ARCNEMA tags * - * Oct 12, 2008 - David Aggeler (SVN 26424) - * - * - Follow-up checkin 26417 - * * Oct 3, 2008 - David Aggeler (SVN 26417) * * - DICOM Tags: Support all tags, except for group 1000, 7Fxx @@ -178,7 +188,7 @@ * of a presentation context and therefore grouped. User Info is now grouped. * - Re-assemble PDVs that span multiple PDUs, i.e fix continuation packets * This caused significant changes to the data structures - * - Added preference with dicom tcp ports, to prevent 'stealing' the conversation + * - Added preference with DICOM TCP ports, to prevent 'stealing' the conversation * i.e. don't just rely on heuristic * - Use pinfo->desegment_len instead of tcp_dissect_pdus() * - Returns number of bytes parsed @@ -215,7 +225,7 @@ * Nov 9, 2004 - Rich Coe * * - Fixed the heuristic code -- sometimes a conversation already exists - * - Fixed the dissect code to display all the tags in the pdu + * - Fixed the dissect code to display all the tags in the PDU * * Initial - Rich Coe * @@ -226,13 +236,12 @@ * More known tags might be added in the future. * If the tag data contains a string, it will be displayed. * Even if the tag contains Explicit VR, it is not currently used to - * symbolically display the data. Consider this a future enhancement. + * symbolically display the data. * */ #include "config.h" - #include <epan/packet.h> #include <epan/exceptions.h> #include <epan/prefs.h> @@ -529,7 +538,7 @@ typedef struct dcm_open_tag { guint16 vl_2; /* Partially decoded 2nd two bytes of length */ /* These ones are, where the value was truncated */ - guint32 len_total; /* Tag length of 'oversized' tags. Used for display */ + guint32 len_total; /* Tag length of 'over-sized' tags. Used for display */ guint32 len_remaining; /* Remaining tag bytes to 'decoded' as binary data after this PDV */ gchar *desc; /* Last decoded description */ @@ -546,7 +555,7 @@ typedef struct dcm_state_pdv { guint32 packet_no; /* Wireshark packet number, where pdv starts */ guint32 offset; /* Offset in packet, where PDV header starts */ - gchar *desc; /* PDV description. wmem_file_scope() */ + gchar *desc; /* PDV description. wmem_file_scope() */ guint8 pctx_id; /* Reference to used Presentation Context */ @@ -565,8 +574,7 @@ typedef struct dcm_state_pdv { gboolean is_flagvalid; /* The following two flags are initialized correctly */ gboolean is_command; /* This PDV is a command rather than a data package */ gboolean is_last_fragment; /* Last Fragment bit was set, i.e. termination of an object - This flag delimits different dicom object in the same - association */ + This flag delimits different DICOM object in the same association */ gboolean is_corrupt; /* Early termination of long PDVs */ /* The following five attributes are only used for command PDVs */ @@ -590,7 +598,7 @@ typedef struct dcm_state_pdv { } dcm_state_pdv_t; /* - Per Presentation Context in an association store data needed, for subsequent decoding +Per Presentation Context in an association store data needed, for subsequent decoding */ typedef struct dcm_state_pctx { @@ -893,11 +901,12 @@ dcm_state_pctx_get(dcm_state_assoc_t *assoc, guint8 pctx_id, gboolean create) } +/* +Create new PDV object and initialize all members +*/ static dcm_state_pdv_t* dcm_state_pdv_new(dcm_state_pctx_t *pctx, guint32 packet_no, guint32 offset) { - /* Create new PDV object and initialize the members */ - dcm_state_pdv_t *pdv; pdv = (dcm_state_pdv_t *) wmem_alloc0(wmem_file_scope(), sizeof(dcm_state_pdv_t)); @@ -906,7 +915,7 @@ dcm_state_pdv_new(dcm_state_pctx_t *pctx, guint32 packet_no, guint32 offset) pdv->packet_no = packet_no; pdv->offset = offset; - /* add to the end of the list list */ + /* add to the end of the list */ if (pctx->last_pdv) { pctx->last_pdv->next = pdv; pdv->prev = pctx->last_pdv; @@ -1242,21 +1251,21 @@ dcm_export_create_header(guint32 *dcm_header_len, const gchar *sop_class_uid, gc } -static void -dcm_export_create_object(packet_info *pinfo, dcm_state_assoc_t *assoc, dcm_state_pdv_t *pdv) -{ - /* Concat different PDVs into one buffer and add it to export object list - This function caused quite a few crashes, with all the string pointers +/* +Concatenate related PDVs into one buffer and add it to the export object list. - Every since the adding fragment_add_seq_next() and process_reassembled_data(), - this function would not need to perform any reassembly anymore, but it's - left unchanged, to still support export, even when global_dcm_reassemble - is not set. +Supports both modes: - Using process_reassembled_data(), all data will be in the last PDV, and all - its predecessors will zero data. - */ +- Multiple DICOM PDVs are reassembled with fragment_add_seq_next() + and process_reassembled_data(). In this case all data will be in the last + PDV, and all its predecessors will have zero data. + +- DICOM PDVs are keep separate. Every PDV contains data. +*/ +static void +dcm_export_create_object(packet_info *pinfo, dcm_state_assoc_t *assoc, dcm_state_pdv_t *pdv) +{ dicom_eo_t *eo_info = NULL; @@ -1385,7 +1394,7 @@ static guint32 dcm_vm_item_count(guint32 value_length, guint32 item_length) { - /* This could all be formulated in a single line but it doe not make it easier to read */ + /* This could all be formulated in a single line but it does not make it easier to read */ if (value_length == 0) { return 0; @@ -1399,13 +1408,13 @@ dcm_vm_item_count(guint32 value_length, guint32 item_length) } +/* +Decode the association header + */ static guint32 dissect_dcm_assoc_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset, dcm_state_assoc_t *assoc, guint8 pdu_type, guint32 pdu_len) { - /* - * Decode association header - */ proto_item *assoc_header_pitem; proto_tree *assoc_header_ptree; /* Tree for item details */ @@ -1685,13 +1694,13 @@ dissect_dcm_assoc_item(tvbuff_t *tvb, proto_tree *tree, guint32 offset, } } +/* +Decode the SOP Class Extended Negotiation Sub-Item Fields in a association request or response. +Lookup UIDs if requested +*/ static void dissect_dcm_assoc_sopclass_extneg(tvbuff_t *tvb, proto_tree *tree, guint32 offset) { - /* - * Decode the SOP Class Extended Negotiation Sub-Item Fields in a association request or response. - * Lookup UIDs if requested - */ proto_tree *assoc_item_extneg_tree = NULL; /* Tree for item details */ proto_item *assoc_item_extneg_item = NULL; @@ -1788,12 +1797,12 @@ dissect_dcm_assoc_sopclass_extneg(tvbuff_t *tvb, proto_tree *tree, guint32 offse } } +/* +Decode user identities in the association +*/ static void dissect_dcm_assoc_user_identify(tvbuff_t *tvb, proto_tree *tree, guint32 offset) { - /* - * Decode unknown type - */ proto_tree *assoc_item_user_identify_tree = NULL; /* Tree for item details */ proto_item *assoc_item_user_identify_item = NULL; @@ -1836,12 +1845,12 @@ dissect_dcm_assoc_user_identify(tvbuff_t *tvb, proto_tree *tree, guint32 offset) } } +/* +Decode unknown item types in the association +*/ static void dissect_dcm_assoc_unknown(tvbuff_t *tvb, proto_tree *tree, guint32 offset) { - /* - * Decode unknown type - */ proto_tree *assoc_item_unknown_tree = NULL; /* Tree for item details */ proto_item *assoc_item_unknown_item = NULL; @@ -1858,16 +1867,15 @@ dissect_dcm_assoc_unknown(tvbuff_t *tvb, proto_tree *tree, guint32 offset) offset += 4; proto_tree_add_item(assoc_item_unknown_tree, hf_dcm_assoc_item_data, tvb, offset, item_len, ENC_NA); - } +/* +Decode the SCP/SCU Role Selection Sub-Item Fields in a association request or response. +Lookup UIDs if requested +*/ static void dissect_dcm_assoc_role_selection(tvbuff_t *tvb, proto_tree *tree, guint32 offset) { - /* - * Decode the SCP/SCU Role Selection Sub-Item Fields in a association request or response. - * Lookup UIDs if requested - */ proto_tree *assoc_item_rolesel_tree; /* Tree for item details */ proto_item *assoc_item_rolesel_item; @@ -1923,12 +1931,12 @@ dissect_dcm_assoc_role_selection(tvbuff_t *tvb, proto_tree *tree, guint32 offset proto_tree_add_item(assoc_item_rolesel_tree, hf_dcm_info_rolesel_scprole, tvb, offset+7+sop_class_uid_len, 1, ENC_BIG_ENDIAN); } +/* +Decode the Asynchronous operations (and sub-operations) Window Negotiation Sub-Item Fields in a association request or response. +*/ static void dissect_dcm_assoc_async_negotiation(tvbuff_t *tvb, proto_tree *tree, guint32 offset) { - /* - * Decode the Asynchronous operations (and sub-operations) Window Negotiation Sub-Item Fields in a association request or response. - */ proto_tree *assoc_item_asyncneg_tree; /* Tree for item details */ proto_item *assoc_item_asyncneg_item; @@ -1999,7 +2007,7 @@ dissect_dcm_pctx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, pctx_id = tvb_get_guint8(tvb, offset); pctx_result = tvb_get_guint8(tvb, 2 + offset); /* only set in responses, otherwise reserved and 0x00 */ - /* Find or create dicom context object */ + /* Find or create DICOM context object */ pctx = dcm_state_pctx_get(assoc, pctx_id, TRUE); if (pctx == NULL) { /* Internal error. Failed to create data structure */ return; @@ -2146,7 +2154,6 @@ static void dissect_dcm_userinfo(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint32 len, const gchar *pitem_prefix) { - proto_item *userinfo_pitem = NULL; proto_tree *userinfo_ptree = NULL; /* Tree for presentation context details */ @@ -2500,7 +2507,10 @@ dissect_dcm_pdv_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, return offset; } -/* Based on the value representation, decode the value of one tag. Support VM>1 for most types, but not all. Returns new offset */ +/* +Based on the value representation, decode the value of one tag. +Support VM>1 for most types, but not all. Returns new offset +*/ static guint32 dissect_dcm_tag_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, dcm_state_pdv_t *pdv, guint32 offset, guint16 grp, guint16 elm, @@ -2764,12 +2774,12 @@ dissect_dcm_tag_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, dcm_s } +/* +Return true, if the required size does not fit at position 'offset'. +*/ static gboolean dcm_tag_is_open(dcm_state_pdv_t *pdv, guint32 startpos, guint32 offset, guint32 endpos, guint32 size_required) { - /* Return true, if the required size does not fit at position 'offset'. - Copy memory from startpos to endpos into pdv structure - */ if (offset + size_required > endpos) { @@ -3282,11 +3292,13 @@ dissect_dcm_tag(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, return offset; } +/* +'Decode' open tags from previous PDV. It mostly ends in 'continuation' or 'end' in the description. +*/ static guint32 dissect_dcm_tag_open(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, dcm_state_pdv_t *pdv, guint32 offset, guint32 endpos, gboolean *is_first_tag) { - /* 'Decode' open tags from previous PDV */ proto_item *pitem = NULL; @@ -3357,40 +3369,75 @@ dissect_dcm_tag_open(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, return offset; } +/* +Decode the tag section inside a PDV. This can be a single combined dataset +or DICOM natively split PDVs. Therefore it needs to resume previously opened tags. +For data PDVs, only process tags when tree is set. +For command PDVs, process all tags. +On export copy the content to the export buffer. +*/ static guint32 -dissect_dcm_pdv_body(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, - dcm_state_pdv_t *pdv, guint32 offset, guint32 pdv_body_len, - gchar **pdv_description) +dissect_dcm_pdv_body( + tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *tree, + dcm_state_assoc_t *assoc, + dcm_state_pdv_t *pdv, + guint32 offset, + guint32 pdv_body_len, + gchar **pdv_description) { - /* Handle one PDV inside a data PDU */ - const gchar *tag_value = NULL; gboolean dummy = FALSE; guint32 endpos = 0; endpos = offset + pdv_body_len; - if (pdv->syntax == DCM_UNK) { - /* Eventually, we will have a syntax detector. Until then, don't decode */ + if (have_tap_listener(dicom_eo_tap)) { + + if (pdv->data_len == 0) { + /* Copy pure DICOM data to buffer, without PDV flags + Packet scope for the memory allocation is too small, since we may have PDV in different tvb. + Therefore check if this was already done. + */ + pdv->data = wmem_alloc0(wmem_file_scope(), pdv_body_len); + pdv->data_len = pdv_body_len; + tvb_memcpy(tvb, pdv->data, offset, pdv_body_len); + } - proto_tree_add_bytes_format(tree, hf_dcm_data_tag, tvb, - offset, pdv_body_len, NULL, - "(%04x,%04x) %-8x Unparsed data", 0, 0, pdv_body_len); + if ((pdv_body_len > 0) && (pdv->is_last_fragment)) { + /* At the last segment, merge all related previous PDVs and copy to export buffer */ + dcm_export_create_object(pinfo, assoc, pdv); + } } - else { - gboolean is_first_tag = TRUE; + if (pdv->is_command || tree) { + /* Performance optimization starts here. Don't put any COL_INFO related stuff in here */ - /* Treat the left overs */ - offset = dissect_dcm_tag_open(tvb, pinfo, tree, pdv, offset, endpos, &is_first_tag); + if (pdv->syntax == DCM_UNK) { + /* Eventually, we will have a syntax detector. Until then, don't decode */ - /* Decode all tags, sequences and items in this PDV recursively */ - while (offset < endpos) { - offset = dissect_dcm_tag(tvb, pinfo, tree, pdv, offset, endpos, is_first_tag, &tag_value, &dummy); - is_first_tag = FALSE; + proto_tree_add_bytes_format(tree, hf_dcm_data_tag, tvb, + offset, pdv_body_len, NULL, + "(%04x,%04x) %-8x Unparsed data", 0, 0, pdv_body_len); + } + else { + + gboolean is_first_tag = TRUE; + + /* Treat the left overs */ + offset = dissect_dcm_tag_open(tvb, pinfo, tree, pdv, offset, endpos, &is_first_tag); + + /* Decode all tags, sequences and items in this PDV recursively */ + while (offset < endpos) { + offset = dissect_dcm_tag(tvb, pinfo, tree, pdv, offset, endpos, is_first_tag, &tag_value, &dummy); + is_first_tag = FALSE; + } } } + *pdv_description = pdv->desc; + if (pdv->is_command) { if (pdv->is_warning) { @@ -3425,23 +3472,17 @@ dissect_dcm_pdv_body(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, *pdv_description = wmem_strdup_printf(wmem_packet_scope(), "%s F=%d", *pdv_description, pdv->no_failed); } } - else { - *pdv_description = pdv->desc; - } } - else { - *pdv_description = pdv->desc; - } - } - else { - *pdv_description = pdv->desc; + } - return endpos; /* we could try offset as return value */ + return endpos; } /* -Handle one PDV inside a data PDU. Perform the necessary reassembly of PDV fragments. Create PDV object when needed. +Handle one PDV inside a data PDU. When needed, perform the reassembly of PDV fragments. +PDV fragments are different from TCP fragmentation. +Create PDV object when needed. Return pdv_description to be used e.g. in COL_INFO. */ static guint32 @@ -3453,23 +3494,22 @@ dissect_dcm_pdv_fragmented(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, dcm_state_pdv_t *pdv = NULL; - tvbuff_t *next_tvb = NULL; + tvbuff_t *combined_tvb = NULL; fragment_head *head = NULL; guint32 reassembly_id; guint32 pdv_body_len; - guint32 startpos; - startpos = offset; pdv_body_len = pdv_len-2; /* Dissect Context ID, Find PDV object, Decode Command/Data flag and More Fragments flag */ offset = dissect_dcm_pdv_header(tvb, pinfo, tree, assoc, offset, &pdv); - /* When fragmented, do reassembly and subsequently decode merged PDV */ if (global_dcm_reassemble) { - + /* Combine the different PDVs. This is the default preference and useful in most scenarios. + This will create one 'huge' PDV. E.g. a CT image will fits in one buffer. + */ conv = find_conversation_pinfo(pinfo, 0); /* Try to create somewhat unique ID. @@ -3477,90 +3517,73 @@ dissect_dcm_pdv_fragmented(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, */ DISSECTOR_ASSERT(conv); - reassembly_id = (((conv->conv_index) & 0x00FFFFFF) << 8) + pdv->pctx_id; - - head = fragment_add_seq_next(&dcm_pdv_reassembly_table, - tvb, offset, pinfo, reassembly_id, NULL, - pdv_body_len, - !(pdv->is_last_fragment)); - - if (head && (head->next == NULL)) { - /* Was not really fragmented, therefore use 'conventional' decoding - fragment_add_seq_next() won't add any items to the list, when last fragment only - */ - - offset = dissect_dcm_pdv_body(tvb, pinfo, tree, pdv, offset, pdv_body_len, pdv_description); - } - else { - next_tvb = process_reassembled_data(tvb, offset, pinfo, - "Reassembled PDV", head, - &dcm_pdv_fragment_items, NULL, tree); - - if (next_tvb == NULL) { - /* Just show this as a fragment */ - - if (head && head->reassembled_in != pinfo->num) { - - if (pdv->desc) { - /* We know the presentation context already */ - *pdv_description = wmem_strdup_printf(wmem_packet_scope(), "%s (reassembled in #%u)", pdv->desc, head->reassembled_in); - } - else { - /* Decoding of the presentation context did not occur yet or did not succeed */ - *pdv_description = wmem_strdup_printf(wmem_packet_scope(), "PDV Fragment (reassembled in #%u)", head->reassembled_in); - } + /* The following expression seems to executed late in VS2017 in 'RelWithDebInf'. + Therefore it may appear as 0 at first + */ + reassembly_id = (((conv->conv_index) & 0x00FFFFFF) << 8) + (guint32)(pdv->pctx_id); + + /* This one will chain the packets until 'is_last_fragment' */ + head = fragment_add_seq_next( + &dcm_pdv_reassembly_table, + tvb, + offset, + pinfo, + reassembly_id, + NULL, + pdv_body_len, + !(pdv->is_last_fragment)); + + /* Will return a complete buffer, once last fragment is hit. + The description is not used in packet-dcm. COL_INFO is set specifically in dissect_dcm_pdu() + */ + combined_tvb = process_reassembled_data( + tvb, + offset, + pinfo, + "Reassembled PDV", + head, + &dcm_pdv_fragment_items, + NULL, + tree); + + if (combined_tvb == NULL) { + /* Just show this as a fragment */ + + if (head && head->reassembled_in != pinfo->num) { + + if (pdv->desc) { + /* We know the presentation context already */ + *pdv_description = wmem_strdup_printf(wmem_packet_scope(), "%s (reassembled in #%u)", pdv->desc, head->reassembled_in); } else { - /* We have not done any tag decoding yet */ - *pdv_description = wmem_strdup(wmem_packet_scope(), "PDV Fragment"); + /* Decoding of the presentation context did not occur yet or did not succeed */ + *pdv_description = wmem_strdup_printf(wmem_packet_scope(), "PDV Fragment (reassembled in #%u)", head->reassembled_in); } - - offset += pdv_body_len; } else { - guint next_tvb_length = tvb_captured_length(next_tvb); - /* Decode reassembled data */ - - if (tree || have_tap_listener(dicom_eo_tap)) { - /* The performance optimization now starts at tag level. - - During, tree can be NULL, but we need a few tags to be decoded, - i.e Class & Instance UID, so the export dialog has all information and - that the dicom header is complete - */ - offset += dissect_dcm_pdv_body(next_tvb, pinfo, tree, pdv, 0, next_tvb_length, pdv_description); - } - - if (have_tap_listener(dicom_eo_tap)) { - /* Copy pure DICOM data to buffer, no PDV flags */ - - pdv->data = wmem_alloc(wmem_packet_scope(), next_tvb_length); - tvb_memcpy(next_tvb, pdv->data, 0, next_tvb_length); - pdv->data_len = next_tvb_length; - - /* Copy to export buffer */ - dcm_export_create_object(pinfo, assoc, pdv); - } + /* We don't know the last fragment yet (and/or we'll never see it). + This can happen, e.g. when TCP packet arrive our of order. + */ + *pdv_description = wmem_strdup(wmem_packet_scope(), "PDV Fragment"); } - } - } - else if (tree) { - /* Do not reassemble PDVs, i.e. decode PDV one by one. Only execute when in detail mode */ - offset = dissect_dcm_pdv_body(tvb, pinfo, tree, pdv, offset, pdv_body_len, pdv_description); - - /* During DICOM Export, perform a few extra steps */ - if (have_tap_listener(dicom_eo_tap)) { - /* Copy pure DICOM data to buffer, no PDV flags */ - pdv->data = wmem_alloc(wmem_packet_scope(), pdv_body_len); - tvb_memcpy(tvb, pdv->data, startpos, pdv_body_len); - pdv->data_len = pdv_body_len; - - if ((pdv_body_len > 0) && (pdv->is_last_fragment)) { - /* At the last segment, merge all related previous PDVs and copy to export buffer */ - dcm_export_create_object(pinfo, assoc, pdv); - } + offset += pdv_body_len; } + else + { + /* Decode reassembled data. This needs to be += */ + offset += dissect_dcm_pdv_body(combined_tvb, pinfo, tree, assoc, pdv, 0, tvb_captured_length(combined_tvb), pdv_description); + } + } + else + { + /* Do not reassemble DICOM PDVs, i.e. decode PDVs one by one. + This may be useful when troubleshooting PDU length issues, + or to better understand the PDV split. + The tag level decoding is more challenging, as leftovers need + to be displayed adequately. Not a big deal for binary values. + */ + offset = dissect_dcm_pdv_body(tvb, pinfo, tree, assoc, pdv, offset, pdv_body_len, pdv_description); } return offset; @@ -3810,7 +3833,7 @@ dissect_dcm_main(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean i } /* -Call back function used to register +Callback function used to register */ static int dissect_dcm_static(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) @@ -3891,6 +3914,9 @@ dissect_dcm_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 off if (pdu_type == 4) { col_set_str(pinfo->cinfo, COL_INFO, "P-DATA"); + /* Everything that needs to be shown in any UI column (like COL_INFO) + needs to be calculated also with tree == null + */ offset = dissect_dcm_pdu_data(tvb, pinfo, dcm_ptree, assoc, offset, pdu_len, &pdu_data_description); if (pdu_data_description) { @@ -3907,8 +3933,9 @@ dissect_dcm_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 off return offset; /* return the number of processed bytes */ } -/* Register the protocol with Wireshark */ - +/* +Register the protocol with Wireshark +*/ void proto_register_dcm(void) { @@ -4150,7 +4177,7 @@ proto_register_dcm(void) prefs_register_bool_preference(dcm_module, "seq_tree", "Create subtrees for Sequences and Items", "Create a node for sequences and items, and show children in a hierarchy. " - "Deselect this option, if you prefer a flat display or e.g. " + "De-select this option, if you prefer a flat display or e.g. " "when using TShark to create a text output.", &global_dcm_seq_subtree); @@ -4169,6 +4196,7 @@ proto_register_dcm(void) prefs_register_bool_preference(dcm_module, "pdv_reassemble", "Merge fragmented PDVs", "Decode all DICOM tags in the last PDV. This will ensure the proper reassembly. " + "De-select, to troubleshoot PDU length issues, or to understand PDV fragmentation. " "When not set, the decoding may fail and the exports may become corrupt.", &global_dcm_reassemble); |