2004-05-08 08:49:02 +00:00
/* packet-dcm.c
* Routines for DICOM dissection
2016-01-18 05:30:51 +00:00
* Copyright 2003 , Rich Coe < richcoe2 @ gmail . com >
2019-02-11 11:27:19 +00:00
* Copyright 2008 - 2019 , David Aggeler < david_aggeler @ hispeed . ch >
2004-05-08 08:49:02 +00:00
*
2019-07-27 07:54:44 +00:00
* DICOM communication protocol : https : //www.dicomstandard.org/current/
2018-03-05 10:54:55 +00:00
*
* Part 5 : Data Structures and Encoding
* Part 6 : Data Dictionary
* Part 7 : Message Exchange
* Part 8 : Network Communication Support for Message Exchange
* Part 10 : Media Storage and File Format
2004-05-08 08:49:02 +00:00
*
2006-05-21 04:49:01 +00:00
* Wireshark - Network traffic analyzer
* By Gerald Combs < gerald @ wireshark . org >
2004-05-08 08:49:02 +00:00
* Copyright 1998 Gerald Combs
*
2018-02-12 11:23:27 +00:00
* SPDX - License - Identifier : GPL - 2.0 - or - later
2004-05-08 08:49:02 +00:00
*/
2018-03-05 10:54:55 +00:00
/*
*
2008-10-11 14:25:02 +00:00
* ToDo
2005-05-02 21:56:40 +00:00
*
2018-03-05 10:54:55 +00:00
* - Implement value multiplicity ( VM ) consistently in dissect_dcm_tag_value ( )
2008-10-11 14:25:02 +00:00
* - Syntax detection , in case an association request is missing in capture
* - Read private tags from configuration and parse in capture
2018-03-05 10:54:55 +00:00
*
* History
*
2019-02-11 11:27:19 +00:00
* Feb 2019 - David Aggeler
*
* - Fixed re - assembly and export ( consolidated duplicate code )
* - Fixed random COL_INFO issues
2019-02-18 14:53:06 +00:00
* - Improved COL_INFO for C - FIND
* - Improved COL_INFO for multiple PDUs in one frame
2019-02-11 11:27:19 +00:00
*
* Feb 2019 - Rickard Holmberg
*
* - Updated DICOM definitions to 2019 a
*
* Oct 2018 - Rickard Holmberg
*
* - Moved DICOM definitions to packet - dcm . h
* - Generate definitions from docbook with Phyton script
* - Updated DICOM definitions to 2018 e
*
2018-05-06 15:33:51 +00:00
* June 2018 - David Aggeler
*
* - Fixed initial COL_INFO for associations . It used to ' append ' instead of ' set ' .
* - Changed initial length check from tvb_reported_length ( ) to tvb_captured_length ( )
* - Heuristic Dissection :
* o Modified registration , so it can be clearly identified in the Enable / Disable Protocols dialog
* o Enabled by default
* o Return proper data type
*
* February 2018 - David Aggeler
2018-03-05 10:54:55 +00:00
*
* - Fixed Bug 14415. Some tag descriptions which are added to the parent item ( 32 tags ) .
* If one of those was empty a crash occurred . Mainly the RTPlan modality was affected .
* - Fixed length decoding for OD , OL , UC , UR
* - Fixed hf_dcm_assoc_item_type to be interpreted as 1 byte
* - Fixed pdu_type to be interpreted as 1 byte
* - Fixed decoding of AT type , where value length was wrongly reported in capture as 2 ( instead of n * 4 )
*
* Misc . authors & dates
*
* - Fixed ' AT ' value representation . The ' element ' was equal to the ' group ' .
* - Changed ' FL ' value representations
2010-08-09 19:28:09 +00:00
*
2015-01-18 21:02:15 +00:00
* September 2013 - Pascal Quantin
*
* - Replace all ep_ and se_ allocation with wmem_ allocations
*
2013-02-17 19:36:08 +00:00
* February 2013 - Stefan Allers
*
2019-02-11 11:27:19 +00:00
* - Support for dissection of Extended Negotiation ( Query / Retrieve )
2013-02-17 19:36:08 +00:00
* - Support for dissection of SCP / SCU Role Selection
* - Support for dissection of Async Operations Window Negotiation
2018-03-05 10:54:55 +00:00
* - Fixed : Improper calculation of length for Association Header
2013-02-17 19:36:08 +00:00
* - Missing UIDs ( Transfer Syntax , SOP Class . . . ) added acc . PS 3. x - 2011
*
2010-08-09 19:28:09 +00:00
* Jul 11 , 2010 - David Aggeler
*
* - Finally , better reassembly using fragment_add_seq_next ( ) .
* The previous mode is still supported .
* - Fixed sporadic decoding and export issues . Always decode
* association negotiation , since performance check ( tree = = NULL )
* is now only in dissect_dcm_pdv_fragmented ( ) .
* - Added one more PDV length check
2008-10-11 14:25:02 +00:00
* - Show Association Headers as individual items
2010-08-09 19:28:09 +00:00
* - Code cleanup . i . e . moved a few lookup functions to be closer to the dissection
2008-10-31 22:59:14 +00:00
*
2010-08-09 19:28:09 +00:00
* May 13 , 2010 - David Aggeler ( SVN 32815 )
2010-05-14 21:54:48 +00:00
*
* - Fixed HF to separate signed & unsigned values and to have BASE_DEC all signed ones
* - Fixed private sequences with undefined length in ILE
* - Fixed some spellings in comments
*
* May 27 , 2009 - David Aggeler ( SVN 29060 )
2009-07-10 21:54:29 +00:00
*
* - Fixed corrupt files on DICOM Export
* - Fixed memory limitation on DICOM Export
2010-05-14 21:54:48 +00:00
* - Removed minimum packet length for static port mode
2009-07-10 21:54:29 +00:00
* - Simplified checks for heuristic mode
* - Removed unused functions
*
* May 17 , 2009 - David Aggeler ( SVN 28392 )
2009-05-18 06:21:22 +00:00
*
* - Spelling
* - Added expert_add_info ( ) for status responses with warning & error level
* - Added command details in info column ( optionally )
*
2010-05-14 21:54:48 +00:00
* Dec 19 , 2008 to Mar 29 , 2009 - Misc ( SVN 27880 )
2009-05-18 06:21:22 +00:00
*
* - Spellings , see SVN
*
* Oct 26 , 2008 - David Aggeler ( SVN 26662 )
2008-10-31 22:59:14 +00:00
*
* - Support remaining DICOM / ARCNEMA tags
*
2008-10-12 21:35:23 +00:00
* Oct 3 , 2008 - David Aggeler ( SVN 26417 )
2005-05-02 21:56:40 +00:00
*
2008-10-11 14:25:02 +00:00
* - DICOM Tags : Support all tags , except for group 1000 , 7F xx
* and tags ( 0020 , 3100 to 0020 , 31FF ) .
2010-08-09 19:28:09 +00:00
* Luckily these ones are retired anyhow
2008-10-11 14:25:02 +00:00
* - DICOM Tags : Optionally show sequences , items and tags as subtree
* - DICOM Tags : Certain items do have a summary of a few contained tags
* - DICOM Tags : Support all defined VR representations
* - DICOM Tags : For Explicit Syntax , use VR in the capture
* - DICOM Tags : Lookup UIDs
* - DICOM Tags : Handle split at PDV start and end . RT Structures were affected by this .
* - DICOM Tags : Handle split in tag header
2005-05-02 21:56:40 +00:00
*
2008-10-11 14:25:02 +00:00
* - Added all status messages from PS 3.4 & PS 3.7
* - Fixed two more type warnings on solaris , i . e . ( gchar * ) tvb_get_ephemeral_string
* - Replaced all ep_alloc ( ) with ep_alloc0 ( ) and se_alloc ( ) with se_alloc0 ( )
* - Replaced g_strdup with ep_strdup ( ) or se_strdup ( )
* - Show multiple PDU description in COL_INFO , not just last one . Still not all , but more
* sophisticated logic for this column is probably overkill
2010-05-14 21:54:48 +00:00
* - Since DICOM is a 32 bit protocol with all length items specified unsigned
2008-10-11 14:25:02 +00:00
* all offset & position variables are now declared as guint32 for dissect_dcm_pdu and
* its nested functions . dissect_dcm_main ( ) remained by purpose on int ,
2010-05-14 21:54:48 +00:00
* since we request data consolidation , requiring a TRUE as return value
2008-10-11 14:25:02 +00:00
* - Decode DVTk streams when using defined ports ( not in heuristic mode )
* - Changed to warning level 4 ( for MSVC ) and fixed the warnings
* - Code cleanup & removed last DISSECTOR_ASSERT ( )
2005-05-02 21:56:40 +00:00
*
2008-10-11 14:25:02 +00:00
* Jul 25 , 2008 - David Aggeler ( SVN 25834 )
2005-05-02 21:56:40 +00:00
*
2008-10-11 14:25:02 +00:00
* - Replaced guchar with gchar , since it caused a lot of warnings on solaris .
* - Moved a little more form the include to this one to be consistent
2005-05-02 21:56:40 +00:00
*
2008-10-11 14:25:02 +00:00
* Jul 17 , 2008 - David Aggeler
2005-05-02 21:56:40 +00:00
*
2010-05-14 21:54:48 +00:00
* - Export objects as part 10 compliant DICOM file . Finally , this major milestone has been reached .
2008-10-11 14:25:02 +00:00
* - PDVs are now a child of the PCTX rather than the ASSOC object .
* - Fixed PDV continuation for unknown tags ( e . g . RT Structure Set )
* - Replaced proprietary trim ( ) with g_strstrip ( )
* - Fixed strings that are displayed with / 000 ( padding of odd length )
* - Added expert_add_info ( ) for invalid flags and presentation context IDs
2005-05-02 21:56:40 +00:00
*
2008-10-11 14:25:02 +00:00
* Jun 17 , 2008 - David Aggeler
2005-05-02 21:56:40 +00:00
*
2008-10-11 14:25:02 +00:00
* - Support multiple PDVs per PDU
* - Better summary , in PDV , PDU header and in INFO Column , e . g . show commands like C - STORE
* - Fixed Association Reject ( was working before my changes )
* - Fixed PDV Continuation with very small packets . Reduced minimum packet length
* from 10 to 2 Bytes for PDU Type 4
* - Fixed PDV Continuation . Last packet was not found correctly .
2010-05-14 21:54:48 +00:00
* - Fixed compilation warning ( build 56 on solaris )
2008-10-11 14:25:02 +00:00
* - Fixed tree expansion ( hf_dcm_xxx )
2008-12-17 00:08:38 +00:00
* - Added expert_add_info ( ) for Association Reject
* - Added expert_add_info ( ) for Association Abort
2008-10-11 14:25:02 +00:00
* - Added expert_add_info ( ) for short PDVs ( i . e . last fragment , but PDV is not completed yet )
* - Clarified and grouped data structures and its related code ( dcmItem , dcmState ) to have
2019-02-18 14:53:06 +00:00
* consistent _new ( ) & _get ( ) functions and to be according to coding conventions
2008-10-11 14:25:02 +00:00
* - Added more function declaration to be more consistent
* - All dissect_dcm_xx now have ( almost ) the same parameter order
* - Removed DISSECTOR_ASSERT ( ) for packet data errors . Not designed to handle this .
* - Handle multiple DICOM Associations in a capture correctly , i . e . if presentation contexts are different .
2008-07-25 13:20:18 +00:00
*
2008-10-11 14:25:02 +00:00
* May 23 , 2008 - David Aggeler
2008-07-25 13:20:18 +00:00
*
* - Added Class UID lookup , both in the association and in the transfer
* - Better hierarchy for items in Association request / response and therefore better overview
* This was a major rework . Abstract Syntax & Transfer Syntax are now children
* 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
2019-02-11 11:27:19 +00:00
* - Added preference with DICOM TCP ports , to prevent ' stealing ' the conversation
2008-07-25 13:20:18 +00:00
* i . e . don ' t just rely on heuristic
* - Use pinfo - > desegment_len instead of tcp_dissect_pdus ( )
* - Returns number of bytes parsed
* - For non DICOM packets , do not allocate any memory anymore ,
* - Added one DISSECTOR_ASSERT ( ) to prevent loop with len = = 0. More to come
* - Heuristic search is optional to save resources for non DICOM users
*
* - Output naming closer to DICOM Standard
* - Variable names closer to Standard
* - Protocol in now called DICOM not dcm anymore .
* - Fixed type of a few variables to guchar instead of guint8
* - Changed some of the length displays to decimal , because the hex value can
* already be seen in the packet and decimal is easier for length calculation
* in respect to TCP
*
2008-10-11 14:25:02 +00:00
* Apr 28 , 2005 - Rich Coe
2008-07-25 13:36:58 +00:00
*
2008-10-11 14:25:02 +00:00
* - fix memory leak when Assoc packet is processed repeatedly in wireshark
* - removed unused partial packet flag
* - added better support for DICOM VR
2014-10-02 21:47:19 +00:00
* - sequences
* - report actual VR in packet display , if supplied by xfer syntax
* - show that we are not displaying entire tag string with ' [ . . . ] ' ,
* some tags can hold up to 2 ^ 32 - 1 chars
2008-07-25 13:36:58 +00:00
*
2008-10-11 14:25:02 +00:00
* - remove my goofy attempt at trying to get access to the fragmented packets
* - process all the data in the Assoc packet even if display is off
* - limit display of data in Assoc packet to defined size of the data even
* if reported size is larger
* - show the last tag in a packet as [ incomplete ] if we don ' t have all the data
* - added framework for reporting DICOM async negotiation ( not finished )
* ( I ' m not aware of an implementation which currently supports this )
2008-07-25 13:36:58 +00:00
*
2008-10-11 14:25:02 +00:00
* Nov 9 , 2004 - Rich Coe
2008-07-25 13:36:58 +00:00
*
2008-10-11 14:25:02 +00:00
* - Fixed the heuristic code - - sometimes a conversation already exists
2019-02-11 11:27:19 +00:00
* - Fixed the dissect code to display all the tags in the PDU
2008-10-11 14:25:02 +00:00
*
2010-05-14 21:54:48 +00:00
* Initial - Rich Coe
2008-10-11 14:25:02 +00:00
*
* - It currently displays most of the DICOM packets .
* - I ' ve used it to debug Query / Retrieve , Storage , and Echo protocols .
* - Not all DICOM tags are currently displayed symbolically .
* Unknown tags are displayed as ' ( unknown ) '
* 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
2019-02-11 11:27:19 +00:00
* symbolically display the data .
2008-07-25 22:58:05 +00:00
*
2004-05-08 08:49:02 +00:00
*/
2012-09-20 02:03:38 +00:00
# include "config.h"
2008-10-11 14:25:02 +00:00
2004-05-08 08:49:02 +00:00
# include <epan/packet.h>
2013-11-10 15:59:37 +00:00
# include <epan/exceptions.h>
2012-05-15 19:23:35 +00:00
# include <epan/prefs.h>
2008-07-25 13:36:58 +00:00
# include <epan/expert.h>
# include <epan/tap.h>
2010-08-09 19:28:09 +00:00
# include <epan/reassemble.h>
2016-11-24 14:37:01 +00:00
# include <epan/export_object.h>
2004-05-08 08:49:02 +00:00
# include "packet-tcp.h"
2018-10-22 15:50:42 +00:00
# include "packet-dcm.h"
2013-12-15 23:44:12 +00:00
void proto_register_dcm ( void ) ;
void proto_reg_handoff_dcm ( void ) ;
2008-07-25 13:20:18 +00:00
# define DICOM_DEFAULT_RANGE "104"
2008-07-25 13:36:58 +00:00
/* Many thanks to http://medicalconnections.co.uk/ for the GUID */
2014-10-02 21:47:19 +00:00
# define WIRESHARK_IMPLEMENTATION_UID "1.2.826.0.1.3680043.8.427.10"
# define WIRESHARK_MEDIA_STORAGE_SOP_CLASS_UID "1.2.826.0.1.3680043.8.427.11.1"
# define WIRESHARK_MEDIA_STORAGE_SOP_INSTANCE_UID_PREFIX "1.2.826.0.1.3680043.8.427.11.2"
# define WIRESHARK_IMPLEMENTATION_VERSION "WIRESHARK"
2008-07-25 13:36:58 +00:00
2008-10-11 14:25:02 +00:00
static gboolean global_dcm_export_header = TRUE ;
2014-10-02 21:47:19 +00:00
static guint global_dcm_export_minsize = 4096 ; /* Filter small objects in export */
2008-10-11 14:25:02 +00:00
static gboolean global_dcm_seq_subtree = TRUE ;
2014-10-02 21:47:19 +00:00
static gboolean global_dcm_tag_subtree = FALSE ; /* Only useful for debugging */
static gboolean global_dcm_cmd_details = TRUE ; /* Show details in header and info column */
static gboolean global_dcm_reassemble = TRUE ; /* Merge fragmented PDVs */
2008-10-11 14:25:02 +00:00
2017-02-25 00:46:49 +00:00
static wmem_map_t * dcm_tag_table = NULL ;
static wmem_map_t * dcm_uid_table = NULL ;
static wmem_map_t * dcm_status_table = NULL ;
2008-07-25 13:20:18 +00:00
2004-05-08 08:49:02 +00:00
/* Initialize the protocol and registered fields */
static int proto_dcm = - 1 ;
2008-07-25 13:36:58 +00:00
static int dicom_eo_tap = - 1 ;
2018-03-05 10:54:55 +00:00
static int hf_dcm_pdu_type = - 1 ;
2013-02-04 14:58:04 +00:00
static int hf_dcm_pdu_len = - 1 ;
static int hf_dcm_assoc_version = - 1 ;
static int hf_dcm_assoc_called = - 1 ;
static int hf_dcm_assoc_calling = - 1 ;
static int hf_dcm_assoc_reject_result = - 1 ;
static int hf_dcm_assoc_reject_source = - 1 ;
static int hf_dcm_assoc_reject_reason = - 1 ;
static int hf_dcm_assoc_abort_source = - 1 ;
static int hf_dcm_assoc_abort_reason = - 1 ;
static int hf_dcm_assoc_item_type = - 1 ;
static int hf_dcm_assoc_item_len = - 1 ;
static int hf_dcm_actx = - 1 ;
static int hf_dcm_pctx_id = - 1 ;
static int hf_dcm_pctx_result = - 1 ;
static int hf_dcm_pctx_abss_syntax = - 1 ;
static int hf_dcm_pctx_xfer_syntax = - 1 ;
2013-02-06 13:33:31 +00:00
static int hf_dcm_info = - 1 ;
2013-02-04 14:58:04 +00:00
static int hf_dcm_info_uid = - 1 ;
static int hf_dcm_info_version = - 1 ;
2013-02-06 13:33:31 +00:00
static int hf_dcm_info_extneg = - 1 ;
static int hf_dcm_info_extneg_sopclassuid_len = - 1 ;
static int hf_dcm_info_extneg_sopclassuid = - 1 ;
static int hf_dcm_info_extneg_relational_query = - 1 ;
static int hf_dcm_info_extneg_date_time_matching = - 1 ;
static int hf_dcm_info_extneg_fuzzy_semantic_matching = - 1 ;
static int hf_dcm_info_extneg_timezone_query_adjustment = - 1 ;
2013-02-17 19:36:08 +00:00
static int hf_dcm_info_rolesel = - 1 ;
static int hf_dcm_info_rolesel_sopclassuid_len = - 1 ;
static int hf_dcm_info_rolesel_sopclassuid = - 1 ;
static int hf_dcm_info_rolesel_scurole = - 1 ;
static int hf_dcm_info_rolesel_scprole = - 1 ;
static int hf_dcm_info_async_neg = - 1 ;
static int hf_dcm_info_async_neg_max_num_ops_inv = - 1 ;
static int hf_dcm_info_async_neg_max_num_ops_per = - 1 ;
2017-07-19 13:00:22 +00:00
static int hf_dcm_info_user_identify = - 1 ;
static int hf_dcm_info_user_identify_type = - 1 ;
static int hf_dcm_info_user_identify_response_requested = - 1 ;
static int hf_dcm_info_user_identify_primary_field_length = - 1 ;
static int hf_dcm_info_user_identify_primary_field = - 1 ;
static int hf_dcm_info_user_identify_secondary_field_length = - 1 ;
static int hf_dcm_info_user_identify_secondary_field = - 1 ;
2017-07-19 11:47:03 +00:00
static int hf_dcm_info_unknown = - 1 ;
static int hf_dcm_assoc_item_data = - 1 ;
2013-02-04 14:58:04 +00:00
static int hf_dcm_pdu_maxlen = - 1 ;
static int hf_dcm_pdv_len = - 1 ;
static int hf_dcm_pdv_ctx = - 1 ;
static int hf_dcm_pdv_flags = - 1 ;
static int hf_dcm_data_tag = - 1 ;
static int hf_dcm_tag = - 1 ;
static int hf_dcm_tag_vr = - 1 ;
static int hf_dcm_tag_vl = - 1 ;
static int hf_dcm_tag_value_str = - 1 ;
static int hf_dcm_tag_value_16u = - 1 ;
static int hf_dcm_tag_value_16s = - 1 ;
static int hf_dcm_tag_value_32s = - 1 ;
static int hf_dcm_tag_value_32u = - 1 ;
static int hf_dcm_tag_value_byte = - 1 ;
2008-10-11 14:25:02 +00:00
2004-05-08 08:49:02 +00:00
/* Initialize the subtree pointers */
2013-02-04 14:58:04 +00:00
static gint ett_dcm = - 1 ;
static gint ett_assoc = - 1 ;
static gint ett_assoc_header = - 1 ;
static gint ett_assoc_actx = - 1 ;
static gint ett_assoc_pctx = - 1 ;
static gint ett_assoc_pctx_abss = - 1 ;
static gint ett_assoc_pctx_xfer = - 1 ;
static gint ett_assoc_info = - 1 ;
static gint ett_assoc_info_uid = - 1 ;
static gint ett_assoc_info_version = - 1 ;
2013-02-06 13:33:31 +00:00
static gint ett_assoc_info_extneg = - 1 ;
2013-02-17 19:36:08 +00:00
static gint ett_assoc_info_rolesel = - 1 ;
static gint ett_assoc_info_async_neg = - 1 ;
2017-07-19 13:00:22 +00:00
static gint ett_assoc_info_user_identify = - 1 ;
2017-07-19 11:47:03 +00:00
static gint ett_assoc_info_unknown = - 1 ;
2013-02-04 14:58:04 +00:00
static gint ett_dcm_data = - 1 ;
static gint ett_dcm_data_pdv = - 1 ;
static gint ett_dcm_data_tag = - 1 ;
static gint ett_dcm_data_seq = - 1 ;
static gint ett_dcm_data_item = - 1 ;
2008-10-11 14:25:02 +00:00
2013-09-07 16:07:02 +00:00
static expert_field ei_dcm_data_tag = EI_INIT ;
static expert_field ei_dcm_multiple_transfer_syntax = EI_INIT ;
static expert_field ei_dcm_pdv_len = EI_INIT ;
static expert_field ei_dcm_pdv_flags = EI_INIT ;
static expert_field ei_dcm_pdv_ctx = EI_INIT ;
static expert_field ei_dcm_no_abstract_syntax = EI_INIT ;
static expert_field ei_dcm_no_abstract_syntax_uid = EI_INIT ;
static expert_field ei_dcm_status_msg = EI_INIT ;
static expert_field ei_dcm_no_transfer_syntax = EI_INIT ;
static expert_field ei_dcm_multiple_abstract_syntax = EI_INIT ;
static expert_field ei_dcm_invalid_pdu_length = EI_INIT ;
static expert_field ei_dcm_assoc_item_len = EI_INIT ;
static expert_field ei_dcm_assoc_rejected = EI_INIT ;
static expert_field ei_dcm_assoc_aborted = EI_INIT ;
2008-07-25 13:20:18 +00:00
static dissector_handle_t dcm_handle ;
2004-05-08 08:49:02 +00:00
static const value_string dcm_pdu_ids [ ] = {
{ 1 , " ASSOC Request " } ,
{ 2 , " ASSOC Accept " } ,
{ 3 , " ASSOC Reject " } ,
{ 4 , " Data " } ,
{ 5 , " RELEASE Request " } ,
{ 6 , " RELEASE Response " } ,
{ 7 , " ABORT " } ,
{ 0 , NULL }
} ;
2008-07-25 13:20:18 +00:00
static const value_string dcm_assoc_item_type [ ] = {
2004-05-08 08:49:02 +00:00
{ 0x10 , " Application Context " } ,
{ 0x20 , " Presentation Context " } ,
{ 0x21 , " Presentation Context Reply " } ,
2008-07-25 13:20:18 +00:00
{ 0x30 , " Abstract Syntax " } ,
{ 0x40 , " Transfer Syntax " } ,
2004-05-08 08:49:02 +00:00
{ 0x50 , " User Info " } ,
{ 0x51 , " Max Length " } ,
2008-07-25 13:20:18 +00:00
{ 0x52 , " Implementation Class UID " } ,
2013-02-17 19:36:08 +00:00
{ 0x53 , " Asynchronous Operations Window Negotiation " } ,
{ 0x54 , " SCP/SCU Role Selection " } ,
2008-07-25 13:36:58 +00:00
{ 0x55 , " Implementation Version " } ,
2013-02-06 13:33:31 +00:00
{ 0x56 , " SOP Class Extended Negotiation " } ,
2017-07-19 13:00:22 +00:00
{ 0x58 , " User Identity " } ,
{ 0 , NULL }
} ;
static const value_string user_identify_type_vals [ ] = {
{ 1 , " Username as a string in UTF-8 " } ,
{ 2 , " Username as a string in UTF-8 and passcode " } ,
{ 3 , " Kerberos Service ticket " } ,
{ 4 , " SAML Assertion " } ,
2004-05-08 08:49:02 +00:00
{ 0 , NULL }
} ;
2017-09-02 02:33:24 +00:00
/* Used for DICOM Export Object feature */
typedef struct _dicom_eo_t {
2018-03-05 10:54:55 +00:00
guint32 pkt_num ;
gchar * hostname ;
gchar * filename ;
gchar * content_type ;
guint32 payload_len ;
guint8 * payload_data ;
2017-09-02 02:33:24 +00:00
} dicom_eo_t ;
2019-01-01 03:36:12 +00:00
static tap_packet_status
2016-11-24 14:37:01 +00:00
dcm_eo_packet ( void * tapdata , packet_info * pinfo , epan_dissect_t * edt _U_ ,
const void * data )
{
export_object_list_t * object_list = ( export_object_list_t * ) tapdata ;
const dicom_eo_t * eo_info = ( const dicom_eo_t * ) data ;
export_object_entry_t * entry ;
if ( eo_info ) { /* We have data waiting for us */
/*
Don ' t copy any data . dcm_export_create_object ( ) is already g_malloc ( ) the items
Still , the values will be freed when the export Object window is closed .
Therefore , strings and buffers must be copied
*/
entry = g_new ( export_object_entry_t , 1 ) ;
entry - > pkt_num = pinfo - > num ;
entry - > hostname = eo_info - > hostname ;
entry - > content_type = eo_info - > content_type ;
entry - > filename = g_path_get_basename ( eo_info - > filename ) ;
entry - > payload_len = eo_info - > payload_len ;
entry - > payload_data = eo_info - > payload_data ;
object_list - > add_entry ( object_list - > gui_data , entry ) ;
2019-01-01 03:36:12 +00:00
return TAP_PACKET_REDRAW ; /* State changed - window should be redrawn */
2016-11-24 14:37:01 +00:00
} else {
2019-01-01 03:36:12 +00:00
return TAP_PACKET_DONT_REDRAW ; /* State unchanged - no window updates needed */
2016-11-24 14:37:01 +00:00
}
}
2010-08-09 19:28:09 +00:00
/* ************************************************************************* */
/* Fragment items */
/* ************************************************************************* */
2008-10-11 14:25:02 +00:00
2010-08-09 19:28:09 +00:00
/* Initialize the subtree pointers */
static gint ett_dcm_pdv = - 1 ;
static gint ett_dcm_pdv_fragment = - 1 ;
static gint ett_dcm_pdv_fragments = - 1 ;
static int hf_dcm_pdv_fragments = - 1 ;
static int hf_dcm_pdv_fragment = - 1 ;
static int hf_dcm_pdv_fragment_overlap = - 1 ;
static int hf_dcm_pdv_fragment_overlap_conflicts = - 1 ;
static int hf_dcm_pdv_fragment_multiple_tails = - 1 ;
static int hf_dcm_pdv_fragment_too_long_fragment = - 1 ;
static int hf_dcm_pdv_fragment_error = - 1 ;
2011-01-30 21:01:07 +00:00
static int hf_dcm_pdv_fragment_count = - 1 ;
2010-08-09 19:28:09 +00:00
static int hf_dcm_pdv_reassembled_in = - 1 ;
static int hf_dcm_pdv_reassembled_length = - 1 ;
static const fragment_items dcm_pdv_fragment_items = {
/* Fragment subtrees */
& ett_dcm_pdv_fragment ,
& ett_dcm_pdv_fragments ,
/* Fragment fields */
& hf_dcm_pdv_fragments ,
& hf_dcm_pdv_fragment ,
& hf_dcm_pdv_fragment_overlap ,
& hf_dcm_pdv_fragment_overlap_conflicts ,
& hf_dcm_pdv_fragment_multiple_tails ,
& hf_dcm_pdv_fragment_too_long_fragment ,
& hf_dcm_pdv_fragment_error ,
2011-01-30 21:01:07 +00:00
& hf_dcm_pdv_fragment_count ,
2010-08-09 19:28:09 +00:00
& hf_dcm_pdv_reassembled_in ,
& hf_dcm_pdv_reassembled_length ,
2012-09-07 02:09:59 +00:00
/* Reassembled data field */
NULL ,
2010-08-09 19:28:09 +00:00
/* Tag */
" Message fragments "
} ;
2008-10-11 14:25:02 +00:00
2013-03-22 23:59:54 +00:00
/* Structure to handle fragmented DICOM PDU packets */
static reassembly_table dcm_pdv_reassembly_table ;
2008-10-11 14:25:02 +00:00
typedef struct dcm_open_tag {
/* Contains information about an open tag in a PDV, in case it was not complete.
This implementation differentiates between open headers ( grm , elm , vr , vl ) and
2011-12-27 17:34:01 +00:00
open values . This data structure will handle both cases .
2008-10-11 14:25:02 +00:00
Open headers are not shown in the packet where the tag starts , but only in the next PDV .
Open values are shown in the packet where the tag starts , with < Byte 1 - n > as the value
The same PDV can close an open tag from a previous PDV at the beginning
and at the same have time open a new tag at the end . The closing part at the beginning
2013-02-26 01:06:19 +00:00
does not have its own persistent data .
2008-10-11 14:25:02 +00:00
Do not overwrite the values , once defined , to save some memory .
Since PDVs are always n * 2 bytes , store each of the 2 Bytes in a variable .
This way , we don ' t need to call tvb_get_xxx on a self created buffer
*/
2014-10-02 21:47:19 +00:00
gboolean is_header_fragmented ;
gboolean is_value_fragmented ;
2008-10-11 14:25:02 +00:00
2014-10-02 21:47:19 +00:00
guint32 len_decoded ; /* Should only be < 16 bytes */
2008-10-11 14:25:02 +00:00
2014-10-02 21:47:19 +00:00
guint16 grp ; /* Already decoded group */
guint16 elm ; /* Already decoded element */
gchar * vr ; /* Already decoded VR */
2008-10-11 14:25:02 +00:00
2014-10-02 21:47:19 +00:00
gboolean is_vl_long ; /* If TRUE, Value Length is 4 Bytes, otherwise 2 */
guint16 vl_1 ; /* Partially decoded 1st two bytes of length */
guint16 vl_2 ; /* Partially decoded 2nd two bytes of length */
2008-10-11 14:25:02 +00:00
/* These ones are, where the value was truncated */
2019-02-11 11:27:19 +00:00
guint32 len_total ; /* Tag length of 'over-sized' tags. Used for display */
2014-10-02 21:47:19 +00:00
guint32 len_remaining ; /* Remaining tag bytes to 'decoded' as binary data after this PDV */
2008-10-11 14:25:02 +00:00
2014-10-02 21:47:19 +00:00
gchar * desc ; /* Last decoded description */
2008-10-11 14:25:02 +00:00
} dcm_open_tag_t ;
2008-07-25 13:36:58 +00:00
/*
Per Data PDV store data needed , to allow decoding of tags longer than a PDV
*/
typedef struct dcm_state_pdv {
struct dcm_state_pdv * next , * prev ;
2014-10-02 21:47:19 +00:00
guint32 packet_no ; /* Wireshark packet number, where pdv starts */
guint32 offset ; /* Offset in packet, where PDV header starts */
2008-07-25 13:36:58 +00:00
2019-02-11 11:27:19 +00:00
gchar * desc ; /* PDV description. wmem_file_scope() */
2008-07-25 13:36:58 +00:00
2014-10-02 21:47:19 +00:00
guint8 pctx_id ; /* Reference to used Presentation Context */
2008-07-25 13:20:18 +00:00
2011-12-27 17:34:01 +00:00
/* Following is derived from the transfer syntax in the parent PCTX, except for Command PDVs */
2008-10-11 14:25:02 +00:00
guint8 syntax ;
2008-07-25 13:36:58 +00:00
/* Used and filled for Export Object only */
2014-10-02 21:47:19 +00:00
gpointer data ; /* Copy of PDV data without any PDU/PDV header */
guint32 data_len ; /* Length of this PDV buffer. If >0, memory has been allocated */
2008-07-25 13:36:58 +00:00
2014-10-02 21:47:19 +00:00
gchar * sop_class_uid ; /* SOP Class UID. Set in 1st PDV of a DICOM object. wmem_file_scope() */
gchar * sop_instance_uid ; /* SOP Instance UID. Set in 1st PDV of a DICOM object. wmem_file_scope() */
2008-07-25 13:36:58 +00:00
/* End Export use */
2014-10-02 21:47:19 +00:00
gboolean is_storage ; /* True, if the Data PDV is on the context of a storage SOP Class */
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
2019-02-11 11:27:19 +00:00
This flag delimits different DICOM object in the same association */
2014-10-02 21:47:19 +00:00
gboolean is_corrupt ; /* Early termination of long PDVs */
2008-07-25 13:36:58 +00:00
2018-03-05 10:54:55 +00:00
/* The following five attributes are only used for command PDVs */
2009-05-18 06:21:22 +00:00
2014-10-02 21:47:19 +00:00
gchar * command ; /* Decoded command as text */
2019-02-18 14:53:06 +00:00
gchar * status ; /* Decoded status as text */
2014-10-02 21:47:19 +00:00
gchar * comment ; /* Error comment, if any */
2009-05-18 06:21:22 +00:00
2014-10-02 21:47:19 +00:00
gboolean is_warning ; /* Command response is a cancel, warning, error */
2019-02-18 14:53:06 +00:00
gboolean is_pending ; /* Command response is 'Current Match is supplied. Sub-operations are continuing' */
2009-05-18 06:21:22 +00:00
2014-10-02 21:47:19 +00:00
guint16 message_id ; /* (0000,0110) Message ID */
2019-02-18 14:53:06 +00:00
guint16 message_id_resp ; /* (0000,0120) Message ID being responded to */
2009-05-18 06:21:22 +00:00
2019-02-18 14:53:06 +00:00
guint16 no_remaining ; /* (0000,1020) Number of remaining sub-operations */
guint16 no_completed ; /* (0000,1021) Number of completed sub-operations */
guint16 no_failed ; /* (0000,1022) Number of failed sub-operations */
guint16 no_warning ; /* (0000,1023) Number of warning sub-operations */
2009-05-18 06:21:22 +00:00
2014-10-02 21:47:19 +00:00
dcm_open_tag_t open_tag ; /* Container to store information about a fragmented tag */
2008-07-25 13:36:58 +00:00
2020-08-19 14:15:33 +00:00
guint8 reassembly_id ;
2008-07-25 13:36:58 +00:00
} dcm_state_pdv_t ;
2008-07-25 13:20:18 +00:00
/*
2019-02-11 11:27:19 +00:00
Per Presentation Context in an association store data needed , for subsequent decoding
2008-07-25 13:20:18 +00:00
*/
2008-07-25 13:36:58 +00:00
typedef struct dcm_state_pctx {
struct dcm_state_pctx * next , * prev ;
2014-10-02 21:47:19 +00:00
guint8 id ; /* 0x20 Presentation Context ID */
gchar * abss_uid ; /* 0x30 Abstract syntax */
gchar * abss_desc ; /* 0x30 Abstract syntax decoded*/
gchar * xfer_uid ; /* 0x40 Accepted Transfer syntax */
gchar * xfer_desc ; /* 0x40 Accepted Transfer syntax decoded*/
guint8 syntax ; /* Decoded transfer syntax */
# define DCM_ILE 0x01 /* implicit, little endian */
2004-05-08 08:49:02 +00:00
# define DCM_EBE 0x02 /* explicit, big endian */
# define DCM_ELE 0x03 /* explicit, little endian */
# define DCM_UNK 0xf0
2020-08-19 14:15:33 +00:00
guint8 reassembly_count ;
2014-10-02 21:47:19 +00:00
dcm_state_pdv_t * first_pdv , * last_pdv ; /* List of PDV objects */
2008-07-25 13:20:18 +00:00
2008-07-25 13:36:58 +00:00
} dcm_state_pctx_t ;
2008-07-25 13:20:18 +00:00
2008-07-25 13:36:58 +00:00
typedef struct dcm_state_assoc {
struct dcm_state_assoc * next , * prev ;
2014-10-02 21:47:19 +00:00
dcm_state_pctx_t * first_pctx , * last_pctx ; /* List of Presentation context objects */
2008-07-25 13:36:58 +00:00
2014-10-02 21:47:19 +00:00
guint32 packet_no ; /* Wireshark packet number, where association starts */
2008-07-25 13:20:18 +00:00
2019-07-15 20:24:23 +00:00
char * ae_called ; /* Called AE title in A-ASSOCIATE RQ */
char * ae_calling ; /* Calling AE title in A-ASSOCIATE RQ */
char * ae_called_resp ; /* Called AE title in A-ASSOCIATE RP */
char * ae_calling_resp ; /* Calling AE title in A-ASSOCIATE RP */
2010-08-09 19:28:09 +00:00
2008-07-25 13:36:58 +00:00
} dcm_state_assoc_t ;
typedef struct dcm_state {
2004-05-08 08:49:02 +00:00
2008-07-25 13:36:58 +00:00
struct dcm_state_assoc * first_assoc , * last_assoc ;
2014-10-02 21:47:19 +00:00
gboolean valid ; /* this conversation is a DICOM conversation */
2008-07-25 13:36:58 +00:00
} dcm_state_t ;
2008-10-11 14:25:02 +00:00
/* ---------------------------------------------------------------------
* DICOM Status Value Definitions
*
* Collected from PS 3.7 & 3.4
*
*/
typedef struct dcm_status {
const guint16 value ;
const gchar * description ;
} dcm_status_t ;
static dcm_status_t dcm_status_data [ ] = {
/* From PS 3.7 */
2014-10-02 21:47:19 +00:00
{ 0x0000 , " Success " } ,
{ 0x0105 , " No such attribute " } ,
{ 0x0106 , " Invalid attribute value " } ,
{ 0x0107 , " Attribute list error " } ,
{ 0x0110 , " Processing failure " } ,
{ 0x0111 , " Duplicate SOP instance " } ,
{ 0x0112 , " No Such object instance " } ,
{ 0x0113 , " No such event type " } ,
{ 0x0114 , " No such argument " } ,
{ 0x0115 , " Invalid argument value " } ,
{ 0x0116 , " Attribute Value Out of Range " } ,
{ 0x0117 , " Invalid object instance " } ,
{ 0x0118 , " No Such SOP class " } ,
{ 0x0119 , " Class-instance conflict " } ,
{ 0x0120 , " Missing attribute " } ,
{ 0x0121 , " Missing attribute value " } ,
{ 0x0122 , " Refused: SOP class not supported " } ,
{ 0x0123 , " No such action type " } ,
{ 0x0210 , " Duplicate invocation " } ,
{ 0x0211 , " Unrecognized operation " } ,
{ 0x0212 , " Mistyped argument " } ,
{ 0x0213 , " Resource limitation " } ,
{ 0xFE00 , " Cancel " } ,
2008-10-11 14:25:02 +00:00
/* from PS 3.4 */
2014-10-02 21:47:19 +00:00
{ 0x0001 , " Requested optional Attributes are not supported " } ,
{ 0xA501 , " Refused because General Purpose Scheduled Procedure Step Object may no longer be updated " } ,
{ 0xA502 , " Refused because the wrong Transaction UID is used " } ,
{ 0xA503 , " Refused because the General Purpose Scheduled Procedure Step SOP Instance is already in the 'IN PROGRESS' state " } ,
{ 0xA504 , " Refused because the related General Purpose Scheduled Procedure Step SOP Instance is not in the 'IN PROGRESS' state " } ,
{ 0xA505 , " Refused because Referenced General Purpose Scheduled Procedure Step Transaction UID does not match the Transaction UID of the N-ACTION request " } ,
{ 0xA510 , " Refused because an Initiate Media Creation action has already been received for this SOP Instance " } ,
{ 0xA700 , " Refused: Out of Resources " } ,
{ 0xA701 , " Refused: Out of Resources - Unable to calculate number of matches " } ,
{ 0xA702 , " Refused: Out of Resources - Unable to perform sub-operations " } ,
2008-10-11 14:25:02 +00:00
/*
2014-10-02 21:47:19 +00:00
{ 0xA7 xx , " Refused: Out of Resources " } ,
2008-10-11 14:25:02 +00:00
*/
2014-10-02 21:47:19 +00:00
{ 0xA801 , " Refused: Move Destination unknown " } ,
2008-10-11 14:25:02 +00:00
/*
2014-10-02 21:47:19 +00:00
{ 0xA9 xx , " Error: Data Set does not match SOP Class " } ,
2008-10-11 14:25:02 +00:00
*/
2014-10-02 21:47:19 +00:00
{ 0xB000 , " Sub-operations Complete - One or more Failures " } ,
{ 0xB006 , " Elements Discarded " } ,
{ 0xB007 , " Data Set does not match SOP Class " } ,
{ 0xB101 , " Specified Synchronization Frame of Reference UID does not match SCP Synchronization Frame of Reference " } ,
{ 0xB102 , " Study Instance UID coercion; Event logged under a different Study Instance UID " } ,
{ 0xB104 , " IDs inconsistent in matching a current study; Event logged " } ,
{ 0xB605 , " Requested Min Density or Max Density outside of printer's operating range. The printer will use its respective minimum or maximum density value instead " } ,
{ 0xC000 , " Error: Cannot understand/Unable to process " } ,
{ 0xC100 , " More than one match found " } ,
{ 0xC101 , " Procedural Logging not available for specified Study Instance UID " } ,
{ 0xC102 , " Event Information does not match Template " } ,
{ 0xC103 , " Cannot match event to a current study " } ,
{ 0xC104 , " IDs inconsistent in matching a current study; Event not logged " } ,
{ 0xC200 , " Unable to support requested template " } ,
{ 0xC201 , " Media creation request already completed " } ,
{ 0xC202 , " Media creation request already in progress and cannot be interrupted " } ,
{ 0xC203 , " Cancellation denied for unspecified reason " } ,
2008-10-11 14:25:02 +00:00
/*
2014-10-02 21:47:19 +00:00
{ 0xC xxx , " Error: Cannot understand/Unable to Process " } ,
{ 0xFE00 , " Matching/Sub-operations terminated due to Cancel request " } ,
2008-10-11 14:25:02 +00:00
*/
2014-10-02 21:47:19 +00:00
{ 0xFF00 , " Current Match is supplied. Sub-operations are continuing " } ,
{ 0xFF01 , " Matches are continuing - Warning that one or more Optional Keys were not supported for existence for this Identifier " }
2004-05-08 08:49:02 +00:00
} ;
2008-07-25 15:42:46 +00:00
2008-07-25 13:36:58 +00:00
/* following definitions are used to call dissect_dcm_assoc_item() */
2014-10-02 21:47:19 +00:00
# define DCM_ITEM_VALUE_TYPE_UID 1
2008-07-25 13:20:18 +00:00
# define DCM_ITEM_VALUE_TYPE_STRING 2
# define DCM_ITEM_VALUE_TYPE_UINT32 3
2008-10-11 14:25:02 +00:00
/* And from here on, only use unsigned 32 bit values. Offset is always positive number in respect to the tvb buffer start */
2014-10-02 21:47:19 +00:00
static guint32 dissect_dcm_pdu ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree , guint32 offset ) ;
2008-10-11 14:25:02 +00:00
2010-08-09 19:28:09 +00:00
static guint32 dissect_dcm_assoc_detail ( tvbuff_t * tvb , packet_info * pinfo , proto_item * ti , dcm_state_assoc_t * assoc , guint32 offset , guint32 len ) ;
2008-07-25 13:20:18 +00:00
2018-03-05 10:54:55 +00:00
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 , guint32 vl , guint32 vl_max , const gchar * vr , gchar * * tag_value ) ;
2004-05-08 08:49:02 +00:00
static void
dcm_init ( void )
{
2008-10-11 14:25:02 +00:00
guint i ;
2008-07-25 13:20:18 +00:00
2015-06-28 13:15:07 +00:00
/* Create three hash tables for quick lookups */
2008-10-11 14:25:02 +00:00
/* Add UID objects to hash table */
2017-02-25 00:46:49 +00:00
dcm_uid_table = wmem_map_new ( wmem_file_scope ( ) , wmem_str_hash , g_str_equal ) ;
2015-06-28 13:15:07 +00:00
for ( i = 0 ; i < array_length ( dcm_uid_data ) ; i + + ) {
2017-02-25 00:46:49 +00:00
wmem_map_insert ( dcm_uid_table , ( gpointer ) dcm_uid_data [ i ] . value ,
2015-06-28 13:15:07 +00:00
( gpointer ) & dcm_uid_data [ i ] ) ;
2004-05-08 08:49:02 +00:00
}
2008-07-25 13:20:18 +00:00
2008-10-11 14:25:02 +00:00
/* Add Tag objects to hash table */
2017-02-25 00:46:49 +00:00
dcm_tag_table = wmem_map_new ( wmem_file_scope ( ) , g_direct_hash , g_direct_equal ) ;
2015-06-28 13:15:07 +00:00
for ( i = 0 ; i < array_length ( dcm_tag_data ) ; i + + ) {
2017-02-25 00:46:49 +00:00
wmem_map_insert ( dcm_tag_table , GUINT_TO_POINTER ( dcm_tag_data [ i ] . tag ) ,
2015-06-28 13:15:07 +00:00
( gpointer ) & dcm_tag_data [ i ] ) ;
2008-10-11 14:25:02 +00:00
}
2008-07-25 13:20:18 +00:00
2008-10-11 14:25:02 +00:00
/* Add Status Values to hash table */
2017-02-25 00:46:49 +00:00
dcm_status_table = wmem_map_new ( wmem_file_scope ( ) , g_direct_hash , g_direct_equal ) ;
2015-06-28 13:15:07 +00:00
for ( i = 0 ; i < array_length ( dcm_status_data ) ; i + + ) {
2017-02-25 00:46:49 +00:00
wmem_map_insert ( dcm_status_table , GUINT_TO_POINTER ( ( guint32 ) dcm_status_data [ i ] . value ) ,
2015-06-28 13:15:07 +00:00
( gpointer ) & dcm_status_data [ i ] ) ;
2008-07-25 13:20:18 +00:00
}
2004-05-08 08:49:02 +00:00
}
2018-05-06 15:33:51 +00:00
/*
Get or create conversation and DICOM data structure if desired .
Return new or existing DICOM structure , which is used to store context IDs and transfer syntax .
Return NULL in case of the structure couldn ' t be created .
*/
2008-07-25 13:36:58 +00:00
static dcm_state_t *
dcm_state_get ( packet_info * pinfo , gboolean create )
{
2016-11-20 22:38:14 +00:00
conversation_t * conv ;
dcm_state_t * dcm_data ;
2008-07-25 13:20:18 +00:00
2016-11-20 22:38:14 +00:00
conv = find_or_create_conversation ( pinfo ) ;
dcm_data = ( dcm_state_t * ) conversation_get_proto_data ( conv , proto_dcm ) ;
2010-08-09 19:28:09 +00:00
2008-07-25 13:36:58 +00:00
if ( dcm_data = = NULL & & create ) {
2008-07-25 13:20:18 +00:00
2016-11-20 22:38:14 +00:00
dcm_data = wmem_new0 ( wmem_file_scope ( ) , dcm_state_t ) ;
2010-01-25 11:47:39 +00:00
conversation_add_proto_data ( conv , proto_dcm , dcm_data ) ;
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
/* Mark it as DICOM conversation. Needed for the heuristic mode,
to prevent stealing subsequent packets by other dissectors
*/
conversation_set_dissector ( conv , dcm_handle ) ;
2008-07-25 13:36:58 +00:00
}
return dcm_data ;
2004-05-08 08:49:02 +00:00
}
2008-07-25 13:36:58 +00:00
static dcm_state_assoc_t *
dcm_state_assoc_new ( dcm_state_t * dcm_data , guint32 packet_no )
2008-07-25 13:20:18 +00:00
{
2011-12-27 17:34:01 +00:00
/* Create new association object and initialize the members */
2008-07-25 13:20:18 +00:00
2008-07-25 13:36:58 +00:00
dcm_state_assoc_t * assoc ;
2008-07-25 13:20:18 +00:00
2020-05-07 12:35:45 +00:00
assoc = wmem_new0 ( wmem_file_scope ( ) , dcm_state_assoc_t ) ;
2014-10-02 21:47:19 +00:00
assoc - > packet_no = packet_no ; /* Identifier */
2008-07-25 13:20:18 +00:00
2010-01-25 11:47:39 +00:00
/* add to the end of the list */
if ( dcm_data - > last_assoc ) {
dcm_data - > last_assoc - > next = assoc ;
assoc - > prev = dcm_data - > last_assoc ;
}
else {
dcm_data - > first_assoc = assoc ;
2008-07-25 13:36:58 +00:00
}
2010-01-25 11:47:39 +00:00
dcm_data - > last_assoc = assoc ;
2008-07-25 13:36:58 +00:00
return assoc ;
}
2018-03-05 10:54:55 +00:00
/*
Find or create association object based on packet number . Return NULL , if association was not found .
*/
2008-07-25 13:36:58 +00:00
static dcm_state_assoc_t *
dcm_state_assoc_get ( dcm_state_t * dcm_data , guint32 packet_no , gboolean create )
{
2016-11-20 22:38:14 +00:00
dcm_state_assoc_t * assoc = dcm_data - > first_assoc ;
2008-07-25 13:20:18 +00:00
2008-07-25 13:36:58 +00:00
while ( assoc ) {
2014-10-02 21:47:19 +00:00
if ( assoc - > next ) {
/* we have more associations in the same stream */
if ( ( assoc - > packet_no < = packet_no ) & & ( packet_no < assoc - > next - > packet_no ) )
break ;
}
else {
/* last or only associations in the same stream */
if ( assoc - > packet_no < = packet_no )
break ;
}
assoc = assoc - > next ;
2008-07-25 13:36:58 +00:00
}
2008-07-25 13:20:18 +00:00
2008-07-25 13:36:58 +00:00
if ( assoc = = NULL & & create ) {
2014-10-02 21:47:19 +00:00
assoc = dcm_state_assoc_new ( dcm_data , packet_no ) ;
2008-07-25 13:20:18 +00:00
}
2008-07-25 13:36:58 +00:00
return assoc ;
}
static dcm_state_pctx_t *
dcm_state_pctx_new ( dcm_state_assoc_t * assoc , guint8 pctx_id )
{
2011-12-27 17:34:01 +00:00
/* Create new presentation context object and initialize the members */
2008-07-25 13:36:58 +00:00
2016-11-20 22:38:14 +00:00
dcm_state_pctx_t * pctx ;
2008-07-25 13:36:58 +00:00
2020-05-07 12:35:45 +00:00
pctx = wmem_new0 ( wmem_file_scope ( ) , dcm_state_pctx_t ) ;
2010-01-25 11:47:39 +00:00
pctx - > id = pctx_id ;
pctx - > syntax = DCM_UNK ;
2008-07-25 13:20:18 +00:00
2010-01-25 11:47:39 +00:00
/* add to the end of the list list */
if ( assoc - > last_pctx ) {
assoc - > last_pctx - > next = pctx ;
pctx - > prev = assoc - > last_pctx ;
2008-07-25 13:36:58 +00:00
}
2010-01-25 11:47:39 +00:00
else {
assoc - > first_pctx = pctx ;
}
assoc - > last_pctx = pctx ;
2008-07-25 13:36:58 +00:00
return pctx ;
2008-07-25 13:20:18 +00:00
}
2008-07-25 13:36:58 +00:00
static dcm_state_pctx_t *
dcm_state_pctx_get ( dcm_state_assoc_t * assoc , guint8 pctx_id , gboolean create )
2008-07-25 13:20:18 +00:00
{
2008-07-25 13:36:58 +00:00
/* Find or create presentation context object. Return NULL, if Context ID was not found */
2016-11-20 22:38:14 +00:00
dcm_state_pctx_t * pctx = assoc - > first_pctx ;
2008-07-25 13:36:58 +00:00
/*
static char notfound [ ] = " not found - click on ASSOC Request " ;
static dcm_state_pctx_t dunk = { NULL , NULL , FALSE , 0 , notfound , notfound , notfound , notfound , DCM_UNK } ;
*/
while ( pctx ) {
2014-10-02 21:47:19 +00:00
if ( pctx - > id = = pctx_id )
break ;
pctx = pctx - > next ;
2008-07-25 13:36:58 +00:00
}
if ( pctx = = NULL & & create ) {
2014-10-02 21:47:19 +00:00
pctx = dcm_state_pctx_new ( assoc , pctx_id ) ;
2008-07-25 13:36:58 +00:00
}
return pctx ;
}
2008-07-25 13:20:18 +00:00
2019-02-11 11:27:19 +00:00
/*
Create new PDV object and initialize all members
*/
2008-07-25 13:36:58 +00:00
static dcm_state_pdv_t *
dcm_state_pdv_new ( dcm_state_pctx_t * pctx , guint32 packet_no , guint32 offset )
{
2016-11-20 22:38:14 +00:00
dcm_state_pdv_t * pdv ;
2008-07-25 13:36:58 +00:00
2020-05-07 12:35:45 +00:00
pdv = wmem_new0 ( wmem_file_scope ( ) , dcm_state_pdv_t ) ;
2010-01-25 11:47:39 +00:00
pdv - > syntax = DCM_UNK ;
2014-10-02 21:47:19 +00:00
pdv - > is_last_fragment = TRUE ; /* Continuation PDVs are more tricky */
2010-01-25 11:47:39 +00:00
pdv - > packet_no = packet_no ;
pdv - > offset = offset ;
2019-02-11 11:27:19 +00:00
/* add to the end of the list */
2010-01-25 11:47:39 +00:00
if ( pctx - > last_pdv ) {
pctx - > last_pdv - > next = pdv ;
pdv - > prev = pctx - > last_pdv ;
}
else {
pctx - > first_pdv = pdv ;
2008-07-25 13:36:58 +00:00
}
2010-01-25 11:47:39 +00:00
pctx - > last_pdv = pdv ;
2008-07-25 13:36:58 +00:00
return pdv ;
}
2008-07-25 13:20:18 +00:00
2008-07-25 13:36:58 +00:00
static dcm_state_pdv_t *
dcm_state_pdv_get ( dcm_state_pctx_t * pctx , guint32 packet_no , guint32 offset , gboolean create )
{
/* Find or create PDV object. Return NULL, if PDV was not found, based on packet number and offset */
2016-11-20 22:38:14 +00:00
dcm_state_pdv_t * pdv = pctx - > first_pdv ;
2008-07-25 13:36:58 +00:00
while ( pdv ) {
2014-10-02 21:47:19 +00:00
if ( ( pdv - > packet_no = = packet_no ) & & ( pdv - > offset = = offset ) )
break ;
pdv = pdv - > next ;
2008-07-25 13:20:18 +00:00
}
2008-07-25 13:36:58 +00:00
if ( pdv = = NULL & & create ) {
2014-10-02 21:47:19 +00:00
pdv = dcm_state_pdv_new ( pctx , packet_no , offset ) ;
2008-07-25 13:20:18 +00:00
}
2008-07-25 13:36:58 +00:00
return pdv ;
2008-07-25 13:20:18 +00:00
}
2008-07-25 13:36:58 +00:00
static dcm_state_pdv_t *
dcm_state_pdv_get_obj_start ( dcm_state_pdv_t * pdv_curr )
{
dcm_state_pdv_t * pdv_first = pdv_curr ;
/* Get First PDV of the DICOM Object */
while ( pdv_first - > prev & & ! pdv_first - > prev - > is_last_fragment ) {
2014-10-02 21:47:19 +00:00
pdv_first = pdv_first - > prev ;
2008-07-25 13:36:58 +00:00
}
return pdv_first ;
}
2008-07-25 13:20:18 +00:00
2016-11-20 22:38:14 +00:00
static const value_string dcm_cmd_vals [ ] = {
{ 0x0001 , " C-STORE-RQ " } ,
{ 0x0010 , " C-GET-RQ " } ,
{ 0x0020 , " C-FIND-RQ " } ,
{ 0x0021 , " C-MOVE-RQ " } ,
{ 0x0030 , " C-ECHO-RQ " } ,
{ 0x0100 , " N-EVENT-REPORT-RQ " } ,
{ 0x0110 , " N-GET-RQ " } ,
{ 0x0120 , " N-SET-RQ " } ,
{ 0x0130 , " N-ACTION-RQ " } ,
{ 0x0140 , " N-CREATE-RQ " } ,
{ 0x0150 , " N-DELETE-RQ " } ,
{ 0x8001 , " C-STORE-RSP " } ,
{ 0x8010 , " C-GET-RSP " } ,
{ 0x8020 , " C-FIND-RSP " } ,
{ 0x8021 , " C-MOVE-RSP " } ,
{ 0x8030 , " C-ECHO-RSP " } ,
{ 0x8100 , " N-EVENT-REPORT-RSP " } ,
{ 0x8110 , " N-GET-RSP " } ,
{ 0x8120 , " N-SET-RSP " } ,
{ 0x8130 , " N-ACTION-RSP " } ,
{ 0x8140 , " N-CREATE-RSP " } ,
{ 0x8150 , " N-DELETE-RSP " } ,
{ 0x0FFF , " C-CANCEL-RQ " } ,
{ 0 , NULL }
} ;
2004-05-08 08:49:02 +00:00
2019-02-18 14:53:06 +00:00
/*
Convert the two status bytes into a text based on lookup .
Classification
0x0000 : SUCCESS
0x0001 & Bxxx : WARNING
0xFE00 : CANCEL
0 XFFxx : PENDING
All other : FAILURE
*/
2009-05-18 06:21:22 +00:00
static const gchar *
2008-10-11 14:25:02 +00:00
dcm_rsp2str ( guint16 status_value )
2004-05-08 08:49:02 +00:00
{
2008-10-11 14:25:02 +00:00
dcm_status_t * status = NULL ;
2009-05-18 06:21:22 +00:00
const gchar * s = " " ;
2008-10-11 14:25:02 +00:00
/* Use specific text first */
2017-02-25 00:46:49 +00:00
status = ( dcm_status_t * ) wmem_map_lookup ( dcm_status_table , GUINT_TO_POINTER ( ( guint32 ) status_value ) ) ;
2008-10-11 14:25:02 +00:00
if ( status ) {
2014-10-02 21:47:19 +00:00
s = status - > description ;
2008-10-11 14:25:02 +00:00
}
else {
2014-10-02 21:47:19 +00:00
if ( ( status_value & 0xFF00 ) = = 0xA700 ) {
/* 0xA7xx */
s = " Refused: Out of Resources " ;
}
else if ( ( status_value & 0xFF00 ) = = 0xA900 ) {
/* 0xA9xx */
s = " Error: Data Set does not match SOP Class " ;
}
else if ( ( status_value & 0xF000 ) = = 0xC000 ) {
/* 0xCxxx */
s = " Error: Cannot understand/Unable to Process " ;
}
else {
2019-02-18 14:53:06 +00:00
/* Encountered at least one case, with status_value == 0xD001 */
2014-10-02 21:47:19 +00:00
s = " Unknown " ;
}
2004-05-08 08:49:02 +00:00
}
2008-10-11 14:25:02 +00:00
2004-05-08 08:49:02 +00:00
return s ;
}
2010-03-19 20:24:06 +00:00
static const gchar *
2008-07-25 22:58:05 +00:00
dcm_uid_or_desc ( gchar * dcm_uid , gchar * dcm_desc )
2008-07-25 13:20:18 +00:00
{
/* Return Description, UID or error */
2010-03-19 20:24:06 +00:00
return ( dcm_desc = = NULL ? ( dcm_uid = = NULL ? " Malformed Packet " : dcm_uid ) : dcm_desc ) ;
2008-07-25 13:20:18 +00:00
}
2005-07-30 01:01:02 +00:00
static void
2010-03-19 20:24:06 +00:00
dcm_set_syntax ( dcm_state_pctx_t * pctx , gchar * xfer_uid , const gchar * xfer_desc )
2004-05-08 08:49:02 +00:00
{
2008-10-11 14:25:02 +00:00
if ( ( pctx = = NULL ) | | ( xfer_uid = = NULL ) | | ( xfer_desc = = NULL ) )
2014-10-02 21:47:19 +00:00
return ;
2008-07-25 13:36:58 +00:00
2014-10-02 21:47:19 +00:00
g_free ( pctx - > xfer_uid ) ; /* free prev allocated xfer */
g_free ( pctx - > xfer_desc ) ; /* free prev allocated xfer */
2008-07-25 13:20:18 +00:00
2008-07-25 13:36:58 +00:00
pctx - > syntax = 0 ;
pctx - > xfer_uid = g_strdup ( xfer_uid ) ;
pctx - > xfer_desc = g_strdup ( xfer_desc ) ;
2008-07-25 13:20:18 +00:00
/* this would be faster to skip the common parts, and have a FSA to
2004-05-08 08:49:02 +00:00
* find the syntax .
* Absent of coding that , this is in descending order of probability */
2008-07-25 13:20:18 +00:00
if ( 0 = = strcmp ( xfer_uid , " 1.2.840.10008.1.2 " ) )
2014-10-02 21:47:19 +00:00
pctx - > syntax = DCM_ILE ; /* implicit little endian */
2008-07-25 13:20:18 +00:00
else if ( 0 = = strcmp ( xfer_uid , " 1.2.840.10008.1.2.1 " ) )
2014-10-02 21:47:19 +00:00
pctx - > syntax = DCM_ELE ; /* explicit little endian */
2008-07-25 13:20:18 +00:00
else if ( 0 = = strcmp ( xfer_uid , " 1.2.840.10008.1.2.2 " ) )
2014-10-02 21:47:19 +00:00
pctx - > syntax = DCM_EBE ; /* explicit big endian */
2008-07-25 13:20:18 +00:00
else if ( 0 = = strcmp ( xfer_uid , " 1.2.840.113619.5.2 " ) )
2014-10-02 21:47:19 +00:00
pctx - > syntax = DCM_ILE ; /* implicit little endian, big endian pixels, GE private */
2008-07-25 13:20:18 +00:00
else if ( 0 = = strcmp ( xfer_uid , " 1.2.840.10008.1.2.4.70 " ) )
2014-10-02 21:47:19 +00:00
pctx - > syntax = DCM_ELE ; /* explicit little endian, jpeg */
2008-07-25 13:20:18 +00:00
else if ( 0 = = strncmp ( xfer_uid , " 1.2.840.10008.1.2.4 " , 18 ) )
2014-10-02 21:47:19 +00:00
pctx - > syntax = DCM_ELE ; /* explicit little endian, jpeg */
2008-07-25 13:20:18 +00:00
else if ( 0 = = strcmp ( xfer_uid , " 1.2.840.10008.1.2.1.99 " ) )
2014-10-02 21:47:19 +00:00
pctx - > syntax = DCM_ELE ; /* explicit little endian, deflated */
2004-05-08 08:49:02 +00:00
}
2008-07-25 13:20:18 +00:00
static void
2008-07-25 22:58:05 +00:00
dcm_guint16_to_le ( guint8 * buffer , guint16 value )
2008-07-25 13:36:58 +00:00
{
buffer [ 0 ] = ( guint8 ) ( value & 0x00FF ) ;
buffer [ 1 ] = ( guint8 ) ( ( value & 0xFF00 ) > > 8 ) ;
}
static void
2008-07-25 22:58:05 +00:00
dcm_guint32_to_le ( guint8 * buffer , guint32 value )
2008-07-25 13:36:58 +00:00
{
buffer [ 0 ] = ( guint8 ) ( value & 0x000000FF ) ;
buffer [ 1 ] = ( guint8 ) ( ( value & 0x0000FF00 ) > > 8 ) ;
buffer [ 2 ] = ( guint8 ) ( ( value & 0x00FF0000 ) > > 16 ) ;
buffer [ 3 ] = ( guint8 ) ( ( value & 0xFF000000 ) > > 24 ) ;
}
static guint32
2008-10-11 14:25:02 +00:00
dcm_export_create_tag_base ( guint8 * buffer , guint32 bufflen , guint32 offset ,
2014-10-02 21:47:19 +00:00
guint16 grp , guint16 elm , guint16 vr ,
const guint8 * value_buffer , guint32 value_len )
2008-10-11 14:25:02 +00:00
{
2011-12-27 17:34:01 +00:00
/* Only Explicit Little Endian is needed to create Metafile Header
2014-10-02 21:47:19 +00:00
Generic function to write a TAG , VR , LEN & VALUE to a combined buffer
The value ( buffer , len ) must be preprocessed by a VR specific function
2008-07-25 13:36:58 +00:00
*/
2008-10-11 14:25:02 +00:00
if ( offset + 6 > bufflen ) return bufflen ;
2008-07-25 13:36:58 +00:00
2008-10-11 14:25:02 +00:00
dcm_guint16_to_le ( buffer + offset , grp ) ;
offset + = 2 ;
dcm_guint16_to_le ( buffer + offset , elm ) ;
offset + = 2 ;
2008-10-31 22:59:14 +00:00
memmove ( buffer + offset , dcm_tag_vr_lookup [ vr ] , 2 ) ;
2008-10-11 14:25:02 +00:00
offset + = 2 ;
2008-07-25 13:36:58 +00:00
switch ( vr ) {
case DCM_VR_OB :
2018-10-22 15:58:35 +00:00
case DCM_VR_OD :
2008-07-25 13:36:58 +00:00
case DCM_VR_OF :
2018-10-22 15:58:35 +00:00
case DCM_VR_OL :
case DCM_VR_OW :
2008-07-25 13:36:58 +00:00
case DCM_VR_SQ :
2018-10-22 15:58:35 +00:00
case DCM_VR_UC :
case DCM_VR_UR :
2008-07-25 13:36:58 +00:00
case DCM_VR_UT :
case DCM_VR_UN :
2014-10-02 21:47:19 +00:00
/* DICOM likes it complicated. Special handling for these types */
2008-07-25 13:36:58 +00:00
2008-10-11 14:25:02 +00:00
if ( offset + 6 > bufflen ) return bufflen ;
2014-10-02 21:47:19 +00:00
/* Add two reserved 0x00 bytes */
dcm_guint16_to_le ( buffer + offset , 0 ) ;
offset + = 2 ;
2008-07-25 13:36:58 +00:00
2014-10-02 21:47:19 +00:00
/* Length is a 4 byte field */
2008-10-11 14:25:02 +00:00
dcm_guint32_to_le ( buffer + offset , value_len ) ;
2014-10-02 21:47:19 +00:00
offset + = 4 ;
2008-10-11 14:25:02 +00:00
2014-10-02 21:47:19 +00:00
break ;
2008-07-25 13:36:58 +00:00
default :
2014-10-02 21:47:19 +00:00
/* Length is a 2 byte field */
2008-10-11 14:25:02 +00:00
if ( offset + 2 > bufflen ) return bufflen ;
dcm_guint16_to_le ( buffer + offset , ( guint16 ) value_len ) ;
2014-10-02 21:47:19 +00:00
offset + = 2 ;
2008-07-25 13:36:58 +00:00
}
2008-10-11 14:25:02 +00:00
if ( offset + value_len > bufflen ) return bufflen ;
2008-07-25 13:36:58 +00:00
2008-10-11 14:25:02 +00:00
memmove ( buffer + offset , value_buffer , value_len ) ;
offset + = value_len ;
return offset ;
2008-07-25 13:36:58 +00:00
}
static guint32
dcm_export_create_tag_guint16 ( guint8 * buffer , guint32 bufflen , guint32 offset ,
2014-10-02 21:47:19 +00:00
guint16 grp , guint16 elm , guint16 vr , guint16 value )
2008-07-25 13:36:58 +00:00
{
return dcm_export_create_tag_base ( buffer , bufflen , offset , grp , elm , vr , ( guint8 * ) & value , 2 ) ;
}
static guint32
dcm_export_create_tag_guint32 ( guint8 * buffer , guint32 bufflen , guint32 offset ,
2014-10-02 21:47:19 +00:00
guint16 grp , guint16 elm , guint16 vr , guint32 value )
2008-07-25 13:36:58 +00:00
{
return dcm_export_create_tag_base ( buffer , bufflen , offset , grp , elm , vr , ( guint8 * ) & value , 4 ) ;
}
static guint32
dcm_export_create_tag_str ( guint8 * buffer , guint32 bufflen , guint32 offset ,
2014-10-02 21:47:19 +00:00
guint16 grp , guint16 elm , guint16 vr ,
const gchar * value )
2008-07-25 13:36:58 +00:00
{
2008-10-11 14:25:02 +00:00
guint32 len ;
2008-07-25 13:36:58 +00:00
if ( ! value ) {
2014-10-02 21:47:19 +00:00
/* NULL object. E.g. happens if UID was not found/set. Don't create element*/
return offset ;
2008-07-25 13:36:58 +00:00
}
2009-03-29 13:47:15 +00:00
len = ( int ) strlen ( value ) ;
2008-07-25 13:36:58 +00:00
if ( ( len & 0x01 ) = = 1 ) {
2014-10-02 21:47:19 +00:00
/* Odd length: since buffer is 0 initialized, pad with a 0x00 */
len + = 1 ;
2008-07-25 13:36:58 +00:00
}
2010-03-19 20:24:06 +00:00
return dcm_export_create_tag_base ( buffer , bufflen , offset , grp , elm , vr , ( const guint8 * ) value , len ) ;
2008-07-25 13:36:58 +00:00
}
static guint8 *
2012-12-26 05:57:06 +00:00
dcm_export_create_header ( guint32 * dcm_header_len , const gchar * sop_class_uid , gchar * sop_instance_uid , gchar * xfer_uid )
2008-07-25 13:36:58 +00:00
{
2014-10-02 21:47:19 +00:00
guint8 * dcm_header = NULL ;
guint32 offset = 0 ;
guint32 offset_header_len = 0 ;
2008-07-25 13:36:58 +00:00
# define DCM_HEADER_MAX 512
2013-09-14 10:53:29 +00:00
dcm_header = ( guint8 * ) wmem_alloc0 ( wmem_packet_scope ( ) , DCM_HEADER_MAX ) ; /* Slightly longer than needed */
2014-10-02 21:47:19 +00:00
/* The subsequent functions rely on a 0 initialized buffer */
2008-07-25 13:36:58 +00:00
offset = 128 ;
memmove ( dcm_header + offset , " DICM " , 4 ) ;
offset + = 4 ;
2014-10-02 21:47:19 +00:00
offset_header_len = offset ; /* remember for later */
2008-07-25 13:36:58 +00:00
offset + = 12 ;
/*
2014-10-02 21:47:19 +00:00
( 0002 , 0000 ) File Meta Information Group Length UL
( 0002 , 0001 ) File Meta Information Version OB
( 0002 , 0002 ) Media Storage SOP Class UID UI
( 0002 , 0003 ) Media Storage SOP Instance UID UI
( 0002 , 0010 ) Transfer Syntax UID UI
( 0002 , 0012 ) Implementation Class UID UI
( 0002 , 0013 ) Implementation Version Name SH
2008-07-25 13:36:58 +00:00
*/
offset = dcm_export_create_tag_guint16 ( dcm_header , DCM_HEADER_MAX , offset ,
2014-10-02 21:47:19 +00:00
0x0002 , 0x0001 , DCM_VR_OB , 0x0100 ) ; /* will result on 00 01 since it is little endian */
2008-07-25 13:36:58 +00:00
offset = dcm_export_create_tag_str ( dcm_header , DCM_HEADER_MAX , offset ,
2014-10-02 21:47:19 +00:00
0x0002 , 0x0002 , DCM_VR_UI , sop_class_uid ) ;
2008-07-25 13:36:58 +00:00
offset = dcm_export_create_tag_str ( dcm_header , DCM_HEADER_MAX , offset ,
2014-10-02 21:47:19 +00:00
0x0002 , 0x0003 , DCM_VR_UI , sop_instance_uid ) ;
2008-07-25 13:36:58 +00:00
offset = dcm_export_create_tag_str ( dcm_header , DCM_HEADER_MAX , offset ,
2014-10-02 21:47:19 +00:00
0x0002 , 0x0010 , DCM_VR_UI , xfer_uid ) ;
2008-07-25 13:36:58 +00:00
offset = dcm_export_create_tag_str ( dcm_header , DCM_HEADER_MAX , offset ,
2014-10-02 21:47:19 +00:00
0x0002 , 0x0012 , DCM_VR_UI , WIRESHARK_IMPLEMENTATION_UID ) ;
2008-07-25 13:36:58 +00:00
offset = dcm_export_create_tag_str ( dcm_header , DCM_HEADER_MAX , offset ,
2014-10-02 21:47:19 +00:00
0x0002 , 0x0013 , DCM_VR_SH , WIRESHARK_IMPLEMENTATION_VERSION ) ;
2008-07-25 13:36:58 +00:00
2008-12-18 19:08:49 +00:00
/* Finally write the meta header length */
2008-07-25 13:36:58 +00:00
dcm_export_create_tag_guint32 ( dcm_header , DCM_HEADER_MAX , offset_header_len ,
2014-10-02 21:47:19 +00:00
0x0002 , 0x0000 , DCM_VR_UL , offset - offset_header_len - 12 ) ;
2008-07-25 13:36:58 +00:00
* dcm_header_len = offset ;
return dcm_header ;
}
2019-02-11 11:27:19 +00:00
/*
Concatenate related PDVs into one buffer and add it to the export object list .
2010-08-09 19:28:09 +00:00
2019-02-11 11:27:19 +00:00
Supports both modes :
2010-08-09 19:28:09 +00:00
2019-02-11 11:27:19 +00:00
- 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 )
{
2008-07-25 13:36:58 +00:00
2014-10-02 21:47:19 +00:00
dicom_eo_t * eo_info = NULL ;
2008-07-25 13:36:58 +00:00
2014-10-02 21:47:19 +00:00
dcm_state_pdv_t * pdv_curr = NULL ;
dcm_state_pdv_t * pdv_same_pkt = NULL ;
dcm_state_pctx_t * pctx = NULL ;
2008-07-25 13:36:58 +00:00
guint8 * pdv_combined = NULL ;
guint8 * pdv_combined_curr = NULL ;
guint8 * dcm_header = NULL ;
2014-10-02 21:47:19 +00:00
guint32 pdv_combined_len = 0 ;
guint32 dcm_header_len = 0 ;
guint16 cnt_same_pkt = 1 ;
2009-10-25 11:43:30 +00:00
gchar * filename ;
const gchar * hostname ;
2008-07-25 13:36:58 +00:00
2014-10-02 21:47:19 +00:00
const gchar * sop_class_uid ;
gchar * sop_instance_uid ;
2008-07-25 13:36:58 +00:00
2008-12-18 19:32:11 +00:00
/* Calculate total PDV length, i.e. all packets until last PDV without continuation */
2008-07-25 13:36:58 +00:00
pdv_curr = pdv ;
pdv_same_pkt = pdv ;
pdv_combined_len = pdv_curr - > data_len ;
while ( pdv_curr - > prev & & ! pdv_curr - > prev - > is_last_fragment ) {
2014-10-02 21:47:19 +00:00
pdv_curr = pdv_curr - > prev ;
pdv_combined_len + = pdv_curr - > data_len ;
2008-07-25 13:36:58 +00:00
}
/* Count number of PDVs with the same Packet Number */
while ( pdv_same_pkt - > prev & & ( pdv_same_pkt - > prev - > packet_no = = pdv_same_pkt - > packet_no ) ) {
2014-10-02 21:47:19 +00:00
pdv_same_pkt = pdv_same_pkt - > prev ;
cnt_same_pkt + = 1 ;
2008-07-25 13:36:58 +00:00
}
pctx = dcm_state_pctx_get ( assoc , pdv_curr - > pctx_id , FALSE ) ;
2020-08-06 20:18:31 +00:00
if ( assoc - > ae_calling ! = NULL & & strlen ( assoc - > ae_calling ) > 0 & &
assoc - > ae_called ! = NULL & & strlen ( assoc - > ae_called ) > 0 ) {
2014-10-02 21:47:19 +00:00
hostname = wmem_strdup_printf ( wmem_packet_scope ( ) , " %s <-> %s " , assoc - > ae_calling , assoc - > ae_called ) ;
2008-07-25 13:36:58 +00:00
}
else {
2014-10-02 21:47:19 +00:00
hostname = " AE title(s) unknown " ;
2008-07-25 13:36:58 +00:00
}
if ( pdv - > is_storage & &
2014-10-02 21:47:19 +00:00
pdv_curr - > sop_class_uid & & strlen ( pdv_curr - > sop_class_uid ) > 0 & &
pdv_curr - > sop_instance_uid & & strlen ( pdv_curr - > sop_instance_uid ) > 0 ) {
2016-11-21 03:46:10 +00:00
sop_class_uid = wmem_strdup ( wmem_packet_scope ( ) , pdv_curr - > sop_class_uid ) ;
sop_instance_uid = wmem_strdup ( wmem_packet_scope ( ) , pdv_curr - > sop_instance_uid ) ;
2014-10-02 21:47:19 +00:00
/* Make sure filename does not contain invalid character. Rather conservative.
Even though this should be a valid DICOM UID , apply the same filter rules
in case of bogus data .
*/
2016-01-24 03:40:51 +00:00
filename = wmem_strdup_printf ( wmem_packet_scope ( ) , " %06d-%d-%s.dcm " , pinfo - > num , cnt_same_pkt ,
2014-10-02 21:47:19 +00:00
g_strcanon ( pdv_curr - > sop_instance_uid , G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS " -. " , ' - ' ) ) ;
2008-07-25 13:36:58 +00:00
}
else {
2014-10-02 21:47:19 +00:00
/* No SOP Instance or SOP Class UID found in PDV. Use wireshark ones */
2008-07-25 13:36:58 +00:00
2014-10-02 21:47:19 +00:00
sop_class_uid = wmem_strdup ( wmem_packet_scope ( ) , WIRESHARK_MEDIA_STORAGE_SOP_CLASS_UID ) ;
sop_instance_uid = wmem_strdup_printf ( wmem_packet_scope ( ) , " %s.%d.%d " ,
2016-01-24 03:40:51 +00:00
WIRESHARK_MEDIA_STORAGE_SOP_INSTANCE_UID_PREFIX , pinfo - > num , cnt_same_pkt ) ;
2008-07-25 13:36:58 +00:00
2014-10-02 21:47:19 +00:00
/* Make sure filename does not contain invalid character. Rather conservative.*/
2016-01-24 03:40:51 +00:00
filename = wmem_strdup_printf ( wmem_packet_scope ( ) , " %06d-%d-%s.dcm " , pinfo - > num , cnt_same_pkt ,
2014-10-02 21:47:19 +00:00
g_strcanon ( pdv - > desc , G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS " -. " , ' - ' ) ) ;
2008-07-25 13:36:58 +00:00
}
2008-10-11 14:25:02 +00:00
if ( global_dcm_export_header ) {
2014-10-02 21:47:19 +00:00
if ( pctx & & pctx - > xfer_uid & & strlen ( pctx - > xfer_uid ) > 0 ) {
dcm_header = dcm_export_create_header ( & dcm_header_len , sop_class_uid , sop_instance_uid , pctx - > xfer_uid ) ;
}
else {
/* We are running blind, i.e. no presentation context/syntax found.
Don ' t invent one , so the meta header will miss
the transfer syntax UID tag ( even though it is mandatory )
*/
dcm_header = dcm_export_create_header ( & dcm_header_len , sop_class_uid , sop_instance_uid , NULL ) ;
}
2008-07-25 13:36:58 +00:00
}
2008-10-11 14:25:02 +00:00
if ( dcm_header_len + pdv_combined_len > = global_dcm_export_minsize ) {
2014-10-02 21:47:19 +00:00
/* Allocate the final size */
2009-07-10 21:54:29 +00:00
2016-04-12 16:14:14 +00:00
pdv_combined = ( guint8 * ) wmem_alloc0 ( wmem_file_scope ( ) , dcm_header_len + pdv_combined_len ) ;
2008-07-25 13:36:58 +00:00
2014-10-02 21:47:19 +00:00
pdv_combined_curr = pdv_combined ;
2008-07-25 13:36:58 +00:00
2014-10-02 21:47:19 +00:00
if ( dcm_header_len ! = 0 ) { /* Will be 0 when global_dcm_export_header is FALSE */
memmove ( pdv_combined , dcm_header , dcm_header_len ) ;
pdv_combined_curr + = dcm_header_len ;
}
2008-10-11 14:25:02 +00:00
2014-10-02 21:47:19 +00:00
/* Copy PDV per PDV to target buffer */
while ( ! pdv_curr - > is_last_fragment ) {
memmove ( pdv_combined_curr , pdv_curr - > data , pdv_curr - > data_len ) ; /* this is a copy not move */
pdv_combined_curr + = pdv_curr - > data_len ;
pdv_curr = pdv_curr - > next ;
}
2008-07-25 13:36:58 +00:00
2014-10-02 21:47:19 +00:00
/* Last packet */
memmove ( pdv_combined_curr , pdv - > data , pdv - > data_len ) ; /* this is a copy not a move */
2008-07-25 13:36:58 +00:00
2014-10-02 21:47:19 +00:00
/* Add to list */
2020-05-07 12:35:45 +00:00
eo_info = wmem_new0 ( wmem_file_scope ( ) , dicom_eo_t ) ;
2014-10-02 21:47:19 +00:00
eo_info - > hostname = g_strdup ( hostname ) ;
eo_info - > filename = g_strdup ( filename ) ;
eo_info - > content_type = g_strdup ( pdv - > desc ) ;
2008-07-25 13:36:58 +00:00
2014-10-02 21:47:19 +00:00
eo_info - > payload_data = pdv_combined ;
eo_info - > payload_len = dcm_header_len + pdv_combined_len ;
2008-07-25 13:36:58 +00:00
2014-10-02 21:47:19 +00:00
tap_queue_packet ( dicom_eo_tap , pinfo , eo_info ) ;
2008-10-11 14:25:02 +00:00
}
2008-07-25 13:36:58 +00:00
}
2018-03-05 10:54:55 +00:00
/*
For tags with fixed length items , calculate the value multiplicity ( VM ) . String tags use a separator , which is not supported by this function .
Support item count from 0 to n . and handles bad encoding ( e . g . an ' AT ' tag was reported to be 2 bytes instead of 4 bytes )
*/
static guint32
dcm_vm_item_count ( guint32 value_length , guint32 item_length )
{
2019-02-11 11:27:19 +00:00
/* This could all be formulated in a single line but it does not make it easier to read */
2018-03-05 10:54:55 +00:00
if ( value_length = = 0 ) {
return 0 ;
}
else if ( value_length < = item_length ) {
return 1 ; /* This is the special case of bad encoding */
}
else {
return ( value_length / item_length ) ;
}
}
2019-02-11 11:27:19 +00:00
/*
Decode the association header
*/
2010-08-09 19:28:09 +00:00
static guint32
dissect_dcm_assoc_header ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree , guint32 offset , dcm_state_assoc_t * assoc ,
2014-10-02 21:47:19 +00:00
guint8 pdu_type , guint32 pdu_len )
2010-08-09 19:28:09 +00:00
{
2014-06-25 03:24:14 +00:00
proto_item * assoc_header_pitem ;
2014-10-02 21:47:19 +00:00
proto_tree * assoc_header_ptree ; /* Tree for item details */
2010-08-09 19:28:09 +00:00
2014-10-02 21:47:19 +00:00
const gchar * buf_desc = NULL ;
2010-08-09 19:28:09 +00:00
const char * reject_result_desc = " " ;
const char * reject_source_desc = " " ;
const char * reject_reason_desc = " " ;
const char * abort_source_desc = " " ;
const char * abort_reason_desc = " " ;
2019-07-15 20:24:23 +00:00
char * ae_called ;
char * ae_calling ;
char * ae_called_resp ;
char * ae_calling_resp ;
2019-07-15 16:21:01 +00:00
2010-08-09 19:28:09 +00:00
guint8 reject_result ;
guint8 reject_source ;
guint8 reject_reason ;
guint8 abort_source ;
guint8 abort_reason ;
2014-06-25 03:24:14 +00:00
assoc_header_ptree = proto_tree_add_subtree ( tree , tvb , offset , pdu_len , ett_assoc_header , & assoc_header_pitem , " Association Header " ) ;
2010-08-09 19:28:09 +00:00
switch ( pdu_type ) {
2014-10-02 21:47:19 +00:00
case 1 : /* Association Request */
2019-02-12 13:15:29 +00:00
proto_tree_add_item ( assoc_header_ptree , hf_dcm_assoc_version , tvb , offset , 2 , ENC_BIG_ENDIAN ) ;
2014-10-02 21:47:19 +00:00
offset + = 2 ;
offset + = 2 ; /* Two reserved bytes*/
2019-07-15 16:21:01 +00:00
/*
* XXX - this is in " the ISO 646:1990-Basic G0 Set " ; ISO / IEC 646 : 1991
* claims to be the third edition of the standard , with the second
* version being ISO 646 : 1983 , so I ' m not sure what happened to
* ISO 646 : 1990. ISO / IEC 646 : 1991 speaks of " the basic 7-bit code
* table " , which leaves positions 2/3 (0x23) and 2/4 (0x24) as
* being either NUMBER SIGN or POUND SIGN and either DOLLAR SIGN or
* CURRENCY SIGN , respectively , and positions 4 / 0 ( 0x40 ) , 5 / 11 ( 0x5b ) ,
* 5 / 12 ( 0x5c ) , 5 / 13 ( 0x5d ) , 5 / 14 ( 0x5e ) , 6 / 0 ( 0x60 ) , 7 / 11 ( 0x7b ) ,
* 7 / 12 ( 0x7c ) , 7 / 13 ( 0x7d ) , and 7 / 14 ( 0x7e ) as being " available for
* national or application - oriented use " , so I'm *guessing* that
* " the ISO 646:1990-Basic G0 Set " means " those positions aren't
* specified " and thus should probably be treated as not valid
* in that " Basic " set .
*/
2019-07-15 20:24:23 +00:00
proto_tree_add_item_ret_display_string ( assoc_header_ptree , hf_dcm_assoc_called , tvb , offset , 16 , ENC_ISO_646_BASIC | ENC_NA , wmem_packet_scope ( ) , & ae_called ) ;
assoc - > ae_called = wmem_strdup ( wmem_file_scope ( ) , g_strstrip ( ae_called ) ) ;
2014-10-02 21:47:19 +00:00
offset + = 16 ;
2019-07-15 20:24:23 +00:00
proto_tree_add_item_ret_display_string ( assoc_header_ptree , hf_dcm_assoc_calling , tvb , offset , 16 , ENC_ISO_646_BASIC | ENC_NA , wmem_packet_scope ( ) , & ae_calling ) ;
assoc - > ae_calling = wmem_strdup ( wmem_file_scope ( ) , g_strstrip ( ae_calling ) ) ;
2014-10-02 21:47:19 +00:00
offset + = 16 ;
offset + = 32 ; /* 32 reserved bytes */
2018-06-28 14:30:29 +00:00
buf_desc = wmem_strdup_printf ( pinfo - > pool , " A-ASSOCIATE request %s --> %s " ,
2019-07-15 20:24:23 +00:00
assoc - > ae_calling , assoc - > ae_called ) ;
2014-10-02 21:47:19 +00:00
2018-03-05 10:54:55 +00:00
offset = dissect_dcm_assoc_detail ( tvb , pinfo , assoc_header_ptree , assoc , offset , pdu_len - offset ) ;
2014-10-02 21:47:19 +00:00
break ;
case 2 : /* Association Accept */
2019-02-12 13:15:29 +00:00
proto_tree_add_item ( assoc_header_ptree , hf_dcm_assoc_version , tvb , offset , 2 , ENC_BIG_ENDIAN ) ;
2014-10-02 21:47:19 +00:00
offset + = 2 ;
offset + = 2 ; /* Two reserved bytes*/
2019-07-15 20:24:23 +00:00
proto_tree_add_item_ret_display_string ( assoc_header_ptree , hf_dcm_assoc_called , tvb , offset , 16 , ENC_ISO_646_BASIC | ENC_NA , wmem_packet_scope ( ) , & ae_called_resp ) ;
assoc - > ae_called_resp = wmem_strdup ( wmem_file_scope ( ) , g_strstrip ( ae_called_resp ) ) ;
2014-10-02 21:47:19 +00:00
offset + = 16 ;
2019-07-15 20:24:23 +00:00
proto_tree_add_item_ret_display_string ( assoc_header_ptree , hf_dcm_assoc_calling , tvb , offset , 16 , ENC_ISO_646_BASIC | ENC_NA , wmem_packet_scope ( ) , & ae_calling_resp ) ;
assoc - > ae_calling_resp = wmem_strdup ( wmem_file_scope ( ) , g_strstrip ( ae_calling_resp ) ) ;
2014-10-02 21:47:19 +00:00
offset + = 16 ;
offset + = 32 ; /* 32 reserved bytes */
2018-06-28 14:30:29 +00:00
buf_desc = wmem_strdup_printf ( pinfo - > pool , " A-ASSOCIATE accept %s <-- %s " ,
2019-07-15 20:24:23 +00:00
assoc - > ae_calling_resp , assoc - > ae_called_resp ) ;
2010-08-09 19:28:09 +00:00
2018-03-05 10:54:55 +00:00
offset = dissect_dcm_assoc_detail ( tvb , pinfo , assoc_header_ptree , assoc , offset , pdu_len - offset ) ;
2010-08-09 19:28:09 +00:00
2014-10-02 21:47:19 +00:00
break ;
case 3 : /* Association Reject */
2010-08-09 19:28:09 +00:00
2014-10-02 21:47:19 +00:00
offset + = 1 ; /* One reserved byte */
2010-08-09 19:28:09 +00:00
2014-10-02 21:47:19 +00:00
reject_result = tvb_get_guint8 ( tvb , offset ) ;
reject_source = tvb_get_guint8 ( tvb , offset + 1 ) ;
reject_reason = tvb_get_guint8 ( tvb , offset + 2 ) ;
2010-08-09 19:28:09 +00:00
2014-10-02 21:47:19 +00:00
switch ( reject_result ) {
case 1 : reject_result_desc = " Reject Permanent " ; break ;
case 2 : reject_result_desc = " Reject Transient " ; break ;
default : break ;
}
switch ( reject_source ) {
case 1 :
reject_source_desc = " User " ;
switch ( reject_reason ) {
case 1 : reject_reason_desc = " No reason given " ; break ;
case 2 : reject_reason_desc = " Application context name not supported " ; break ;
case 3 : reject_reason_desc = " Calling AE title not recognized " ; break ;
case 7 : reject_reason_desc = " Called AE title not recognized " ; break ;
}
break ;
case 2 :
reject_source_desc = " Provider (ACSE) " ;
switch ( reject_reason ) {
case 1 : reject_reason_desc = " No reason given " ; break ;
case 2 : reject_reason_desc = " Protocol version not supported " ; break ;
}
break ;
case 3 :
reject_source_desc = " Provider (Presentation) " ;
switch ( reject_reason ) {
case 1 : reject_reason_desc = " Temporary congestion " ; break ;
case 2 : reject_reason_desc = " Local limit exceeded " ; break ;
}
break ;
}
proto_tree_add_uint_format_value ( assoc_header_ptree , hf_dcm_assoc_reject_result , tvb ,
offset , 1 , reject_result , " %s " , reject_result_desc ) ;
proto_tree_add_uint_format_value ( assoc_header_ptree , hf_dcm_assoc_reject_source , tvb ,
offset + 1 , 1 , reject_source , " %s " , reject_source_desc ) ;
proto_tree_add_uint_format_value ( assoc_header_ptree , hf_dcm_assoc_reject_reason , tvb ,
offset + 2 , 1 , reject_reason , " %s " , reject_reason_desc ) ;
offset + = 3 ;
/* Provider aborted */
2018-06-28 14:30:29 +00:00
buf_desc = wmem_strdup_printf ( pinfo - > pool , " A-ASSOCIATE reject %s <-- %s (%s) " ,
2019-07-15 20:24:23 +00:00
assoc - > ae_calling , assoc - > ae_called , reject_reason_desc ) ;
2014-10-02 21:47:19 +00:00
expert_add_info ( pinfo , assoc_header_pitem , & ei_dcm_assoc_rejected ) ;
break ;
case 5 : /* RELEASE Request */
offset + = 2 ; /* Two reserved bytes */
buf_desc = " A-RELEASE request " ;
break ;
case 6 : /* RELEASE Response */
offset + = 2 ; /* Two reserved bytes */
buf_desc = " A-RELEASE response " ;
break ;
case 7 : /* ABORT */
2010-08-09 19:28:09 +00:00
2014-10-02 21:47:19 +00:00
offset + = 2 ; /* Two reserved bytes */
2010-08-09 19:28:09 +00:00
2014-10-02 21:47:19 +00:00
abort_source = tvb_get_guint8 ( tvb , offset ) ;
abort_reason = tvb_get_guint8 ( tvb , offset + 1 ) ;
switch ( abort_source ) {
case 0 :
abort_source_desc = " User " ;
abort_reason_desc = " N/A " ; /* No details can be provided*/
break ;
case 1 :
/* reserved */
break ;
case 2 :
abort_source_desc = " Provider " ;
switch ( abort_reason ) {
case 0 : abort_reason_desc = " Not specified " ; break ;
case 1 : abort_reason_desc = " Unrecognized PDU " ; break ;
case 2 : abort_reason_desc = " Unexpected PDU " ; break ;
case 4 : abort_reason_desc = " Unrecognized PDU parameter " ; break ;
case 5 : abort_reason_desc = " Unexpected PDU parameter " ; break ;
case 6 : abort_reason_desc = " Invalid PDU parameter value " ; break ;
}
break ;
}
proto_tree_add_uint_format_value ( assoc_header_ptree , hf_dcm_assoc_abort_source ,
tvb , offset , 1 , abort_source , " %s " , abort_source_desc ) ;
proto_tree_add_uint_format_value ( assoc_header_ptree , hf_dcm_assoc_abort_reason ,
tvb , offset + 1 , 1 , abort_reason , " %s " , abort_reason_desc ) ;
offset + = 2 ;
if ( abort_source = = 0 ) {
/* User aborted */
2018-06-28 14:30:29 +00:00
buf_desc = wmem_strdup_printf ( pinfo - > pool , " ABORT %s --> %s " ,
2019-07-15 20:24:23 +00:00
assoc - > ae_calling , assoc - > ae_called ) ;
2014-10-02 21:47:19 +00:00
}
else {
/* Provider aborted, slightly more information */
2018-06-28 14:30:29 +00:00
buf_desc = wmem_strdup_printf ( pinfo - > pool , " ABORT %s <-- %s (%s) " ,
2019-07-15 20:24:23 +00:00
assoc - > ae_calling , assoc - > ae_called , abort_reason_desc ) ;
2014-10-02 21:47:19 +00:00
}
expert_add_info ( pinfo , assoc_header_pitem , & ei_dcm_assoc_aborted ) ;
break ;
2010-08-09 19:28:09 +00:00
}
proto_item_set_text ( assoc_header_pitem , " %s " , buf_desc ) ;
2018-05-06 15:33:51 +00:00
col_set_str ( pinfo - > cinfo , COL_INFO , buf_desc ) ;
2010-08-09 19:28:09 +00:00
/* proto_item and proto_tree are one and the same */
proto_item_append_text ( tree , " , %s " , buf_desc ) ;
return offset ;
}
2008-07-25 13:36:58 +00:00
2018-03-05 10:54:55 +00:00
/*
Decode one item in a association request or response . Lookup UIDs if requested .
Create a subtree node with summary and three elements ( item_type , item_len , value )
*/
2008-07-25 13:36:58 +00:00
static void
2008-10-11 14:25:02 +00:00
dissect_dcm_assoc_item ( tvbuff_t * tvb , proto_tree * tree , guint32 offset ,
2014-10-02 21:47:19 +00:00
const gchar * pitem_prefix , int item_value_type ,
gchar * * item_value , const gchar * * item_description ,
int * hf_type , int * hf_len , int * hf_value , int ett_subtree )
2004-05-08 08:49:02 +00:00
{
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
proto_tree * assoc_item_ptree ; /* Tree for item details */
2014-06-25 03:24:14 +00:00
proto_item * assoc_item_pitem ;
2008-10-11 14:25:02 +00:00
dcm_uid_t * uid = NULL ;
2008-07-25 13:20:18 +00:00
2008-10-11 14:25:02 +00:00
guint32 item_number = 0 ;
2008-07-25 13:20:18 +00:00
2018-03-05 10:54:55 +00:00
guint8 item_type ;
guint16 item_len ;
2008-07-25 13:20:18 +00:00
2016-11-21 03:46:10 +00:00
gchar * buf_desc = " " ; /* Used for item text */
2008-07-25 13:20:18 +00:00
2008-10-11 14:25:02 +00:00
* item_value = NULL ;
* item_description = NULL ;
2008-07-25 13:20:18 +00:00
item_type = tvb_get_guint8 ( tvb , offset ) ;
item_len = tvb_get_ntohs ( tvb , offset + 2 ) ;
2014-06-25 03:24:14 +00:00
assoc_item_ptree = proto_tree_add_subtree ( tree , tvb , offset , item_len + 4 , ett_subtree , & assoc_item_pitem , pitem_prefix ) ;
2008-07-25 13:20:18 +00:00
2018-03-05 10:54:55 +00:00
proto_tree_add_uint ( assoc_item_ptree , * hf_type , tvb , offset , 1 , item_type ) ;
proto_tree_add_uint ( assoc_item_ptree , * hf_len , tvb , offset + 2 , 2 , item_len ) ;
2008-07-25 13:20:18 +00:00
switch ( item_value_type ) {
case DCM_ITEM_VALUE_TYPE_UID :
2014-10-02 21:47:19 +00:00
* item_value = ( gchar * ) tvb_get_string_enc ( wmem_packet_scope ( ) , tvb , offset + 4 , item_len , ENC_ASCII ) ;
2004-05-08 08:49:02 +00:00
2017-02-25 00:46:49 +00:00
uid = ( dcm_uid_t * ) wmem_map_lookup ( dcm_uid_table , ( gpointer ) * item_value ) ;
2014-10-02 21:47:19 +00:00
if ( uid ) {
* item_description = uid - > name ;
2016-11-21 03:46:10 +00:00
buf_desc = wmem_strdup_printf ( wmem_packet_scope ( ) , " %s (%s) " , * item_description , * item_value ) ;
2014-10-02 21:47:19 +00:00
}
else {
/* Unknown UID, or no UID at all */
2016-11-21 03:46:10 +00:00
buf_desc = * item_value ;
2014-10-02 21:47:19 +00:00
}
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
proto_item_append_text ( assoc_item_pitem , " %s " , buf_desc ) ;
proto_tree_add_string ( assoc_item_ptree , * hf_value , tvb , offset + 4 , item_len , buf_desc ) ;
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
break ;
2008-07-25 13:20:18 +00:00
case DCM_ITEM_VALUE_TYPE_STRING :
2014-10-02 21:47:19 +00:00
* item_value = ( gchar * ) tvb_get_string_enc ( wmem_packet_scope ( ) , tvb , offset + 4 , item_len , ENC_ASCII ) ;
2008-07-25 13:20:18 +00:00
proto_item_append_text ( assoc_item_pitem , " %s " , * item_value ) ;
2014-10-02 21:47:19 +00:00
proto_tree_add_string ( assoc_item_ptree , * hf_value , tvb , offset + 4 , item_len , * item_value ) ;
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
break ;
2008-07-25 13:36:58 +00:00
2008-07-25 13:20:18 +00:00
case DCM_ITEM_VALUE_TYPE_UINT32 :
2014-10-02 21:47:19 +00:00
item_number = tvb_get_ntohl ( tvb , offset + 4 ) ;
2016-11-21 03:46:10 +00:00
* item_value = ( gchar * ) wmem_strdup_printf ( wmem_file_scope ( ) , " %d " , item_number ) ;
2008-07-25 13:36:58 +00:00
2014-10-02 21:47:19 +00:00
proto_item_append_text ( assoc_item_pitem , " %s " , * item_value ) ;
proto_tree_add_item ( assoc_item_ptree , * hf_value , tvb , offset + 4 , 4 , ENC_BIG_ENDIAN ) ;
2008-07-25 13:36:58 +00:00
2014-10-02 21:47:19 +00:00
break ;
2008-07-25 13:20:18 +00:00
default :
2014-10-02 21:47:19 +00:00
break ;
2008-07-25 13:20:18 +00:00
}
2004-05-08 08:49:02 +00:00
}
2019-02-11 11:27:19 +00:00
/*
Decode the SOP Class Extended Negotiation Sub - Item Fields in a association request or response .
Lookup UIDs if requested
*/
2013-02-06 13:33:31 +00:00
static void
dissect_dcm_assoc_sopclass_extneg ( tvbuff_t * tvb , proto_tree * tree , guint32 offset )
{
2014-10-02 21:47:19 +00:00
proto_tree * assoc_item_extneg_tree = NULL ; /* Tree for item details */
2013-02-06 13:33:31 +00:00
proto_item * assoc_item_extneg_item = NULL ;
guint16 item_len = 0 ;
guint16 sop_class_uid_len = 0 ;
gint32 cnt = 0 ;
2014-10-02 21:47:19 +00:00
gchar * buf_desc = NULL ; /* Used for item text */
2013-02-06 13:33:31 +00:00
dcm_uid_t * sopclassuid = NULL ;
gchar * sopclassuid_str = NULL ;
item_len = tvb_get_ntohs ( tvb , offset + 2 ) ;
sop_class_uid_len = tvb_get_ntohs ( tvb , offset + 4 ) ;
assoc_item_extneg_item = proto_tree_add_item ( tree , hf_dcm_info_extneg , tvb , offset , item_len + 4 , ENC_NA ) ;
proto_item_set_text ( assoc_item_extneg_item , " Ext. Neg.: " ) ;
assoc_item_extneg_tree = proto_item_add_subtree ( assoc_item_extneg_item , ett_assoc_info_extneg ) ;
2014-12-13 17:52:20 +00:00
proto_tree_add_item ( assoc_item_extneg_tree , hf_dcm_assoc_item_type , tvb , offset , 1 , ENC_BIG_ENDIAN ) ;
2013-02-06 13:33:31 +00:00
proto_tree_add_item ( assoc_item_extneg_tree , hf_dcm_assoc_item_len , tvb , offset + 2 , 2 , ENC_BIG_ENDIAN ) ;
proto_tree_add_item ( assoc_item_extneg_tree , hf_dcm_info_extneg_sopclassuid_len , tvb , offset + 4 , 2 , ENC_BIG_ENDIAN ) ;
2014-06-17 15:30:58 +00:00
sopclassuid_str = ( gchar * ) tvb_get_string_enc ( wmem_packet_scope ( ) , tvb , offset + 6 , sop_class_uid_len , ENC_ASCII ) ;
2017-02-25 00:46:49 +00:00
sopclassuid = ( dcm_uid_t * ) wmem_map_lookup ( dcm_uid_table , ( gpointer ) sopclassuid_str ) ;
2013-02-06 13:33:31 +00:00
if ( sopclassuid ) {
2016-11-21 03:46:10 +00:00
buf_desc = wmem_strdup_printf ( wmem_packet_scope ( ) , " %s (%s) " , sopclassuid - > name , sopclassuid - > value ) ;
2013-02-06 13:33:31 +00:00
}
else {
2016-11-21 03:46:10 +00:00
buf_desc = sopclassuid_str ;
2013-02-06 13:33:31 +00:00
}
proto_item_append_text ( assoc_item_extneg_item , " %s " , buf_desc ) ;
proto_tree_add_string ( assoc_item_extneg_tree , hf_dcm_info_extneg_sopclassuid , tvb , offset + 6 , sop_class_uid_len , buf_desc ) ;
/* Count how many fields are following. */
cnt = item_len - 2 - sop_class_uid_len ;
/*
* The next field contains Service Class specific information identified by the SOP Class UID .
*/
2018-10-22 15:58:35 +00:00
if ( 0 = = strcmp ( sopclassuid_str , DCM_UID_SOP_CLASS_PATIENT_ROOT_QUERYRETRIEVE_INFORMATION_MODEL_FIND ) | |
0 = = strcmp ( sopclassuid_str , DCM_UID_SOP_CLASS_STUDY_ROOT_QUERYRETRIEVE_INFORMATION_MODEL_FIND ) | |
0 = = strcmp ( sopclassuid_str , DCM_UID_SOP_CLASS_PATIENTSTUDY_ONLY_QUERYRETRIEVE_INFORMATION_MODEL_FIND_RETIRED ) | |
0 = = strcmp ( sopclassuid_str , DCM_UID_SOP_CLASS_PATIENT_ROOT_QUERYRETRIEVE_INFORMATION_MODEL_MOVE ) | |
0 = = strcmp ( sopclassuid_str , DCM_UID_SOP_CLASS_STUDY_ROOT_QUERYRETRIEVE_INFORMATION_MODEL_MOVE ) | |
0 = = strcmp ( sopclassuid_str , DCM_UID_SOP_CLASS_PATIENTSTUDY_ONLY_QUERYRETRIEVE_INFORMATION_MODEL_MOVE_RETIRED ) | |
0 = = strcmp ( sopclassuid_str , DCM_UID_SOP_CLASS_PATIENT_ROOT_QUERYRETRIEVE_INFORMATION_MODEL_GET ) | |
0 = = strcmp ( sopclassuid_str , DCM_UID_SOP_CLASS_STUDY_ROOT_QUERYRETRIEVE_INFORMATION_MODEL_GET ) | |
0 = = strcmp ( sopclassuid_str , DCM_UID_SOP_CLASS_PATIENTSTUDY_ONLY_QUERYRETRIEVE_INFORMATION_MODEL_GET_RETIRED ) )
2013-02-06 13:33:31 +00:00
{
if ( cnt < = 0 )
{
return ;
}
/* Support for Relational queries. */
2014-12-13 17:52:20 +00:00
proto_tree_add_item ( assoc_item_extneg_tree , hf_dcm_info_extneg_relational_query , tvb , offset + 6 + sop_class_uid_len , 1 , ENC_BIG_ENDIAN ) ;
2013-02-06 13:33:31 +00:00
- - cnt ;
}
/* More sub-items are only allowed for the C-FIND SOP Classes. */
2018-10-22 15:58:35 +00:00
if ( 0 = = strcmp ( sopclassuid_str , DCM_UID_SOP_CLASS_PATIENT_ROOT_QUERYRETRIEVE_INFORMATION_MODEL_FIND ) | |
0 = = strcmp ( sopclassuid_str , DCM_UID_SOP_CLASS_STUDY_ROOT_QUERYRETRIEVE_INFORMATION_MODEL_FIND ) | |
0 = = strcmp ( sopclassuid_str , DCM_UID_SOP_CLASS_PATIENTSTUDY_ONLY_QUERYRETRIEVE_INFORMATION_MODEL_FIND_RETIRED ) )
2013-02-06 13:33:31 +00:00
{
if ( cnt < = 0 )
{
return ;
}
/* Combined Date-Time matching. */
2014-12-13 17:52:20 +00:00
proto_tree_add_item ( assoc_item_extneg_tree , hf_dcm_info_extneg_date_time_matching , tvb , offset + 7 + sop_class_uid_len , 1 , ENC_BIG_ENDIAN ) ;
2013-02-06 13:33:31 +00:00
- - cnt ;
if ( cnt < = 0 )
{
return ;
}
/* Fuzzy semantic matching of person names. */
2014-12-13 17:52:20 +00:00
proto_tree_add_item ( assoc_item_extneg_tree , hf_dcm_info_extneg_fuzzy_semantic_matching , tvb , offset + 8 + sop_class_uid_len , 1 , ENC_BIG_ENDIAN ) ;
2013-02-06 13:33:31 +00:00
- - cnt ;
if ( cnt < = 0 )
{
return ;
}
/* Timezone query adjustment. */
2014-12-13 17:52:20 +00:00
proto_tree_add_item ( assoc_item_extneg_tree , hf_dcm_info_extneg_timezone_query_adjustment , tvb , offset + 9 + sop_class_uid_len , 1 , ENC_BIG_ENDIAN ) ;
2013-02-06 13:33:31 +00:00
- - cnt ;
}
}
2008-07-25 13:20:18 +00:00
2019-02-11 11:27:19 +00:00
/*
Decode user identities in the association
*/
2017-07-19 13:00:22 +00:00
static void
dissect_dcm_assoc_user_identify ( tvbuff_t * tvb , proto_tree * tree , guint32 offset )
{
proto_tree * assoc_item_user_identify_tree = NULL ; /* Tree for item details */
proto_item * assoc_item_user_identify_item = NULL ;
guint16 primary_field_length , secondary_field_length , item_len = 0 ;
guint8 type ;
item_len = tvb_get_ntohs ( tvb , offset + 2 ) ;
assoc_item_user_identify_item = proto_tree_add_item ( tree , hf_dcm_info_user_identify , tvb , offset , item_len + 4 , ENC_NA ) ;
assoc_item_user_identify_tree = proto_item_add_subtree ( assoc_item_user_identify_item , ett_assoc_info_user_identify ) ;
proto_tree_add_item ( assoc_item_user_identify_tree , hf_dcm_assoc_item_type , tvb , offset , 1 , ENC_BIG_ENDIAN ) ;
offset + = 2 ;
proto_tree_add_item ( assoc_item_user_identify_tree , hf_dcm_assoc_item_len , tvb , offset , 2 , ENC_BIG_ENDIAN ) ;
offset + = 2 ;
type = tvb_get_guint8 ( tvb , offset ) ;
proto_tree_add_item ( assoc_item_user_identify_tree , hf_dcm_info_user_identify_type , tvb , offset , 1 , ENC_BIG_ENDIAN ) ;
offset + = 1 ;
proto_tree_add_item ( assoc_item_user_identify_tree , hf_dcm_info_user_identify_response_requested , tvb , offset , 1 , ENC_BIG_ENDIAN ) ;
offset + = 1 ;
primary_field_length = tvb_get_ntohs ( tvb , offset ) ;
proto_tree_add_item ( assoc_item_user_identify_tree , hf_dcm_info_user_identify_primary_field_length , tvb , offset , 2 , ENC_BIG_ENDIAN ) ;
offset + = 2 ;
proto_tree_add_item ( assoc_item_user_identify_tree , hf_dcm_info_user_identify_primary_field , tvb , offset , primary_field_length , ENC_UTF_8 | ENC_NA ) ;
proto_item_append_text ( assoc_item_user_identify_item , " : %s " , tvb_get_string_enc ( wmem_packet_scope ( ) , tvb , offset , primary_field_length , ENC_UTF_8 | ENC_NA ) ) ;
offset + = primary_field_length ;
if ( type = = 2 ) {
secondary_field_length = tvb_get_ntohs ( tvb , offset ) ;
proto_tree_add_item ( assoc_item_user_identify_tree , hf_dcm_info_user_identify_secondary_field_length , tvb , offset , 2 , ENC_BIG_ENDIAN ) ;
offset + = 2 ;
proto_tree_add_item ( assoc_item_user_identify_tree , hf_dcm_info_user_identify_secondary_field , tvb , offset , secondary_field_length , ENC_UTF_8 | ENC_NA ) ;
proto_item_append_text ( assoc_item_user_identify_item , " , %s " , tvb_get_string_enc ( wmem_packet_scope ( ) , tvb , offset , secondary_field_length , ENC_UTF_8 | ENC_NA ) ) ;
}
}
2019-02-11 11:27:19 +00:00
/*
Decode unknown item types in the association
*/
2017-07-19 11:47:03 +00:00
static void
dissect_dcm_assoc_unknown ( tvbuff_t * tvb , proto_tree * tree , guint32 offset )
{
proto_tree * assoc_item_unknown_tree = NULL ; /* Tree for item details */
proto_item * assoc_item_unknown_item = NULL ;
guint16 item_len = 0 ;
item_len = tvb_get_ntohs ( tvb , offset + 2 ) ;
assoc_item_unknown_item = proto_tree_add_item ( tree , hf_dcm_info_unknown , tvb , offset , item_len + 4 , ENC_NA ) ;
assoc_item_unknown_tree = proto_item_add_subtree ( assoc_item_unknown_item , ett_assoc_info_unknown ) ;
2018-03-05 10:54:55 +00:00
proto_tree_add_item ( assoc_item_unknown_tree , hf_dcm_assoc_item_type , tvb , offset , 1 , ENC_BIG_ENDIAN ) ;
proto_tree_add_item ( assoc_item_unknown_tree , hf_dcm_assoc_item_len , tvb , offset + 2 , 2 , ENC_BIG_ENDIAN ) ;
offset + = 4 ;
2017-07-19 11:47:03 +00:00
2018-03-05 10:54:55 +00:00
proto_tree_add_item ( assoc_item_unknown_tree , hf_dcm_assoc_item_data , tvb , offset , item_len , ENC_NA ) ;
2017-07-19 11:47:03 +00:00
}
2019-02-11 11:27:19 +00:00
/*
Decode the SCP / SCU Role Selection Sub - Item Fields in a association request or response .
Lookup UIDs if requested
*/
2013-02-17 19:36:08 +00:00
static void
dissect_dcm_assoc_role_selection ( tvbuff_t * tvb , proto_tree * tree , guint32 offset )
{
proto_tree * assoc_item_rolesel_tree ; /* Tree for item details */
proto_item * assoc_item_rolesel_item ;
guint16 item_len , sop_class_uid_len ;
guint8 scp_role , scu_role ;
2013-10-13 19:56:52 +00:00
2016-11-21 03:46:10 +00:00
gchar * buf_desc ; /* Used for item text */
2013-02-17 19:36:08 +00:00
dcm_uid_t * sopclassuid ;
gchar * sopclassuid_str ;
item_len = tvb_get_ntohs ( tvb , offset + 2 ) ;
sop_class_uid_len = tvb_get_ntohs ( tvb , offset + 4 ) ;
assoc_item_rolesel_item = proto_tree_add_item ( tree , hf_dcm_info_rolesel , tvb , offset , item_len + 4 , ENC_NA ) ;
proto_item_set_text ( assoc_item_rolesel_item , " Role Selection: " ) ;
assoc_item_rolesel_tree = proto_item_add_subtree ( assoc_item_rolesel_item , ett_assoc_info_rolesel ) ;
2014-12-13 17:52:20 +00:00
proto_tree_add_item ( assoc_item_rolesel_tree , hf_dcm_assoc_item_type , tvb , offset , 1 , ENC_BIG_ENDIAN ) ;
2013-02-17 19:36:08 +00:00
proto_tree_add_item ( assoc_item_rolesel_tree , hf_dcm_assoc_item_len , tvb , offset + 2 , 2 , ENC_BIG_ENDIAN ) ;
proto_tree_add_item ( assoc_item_rolesel_tree , hf_dcm_info_rolesel_sopclassuid_len , tvb , offset + 4 , 2 , ENC_BIG_ENDIAN ) ;
2014-06-17 15:30:58 +00:00
sopclassuid_str = ( gchar * ) tvb_get_string_enc ( wmem_packet_scope ( ) , tvb , offset + 6 , sop_class_uid_len , ENC_ASCII ) ;
2017-02-25 00:46:49 +00:00
sopclassuid = ( dcm_uid_t * ) wmem_map_lookup ( dcm_uid_table , ( gpointer ) sopclassuid_str ) ;
2013-02-17 19:36:08 +00:00
scu_role = tvb_get_guint8 ( tvb , offset + 6 + sop_class_uid_len ) ;
scp_role = tvb_get_guint8 ( tvb , offset + 7 + sop_class_uid_len ) ;
2013-10-13 19:56:52 +00:00
2013-02-17 19:36:08 +00:00
if ( scu_role ) {
proto_item_append_text ( assoc_item_rolesel_item , " %s " , " SCU-role: yes " ) ;
}
else {
proto_item_append_text ( assoc_item_rolesel_item , " %s " , " SCU-role: no " ) ;
}
2013-10-13 19:56:52 +00:00
2013-02-17 19:36:08 +00:00
if ( scp_role ) {
proto_item_append_text ( assoc_item_rolesel_item , " , %s " , " SCP-role: yes " ) ;
}
else {
proto_item_append_text ( assoc_item_rolesel_item , " , %s " , " SCP-role: no " ) ;
}
2013-10-13 19:56:52 +00:00
2013-02-17 19:36:08 +00:00
if ( sopclassuid ) {
2016-11-21 03:46:10 +00:00
buf_desc = wmem_strdup_printf ( wmem_packet_scope ( ) , " %s (%s) " , sopclassuid - > name , sopclassuid - > value ) ;
2013-02-17 19:36:08 +00:00
}
else {
2016-11-21 03:46:10 +00:00
buf_desc = sopclassuid_str ;
2013-02-17 19:36:08 +00:00
}
2013-10-13 19:56:52 +00:00
2013-02-17 19:36:08 +00:00
proto_tree_add_string ( assoc_item_rolesel_tree , hf_dcm_info_rolesel_sopclassuid , tvb , offset + 6 , sop_class_uid_len , buf_desc ) ;
2014-12-13 17:52:20 +00:00
proto_tree_add_item ( assoc_item_rolesel_tree , hf_dcm_info_rolesel_scurole , tvb , offset + 6 + sop_class_uid_len , 1 , ENC_BIG_ENDIAN ) ;
proto_tree_add_item ( assoc_item_rolesel_tree , hf_dcm_info_rolesel_scprole , tvb , offset + 7 + sop_class_uid_len , 1 , ENC_BIG_ENDIAN ) ;
2013-02-17 19:36:08 +00:00
}
2019-02-11 11:27:19 +00:00
/*
Decode the Asynchronous operations ( and sub - operations ) Window Negotiation Sub - Item Fields in a association request or response .
*/
2013-02-17 19:36:08 +00:00
static void
dissect_dcm_assoc_async_negotiation ( tvbuff_t * tvb , proto_tree * tree , guint32 offset )
{
proto_tree * assoc_item_asyncneg_tree ; /* Tree for item details */
proto_item * assoc_item_asyncneg_item ;
guint16 item_len , max_num_ops_inv , max_num_ops_per = 0 ;
item_len = tvb_get_ntohs ( tvb , offset + 2 ) ;
assoc_item_asyncneg_item = proto_tree_add_item ( tree , hf_dcm_info_async_neg , tvb , offset , item_len + 4 , ENC_NA ) ;
proto_item_set_text ( assoc_item_asyncneg_item , " Async Negotiation: " ) ;
assoc_item_asyncneg_tree = proto_item_add_subtree ( assoc_item_asyncneg_item , ett_assoc_info_async_neg ) ;
2014-12-13 17:52:20 +00:00
proto_tree_add_item ( assoc_item_asyncneg_tree , hf_dcm_assoc_item_type , tvb , offset , 1 , ENC_BIG_ENDIAN ) ;
2013-02-17 19:36:08 +00:00
proto_tree_add_item ( assoc_item_asyncneg_tree , hf_dcm_assoc_item_len , tvb , offset + 2 , 2 , ENC_BIG_ENDIAN ) ;
proto_tree_add_item ( assoc_item_asyncneg_tree , hf_dcm_info_async_neg_max_num_ops_inv , tvb , offset + 4 , 2 , ENC_BIG_ENDIAN ) ;
proto_tree_add_item ( assoc_item_asyncneg_tree , hf_dcm_info_async_neg_max_num_ops_per , tvb , offset + 6 , 2 , ENC_BIG_ENDIAN ) ;
max_num_ops_inv = tvb_get_ntohs ( tvb , offset + 4 ) ;
max_num_ops_per = tvb_get_ntohs ( tvb , offset + 6 ) ;
proto_item_append_text ( assoc_item_asyncneg_item , " %s%d " , " Maximum Number Operations Invoked: " , max_num_ops_inv ) ;
if ( max_num_ops_inv = = 0 ) proto_item_append_text ( assoc_item_asyncneg_item , " %s " , " (unlimited) " ) ;
proto_item_append_text ( assoc_item_asyncneg_item , " , %s%d " , " Maximum Number Operations Performed: " , max_num_ops_per ) ;
if ( max_num_ops_per = = 0 ) proto_item_append_text ( assoc_item_asyncneg_item , " %s " , " (unlimited) " ) ;
}
2018-03-05 10:54:55 +00:00
/*
Decode a presentation context item in a Association Request or Response . In the response , set the accepted transfer syntax , if any .
*/
2008-07-25 13:20:18 +00:00
static void
2008-07-25 13:36:58 +00:00
dissect_dcm_pctx ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree ,
2014-10-02 21:47:19 +00:00
dcm_state_assoc_t * assoc , guint32 offset , guint32 len ,
const gchar * pitem_prefix , gboolean is_assoc_request )
2008-07-25 13:20:18 +00:00
{
2018-03-05 10:54:55 +00:00
proto_tree * pctx_ptree ; /* Tree for presentation context details */
2014-06-25 03:24:14 +00:00
proto_item * pctx_pitem ;
2008-07-25 13:20:18 +00:00
2008-07-25 13:36:58 +00:00
dcm_state_pctx_t * pctx = NULL ;
2008-07-25 13:20:18 +00:00
2008-10-11 14:25:02 +00:00
guint8 item_type = 0 ;
guint16 item_len = 0 ;
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
guint8 pctx_id = 0 ; /* Presentation Context ID */
2008-10-11 14:25:02 +00:00
guint8 pctx_result = 0 ;
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
const char * pctx_result_desc = " " ;
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
gchar * pctx_abss_uid = NULL ; /* Abstract Syntax UID alias SOP Class UID */
const gchar * pctx_abss_desc = NULL ; /* Description of UID */
2010-08-09 19:28:09 +00:00
2014-10-02 21:47:19 +00:00
gchar * pctx_xfer_uid = NULL ; /* Transfer Syntax UID */
const gchar * pctx_xfer_desc = NULL ; /* Description of UID */
2008-07-25 13:20:18 +00:00
2018-03-05 10:54:55 +00:00
gchar * buf_desc = " " ; /* Used in info mode for item text */
2008-07-25 13:36:58 +00:00
2008-10-11 14:25:02 +00:00
guint32 endpos = 0 ;
2018-03-05 10:54:55 +00:00
int cnt_abbs = 0 ; /* Number of Abstract Syntax Items */
int cnt_xfer = 0 ; /* Number of Transfer Syntax Items */
2008-07-25 13:20:18 +00:00
2008-10-11 14:25:02 +00:00
endpos = offset + len ;
2008-07-25 13:20:18 +00:00
item_type = tvb_get_guint8 ( tvb , offset - 4 ) ;
item_len = tvb_get_ntohs ( tvb , offset - 2 ) ;
2014-06-25 03:24:14 +00:00
pctx_ptree = proto_tree_add_subtree ( tree , tvb , offset - 4 , item_len + 4 , ett_assoc_pctx , & pctx_pitem , pitem_prefix ) ;
2008-07-25 13:20:18 +00:00
pctx_id = tvb_get_guint8 ( tvb , offset ) ;
2014-10-02 21:47:19 +00:00
pctx_result = tvb_get_guint8 ( tvb , 2 + offset ) ; /* only set in responses, otherwise reserved and 0x00 */
2008-07-25 13:20:18 +00:00
2019-02-11 11:27:19 +00:00
/* Find or create DICOM context object */
2008-07-25 13:36:58 +00:00
pctx = dcm_state_pctx_get ( assoc , pctx_id , TRUE ) ;
2014-10-02 21:47:19 +00:00
if ( pctx = = NULL ) { /* Internal error. Failed to create data structure */
return ;
2008-07-25 13:20:18 +00:00
}
2018-03-05 10:54:55 +00:00
proto_tree_add_uint ( pctx_ptree , hf_dcm_assoc_item_type , tvb , offset - 4 , 1 , item_type ) ; /* The type is only one byte long */
2008-07-25 13:36:58 +00:00
proto_tree_add_uint ( pctx_ptree , hf_dcm_assoc_item_len , tvb , offset - 2 , 2 , item_len ) ;
2008-07-25 13:20:18 +00:00
proto_tree_add_uint_format ( pctx_ptree , hf_dcm_pctx_id , tvb , offset , 1 , pctx_id , " Context ID: 0x%02x " , pctx_id ) ;
2008-07-25 13:36:58 +00:00
if ( ! is_assoc_request ) {
2014-10-02 21:47:19 +00:00
/* Association response. */
switch ( pctx_result ) {
case 0 : pctx_result_desc = " Accept " ; break ;
case 1 : pctx_result_desc = " User Reject " ; break ;
case 2 : pctx_result_desc = " No Reason " ; break ;
case 3 : pctx_result_desc = " Abstract Syntax Unsupported " ; break ;
case 4 : pctx_result_desc = " Transfer Syntax Unsupported " ; break ;
}
proto_tree_add_uint_format ( pctx_ptree , hf_dcm_pctx_result , tvb , offset + 2 , 1 ,
pctx_result , " Result: %s (0x%x) " , pctx_result_desc , pctx_result ) ;
2008-07-25 13:20:18 +00:00
}
offset + = 4 ;
2008-10-11 14:25:02 +00:00
while ( offset < endpos ) {
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
item_type = tvb_get_guint8 ( tvb , offset ) ;
item_len = tvb_get_ntohs ( tvb , 2 + offset ) ;
offset + = 4 ;
switch ( item_type ) {
case 0x30 : /* Abstract syntax */
/* Parse Item. Works also in info mode where dcm_pctx_tree is NULL */
dissect_dcm_assoc_item ( tvb , pctx_ptree , offset - 4 ,
" Abstract Syntax: " , DCM_ITEM_VALUE_TYPE_UID , & pctx_abss_uid , & pctx_abss_desc ,
& hf_dcm_assoc_item_type , & hf_dcm_assoc_item_len , & hf_dcm_pctx_abss_syntax , ett_assoc_pctx_abss ) ;
cnt_abbs + = 1 ;
offset + = item_len ;
break ;
case 0x40 : /* Transfer syntax */
dissect_dcm_assoc_item ( tvb , pctx_ptree , offset - 4 ,
" Transfer Syntax: " , DCM_ITEM_VALUE_TYPE_UID , & pctx_xfer_uid , & pctx_xfer_desc ,
& hf_dcm_assoc_item_type , & hf_dcm_assoc_item_len , & hf_dcm_pctx_xfer_syntax , ett_assoc_pctx_xfer ) ;
/*
In a correct Association Response , only one Transfer syntax shall be present .
Therefore , pctx_xfer_uid , pctx_xfer_desc are used for the accept scenario in the info mode
*/
if ( ! is_assoc_request & & pctx_result = = 0 ) {
/* Association Response, Context Accepted */
dcm_set_syntax ( pctx , pctx_xfer_uid , pctx_xfer_desc ) ;
}
cnt_xfer + = 1 ;
offset + = item_len ;
break ;
default :
offset + = item_len ;
break ;
}
2008-07-25 13:20:18 +00:00
}
2008-07-25 13:36:58 +00:00
if ( is_assoc_request ) {
2014-10-02 21:47:19 +00:00
if ( cnt_abbs < 1 ) {
expert_add_info ( pinfo , pctx_pitem , & ei_dcm_no_abstract_syntax ) ;
return ;
}
else if ( cnt_abbs > 1 ) {
expert_add_info ( pinfo , pctx_pitem , & ei_dcm_multiple_abstract_syntax ) ;
return ;
}
if ( cnt_xfer = = 0 ) {
expert_add_info ( pinfo , pctx_pitem , & ei_dcm_no_transfer_syntax ) ;
return ;
}
if ( pctx_abss_uid = = NULL ) {
expert_add_info ( pinfo , pctx_pitem , & ei_dcm_no_abstract_syntax_uid ) ;
return ;
}
2008-07-25 13:36:58 +00:00
2008-07-25 13:20:18 +00:00
}
2008-07-25 13:36:58 +00:00
else {
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
if ( cnt_xfer > 1 ) {
expert_add_info ( pinfo , pctx_pitem , & ei_dcm_multiple_transfer_syntax ) ;
return ;
}
2008-07-25 13:36:58 +00:00
}
if ( pctx - > abss_uid = = NULL ) {
2014-10-02 21:47:19 +00:00
/* Permanent copy information into structure */
pctx - > abss_uid = wmem_strdup ( wmem_file_scope ( ) , pctx_abss_uid ) ;
pctx - > abss_desc = wmem_strdup ( wmem_file_scope ( ) , pctx_abss_desc ) ;
2008-07-25 13:36:58 +00:00
}
2008-07-25 13:20:18 +00:00
/*
Copy to buffer first , because proto_item_append_text ( )
crashed for an unknown reason using ' ID 0 x % 02 x , % s , % s '
and in my opinion correctly set parameters .
*/
2008-07-25 13:36:58 +00:00
if ( is_assoc_request ) {
2014-10-02 21:47:19 +00:00
if ( pctx_abss_desc = = NULL ) {
2016-11-21 03:46:10 +00:00
buf_desc = pctx_abss_uid ;
2014-10-02 21:47:19 +00:00
}
else {
2016-11-21 03:46:10 +00:00
buf_desc = wmem_strdup_printf ( wmem_packet_scope ( ) , " %s (%s) " , pctx_abss_desc , pctx_abss_uid ) ;
2014-10-02 21:47:19 +00:00
}
2008-07-25 13:20:18 +00:00
}
else
{
2014-10-02 21:47:19 +00:00
if ( pctx_result = = 0 ) {
/* Accepted */
2016-11-21 03:46:10 +00:00
buf_desc = wmem_strdup_printf ( wmem_packet_scope ( ) , " ID 0x%02x, %s, %s, %s " ,
2014-10-02 21:47:19 +00:00
pctx_id , pctx_result_desc ,
dcm_uid_or_desc ( pctx - > xfer_uid , pctx - > xfer_desc ) ,
dcm_uid_or_desc ( pctx - > abss_uid , pctx - > abss_desc ) ) ;
}
else {
/* Rejected */
2016-11-21 03:46:10 +00:00
buf_desc = wmem_strdup_printf ( wmem_packet_scope ( ) , " ID 0x%02x, %s, %s " ,
2014-10-02 21:47:19 +00:00
pctx_id , pctx_result_desc ,
dcm_uid_or_desc ( pctx - > abss_uid , pctx - > abss_desc ) ) ;
}
2008-07-25 13:20:18 +00:00
}
proto_item_append_text ( pctx_pitem , " %s " , buf_desc ) ;
}
2018-03-05 10:54:55 +00:00
/*
Decode the user info item in a Association Request or Response
*/
2008-07-25 13:20:18 +00:00
static void
2010-03-19 20:24:06 +00:00
dissect_dcm_userinfo ( tvbuff_t * tvb , proto_tree * tree , guint32 offset , guint32 len , const gchar * pitem_prefix )
2008-07-25 13:20:18 +00:00
{
2018-03-05 10:54:55 +00:00
2008-07-25 13:20:18 +00:00
proto_item * userinfo_pitem = NULL ;
2014-10-02 21:47:19 +00:00
proto_tree * userinfo_ptree = NULL ; /* Tree for presentation context details */
2008-07-25 13:20:18 +00:00
guint8 item_type ;
guint16 item_len ;
2008-07-25 13:36:58 +00:00
gboolean first_item = TRUE ;
2008-07-25 13:20:18 +00:00
2008-07-25 22:58:05 +00:00
gchar * info_max_pdu = NULL ;
gchar * info_impl_uid = NULL ;
gchar * info_impl_version = NULL ;
2010-03-19 20:24:06 +00:00
const gchar * dummy = NULL ;
2008-07-25 13:20:18 +00:00
2008-10-11 14:25:02 +00:00
guint32 endpos ;
2008-07-25 13:20:18 +00:00
2008-10-11 14:25:02 +00:00
endpos = offset + len ;
2008-07-25 13:20:18 +00:00
item_type = tvb_get_guint8 ( tvb , offset - 4 ) ;
item_len = tvb_get_ntohs ( tvb , offset - 2 ) ;
2013-02-06 13:33:31 +00:00
userinfo_pitem = proto_tree_add_item ( tree , hf_dcm_info , tvb , offset - 4 , item_len + 4 , ENC_NA ) ;
proto_item_set_text ( userinfo_pitem , " %s " , pitem_prefix ) ;
2008-07-25 13:36:58 +00:00
userinfo_ptree = proto_item_add_subtree ( userinfo_pitem , ett_assoc_info ) ;
2008-07-25 13:20:18 +00:00
2018-03-05 10:54:55 +00:00
proto_tree_add_uint ( userinfo_ptree , hf_dcm_assoc_item_type , tvb , offset - 4 , 1 , item_type ) ; /* The type is only one byte long */
proto_tree_add_uint ( userinfo_ptree , hf_dcm_assoc_item_len , tvb , offset - 2 , 2 , item_len ) ;
2008-07-25 13:20:18 +00:00
2008-10-11 14:25:02 +00:00
while ( offset < endpos ) {
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
item_type = tvb_get_guint8 ( tvb , offset ) ;
item_len = tvb_get_ntohs ( tvb , 2 + offset ) ;
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
offset + = 4 ;
switch ( item_type ) {
case 0x51 : /* Max length */
2008-07-25 13:36:58 +00:00
2014-10-02 21:47:19 +00:00
dissect_dcm_assoc_item ( tvb , userinfo_ptree , offset - 4 ,
" Max PDU Length: " , DCM_ITEM_VALUE_TYPE_UINT32 , & info_max_pdu , & dummy ,
& hf_dcm_assoc_item_type , & hf_dcm_assoc_item_len , & hf_dcm_pdu_maxlen , ett_assoc_info_uid ) ;
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
if ( ! first_item ) {
proto_item_append_text ( userinfo_pitem , " , " ) ;
}
proto_item_append_text ( userinfo_pitem , " Max PDU Length %s " , info_max_pdu ) ;
first_item = FALSE ;
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
offset + = item_len ;
break ;
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
case 0x52 : /* UID */
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
/* Parse Item. Works also in info mode where dcm_pctx_tree is NULL */
dissect_dcm_assoc_item ( tvb , userinfo_ptree , offset - 4 ,
" Implementation UID: " , DCM_ITEM_VALUE_TYPE_STRING , & info_impl_uid , & dummy ,
& hf_dcm_assoc_item_type , & hf_dcm_assoc_item_len , & hf_dcm_info_uid , ett_assoc_info_uid ) ;
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
if ( ! first_item ) {
proto_item_append_text ( userinfo_pitem , " , " ) ;
}
proto_item_append_text ( userinfo_pitem , " Implementation UID %s " , info_impl_uid ) ;
first_item = FALSE ;
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
offset + = item_len ;
break ;
2008-07-25 13:36:58 +00:00
2014-10-02 21:47:19 +00:00
case 0x55 : /* version */
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
dissect_dcm_assoc_item ( tvb , userinfo_ptree , offset - 4 ,
" Implementation Version: " , DCM_ITEM_VALUE_TYPE_STRING , & info_impl_version , & dummy ,
& hf_dcm_assoc_item_type , & hf_dcm_assoc_item_len , & hf_dcm_info_version , ett_assoc_info_version ) ;
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
if ( ! first_item ) {
proto_item_append_text ( userinfo_pitem , " , " ) ;
}
proto_item_append_text ( userinfo_pitem , " Version %s " , info_impl_version ) ;
first_item = FALSE ;
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
offset + = item_len ;
break ;
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
case 0x53 : /* async negotiation */
2013-10-13 19:56:52 +00:00
2014-10-02 21:47:19 +00:00
dissect_dcm_assoc_async_negotiation ( tvb , userinfo_ptree , offset - 4 ) ;
2013-10-13 19:56:52 +00:00
2014-10-02 21:47:19 +00:00
offset + = item_len ;
break ;
2008-07-25 13:20:18 +00:00
2018-03-05 10:54:55 +00:00
case 0x54 : /* scp/scu role selection */
2013-10-13 19:56:52 +00:00
2014-10-02 21:47:19 +00:00
dissect_dcm_assoc_role_selection ( tvb , userinfo_ptree , offset - 4 ) ;
2013-10-13 19:56:52 +00:00
2014-10-02 21:47:19 +00:00
offset + = item_len ;
break ;
2013-10-13 19:56:52 +00:00
2014-10-02 21:47:19 +00:00
case 0x56 : /* extended negotiation */
2013-02-06 13:33:31 +00:00
2014-10-02 21:47:19 +00:00
dissect_dcm_assoc_sopclass_extneg ( tvb , userinfo_ptree , offset - 4 ) ;
2013-02-06 13:33:31 +00:00
2014-10-02 21:47:19 +00:00
offset + = item_len ;
break ;
2013-02-06 13:33:31 +00:00
2017-07-19 13:00:22 +00:00
case 0x58 : /* User Identify */
dissect_dcm_assoc_user_identify ( tvb , userinfo_ptree , offset - 4 ) ;
offset + = item_len ;
break ;
2014-10-02 21:47:19 +00:00
default :
2017-07-19 11:47:03 +00:00
dissect_dcm_assoc_unknown ( tvb , userinfo_ptree , offset - 4 ) ;
2014-10-02 21:47:19 +00:00
offset + = item_len ;
break ;
}
2004-05-08 08:49:02 +00:00
}
}
2008-07-25 13:20:18 +00:00
2018-03-05 10:54:55 +00:00
/*
Create a subtree for association requests or responses
*/
2008-10-11 14:25:02 +00:00
static guint32
2010-08-09 19:28:09 +00:00
dissect_dcm_assoc_detail ( tvbuff_t * tvb , packet_info * pinfo , proto_item * ti ,
2014-10-02 21:47:19 +00:00
dcm_state_assoc_t * assoc , guint32 offset , guint32 len )
2008-07-25 13:20:18 +00:00
{
2014-10-02 21:47:19 +00:00
proto_tree * assoc_tree = NULL ; /* Tree for PDU details */
2008-07-25 13:20:18 +00:00
guint8 item_type ;
guint16 item_len ;
2008-10-11 14:25:02 +00:00
guint32 endpos ;
2008-07-25 13:20:18 +00:00
2008-10-11 14:25:02 +00:00
gchar * item_value = NULL ;
2010-03-19 20:24:06 +00:00
const gchar * item_description = NULL ;
2008-07-25 13:20:18 +00:00
2008-10-11 14:25:02 +00:00
endpos = offset + len ;
2008-07-25 13:20:18 +00:00
2010-08-09 19:28:09 +00:00
assoc_tree = proto_item_add_subtree ( ti , ett_assoc ) ;
while ( offset < endpos ) {
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
item_type = tvb_get_guint8 ( tvb , offset ) ;
item_len = tvb_get_ntohs ( tvb , 2 + offset ) ;
if ( item_len = = 0 ) {
expert_add_info ( pinfo , ti , & ei_dcm_assoc_item_len ) ;
return endpos ;
}
offset + = 4 ;
switch ( item_type ) {
case 0x10 : /* Application context */
dissect_dcm_assoc_item ( tvb , assoc_tree , offset - 4 ,
" Application Context: " , DCM_ITEM_VALUE_TYPE_UID , & item_value , & item_description ,
& hf_dcm_assoc_item_type , & hf_dcm_assoc_item_len , & hf_dcm_actx , ett_assoc_actx ) ;
offset + = item_len ;
break ;
case 0x20 : /* Presentation context request */
2018-03-05 10:54:55 +00:00
dissect_dcm_pctx ( tvb , pinfo , assoc_tree , assoc , offset , item_len , " Presentation Context: " , TRUE ) ;
2014-10-02 21:47:19 +00:00
offset + = item_len ;
break ;
case 0x21 : /* Presentation context reply */
2018-03-05 10:54:55 +00:00
dissect_dcm_pctx ( tvb , pinfo , assoc_tree , assoc , offset , item_len , " Presentation Context: " , FALSE ) ;
2014-10-02 21:47:19 +00:00
offset + = item_len ;
break ;
case 0x50 : /* User Info */
dissect_dcm_userinfo ( tvb , assoc_tree , offset , item_len , " User Info: " ) ;
offset + = item_len ;
break ;
default :
offset + = item_len ;
break ;
}
2008-07-25 13:20:18 +00:00
}
2010-08-09 19:28:09 +00:00
2008-07-25 13:20:18 +00:00
return offset ;
}
2008-10-11 14:25:02 +00:00
static guint32
2008-07-25 13:36:58 +00:00
dissect_dcm_pdv_header ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree ,
2014-10-02 21:47:19 +00:00
dcm_state_assoc_t * assoc , guint32 offset , dcm_state_pdv_t * * pdv )
2004-05-08 08:49:02 +00:00
{
2011-12-27 17:34:01 +00:00
/* Dissect Context and Flags of a PDV and create new PDV structure */
2004-05-08 08:49:02 +00:00
2008-07-25 13:36:58 +00:00
proto_item * pdv_ctx_pitem = NULL ;
proto_item * pdv_flags_pitem = NULL ;
2004-05-08 08:49:02 +00:00
2014-10-02 21:47:19 +00:00
dcm_state_pctx_t * pctx = NULL ;
dcm_state_pdv_t * pdv_first_data = NULL ;
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
const gchar * desc_flag = NULL ; /* Flag Description in tree */
gchar * desc_header = NULL ; /* Used for PDV description */
2008-07-25 13:20:18 +00:00
2016-01-18 05:30:51 +00:00
guint8 flags = 0 , o_flags = 0 ;
2008-07-25 13:36:58 +00:00
guint8 pctx_id = 0 ;
2008-07-25 13:20:18 +00:00
2008-07-25 13:36:58 +00:00
/* 1 Byte Context */
pctx_id = tvb_get_guint8 ( tvb , offset ) ;
pctx = dcm_state_pctx_get ( assoc , pctx_id , FALSE ) ;
if ( pctx & & pctx - > xfer_uid ) {
2014-10-02 21:47:19 +00:00
proto_tree_add_uint_format ( tree , hf_dcm_pdv_ctx , tvb , offset , 1 ,
pctx_id , " Context: 0x%02x (%s, %s) " , pctx_id ,
dcm_uid_or_desc ( pctx - > xfer_uid , pctx - > xfer_desc ) ,
dcm_uid_or_desc ( pctx - > abss_uid , pctx - > abss_desc ) ) ;
2008-07-25 13:36:58 +00:00
}
else {
2014-10-02 21:47:19 +00:00
pdv_ctx_pitem = proto_tree_add_uint_format ( tree , hf_dcm_pdv_ctx , tvb , offset , 1 ,
pctx_id , " Context: 0x%02x not found. A-ASSOCIATE request not found in capture. " , pctx_id ) ;
2008-07-25 15:42:46 +00:00
2014-10-02 21:47:19 +00:00
expert_add_info ( pinfo , pdv_ctx_pitem , & ei_dcm_pdv_ctx ) ;
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
if ( pctx = = NULL ) {
/* only create presentation context, if it does not yet exist */
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
/* Create fake PCTX and guess Syntax ILE, ELE, EBE */
pctx = dcm_state_pctx_new ( assoc , pctx_id ) ;
2010-05-14 21:54:48 +00:00
2014-10-02 21:47:19 +00:00
/* To be done: Guess Syntax */
pctx - > syntax = DCM_UNK ;
}
2008-07-25 13:20:18 +00:00
}
2008-07-25 13:36:58 +00:00
offset + = 1 ;
2008-07-25 13:20:18 +00:00
2008-07-25 13:36:58 +00:00
/* Create PDV structure:
2008-07-25 13:20:18 +00:00
2008-07-25 13:36:58 +00:00
Since we can have multiple PDV per packet ( offset ) and
2011-05-27 01:57:33 +00:00
multiple merged packets per PDV ( the tvb raw_offset )
2008-07-25 13:36:58 +00:00
we need both values to uniquely identify a PDV
*/
2008-07-25 13:20:18 +00:00
2016-01-24 03:40:51 +00:00
* pdv = dcm_state_pdv_get ( pctx , pinfo - > num , tvb_raw_offset ( tvb ) + offset , TRUE ) ;
2008-10-11 14:25:02 +00:00
if ( * pdv = = NULL ) {
2014-10-02 21:47:19 +00:00
return 0 ; /* Failed to allocate memory */
2008-07-25 13:36:58 +00:00
}
2008-07-25 13:20:18 +00:00
2008-07-25 13:36:58 +00:00
/* 1 Byte Flag */
2016-01-18 05:30:51 +00:00
/* PS3.8 E.2 Bits 2 through 7 are always set to 0 by the sender and never checked by the receiver. */
o_flags = tvb_get_guint8 ( tvb , offset ) ;
flags = 0x3 & o_flags ;
2008-07-25 13:20:18 +00:00
2010-08-09 19:28:09 +00:00
( * pdv ) - > pctx_id = pctx_id ;
2008-07-25 15:42:46 +00:00
2008-07-25 13:36:58 +00:00
switch ( flags ) {
2014-10-02 21:47:19 +00:00
case 0 : /* 00 */
2016-01-18 05:30:51 +00:00
if ( 0 ! = ( 0xfc & o_flags ) )
desc_flag = " Data, More Fragments (Warning: Invalid) " ;
else
desc_flag = " Data, More Fragments " ;
2014-10-02 21:47:19 +00:00
( * pdv ) - > is_flagvalid = TRUE ;
( * pdv ) - > is_command = FALSE ;
( * pdv ) - > is_last_fragment = FALSE ;
( * pdv ) - > syntax = pctx - > syntax ; /* Inherit syntax for data PDVs*/
break ;
case 2 : /* 10 */
2016-01-18 05:30:51 +00:00
if ( 0 ! = ( 0xfc & o_flags ) )
desc_flag = " Data, Last Fragment (Warning: Invalid) " ;
else
desc_flag = " Data, Last Fragment " ;
2014-10-02 21:47:19 +00:00
( * pdv ) - > is_flagvalid = TRUE ;
( * pdv ) - > is_command = FALSE ;
( * pdv ) - > is_last_fragment = TRUE ;
( * pdv ) - > syntax = pctx - > syntax ; /* Inherit syntax for data PDVs*/
break ;
case 1 : /* 01 */
2016-01-18 05:30:51 +00:00
if ( 0 ! = ( 0xfc & o_flags ) )
desc_flag = " Command, More Fragments (Warning: Invalid) " ;
else
desc_flag = " Command, More Fragments " ;
2016-11-21 03:46:10 +00:00
desc_header = wmem_strdup ( wmem_file_scope ( ) , " Command " ) ; /* Will be overwritten with real command tag */
2014-10-02 21:47:19 +00:00
( * pdv ) - > is_flagvalid = TRUE ;
( * pdv ) - > is_command = TRUE ;
( * pdv ) - > is_last_fragment = FALSE ;
( * pdv ) - > syntax = DCM_ILE ; /* Command tags are always little endian*/
break ;
case 3 : /* 11 */
2016-01-18 05:30:51 +00:00
if ( 0 ! = ( 0xfc & o_flags ) )
desc_flag = " Command, Last Fragment (Warning: Invalid) " ;
else
desc_flag = " Command, Last Fragment " ;
2016-11-21 03:46:10 +00:00
desc_header = wmem_strdup ( wmem_file_scope ( ) , " Command " ) ;
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
( * pdv ) - > is_flagvalid = TRUE ;
( * pdv ) - > is_command = TRUE ;
( * pdv ) - > is_last_fragment = TRUE ;
( * pdv ) - > syntax = DCM_ILE ; /* Command tags are always little endian*/
break ;
2008-07-25 13:36:58 +00:00
default :
2014-10-02 21:47:19 +00:00
desc_flag = " Invalid Flags " ;
2016-11-21 03:46:10 +00:00
desc_header = wmem_strdup ( wmem_file_scope ( ) , desc_flag ) ;
2008-07-25 13:36:58 +00:00
2014-10-02 21:47:19 +00:00
( * pdv ) - > is_flagvalid = FALSE ;
( * pdv ) - > is_command = FALSE ;
( * pdv ) - > is_last_fragment = FALSE ;
( * pdv ) - > syntax = DCM_UNK ;
2008-07-25 13:20:18 +00:00
}
2008-07-25 13:36:58 +00:00
2020-08-19 14:15:33 +00:00
if ( ! PINFO_FD_VISITED ( pinfo ) ) {
( * pdv ) - > reassembly_id = pctx - > reassembly_count ;
if ( ( * pdv ) - > is_last_fragment ) {
pctx - > reassembly_count + + ;
}
}
2008-07-25 13:36:58 +00:00
if ( flags = = 0 | | flags = = 2 ) {
2014-10-02 21:47:19 +00:00
/* Data PDV */
pdv_first_data = dcm_state_pdv_get_obj_start ( * pdv ) ;
if ( pdv_first_data - > prev & & pdv_first_data - > prev - > is_command ) {
/* Every Data PDV sequence should be preceded by a Command PDV,
so we should always hit this for a correct capture
*/
if ( pctx - > abss_desc & & g_str_has_suffix ( pctx - > abss_desc , " Storage " ) ) {
/* Should be done far more intelligent, e.g. does not catch the (Retired) ones */
if ( flags = = 0 ) {
2016-11-21 03:46:10 +00:00
desc_header = wmem_strdup_printf ( wmem_file_scope ( ) , " %s Fragment " , pctx - > abss_desc ) ;
2014-10-02 21:47:19 +00:00
}
else {
2016-11-21 03:46:10 +00:00
desc_header = wmem_strdup ( wmem_file_scope ( ) , pctx - > abss_desc ) ;
2014-10-02 21:47:19 +00:00
}
( * pdv ) - > is_storage = TRUE ;
}
else {
/* Use previous command and append DATA*/
2016-11-21 03:46:10 +00:00
desc_header = wmem_strdup_printf ( wmem_file_scope ( ) , " %s-DATA " , pdv_first_data - > prev - > desc ) ;
2014-10-02 21:47:19 +00:00
}
}
else {
2016-11-21 03:46:10 +00:00
desc_header = wmem_strdup ( wmem_file_scope ( ) , " DATA " ) ;
2014-10-02 21:47:19 +00:00
}
2008-07-25 13:20:18 +00:00
}
2008-07-25 13:36:58 +00:00
( * pdv ) - > desc = desc_header ;
pdv_flags_pitem = proto_tree_add_uint_format ( tree , hf_dcm_pdv_flags , tvb , offset , 1 ,
2016-01-18 05:30:51 +00:00
flags , " Flags: 0x%02x (%s) " , o_flags , desc_flag ) ;
2008-07-25 13:20:18 +00:00
2016-01-18 05:30:51 +00:00
if ( o_flags > 3 ) {
2014-10-02 21:47:19 +00:00
expert_add_info ( pinfo , pdv_flags_pitem , & ei_dcm_pdv_flags ) ;
2008-07-25 13:36:58 +00:00
}
2008-07-25 13:20:18 +00:00
offset + = 1 ;
2008-07-25 13:36:58 +00:00
return offset ;
}
2008-07-25 13:20:18 +00:00
2019-02-11 11:27:19 +00:00
/*
Based on the value representation , decode the value of one tag .
Support VM > 1 for most types , but not all . Returns new offset
*/
2008-10-11 14:25:02 +00:00
static guint32
2009-05-18 06:21:22 +00:00
dissect_dcm_tag_value ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree , dcm_state_pdv_t * pdv ,
2014-10-02 21:47:19 +00:00
guint32 offset , guint16 grp , guint16 elm ,
guint32 vl , guint32 vl_max , const gchar * vr , gchar * * tag_value )
2008-07-25 13:36:58 +00:00
{
2009-05-18 06:21:22 +00:00
proto_item * pitem = NULL ;
2016-11-20 22:38:14 +00:00
guint encoding = ( pdv - > syntax = = DCM_EBE ) ? ENC_BIG_ENDIAN : ENC_LITTLE_ENDIAN ;
2008-07-25 13:36:58 +00:00
2018-05-28 02:42:35 +00:00
/* Make sure we have all the bytes of the item; this should throw
and exception if vl_max is so large that it causes the offset
to overflow . */
tvb_ensure_bytes_exist ( tvb , offset , vl_max ) ;
2008-10-11 14:25:02 +00:00
/* ---------------------------------------------------------------------------
Potentially long types . Obey vl_max
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
2008-07-25 13:36:58 +00:00
2008-10-11 14:25:02 +00:00
if ( ( strncmp ( vr , " AE " , 2 ) = = 0 ) | | ( strncmp ( vr , " AS " , 2 ) = = 0 ) | | ( strncmp ( vr , " CS " , 2 ) = = 0 ) | |
2014-10-02 21:47:19 +00:00
( strncmp ( vr , " DA " , 2 ) = = 0 ) | | ( strncmp ( vr , " DS " , 2 ) = = 0 ) | | ( strncmp ( vr , " DT " , 2 ) = = 0 ) | |
( strncmp ( vr , " IS " , 2 ) = = 0 ) | | ( strncmp ( vr , " LO " , 2 ) = = 0 ) | | ( strncmp ( vr , " LT " , 2 ) = = 0 ) | |
( strncmp ( vr , " PN " , 2 ) = = 0 ) | | ( strncmp ( vr , " SH " , 2 ) = = 0 ) | | ( strncmp ( vr , " ST " , 2 ) = = 0 ) | |
( strncmp ( vr , " TM " , 2 ) = = 0 ) | | ( strncmp ( vr , " UI " , 2 ) = = 0 ) | | ( strncmp ( vr , " UT " , 2 ) = = 0 ) ) {
2018-03-05 10:54:55 +00:00
/*
15 ways to represent a string .
For LT , ST , UT the DICOM standard does not allow multi - value
For the others , VM is built into ' automatically , because it uses ' \ ' as separator
*/
2014-10-02 21:47:19 +00:00
gchar * vals ;
dcm_uid_t * uid = NULL ;
guint8 val8 ;
val8 = tvb_get_guint8 ( tvb , offset + vl_max - 1 ) ;
if ( val8 = = 0x00 ) {
/* Last byte of string is 0x00, i.e. padded */
vals = tvb_format_text ( tvb , offset , vl_max - 1 ) ;
}
else {
vals = tvb_format_text ( tvb , offset , vl_max ) ;
}
if ( ( strncmp ( vr , " UI " , 2 ) = = 0 ) ) {
/* This is a UID. Attempt a lookup. Will only return something for classes of course */
2017-02-25 00:46:49 +00:00
uid = ( dcm_uid_t * ) wmem_map_lookup ( dcm_uid_table , ( gpointer ) vals ) ;
2014-10-02 21:47:19 +00:00
if ( uid ) {
2016-11-21 03:46:10 +00:00
* tag_value = wmem_strdup_printf ( wmem_packet_scope ( ) , " %s (%s) " , vals , uid - > name ) ;
2014-10-02 21:47:19 +00:00
}
else {
2016-11-21 03:46:10 +00:00
* tag_value = vals ;
2014-10-02 21:47:19 +00:00
}
}
else {
if ( strlen ( vals ) > 50 ) {
2016-11-21 03:46:10 +00:00
* tag_value = wmem_strdup_printf ( wmem_packet_scope ( ) , " %-50.50s... " , vals ) ;
2014-10-02 21:47:19 +00:00
}
else {
2016-11-21 03:46:10 +00:00
* tag_value = vals ;
2014-10-02 21:47:19 +00:00
}
}
2016-11-20 22:38:14 +00:00
proto_tree_add_string ( tree , hf_dcm_tag_value_str , tvb , offset , vl_max , * tag_value ) ;
2014-10-02 21:47:19 +00:00
if ( grp = = 0x0000 & & elm = = 0x0902 ) {
/* The error comment */
pdv - > comment = wmem_strdup ( wmem_file_scope ( ) , g_strstrip ( vals ) ) ;
}
2008-10-11 14:25:02 +00:00
}
2018-03-05 10:54:55 +00:00
else if ( ( strncmp ( vr , " OB " , 2 ) = = 0 ) | | ( strncmp ( vr , " OW " , 2 ) = = 0 ) | |
( strncmp ( vr , " OF " , 2 ) = = 0 ) | | ( strncmp ( vr , " OD " , 2 ) = = 0 ) ) {
2008-07-25 13:36:58 +00:00
2018-03-05 10:54:55 +00:00
/* Array of Bytes, Words, Float, or Doubles. Don't perform any decoding. VM=1. Multiple arrays are not possible */
proto_tree_add_bytes_format_value ( tree , hf_dcm_tag_value_byte , tvb , offset , vl_max , NULL , " %s " , " (binary) " ) ;
2008-07-25 13:36:58 +00:00
2016-11-21 03:46:10 +00:00
* tag_value = wmem_strdup ( wmem_packet_scope ( ) , " (binary) " ) ;
2008-10-11 14:25:02 +00:00
}
else if ( strncmp ( vr , " UN " , 2 ) = = 0 ) {
2018-03-05 10:54:55 +00:00
/* Usually the case for private tags in implicit syntax, since tag was not found and VR not specified.
Not been able to create UN yet . No need to support VM > 1.
*/
2014-10-02 21:47:19 +00:00
guint8 val8 ;
gchar * vals ;
guint32 i ;
/* String detector, i.e. check if we only have alpha-numeric character */
gboolean is_string = TRUE ;
gboolean is_padded = FALSE ;
for ( i = 0 ; i < vl_max ; i + + ) {
val8 = tvb_get_guint8 ( tvb , offset + i ) ;
if ( ( val8 = = 0x09 ) | | ( val8 = = 0x0A ) | | ( val8 = = 0x0D ) ) {
/* TAB, LF, CR */
}
else if ( ( val8 > = 0x20 ) & & ( val8 < = 0x7E ) ) {
/* No extended ASCII, 0-9, A-Z, a-z */
}
else if ( ( i = = vl_max - 1 ) & & ( val8 = = 0x00 ) ) {
/* Last Byte can be null*/
is_padded = TRUE ;
}
else {
/* Here's the code */
is_string = FALSE ;
}
}
if ( is_string ) {
vals = tvb_format_text ( tvb , offset , ( is_padded ? vl_max - 1 : vl_max ) ) ;
2016-11-20 22:38:14 +00:00
proto_tree_add_string ( tree , hf_dcm_tag_value_str , tvb , offset , vl_max , vals ) ;
2014-10-02 21:47:19 +00:00
2016-11-21 03:46:10 +00:00
* tag_value = vals ;
2014-10-02 21:47:19 +00:00
}
else {
2018-03-05 10:54:55 +00:00
proto_tree_add_bytes_format_value ( tree , hf_dcm_tag_value_byte , tvb , offset , vl_max , NULL , " %s " , " (binary) " ) ;
2014-10-02 21:47:19 +00:00
2016-11-21 03:46:10 +00:00
* tag_value = wmem_strdup ( wmem_packet_scope ( ) , " (binary) " ) ;
2014-10-02 21:47:19 +00:00
}
2008-07-25 13:20:18 +00:00
}
2008-10-11 14:25:02 +00:00
/* ---------------------------------------------------------------------------
2008-12-18 19:08:49 +00:00
Smaller types . vl / vl_max are not used . Fixed item length from 2 to 8 bytes
2008-10-11 14:25:02 +00:00
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
2018-03-05 10:54:55 +00:00
else if ( strncmp ( vr , " AT " , 2 ) = = 0 ) {
/* Attribute Tag e.g. (0022,8866). 2*2 Bytes, Can have VM > 1 */
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
guint16 at_grp ;
guint16 at_elm ;
2016-11-21 03:46:10 +00:00
gchar * at_value = " " ;
2008-07-25 13:20:18 +00:00
2018-03-05 10:54:55 +00:00
/* In on capture the reported length for this tag was 2 bytes. And since vl_max is unsigned long, -3 caused it to be 2^32-1
So make it at least one loop so set it to at least 4.
*/
guint32 vm_item_len = 4 ;
guint32 vm_item_count = dcm_vm_item_count ( vl_max , vm_item_len ) ;
guint32 i = 0 ;
while ( i < vm_item_count ) {
at_grp = tvb_get_guint16 ( tvb , offset + i * vm_item_len , encoding ) ;
at_elm = tvb_get_guint16 ( tvb , offset + i * vm_item_len + 2 , encoding ) ;
2008-07-25 13:20:18 +00:00
2018-03-05 10:54:55 +00:00
proto_tree_add_uint_format_value ( tree , hf_dcm_tag_value_32u , tvb , offset + i * vm_item_len , vm_item_len ,
2016-11-20 22:38:14 +00:00
( at_grp < < 16 ) | at_elm , " %04x,%04x " , at_grp , at_elm ) ;
2008-07-25 13:20:18 +00:00
2016-11-14 23:14:51 +00:00
at_value = wmem_strdup_printf ( wmem_packet_scope ( ) , " %s(%04x,%04x) " , at_value , at_grp , at_elm ) ;
2018-03-05 10:54:55 +00:00
i + + ;
2016-11-14 23:14:51 +00:00
}
2016-11-21 03:46:10 +00:00
* tag_value = at_value ;
2008-10-11 14:25:02 +00:00
}
2018-03-05 10:54:55 +00:00
else if ( strncmp ( vr , " FL " , 2 ) = = 0 ) { /* Single Float. Can be VM > 1, but not yet supported */
2008-10-11 14:25:02 +00:00
2016-11-20 22:38:14 +00:00
gfloat valf = tvb_get_ieee_float ( tvb , offset , encoding ) ;
2008-10-11 14:25:02 +00:00
2018-03-05 10:54:55 +00:00
proto_tree_add_bytes_format_value ( tree , hf_dcm_tag_value_byte , tvb , offset , 4 , NULL , " %f " , valf ) ;
2008-10-11 14:25:02 +00:00
2016-11-21 03:46:10 +00:00
* tag_value = wmem_strdup_printf ( wmem_packet_scope ( ) , " %f " , valf ) ;
2008-10-11 14:25:02 +00:00
}
2018-03-05 10:54:55 +00:00
else if ( strncmp ( vr , " FD " , 2 ) = = 0 ) { /* Double Float. Can be VM > 1, but not yet supported */
2008-10-11 14:25:02 +00:00
2016-11-20 22:38:14 +00:00
gdouble vald = tvb_get_ieee_double ( tvb , offset , encoding ) ;
2008-10-11 14:25:02 +00:00
2018-03-05 10:54:55 +00:00
proto_tree_add_bytes_format_value ( tree , hf_dcm_tag_value_byte , tvb , offset , 8 , NULL , " %f " , vald ) ;
2010-05-14 21:54:48 +00:00
2016-11-21 03:46:10 +00:00
* tag_value = wmem_strdup_printf ( wmem_packet_scope ( ) , " %f " , vald ) ;
2008-10-11 14:25:02 +00:00
}
2018-03-05 10:54:55 +00:00
else if ( strncmp ( vr , " SL " , 2 ) = = 0 ) { /* Signed Long. Can be VM > 1, but not yet supported */
2014-10-02 21:47:19 +00:00
gint32 val32 ;
2008-10-11 14:25:02 +00:00
2016-11-20 22:38:14 +00:00
proto_tree_add_item_ret_int ( tree , hf_dcm_tag_value_32s , tvb , offset , 4 , encoding , & val32 ) ;
2008-10-11 14:25:02 +00:00
2016-11-21 03:46:10 +00:00
* tag_value = wmem_strdup_printf ( wmem_packet_scope ( ) , " %d " , val32 ) ;
2008-10-11 14:25:02 +00:00
}
2018-03-05 10:54:55 +00:00
else if ( strncmp ( vr , " SS " , 2 ) = = 0 ) { /* Signed Short. Can be VM > 1, but not yet supported */
2016-11-20 22:38:14 +00:00
gint32 val32 ;
2008-10-11 14:25:02 +00:00
2016-11-20 22:38:14 +00:00
proto_tree_add_item_ret_int ( tree , hf_dcm_tag_value_16s , tvb , offset , 2 , encoding , & val32 ) ;
2008-10-11 14:25:02 +00:00
2016-11-21 03:46:10 +00:00
* tag_value = wmem_strdup_printf ( wmem_packet_scope ( ) , " %d " , val32 ) ;
2008-10-11 14:25:02 +00:00
}
2018-03-05 10:54:55 +00:00
else if ( strncmp ( vr , " UL " , 2 ) = = 0 ) { /* Unsigned Long. Can be VM > 1, but not yet supported */
2014-10-02 21:47:19 +00:00
guint32 val32 ;
2008-10-11 14:25:02 +00:00
2016-11-20 22:38:14 +00:00
proto_tree_add_item_ret_uint ( tree , hf_dcm_tag_value_32u , tvb , offset , 4 , encoding , & val32 ) ;
2008-10-11 14:25:02 +00:00
2016-11-21 03:46:10 +00:00
* tag_value = wmem_strdup_printf ( wmem_packet_scope ( ) , " %u " , val32 ) ;
2008-10-11 14:25:02 +00:00
}
2018-03-05 10:54:55 +00:00
else if ( strncmp ( vr , " US " , 2 ) = = 0 ) { /* Unsigned Short. Can be VM > 1, but not yet supported */
2014-10-02 21:47:19 +00:00
const gchar * status_message = NULL ;
2016-11-20 22:38:14 +00:00
guint16 val16 = tvb_get_guint16 ( tvb , offset , encoding ) ;
2014-10-02 21:47:19 +00:00
if ( grp = = 0x0000 & & elm = = 0x0100 ) {
/* This is a command */
2016-11-21 03:46:10 +00:00
pdv - > command = wmem_strdup ( wmem_file_scope ( ) , val_to_str ( val16 , dcm_cmd_vals , " " ) ) ;
* tag_value = pdv - > command ;
2014-10-02 21:47:19 +00:00
}
else if ( grp = = 0x0000 & & elm = = 0x0900 ) {
/* This is a status message. If value is not 0x0000, add an expert info */
status_message = dcm_rsp2str ( val16 ) ;
2016-11-21 03:46:10 +00:00
* tag_value = wmem_strdup_printf ( wmem_packet_scope ( ) , " %s (0x%02x) " , status_message , val16 ) ;
2014-10-02 21:47:19 +00:00
2019-02-18 14:53:06 +00:00
if ( ( val16 & 0xFF00 ) = = 0xFF00 ) {
/* C-FIND also has a 0xFF01 as a valid response */
pdv - > is_pending = TRUE ;
}
else if ( val16 ! = 0x0000 ) {
/* Neither success nor pending */
2014-10-02 21:47:19 +00:00
pdv - > is_warning = TRUE ;
}
pdv - > status = wmem_strdup ( wmem_file_scope ( ) , status_message ) ;
}
else {
2016-11-21 03:46:10 +00:00
* tag_value = wmem_strdup_printf ( wmem_packet_scope ( ) , " %u " , val16 ) ;
2014-10-02 21:47:19 +00:00
}
if ( grp = = 0x0000 ) {
if ( elm = = 0x0110 ) { /* (0000,0110) Message ID */
pdv - > message_id = val16 ;
}
else if ( elm = = 0x0120 ) { /* (0000,0120) Message ID Being Responded To */
pdv - > message_id_resp = val16 ;
}
else if ( elm = = 0x1020 ) { /* (0000,1020) Number of Remaining Sub-operations */
pdv - > no_remaining = val16 ;
}
else if ( elm = = 0x1021 ) { /* (0000,1021) Number of Completed Sub-operations */
pdv - > no_completed = val16 ;
}
else if ( elm = = 0x1022 ) { /* (0000,1022) Number of Failed Sub-operations */
pdv - > no_failed = val16 ;
}
else if ( elm = = 0x1023 ) { /* (0000,1023) Number of Warning Sub-operations */
pdv - > no_warning = val16 ;
}
}
2016-11-20 22:38:14 +00:00
pitem = proto_tree_add_uint_format_value ( tree , hf_dcm_tag_value_16u , tvb , offset , 2 ,
val16 , " %s " , * tag_value ) ;
2014-10-02 21:47:19 +00:00
if ( pdv - > is_warning & & status_message ) {
expert_add_info ( pinfo , pitem , & ei_dcm_status_msg ) ;
}
2008-10-11 14:25:02 +00:00
}
/* Invalid VR, can only occur with Explicit syntax */
else {
2016-11-20 22:38:14 +00:00
proto_tree_add_bytes_format_value ( tree , hf_dcm_tag_value_byte , tvb , offset , vl_max ,
NULL , " %s " , ( vl > vl_max ? " " : " (unknown VR) " ) ) ;
2008-10-11 14:25:02 +00:00
2016-11-21 03:46:10 +00:00
* tag_value = wmem_strdup ( wmem_packet_scope ( ) , " (unknown VR) " ) ;
2008-10-11 14:25:02 +00:00
}
offset + = vl_max ;
return offset ;
}
2019-02-11 11:27:19 +00:00
/*
Return true , if the required size does not fit at position ' offset ' .
*/
2008-10-11 14:25:02 +00:00
static gboolean
dcm_tag_is_open ( dcm_state_pdv_t * pdv , guint32 startpos , guint32 offset , guint32 endpos , guint32 size_required )
{
if ( offset + size_required > endpos ) {
2014-10-02 21:47:19 +00:00
pdv - > open_tag . is_header_fragmented = TRUE ;
pdv - > open_tag . len_decoded = endpos - startpos ;
2008-10-11 14:25:02 +00:00
2014-10-02 21:47:19 +00:00
return TRUE ;
2008-10-11 14:25:02 +00:00
}
else {
2014-10-02 21:47:19 +00:00
return FALSE ;
2008-10-11 14:25:02 +00:00
}
}
2008-10-31 22:59:14 +00:00
static dcm_tag_t *
dcm_tag_lookup ( guint16 grp , guint16 elm )
{
static dcm_tag_t * tag_def = NULL ;
2014-10-02 21:47:19 +00:00
static dcm_tag_t tag_unknown = { 0x00000000 , " (unknown) " , " UN " , " 1 " , 0 , 0 } ;
static dcm_tag_t tag_private = { 0x00000000 , " Private Tag " , " UN " , " 1 " , 0 , 0 } ;
2008-10-31 22:59:14 +00:00
static dcm_tag_t tag_private_grp_len = { 0x00000000 , " Private Tag Group Length " , " UL " , " 1 " , 0 , 0 } ;
2014-10-02 21:47:19 +00:00
static dcm_tag_t tag_grp_length = { 0x00000000 , " Group Length " , " UL " , " 1 " , 0 , 0 } ;
2008-10-31 22:59:14 +00:00
/* Try a direct hit first before doing a masked search */
2017-02-25 00:46:49 +00:00
tag_def = ( dcm_tag_t * ) wmem_map_lookup ( dcm_tag_table , GUINT_TO_POINTER ( ( ( guint32 ) grp < < 16 ) | elm ) ) ;
2008-10-31 22:59:14 +00:00
if ( tag_def = = NULL ) {
2014-10-02 21:47:19 +00:00
/* No match found */
if ( ( grp & 0x0001 ) & & ( elm = = 0x0000 ) ) {
tag_def = & tag_private_grp_len ;
}
else if ( grp & 0x0001 ) {
tag_def = & tag_private ;
}
else if ( elm = = 0x0000 ) {
tag_def = & tag_grp_length ;
}
2008-10-31 22:59:14 +00:00
/* There are a few tags that require a mask to be found */
2014-10-02 21:47:19 +00:00
else if ( ( ( grp & 0xFF00 ) = = 0x5000 ) | | ( ( grp & 0xFF00 ) = = 0x6000 ) | | ( ( grp & 0xFF00 ) = = 0x7F00 ) ) {
/* Do a special for groups 0x50xx, 0x60xx and 0x7Fxx */
2017-02-25 00:46:49 +00:00
tag_def = ( dcm_tag_t * ) wmem_map_lookup ( dcm_tag_table , GUINT_TO_POINTER ( ( ( ( guint32 ) grp & 0xFF00 ) < < 16 ) | elm ) ) ;
2014-10-02 21:47:19 +00:00
}
else if ( ( grp = = 0x0020 ) & & ( ( elm & 0xFF00 ) = = 0x3100 ) ) {
2017-02-25 00:46:49 +00:00
tag_def = ( dcm_tag_t * ) wmem_map_lookup ( dcm_tag_table , GUINT_TO_POINTER ( ( ( guint32 ) grp < < 16 ) | ( elm & 0xFF00 ) ) ) ;
2014-10-02 21:47:19 +00:00
}
else if ( ( grp = = 0x0028 ) & & ( ( elm & 0xFF00 ) = = 0x0400 ) ) {
/* This map was done to 0x041x */
2017-02-25 00:46:49 +00:00
tag_def = ( dcm_tag_t * ) wmem_map_lookup ( dcm_tag_table , GUINT_TO_POINTER ( ( ( guint32 ) grp < < 16 ) | ( elm & 0xFF0F ) | 0x0010 ) ) ;
2014-10-02 21:47:19 +00:00
}
else if ( ( grp = = 0x0028 ) & & ( ( elm & 0xFF00 ) = = 0x0800 ) ) {
2017-02-25 00:46:49 +00:00
tag_def = ( dcm_tag_t * ) wmem_map_lookup ( dcm_tag_table , GUINT_TO_POINTER ( ( ( guint32 ) grp < < 16 ) | ( elm & 0xFF0F ) ) ) ;
2014-10-02 21:47:19 +00:00
}
else if ( grp = = 0x1000 ) {
2017-02-25 00:46:49 +00:00
tag_def = ( dcm_tag_t * ) wmem_map_lookup ( dcm_tag_table , GUINT_TO_POINTER ( ( ( guint32 ) grp < < 16 ) | ( elm & 0x000F ) ) ) ;
2014-10-02 21:47:19 +00:00
}
else if ( grp = = 0x1010 ) {
2017-02-25 00:46:49 +00:00
tag_def = ( dcm_tag_t * ) wmem_map_lookup ( dcm_tag_table , GUINT_TO_POINTER ( ( ( guint32 ) grp < < 16 ) | ( elm & 0x0000 ) ) ) ;
2014-10-02 21:47:19 +00:00
}
2008-10-31 22:59:14 +00:00
if ( tag_def = = NULL ) {
2014-10-02 21:47:19 +00:00
/* Still no match found */
tag_def = & tag_unknown ;
}
2008-10-31 22:59:14 +00:00
}
return tag_def ;
}
2008-10-11 14:25:02 +00:00
static gchar *
2010-03-19 20:24:06 +00:00
dcm_tag_summary ( guint16 grp , guint16 elm , guint32 vl , const gchar * tag_desc , const gchar * vr ,
2014-10-02 21:47:19 +00:00
gboolean is_retired , gboolean is_implicit )
2008-10-11 14:25:02 +00:00
{
2009-10-25 11:43:30 +00:00
gchar * desc_mod ;
gchar * tag_vl ;
gchar * tag_sum ;
2008-10-11 14:25:02 +00:00
if ( is_retired ) {
2014-10-02 21:47:19 +00:00
desc_mod = wmem_strdup_printf ( wmem_packet_scope ( ) , " (Retired) %-35.35s " , tag_desc ) ;
2008-10-11 14:25:02 +00:00
}
else {
2014-10-02 21:47:19 +00:00
desc_mod = wmem_strdup_printf ( wmem_packet_scope ( ) , " %-45.45s " , tag_desc ) ;
2008-10-11 14:25:02 +00:00
}
if ( vl = = 0xFFFFFFFF ) {
2014-10-02 21:47:19 +00:00
tag_vl = wmem_strdup_printf ( wmem_packet_scope ( ) , " %10.10s " , " <udef> " ) ;
2008-10-11 14:25:02 +00:00
}
else {
2014-10-02 21:47:19 +00:00
tag_vl = wmem_strdup_printf ( wmem_packet_scope ( ) , " %10u " , vl ) ; /* Show as dec */
2008-10-11 14:25:02 +00:00
}
2014-10-02 21:47:19 +00:00
if ( is_implicit ) tag_sum = wmem_strdup_printf ( wmem_packet_scope ( ) , " (%04x,%04x) %s %s " , grp , elm , tag_vl , desc_mod ) ;
else tag_sum = wmem_strdup_printf ( wmem_packet_scope ( ) , " (%04x,%04x) %s %s [%s] " , grp , elm , tag_vl , desc_mod , vr ) ;
2008-10-11 14:25:02 +00:00
return tag_sum ;
}
2018-03-05 10:54:55 +00:00
/*
Decode one tag . If it is a sequence or item start create a subtree . Returns new offset .
http : //dicom.nema.org/medical/dicom/current/output/chtml/part05/chapter_7.html
*/
2008-10-11 14:25:02 +00:00
static guint32
dissect_dcm_tag ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree ,
2014-10-02 21:47:19 +00:00
dcm_state_pdv_t * pdv , guint32 offset , guint32 endpos ,
gboolean is_first_tag , const gchar * * tag_description ,
gboolean * end_of_seq_or_item )
2008-10-11 14:25:02 +00:00
{
2018-03-05 10:54:55 +00:00
2008-10-11 14:25:02 +00:00
2014-10-02 21:47:19 +00:00
proto_tree * tag_ptree = NULL ; /* Tree for decoded tag details */
proto_tree * seq_ptree = NULL ; /* Possible subtree for sequences and items */
2008-10-11 14:25:02 +00:00
2010-03-19 20:24:06 +00:00
proto_item * tag_pitem = NULL ;
dcm_tag_t * tag_def = NULL ;
2008-10-11 14:25:02 +00:00
2016-01-14 16:47:06 +00:00
gint ett ;
2010-03-19 20:24:06 +00:00
const gchar * vr = NULL ;
2016-11-21 03:46:10 +00:00
gchar * tag_value = " " ; /* Tag Value converted to a string */
2010-03-19 20:24:06 +00:00
gchar * tag_summary ;
2008-10-11 14:25:02 +00:00
guint32 vl = 0 ;
guint16 vl_1 = 0 ;
guint16 vl_2 = 0 ;
2014-10-02 21:47:19 +00:00
guint32 offset_tag = 0 ; /* Remember offsets for tree, since the tree */
guint32 offset_vr = 0 ; /* header is created pretty late */
2008-10-11 14:25:02 +00:00
guint32 offset_vl = 0 ;
2014-10-02 21:47:19 +00:00
guint32 vl_max = 0 ; /* Max Value Length to Parse */
2008-10-11 14:25:02 +00:00
guint16 grp = 0 ;
guint16 elm = 0 ;
guint32 len_decoded_remaing = 0 ;
2016-11-20 22:38:14 +00:00
/* Decode the syntax a little more */
guint32 encoding = ( pdv - > syntax = = DCM_EBE ) ? ENC_BIG_ENDIAN : ENC_LITTLE_ENDIAN ;
gboolean is_implicit = ( pdv - > syntax = = DCM_ILE ) ;
2014-10-02 21:47:19 +00:00
gboolean is_vl_long = FALSE ; /* True for 4 Bytes length fields */
2008-10-11 14:25:02 +00:00
2014-10-02 21:47:19 +00:00
gboolean is_sequence = FALSE ; /* True for Sequence Tags */
gboolean is_item = FALSE ; /* True for Sequence Item Tags */
2008-10-11 14:25:02 +00:00
2015-01-18 21:02:15 +00:00
* tag_description = NULL ; /* Reset description. It's wmem packet scope memory, so not really bad*/
2008-10-11 14:25:02 +00:00
offset_tag = offset ;
if ( pdv - > prev & & is_first_tag ) {
2014-10-02 21:47:19 +00:00
len_decoded_remaing = pdv - > prev - > open_tag . len_decoded ;
2008-10-11 14:25:02 +00:00
}
/* Since we may have a fragmented header, check for every attribute,
whether we have already decoded left - overs from the previous PDV .
Since we have implicit & explicit syntax , copying the open tag to
a buffer without decoding , would have caused tvb_get_xxtohs ( )
2011-12-27 17:34:01 +00:00
implementations on the copy .
2008-10-11 14:25:02 +00:00
An alternative approach would have been to resemble the PDVs first .
2011-12-27 17:34:01 +00:00
The attempts to reassemble without named sources ( to be implemented )
2008-10-11 14:25:02 +00:00
were very sensitive to missing packets . In such a case , no packet
of a PDV chain was decoded , not even the start .
So for the time being , use this rather cumbersome approach .
For every two bytes ( PDV length are always a factor of 2 )
check whether we have enough data in the buffer and store the value
accordingly . In the next frame check , whether we have decoded this yet .
*/
/* Group */
if ( len_decoded_remaing > = 2 ) {
2014-10-02 21:47:19 +00:00
grp = pdv - > prev - > open_tag . grp ;
len_decoded_remaing - = 2 ;
2008-10-11 14:25:02 +00:00
}
else {
2016-11-20 22:38:14 +00:00
if ( dcm_tag_is_open ( pdv , offset_tag , offset , endpos , 2 ) )
return endpos ; /* Exit if needed */
2008-10-11 14:25:02 +00:00
2016-11-20 22:38:14 +00:00
grp = tvb_get_guint16 ( tvb , offset , encoding ) ;
2014-10-02 21:47:19 +00:00
offset + = 2 ;
pdv - > open_tag . grp = grp ;
2008-10-11 14:25:02 +00:00
}
/* Element */
if ( len_decoded_remaing > = 2 ) {
2014-10-02 21:47:19 +00:00
elm = pdv - > prev - > open_tag . elm ;
len_decoded_remaing - = 2 ;
2008-10-11 14:25:02 +00:00
}
else {
2016-11-20 22:38:14 +00:00
if ( dcm_tag_is_open ( pdv , offset_tag , offset , endpos , 2 ) )
return endpos ; /* Exit if needed */
2008-10-11 14:25:02 +00:00
2016-11-20 22:38:14 +00:00
elm = tvb_get_guint16 ( tvb , offset , encoding ) ;
2014-10-02 21:47:19 +00:00
offset + = 2 ;
pdv - > open_tag . elm = elm ;
2008-10-11 14:25:02 +00:00
}
2008-10-31 22:59:14 +00:00
/* Find the best matching tag */
tag_def = dcm_tag_lookup ( grp , elm ) ;
2008-10-11 14:25:02 +00:00
/* Value Representation */
offset_vr = offset ;
if ( ( grp = = 0xFFFE ) & & ( elm = = 0xE000 | | elm = = 0xE00D | | elm = = 0xE0DD ) ) {
2014-10-02 21:47:19 +00:00
/* Item start, Item Delimitation or Sequence Delimitation */
vr = " UL " ;
is_vl_long = TRUE ; /* These tags always have a 4 byte length field */
2008-10-11 14:25:02 +00:00
}
else if ( is_implicit ) {
2014-10-02 21:47:19 +00:00
/* Get VR from tag definition */
vr = wmem_strdup ( wmem_packet_scope ( ) , tag_def - > vr ) ;
is_vl_long = TRUE ; /* Implicit always has 4 byte length field */
2008-10-11 14:25:02 +00:00
}
else {
2014-10-02 21:47:19 +00:00
if ( len_decoded_remaing > = 2 ) {
vr = wmem_strdup ( wmem_packet_scope ( ) , pdv - > prev - > open_tag . vr ) ;
len_decoded_remaing - = 2 ;
}
else {
/* Controlled exit, if VR does not fit. */
2016-11-20 22:38:14 +00:00
if ( dcm_tag_is_open ( pdv , offset_tag , offset_vr , endpos , 2 ) )
return endpos ;
2014-10-02 21:47:19 +00:00
vr = ( gchar * ) tvb_get_string_enc ( wmem_packet_scope ( ) , tvb , offset , 2 , ENC_ASCII ) ;
offset + = 2 ;
g_free ( pdv - > open_tag . vr ) ;
2018-03-05 10:54:55 +00:00
pdv - > open_tag . vr = g_strdup ( vr ) ; /* needs to survive within a session */
2014-10-02 21:47:19 +00:00
}
2018-03-05 10:54:55 +00:00
if ( ( strcmp ( vr , " OB " ) = = 0 ) | | ( strcmp ( vr , " OW " ) = = 0 ) | | ( strcmp ( vr , " OF " ) = = 0 ) | | ( strcmp ( vr , " OD " ) = = 0 ) | | ( strcmp ( vr , " OL " ) = = 0 ) | |
( strcmp ( vr , " SQ " ) = = 0 ) | | ( strcmp ( vr , " UC " ) = = 0 ) | | ( strcmp ( vr , " UR " ) = = 0 ) | | ( strcmp ( vr , " UT " ) = = 0 ) | | ( strcmp ( vr , " UN " ) = = 0 ) ) {
2018-10-22 15:58:35 +00:00
/* Part 5, Table 7.1-1 in the standard */
2018-03-05 10:54:55 +00:00
/* Length is always 4 bytes: OB, OD, OF, OL, OW, SQ, UC, UR, UT or UN */
2014-10-02 21:47:19 +00:00
is_vl_long = TRUE ;
/* Skip 2 Bytes */
if ( len_decoded_remaing > = 2 ) {
len_decoded_remaing - = 2 ;
}
else {
2016-11-20 22:38:14 +00:00
if ( dcm_tag_is_open ( pdv , offset_tag , offset_vr , endpos , 2 ) )
return endpos ;
2014-10-02 21:47:19 +00:00
offset + = 2 ;
}
}
else {
is_vl_long = FALSE ;
}
2008-10-11 14:25:02 +00:00
}
2011-12-27 17:34:01 +00:00
/* Value Length. This is rather cumbersome code to get a 4 byte length, but in the
2008-10-11 14:25:02 +00:00
fragmented case , we have 2 * 2 bytes . So always use that pattern
*/
offset_vl = offset ;
if ( len_decoded_remaing > = 2 ) {
2014-10-02 21:47:19 +00:00
vl_1 = pdv - > prev - > open_tag . vl_1 ;
len_decoded_remaing - = 2 ;
2008-10-11 14:25:02 +00:00
}
else {
2016-11-20 22:38:14 +00:00
if ( dcm_tag_is_open ( pdv , offset_tag , offset_vl , endpos , 2 ) )
return endpos ;
vl_1 = tvb_get_guint16 ( tvb , offset , encoding ) ;
2014-10-02 21:47:19 +00:00
offset + = 2 ;
pdv - > open_tag . vl_1 = vl_1 ;
2008-10-11 14:25:02 +00:00
}
if ( is_vl_long ) {
2014-10-02 21:47:19 +00:00
if ( len_decoded_remaing > = 2 ) {
vl_2 = pdv - > prev - > open_tag . vl_2 ;
}
else {
2008-07-25 13:20:18 +00:00
2016-11-20 22:38:14 +00:00
if ( dcm_tag_is_open ( pdv , offset_tag , offset_vl + 2 , endpos , 2 ) )
return endpos ;
vl_2 = tvb_get_guint16 ( tvb , offset , encoding ) ;
2014-10-02 21:47:19 +00:00
offset + = 2 ;
pdv - > open_tag . vl_2 = vl_2 ;
}
2008-10-11 14:25:02 +00:00
2016-11-20 22:38:14 +00:00
if ( encoding = = ENC_LITTLE_ENDIAN ) vl = ( vl_2 < < 16 ) + vl_1 ;
2014-10-02 21:47:19 +00:00
else vl = ( vl_1 < < 16 ) + vl_2 ;
2008-10-11 14:25:02 +00:00
}
else {
2014-10-02 21:47:19 +00:00
vl = vl_1 ;
2008-10-11 14:25:02 +00:00
}
2011-12-27 17:34:01 +00:00
/* Now we have most of the information, except for sequences and items with undefined
2010-05-14 21:54:48 +00:00
length : - / . But , whether we know the length or not , we now need to create the tree
2008-10-12 21:35:23 +00:00
item and subtree , before we can loop into sequences and items
Display the information we collected so far . Don ' t wait until the value is parsed ,
because that parsing might cause an exception . If that happens within a sequence ,
the sequence tag would not show up with the value
2014-08-04 01:10:24 +00:00
Use different ett_ for Sequences & Items , so that fold / unfold state makes sense
2008-10-11 14:25:02 +00:00
*/
2010-03-19 20:24:06 +00:00
tag_summary = dcm_tag_summary ( grp , elm , vl , tag_def - > description , vr , tag_def - > is_retired , is_implicit ) ;
2010-05-14 21:54:48 +00:00
is_sequence = ( strcmp ( vr , " SQ " ) = = 0 ) | | ( vl = = 0xFFFFFFFF ) ;
2008-10-11 14:25:02 +00:00
is_item = ( ( grp = = 0xFFFE ) & & ( elm = = 0xE000 ) ) ;
2008-07-25 13:20:18 +00:00
2016-01-14 16:47:06 +00:00
if ( ( is_sequence | is_item ) & & global_dcm_seq_subtree ) {
ett = is_sequence ? ett_dcm_data_seq : ett_dcm_data_item ;
2018-03-05 10:54:55 +00:00
}
else {
2016-01-14 16:47:06 +00:00
ett = ett_dcm_data_tag ;
}
2018-03-05 10:54:55 +00:00
if ( vl = = 0xFFFFFFFF ) {
/* 'Just' mark header as the length of the item */
tag_ptree = proto_tree_add_subtree ( tree , tvb , offset_tag , offset - offset_tag , ett , & tag_pitem , tag_summary ) ;
vl_max = 0 ; /* We don't know who long this sequence/item is */
}
else if ( offset + vl < = endpos ) {
/* Show real length of item */
tag_ptree = proto_tree_add_subtree ( tree , tvb , offset_tag , offset + vl - offset_tag , ett , & tag_pitem , tag_summary ) ;
vl_max = vl ;
}
else {
/* Value is longer than what we have in the PDV, -> we do have a OPEN tag */
tag_ptree = proto_tree_add_subtree ( tree , tvb , offset_tag , endpos - offset_tag , ett , & tag_pitem , tag_summary ) ;
vl_max = endpos - offset ;
}
2008-07-25 13:20:18 +00:00
2008-10-11 14:25:02 +00:00
/* If you are going to touch the following 25 lines, make sure you reserve a few hours to go
2018-03-05 10:54:55 +00:00
through both display options and check for proper tree display : - )
2008-10-11 14:25:02 +00:00
*/
2018-03-05 10:54:55 +00:00
if ( is_sequence | is_item ) {
2014-10-02 21:47:19 +00:00
2018-03-05 10:54:55 +00:00
if ( global_dcm_seq_subtree ) {
/* Use different ett_ for Sequences & Items, so that fold/unfold state makes sense */
seq_ptree = tag_ptree ;
if ( ! global_dcm_tag_subtree ) {
tag_ptree = NULL ;
}
2014-10-02 21:47:19 +00:00
}
else {
2018-03-05 10:54:55 +00:00
seq_ptree = tree ;
if ( ! global_dcm_tag_subtree ) {
tag_ptree = NULL ;
}
}
}
else {
/* For tags */
if ( ! global_dcm_tag_subtree ) {
tag_ptree = NULL ;
2014-10-02 21:47:19 +00:00
}
2018-03-05 10:54:55 +00:00
}
2014-10-02 21:47:19 +00:00
2018-03-05 10:54:55 +00:00
/* ---------------------------------------------------------------
2014-10-02 21:47:19 +00:00
Tag details as separate items
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2018-03-05 10:54:55 +00:00
*/
2008-10-11 14:25:02 +00:00
2013-09-15 01:48:30 +00:00
proto_tree_add_uint_format_value ( tag_ptree , hf_dcm_tag , tvb , offset_tag , 4 ,
( grp < < 16 ) | elm , " %04x,%04x (%s) " , grp , elm , tag_def - > description ) ;
2008-10-11 14:25:02 +00:00
2018-03-05 10:54:55 +00:00
/* Add VR to tag detail, except for sequence items */
2008-10-11 14:25:02 +00:00
if ( ! is_item ) {
2014-10-02 21:47:19 +00:00
if ( is_implicit ) {
/* Select header, since no VR is present in implicit syntax */
2016-11-20 22:38:14 +00:00
proto_tree_add_string ( tag_ptree , hf_dcm_tag_vr , tvb , offset_tag , 4 , vr ) ;
2014-10-02 21:47:19 +00:00
}
else {
2016-11-20 22:38:14 +00:00
proto_tree_add_string ( tag_ptree , hf_dcm_tag_vr , tvb , offset_vr , 2 , vr ) ;
2014-10-02 21:47:19 +00:00
}
2008-07-25 13:36:58 +00:00
}
2008-07-25 13:20:18 +00:00
2008-12-18 19:08:49 +00:00
/* Add length to tag detail */
2016-11-20 22:38:14 +00:00
proto_tree_add_uint ( tag_ptree , hf_dcm_tag_vl , tvb , offset_vl , ( is_vl_long ? 4 : 2 ) , vl ) ;
2008-10-11 14:25:02 +00:00
/* ---------------------------------------------------------------
2014-10-02 21:47:19 +00:00
Finally the Tag Value
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2008-10-11 14:25:02 +00:00
*/
if ( ( is_sequence | | is_item ) & & ( vl > 0 ) ) {
2014-10-02 21:47:19 +00:00
/* Sequence or Item Start */
2008-10-11 14:25:02 +00:00
2014-10-02 21:47:19 +00:00
guint32 endpos_item = 0 ;
gboolean local_end_of_seq_or_item = FALSE ;
gboolean is_first_desc = TRUE ;
2008-10-11 14:25:02 +00:00
2015-01-18 21:02:15 +00:00
const gchar * item_description = NULL ; /* Will be allocated as wmem packet scope memory in dissect_dcm_tag() */
2008-10-11 14:25:02 +00:00
2014-10-02 21:47:19 +00:00
if ( vl = = 0xFFFFFFFF ) {
/* Undefined length */
2008-10-11 14:25:02 +00:00
2014-10-02 21:47:19 +00:00
while ( ( ! local_end_of_seq_or_item ) & & ( ! pdv - > open_tag . is_header_fragmented ) & & ( offset < endpos ) ) {
2008-10-11 14:25:02 +00:00
2018-03-05 10:54:55 +00:00
offset = dissect_dcm_tag ( tvb , pinfo , seq_ptree , pdv , offset , endpos , FALSE , & item_description , & local_end_of_seq_or_item ) ;
2008-10-11 14:25:02 +00:00
2014-10-02 21:47:19 +00:00
if ( item_description & & global_dcm_seq_subtree ) {
proto_item_append_text ( tag_pitem , ( is_first_desc ? " %s " : " , %s " ) , item_description ) ;
is_first_desc = FALSE ;
}
}
}
else {
/* Defined length */
endpos_item = offset + vl_max ;
2008-10-11 14:25:02 +00:00
2014-10-02 21:47:19 +00:00
while ( offset < endpos_item ) {
2008-10-11 14:25:02 +00:00
2018-03-05 10:54:55 +00:00
offset = dissect_dcm_tag ( tvb , pinfo , seq_ptree , pdv , offset , endpos_item , FALSE , & item_description , & local_end_of_seq_or_item ) ;
2008-10-11 14:25:02 +00:00
2014-10-02 21:47:19 +00:00
if ( item_description & & global_dcm_seq_subtree ) {
proto_item_append_text ( tag_pitem , ( is_first_desc ? " %s " : " , %s " ) , item_description ) ;
is_first_desc = FALSE ;
}
}
}
2010-01-18 21:49:47 +00:00
} /* if ((is_sequence || is_item) && (vl > 0)) */
2008-10-11 14:25:02 +00:00
else if ( ( grp = = 0xFFFE ) & & ( elm = = 0xE00D ) ) {
2014-10-02 21:47:19 +00:00
/* Item delimitation for items with undefined length */
* end_of_seq_or_item = TRUE ;
2008-10-11 14:25:02 +00:00
}
else if ( ( grp = = 0xFFFE ) & & ( elm = = 0xE0DD ) ) {
2014-10-02 21:47:19 +00:00
/* Sequence delimitation for sequences with undefined length */
* end_of_seq_or_item = TRUE ;
2008-10-11 14:25:02 +00:00
}
else if ( vl = = 0 ) {
2018-03-05 10:54:55 +00:00
/* No value for this tag */
/* The following copy is needed. tag_value is post processed with g_strstrip()
and that one will crash the whole application , when a constant is used .
*/
tag_value = wmem_strdup ( wmem_packet_scope ( ) , " <Empty> " ) ;
2008-10-11 14:25:02 +00:00
}
else if ( vl > vl_max ) {
2014-10-02 21:47:19 +00:00
/* Tag is longer than the PDV/PDU. Don't perform any decoding */
2008-10-11 14:25:02 +00:00
2014-10-02 21:47:19 +00:00
gchar * tag_desc ;
2008-10-11 14:25:02 +00:00
proto_tree_add_bytes_format ( tag_ptree , hf_dcm_tag_value_byte , tvb , offset , vl_max ,
2014-10-02 21:47:19 +00:00
NULL , " %-8.8sBytes %d - %d [start] " , " Value: " , 1 , vl_max ) ;
2008-10-11 14:25:02 +00:00
2016-11-21 03:46:10 +00:00
tag_value = wmem_strdup_printf ( wmem_packet_scope ( ) , " <Bytes %d - %d, start> " , 1 , vl_max ) ;
2014-10-02 21:47:19 +00:00
offset + = vl_max ;
2008-10-11 14:25:02 +00:00
2014-10-02 21:47:19 +00:00
/* Save the needed data for reuse, and subsequent packets
This will leak a little within the session .
2008-10-11 14:25:02 +00:00
2014-10-02 21:47:19 +00:00
But since we may have tags being closed and reopen in the same PDV
we will always need to store this
*/
2008-10-11 14:25:02 +00:00
2014-10-02 21:47:19 +00:00
tag_desc = dcm_tag_summary ( grp , elm , vl , tag_def - > description , vr , tag_def - > is_retired , is_implicit ) ;
2008-10-11 14:25:02 +00:00
2014-10-02 21:47:19 +00:00
if ( pdv - > open_tag . desc = = NULL ) {
pdv - > open_tag . is_value_fragmented = TRUE ;
pdv - > open_tag . desc = wmem_strdup ( wmem_file_scope ( ) , tag_desc ) ;
pdv - > open_tag . len_total = vl ;
pdv - > open_tag . len_remaining = vl - vl_max ;
}
2008-10-11 14:25:02 +00:00
}
else {
2014-10-02 21:47:19 +00:00
/* Regular value. Identify the type, decode and display */
offset = dissect_dcm_tag_value ( tvb , pinfo , tag_ptree , pdv , offset , grp , elm , vl , vl_max , vr , & tag_value ) ;
/* -------------------------------------------------------------
We have decoded the value . Now store those tags of interest
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
/* Store SOP Class and Instance UID in first PDV of this object */
if ( grp = = 0x0008 & & elm = = 0x0016 ) {
dcm_state_pdv_get_obj_start ( pdv ) - > sop_class_uid = wmem_strdup ( wmem_file_scope ( ) , tag_value ) ;
}
else if ( grp = = 0x0008 & & elm = = 0x0018 ) {
dcm_state_pdv_get_obj_start ( pdv ) - > sop_instance_uid = wmem_strdup ( wmem_file_scope ( ) , tag_value ) ;
}
else if ( grp = = 0x0000 & & elm = = 0x0100 ) {
/* This is the command tag -> overwrite existing PDV description */
pdv - > desc = wmem_strdup ( wmem_file_scope ( ) , tag_value ) ;
}
2008-10-11 14:25:02 +00:00
}
/* -------------------------------------------------------------------
2011-12-27 17:34:01 +00:00
Add the value to the already constructed item
2008-10-11 14:25:02 +00:00
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
proto_item_append_text ( tag_pitem , " %s " , tag_value ) ;
if ( tag_def - > add_to_summary ) {
2014-10-02 21:47:19 +00:00
* tag_description = wmem_strdup ( wmem_packet_scope ( ) , g_strstrip ( tag_value ) ) ;
2008-10-11 14:25:02 +00:00
}
return offset ;
}
2019-02-11 11:27:19 +00:00
/*
' Decode ' open tags from previous PDV . It mostly ends in ' continuation ' or ' end ' in the description .
*/
2008-10-11 14:25:02 +00:00
static guint32
dissect_dcm_tag_open ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree ,
2014-10-02 21:47:19 +00:00
dcm_state_pdv_t * pdv , guint32 offset , guint32 endpos , gboolean * is_first_tag )
2008-10-11 14:25:02 +00:00
{
proto_item * pitem = NULL ;
guint32 tag_value_fragment_len = 0 ;
if ( ( pdv - > prev ) & & ( pdv - > prev - > open_tag . len_remaining > 0 ) ) {
2014-10-02 21:47:19 +00:00
/* Not first PDV in the given presentation context (Those don't have remaining data to parse :-) */
/* And previous PDV has left overs, i.e. this is a continuation PDV */
if ( endpos - offset > = pdv - > prev - > open_tag . len_remaining ) {
/*
Remaining bytes are equal or more than we expect for the open tag
Finally reach the end of this tag . Don ' t touch the open_tag structure
of this PDV , as we may see a new open tag at the end
*/
tag_value_fragment_len = pdv - > prev - > open_tag . len_remaining ;
pdv - > is_corrupt = FALSE ;
}
else if ( pdv - > is_flagvalid & & pdv - > is_last_fragment ) {
/*
The tag is not yet complete , however , the flag indicates that it should be
Therefore end this tag and issue an expert_add_info . Don ' t touch the
open_tag structure of this PDV , as we may see a new open tag at the end
*/
tag_value_fragment_len = endpos - offset ;
pdv - > is_corrupt = TRUE ;
}
else {
/*
* More to do for this tag
*/
tag_value_fragment_len = endpos - offset ;
/* Set data in current PDV structure */
if ( ! pdv - > open_tag . is_value_fragmented ) {
/* No need to do it twice or more */
pdv - > open_tag . is_value_fragmented = TRUE ;
pdv - > open_tag . len_total = pdv - > prev - > open_tag . len_total ;
pdv - > open_tag . len_remaining = pdv - > prev - > open_tag . len_remaining - tag_value_fragment_len ;
pdv - > open_tag . desc = wmem_strdup ( wmem_file_scope ( ) , pdv - > prev - > open_tag . desc ) ;
}
pdv - > is_corrupt = FALSE ;
}
if ( pdv - > is_corrupt ) {
pitem = proto_tree_add_bytes_format ( tree , hf_dcm_data_tag , tvb ,
offset , tag_value_fragment_len , NULL ,
" %s <incomplete> " , pdv - > prev - > open_tag . desc ) ;
expert_add_info ( pinfo , pitem , & ei_dcm_data_tag ) ;
}
else {
proto_tree_add_bytes_format ( tree , hf_dcm_data_tag , tvb ,
offset , tag_value_fragment_len , NULL ,
" %s <Bytes %d - %d, %s> " , pdv - > prev - > open_tag . desc ,
pdv - > prev - > open_tag . len_total - pdv - > prev - > open_tag . len_remaining + 1 ,
pdv - > prev - > open_tag . len_total - pdv - > prev - > open_tag . len_remaining + tag_value_fragment_len ,
( pdv - > prev - > open_tag . len_remaining > tag_value_fragment_len ? " continuation " : " end " ) ) ;
}
offset + = tag_value_fragment_len ;
* is_first_tag = FALSE ;
2004-05-08 08:49:02 +00:00
}
2008-07-25 13:20:18 +00:00
2008-10-11 14:25:02 +00:00
return offset ;
}
2008-07-25 13:20:18 +00:00
2019-02-11 11:27:19 +00:00
/*
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 .
2020-08-15 04:48:33 +00:00
For data PDVs , only process tags when tree is set or listening to export objects tap .
2019-02-11 11:27:19 +00:00
For command PDVs , process all tags .
On export copy the content to the export buffer .
*/
2008-10-11 14:25:02 +00:00
static guint32
2019-02-11 11:27:19 +00:00
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 )
2008-10-11 14:25:02 +00:00
{
2012-12-26 05:57:06 +00:00
const gchar * tag_value = NULL ;
2008-10-11 14:25:02 +00:00
gboolean dummy = FALSE ;
2020-08-15 04:48:33 +00:00
guint32 startpos = offset ;
2008-10-11 14:25:02 +00:00
guint32 endpos = 0 ;
2008-07-25 13:20:18 +00:00
2010-08-09 19:28:09 +00:00
endpos = offset + pdv_body_len ;
2008-07-25 13:20:18 +00:00
2020-08-15 04:48:33 +00:00
if ( pdv - > is_command | | tree | | have_tap_listener ( dicom_eo_tap ) ) {
2019-02-11 11:27:19 +00:00
/* Performance optimization starts here. Don't put any COL_INFO related stuff in here */
2008-10-11 14:25:02 +00:00
2019-02-11 11:27:19 +00:00
if ( pdv - > syntax = = DCM_UNK ) {
/* Eventually, we will have a syntax detector. Until then, don't decode */
2008-10-11 14:25:02 +00:00
2019-02-11 11:27:19 +00:00
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 ;
}
2014-10-02 21:47:19 +00:00
}
2008-07-25 13:20:18 +00:00
}
2004-05-08 08:49:02 +00:00
2019-02-11 11:27:19 +00:00
* pdv_description = pdv - > desc ;
2009-05-18 06:21:22 +00:00
if ( pdv - > is_command ) {
2014-10-02 21:47:19 +00:00
if ( pdv - > is_warning ) {
if ( pdv - > comment ) {
2016-11-21 03:46:10 +00:00
* pdv_description = wmem_strdup_printf ( wmem_packet_scope ( ) , " %s (%s, %s) " , pdv - > desc , pdv - > status , pdv - > comment ) ;
2014-10-02 21:47:19 +00:00
}
else {
2016-11-21 03:46:10 +00:00
* pdv_description = wmem_strdup_printf ( wmem_packet_scope ( ) , " %s (%s) " , pdv - > desc , pdv - > status ) ;
2014-10-02 21:47:19 +00:00
}
}
else if ( global_dcm_cmd_details ) {
/* Show command details in header */
if ( pdv - > message_id > 0 ) {
2016-11-21 03:46:10 +00:00
* pdv_description = wmem_strdup_printf ( wmem_packet_scope ( ) , " %s ID=%d " , pdv - > desc , pdv - > message_id ) ;
2014-10-02 21:47:19 +00:00
}
else if ( pdv - > message_id_resp > 0 ) {
2016-11-21 03:46:10 +00:00
* pdv_description = wmem_strdup_printf ( wmem_packet_scope ( ) , " %s ID=%d " , pdv - > desc , pdv - > message_id_resp ) ;
2014-10-02 21:47:19 +00:00
if ( pdv - > no_completed > 0 ) {
2016-11-21 03:46:10 +00:00
* pdv_description = wmem_strdup_printf ( wmem_packet_scope ( ) , " %s C=%d " , * pdv_description , pdv - > no_completed ) ;
2014-10-02 21:47:19 +00:00
}
if ( pdv - > no_remaining > 0 ) {
2016-11-21 03:46:10 +00:00
* pdv_description = wmem_strdup_printf ( wmem_packet_scope ( ) , " %s R=%d " , * pdv_description , pdv - > no_remaining ) ;
2014-10-02 21:47:19 +00:00
}
if ( pdv - > no_warning > 0 ) {
2016-11-21 03:46:10 +00:00
* pdv_description = wmem_strdup_printf ( wmem_packet_scope ( ) , " %s W=%d " , * pdv_description , pdv - > no_warning ) ;
2014-10-02 21:47:19 +00:00
}
if ( pdv - > no_failed > 0 ) {
2016-11-21 03:46:10 +00:00
* pdv_description = wmem_strdup_printf ( wmem_packet_scope ( ) , " %s F=%d " , * pdv_description , pdv - > no_failed ) ;
2014-10-02 21:47:19 +00:00
}
2019-02-18 14:53:06 +00:00
if ( ! pdv - > is_pending & & pdv - > status )
{
* pdv_description = wmem_strdup_printf ( wmem_packet_scope ( ) , " %s (%s) " , * pdv_description , pdv - > status ) ;
}
2014-10-02 21:47:19 +00:00
}
}
2009-05-18 06:21:22 +00:00
}
2008-07-25 13:36:58 +00:00
2020-08-15 04:48:33 +00:00
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 , startpos , 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 ) ;
}
}
2019-02-11 11:27:19 +00:00
return endpos ;
2008-07-25 13:20:18 +00:00
}
2004-05-08 08:49:02 +00:00
2018-03-05 10:54:55 +00:00
/*
2019-02-11 11:27:19 +00:00
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 .
2018-03-05 10:54:55 +00:00
Return pdv_description to be used e . g . in COL_INFO .
*/
2010-08-09 19:28:09 +00:00
static guint32
dissect_dcm_pdv_fragmented ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree ,
2014-10-02 21:47:19 +00:00
dcm_state_assoc_t * assoc , guint32 offset , guint32 pdv_len , gchar * * pdv_description )
2010-08-09 19:28:09 +00:00
{
2018-03-05 10:54:55 +00:00
conversation_t * conv = NULL ;
2010-08-09 19:28:09 +00:00
dcm_state_pdv_t * pdv = NULL ;
2019-02-11 11:27:19 +00:00
tvbuff_t * combined_tvb = NULL ;
2013-07-17 21:12:24 +00:00
fragment_head * head = NULL ;
2010-08-09 19:28:09 +00:00
guint32 reassembly_id ;
guint32 pdv_body_len ;
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 ) ;
if ( global_dcm_reassemble )
{
2019-02-11 11:27:19 +00:00
/* 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 .
*/
2017-10-28 13:58:28 +00:00
conv = find_conversation_pinfo ( pinfo , 0 ) ;
2014-10-02 21:47:19 +00:00
/* Try to create somewhat unique ID.
Include the conversation index , to separate TCP session
2020-08-19 14:15:33 +00:00
Include bits from the reassembly number in the current Presentation
Context ( that we track ourselves ) in order to distinguish between
PDV fragments from the same frame but different reassemblies .
2014-10-02 21:47:19 +00:00
*/
2016-03-26 15:03:03 +00:00
DISSECTOR_ASSERT ( conv ) ;
2019-02-11 11:27:19 +00:00
/* The following expression seems to executed late in VS2017 in 'RelWithDebInf'.
Therefore it may appear as 0 at first
*/
2020-08-19 14:15:33 +00:00
reassembly_id = ( ( ( conv - > conv_index ) & 0x000FFFFF ) < < 12 ) +
( ( guint32 ) ( pdv - > pctx_id ) < < 4 ) + ( ( guint32 ) ( pdv - > reassembly_id & 0xF ) ) ;
2019-02-11 11:27:19 +00:00
/* 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 ) ) ;
2019-02-18 14:53:06 +00:00
if ( head & & ( head - > next = = NULL ) ) {
/* Was not really fragmented, therefore use 'conventional' decoding.
process_reassembled_data ( ) does not cope with two PDVs in the same frame , therefore catch it here
*/
2019-02-11 11:27:19 +00:00
2019-02-18 14:53:06 +00:00
offset = dissect_dcm_pdv_body ( tvb , pinfo , tree , assoc , pdv , offset , pdv_body_len , pdv_description ) ;
}
else
{
/* 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 {
/* 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 ) ;
}
2014-10-02 21:47:19 +00:00
}
else {
2019-02-18 14:53:06 +00:00
/* 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 " ) ;
2014-10-02 21:47:19 +00:00
}
2019-02-18 14:53:06 +00:00
offset + = pdv_body_len ;
2014-10-02 21:47:19 +00:00
}
else {
2019-02-18 14:53:06 +00:00
/* 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 ) ;
2014-10-02 21:47:19 +00:00
}
2019-02-11 11:27:19 +00:00
}
}
2019-02-18 14:53:06 +00:00
else {
2019-02-11 11:27:19 +00:00
/* 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 ) ;
2010-08-09 19:28:09 +00:00
}
return offset ;
}
2019-02-18 14:53:06 +00:00
2008-10-11 14:25:02 +00:00
static guint32
dissect_dcm_pdu_data ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree ,
2014-10-02 21:47:19 +00:00
dcm_state_assoc_t * assoc , guint32 offset , guint32 pdu_len , gchar * * pdu_data_description )
2004-05-08 08:49:02 +00:00
{
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
/* 04 P-DATA-TF
1 1 reserved
2 4 length
- ( 1 + ) presentation data value ( PDV ) items
6 4 length
10 1 Presentation Context ID ( odd ints 1 - 255 )
- PDV
11 1 header
0x01 if set , contains Message Command info , else Message Data
0x02 if set , contains last fragment
2008-07-25 13:20:18 +00:00
*/
2014-10-02 21:47:19 +00:00
proto_tree * pdv_ptree ; /* Tree for item details */
2013-09-07 16:07:02 +00:00
proto_item * pdv_pitem , * pdvlen_item ;
2004-05-08 08:49:02 +00:00
2014-10-02 21:47:19 +00:00
gchar * buf_desc = NULL ; /* PDU description */
2008-10-11 14:25:02 +00:00
gchar * pdv_description = NULL ;
gboolean first_pdv = TRUE ;
2004-05-08 13:39:36 +00:00
2008-10-11 14:25:02 +00:00
guint32 endpos = 0 ;
guint32 pdv_len = 0 ;
2004-11-10 10:28:43 +00:00
2008-10-11 14:25:02 +00:00
endpos = offset + pdu_len ;
2008-07-25 13:20:18 +00:00
2008-10-11 14:25:02 +00:00
/* Loop through multiple PDVs */
2008-07-25 13:36:58 +00:00
while ( offset < endpos ) {
2008-10-11 14:25:02 +00:00
2014-10-02 21:47:19 +00:00
pdv_len = tvb_get_ntohl ( tvb , offset ) ;
pdv_ptree = proto_tree_add_subtree ( tree , tvb , offset , pdv_len + 4 , ett_dcm_data_pdv , & pdv_pitem , " PDV " ) ;
pdvlen_item = proto_tree_add_item ( pdv_ptree , hf_dcm_pdv_len , tvb , offset , 4 , ENC_BIG_ENDIAN ) ;
offset + = 4 ;
2017-05-05 21:23:59 +00:00
if ( ( pdv_len + 4 > pdu_len ) | | ( pdv_len + 4 < pdv_len ) ) {
2014-10-02 21:47:19 +00:00
expert_add_info_format ( pinfo , pdvlen_item , & ei_dcm_pdv_len , " Invalid PDV length (too large) " ) ;
return endpos ;
}
else if ( pdv_len < = 2 ) {
expert_add_info_format ( pinfo , pdvlen_item , & ei_dcm_pdv_len , " Invalid PDV length (too small) " ) ;
return endpos ;
}
else if ( ( ( pdv_len > > 1 ) < < 1 ) ! = pdv_len ) {
expert_add_info_format ( pinfo , pdvlen_item , & ei_dcm_pdv_len , " Invalid PDV length (not even) " ) ;
return endpos ;
}
offset = dissect_dcm_pdv_fragmented ( tvb , pinfo , pdv_ptree , assoc , offset , pdv_len , & pdv_description ) ;
/* The following doesn't seem to work anymore */
if ( pdv_description ) {
if ( first_pdv ) {
2016-11-21 03:46:10 +00:00
buf_desc = wmem_strdup ( wmem_packet_scope ( ) , pdv_description ) ;
2014-10-02 21:47:19 +00:00
}
else {
2016-11-21 03:46:10 +00:00
buf_desc = wmem_strdup_printf ( wmem_packet_scope ( ) , " %s, %s " , buf_desc , pdv_description ) ;
2014-10-02 21:47:19 +00:00
}
}
proto_item_append_text ( pdv_pitem , " , %s " , pdv_description ) ;
first_pdv = FALSE ;
2008-07-25 13:36:58 +00:00
2004-05-08 08:49:02 +00:00
}
2008-10-11 14:25:02 +00:00
* pdu_data_description = buf_desc ;
2008-07-25 13:36:58 +00:00
return offset ;
2008-07-25 13:20:18 +00:00
}
2004-11-10 10:28:43 +00:00
2018-05-06 15:33:51 +00:00
/*
Test for DICOM traffic .
- Minimum 10 Bytes
- Look for the association request
- Check PDU size vs TCP payload size
Since used in heuristic mode , be picky for performance reasons .
We are called in static mode , once we decoded the association request and called conversation_set_dissector ( )
They we can be more liberal on the packet selection
*/
static gboolean
test_dcm ( tvbuff_t * tvb )
{
guint8 pdu_type ;
guint32 pdu_len ;
guint16 vers ;
/*
Ensure that the tvb_captured_length is big enough before fetching the values .
Otherwise it can trigger an exception during the heuristic check ,
preventing next heuristic dissectors from being called
tvb_reported_length ( ) is the real size of the packet as transmitted on the wire
tvb_captured_length ( ) is the number of bytes captured ( so you always have captured < = reported ) .
The 10 bytes represent an association request header including the 2 reserved bytes not used below
In the captures at hand , the parsing result was equal .
*/
if ( tvb_captured_length ( tvb ) < 8 ) {
return FALSE ;
}
if ( tvb_reported_length ( tvb ) < 10 ) {
return FALSE ;
}
pdu_type = tvb_get_guint8 ( tvb , 0 ) ;
pdu_len = tvb_get_ntohl ( tvb , 2 ) ;
vers = tvb_get_ntohs ( tvb , 6 ) ;
/* Exit, if not an association request at version 1 */
if ( ! ( pdu_type = = 1 & & vers = = 1 ) ) {
return FALSE ;
}
/* Exit if TCP payload is bigger than PDU length (plus header)
OK for PRESENTATION_DATA , questionable for ASSOCIATION requests
*/
if ( tvb_reported_length ( tvb ) > pdu_len + 6 ) {
return FALSE ;
}
return TRUE ;
}
2018-03-05 10:54:55 +00:00
/*
Main function to decode DICOM traffic . Supports reassembly of TCP packets .
*/
2008-07-25 13:20:18 +00:00
static int
2009-07-10 21:54:29 +00:00
dissect_dcm_main ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree , gboolean is_port_static )
2008-07-25 13:20:18 +00:00
{
2008-07-25 13:36:58 +00:00
2008-10-11 14:25:02 +00:00
guint8 pdu_type = 0 ;
guint32 pdu_start = 0 ;
guint32 pdu_len = 0 ;
guint32 tlen = 0 ;
2008-07-25 13:20:18 +00:00
2008-10-11 14:25:02 +00:00
int offset = 0 ;
2008-07-25 13:20:18 +00:00
/*
2018-03-05 10:54:55 +00:00
TCP packets are assembled well by wireshark in conjunction with the dissectors .
2008-07-25 13:20:18 +00:00
2018-03-05 10:54:55 +00:00
Therefore , we will only see properly aligned PDUs , at the beginning of the buffer .
So if the buffer does not start with the PDU header , it ' s not DICOM traffic .
2008-07-25 13:20:18 +00:00
2018-03-05 10:54:55 +00:00
Do the byte checking as early as possible .
2014-10-02 21:47:19 +00:00
The heuristic hook requires an association request
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
DICOM PDU are nice , but need to be managed
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
We can have any combination :
- One or more DICOM PDU per TCP packet
- PDU split over different TCP packets
- And both together , i . e . some complete PDUs and then a fraction of a new PDU in a TCP packet
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
This function will handle multiple PDUs per TCP packet and will ask for more data ,
if the last PDU does not fit
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
It does not reassemble fragmented PDVs by purpose , since the Tag Value parsing needs to be done
per Tag , and PDU recombination here would
a ) need to eliminate PDU / PDV / Ctx header ( 12 bytes )
b ) not show the true DICOM logic in transfer
2008-07-25 13:36:58 +00:00
2014-10-02 21:47:19 +00:00
The length check is tricky . If not a PDV continuation , 10 Bytes are required . For PDV continuation
anything seems to be possible , depending on the buffer alignment of the sending process .
2008-07-25 13:36:58 +00:00
2008-07-25 13:20:18 +00:00
*/
tlen = tvb_reported_length ( tvb ) ;
pdu_type = tvb_get_guint8 ( tvb , 0 ) ;
2014-10-02 21:47:19 +00:00
if ( pdu_type = = 0 | | pdu_type > 7 ) /* Wrong PDU type. 'Or' is slightly more efficient than 'and' */
return 0 ; /* No bytes taken from the stack */
2008-07-25 13:36:58 +00:00
2009-07-10 21:54:29 +00:00
if ( is_port_static ) {
2014-10-02 21:47:19 +00:00
/* Port is defined explicitly, or association request was previously found successfully.
Be more tolerant on minimum packet size . Also accept < 6
*/
2010-05-14 21:54:48 +00:00
2014-10-02 21:47:19 +00:00
if ( tlen < 6 ) {
/* we need 6 bytes at least to get PDU length */
pinfo - > desegment_offset = offset ;
2008-07-25 13:36:58 +00:00
pinfo - > desegment_len = DESEGMENT_ONE_MORE_SEGMENT ;
2016-01-06 22:25:09 +00:00
return tvb_captured_length ( tvb ) ;
2014-10-02 21:47:19 +00:00
}
2008-07-25 13:36:58 +00:00
}
2008-07-25 13:20:18 +00:00
2010-05-14 21:54:48 +00:00
2009-07-10 21:54:29 +00:00
/* Passing this point, we should always have tlen >= 6 */
pdu_len = tvb_get_ntohl ( tvb , 2 ) ;
2018-05-06 15:33:51 +00:00
if ( pdu_len < 4 ) /* The smallest PDUs are ASSOC Rejects & Release messages */
2014-10-02 21:47:19 +00:00
return 0 ;
2009-07-10 21:54:29 +00:00
2008-10-11 14:25:02 +00:00
/* Mark it. This is a DICOM packet */
2009-08-09 07:59:51 +00:00
col_set_str ( pinfo - > cinfo , COL_PROTOCOL , " DICOM " ) ;
2008-07-25 13:20:18 +00:00
/* Process all PDUs in the buffer */
while ( pdu_start < tlen ) {
2014-10-02 21:47:19 +00:00
guint32 old_pdu_start ;
if ( ( pdu_len + 6 ) > ( tlen - offset ) ) {
/* PDU is larger than the remaining packet (buffer), therefore request whole PDU
The next time this function is called , tlen will be equal to pdu_len
*/
pinfo - > desegment_offset = offset ;
pinfo - > desegment_len = ( pdu_len + 6 ) - ( tlen - offset ) ;
2016-01-06 22:25:09 +00:00
return tvb_captured_length ( tvb ) ;
2014-10-02 21:47:19 +00:00
}
/* Process a whole PDU */
offset = dissect_dcm_pdu ( tvb , pinfo , tree , pdu_start ) ;
/* Next PDU */
old_pdu_start = pdu_start ;
pdu_start = pdu_start + pdu_len + 6 ;
if ( pdu_start < = old_pdu_start ) {
expert_add_info_format ( pinfo , NULL , & ei_dcm_invalid_pdu_length , " Invalid PDU length (%u) " , pdu_len ) ;
2016-01-06 22:19:59 +00:00
break ;
2014-10-02 21:47:19 +00:00
}
if ( pdu_start < tlen - 6 ) {
/* we got at least 6 bytes of the next PDU still in the buffer */
pdu_len = tvb_get_ntohl ( tvb , pdu_start + 2 ) ;
}
else {
pdu_len = 0 ;
}
2008-07-25 13:20:18 +00:00
}
return offset ;
2004-05-08 08:49:02 +00:00
}
2018-05-06 15:33:51 +00:00
/*
2019-02-11 11:27:19 +00:00
Callback function used to register
2018-05-06 15:33:51 +00:00
*/
2008-07-25 13:20:18 +00:00
static int
2012-09-10 21:40:21 +00:00
dissect_dcm_static ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree , void * data _U_ )
2008-07-25 13:20:18 +00:00
{
/* Less checking on ports that match */
2009-07-10 21:54:29 +00:00
return dissect_dcm_main ( tvb , pinfo , tree , TRUE ) ;
2008-07-25 13:20:18 +00:00
}
2018-05-06 15:33:51 +00:00
/*
Test for an Association Request . Decode , when successful .
*/
static gboolean
2012-09-10 21:40:21 +00:00
dissect_dcm_heuristic ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree , void * data _U_ )
2008-07-25 13:20:18 +00:00
{
2018-05-06 15:33:51 +00:00
2008-07-25 13:20:18 +00:00
/* This will be potentially called for every packet */
2018-05-06 15:33:51 +00:00
if ( ! test_dcm ( tvb ) )
return FALSE ;
/*
Conversation_set_dissector ( ) is called inside dcm_state_get ( ) once
we have enough details . From there on , we will be ' static '
*/
if ( dissect_dcm_main ( tvb , pinfo , tree , FALSE ) = = 0 ) {
/* there may have been another reason why it is not DICOM */
return FALSE ;
}
return TRUE ;
2008-07-25 13:20:18 +00:00
}
2019-02-18 14:53:06 +00:00
/*
Only set a valued with col_set_str ( ) if it does not yet exist .
( In a multiple PDV scenario , col_set_str ( ) actually appends for the subsequent calls )
*/
2019-06-06 08:47:47 +00:00
static void col_set_str_conditional ( column_info * cinfo , const gint el , const gchar * str )
2019-02-18 14:53:06 +00:00
{
2019-05-16 18:48:15 +00:00
const char * col_string = col_get_text ( cinfo , el ) ;
if ( col_string = = NULL | | ! g_str_has_prefix ( col_string , str ) )
2019-02-18 14:53:06 +00:00
{
col_add_str ( cinfo , el , str ) ;
}
}
/*
CSV add a value to a column , if it does not exist yet
*/
2019-06-06 08:47:47 +00:00
static void col_append_str_conditional ( column_info * cinfo , const gint el , const gchar * str )
2019-02-18 14:53:06 +00:00
{
2019-05-16 18:48:15 +00:00
const char * col_string = col_get_text ( cinfo , el ) ;
if ( col_string = = NULL | | ! g_strrstr ( col_string , str ) )
2019-02-18 14:53:06 +00:00
{
col_append_fstr ( cinfo , el , " , %s " , str ) ;
}
}
2018-03-05 10:54:55 +00:00
/*
2018-05-06 15:33:51 +00:00
Dissect a single DICOM PDU . Can be an association or a data package . Creates a tree item .
2018-03-05 10:54:55 +00:00
*/
2008-10-11 14:25:02 +00:00
static guint32
dissect_dcm_pdu ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree , guint32 offset )
2004-05-08 08:49:02 +00:00
{
2014-10-02 21:47:19 +00:00
proto_tree * dcm_ptree = NULL ; /* Root DICOM tree and its item */
2010-08-09 19:28:09 +00:00
proto_item * dcm_pitem = NULL ;
2008-07-25 13:36:58 +00:00
2014-10-02 21:47:19 +00:00
dcm_state_t * dcm_data = NULL ;
2008-07-25 13:36:58 +00:00
dcm_state_assoc_t * assoc = NULL ;
guint8 pdu_type = 0 ;
guint32 pdu_len = 0 ;
2008-07-25 13:20:18 +00:00
2008-10-11 14:25:02 +00:00
gchar * pdu_data_description = NULL ;
2008-07-25 13:20:18 +00:00
2011-12-27 17:34:01 +00:00
/* Get or create conversation. Used to store context IDs and xfer Syntax */
2008-07-25 13:20:18 +00:00
2008-07-25 13:36:58 +00:00
dcm_data = dcm_state_get ( pinfo , TRUE ) ;
2018-05-06 15:33:51 +00:00
if ( dcm_data = = NULL ) { /* Internal error. Failed to create main DICOM data structure */
2014-10-02 21:47:19 +00:00
return offset ;
2008-07-25 13:20:18 +00:00
}
2004-05-08 08:49:02 +00:00
2011-10-21 02:10:19 +00:00
dcm_pitem = proto_tree_add_item ( tree , proto_dcm , tvb , offset , - 1 , ENC_NA ) ;
2010-08-09 19:28:09 +00:00
dcm_ptree = proto_item_add_subtree ( dcm_pitem , ett_dcm ) ;
2008-07-25 13:36:58 +00:00
2018-03-05 10:54:55 +00:00
/* PDU type is only one byte, then one byte reserved */
2008-07-25 13:20:18 +00:00
pdu_type = tvb_get_guint8 ( tvb , offset ) ;
2018-03-05 10:54:55 +00:00
proto_tree_add_item ( dcm_ptree , hf_dcm_pdu_type , tvb , offset , 1 , ENC_BIG_ENDIAN ) ;
2010-08-09 19:28:09 +00:00
offset + = 2 ;
2004-05-08 08:49:02 +00:00
2010-08-09 19:28:09 +00:00
pdu_len = tvb_get_ntohl ( tvb , offset ) ;
2011-10-06 03:35:44 +00:00
proto_tree_add_item ( dcm_ptree , hf_dcm_pdu_len , tvb , offset , 4 , ENC_BIG_ENDIAN ) ;
2010-08-09 19:28:09 +00:00
offset + = 4 ;
2008-07-25 13:20:18 +00:00
2010-08-09 19:28:09 +00:00
/* Find previously detected association, else create a new one object*/
2016-01-24 03:40:51 +00:00
assoc = dcm_state_assoc_get ( dcm_data , pinfo - > num , TRUE ) ;
2008-10-11 14:25:02 +00:00
2014-10-02 21:47:19 +00:00
if ( assoc = = NULL ) { /* Internal error. Failed to create association structure */
return offset ;
2008-10-11 14:25:02 +00:00
}
2004-05-08 08:49:02 +00:00
2010-08-09 19:28:09 +00:00
if ( pdu_type = = 4 ) {
2019-02-18 14:53:06 +00:00
col_set_str_conditional ( pinfo - > cinfo , COL_INFO , " P-DATA " ) ;
2008-07-25 13:20:18 +00:00
2019-02-11 11:27:19 +00:00
/* Everything that needs to be shown in any UI column (like COL_INFO)
needs to be calculated also with tree = = null
*/
2014-10-02 21:47:19 +00:00
offset = dissect_dcm_pdu_data ( tvb , pinfo , dcm_ptree , assoc , offset , pdu_len , & pdu_data_description ) ;
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
if ( pdu_data_description ) {
proto_item_append_text ( dcm_pitem , " , %s " , pdu_data_description ) ;
2019-02-18 14:53:06 +00:00
col_append_str_conditional ( pinfo - > cinfo , COL_INFO , pdu_data_description ) ;
2014-10-02 21:47:19 +00:00
}
2004-05-08 08:49:02 +00:00
}
2010-08-09 19:28:09 +00:00
else {
2004-05-08 08:49:02 +00:00
2014-10-02 21:47:19 +00:00
/* Decode Association request, response, reject, abort details */
2010-08-09 19:28:09 +00:00
offset = dissect_dcm_assoc_header ( tvb , pinfo , dcm_ptree , offset , assoc , pdu_type , pdu_len ) ;
}
2008-07-25 13:20:18 +00:00
2014-10-02 21:47:19 +00:00
return offset ; /* return the number of processed bytes */
2004-05-08 08:49:02 +00:00
}
2019-02-18 14:53:06 +00:00
2019-02-11 11:27:19 +00:00
/*
Register the protocol with Wireshark
*/
2004-05-08 08:49:02 +00:00
void
proto_register_dcm ( void )
2008-07-25 13:20:18 +00:00
{
static hf_register_info hf [ ] = {
2018-03-05 10:54:55 +00:00
{ & hf_dcm_pdu_type , { " PDU Type " , " dicom.pdu.type " ,
2014-10-02 21:47:19 +00:00
FT_UINT8 , BASE_HEX , VALS ( dcm_pdu_ids ) , 0 , NULL , HFILL } } ,
2008-07-25 13:20:18 +00:00
{ & hf_dcm_pdu_len , { " PDU Length " , " dicom.pdu.len " ,
2014-10-02 21:47:19 +00:00
FT_UINT32 , BASE_DEC , NULL , 0 , NULL , HFILL } } ,
2010-08-09 19:28:09 +00:00
{ & hf_dcm_assoc_version , { " Protocol Version " , " dicom.assoc.version " ,
2014-10-02 21:47:19 +00:00
FT_UINT16 , BASE_DEC , NULL , 0 , NULL , HFILL } } ,
2010-08-09 19:28:09 +00:00
{ & hf_dcm_assoc_called , { " Called AE Title " , " dicom.assoc.ae.called " ,
2014-10-02 21:47:19 +00:00
FT_STRING , BASE_NONE , NULL , 0 , NULL , HFILL } } ,
2010-08-09 19:28:09 +00:00
{ & hf_dcm_assoc_calling , { " Calling AE Title " , " dicom.assoc.ae.calling " ,
2014-10-02 21:47:19 +00:00
FT_STRING , BASE_NONE , NULL , 0 , NULL , HFILL } } ,
2010-08-09 19:28:09 +00:00
{ & hf_dcm_assoc_reject_result , { " Result " , " dicom.assoc.reject.result " ,
2014-10-02 21:47:19 +00:00
FT_UINT8 , BASE_DEC , NULL , 0 , NULL , HFILL } } ,
2010-08-09 19:28:09 +00:00
{ & hf_dcm_assoc_reject_source , { " Source " , " dicom.assoc.reject.source " ,
2014-10-02 21:47:19 +00:00
FT_UINT8 , BASE_DEC , NULL , 0 , NULL , HFILL } } ,
2010-08-09 19:28:09 +00:00
{ & hf_dcm_assoc_reject_reason , { " Reason " , " dicom.assoc.reject.reason " ,
2014-10-02 21:47:19 +00:00
FT_UINT8 , BASE_DEC , NULL , 0 , NULL , HFILL } } ,
2010-08-09 19:28:09 +00:00
{ & hf_dcm_assoc_abort_source , { " Source " , " dicom.assoc.abort.source " ,
2014-10-02 21:47:19 +00:00
FT_UINT8 , BASE_DEC , NULL , 0 , NULL , HFILL } } ,
2010-08-09 19:28:09 +00:00
{ & hf_dcm_assoc_abort_reason , { " Reason " , " dicom.assoc.abort.reason " ,
2014-10-02 21:47:19 +00:00
FT_UINT8 , BASE_DEC , NULL , 0 , NULL , HFILL } } ,
2008-07-25 13:20:18 +00:00
{ & hf_dcm_assoc_item_type , { " Item Type " , " dicom.assoc.item.type " ,
2014-10-02 21:47:19 +00:00
FT_UINT8 , BASE_HEX , VALS ( dcm_assoc_item_type ) , 0 , NULL , HFILL } } ,
2008-07-25 13:36:58 +00:00
{ & hf_dcm_assoc_item_len , { " Item Length " , " dicom.assoc.item.len " ,
2014-10-02 21:47:19 +00:00
FT_UINT16 , BASE_DEC , NULL , 0 , NULL , HFILL } } ,
2010-08-09 19:28:09 +00:00
2008-07-25 13:20:18 +00:00
{ & hf_dcm_actx , { " Application Context " , " dicom.actx " ,
2014-10-02 21:47:19 +00:00
FT_STRING , BASE_NONE , NULL , 0 , NULL , HFILL } } ,
2008-07-25 13:20:18 +00:00
{ & hf_dcm_pctx_id , { " Presentation Context ID " , " dicom.pctx.id " ,
2014-10-02 21:47:19 +00:00
FT_UINT8 , BASE_HEX , NULL , 0 , NULL , HFILL } } ,
2020-09-26 22:14:23 +00:00
{ & hf_dcm_pctx_result , { " Presentation Context Result " , " dicom.pctx.result " ,
2014-10-02 21:47:19 +00:00
FT_UINT8 , BASE_HEX , NULL , 0 , NULL , HFILL } } ,
2008-07-25 13:20:18 +00:00
{ & hf_dcm_pctx_abss_syntax , { " Abstract Syntax " , " dicom.pctx.abss.syntax " ,
2014-10-02 21:47:19 +00:00
FT_STRING , BASE_NONE , NULL , 0 , NULL , HFILL } } ,
2008-07-25 13:20:18 +00:00
{ & hf_dcm_pctx_xfer_syntax , { " Transfer Syntax " , " dicom.pctx.xfer.syntax " ,
2014-10-02 21:47:19 +00:00
FT_STRING , BASE_NONE , NULL , 0 , NULL , HFILL } } ,
2013-02-06 13:33:31 +00:00
{ & hf_dcm_info , { " User Info " , " dicom.userinfo " ,
2014-10-02 21:47:19 +00:00
FT_NONE , BASE_NONE , NULL , 0 , " This field contains the ACSE User Information Item of the A-ASSOCIATErequest. " , HFILL } } ,
2008-07-25 13:20:18 +00:00
{ & hf_dcm_info_uid , { " Implementation Class UID " , " dicom.userinfo.uid " ,
2014-10-02 21:47:19 +00:00
FT_STRING , BASE_NONE , NULL , 0 , NULL , HFILL } } ,
2008-07-25 13:20:18 +00:00
{ & hf_dcm_info_version , { " Implementation Version " , " dicom.userinfo.version " ,
2014-10-02 21:47:19 +00:00
FT_STRING , BASE_NONE , NULL , 0 , NULL , HFILL } } ,
2013-02-06 13:33:31 +00:00
{ & hf_dcm_info_extneg , { " Extended Negotiation " , " dicom.userinfo.extneg " ,
2014-10-02 21:47:19 +00:00
FT_NONE , BASE_NONE , NULL , 0 , " This field contains the optional SOP Class Extended Negotiation Sub-Item of the ACSE User Information Item of the A-ASSOCIATE-RQ/RSP. " , HFILL } } ,
2013-02-06 13:33:31 +00:00
{ & hf_dcm_info_extneg_sopclassuid_len , { " SOP Class UID Length " , " dicom.userinfo.extneg.sopclassuid.len " ,
2014-10-02 21:47:19 +00:00
FT_UINT16 , BASE_DEC , NULL , 0 , " This field contains the length of the SOP Class UID in the Extended Negotiation Sub-Item. " , HFILL } } ,
2013-02-06 13:33:31 +00:00
{ & hf_dcm_info_extneg_sopclassuid , { " SOP Class UID " , " dicom.userinfo.extneg.sopclassuid " ,
2014-10-02 21:47:19 +00:00
FT_STRING , BASE_NONE , NULL , 0 , " This field contains the SOP Class UID in the Extended Negotiation Sub-Item. " , HFILL } } ,
2013-02-06 13:33:31 +00:00
{ & hf_dcm_info_extneg_relational_query , { " Relational-queries " , " dicom.userinfo.extneg.relational " ,
2014-10-02 21:47:19 +00:00
FT_UINT8 , BASE_HEX , NULL , 0 , " This field indicates, if relational queries are supported. " , HFILL } } ,
2013-02-06 13:33:31 +00:00
{ & hf_dcm_info_extneg_date_time_matching , { " Combined Date-Time matching " , " dicom.userinfo.extneg.datetimematching " ,
2014-10-02 21:47:19 +00:00
FT_UINT8 , BASE_HEX , NULL , 0 , " This field indicates, if combined date-time matching is supported. " , HFILL } } ,
2013-02-06 13:33:31 +00:00
{ & hf_dcm_info_extneg_fuzzy_semantic_matching , { " Fuzzy semantic matching " , " dicom.userinfo.extneg.fuzzymatching " ,
2014-10-02 21:47:19 +00:00
FT_UINT8 , BASE_HEX , NULL , 0 , " This field indicates, if fuzzy semantic matching of person names is supported. " , HFILL } } ,
2013-02-06 13:33:31 +00:00
{ & hf_dcm_info_extneg_timezone_query_adjustment , { " Timezone query adjustment " , " dicom.userinfo.extneg.timezone " ,
2014-10-02 21:47:19 +00:00
FT_UINT8 , BASE_HEX , NULL , 0 , " This field indicates, if timezone query adjustment is supported. " , HFILL } } ,
2013-02-17 19:36:08 +00:00
{ & hf_dcm_info_rolesel , { " SCP/SCU Role Selection " , " dicom.userinfo.rolesel " ,
2014-10-02 21:47:19 +00:00
FT_NONE , BASE_NONE , NULL , 0 , " This field contains the optional SCP/SCU Role Selection Sub-Item of the ACSE User Information Item of the A-ASSOCIATE-RQ/RSP. " , HFILL } } ,
2013-02-17 19:36:08 +00:00
{ & hf_dcm_info_rolesel_sopclassuid_len , { " SOP Class UID Length " , " dicom.userinfo.rolesel.sopclassuid.len " ,
2014-10-02 21:47:19 +00:00
FT_UINT16 , BASE_DEC , NULL , 0 , " This field contains the length of the SOP Class UID in the SCP/SCU Role Selection Sub-Item. " , HFILL } } ,
2013-02-17 19:36:08 +00:00
{ & hf_dcm_info_rolesel_sopclassuid , { " SOP Class UID " , " dicom.userinfo.rolesel.sopclassuid " ,
2014-10-02 21:47:19 +00:00
FT_STRING , BASE_NONE , NULL , 0 , " This field contains the SOP Class UID in the SCP/SCU Role Selection Sub-Item. " , HFILL } } ,
2013-02-17 19:36:08 +00:00
{ & hf_dcm_info_rolesel_scurole , { " SCU-role " , " dicom.userinfo.rolesel.scurole " ,
2014-10-02 21:47:19 +00:00
FT_UINT8 , BASE_HEX , NULL , 0 , " This field contains the SCU-role as defined for the Association-requester. " , HFILL } } ,
2013-02-17 19:36:08 +00:00
{ & hf_dcm_info_rolesel_scprole , { " SCP-role " , " dicom.userinfo.rolesel.scprole " ,
2014-10-02 21:47:19 +00:00
FT_UINT8 , BASE_HEX , NULL , 0 , " This field contains the SCP-role as defined for the Association-requester. " , HFILL } } ,
2013-02-17 19:36:08 +00:00
{ & hf_dcm_info_async_neg , { " Asynchronous Operations (and sub-operations) Window Negotiation " , " dicom.userinfo.asyncneg " ,
2014-10-02 21:47:19 +00:00
FT_NONE , BASE_NONE , NULL , 0 , " This field contains the optional Asynchronous Operations (and sub-operations) Window Negotiation Sub-Item of the ACSE User Information Item of the A-ASSOCIATE-RQ/RSP. " , HFILL } } ,
2013-02-17 19:36:08 +00:00
{ & hf_dcm_info_async_neg_max_num_ops_inv , { " Maximum-number-operations-invoked " , " dicom.userinfo.asyncneg.maxnumopsinv " ,
2014-10-02 21:47:19 +00:00
FT_UINT16 , BASE_DEC , NULL , 0 , " This field contains the maximum-number-operations-invoked in the Asynchronous Operations (and sub-operations) Window Negotiation Sub-Item. " , HFILL } } ,
2013-02-17 19:36:08 +00:00
{ & hf_dcm_info_async_neg_max_num_ops_per , { " Maximum-number-operations-performed " , " dicom.userinfo.asyncneg.maxnumopsper " ,
2014-10-02 21:47:19 +00:00
FT_UINT16 , BASE_DEC , NULL , 0 , " This field contains the maximum-number-operations-performed in the Asynchronous Operations (and sub-operations) Window Negotiation Sub-Item. " , HFILL } } ,
2017-07-19 11:47:03 +00:00
{ & hf_dcm_info_unknown , { " Unknown " , " dicom.userinfo.unknown " ,
FT_NONE , BASE_NONE , NULL , 0 , NULL , HFILL } } ,
{ & hf_dcm_assoc_item_data , { " Unknown Data " , " dicom.userinfo.data " ,
FT_BYTES , BASE_NONE , NULL , 0 , NULL , HFILL } } ,
2017-07-19 13:00:22 +00:00
{ & hf_dcm_info_user_identify , { " User Identify " , " dicom.userinfo.user_identify " ,
FT_NONE , BASE_NONE , NULL , 0 , NULL , HFILL } } ,
{ & hf_dcm_info_user_identify_type , { " Type " , " dicom.userinfo.user_identify.type " ,
FT_UINT8 , BASE_DEC , VALS ( user_identify_type_vals ) , 0 , NULL , HFILL } } ,
{ & hf_dcm_info_user_identify_response_requested , { " Response Requested " , " dicom.userinfo.user_identify.response_requested " ,
FT_UINT8 , BASE_DEC , NULL , 0 , NULL , HFILL } } ,
{ & hf_dcm_info_user_identify_primary_field_length , { " Primary Field Length " , " dicom.userinfo.user_identify.primary_field_length " ,
FT_UINT16 , BASE_DEC , NULL , 0 , NULL , HFILL } } ,
{ & hf_dcm_info_user_identify_primary_field , { " Primary Field " , " dicom.userinfo.user_identify.primary_field " ,
FT_STRING , BASE_NONE , NULL , 0 , NULL , HFILL } } ,
{ & hf_dcm_info_user_identify_secondary_field_length , { " Secondary Field Length " , " dicom.userinfo.user_identify.secondary_field_length " ,
FT_UINT16 , BASE_DEC , NULL , 0 , NULL , HFILL } } ,
{ & hf_dcm_info_user_identify_secondary_field , { " Secondary Field " , " dicom.userinfo.user_identify.secondary_field " ,
FT_STRING , BASE_NONE , NULL , 0 , NULL , HFILL } } ,
2008-07-25 13:36:58 +00:00
{ & hf_dcm_pdu_maxlen , { " Max PDU Length " , " dicom.max_pdu_len " ,
2014-10-02 21:47:19 +00:00
FT_UINT32 , BASE_DEC , NULL , 0 , NULL , HFILL } } ,
2008-07-25 13:20:18 +00:00
{ & hf_dcm_pdv_len , { " PDV Length " , " dicom.pdv.len " ,
2014-10-02 21:47:19 +00:00
FT_UINT32 , BASE_DEC , NULL , 0 , NULL , HFILL } } ,
2008-07-25 13:20:18 +00:00
{ & hf_dcm_pdv_ctx , { " PDV Context " , " dicom.pdv.ctx " ,
2014-10-02 21:47:19 +00:00
FT_UINT8 , BASE_DEC , NULL , 0 , NULL , HFILL } } ,
2008-07-25 13:20:18 +00:00
{ & hf_dcm_pdv_flags , { " PDV Flags " , " dicom.pdv.flags " ,
2014-10-02 21:47:19 +00:00
FT_UINT8 , BASE_HEX , NULL , 0 , NULL , HFILL } } ,
2008-07-25 13:20:18 +00:00
{ & hf_dcm_data_tag , { " Tag " , " dicom.data.tag " ,
2014-10-02 21:47:19 +00:00
FT_BYTES , BASE_NONE , NULL , 0 , NULL , HFILL } } ,
2008-10-11 14:25:02 +00:00
{ & hf_dcm_tag , { " Tag " , " dicom.tag " ,
2014-10-02 21:47:19 +00:00
FT_UINT32 , BASE_HEX , NULL , 0 , NULL , HFILL } } ,
2008-10-11 14:25:02 +00:00
{ & hf_dcm_tag_vr , { " VR " , " dicom.tag.vr " ,
2014-10-02 21:47:19 +00:00
FT_STRING , BASE_NONE , NULL , 0 , NULL , HFILL } } ,
2008-12-18 19:08:49 +00:00
{ & hf_dcm_tag_vl , { " Length " , " dicom.tag.vl " ,
2014-10-02 21:47:19 +00:00
FT_UINT32 , BASE_DEC , NULL , 0 , NULL , HFILL } } ,
2008-10-11 14:25:02 +00:00
{ & hf_dcm_tag_value_str , { " Value " , " dicom.tag.value.str " ,
2014-10-02 21:47:19 +00:00
FT_STRING , BASE_NONE , NULL , 0 , NULL , HFILL } } ,
2010-05-14 21:54:48 +00:00
{ & hf_dcm_tag_value_16s , { " Value " , " dicom.tag.value.16s " ,
2014-10-02 21:47:19 +00:00
FT_INT16 , BASE_DEC , NULL , 0 , NULL , HFILL } } ,
2010-05-14 21:54:48 +00:00
{ & hf_dcm_tag_value_16u , { " Value " , " dicom.tag.value.16u " ,
2014-10-02 21:47:19 +00:00
FT_UINT16 , BASE_DEC , NULL , 0 , NULL , HFILL } } ,
2010-05-14 21:54:48 +00:00
{ & hf_dcm_tag_value_32s , { " Value " , " dicom.tag.value.32s " ,
2014-10-02 21:47:19 +00:00
FT_INT32 , BASE_DEC , NULL , 0 , NULL , HFILL } } ,
2010-05-14 21:54:48 +00:00
{ & hf_dcm_tag_value_32u , { " Value " , " dicom.tag.value.32u " ,
2014-10-02 21:47:19 +00:00
FT_UINT32 , BASE_DEC , NULL , 0 , NULL , HFILL } } ,
2008-10-11 14:25:02 +00:00
{ & hf_dcm_tag_value_byte , { " Value " , " dicom.tag.value.byte " ,
2014-10-02 21:47:19 +00:00
FT_BYTES , BASE_NONE , NULL , 0 , NULL , HFILL } } ,
2010-08-09 19:28:09 +00:00
/* Fragment entries */
{ & hf_dcm_pdv_fragments ,
2014-10-02 21:47:19 +00:00
{ " Message fragments " , " dicom.pdv.fragments " ,
FT_NONE , BASE_NONE , NULL , 0x00 , NULL , HFILL } } ,
2010-08-09 19:28:09 +00:00
{ & hf_dcm_pdv_fragment ,
2014-10-02 21:47:19 +00:00
{ " Message fragment " , " dicom.pdv.fragment " ,
FT_FRAMENUM , BASE_NONE , NULL , 0x00 , NULL , HFILL } } ,
2010-08-09 19:28:09 +00:00
{ & hf_dcm_pdv_fragment_overlap ,
2014-10-02 21:47:19 +00:00
{ " Message fragment overlap " , " dicom.pdv.fragment.overlap " ,
FT_BOOLEAN , BASE_NONE , NULL , 0x00 , NULL , HFILL } } ,
2010-08-09 19:28:09 +00:00
{ & hf_dcm_pdv_fragment_overlap_conflicts ,
2014-10-02 21:47:19 +00:00
{ " Message fragment overlapping with conflicting data " ,
" dicom.pdv.fragment.overlap.conflicts " ,
FT_BOOLEAN , BASE_NONE , NULL , 0x00 , NULL , HFILL } } ,
2010-08-09 19:28:09 +00:00
{ & hf_dcm_pdv_fragment_multiple_tails ,
2014-10-02 21:47:19 +00:00
{ " Message has multiple tail fragments " ,
" dicom.pdv.fragment.multiple_tails " ,
FT_BOOLEAN , BASE_NONE , NULL , 0x00 , NULL , HFILL } } ,
2010-08-09 19:28:09 +00:00
{ & hf_dcm_pdv_fragment_too_long_fragment ,
2014-10-02 21:47:19 +00:00
{ " Message fragment too long " , " dicom.pdv.fragment.too_long_fragment " ,
FT_BOOLEAN , BASE_NONE , NULL , 0x00 , NULL , HFILL } } ,
2010-08-09 19:28:09 +00:00
{ & hf_dcm_pdv_fragment_error ,
2014-10-02 21:47:19 +00:00
{ " Message defragmentation error " , " dicom.pdv.fragment.error " ,
FT_FRAMENUM , BASE_NONE , NULL , 0x00 , NULL , HFILL } } ,
2011-01-30 21:01:07 +00:00
{ & hf_dcm_pdv_fragment_count ,
2014-10-02 21:47:19 +00:00
{ " Message fragment count " , " dicom.pdv.fragment_count " ,
FT_UINT32 , BASE_DEC , NULL , 0x00 , NULL , HFILL } } ,
2010-08-09 19:28:09 +00:00
{ & hf_dcm_pdv_reassembled_in ,
2014-10-02 21:47:19 +00:00
{ " Reassembled in " , " dicom.pdv.reassembled.in " ,
FT_FRAMENUM , BASE_NONE , NULL , 0x00 , NULL , HFILL } } ,
2010-08-09 19:28:09 +00:00
{ & hf_dcm_pdv_reassembled_length ,
2014-10-02 21:47:19 +00:00
{ " Reassembled PDV length " , " dicom.pdv.reassembled.length " ,
FT_UINT32 , BASE_DEC , NULL , 0x00 , NULL , HFILL } }
2004-05-08 08:49:02 +00:00
} ;
/* Setup protocol subtree array */
static gint * ett [ ] = {
2014-10-02 21:47:19 +00:00
& ett_dcm ,
& ett_assoc ,
& ett_assoc_header ,
& ett_assoc_actx ,
& ett_assoc_pctx ,
& ett_assoc_pctx_abss ,
& ett_assoc_pctx_xfer ,
& ett_assoc_info ,
& ett_assoc_info_uid ,
& ett_assoc_info_version ,
& ett_assoc_info_extneg ,
& ett_assoc_info_rolesel ,
& ett_assoc_info_async_neg ,
2017-07-19 13:00:22 +00:00
& ett_assoc_info_user_identify ,
2017-07-19 11:47:03 +00:00
& ett_assoc_info_unknown ,
2014-10-02 21:47:19 +00:00
& ett_dcm_data ,
& ett_dcm_data_pdv ,
& ett_dcm_data_tag ,
& ett_dcm_data_seq ,
& ett_dcm_data_item ,
& ett_dcm_pdv , /* used for fragments */
& ett_dcm_pdv_fragment ,
& ett_dcm_pdv_fragments
2004-05-08 08:49:02 +00:00
} ;
2013-09-07 16:07:02 +00:00
static ei_register_info ei [ ] = {
{ & ei_dcm_assoc_rejected , { " dicom.assoc.reject " , PI_RESPONSE_CODE , PI_WARN , " Association rejected " , EXPFILL } } ,
{ & ei_dcm_assoc_aborted , { " dicom.assoc.abort " , PI_RESPONSE_CODE , PI_WARN , " Association aborted " , EXPFILL } } ,
{ & ei_dcm_no_abstract_syntax , { " dicom.no_abstract_syntax " , PI_MALFORMED , PI_ERROR , " No Abstract Syntax provided for this Presentation Context " , EXPFILL } } ,
{ & ei_dcm_multiple_abstract_syntax , { " dicom.multiple_abstract_syntax " , PI_MALFORMED , PI_ERROR , " More than one Abstract Syntax provided for this Presentation Context " , EXPFILL } } ,
{ & ei_dcm_no_transfer_syntax , { " dicom.no_transfer_syntax " , PI_MALFORMED , PI_ERROR , " No Transfer Syntax provided for this Presentation Context " , EXPFILL } } ,
{ & ei_dcm_no_abstract_syntax_uid , { " dicom.no_abstract_syntax_uid " , PI_MALFORMED , PI_ERROR , " No Abstract Syntax UID found for this Presentation Context " , EXPFILL } } ,
{ & ei_dcm_multiple_transfer_syntax , { " dicom.multiple_transfer_syntax " , PI_MALFORMED , PI_ERROR , " Only one Transfer Syntax allowed in a Association Response " , EXPFILL } } ,
{ & ei_dcm_assoc_item_len , { " dicom.assoc.item.len.invalid " , PI_MALFORMED , PI_ERROR , " Invalid Association Item Length " , EXPFILL } } ,
{ & ei_dcm_pdv_ctx , { " dicom.pdv.ctx.invalid " , PI_MALFORMED , PI_ERROR , " Invalid Presentation Context ID " , EXPFILL } } ,
{ & ei_dcm_pdv_flags , { " dicom.pdv.flags.invalid " , PI_MALFORMED , PI_ERROR , " Invalid Flags " , EXPFILL } } ,
{ & ei_dcm_status_msg , { " dicom.status_msg " , PI_RESPONSE_CODE , PI_WARN , " %s " , EXPFILL } } ,
{ & ei_dcm_data_tag , { " dicom.data.tag.missing " , PI_MALFORMED , PI_ERROR , " Early termination of tag. Data is missing " , EXPFILL } } ,
{ & ei_dcm_pdv_len , { " dicom.pdv.len.invalid " , PI_MALFORMED , PI_ERROR , " Invalid PDV length " , EXPFILL } } ,
{ & ei_dcm_invalid_pdu_length , { " dicom.pdu_length.invalid " , PI_MALFORMED , PI_ERROR , " Invalid PDU length " , EXPFILL } } ,
} ;
2008-07-25 13:20:18 +00:00
module_t * dcm_module ;
2013-09-07 16:07:02 +00:00
expert_module_t * expert_dcm ;
2008-07-25 13:20:18 +00:00
/* Register the protocol name and description */
proto_dcm = proto_register_protocol ( " DICOM " , " DICOM " , " dicom " ) ;
/* Required function calls to register the header fields and subtrees used */
2004-05-08 08:49:02 +00:00
proto_register_field_array ( proto_dcm , hf , array_length ( hf ) ) ;
proto_register_subtree_array ( ett , array_length ( ett ) ) ;
2013-09-07 16:07:02 +00:00
expert_dcm = expert_register_protocol ( proto_dcm ) ;
expert_register_field_array ( expert_dcm , ei , array_length ( ei ) ) ;
2004-05-08 08:49:02 +00:00
2014-09-08 15:50:41 +00:00
/* Allow other dissectors to find this one by name. */
2016-01-13 01:16:04 +00:00
dcm_handle = register_dissector ( " dicom " , dissect_dcm_static , proto_dcm ) ;
2014-09-08 15:50:41 +00:00
2016-10-07 20:25:01 +00:00
dcm_module = prefs_register_protocol ( proto_dcm , NULL ) ;
2008-07-25 13:20:18 +00:00
2018-05-06 15:33:51 +00:00
/* Used to migrate an older configuration file to a newer one */
2015-07-13 00:40:31 +00:00
prefs_register_obsolete_preference ( dcm_module , " heuristic " ) ;
2008-07-25 13:20:18 +00:00
2008-10-11 14:25:02 +00:00
prefs_register_bool_preference ( dcm_module , " export_header " ,
2014-10-02 21:47:19 +00:00
" Create Meta Header on Export " ,
" Create DICOM File Meta Header according to PS 3.10 on export for PDUs. "
" If the captured PDV does not contain a SOP Class UID and SOP Instance UID "
" (e.g. for command PDVs), wireshark specific ones will be created. " ,
& global_dcm_export_header ) ;
2008-10-11 14:25:02 +00:00
prefs_register_uint_preference ( dcm_module , " export_minsize " ,
2014-10-02 21:47:19 +00:00
" Min. item size in bytes to export " ,
" Do not show items below this size in the export list. "
" Set it to 0, to see DICOM commands and responses in the list. "
" Set it higher, to just export DICOM IODs (i.e. CT Images, RT Structures). " , 10 ,
& global_dcm_export_minsize ) ;
2008-10-11 14:25:02 +00:00
prefs_register_bool_preference ( dcm_module , " seq_tree " ,
2014-10-02 21:47:19 +00:00
" Create subtrees for Sequences and Items " ,
" Create a node for sequences and items, and show children in a hierarchy. "
2019-02-11 11:27:19 +00:00
" De-select this option, if you prefer a flat display or e.g. "
2014-10-02 21:47:19 +00:00
" when using TShark to create a text output. " ,
& global_dcm_seq_subtree ) ;
2008-10-11 14:25:02 +00:00
prefs_register_bool_preference ( dcm_module , " tag_tree " ,
2014-10-02 21:47:19 +00:00
" Create subtrees for DICOM Tags " ,
" Create a node for a tag and show tag details as single elements. "
" This can be useful to debug a tag and to allow display filters on these attributes. "
" When using TShark to create a text output, it's better to have it disabled. " ,
& global_dcm_tag_subtree ) ;
2008-07-25 13:36:58 +00:00
2009-05-18 06:21:22 +00:00
prefs_register_bool_preference ( dcm_module , " cmd_details " ,
2014-10-02 21:47:19 +00:00
" Show command details in header " ,
" Show message ID and number of completed, remaining, warned or failed operations in header and info column. " ,
& global_dcm_cmd_details ) ;
2009-05-18 06:21:22 +00:00
2010-08-09 19:28:09 +00:00
prefs_register_bool_preference ( dcm_module , " pdv_reassemble " ,
2014-10-02 21:47:19 +00:00
" Merge fragmented PDVs " ,
" Decode all DICOM tags in the last PDV. This will ensure the proper reassembly. "
2019-02-11 11:27:19 +00:00
" De-select, to troubleshoot PDU length issues, or to understand PDV fragmentation. "
2014-10-02 21:47:19 +00:00
" When not set, the decoding may fail and the exports may become corrupt. " ,
& global_dcm_reassemble ) ;
2010-08-09 19:28:09 +00:00
2016-11-24 14:37:01 +00:00
dicom_eo_tap = register_export_object ( proto_dcm , dcm_eo_packet , NULL ) ;
2008-07-25 13:36:58 +00:00
2004-05-08 08:49:02 +00:00
register_init_routine ( & dcm_init ) ;
2017-02-25 00:46:49 +00:00
2017-01-29 00:53:36 +00:00
/* Register processing of fragmented DICOM PDVs */
2018-05-06 15:33:51 +00:00
reassembly_table_register ( & dcm_pdv_reassembly_table , & addresses_reassembly_table_functions ) ;
2017-01-29 00:53:36 +00:00
2004-05-08 08:49:02 +00:00
}
2018-05-06 15:33:51 +00:00
/*
Register static TCP port range specified in preferences .
Register heuristic search as well .
Statically defined ports take precedence over a heuristic one . I . e . , if a foreign protocol claims a port ,
where DICOM is running on , we would never be called , by just having the heuristic registration .
This function is also called , when preferences change .
*/
2004-05-08 08:49:02 +00:00
void
proto_reg_handoff_dcm ( void )
{
2018-05-06 15:33:51 +00:00
/* Adds a UI element to the preferences dialog. This is the static part. */
2016-10-07 20:25:01 +00:00
dissector_add_uint_range_with_preference ( " tcp.port " , DICOM_DEFAULT_RANGE , dcm_handle ) ;
2008-07-25 13:20:18 +00:00
2018-05-06 15:33:51 +00:00
/*
The following shows up as child protocol of ' DICOM ' in ' Enable / Disable Protocols . . . '
The registration procedure for dissectors is a two - stage procedure .
In stage 1 , dissectors create tables in which other dissectors can register them . That ' s the stage in which proto_register_ routines are called .
In stage 2 , dissectors register themselves in tables created in stage 1. That ' s the stage in which proto_reg_handoff_ routines are called .
heur_dissector_add ( ) needs to be called in proto_reg_handoff_dcm ( ) function .
*/
heur_dissector_add ( " tcp " , dissect_dcm_heuristic , " DICOM on any TCP port (heuristic) " , " dicom_tcp " , proto_dcm , HEURISTIC_ENABLE ) ;
2004-05-08 08:49:02 +00:00
}
2008-07-25 13:20:18 +00:00
/*
2004-05-08 08:49:02 +00:00
PDU ' s
01 ASSOC - RQ
1 1 reserved
2 4 length
6 2 protocol version ( 0x0 0x1 )
8 2 reserved
10 16 dest aetitle
26 16 src aetitle
2008-07-25 13:20:18 +00:00
42 32 reserved
2004-05-08 08:49:02 +00:00
74 - presentation data value items
02 A - ASSOC - AC
1 reserved
4 length
2 protocol version ( 0x0 0x1 )
2 reserved
16 dest aetitle ( not checked )
16 src aetitle ( not checked )
2008-07-25 13:20:18 +00:00
32 reserved
2004-05-08 08:49:02 +00:00
- presentation data value items
03 ASSOC - RJ
1 reserved
4 length ( 4 )
1 reserved
1 result ( 1 reject perm , 2 reject transient )
2011-12-27 17:34:01 +00:00
1 source ( 1 service user , 2 service provider , 3 service provider )
2004-05-08 08:49:02 +00:00
1 reason
2014-10-02 21:47:19 +00:00
1 = = source
1 no reason given
2 application context name not supported
3 calling aetitle not recognized
7 called aetitle not recognized
2 = = source
1 no reason given
2 protocol version not supported
3 = = source
1 temporary congestion
2 local limit exceeded
2004-05-08 08:49:02 +00:00
2010-08-09 19:28:09 +00:00
04 P - DATA
2004-05-08 08:49:02 +00:00
1 1 reserved
2 4 length
- ( 1 + ) presentation data value ( PDV ) items
6 4 length
10 1 Presentation Context ID ( odd ints 1 - 255 )
2014-10-02 21:47:19 +00:00
- PDV
2008-07-25 13:20:18 +00:00
11 1 header
2014-10-02 21:47:19 +00:00
0x01 if set , contains Message Command info , else Message Data
0x02 if set , contains last fragment
2004-05-08 08:49:02 +00:00
05 A - RELEASE - RQ
1 reserved
4 length ( 4 )
4 reserved
06 A - RELEASE - RP
1 reserved
4 length ( 4 )
4 reserved
07 A - ABORT
1 reserved
4 length ( 4 )
2 reserved
1 source ( 0 = user , 1 = provider )
1 reason if 1 = = source ( 0 not spec , 1 unrecognized , 2 unexpected 4 unrecognized param , 5 unexpected param , 6 invalid param )
ITEM ' s
10 Application Context
1 reserved
2 length
- name
20 Presentation Context
1 reserved
2 length
1 Presentation context id
3 reserved
- ( 1 ) abstract and ( 1 + ) transfer syntax sub - items
21 Presentation Context ( Reply )
1 reserved
2 length
1 ID ( odd int ' s 1 - 255 )
1 reserved
1 result ( 0 accept , 1 user - reject , 2 no - reason , 3 abstract not supported , 4 - transfer syntax not supported )
1 reserved
- ( 1 ) type 40
2008-07-25 13:20:18 +00:00
30 Abstract syntax
2004-05-08 08:49:02 +00:00
1 reserved
2 length
- name ( < = 64 )
40 Transfer syntax
1 reserved
2 length
- name ( < = 64 )
50 user information
1 reserved
2 length
- user data
51 max length
1 reserved
2 length ( 4 )
4 max PDU lengths
2008-07-25 13:20:18 +00:00
From 3.7 Annex D Association Negotiation
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
52 IMPLEMENTATION CLASS UID
1 Item - type 52 H
1 Reserved
2 Item - length
n Implementation - class - uid
55 IMPLEMENTATION VERSION NAME
1 Item - type 55 H
1 Reserved
2 Item - length
n Implementation - version - name
53 ASYNCHRONOUS OPERATIONS WINDOW
1 Item - type 53 H
1 Reserved
2 Item - length
2 Maximum - number - operations - invoked
2 Maximum - number - operations - performed
54 SCP / SCU ROLE SELECTION
1 Item - type 54 H
1 Reserved
2 Item - length ( n )
2 UID - length ( m )
m SOP - class - uid
1 SCU - role
0 - non support of the SCU role
1 - support of the SCU role
1 SCP - role
0 - non support of the SCP role
1 - support of the SCP role .
56 SOP CLASS EXTENDED NEGOTIATION
1 Item - type 56 H
1 Reserved
2 Item - Length ( n )
2 SOP - class - uid - length ( m )
m SOP - class - uid
n - m Service - class - application - information
57 SOP CLASS COMMON EXTENDED NEGOTIATION
1 Item - type 57 H
1 Sub - item - version
2 Item - Length
2 SOP - class - uid - length ( m )
7 - x SOP - class - uid The SOP Class identifier encoded as a UID as defined in PS 3.5 .
( x + 1 ) - ( x + 2 ) Service - class - uid - length The Service - class - uid - length shall be the number of bytes in the Service - class - uid field . It shall be encoded as an unsigned binary number .
( x + 3 ) - y Service - class - uid The Service Class identifier encoded as a UID as defined in PS 3.5 .
( y + 1 ) - ( y + 2 ) Related - general - sop - class - identification - length The Related - general - sop - class - identification - length shall be the number of bytes in the Related - general - sop - class - identification field . Shall be zero if no Related General SOP Classes are identified .
( y + 3 ) - z Related - general - sop - class - identification The Related - general - sop - class - identification is a sequence of pairs of length and UID sub - fields . Each pair of sub - fields shall be formatted in accordance with Table D .3 - 13.
( z + 1 ) - k Reserved Reserved for additional fields of the sub - item . Shall be zero - length for Version 0 of Sub - item definition .
Table D .3 - 13
RELATED - GENERAL - SOP - CLASS - IDENTIFICATION SUB - FIELDS
Bytes Sub - Field Name Description of Sub - Field
1 - 2 Related - general - sop - class - uid - length The Related - general - sop - class - uid - length shall be the number of bytes in the Related - general - sop - class - uid sub - field . It shall be encoded as an unsigned binary number .
3 - n Related - general - sop - class - uid The Related General SOP Class identifier encoded as a UID as defined in PS 3.5 .
58 User Identity Negotiation
1 Item - type 58 H
1 Reserved
2 Item - length
1 User - Identity - Type Field value shall be in the range 1 to 4 with the following meanings :
2008-08-09 16:24:39 +00:00
1 - Username as a string in UTF - 8
2 - Username as a string in UTF - 8 and passcode
3 - Kerberos Service ticket
4 - SAML Assertion
2008-07-25 13:20:18 +00:00
Other values are reserved for future standardization .
1 Positive - response - requested Field value :
0 - no response requested
1 - positive response requested
2 Primary - field - length The User - Identity - Length shall contain the length of the User - Identity value .
9 - n Primary - field This field shall convey the user identity , either the username as a series of characters , or the Kerberos Service ticket encoded in accordance with RFC - 1510.
n + 1 - n + 2 Secondary - field - length This field shall be non - zero only if User - Identity - Type has the value 2. It shall contain the length of the secondary - field .
n + 3 - m Secondary - field This field shall be present only if User - Identity - Type has the value 2. It shall contain the Passcode value .
59 User Identity Negotiation Reply
1 Item - type 59 H
1 Reserved
2 Item - length
5 - 6 Server - response - length This field shall contain the number of bytes in the Server - response . May be zero .
7 - n Server - response This field shall contain the Kerberos Server ticket , encoded in accordance with RFC - 1510 , if the User - Identity - Type value in the A - ASSOCIATE - RQ was 3. This field shall contain the SAML response if the User - Identity - Type value in the A - ASSOCIATE - RQ was 4. This field shall be zero length if the value of the User - Identity - Type in the A - ASSOCIATE - RQ was 1 or 2.
2004-05-08 08:49:02 +00:00
*/
2014-10-02 21:47:19 +00:00
/*
2019-07-26 18:43:17 +00:00
* Editor modelines - https : //www.wireshark.org/tools/modelines.html
2014-10-02 21:47:19 +00:00
*
* Local variables :
* c - basic - offset : 4
* tab - width : 8
* indent - tabs - mode : nil
* End :
*
* vi : set shiftwidth = 4 tabstop = 8 expandtab :
* : indentSize = 4 : tabSize = 8 : noTabs = true :
*/