Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-sinecap.c
blob7810952fdc25c98b35b1c66f220289bb7b74a5d9
1 /* packet-sinecap.c
3 * Author: Nikolas Koesling, 2023 (nikolas@koesling.info)
4 * Description: Wireshark dissector for the SINEC AP protocol according to
5 * https://cache.industry.siemens.com/dl/files/274/22090274/att_83836/v1/447_840_840C_880_Computer_Link_General_Description.pdf
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * SPDX-License-Identifier: GPL-2.0-or-later
14 #include "config.h"
15 #include <epan/packet.h>
17 #define PROTO_TAG_AP "SINEC-AP"
19 /* Min. telegram length for heuristic check */
20 #define TXP_MIN_TELEGRAM_LENGTH 22
22 /* Wireshark ID of the AP1 protocol */
23 static int proto_ap;
25 static int hf_ap_protoid;
26 static int hf_ap_mpxadr;
27 static int hf_ap_comcls;
28 static int hf_ap_comcod;
29 static int hf_ap_modfr1;
30 static int hf_ap_modfr2;
31 static int hf_ap_errcls;
32 static int hf_ap_errcod;
33 static int hf_ap_rosctr;
34 static int hf_ap_sgsqnr;
35 static int hf_ap_tactid;
36 static int hf_ap_tasqnr;
37 static int hf_ap_spare;
38 static int hf_ap_pduref;
39 static int hf_ap_pduid;
40 static int hf_ap_pdulg;
41 static int hf_ap_parlg;
42 static int hf_ap_datlg;
44 static int ett_ap;
46 static heur_dissector_list_t ap_heur_subdissector_list;
48 static const value_string vs_comcls[] = {
49 {0x0, "ACK without data"},
50 {0x4, "Serial transfer"},
51 {0, NULL}
54 static const value_string vs_protid[] = {
55 {0x0, "SINEC AP 1.0"},
56 {0, NULL}
59 static bool
60 dissect_ap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, void *data _U_)
62 /*----------------- Heuristic Checks - Begin */
63 /* 1) check for minimum length */
64 if (tvb_captured_length(tvb) < TXP_MIN_TELEGRAM_LENGTH)
65 return false;
67 /* 2) protocol id == 0 */
68 if (tvb_get_uint8(tvb, 0) != 0)
69 return false;
70 /*----------------- Heuristic Checks - End */
72 col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTO_TAG_AP);
73 col_clear(pinfo->cinfo, COL_INFO);
75 uint8_t comcls = tvb_get_uint8(tvb, 2);
77 int offset = 16;
78 uint16_t pdulg = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
79 offset += 4;
81 uint16_t datlg = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
82 offset += 2;
84 ws_assert(offset == 22);
86 /* check pdu and data length */
87 if (pdulg != tvb_captured_length(tvb))
88 return false;
89 if (datlg != tvb_captured_length(tvb) - 22)
90 return false;
92 switch (comcls) {
93 case 0x0: {
94 // ack without data
95 col_append_str(pinfo->cinfo, COL_INFO, "ACK without data");
96 break;
98 case 0x4: {
99 // serial transfer
100 col_append_str(pinfo->cinfo, COL_INFO, "Serial transfer");
101 break;
103 default:
104 col_append_str(pinfo->cinfo, COL_INFO, "UNKNOWN command class");
107 proto_item *ap_item = proto_tree_add_item(tree, proto_ap, tvb, 0, -1, ENC_NA);
108 proto_tree *ap_tree = proto_item_add_subtree(ap_item, ett_ap);
110 offset = 0;
111 proto_tree_add_item(ap_tree, hf_ap_protoid, tvb, offset++, 1, ENC_BIG_ENDIAN);
112 proto_tree_add_item(ap_tree, hf_ap_mpxadr, tvb, offset++, 1, ENC_BIG_ENDIAN);
113 proto_tree_add_item(ap_tree, hf_ap_comcls, tvb, offset++, 1, ENC_BIG_ENDIAN);
114 proto_tree_add_item(ap_tree, hf_ap_comcod, tvb, offset++, 1, ENC_BIG_ENDIAN);
116 switch (comcls) {
117 case 0x0: {
118 // ack without data
119 proto_tree_add_item(ap_tree, hf_ap_errcls, tvb, offset++, 1, ENC_BIG_ENDIAN);
120 proto_tree_add_item(ap_tree, hf_ap_errcod, tvb, offset++, 1, ENC_BIG_ENDIAN);
121 break;
123 case 0x4: {
124 // serial transfer
125 proto_tree_add_item(ap_tree, hf_ap_modfr1, tvb, offset++, 1, ENC_BIG_ENDIAN);
126 proto_tree_add_item(ap_tree, hf_ap_modfr2, tvb, offset++, 1, ENC_BIG_ENDIAN);
127 break;
129 default:
130 proto_tree_add_item(ap_tree, hf_ap_modfr1, tvb, offset++, 1, ENC_BIG_ENDIAN);
131 proto_tree_add_item(ap_tree, hf_ap_modfr2, tvb, offset++, 1, ENC_BIG_ENDIAN);
134 proto_tree_add_item(ap_tree, hf_ap_rosctr, tvb, offset++, 1, ENC_BIG_ENDIAN);
135 proto_tree_add_item(ap_tree, hf_ap_sgsqnr, tvb, offset++, 1, ENC_BIG_ENDIAN);
136 proto_tree_add_item(ap_tree, hf_ap_tactid, tvb, offset++, 1, ENC_BIG_ENDIAN);
137 proto_tree_add_item(ap_tree, hf_ap_tasqnr, tvb, offset++, 1, ENC_BIG_ENDIAN);
138 proto_tree_add_item(ap_tree, hf_ap_spare, tvb, offset, 2, ENC_BIG_ENDIAN);
139 offset += 2;
140 proto_tree_add_item(ap_tree, hf_ap_pduref, tvb, offset, 2, ENC_BIG_ENDIAN);
141 offset += 2;
142 proto_tree_add_item(ap_tree, hf_ap_pduid, tvb, offset, 2, ENC_BIG_ENDIAN);
143 offset += 2;
144 proto_tree_add_item(ap_tree, hf_ap_pdulg, tvb, offset, 2, ENC_BIG_ENDIAN);
145 offset += 2;
146 proto_tree_add_item(ap_tree, hf_ap_parlg, tvb, offset, 2, ENC_BIG_ENDIAN);
147 offset += 2;
148 proto_tree_add_item(ap_tree, hf_ap_datlg, tvb, offset, 2, ENC_BIG_ENDIAN);
149 offset += 2;
151 ws_assert(offset == 22);
153 if (tvb_reported_length_remaining(tvb, offset) > 0) {
154 struct tvbuff *next_tvb = tvb_new_subset_remaining(tvb, offset);
155 heur_dtbl_entry_t *hdtbl_entry;
156 if (!dissector_try_heuristic(ap_heur_subdissector_list, next_tvb, pinfo, tree, &hdtbl_entry, NULL)) {
157 call_data_dissector(next_tvb, pinfo, tree);
161 return true;
164 void
165 proto_register_ap(void)
167 static hf_register_info hf[] = {
168 {&hf_ap_protoid, {"PROTID", "sinecap.protid", FT_UINT8, BASE_HEX, VALS(vs_protid), 0x0, "Protocol version", HFILL}},
169 {&hf_ap_mpxadr, {"MPXADR", "sinecap.mpxadr", FT_UINT8, BASE_HEX, NULL, 0x0, "Multiplex address", HFILL}},
170 {&hf_ap_comcls, {"COMCLS", "sinecap.comcls", FT_UINT8, BASE_HEX, VALS(vs_comcls), 0x0, "Command class", HFILL}},
171 {&hf_ap_comcod, {"COMCOD", "sinecap.comcod", FT_UINT8, BASE_HEX, NULL, 0x0, "Command code", HFILL}},
172 {&hf_ap_modfr1, {"MODFR1", "sinecap.modfr1", FT_UINT8, BASE_HEX, NULL, 0x0, "Modifier 1", HFILL}},
173 {&hf_ap_errcls, {"ERRCLS", "sinecap.errcls", FT_UINT8, BASE_HEX, NULL, 0x0, "Error class", HFILL}},
174 {&hf_ap_modfr2, {"MODFR2", "sinecap.modfr2", FT_UINT8, BASE_HEX, NULL, 0x0, "Modifier 2", HFILL}},
175 {&hf_ap_errcod, {"ERRCOD", "sinecap.errcod", FT_UINT8, BASE_HEX, NULL, 0x0, "Error code", HFILL}},
176 {&hf_ap_rosctr, {"ROSCTR", "sinecap.rosctr", FT_UINT8, BASE_HEX, NULL, 0x0, "Remote operating service", HFILL}},
177 {&hf_ap_sgsqnr, {"SGSQNR", "sinecap.sgsqnr", FT_UINT8, BASE_HEX_DEC, NULL, 0x0, "Segment sequence number", HFILL}},
178 {&hf_ap_tactid, {"TACTID", "sinecap.tactid", FT_UINT8, BASE_HEX, NULL, 0x0, "Transaction identifier", HFILL}},
179 {&hf_ap_tasqnr, {"TASQNR", "sinecap.tasqnr", FT_UINT8, BASE_HEX, NULL, 0x0, "Transaction sequence number", HFILL}},
180 {&hf_ap_spare, {"SPARE", "sinecap.spare", FT_UINT16, BASE_HEX, NULL, 0x0, "Free space", HFILL}},
181 {&hf_ap_pduref, {"PDUREF", "sinecap.pduref", FT_UINT16, BASE_HEX, NULL, 0x0, "Protocol Data Unit reference", HFILL}},
182 {&hf_ap_pduid, {"PDUID", "sinecap.pduid", FT_UINT16, BASE_HEX, NULL, 0x0, "Protocol Data Unit identifier", HFILL}},
183 {&hf_ap_pdulg, {"PDULG", "sinecap.pdulg", FT_UINT16, BASE_HEX_DEC, NULL, 0x0, "Protocol Data Unit length", HFILL}},
184 {&hf_ap_parlg, {"PARLG", "sinecap.parlg", FT_UINT16, BASE_HEX_DEC, NULL, 0x0, "Parameter length", HFILL}},
185 {&hf_ap_datlg, {"DATLG", "sinecap.datlg", FT_UINT16, BASE_HEX_DEC, NULL, 0x0, "Data length", HFILL}},
188 proto_ap = proto_register_protocol (
189 "SINEC AP Telegram", /* name */
190 "SINEC AP", /* short name */
191 "sinecap" /* filter_name */
194 static int *ett[] = {
195 &ett_ap,
198 proto_register_field_array(proto_ap, hf, array_length(hf));
199 proto_register_subtree_array(ett, array_length (ett));
200 ap_heur_subdissector_list = register_heur_dissector_list_with_description("sinecap", "SINEC AP data", proto_ap);
203 void
204 proto_reg_handoff_ap(void)
206 heur_dissector_add("cotp", dissect_ap, "SINEC AP Telegram over COTP", "sinecap", proto_ap, HEURISTIC_ENABLE);
207 heur_dissector_add("cotp_is", dissect_ap, "SINEC AP Telegram over COTP", "sinecap_is", proto_ap, HEURISTIC_ENABLE);