/src/wireshark/epan/dissectors/packet-smp.c
Line | Count | Source |
1 | | /* packet-smp.c |
2 | | * Routines for Session Multiplex Protocol (SMP) dissection |
3 | | * January 2017 Uli Heilmeier with the help of Michael Mann |
4 | | * |
5 | | * Wireshark - Network traffic analyzer |
6 | | * By Gerald Combs <gerald@wireshark.org> |
7 | | * Copyright 1998 Gerald Combs |
8 | | * |
9 | | * SPDX-License-Identifier: GPL-2.0-or-later |
10 | | */ |
11 | | |
12 | | /* |
13 | | * References: |
14 | | * |
15 | | * MC-SMP - https://docs.microsoft.com/en-us/openspecs/windows_protocols/mc-smp |
16 | | * MS-TDS - https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-tds |
17 | | * https://docs.microsoft.com/en-us/sql/relational-databases/native-client/features/using-multiple-active-result-sets-mars |
18 | | * |
19 | | * 0 1 2 3 |
20 | | * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
21 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
22 | | * | SMID | FLAGS | SID | |
23 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
24 | | * | LENGTH | |
25 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
26 | | * | SEQNUM | |
27 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
28 | | * | WNDW | |
29 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
30 | | * | | |
31 | | * / DATA (variable) / |
32 | | * | | |
33 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
34 | | */ |
35 | | |
36 | | #include <config.h> |
37 | | #include <epan/packet.h> |
38 | | #include <epan/prefs.h> |
39 | | #include <epan/decode_as.h> |
40 | | #include <epan/tfs.h> |
41 | | #include <wsutil/array.h> |
42 | | #include "packet-tcp.h" |
43 | | |
44 | | void proto_reg_handoff_smp(void); |
45 | | void proto_register_smp(void); |
46 | | |
47 | | static int proto_smp; |
48 | | |
49 | | static int hf_smp_smid; |
50 | | static int hf_smp_flags; |
51 | | static int hf_smp_flags_syn; |
52 | | static int hf_smp_flags_ack; |
53 | | static int hf_smp_flags_fin; |
54 | | static int hf_smp_flags_data; |
55 | | static int hf_smp_sid; |
56 | | static int hf_smp_length; |
57 | | static int hf_smp_seqnum; |
58 | | static int hf_smp_wndw; |
59 | | static int hf_smp_data; |
60 | | |
61 | | static int ett_smp; |
62 | | static int ett_smp_flags; |
63 | | |
64 | 18 | #define SMP_FLAGS_SYN 0x01 |
65 | 18 | #define SMP_FLAGS_ACK 0x02 |
66 | 18 | #define SMP_FLAGS_FIN 0x04 |
67 | 22 | #define SMP_FLAGS_DATA 0x08 |
68 | | |
69 | 5 | #define SMP_MIN_LENGTH 16 |
70 | | |
71 | | static dissector_handle_t tds_handle; |
72 | | static dissector_handle_t smp_handle; |
73 | | static dissector_table_t smp_payload_table; |
74 | | |
75 | | static bool reassemble_smp = true; |
76 | | |
77 | | static void smp_prompt(packet_info *pinfo _U_, char* result) |
78 | 0 | { |
79 | 0 | snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "Payload as"); |
80 | 0 | } |
81 | | |
82 | | /* Code to actually dissect the packets */ |
83 | | static int |
84 | | dissect_smp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, bool tds_payload) |
85 | 4 | { |
86 | 4 | unsigned offset = 0; |
87 | 4 | unsigned remaining_bytes; |
88 | 4 | proto_item *ti; |
89 | 4 | proto_tree *smp_tree; |
90 | 4 | uint32_t flags, sid, smp_length; |
91 | 4 | tvbuff_t* next_tvb; |
92 | 4 | int parsed_bytes; |
93 | 4 | static int * const flag_fields[] = { |
94 | 4 | &hf_smp_flags_syn, |
95 | 4 | &hf_smp_flags_ack, |
96 | 4 | &hf_smp_flags_fin, |
97 | 4 | &hf_smp_flags_data, |
98 | 4 | NULL |
99 | 4 | }; |
100 | | |
101 | 4 | if (tvb_reported_length(tvb) < SMP_MIN_LENGTH) |
102 | 0 | return 0; |
103 | | |
104 | 4 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "SMP"); |
105 | 4 | col_clear(pinfo->cinfo, COL_INFO); |
106 | | |
107 | 4 | ti = proto_tree_add_item(tree, proto_smp, tvb, 0, -1, ENC_NA); |
108 | 4 | smp_tree = proto_item_add_subtree(ti, ett_smp); |
109 | | |
110 | 4 | proto_tree_add_item(smp_tree, hf_smp_smid, tvb, offset, 1, ENC_NA); |
111 | 4 | offset+=1; |
112 | | |
113 | 4 | proto_tree_add_bitmask(smp_tree, tvb, offset, hf_smp_flags, ett_smp_flags, flag_fields, ENC_NA); |
114 | 4 | flags = tvb_get_uint8(tvb, offset); |
115 | 4 | offset += 1; |
116 | | |
117 | 4 | proto_tree_add_item_ret_uint(smp_tree, hf_smp_sid, tvb, offset, 2, ENC_LITTLE_ENDIAN, &sid); |
118 | 4 | col_append_fstr(pinfo->cinfo, COL_INFO, "SID: %u", sid); |
119 | 4 | offset += 2; |
120 | | |
121 | 4 | if (flags & SMP_FLAGS_SYN) |
122 | 3 | col_append_str(pinfo->cinfo, COL_INFO, ", Syn"); |
123 | 4 | if (flags & SMP_FLAGS_ACK) |
124 | 2 | col_append_str(pinfo->cinfo, COL_INFO, ", Ack"); |
125 | 4 | if (flags & SMP_FLAGS_FIN) |
126 | 1 | col_append_str(pinfo->cinfo, COL_INFO, ", Fin"); |
127 | 4 | if (flags & SMP_FLAGS_DATA) |
128 | 1 | col_append_str(pinfo->cinfo, COL_INFO, ", Data"); |
129 | | |
130 | 4 | proto_tree_add_item_ret_uint(smp_tree, hf_smp_length, tvb, offset, 4, ENC_LITTLE_ENDIAN, &smp_length); |
131 | 4 | offset += 4; |
132 | | |
133 | 4 | proto_tree_add_item(smp_tree, hf_smp_seqnum, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
134 | 4 | offset += 4; |
135 | | |
136 | 4 | proto_tree_add_item(smp_tree, hf_smp_wndw, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
137 | 4 | offset += 4; |
138 | | |
139 | 4 | if ((flags & SMP_FLAGS_DATA) && (tvb_reported_length(tvb) > SMP_MIN_LENGTH)) { |
140 | | |
141 | 1 | next_tvb = tvb_new_subset_remaining(tvb, offset); |
142 | 1 | if (tds_payload) { |
143 | 1 | parsed_bytes = call_dissector(tds_handle, next_tvb, pinfo, tree); |
144 | 1 | } else { |
145 | 0 | parsed_bytes = dissector_try_payload_with_data(smp_payload_table, next_tvb, pinfo, tree, true, NULL); |
146 | 0 | } |
147 | 1 | if (parsed_bytes <= 0) |
148 | 0 | { |
149 | 0 | remaining_bytes = tvb_reported_length_remaining(tvb, offset); |
150 | 0 | if ( remaining_bytes < (smp_length - SMP_MIN_LENGTH)) { |
151 | | // Fragmented |
152 | 0 | proto_tree_add_item(smp_tree, hf_smp_data, tvb, offset, remaining_bytes, ENC_NA); |
153 | 0 | offset += remaining_bytes; |
154 | 0 | } |
155 | 0 | else { |
156 | 0 | proto_tree_add_item(smp_tree, hf_smp_data, tvb, offset, smp_length - SMP_MIN_LENGTH, ENC_NA); |
157 | 0 | offset += (smp_length - SMP_MIN_LENGTH); |
158 | 0 | } |
159 | 0 | } |
160 | 1 | else { |
161 | 1 | offset += parsed_bytes; |
162 | 1 | } |
163 | 1 | } |
164 | | |
165 | 4 | return offset; |
166 | 4 | } |
167 | | |
168 | | static unsigned get_smp_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_) |
169 | 0 | { |
170 | 0 | return tvb_get_letohl(tvb, offset + 4); |
171 | 0 | } |
172 | | |
173 | | static int |
174 | | dissect_smp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) |
175 | 0 | { |
176 | 0 | return dissect_smp_common(tvb, pinfo, tree, false); |
177 | 0 | } |
178 | | |
179 | | static int dissect_smp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) |
180 | 0 | { |
181 | 0 | if ((tvb_reported_length(tvb) > 0) && (tvb_get_uint8(tvb, 0) == 0x53)) { |
182 | 0 | tcp_dissect_pdus(tvb, pinfo, tree, reassemble_smp, SMP_MIN_LENGTH, |
183 | 0 | get_smp_pdu_len, dissect_smp_pdu, data); |
184 | |
|
185 | 0 | return tvb_captured_length(tvb); |
186 | 0 | } |
187 | | |
188 | 0 | return 0; |
189 | 0 | } |
190 | | |
191 | | static int |
192 | | dissect_smp_tds(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) |
193 | 4 | { |
194 | 4 | return dissect_smp_common(tvb, pinfo, tree, true); |
195 | 4 | } |
196 | | |
197 | | void |
198 | | proto_register_smp(void) |
199 | 14 | { |
200 | 14 | static hf_register_info hf[] = { |
201 | 14 | { &hf_smp_smid, |
202 | 14 | { "Smid", "smp.smid", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }}, |
203 | 14 | { &hf_smp_flags, |
204 | 14 | { "Flags", "smp.flags", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } }, |
205 | 14 | { &hf_smp_flags_syn, |
206 | 14 | { "Syn", "smp.flags.syn", FT_BOOLEAN, 8, TFS(&tfs_set_notset), SMP_FLAGS_SYN, NULL, HFILL }}, |
207 | 14 | { &hf_smp_flags_ack, |
208 | 14 | { "Ack", "smp.flags.ack", FT_BOOLEAN, 8, TFS(&tfs_set_notset), SMP_FLAGS_ACK, NULL, HFILL }}, |
209 | 14 | { &hf_smp_flags_fin, |
210 | 14 | { "Fin", "smp.flags.fin", FT_BOOLEAN, 8, TFS(&tfs_set_notset), SMP_FLAGS_FIN, NULL, HFILL }}, |
211 | 14 | { &hf_smp_flags_data, |
212 | 14 | { "Data", "smp.flags.data", FT_BOOLEAN, 8, TFS(&tfs_set_notset), SMP_FLAGS_DATA, NULL, HFILL }}, |
213 | 14 | { &hf_smp_sid, |
214 | 14 | { "SID", "smp.sid", FT_UINT16, BASE_DEC, NULL, 0, "Session ID", HFILL }}, |
215 | 14 | { &hf_smp_length, |
216 | 14 | { "Length", "smp.length", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }}, |
217 | 14 | { &hf_smp_seqnum, |
218 | 14 | { "SeqNum", "smp.seqnum", FT_UINT32, BASE_HEX, NULL, 0, "Sequence Number", HFILL }}, |
219 | 14 | { &hf_smp_wndw, |
220 | 14 | { "Wndw", "smp.wndw", FT_UINT32, BASE_HEX, NULL, 0, "Window Size", HFILL }}, |
221 | 14 | { &hf_smp_data, |
222 | 14 | { "Data", "smp.data", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }}, |
223 | 14 | }; |
224 | | |
225 | 14 | static int *ett[] = { |
226 | 14 | &ett_smp, |
227 | 14 | &ett_smp_flags, |
228 | 14 | }; |
229 | | |
230 | 14 | module_t *smp_module; |
231 | | |
232 | 14 | proto_smp = proto_register_protocol("Session Multiplex Protocol", "SMP", "smp"); |
233 | | |
234 | 14 | proto_register_field_array(proto_smp, hf, array_length(hf)); |
235 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
236 | 14 | register_dissector("smp_tds", dissect_smp_tds, proto_smp); |
237 | 14 | smp_handle = register_dissector("smp", dissect_smp, proto_smp); |
238 | | |
239 | 14 | smp_payload_table = register_decode_as_next_proto(proto_smp, "smp.payload", "SMP Payload", smp_prompt); |
240 | | |
241 | 14 | smp_module = prefs_register_protocol(proto_smp, NULL); |
242 | 14 | prefs_register_bool_preference(smp_module, "desegment", |
243 | 14 | "Reassemble SMP messages spanning multiple TCP segments", |
244 | 14 | "Whether the SMP dissector should reassemble messages spanning multiple TCP segments." |
245 | 14 | " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.", |
246 | 14 | &reassemble_smp); |
247 | 14 | } |
248 | | |
249 | | void |
250 | | proto_reg_handoff_smp(void) |
251 | 14 | { |
252 | 14 | dissector_add_for_decode_as_with_preference("tcp.port", smp_handle); |
253 | | |
254 | 14 | tds_handle = find_dissector_add_dependency("tds", proto_smp); |
255 | 14 | } |
256 | | |
257 | | /* |
258 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
259 | | * |
260 | | * Local variables: |
261 | | * c-basic-offset: 4 |
262 | | * tab-width: 8 |
263 | | * indent-tabs-mode: nil |
264 | | * End: |
265 | | * |
266 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
267 | | * :indentSize=4:tabSize=8:noTabs=true: |
268 | | */ |