Ethereal-dev: [Ethereal-dev] please checkin: packet-dcm.c

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

Date: Tue, 09 Nov 2004 13:03:01 -0600
Please check-in.

* 9 Nov 2004
* - Fixed calculating the size of the complete dicom pdu in dcm_get_pdu_len
* - Fixed the heuristic code -- sometimes a conversation already exists
* - Fixed the dissect code to display all the tags in the pdu

--
Rich Coe		richard.coe@xxxxxxxxxx
General Electric Medical Systems

*** ethereal-0.10.3-a/packet-dcm.c	Sat May  8 13:52:38 2004
--- ethereal-0.10.4/packet-dcm.c	Tue Nov  9 12:59:58 2004
***************
*** 9,17 ****
   * (NOTE: you need to turn on 'Allow subdissector to desegment TCP streams'
   *        in Preferences/Protocols/TCP Option menu, in order to view
   *        DICOM packets correctly.  
   *        This should probably be documented somewhere besides here.)
   *
   * $Id: packet-dcm.c,v 1.3 2004/05/08 21:31:52 obiot Exp $
   *
   * Ethereal - Network traffic analyzer
   * By Gerald Combs <gerald@xxxxxxxxxxxx>
--- 9,19 ----
   * (NOTE: you need to turn on 'Allow subdissector to desegment TCP streams'
   *        in Preferences/Protocols/TCP Option menu, in order to view
   *        DICOM packets correctly.  
+  *        Also, you might have to turn off tcp.check_checksum if tcp
+  *        detects that the checksum is bad.  
   *        This should probably be documented somewhere besides here.)
   *
   * $Id: packet-dcm.c,v 1.3 2004/05/08 21:31:52 obiot Exp $
   *
   * Ethereal - Network traffic analyzer
   * By Gerald Combs <gerald@xxxxxxxxxxxx>
***************
*** 57,62 ****
--- 59,68 ----
   * 
   * - The 'value to string' routines should probably be hash lookups.
   *
+  * 9 Nov 2004
+  * - Fixed calculating the size of the complete dicom pdu in dcm_get_pdu_len
+  * - Fixed the heuristic code -- sometimes a conversation already exists
+  * - Fixed the dissect code to display all the tags in the pdu
   */
  
  #include <stdio.h>
***************
*** 125,130 ****
--- 131,137 ----
  };
  struct dcmItem {
      struct dcmItem *next, *prev;
+     int valid;
      guint8 id;		/* 0x20 Presentation Context */
      guint8 *abs;	/* 0x30 Abstract syntax */
      guint8 *xfer;	/* 0x40 Transfer syntax */
***************
*** 142,147 ****
--- 149,155 ----
      guint32 tlen, clen, rlen;    /* length: total, current, remaining */
      int partial;	/* is a partial packet */
      int coff;		/* current offset */
+     int valid;		/* this conversation is a dicom conversation */
      /* enum { DCM_NONE, DCM_ASSOC, DCM_ }; */
  #define AEEND 16
      guint8 orig[1+AEEND], targ[1+AEEND], resp[1+AEEND], source, result, reason;
***************
*** 268,273 ****
--- 276,282 ----
      ds->pdu = 0;
      ds->tlen = ds->rlen = 0;
      ds->partial = 0;
+     ds->valid = TRUE;
      memset(ds->orig, 0, sizeof(ds->orig));
      memset(ds->targ, 0, sizeof(ds->targ));
      memset(ds->resp, 0, sizeof(ds->resp));
***************
*** 440,446 ****
      case 0xff00:  s = "Pending: operations are continuing"; break;
      default: break;
      }
!     if (0xC000 == (0xC000 & us))  s = "Failed:  Unable to Process"; 
      return s;
  }
  
--- 449,455 ----
      case 0xff00:  s = "Pending: operations are continuing"; break;
      default: break;
      }
!     if (0xC000 == (0xF000 & us))  s = "Failed:  Unable to Process"; 
      return s;
  }
  
***************
*** 449,454 ****
--- 458,464 ----
  {
      if (NULL == di) return;
      di->syntax = 0;
+     di->xfer = name;
      if (0 == *name) return;
      /* this would be faster to skip the common parts, and have a FSA to 
       * find the syntax.
***************
*** 478,483 ****
--- 488,494 ----
      guint32 tag, val32;
      guint16 val16;
      dcmTag_t *dtag;
+     guint32 pl;
      static dcmTag_t utag = { 0, 0, "(unknown)" };
  
      *buf = 0;
***************
*** 493,505 ****
  	dtag = &utag;
  
      strcpy(buf, dtag->desc);
      p = buf + strlen(buf);
  
      switch (dtag->dtype) {
      case DCM_TSTR:
  	*p++ = ' ';
  	vval = tvb_get_ptr(tvb, offset, len);
! 	strncpy(p, vval, len);
  	p += len;
  	*p = 0;
  	break;
--- 504,517 ----
  	dtag = &utag;
  
      strcpy(buf, dtag->desc);
+     pl = sizeof(buf) - strlen(buf);
      p = buf + strlen(buf);
  
      switch (dtag->dtype) {
      case DCM_TSTR:
  	*p++ = ' ';
  	vval = tvb_get_ptr(tvb, offset, len);
! 	strncpy(p, vval, len > pl ? pl : len);
  	p += len;
  	*p = 0;
  	break;
***************
*** 549,555 ****
  	vval = tvb_get_ptr(tvb, offset, len);
  	i = 0;
  	*p++ = ' ';
! 	while (i < len && isprint(*(vval+i)))
  	    *p++ = *(vval + i++);
  	*p = 0;
  	} break;
--- 561,567 ----
  	vval = tvb_get_ptr(tvb, offset, len);
  	i = 0;
  	*p++ = ' ';
! 	while (i < len && i < pl && isprint(*(vval+i)))
  	    *p++ = *(vval + i++);
  	*p = 0;
  	} break;
***************
*** 560,584 ****
  static guint
  dcm_get_pdu_len(tvbuff_t *tvb, int offset)
  {
!     long len;
      guint8 pdu_type;
  
      len = tvb_get_ntohl(tvb, 2 + offset);
- #if 0
      pdu_type = tvb_get_guint8(tvb, offset);
      if (4 == pdu_type) {
  	guint8 frag;
! 	/* this is a total swamp.  We only know how big this 
! 	   fragment is and that more are coming.  We have to 
! 	   parse the entire packet to find a clue how much more is
! 	   coming.  this tries to guess .... */
  	frag = tvb_get_guint8(tvb, 11 + offset);
! 	if (0 == (0x2 & frag))
! 	    /* len += tvb_ensure_length_remaining(tvb, offset) - 6; */
! 	    /* there are more fragments */ 
! 	    len++;
      }
- #endif
      return len + 6;		/* add in fixed header part */
  }
  
--- 572,600 ----
  static guint
  dcm_get_pdu_len(tvbuff_t *tvb, int offset)
  {
!     guint len;
      guint8 pdu_type;
+     guint len_rem;
  
+     len_rem = tvb_ensure_length_remaining(tvb, offset);
      len = tvb_get_ntohl(tvb, 2 + offset);
      pdu_type = tvb_get_guint8(tvb, offset);
      if (4 == pdu_type) {
  	guint8 frag;
! 	/* old swamp */
  	frag = tvb_get_guint8(tvb, 11 + offset);
! 	while (0 == (0x2 & frag)) { /* there are more fragments */ 
! 	    int nlen;
! 	    if (len_rem < len + 6 + 12) {
! 		len += 12;	    /* fixed part of next pdu */
! 		break;
! 	    }
! 	    len += 6;
! 	    nlen = tvb_get_ntohl(tvb, 2 + offset + len);
! 	    frag = tvb_get_guint8(tvb, 11 + offset + len);
! 	    len += nlen;
! 	}
      }
      return len + 6;		/* add in fixed header part */
  }
  
***************
*** 587,596 ****
  { 
      proto_tree *dcm_tree;
      dcmItem_t *di = NULL;
  
      dcm_tree = proto_item_add_subtree(ti, ett_assoc);
      while (-1 < offset && offset < (int) dcm_data->clen) {
- 	guint8 id, *name, result;
  	short len;
  	long  mlen;
  	id = tvb_get_guint8(tvb, offset);
--- 603,613 ----
  { 
      proto_tree *dcm_tree;
      dcmItem_t *di = NULL;
+     guint8 id, *name, result;
+     int reply = 0;
  
      dcm_tree = proto_item_add_subtree(ti, ett_assoc);
      while (-1 < offset && offset < (int) dcm_data->clen) {
  	short len;
  	long  mlen;
  	id = tvb_get_guint8(tvb, offset);
***************
*** 615,633 ****
  	    offset += len;
  	    break;
  	case 0x40:		/* Transfer syntax */
! 	    dcm_data->last->xfer = name = g_malloc(1 + len);
  	    tvb_memcpy(tvb, name, offset, len);
  	    *(name + len) = 0;
  	    proto_tree_add_string(dcm_tree, hf_dcm_pdi_syntax, tvb, offset, len, name);
! 	    dcm_setSyntax(di, name);
  	    offset += len;
  	    break;
  	case 0x20:		/* Presentation context */
  	    id = tvb_get_guint8(tvb, offset);
  	    di = lookupCtx(dcm_data, id);
! 	    if (DCM_UNK == di->syntax) {
  		di = g_chunk_new(dcmItem_t, dcm_pdus);
  		di->id = id;
  		di->next = di->prev = NULL;
  		if (dcm_data->last) {
  		    dcm_data->last->next = di;
--- 632,652 ----
  	    offset += len;
  	    break;
  	case 0x40:		/* Transfer syntax */
! 	    name = g_malloc(1 + len);
  	    tvb_memcpy(tvb, name, offset, len);
  	    *(name + len) = 0;
  	    proto_tree_add_string(dcm_tree, hf_dcm_pdi_syntax, tvb, offset, len, name);
! 	    if (reply && di && di->valid) dcm_setSyntax(di, name);
! 	    reply = 0;
  	    offset += len;
  	    break;
  	case 0x20:		/* Presentation context */
  	    id = tvb_get_guint8(tvb, offset);
  	    di = lookupCtx(dcm_data, id);
! 	    if (!di->valid) {
  		di = g_chunk_new(dcmItem_t, dcm_pdus);
  		di->id = id;
+ 		di->valid = 1;
  		di->next = di->prev = NULL;
  		if (dcm_data->last) {
  		    dcm_data->last->next = di;
***************
*** 644,652 ****
  	    result = tvb_get_guint8(tvb, 2 + offset);
  	    proto_tree_add_item(dcm_tree, hf_dcm_pctxt, tvb, offset, 1, FALSE);
  	    proto_tree_add_uint_format(dcm_tree, hf_dcm_pcres, tvb, 
! 		2 + offset, 1, 
! 		result, "Result 0x%x (%s)", result, dcm_PCresult2str(result));
! 	    offset += len;
  	    break;
  	case 0x50:		/* User Info */
  	    break;
--- 663,676 ----
  	    result = tvb_get_guint8(tvb, 2 + offset);
  	    proto_tree_add_item(dcm_tree, hf_dcm_pctxt, tvb, offset, 1, FALSE);
  	    proto_tree_add_uint_format(dcm_tree, hf_dcm_pcres, tvb, 
! 		2 + offset, 1, result, 
! 		"Result 0x%x (%s)", result, dcm_PCresult2str(result));
! 	    if (0 == result) {
! 		reply = 1;
! 		di = lookupCtx(dcm_data, id);
! 		offset += 4;
! 	    } else
! 		offset += len;
  	    break;
  	case 0x50:		/* User Info */
  	    break;
***************
*** 682,688 ****
  lookupCtx(dcmState_t *dd, guint8 ctx)
  {
      dcmItem_t *di = dd->first;
!     static dcmItem_t dunk = { NULL, NULL, -1, 
  	"not found - click on ASSOC Request", 
  	"not found - click on ASSOC Request", DCM_UNK };
      while (di) {
--- 706,712 ----
  lookupCtx(dcmState_t *dd, guint8 ctx)
  {
      dcmItem_t *di = dd->first;
!     static dcmItem_t dunk = { NULL, NULL, 0, -1, 
  	"not found - click on ASSOC Request", 
  	"not found - click on ASSOC Request", DCM_UNK };
      while (di) {
***************
*** 732,738 ****
      len = offset = toffset = 11;
      state = D_HEADER;
      nlen = 1;
!     while (len + nlen < dcm_data->clen) {
      switch (state) {
      case D_HEADER: {
  	guint8 flags;
--- 756,762 ----
      len = offset = toffset = 11;
      state = D_HEADER;
      nlen = 1;
!     while (len + nlen <= dcm_data->clen) {
      switch (state) {
      case D_HEADER: {
  	guint8 flags;
***************
*** 860,904 ****
      guint8 pdu;
      guint16 vers;
      guint32 len, tlen;
!     dcmState_t *dcm_data;
  
      conv = find_conversation(&pinfo->src, &pinfo->dst,
  	pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
  
!     if (NULL == conv) {
  	/* No conversation found.
  	 * only look for the first packet of a DICOM conversation.
  	 * if we don't get the first packet, we cannot decode the rest
  	 * of the session.
  	 */
- 	if (10 > (tlen = tvb_reported_length(tvb)))
- 	    return FALSE;			/* not long enough */
- 	if (1 != (pdu = tvb_get_guint8(tvb, 0)))
- 	    return FALSE;		 /* look for the start */
- 	if (1 != (vers = tvb_get_ntohs(tvb, 6)))
- 	    return FALSE;		/* not version 1 */
- 	len = 6 + tvb_get_ntohl(tvb, 2);
- 	if (len < tlen)
- 	    return FALSE;		/* packet is > decl len */
- 
-     	conv = conversation_new(&pinfo->src, &pinfo->dst, pinfo->ptype,
- 		pinfo->srcport, pinfo->destport, 0);
  	if (NULL == (dcm_data = mkds()))
  	    return FALSE;	/* internal error */
  	conversation_add_proto_data(conv, proto_dcm, dcm_data);
-     } else {
- 	/*
- 	 * conversation exists
- 	 */
- 	 dcm_data = conversation_get_proto_data(conv, proto_dcm);
- 	 if (NULL == dcm_data) {
- 	     /*
- 	      * This is not a DICOM conversation
- 	      */
- 	     return FALSE;
- 	 }
      }
  
      if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
  	col_clear(pinfo->cinfo, COL_PROTOCOL);
  
--- 884,925 ----
      guint8 pdu;
      guint16 vers;
      guint32 len, tlen;
!     dcmState_t *dcm_data = NULL;
  
      conv = find_conversation(&pinfo->src, &pinfo->dst,
  	pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
  
!     if (NULL != conv) 	/* conversation exists */
! 			/* do we have any data for this conversation ? */
! 	dcm_data = conversation_get_proto_data(conv, proto_dcm);
!     else
! 	conv = conversation_new(&pinfo->src, &pinfo->dst, pinfo->ptype,
! 	    pinfo->srcport, pinfo->destport, 0);
! 
!     if (NULL == dcm_data) {
  	/* No conversation found.
  	 * only look for the first packet of a DICOM conversation.
  	 * if we don't get the first packet, we cannot decode the rest
  	 * of the session.
  	 */
  	if (NULL == (dcm_data = mkds()))
  	    return FALSE;	/* internal error */
+ 	if (10 > (tlen = tvb_reported_length(tvb))     /* not long enough */
+ 	    || 1 != (pdu = tvb_get_guint8(tvb, 0))     /* look for the start */
+ 	    || 1 != (vers = tvb_get_ntohs(tvb, 6)))    /* not version 1 */
+ 	    dcm_data->valid = FALSE;		
+ 	else {
+ 	    len = 6 + tvb_get_ntohl(tvb, 2);
+ 	    if (len < tlen)
+ 		dcm_data->valid = FALSE;	/* packet is > decl len */
+ 	}
+ 
  	conversation_add_proto_data(conv, proto_dcm, dcm_data);
      }
  
+     if (FALSE == dcm_data->valid)
+ 	return FALSE;
+ 
      if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
  	col_clear(pinfo->cinfo, COL_PROTOCOL);
  
***************
*** 1110,1116 ****
--- 1131,1141 ----
  void
  proto_reg_handoff_dcm(void)
  {
+     dissector_handle_t dcm_handle;
+ 
      heur_dissector_add("tcp", dissect_dcm, proto_dcm);
+     dcm_handle = new_create_dissector_handle(dissect_dcm, proto_dcm);
+     dissector_add("tcp.port", 104, dcm_handle);
  }
  
  /*