2 * Routines for Android Debug Bridge Client-Server Protocol
4 * Copyright 2014, Michal Labedzki for Tieto Corporation
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
15 #include <epan/packet.h>
16 #include <epan/prefs.h>
17 #include <epan/expert.h>
18 #include <wiretap/wtap.h>
20 #include "packet-adb_service.h"
22 static int proto_adb_cs
;
25 static int hf_hex_ascii_length
;
27 static int hf_service
;
30 static int hf_fail_reason
;
32 static int ett_adb_cs
;
33 static int ett_length
;
35 static expert_field ei_incomplete_message
;
37 static dissector_handle_t adb_cs_handle
;
38 static dissector_handle_t adb_service_handle
;
40 static wmem_tree_t
*client_requests
;
42 static unsigned server_port
= 5037;
44 typedef struct _client_request_t
{
45 int64_t service_length
;
49 int64_t response_frame
;
55 static const value_string role_vals
[] = {
62 #define SERVICE_NONE NULL
64 #define STATUS_UNKNOWN 0
68 void proto_register_adb_cs(void);
69 void proto_reg_handoff_adb_cs(void);
72 dissect_adb_cs(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
74 proto_item
*main_item
;
75 proto_tree
*main_tree
;
81 bool client_request_service
= false;
83 adb_service_data_t adb_service_data
;
84 uint32_t wireshark_interface_id
= 0;
86 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "ADB CS");
87 col_clear(pinfo
->cinfo
, COL_INFO
);
89 main_item
= proto_tree_add_item(tree
, proto_adb_cs
, tvb
, offset
, -1, ENC_NA
);
90 main_tree
= proto_item_add_subtree(main_item
, ett_adb_cs
);
92 if (pinfo
->rec
->presence_flags
& WTAP_HAS_INTERFACE_ID
)
93 wireshark_interface_id
= pinfo
->rec
->rec_header
.packet_header
.interface_id
;
95 if (pinfo
->destport
== server_port
) { /* Client sent to Server */
96 client_request_t
*client_request
;
97 char *service
= SERVICE_NONE
;
99 wmem_tree_key_t key
[5];
101 direction
= P2P_DIR_SENT
;
103 p_item
= proto_tree_add_uint(main_tree
, hf_role
, tvb
, offset
, 0, 0x02);
104 proto_item_set_generated(p_item
);
106 col_set_str(pinfo
->cinfo
, COL_INFO
, "Client");
108 if (pinfo
->rec
->presence_flags
& WTAP_HAS_INTERFACE_ID
)
109 wireshark_interface_id
= pinfo
->rec
->rec_header
.packet_header
.interface_id
;
112 key
[0].key
= &wireshark_interface_id
;
114 key
[1].key
= &pinfo
->srcport
;
116 key
[2].key
= &pinfo
->destport
;
120 subtree
= (wmem_tree_t
*) wmem_tree_lookup32_array(client_requests
, key
);
121 client_request
= (subtree
) ? (client_request_t
*) wmem_tree_lookup32_le(subtree
, pinfo
->num
) : NULL
;
122 if (client_request
&& client_request
->service_in
> -1 && client_request
->service_in
< pinfo
->num
) {
123 p_item
= proto_tree_add_string(main_tree
, hf_service
, tvb
, offset
, 0, client_request
->service
);
124 proto_item_set_generated(p_item
);
125 service
= client_request
->service
;
126 client_request_service
= true;
128 if (client_request
&& client_request
->service_in
> -1 && client_request
->service_in
<= pinfo
->num
)
129 client_request_service
= true;
130 client_request
= NULL
;
133 /* heuristic to recognize type of (partial) packet */
134 if (tvb_reported_length_remaining(tvb
, offset
) >= 4) {
135 uint8_t hex_ascii_length
[5];
138 hex_ascii_length
[4] = 0;
140 tvb_memcpy(tvb
, hex_ascii_length
, offset
, 4);
141 if (g_ascii_xdigit_value(hex_ascii_length
[0]) >= 0 &&
142 g_ascii_xdigit_value(hex_ascii_length
[1]) >= 0 &&
143 g_ascii_xdigit_value(hex_ascii_length
[2]) >= 0 &&
144 g_ascii_xdigit_value(hex_ascii_length
[3]) >= 0) {
145 /* probably 4 bytes ascii hex length field */
146 offset
= dissect_ascii_uint32(main_tree
, hf_hex_ascii_length
, ett_length
, hf_length
, tvb
, offset
, &ulength
);
147 length
= (int64_t) ulength
;
148 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " Length=%u", ulength
);
153 if (length
== -1 && service
) {
154 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " Service=<%s>", service
);
156 /* Decode services */
157 adb_service_data
.service
= service
;
158 adb_service_data
.direction
= direction
;
160 adb_service_data
.session_key_length
= 3;
161 adb_service_data
.session_key
= (uint32_t *) wmem_alloc(pinfo
->pool
, adb_service_data
.session_key_length
* sizeof(uint32_t));
162 adb_service_data
.session_key
[0] = wireshark_interface_id
;
163 adb_service_data
.session_key
[1] = pinfo
->destport
;
164 adb_service_data
.session_key
[2] = pinfo
->srcport
;
166 next_tvb
= tvb_new_subset_remaining(tvb
, offset
);
167 call_dissector_with_data(adb_service_handle
, next_tvb
, pinfo
, tree
, &adb_service_data
);
169 return tvb_captured_length(tvb
);
172 if (!pinfo
->fd
->visited
&& length
> 0) { /* save Length to client_requests */
173 if (pinfo
->rec
->presence_flags
& WTAP_HAS_INTERFACE_ID
)
174 wireshark_interface_id
= pinfo
->rec
->rec_header
.packet_header
.interface_id
;
177 key
[0].key
= &wireshark_interface_id
;
179 key
[1].key
= &pinfo
->srcport
;
181 key
[2].key
= &pinfo
->destport
;
183 key
[3].key
= &pinfo
->num
;
187 client_request
= wmem_new(wmem_file_scope(), client_request_t
);
189 client_request
->service_length
= length
;
190 client_request
->service
= SERVICE_NONE
;
191 client_request
->response_frame
= -1;
192 client_request
->first_in
= pinfo
->num
;
193 client_request
->service_in
= -1;
194 client_request
->data_length
= -1;
195 wmem_tree_insert32_array(client_requests
, key
, client_request
);
198 if (!pinfo
->fd
->visited
&& (length
== -1 || (client_request
&& client_request
->service_in
== -1 && tvb_reported_length_remaining(tvb
, offset
) > 0))) { /* save Service to client_requests */
199 if (!client_request
) {
200 if (pinfo
->rec
->presence_flags
& WTAP_HAS_INTERFACE_ID
)
201 wireshark_interface_id
= pinfo
->rec
->rec_header
.packet_header
.interface_id
;
204 key
[0].key
= &wireshark_interface_id
;
206 key
[1].key
= &pinfo
->srcport
;
208 key
[2].key
= &pinfo
->destport
;
212 subtree
= (wmem_tree_t
*) wmem_tree_lookup32_array(client_requests
, key
);
213 client_request
= (subtree
) ? (client_request_t
*) wmem_tree_lookup32_le(subtree
, pinfo
->num
- 1) : NULL
;
216 if (client_request
) {
218 * I've no idea why the length is 64 bits, but that's
219 * too big to be a field length in Wireshark; if it's
220 * greater than the biggest possible length, clamp it
221 * at the biggest possible length - which is probably
222 * going to be bigger than the available data so that
223 * you'll throw an exception.
226 if (client_request
->service_length
<= INT_MAX
)
227 service_length
= (int)client_request
->service_length
;
229 service_length
= INT_MAX
;
230 client_request
->service
= (char *) tvb_get_string_enc(wmem_file_scope(), tvb
, offset
, service_length
, ENC_ASCII
);
231 client_request
->service_in
= pinfo
->num
;
235 if (!client_request_service
&& tvb_reported_length_remaining(tvb
, offset
) > 0) {
236 col_append_str(pinfo
->cinfo
, COL_INFO
, " Unknown service");
237 proto_tree_add_item(main_tree
, hf_data
, tvb
, offset
, -1, ENC_NA
);
238 } else if (tvb_reported_length_remaining(tvb
, offset
) > 0) {
239 proto_tree_add_item(main_tree
, hf_service
, tvb
, offset
, -1, ENC_NA
| ENC_ASCII
);
241 service
= (char *) tvb_get_string_enc(pinfo
->pool
, tvb
, offset
, tvb_reported_length_remaining(tvb
, offset
), ENC_ASCII
);
242 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " Service=<%s>", service
);
245 offset
= tvb_captured_length(tvb
);
247 } else if (pinfo
->srcport
== server_port
) { /* Server sent to Client */
248 char *service
= SERVICE_NONE
;
249 wmem_tree_t
*subtree
;
250 wmem_tree_key_t key
[5];
251 client_request_t
*client_request
;
252 int64_t response_frame
= -1;
253 uint8_t status
= STATUS_UNKNOWN
;
255 direction
= P2P_DIR_RECV
;
258 key
[0].key
= &wireshark_interface_id
;
260 key
[1].key
= &pinfo
->destport
;
262 key
[2].key
= &pinfo
->srcport
;
266 subtree
= (wmem_tree_t
*) wmem_tree_lookup32_array(client_requests
, key
);
267 client_request
= (subtree
) ? (client_request_t
*) wmem_tree_lookup32_le(subtree
, pinfo
->num
- 1) : NULL
;
268 if (client_request
) {
269 service
= client_request
->service
;
270 status
= client_request
->status
;
271 length
= client_request
->data_length
;
272 response_frame
= client_request
->response_frame
;
275 p_item
= proto_tree_add_uint(main_tree
, hf_role
, tvb
, offset
, 0, 0x01);
276 proto_item_set_generated(p_item
);
278 p_item
= proto_tree_add_string(main_tree
, hf_service
, tvb
, offset
, 0, service
);
279 proto_item_set_generated(p_item
);
281 col_set_str(pinfo
->cinfo
, COL_INFO
, "Server");
284 col_append_str(pinfo
->cinfo
, COL_INFO
, " Unknown service");
285 proto_tree_add_item(main_tree
, hf_data
, tvb
, offset
, -1, ENC_NA
);
287 return tvb_captured_length(tvb
);
290 if (response_frame
== -1 || response_frame
== (int64_t) pinfo
->num
) {
291 proto_tree_add_item(main_tree
, hf_status
, tvb
, offset
, 4, ENC_NA
| ENC_ASCII
);
292 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " Status=%c%c%c%c", tvb_get_uint8(tvb
, offset
),
293 tvb_get_uint8(tvb
, offset
+ 1), tvb_get_uint8(tvb
, offset
+ 2), tvb_get_uint8(tvb
, offset
+ 3));
296 if (tvb_memeql(tvb
, offset
- 4, (const uint8_t *) "FAIL", 4) == 0) {
299 offset
= dissect_ascii_uint32(main_tree
, hf_hex_ascii_length
, ett_length
, hf_length
, tvb
, offset
, &ulength
);
300 length
= (int64_t) ulength
;
302 status
= STATUS_FAIL
;
303 } else if (tvb_memeql(tvb
, offset
- 4, (const uint8_t *) "OKAY", 4) == 0) {
304 status
= STATUS_OKAY
;
308 if (!pinfo
->fd
->visited
&& client_request
) {
309 client_request
->response_frame
= pinfo
->num
;
310 client_request
->status
= status
;
311 client_request
->data_length
= length
;
315 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " Service=<%s>", service
);
317 if (tvb_reported_length_remaining(tvb
, offset
) <= 0) return offset
;
319 if (status
== STATUS_FAIL
) {
321 sub_item
= proto_tree_add_item_ret_string(main_tree
, hf_fail_reason
, tvb
, offset
,
322 tvb_reported_length_remaining(tvb
, offset
), ENC_NA
| ENC_ASCII
, pinfo
->pool
, &str
);
323 if (length
< tvb_reported_length_remaining(tvb
, offset
)) {
324 expert_add_info(pinfo
, sub_item
, &ei_incomplete_message
);
327 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " Fail=<%s>", str
);
328 return tvb_captured_length(tvb
);
331 /* Decode services */
332 adb_service_data
.service
= service
;
333 adb_service_data
.direction
= direction
;
335 adb_service_data
.session_key_length
= 3;
336 adb_service_data
.session_key
= (uint32_t *) wmem_alloc(pinfo
->pool
, adb_service_data
.session_key_length
* sizeof(uint32_t));
337 adb_service_data
.session_key
[0] = wireshark_interface_id
;
338 adb_service_data
.session_key
[1] = pinfo
->destport
;
339 adb_service_data
.session_key
[2] = pinfo
->srcport
;
341 next_tvb
= tvb_new_subset_remaining(tvb
, offset
);
342 call_dissector_with_data(adb_service_handle
, next_tvb
, pinfo
, tree
, &adb_service_data
);
343 offset
= tvb_captured_length(tvb
);
345 col_set_str(pinfo
->cinfo
, COL_INFO
, "Unknown role");
347 p_item
= proto_tree_add_uint(main_tree
, hf_role
, tvb
, offset
, 0, 0x00);
348 proto_item_set_generated(p_item
);
350 next_tvb
= tvb_new_subset_remaining(tvb
, offset
);
351 call_data_dissector(next_tvb
, pinfo
, main_tree
);
352 offset
+= tvb_captured_length_remaining(tvb
, offset
);
359 proto_register_adb_cs(void)
362 expert_module_t
*expert_module
;
364 static hf_register_info hf
[] = {
366 { "Role", "adb_cs.role",
367 FT_UINT8
, BASE_HEX
, VALS(role_vals
), 0x00,
370 { &hf_hex_ascii_length
,
371 { "Hex ASCII Length", "adb_cs.hex_ascii_length",
372 FT_STRING
, BASE_NONE
, NULL
, 0x00,
376 { "Length", "adb_cs.length",
377 FT_UINT32
, BASE_DEC_HEX
, NULL
, 0x00,
381 { "Service", "adb_cs.service",
382 FT_STRING
, BASE_NONE
, NULL
, 0x00,
386 { "Fail Reason", "adb_cs.fail_reason",
387 FT_STRING
, BASE_NONE
, NULL
, 0x00,
391 { "Status", "adb_cs.status",
392 FT_STRING
, BASE_NONE
, NULL
, 0x00,
396 { "Data", "adb_cs.data",
397 FT_BYTES
, BASE_NONE
, NULL
, 0x00,
402 static int *ett
[] = {
407 static ei_register_info ei
[] = {
408 { &ei_incomplete_message
, { "adb_cs.expert.incomplete_message", PI_PROTOCOL
, PI_WARN
, "Incomplete message", EXPFILL
}},
411 client_requests
= wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
413 proto_adb_cs
= proto_register_protocol("Android Debug Bridge Client-Server", "ADB CS", "adb_cs");
414 adb_cs_handle
= register_dissector("adb_cs", dissect_adb_cs
, proto_adb_cs
);
416 proto_register_field_array(proto_adb_cs
, hf
, array_length(hf
));
417 proto_register_subtree_array(ett
, array_length(ett
));
418 expert_module
= expert_register_protocol(proto_adb_cs
);
419 expert_register_field_array(expert_module
, ei
, array_length(ei
));
421 module
= prefs_register_protocol(proto_adb_cs
, NULL
);
422 prefs_register_static_text_preference(module
, "version",
423 "ADB CS protocol version is compatible prior to: adb 1.0.31",
424 "Version of protocol supported by this dissector.");
426 prefs_register_uint_preference(module
, "server_port",
433 proto_reg_handoff_adb_cs(void)
435 adb_service_handle
= find_dissector_add_dependency("adb_service", proto_adb_cs
);
437 dissector_add_for_decode_as_with_preference("tcp.port", adb_cs_handle
);
441 * Editor modelines - https://www.wireshark.org/tools/modelines.html
446 * indent-tabs-mode: nil
449 * vi: set shiftwidth=4 tabstop=8 expandtab:
450 * :indentSize=4:tabSize=8:noTabs=true: