Ethereal-dev: [Ethereal-dev] [Patch] BACnet Updates

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

From: Steve Karg <skarg@xxxxxxxxxxxxxxxxxxxxx>
Date: Tue, 12 Apr 2005 16:33:26 -0400
Hi!

Here are some BACnet dissector improvements:

- BACnet APDU decoding for tree and info
- ARCNET and MS/TP DADR and SADR decoding

There is more decoding of the APDU to do, but this chunk should be a major improvement to sniffing BACnet messages.

I would like to say "Thank You!" to those that maintain the developer documents and the developer section on the website. I was able to install the required libs and tools and have a working build on Debian the same day that I started (last Thursday). The README.developer document worked great. Very nice!

Best Regards,

Steve Karg
Index: doc/README.tvbuff
===================================================================
--- doc/README.tvbuff	(revision 14053)
+++ doc/README.tvbuff	(working copy)
@@ -96,7 +96,7 @@
 in all normal cases you really want to take advantage of the default
 behavior.
 
-Even though the definition of tvbuff is in tvbuff.h, you sholud treat a tvbuff
+Even though the definition of tvbuff is in tvbuff.h, you should treat a tvbuff
 as an opaque structure. You should not access its members directly.  You must
 use one of the provided accessor methods to retrieve data from the tvbuff. All
 accessors will throw an exception if an attempt is made to read beyond the
Index: epan/dissectors/packet-bacnet.c
===================================================================
--- epan/dissectors/packet-bacnet.c	(revision 14053)
+++ epan/dissectors/packet-bacnet.c	(working copy)
@@ -1,6 +1,7 @@
 /* packet-bacnet.c
  * Routines for BACnet (NPDU) dissection
  * Copyright 2001, Hartmut Mueller <hartmut@xxxxxxxxxxxx>, FH Dortmund
+ * Enhanced by Steve Karg, 2005, <skarg@xxxxxxxxxxxxxxxxxxxxx>
  *
  * $Id$
  *
@@ -148,10 +149,12 @@
 static int hf_bacnet_dnet = -1;
 static int hf_bacnet_dlen = -1;
 static int hf_bacnet_dadr_eth = -1;
+static int hf_bacnet_dadr_mstp = -1;
 static int hf_bacnet_dadr_tmp = -1;
 static int hf_bacnet_snet = -1;
 static int hf_bacnet_slen = -1;
 static int hf_bacnet_sadr_eth = -1;
+static int hf_bacnet_sadr_mstp = -1;
 static int hf_bacnet_sadr_tmp = -1;
 static int hf_bacnet_hopc = -1;
 static int hf_bacnet_mesgtyp = -1;
@@ -258,6 +261,15 @@
 				hf_bacnet_dadr_eth, tvb, offset,
 				bacnet_dlen, FALSE);
 			offset += bacnet_dlen;
+		} else if (bacnet_dlen==1) {
+			proto_tree_add_uint(bacnet_tree, hf_bacnet_dlen,
+				tvb, offset, 1, bacnet_dlen);
+			offset ++;
+			/* MS/TP or ARCNET MAC */
+			proto_tree_add_item(bacnet_tree,
+				hf_bacnet_dadr_mstp, tvb, offset,
+				bacnet_dlen, FALSE);
+			offset += bacnet_dlen;
 		} else if (bacnet_dlen<7) {
 			proto_tree_add_uint(bacnet_tree, hf_bacnet_dlen,
 				tvb, offset, 1, bacnet_dlen);
@@ -296,11 +308,21 @@
 				hf_bacnet_sadr_eth, tvb, offset,
 				bacnet_slen, FALSE);
 			offset += bacnet_slen;
-		} else if (bacnet_slen<6) { /* LON,ARCNET,MS/TP MAC */
+		} else if (bacnet_slen==1) {
 			/* SLEN */
 			 proto_tree_add_uint(bacnet_tree, hf_bacnet_slen,
 				tvb, offset, 1, bacnet_slen);
 			offset ++;
+			/* MS/TP or ARCNET MAC */
+			proto_tree_add_item(bacnet_tree,
+				hf_bacnet_sadr_mstp, tvb, offset,
+				bacnet_slen, FALSE);
+			offset += bacnet_slen;
+		} else if (bacnet_slen<6) { /* LON MAC */
+			/* SLEN */
+			 proto_tree_add_uint(bacnet_tree, hf_bacnet_slen,
+				tvb, offset, 1, bacnet_slen);
+			offset ++;
 			/* Other MAC formats should be included here */
 			proto_tree_add_item(bacnet_tree,
 				hf_bacnet_sadr_tmp, tvb, offset,
@@ -493,6 +515,11 @@
 			FT_ETHER, BASE_HEX, NULL, 0,
 			"Destination ISO 8802-3 MAC Address", HFILL }
 		},
+		{ &hf_bacnet_dadr_mstp,
+			{ "DADR", "bacnet.dadr_mstp",
+			FT_BYTES, BASE_HEX, NULL, 0,
+			"Destination MS/TP or ARCNET MAC Address", HFILL }
+		},
 		{ &hf_bacnet_dadr_tmp,
 			{ "Unknown Destination MAC", "bacnet.dadr_tmp",
 			FT_BYTES, BASE_HEX, NULL, 0,
@@ -513,6 +540,11 @@
 			FT_ETHER, BASE_HEX, NULL, 0,
 			"Source ISO 8802-3 MAC Address", HFILL }
 		},
+		{ &hf_bacnet_sadr_mstp,
+			{ "SADR", "bacnet.sadr_mstp",
+			FT_BYTES, BASE_HEX, NULL, 0,
+			"Source MS/TP or ARCNET MAC Address", HFILL }
+		},
 		{ &hf_bacnet_sadr_tmp,
 			{ "Unknown Source MAC", "bacnet.sadr_tmp",
 			FT_BYTES, BASE_HEX, NULL, 0,
Index: epan/dissectors/packet-bacapp.c
===================================================================
--- epan/dissectors/packet-bacapp.c	(revision 14053)
+++ epan/dissectors/packet-bacapp.c	(working copy)
@@ -1,6 +1,7 @@
 /* packet-bacapp.c
  * Routines for BACnet (APDU) dissection
  * Copyright 2001, Hartmut Mueller <hartmut@xxxxxxxxxxxx>, FH Dortmund
+ * Enhanced by Steve Karg, 2005, <skarg@xxxxxxxxxxxxxxxxxxxxx>
  *
  * $Id$
  *
@@ -37,23 +38,281 @@
 
 #include <epan/packet.h>
 
+// BACnet PDU Types
+#define BACAPP_TYPE_CONFIRMED_SERVICE_REQUEST 0
+#define BACAPP_TYPE_UNCONFIRMED_SERVICE_REQUEST 1
+#define BACAPP_TYPE_SIMPLE_ACK 2
+#define BACAPP_TYPE_COMPLEX_ACK 3
+#define BACAPP_TYPE_SEGMENT_ACK 4
+#define BACAPP_TYPE_ERROR 5
+#define BACAPP_TYPE_REJECT 6
+#define BACAPP_TYPE_ABORT 7
+#define MAX_BACAPP_TYPE 8
+
+static const value_string bacapp_type_names[] = {
+	{ BACAPP_TYPE_CONFIRMED_SERVICE_REQUEST, "Confirmed-Request" },
+	{ BACAPP_TYPE_UNCONFIRMED_SERVICE_REQUEST, "Unconfirmed-Request" },
+	{ BACAPP_TYPE_SIMPLE_ACK, "SimpleACK" },
+	{ BACAPP_TYPE_COMPLEX_ACK, "ComplexACK" },
+	{ BACAPP_TYPE_SEGMENT_ACK, "SegmentACK" },
+	{ BACAPP_TYPE_ERROR, "Error" },
+	{ BACAPP_TYPE_REJECT, "Reject" },
+	{ BACAPP_TYPE_ABORT, "Abort" },
+	{ MAX_BACAPP_TYPE, NULL }
+};
+static const char *bacapp_unknown_str = "unknown";
+static const char *bacapp_unknown_service_str = "unknown service";
+
+static const value_string bacapp_confirmed_service_names[] = {
+	{ 0, "Acknowledge-Alarm" },
+	{ 1, "COV-Notification" },
+	{ 2, "Event-Notification" },
+	{ 3, "Get-Alarm-Summary" },
+	{ 4, "Get-Enrollment-Summary" },
+	{ 5, "Subscribe-COV" },
+	{ 6, "Atomic-Read-File" },
+	{ 7, "Atomic-Write-File" },
+	{ 8, "Add-List-Element" },
+	{ 9, "Remove-List-Element" },
+	{ 10, "Create-Object" },
+	{ 11, "Delete-Object" },
+	{ 12, "Read-Property" },
+	{ 13, "Read-Property-Conditional" },
+	{ 14, "Read-Property-Multiple" },
+	{ 15, "Write-Property" },
+	{ 16, "Write-Property-Multiple" },
+	{ 17, "Device-Communication-Control" },
+	{ 18, "Private-Transfer" },
+	{ 19, "Text-Message" },
+	{ 20, "Reinitialize-Device" },
+	{ 21, "VT-Open" },
+	{ 22, "VT-Close" },
+	{ 23, "VT-Data" },
+	{ 24, "Authenticate" },
+	{ 25, "Request-Key" },
+	{ 26, "Read-Range" },
+	{ 27, "Life-Safety_Operation" },
+	{ 28, "Subscribe-COV-Property" },
+	{ 29, "Get-Event-Information" },
+	{ 30, NULL }
+};
+
+#define SERVICE_UNCONFIRMED_I_AM 0
+#define SERVICE_UNCONFIRMED_I_HAVE 1
+#define SERVICE_UNCONFIRMED_COV_NOTIFICATION 2
+#define SERVICE_UNCONFIRMED_EVENT_NOTIFICATION 3
+#define SERVICE_UNCONFIRMED_PRIVATE_TRANSFER 4
+#define SERVICE_UNCONFIRMED_TEXT_MESSAGE 5
+#define SERVICE_UNCONFIRMED_TIME_SYNCHRONIZATION 6
+#define SERVICE_UNCONFIRMED_WHO_HAS 7
+#define SERVICE_UNCONFIRMED_WHO_IS 8
+#define SERVICE_UNCONFIRMED_UTC_TIME_SYNCHRONIZATION 9
+/* Other services to be added as they are defined.
+   All choice values in this production are reserved
+   for definition by ASHRAE.
+   Proprietary extensions are made by using the
+   UnconfirmedPrivateTransfer service. See Clause 23.
+*/
+#define MAX_BACNET_UNCONFIRMED_SERVICE 10
+
+static const value_string bacapp_unconfirmed_service_names[] = {
+	{ SERVICE_UNCONFIRMED_I_AM, "I-Am" },
+	{ SERVICE_UNCONFIRMED_I_HAVE, "I-Have" },
+	{ SERVICE_UNCONFIRMED_COV_NOTIFICATION, "COV-Notification" },
+	{ SERVICE_UNCONFIRMED_EVENT_NOTIFICATION, "Event-Notification" },
+	{ SERVICE_UNCONFIRMED_PRIVATE_TRANSFER, "Private-Transfer" },
+	{ SERVICE_UNCONFIRMED_TEXT_MESSAGE, "Text-Message" },
+	{ SERVICE_UNCONFIRMED_TIME_SYNCHRONIZATION, "Time-Synchronization" },
+	{ SERVICE_UNCONFIRMED_WHO_HAS, "Who-Has" },
+	{ SERVICE_UNCONFIRMED_WHO_IS, "Who-Is" },
+	{ SERVICE_UNCONFIRMED_UTC_TIME_SYNCHRONIZATION, "UTC-Time-Synchronization" },
+	{ MAX_BACNET_UNCONFIRMED_SERVICE, NULL }
+};
+
 static const char*
-bacapp_type_name (guint8 bacapp_type){
-  static const char *type_names[] = {
-	"Confirmed-Request-PDU",
-	"Unconfirmed-Request-PDU",
-	"SimpleACK-PDU",
-	"ComplexACK-PDU",
-	"SegmentACK-PDU",
-	"Error-PDU",
-	"Reject-PDU",
-	"Abort-PDU"
+bacapp_reject_reason_name (guint8 bacapp_reason){
+	static const char *reason_names[] = {
+		"Other",
+		"Buffer Overflow",
+		"Inconsistent Parameters",
+		"Invalid Parameter Data Type",
+		"Invalid Tag",
+		"Missing Required Parameter",
+		"Parameter Out of Range",
+		"Too Many Arguments",
+		"Undefined Enumeration",
+		"Unrecognized Service"
 	};
-        return (bacapp_type > 7)? "unknown PDU" : type_names[bacapp_type];
+	if (bacapp_reason < 10)
+		return reason_names[bacapp_reason];
+	else if (bacapp_reason < 64)
+		return "Reserved for Use by ASHRAE";
+
+	return "Vendor Proprietary Reason";
 }
 
+static const char*
+bacapp_abort_reason_name (guint8 bacapp_reason){
+  static const char *reason_names[] = {
+    "Other",
+    "Buffer Overflow",
+    "Invalid APDU in this State",
+    "Preempted by Higher Priority Task",
+    "Segmentation Not Supported"
+	};
+	if (bacapp_reason < 5)
+		return reason_names[bacapp_reason];
+	else if (bacapp_reason < 64)
+		return "Reserved for Use by ASHRAE";
+
+	return "Vendor Proprietary Reason";
+}
+
+/* from clause 20.1.2.4 max-segments-accepted
+   returns the decoded value
+   
+   max-segments-accepted
+   B'000'      Unspecified number of segments accepted.
+   B'001'      2 segments accepted.
+   B'010'      4 segments accepted.
+   B'011'      8 segments accepted.
+   B'100'      16 segments accepted.
+   B'101'      32 segments accepted.
+   B'110'      64 segments accepted.
+   B'111'      Greater than 64 segments accepted.
+*/
+static guint8 decode_max_segs(guint8 octet)
+{
+    guint8 max_segs = 0;
+
+    switch (octet & 0xF0)
+    {
+      case 0:
+        max_segs = 0;
+        break;
+      case 0x10:
+        max_segs = 2;
+        break;
+      case 0x20:
+        max_segs = 4;
+        break;
+      case 0x30:
+        max_segs = 8;
+        break;
+      case 0x40:
+        max_segs = 16;
+        break;
+      case 0x50:
+        max_segs = 32;
+        break;
+      case 0x60:
+        max_segs = 64;
+        break;
+      case 0x70:
+        max_segs = 65;
+        break;
+      default:
+        break;
+    }
+
+    return max_segs;
+}
+
+/* from clause 20.1.2.5 max-APDU-length-accepted
+   returns the decoded value
+   
+   max-APDU-length-accepted
+   B'0000'  Up to MinimumMessageSize (50 octets)
+   B'0001'  Up to 128 octets
+   B'0010'  Up to 206 octets (fits in a LonTalk frame)
+   B'0011'  Up to 480 octets (fits in an ARCNET frame)
+   B'0100'  Up to 1024 octets
+   B'0101'  Up to 1476 octets (fits in an ISO 8802-3 frame)
+   B'0110'  reserved by ASHRAE
+   B'0111'  reserved by ASHRAE
+   B'1000'  reserved by ASHRAE
+   B'1001'  reserved by ASHRAE
+   B'1010'  reserved by ASHRAE
+   B'1011'  reserved by ASHRAE
+   B'1100'  reserved by ASHRAE
+   B'1101'  reserved by ASHRAE
+   B'1110'  reserved by ASHRAE
+   B'1111'  reserved by ASHRAE
+*/
+static guint16 decode_max_apdu(guint8 octet)
+{
+    guint16 max_apdu = 0;
+    
+    switch (octet & 0x0F)
+    {
+      case 0:
+        max_apdu = 50;
+        break;
+      case 1:
+        max_apdu = 128;
+        break;
+      case 2:
+        max_apdu = 206;
+        break;
+      case 3:
+        max_apdu = 480;
+        break;
+      case 4:
+        max_apdu = 1024;
+        break;
+      case 5:
+        max_apdu = 1476;
+        break;
+      default:
+        break;
+    }
+
+    return max_apdu;
+}
+
+#define BACAPP_SEGMENTED_REQUEST 0x08
+static const true_false_string tfs_segmented_request = {
+	"Segmented Request.",
+	"Unsegmented Request."
+};
+#define BACAPP_MORE_SEGMENTS 0x04
+static const true_false_string tfs_more_segments = {
+	"More Segments Follow.",
+	"No More Segments Follow."
+};
+#define BACAPP_SEGMENTED_RESPONSE 0x02
+static const true_false_string tfs_segmented_response = {
+	"Segmented Response Accepted.",
+	"Segmented Response Not Accepted."
+};
+#define BACAPP_SEGMENT_NAK 0x02
+static const true_false_string tfs_segment_nak = {
+	"Negative Acknowledgement. Segment out of Order.",
+	"Normal Acknowledgement."
+};
+#define BACAPP_SENT_BY 0x01
+static const true_false_string tfs_sent_by = {
+	"Sent By Server.",
+	"Sent By Client."
+};
+
 static int proto_bacapp = -1;
+
 static int hf_bacapp_type = -1;
+static int hf_bacapp_segmented_request = -1;
+static int hf_bacapp_more_segments = -1;
+static int hf_bacapp_segmented_response = -1;
+static int hf_bacapp_max_segments = -1;
+static int hf_bacapp_max_response = -1;
+static int hf_bacapp_invoke_id = -1;
+static int hf_bacapp_sequence_number = -1;
+static int hf_bacapp_window_size = -1;
+static int hf_bacapp_service_choice = -1;
+static int hf_bacapp_segment_nak = -1;
+static int hf_bacapp_sent_by = -1;
+static int hf_bacapp_error_choice = -1;
+static int hf_bacapp_reject_reason = -1;
+static int hf_bacapp_abort_reason = -1;
 
 static gint ett_bacapp = -1;
 
@@ -66,6 +325,15 @@
 	proto_tree *bacapp_tree;
 	guint8 offset;
 	guint8 bacapp_type;
+	guint8 bacapp_type_seg;
+	guint8 bacapp_service;
+	guint8 bacapp_reason;
+	guint8 bacapp_max_seg_resp;
+	guint8 bacapp_invoke_id;
+	guint8 bacapp_sequence_number;
+	guint8 bacapp_window_size;
+	guint8 max_segs;
+	guint16 max_apdu;
 	tvbuff_t *next_tvb;
 
 	if (check_col(pinfo->cinfo, COL_PROTOCOL))
@@ -74,11 +342,80 @@
 		col_add_str(pinfo->cinfo, COL_INFO, "BACnet APDU ");
 
 	offset  = 0;
-	bacapp_type = (tvb_get_guint8(tvb, offset) >> 4) & 0x0f;
-
+	bacapp_type_seg = tvb_get_guint8(tvb, offset);
+	bacapp_type = (bacapp_type_seg >> 4) & 0xf;
+	
+	/* show some descriptive text in the INFO column */
 	if (check_col(pinfo->cinfo, COL_INFO))
-		col_append_fstr(pinfo->cinfo, COL_INFO, "(%s)",
-		bacapp_type_name(bacapp_type));
+	{
+		col_clear(pinfo->cinfo, COL_INFO);
+		col_add_str(pinfo->cinfo, COL_INFO,
+			val_to_str(bacapp_type, bacapp_type_names, bacapp_unknown_str));
+		switch (bacapp_type)
+		{
+			case BACAPP_TYPE_CONFIRMED_SERVICE_REQUEST:
+				/* segmented messages have 2 additional bytes */
+				if (bacapp_type_seg & BACAPP_SEGMENTED_REQUEST)
+					bacapp_service = tvb_get_guint8(tvb, offset + 5);
+				else
+					bacapp_service = tvb_get_guint8(tvb, offset + 3);
+				col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
+					val_to_str(bacapp_service, 
+						bacapp_confirmed_service_names,
+						bacapp_unknown_service_str));
+				break;
+			case BACAPP_TYPE_UNCONFIRMED_SERVICE_REQUEST:
+				bacapp_service = tvb_get_guint8(tvb, offset + 1);
+				col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
+					val_to_str(bacapp_service, 
+						bacapp_unconfirmed_service_names,
+						bacapp_unknown_service_str));
+				break;
+			case BACAPP_TYPE_SIMPLE_ACK:
+				bacapp_service = tvb_get_guint8(tvb, offset + 2);
+				col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
+					val_to_str(bacapp_service, 
+						bacapp_confirmed_service_names,
+						bacapp_unknown_service_str));
+				break;
+			case BACAPP_TYPE_COMPLEX_ACK:
+				/* segmented messages have 2 additional bytes */
+				if (bacapp_type_seg & BACAPP_SEGMENTED_REQUEST)
+					bacapp_service = tvb_get_guint8(tvb, offset + 4);
+				else
+					bacapp_service = tvb_get_guint8(tvb, offset + 2);
+				col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
+					val_to_str(bacapp_service, 
+						bacapp_confirmed_service_names,
+						bacapp_unknown_service_str));
+				break;
+			case BACAPP_TYPE_SEGMENT_ACK:
+				/* nothing more to add */
+				break;
+			case BACAPP_TYPE_ERROR:
+				bacapp_service = tvb_get_guint8(tvb, offset + 2);
+				col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
+					val_to_str(bacapp_service, 
+						bacapp_confirmed_service_names,
+						bacapp_unknown_service_str));
+				break;
+			case BACAPP_TYPE_REJECT:
+				bacapp_reason = tvb_get_guint8(tvb, offset + 2);
+				col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
+					bacapp_reject_reason_name(bacapp_reason));
+				break;
+			case BACAPP_TYPE_ABORT:
+				bacapp_reason = tvb_get_guint8(tvb, offset + 2);
+				col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
+					bacapp_abort_reason_name(bacapp_reason));
+				break;
+			/* UNKNOWN */
+			default:
+				/* nothing more to add */
+				break;
+		}
+	}
+   
 	if (tree) {
 		ti = proto_tree_add_item(tree, proto_bacapp, tvb, offset, -1, FALSE);
 
@@ -86,9 +423,182 @@
 
 		proto_tree_add_uint_format(bacapp_tree, hf_bacapp_type, tvb,
 			offset, 1, bacapp_type, "APDU Type: %u (%s)", bacapp_type,
-				bacapp_type_name(bacapp_type));
-		offset ++;
-
+			val_to_str(bacapp_type, bacapp_type_names, bacapp_unknown_str));
+		switch (bacapp_type)
+		{
+			case BACAPP_TYPE_CONFIRMED_SERVICE_REQUEST:
+				proto_tree_add_boolean(bacapp_tree, hf_bacapp_segmented_request,
+					tvb, offset, 1, bacapp_type_seg);
+				proto_tree_add_boolean(bacapp_tree, hf_bacapp_more_segments,
+					tvb, offset, 1, bacapp_type_seg);
+				proto_tree_add_boolean(bacapp_tree, hf_bacapp_segmented_response,
+					tvb, offset, 1, bacapp_type_seg);
+				offset++;
+				bacapp_max_seg_resp = tvb_get_guint8(tvb, offset);
+				max_segs = decode_max_segs(bacapp_max_seg_resp);
+				if (max_segs > 64)
+					proto_tree_add_uint_format(bacapp_tree, hf_bacapp_max_segments, 
+						tvb, offset, 1, bacapp_max_seg_resp,
+						"Maximum Segments Accepted: %u "
+						"(Greater than 64 segments accepted).",
+						((bacapp_max_seg_resp >> 4) & 0x0f));
+				else
+					proto_tree_add_uint_format(bacapp_tree, hf_bacapp_max_segments, 
+						tvb, offset, 1, bacapp_max_seg_resp,
+						"Maximum Segments Accepted: %u (%u segments accepted).",
+						((bacapp_max_seg_resp >> 4) & 0x0f), max_segs);
+				max_apdu = decode_max_apdu(bacapp_max_seg_resp);
+				proto_tree_add_uint_format(bacapp_tree, hf_bacapp_max_response, 
+					tvb, offset, 1, bacapp_max_seg_resp,
+					"Maximum APDU Accepted: %u (%u octets)",
+					bacapp_max_seg_resp,max_apdu);
+				offset++;
+				bacapp_invoke_id = tvb_get_guint8(tvb, offset);
+				proto_tree_add_uint(bacapp_tree, hf_bacapp_invoke_id, 
+					tvb, offset, 1, bacapp_invoke_id);
+				offset++;
+				/* segmented messages have 2 additional bytes */
+				if (bacapp_type_seg & BACAPP_SEGMENTED_REQUEST)
+				{
+					bacapp_sequence_number = tvb_get_guint8(tvb, offset);
+					proto_tree_add_uint(bacapp_tree, hf_bacapp_sequence_number, 
+						tvb, offset, 1, bacapp_sequence_number);
+					offset++;
+					bacapp_window_size = tvb_get_guint8(tvb, offset);
+					proto_tree_add_uint(bacapp_tree, hf_bacapp_window_size, 
+						tvb, offset, 1, bacapp_window_size);
+					offset++;
+				}
+				bacapp_service = tvb_get_guint8(tvb, offset);
+				proto_tree_add_uint_format(bacapp_tree, hf_bacapp_service_choice, 
+					tvb, offset, 1, bacapp_service, 
+					"Service Choice: %u (%s)", bacapp_service,
+					val_to_str(bacapp_service, 
+						bacapp_confirmed_service_names,
+						bacapp_unknown_service_str));
+				offset++;
+				break;
+			case BACAPP_TYPE_UNCONFIRMED_SERVICE_REQUEST:
+				offset++;
+				bacapp_service = tvb_get_guint8(tvb, offset);
+				proto_tree_add_uint_format(bacapp_tree, hf_bacapp_service_choice, 
+					tvb, offset, 1, bacapp_service, 
+					"Service Choice: %u (%s)", bacapp_service,
+					val_to_str(bacapp_service, 
+						bacapp_unconfirmed_service_names,
+						bacapp_unknown_service_str));
+				offset++;
+				break;
+			case BACAPP_TYPE_SIMPLE_ACK:
+				offset++;
+				bacapp_invoke_id = tvb_get_guint8(tvb, offset);
+				proto_tree_add_uint(bacapp_tree, hf_bacapp_invoke_id, 
+					tvb, offset, 1, bacapp_invoke_id);
+				offset++;
+				bacapp_service = tvb_get_guint8(tvb, offset);
+				proto_tree_add_uint_format(bacapp_tree, hf_bacapp_service_choice, 
+					tvb, offset, 1, bacapp_service, 
+					"Service Choice: %u (%s)", bacapp_service,
+					val_to_str(bacapp_service, 
+						bacapp_confirmed_service_names,
+						bacapp_unknown_service_str));
+				offset++;
+				break;
+			case BACAPP_TYPE_COMPLEX_ACK:
+				proto_tree_add_boolean(bacapp_tree, hf_bacapp_segmented_request,
+					tvb, offset, 1, bacapp_type_seg);
+				proto_tree_add_boolean(bacapp_tree, hf_bacapp_more_segments,
+					tvb, offset, 1, bacapp_type_seg);
+				offset++;
+				bacapp_invoke_id = tvb_get_guint8(tvb, offset);
+				proto_tree_add_uint(bacapp_tree, hf_bacapp_invoke_id, 
+					tvb, offset, 1, bacapp_invoke_id);
+				offset++;
+				/* segmented messages have 2 additional bytes */
+				if (bacapp_type_seg & BACAPP_SEGMENTED_REQUEST)
+				{
+					bacapp_sequence_number = tvb_get_guint8(tvb, offset);
+					proto_tree_add_uint(bacapp_tree, hf_bacapp_sequence_number, 
+						tvb, offset, 1, bacapp_sequence_number);
+					offset++;
+					bacapp_window_size = tvb_get_guint8(tvb, offset);
+					proto_tree_add_uint(bacapp_tree, hf_bacapp_window_size, 
+						tvb, offset, 1, bacapp_window_size);
+					offset++;
+				}
+				bacapp_service = tvb_get_guint8(tvb, offset);
+				proto_tree_add_uint_format(bacapp_tree, hf_bacapp_service_choice, 
+					tvb, offset, 1, bacapp_service, 
+					"Service Choice: %u (%s)", bacapp_service,
+					val_to_str(bacapp_service, 
+						bacapp_confirmed_service_names,
+						bacapp_unknown_service_str));
+				offset++;
+				break;
+			case BACAPP_TYPE_SEGMENT_ACK:
+				proto_tree_add_boolean(bacapp_tree, hf_bacapp_segment_nak,
+					tvb, offset, 1, bacapp_type_seg);
+				proto_tree_add_boolean(bacapp_tree, hf_bacapp_sent_by,
+					tvb, offset, 1, bacapp_type_seg);
+				offset++;
+				bacapp_invoke_id = tvb_get_guint8(tvb, offset);
+				proto_tree_add_uint(bacapp_tree, hf_bacapp_invoke_id, 
+					tvb, offset, 1, bacapp_invoke_id);
+				offset++;
+				bacapp_sequence_number = tvb_get_guint8(tvb, offset);
+				proto_tree_add_uint(bacapp_tree, hf_bacapp_sequence_number, 
+					tvb, offset, 1, bacapp_sequence_number);
+				offset++;
+				bacapp_window_size = tvb_get_guint8(tvb, offset);
+				proto_tree_add_uint(bacapp_tree, hf_bacapp_window_size, 
+					tvb, offset, 1, bacapp_window_size);
+				offset++;
+				break;
+			case BACAPP_TYPE_ERROR:
+				offset++;
+				bacapp_invoke_id = tvb_get_guint8(tvb, offset);
+				proto_tree_add_uint(bacapp_tree, hf_bacapp_invoke_id, 
+					tvb, offset, 1, bacapp_invoke_id);
+				offset++;
+				bacapp_service = tvb_get_guint8(tvb, offset);
+				proto_tree_add_uint_format(bacapp_tree, hf_bacapp_error_choice, 
+					tvb, offset, 1, bacapp_service, 
+					"Error Choice: %u (%s)", bacapp_service,
+					val_to_str(bacapp_service, 
+						bacapp_confirmed_service_names,
+						bacapp_unknown_service_str));
+				offset++;
+				break;
+			case BACAPP_TYPE_REJECT:
+				offset++;
+				bacapp_invoke_id = tvb_get_guint8(tvb, offset);
+				proto_tree_add_uint(bacapp_tree, hf_bacapp_invoke_id, 
+					tvb, offset, 1, bacapp_invoke_id);
+				offset++;
+				bacapp_reason = tvb_get_guint8(tvb, offset);
+				proto_tree_add_uint_format(bacapp_tree, hf_bacapp_reject_reason, 
+					tvb, offset, 1, bacapp_reason, 
+					"Reject Reason: %u (%s)", bacapp_reason,
+					bacapp_reject_reason_name(bacapp_reason));
+				offset++;
+				break;
+			case BACAPP_TYPE_ABORT:
+				offset++;
+				bacapp_invoke_id = tvb_get_guint8(tvb, offset);
+				proto_tree_add_uint(bacapp_tree, hf_bacapp_invoke_id, 
+					tvb, offset, 1, bacapp_invoke_id);
+				offset++;
+				bacapp_reason = tvb_get_guint8(tvb, offset);
+				proto_tree_add_uint_format(bacapp_tree, hf_bacapp_reject_reason, 
+					tvb, offset, 1, bacapp_reason, 
+					"Abort Reason: %u (%s)", bacapp_reason,
+					bacapp_abort_reason_name(bacapp_reason));
+				offset++;
+				break;
+			default:
+				offset++;
+				break;
+		}
 	}
 	next_tvb = tvb_new_subset(tvb,offset,-1,-1);
 	call_dissector(data_handle,next_tvb, pinfo, tree);
@@ -100,10 +610,87 @@
 {
 	static hf_register_info hf[] = {
 		{ &hf_bacapp_type,
-			{ "APDU Type",           "bacapp.bacapp_type",
+			{ "APDU Type",
+			"bacapp.apdu_type",
 			FT_UINT8, BASE_DEC, NULL, 0xf0, "APDU Type", HFILL }
 		},
+		{ &hf_bacapp_segmented_request,
+			{ "Segmented Request",
+			"bacapp.segmented_request",
+			FT_BOOLEAN, 8, TFS(&tfs_segmented_request), 
+			BACAPP_SEGMENTED_REQUEST, "Segmented Request", HFILL }
+		},
+		{ &hf_bacapp_more_segments,
+			{ "More Segments",
+			"bacapp.more_segments",
+			FT_BOOLEAN, 8, TFS(&tfs_more_segments), 
+			BACAPP_MORE_SEGMENTS, "More Segments", HFILL }
+		},
+		{ &hf_bacapp_segmented_response,
+			{ "Segmented Response",
+			"bacapp.segmented_response",
+			FT_BOOLEAN, 8, TFS(&tfs_segmented_response), 
+			BACAPP_SEGMENTED_RESPONSE, "Segmented Response", HFILL }
+		},
+		{ &hf_bacapp_max_segments,
+			{ "Maximum Segments Accepted",
+			"bacapp.max_segments_accepted",
+			FT_UINT8, BASE_DEC, NULL, 0x70, "Maximum Segments Accepted", HFILL }
+		},
+		{ &hf_bacapp_max_response,
+			{ "Maximum APDU accepted",
+			"bacapp.max_apdu_accepted",
+			FT_UINT8, BASE_DEC, NULL, 0x0f, "Maximum APDU accepted", HFILL }
+		},
+		{ &hf_bacapp_invoke_id,
+			{ "Invoke ID",           
+			"bacapp.invoke_id",
+			FT_UINT8, BASE_DEC, NULL, 0, "Invoke ID", HFILL }
+		},
+		{ &hf_bacapp_sequence_number,
+			{ "Sequence Number",
+			"bacapp.segment_sequence_number",
+			FT_UINT8, BASE_DEC, NULL, 0, "Sequence Number", HFILL }
+		},
+		{ &hf_bacapp_window_size,
+			{ "Proposed Window Size",           
+			"bacapp.segment_window_size",
+			FT_UINT8, BASE_DEC, NULL, 0, "Proposed Window Size", HFILL }
+		},
+		{ &hf_bacapp_service_choice,
+			{ "Service Choice",           
+			"bacapp.service_choice",
+			FT_UINT8, BASE_DEC, NULL, 0, "Service Choice", HFILL }
+		},
+		{ &hf_bacapp_segment_nak,
+			{ "Segment NAK",
+			"bacapp.segment_nak",
+			FT_BOOLEAN, 8, TFS(&tfs_segment_nak), 
+			BACAPP_SEGMENT_NAK, "Segment NAK", HFILL }
+		},
+		{ &hf_bacapp_sent_by,
+			{ "Sent By",
+			"bacapp.segment_sent_by",
+			FT_BOOLEAN, 8, TFS(&tfs_sent_by), 
+			BACAPP_SENT_BY, "Sent By", HFILL }
+		},
+		{ &hf_bacapp_error_choice,
+			{ "Error Choice",           
+			"bacapp.error_choice",
+			FT_UINT8, BASE_DEC, NULL, 0, "Error Choice", HFILL }
+		},
+		{ &hf_bacapp_reject_reason,
+			{ "Reject Reason",           
+			"bacapp.reject_reason",
+			FT_UINT8, BASE_DEC, NULL, 0, "Reject Reason", HFILL }
+		},
+		{ &hf_bacapp_abort_reason,
+			{ "Abort Reason",           
+			"bacapp.abort_reason",
+			FT_UINT8, BASE_DEC, NULL, 0, "Abort Reason", HFILL }
+		},
 	};
+	
 	static gint *ett[] = {
 		&ett_bacapp,
 	};