Huge thanks to our Platinum Members Endace and LiveAction,
and our Silver Member Veeam, for supporting the Wireshark Foundation and project.

Wireshark-users: [Wireshark-users] STANAG 5066 SIS Dissector and ACP142/DMP

Date Prev · Date Next · Thread Prev · Thread Next
From: Ricardo Cristian Ramirez <r.cristian.ramirez@xxxxxxxxx>
Date: Fri, 2 Jan 2015 03:49:42 +0200
Hi,

I have been analyzing Acp 142 (P_Mul) data over IP network and
everything was fine. However, I couldn't analyze Acp 142 data over HF
network (STANAG 5066).

S'5066 SIS dissector displays the data section (UPDU) succesfully but
this UPDU contains transport layer header of S'5066 network when the
S'5066 client is TMMHS client (so that it cannot be dissected by Acp
142). The name of the discussed transport layer is RCOP/UDOP and
details are given in STANAG 5066 Ed. 2 ANNEX F.8 and F.9. Header bytes
can be seen as the first six bytes of data section in the attachment
before.cap (00 0X 00 00 20 00).

S'5066 provides HF subnetwork serivce to different type of clients.
Specification describes a transport layer for some clients like Acp
142 and DMP but not for all of them. Since RCOP/UDOP header definition
are given in S'5066 specification, consuming these header bytes in
S'5066 SIS dissector may be appropriate. The attachment s5066sis.diff
suggests below changes:

- When the client type is TMMHS, RCOP or UDOP client (sapid == 2, 6
and 7), add a tree item after the pdu type tree item and display
transport layer content
- If the incoming SIS primitive doesn't contain a UPDU (e.g.
BIND_ACCEPTED), don't add tree item
- Specify an application identifier and register it to the dissector
table ("s5066sis.ctl.appid"). This identifier is used to call related
dissector (Acp 142 or DMP). This make sense because there are
different application identifiers for Acp 142 (0x2000 TMI-1) and DMP
(0x2003 TMI-4).
- If there is not a defined application for the incoming data, call
data handle dissector as usual
- After the above changes, P_Mul tells that it accepts data when the
application identifier is 0x2000.
dissector_add_uint ("s5066sis.ctl.appid", 0x2000, p_mul_handle);
- And in DMP (by the way, I didn't tested DMP):
dissector_add_uint ("s5066sis.ctl.appid", 0x2003, dmp_handle);

The view of the tree is like in atachment after.png

I'm not a wireshark expert but these changes solved my problem. If
there is a better solution, please direct me the right way.

Note: Sometimes, discussed changes causes malformed data assertion for
P_Mul dissector from the statement "DISSECTOR_ASSERT (pkg_data);",
just before the return statement in the register_p_mul_id() function.
When I looked the calls of this function, there is a null check
everytime it is called. Hence, I removed the assertion and it seems
that everytihng is normal.

Thanks.
diff --git a/epan/dissectors/packet-s5066sis.c b/epan/dissectors/packet-s5066sis.c
index f54dc81..e3c5467 100644
--- a/epan/dissectors/packet-s5066sis.c
+++ b/epan/dissectors/packet-s5066sis.c
@@ -37,6 +37,8 @@ void proto_reg_handoff_s5066(void);
 static int dissect_s5066_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data);
 static guint get_s5066_pdu_len(packet_info *pinfo, tvbuff_t *tvb, int offset);
 static int dissect_s5066_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_);
+/* Client transport layer header dissctor */
+static guint dissect_s5066_client_transport_header(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 sapid);
 /* Service type and address dissectors */
 static guint dissect_s5066_servicetype(tvbuff_t *tvb, guint offset, proto_tree *tree);
 static guint dissect_s5066_address(tvbuff_t *tvb, guint offset, proto_tree *tree, gint source);
@@ -72,6 +74,8 @@ static guint dissect_s5066_27(tvbuff_t *tvb, guint offset, proto_tree *tree);
 static gint proto_s5066 = -1;
 static dissector_handle_t data_handle;
 
+static dissector_table_t s5066sis_dissector_table;
+
 /* Enable desegmentation of S5066 over TCP */
 static gboolean s5066_desegment = TRUE;
 /* Dissect old 'edition 1' of STANAG 5066 (It lacks the 'version' field.) */
@@ -179,6 +183,19 @@ static const value_string s5066_st_extended[] = {
 /* Number of retransmissions when in Non-ARQ: */
 static gint hf_s5066_st_retries = -1;
 
+/* Client transport layer header */
+static gint hf_s5066_ctl_conn_id = -1;
+static gint hf_s5066_ctl_reserved = -1;
+static gint hf_s5066_ctl_updu_id = -1;
+static gint hf_s5066_ctl_updu_segment = -1;
+static gint hf_s5066_ctl_app_id = -1;
+static const value_string s5066_client_transport_header[] = {
+	{ 0x2000, "STANAG 4406 ANNEX E: Acp 142 (TMI-1)" },
+	{ 0x2003, "STANAG 4406 ANNEX E: DMP (TMI-4)" }, // TMI-4 is updated with DMP spec.
+	{ 0, NULL },
+};
+gint client_app_id = -1;
+
 /* Type  1: S_BIND_REQUEST */
 static gint hf_s5066_01_sapid = -1;
 static gint hf_s5066_01_rank = -1;
@@ -419,6 +436,7 @@ static gint hf_s5066_27_data = -1;
 static gint ett_s5066 = -1;
 static gint ett_s5066_pdu = -1;
 static gint ett_s5066_servicetype = -1;
+static gint ett_s5066_client_transport_header = -1;
 static gint ett_s5066_address = -1;
 
 void
@@ -463,6 +481,22 @@ proto_register_s5066(void)
 		{ &hf_s5066_st_retries,
 			{ "Minimum number of retransmissions", "s5066sis.st.retries", FT_UINT8, BASE_DEC, NULL, 0xF0, NULL, HFILL }
 		},
+        /* Client transport layer header */
+		{ &hf_s5066_ctl_conn_id,
+			{ "Connection ID number", "s5066sis.ctl.conn_id", FT_UINT8, BASE_HEX, NULL, 0xF0, NULL, HFILL }
+		},
+		{ &hf_s5066_ctl_reserved,
+			{ "Reserved", "s5066sis.ctl.reserved", FT_UINT8, BASE_HEX, NULL, 0x0F, NULL, HFILL }
+		},
+		{ &hf_s5066_ctl_updu_id,
+			{ "UPDU ID number", "s5066sis.ctl.updu_id", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }
+		},
+		{ &hf_s5066_ctl_updu_segment,
+			{ "UPDU segment number", "s5066sis.ctl.updu_segment", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }
+		},
+		{ &hf_s5066_ctl_app_id,
+			{ "Application identifier", "s5066sis.ctl.app_id", FT_UINT16, BASE_HEX, VALS(s5066_client_transport_header), 0x0, NULL, HFILL }
+		},
 		/* PDU Type 01: S_BIND_REQUEST */
 		{ &hf_s5066_01_sapid,
 			{ "Sap ID", "s5066sis.01.sapid", FT_UINT8, BASE_DEC, NULL, 0xF0, NULL, HFILL }
@@ -762,6 +796,7 @@ proto_register_s5066(void)
 		&ett_s5066_pdu,
 		&ett_s5066_servicetype,
 		&ett_s5066_address,
+        &ett_s5066_client_transport_header,
 	};
 
 	module_t *s5066_module;
@@ -790,6 +825,9 @@ proto_register_s5066(void)
 				       "Set the port for STANAG 5066 SIS. (If other than the default 5066."
 				       " This number is registered with IANA.)",
 				       10, &global_s5066_port);
+
+    s5066sis_dissector_table = register_dissector_table("s5066sis.ctl.appid", "STANAG 5066 Application Identifier", FT_UINT16, BASE_DEC);
+
 }
 
 void
@@ -857,6 +895,31 @@ dissect_s5066_servicetype(tvbuff_t *tvb, guint offset, proto_tree *tree)
 	return offset;
 }
 
+static guint
+dissect_s5066_client_transport_header(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 sapid)
+{
+    proto_tree *s5066_tree_client_transport_header;
+    
+    if (!((sapid == 2) | (sapid == 6) | (sapid == 7))) {
+        return offset;
+    }
+
+    s5066_tree_client_transport_header = proto_tree_add_subtree(tree->parent, tvb, offset, 6, ett_s5066_client_transport_header, NULL,  "Client Transport Layer Header");
+
+    proto_tree_add_item(s5066_tree_client_transport_header, hf_s5066_ctl_conn_id, tvb, offset, 1, ENC_BIG_ENDIAN);
+    proto_tree_add_item(s5066_tree_client_transport_header, hf_s5066_ctl_reserved, tvb, offset, 1, ENC_BIG_ENDIAN);
+    offset++;
+    proto_tree_add_item(s5066_tree_client_transport_header, hf_s5066_ctl_updu_id, tvb, offset, 1,      ENC_BIG_ENDIAN);
+    offset++;
+    proto_tree_add_item(s5066_tree_client_transport_header, hf_s5066_ctl_updu_segment, tvb, offset, 2, ENC_BIG_ENDIAN);
+    offset += 2;
+    client_app_id = tvb_get_ntohs(tvb, offset);
+    proto_tree_add_item(s5066_tree_client_transport_header, hf_s5066_ctl_app_id, tvb, offset, 2, ENC_BIG_ENDIAN);
+    offset += 2;
+
+    return offset;
+}
+
 /* S_BIND_REQUEST */
 static guint
 dissect_s5066_01(tvbuff_t *tvb, guint offset, proto_tree *tree)
@@ -1058,12 +1121,16 @@ dissect_s5066_19(tvbuff_t *tvb, guint offset, proto_tree *tree, guint pdu_size)
 static guint
 dissect_s5066_20(tvbuff_t *tvb, guint offset, proto_tree *tree)
 {
+	guint8 sapid = 0;
 	proto_tree_add_item(tree, hf_s5066_20_priority, tvb, offset, 1, ENC_BIG_ENDIAN);
+	sapid = tvb_get_guint8(tvb, offset);
+	sapid = sapid & 0x0F;
 	proto_tree_add_item(tree, hf_s5066_20_sapid, tvb, offset, 1, ENC_BIG_ENDIAN); offset++;
 	offset = dissect_s5066_address(tvb, offset, tree, FALSE);
 	offset = dissect_s5066_servicetype(tvb, offset, tree);
 	proto_tree_add_item(tree, hf_s5066_20_ttl, tvb, offset, 3, ENC_BIG_ENDIAN); offset += 3;
 	proto_tree_add_item(tree, hf_s5066_20_size, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
+    offset = dissect_s5066_client_transport_header(tvb, offset, tree, sapid);
 
 	return offset;
 }
@@ -1079,8 +1146,11 @@ dissect_s5066_21(tvbuff_t *tvb, guint offset, proto_tree *tree, guint pdu_size)
 	guint16 no_err_blocks = 0;
 	guint16 no_nrx_blocks = 0;
 	gboolean non_arq_w_errors = FALSE;
+    guint sapid = 0;
 
 	proto_tree_add_item(tree, hf_s5066_21_priority, tvb, offset, 1, ENC_BIG_ENDIAN);
+    sapid = tvb_get_guint8(tvb, offset);
+    sapid = sapid & 0x0F;
 	proto_tree_add_item(tree, hf_s5066_21_dest_sapid, tvb, offset, 1, ENC_BIG_ENDIAN); offset++;
 	offset = dissect_s5066_address(tvb, offset, tree, FALSE);
 
@@ -1119,6 +1189,7 @@ dissect_s5066_21(tvbuff_t *tvb, guint offset, proto_tree *tree, guint pdu_size)
 			proto_tree_add_item(tree, hf_s5066_21_nrx_size, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
 		}
 	}
+	offset = dissect_s5066_client_transport_header(tvb, offset, tree, sapid);
 	return offset;
 }
 
@@ -1127,12 +1198,16 @@ static guint
 dissect_s5066_22(tvbuff_t *tvb, guint offset, proto_tree *tree)
 {
 	guint pdu_size = 0;
+    guint8 sapid = 0;
 	proto_tree_add_item(tree, hf_s5066_22_unused, tvb, offset, 1, ENC_BIG_ENDIAN);
+    sapid = tvb_get_guint8(tvb, offset);
+    sapid = sapid & 0x0F;
 	proto_tree_add_item(tree, hf_s5066_22_sapid, tvb, offset, 1, ENC_BIG_ENDIAN); offset++;
 	offset = dissect_s5066_address(tvb, offset, tree, FALSE);
 	pdu_size = tvb_get_ntohs(tvb, offset);
 	proto_tree_add_item(tree, hf_s5066_22_size, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
 	proto_tree_add_item(tree, hf_s5066_22_data, tvb, offset, pdu_size, ENC_NA); offset += pdu_size;
+	offset = dissect_s5066_client_transport_header(tvb, offset, tree, sapid);
 
 	return offset;
 }
@@ -1142,12 +1217,16 @@ static guint
 dissect_s5066_23(tvbuff_t *tvb, guint offset, proto_tree *tree)
 {
 	guint pdu_size = 0;
+    guint8 sapid = 0;
 	proto_tree_add_item(tree, hf_s5066_23_reason, tvb, offset, 1, ENC_BIG_ENDIAN);
+    sapid = tvb_get_guint8(tvb, offset);
+    sapid = sapid & 0x0F;
 	proto_tree_add_item(tree, hf_s5066_23_sapid, tvb, offset, 1, ENC_BIG_ENDIAN); offset++;
 	offset = dissect_s5066_address(tvb, offset, tree, FALSE);
 	pdu_size = tvb_get_ntohs(tvb, offset);
 	proto_tree_add_item(tree, hf_s5066_23_size, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
 	proto_tree_add_item(tree, hf_s5066_23_data, tvb, offset, pdu_size, ENC_NA); offset += pdu_size;
+	offset = dissect_s5066_client_transport_header(tvb, offset, tree, sapid);
 
 	return offset;
 }
@@ -1156,12 +1235,16 @@ dissect_s5066_23(tvbuff_t *tvb, guint offset, proto_tree *tree)
 static guint
 dissect_s5066_24(tvbuff_t *tvb, guint offset, proto_tree *tree)
 {
+	guint8 sapid = 0;
 	proto_tree_add_item(tree, hf_s5066_24_unused, tvb, offset, 1, ENC_BIG_ENDIAN);
+    sapid = tvb_get_guint8(tvb, offset);
+    sapid = sapid & 0x0F;
 	proto_tree_add_item(tree, hf_s5066_24_sapid, tvb, offset, 1, ENC_BIG_ENDIAN); offset++;
 	offset = dissect_s5066_address(tvb, offset, tree, FALSE);
 	offset = dissect_s5066_servicetype(tvb, offset, tree);
 	proto_tree_add_item(tree, hf_s5066_24_ttl, tvb, offset, 3, ENC_BIG_ENDIAN); offset += 3;
 	proto_tree_add_item(tree, hf_s5066_24_size, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
+	offset = dissect_s5066_client_transport_header(tvb, offset, tree, sapid);
 
 	return offset;
 }
@@ -1177,8 +1260,11 @@ dissect_s5066_25(tvbuff_t *tvb, guint offset, proto_tree *tree, guint pdu_size)
 	guint16 no_err_blocks = 0;
 	guint16 no_nrx_blocks = 0;
 	gboolean non_arq_w_errors = FALSE;
+	guint8 sapid = 0;
 
 	proto_tree_add_item(tree, hf_s5066_25_unused, tvb, offset, 1, ENC_BIG_ENDIAN);
+    sapid = tvb_get_guint8(tvb, offset);
+    sapid = sapid & 0x0F;
 	proto_tree_add_item(tree, hf_s5066_25_dest_sapid, tvb, offset, 1, ENC_BIG_ENDIAN); offset++;
 	offset = dissect_s5066_address(tvb, offset, tree, FALSE);
 
@@ -1217,6 +1303,7 @@ dissect_s5066_25(tvbuff_t *tvb, guint offset, proto_tree *tree, guint pdu_size)
 			proto_tree_add_item(tree, hf_s5066_25_nrx_size, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
 		}
 	}
+	offset = dissect_s5066_client_transport_header(tvb, offset, tree, sapid);
 	return offset;
 }
 
@@ -1225,12 +1312,16 @@ static guint
 dissect_s5066_26(tvbuff_t *tvb, guint offset, proto_tree *tree)
 {
 	guint pdu_size = 0;
+	guint8 sapid = 0;
 	proto_tree_add_item(tree, hf_s5066_26_unused, tvb, offset, 1, ENC_BIG_ENDIAN);
+    sapid = tvb_get_guint8(tvb, offset);
+    sapid = sapid & 0x0F;
 	proto_tree_add_item(tree, hf_s5066_26_sapid, tvb, offset, 1, ENC_BIG_ENDIAN); offset++;
 	offset = dissect_s5066_address(tvb, offset, tree, FALSE);
 	pdu_size = tvb_get_ntohs(tvb, offset);
 	proto_tree_add_item(tree, hf_s5066_26_size, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
 	proto_tree_add_item(tree, hf_s5066_26_data, tvb, offset, pdu_size, ENC_NA); offset += pdu_size;
+	offset = dissect_s5066_client_transport_header(tvb, offset, tree, sapid);
 
 	return offset;
 }
@@ -1240,12 +1331,16 @@ static guint
 dissect_s5066_27(tvbuff_t *tvb, guint offset, proto_tree *tree)
 {
 	guint pdu_size = 0;
+	guint8 sapid = 0;
 	proto_tree_add_item(tree, hf_s5066_27_reason, tvb, offset, 1, ENC_BIG_ENDIAN);
+    sapid = tvb_get_guint8(tvb, offset);
+    sapid = sapid & 0x0F;
 	proto_tree_add_item(tree, hf_s5066_27_sapid, tvb, offset, 1, ENC_BIG_ENDIAN); offset++;
 	offset = dissect_s5066_address(tvb, offset, tree, FALSE);
 	pdu_size = tvb_get_ntohs(tvb, offset);
 	proto_tree_add_item(tree, hf_s5066_27_size, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
 	proto_tree_add_item(tree, hf_s5066_27_data, tvb, offset, pdu_size, ENC_NA); offset += pdu_size;
+	offset = dissect_s5066_client_transport_header(tvb, offset, tree, sapid);
 
 	return offset;
 }
@@ -1351,7 +1446,14 @@ dissect_s5066_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void*
 	available_length = tvb_length(tvb) - offset;
 
 	next_tvb = tvb_new_subset(tvb, offset, MIN(available_length, reported_length), reported_length);
-	call_dissector(data_handle, next_tvb, pinfo, tree);
+    
+    if((client_app_id != -1) & (pdu_type > 19) & (pdu_type < 28)) {
+        dissector_try_uint(s5066sis_dissector_table, client_app_id, next_tvb, pinfo, tree);
+        client_app_id = -1;
+    }
+    else {
+	    call_dissector(data_handle, next_tvb, pinfo, tree);
+    }
 
 	return tvb_length(tvb);
 }

Attachment: before.pcap
Description: Binary data

Attachment: after.png
Description: PNG image