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 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See thehf_class
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include <epan/packet.h>
28 #include <epan/prefs.h>
29 #include <epan/expert.h>
30 #include <epan/wmem/wmem.h>
31 #include <wiretap/wtap.h>
33 #include "packet-adb_service.h"
35 static int proto_adb_cs = -1;
37 static int hf_role = -1;
38 static int hf_hex_ascii_length = -1;
39 static int hf_length = -1;
40 static int hf_service = -1;
41 static int hf_status = -1;
42 static int hf_data = -1;
43 static int hf_fail_reason = -1;
45 static gint ett_adb_cs = -1;
46 static gint ett_length = -1;
48 static expert_field ei_incomplete_message = EI_INIT;
50 static dissector_handle_t adb_cs_handle;
51 static dissector_handle_t adb_service_handle;
52 static dissector_handle_t data_handle;
54 static wmem_tree_t *client_requests = NULL;
56 static guint server_port = 5037;
58 typedef struct _client_request_t {
59 gint64 service_length;
63 gint64 response_frame;
69 static const value_string role_vals[] = {
76 #define SERVICE_NONE NULL
78 #define STATUS_UNKNOWN 0
82 void proto_register_adb_cs(void);
83 void proto_reg_handoff_adb_cs(void);
86 dissect_adb_cs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
88 proto_item *main_item;
89 proto_tree *main_tree;
95 gboolean client_request_service = FALSE;
97 adb_service_data_t adb_service_data;
98 guint32 wireshark_interface_id = 0;
100 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ADB CS");
101 col_clear(pinfo->cinfo, COL_INFO);
103 main_item = proto_tree_add_item(tree, proto_adb_cs, tvb, offset, -1, ENC_NA);
104 main_tree = proto_item_add_subtree(main_item, ett_adb_cs);
106 if (pinfo->phdr->presence_flags & WTAP_HAS_INTERFACE_ID)
107 wireshark_interface_id = pinfo->phdr->interface_id;
109 if (pinfo->destport == server_port) { /* Client sent to Server */
110 client_request_t *client_request;
111 guint8 *service = SERVICE_NONE;
112 wmem_tree_t *subtree;
113 wmem_tree_key_t key[5];
115 direction = P2P_DIR_SENT;
117 p_item = proto_tree_add_uint(main_tree, hf_role, tvb, offset, 0, 0x02);
118 PROTO_ITEM_SET_GENERATED(p_item);
120 col_add_fstr(pinfo->cinfo, COL_INFO, "Client");
122 if (pinfo->phdr->presence_flags & WTAP_HAS_INTERFACE_ID)
123 wireshark_interface_id = pinfo->phdr->interface_id;
126 key[0].key = &wireshark_interface_id;
128 key[1].key = &pinfo->srcport;
130 key[2].key = &pinfo->destport;
134 subtree = (wmem_tree_t *) wmem_tree_lookup32_array(client_requests, key);
135 client_request = (subtree) ? (client_request_t *) wmem_tree_lookup32_le(subtree, pinfo->fd->num) : NULL;
136 if (client_request && client_request->service_in > -1 && client_request->service_in < pinfo->fd->num) {
137 p_item = proto_tree_add_string(main_tree, hf_service, tvb, offset, 0, client_request->service);
138 PROTO_ITEM_SET_GENERATED(p_item);
139 service = client_request->service;
140 client_request_service = TRUE;
142 if (client_request && client_request->service_in > -1 && client_request->service_in <= pinfo->fd->num)
143 client_request_service = TRUE;
144 client_request = NULL;
147 /* heuristic to recognize type of (partial) packet */
148 if (tvb_reported_length_remaining(tvb, offset) >= 4) {
149 guint8 hex_ascii_length[5];
152 hex_ascii_length[4] = 0;
154 tvb_memcpy(tvb, hex_ascii_length, offset, 4);
155 if (g_ascii_xdigit_value(hex_ascii_length[0]) >= 0 &&
156 g_ascii_xdigit_value(hex_ascii_length[1]) >= 0 &&
157 g_ascii_xdigit_value(hex_ascii_length[2]) >= 0 &&
158 g_ascii_xdigit_value(hex_ascii_length[3]) >= 0) {
159 /* probably 4 bytes ascii hex length field */
160 offset = dissect_ascii_uint32(main_tree, hf_hex_ascii_length, ett_length, hf_length, tvb, offset, &ulength);
161 length = (gint64) ulength;
162 col_append_fstr(pinfo->cinfo, COL_INFO, " Length=%u", ulength);
167 if (length == -1 && service) {
168 col_append_fstr(pinfo->cinfo, COL_INFO, " Service=<%s>", service);
169 length = tvb_captured_length(tvb);
171 /* Decode services */
172 adb_service_data.service = service;
173 adb_service_data.direction = direction;
175 adb_service_data.session_key_length = 3;
176 adb_service_data.session_key = (guint32 *) wmem_alloc(wmem_packet_scope(), adb_service_data.session_key_length * sizeof(guint32));
177 adb_service_data.session_key[0] = wireshark_interface_id;
178 adb_service_data.session_key[1] = pinfo->destport;
179 adb_service_data.session_key[2] = pinfo->srcport;
181 next_tvb = tvb_new_subset(tvb, offset, tvb_captured_length_remaining(tvb, offset), tvb_captured_length_remaining(tvb, offset));
182 call_dissector_with_data(adb_service_handle, next_tvb, pinfo, tree, &adb_service_data);
184 return tvb_captured_length(tvb);
187 if (!pinfo->fd->flags.visited && length > 0) { /* save Length to client_requests */
188 if (pinfo->phdr->presence_flags & WTAP_HAS_INTERFACE_ID)
189 wireshark_interface_id = pinfo->phdr->interface_id;
192 key[0].key = &wireshark_interface_id;
194 key[1].key = &pinfo->srcport;
196 key[2].key = &pinfo->destport;
198 key[3].key = &pinfo->fd->num;
202 client_request = wmem_new(wmem_file_scope(), client_request_t);
204 client_request->service_length = length;
205 client_request->service = SERVICE_NONE;
206 client_request->response_frame = -1;
207 client_request->first_in = pinfo->fd->num;
208 client_request->service_in = -1;
209 client_request->data_length = -1;
210 wmem_tree_insert32_array(client_requests, key, client_request);
213 if (!pinfo->fd->flags.visited && (length == -1 || (client_request && client_request->service_in == -1 && tvb_reported_length_remaining(tvb, offset) > 0))) { /* save Service to client_requests */
214 if (!client_request) {
215 if (pinfo->phdr->presence_flags & WTAP_HAS_INTERFACE_ID)
216 wireshark_interface_id = pinfo->phdr->interface_id;
219 key[0].key = &wireshark_interface_id;
221 key[1].key = &pinfo->srcport;
223 key[2].key = &pinfo->destport;
227 subtree = (wmem_tree_t *) wmem_tree_lookup32_array(client_requests, key);
228 client_request = (subtree) ? (client_request_t *) wmem_tree_lookup32_le(subtree, pinfo->fd->num - 1) : NULL;
231 if (client_request) {
232 client_request->service = (guint8 *) wmem_alloc(wmem_file_scope(), (const size_t)(client_request->service_length + 1));
233 tvb_memcpy(tvb, client_request->service, offset, (size_t) client_request->service_length);
234 client_request->service[client_request->service_length] = '\0';
235 client_request->service_in = pinfo->fd->num;
239 if (!client_request_service && tvb_reported_length_remaining(tvb, offset) > 0) {
240 col_append_fstr(pinfo->cinfo, COL_INFO, " Unknown service");
241 proto_tree_add_item(main_tree, hf_data, tvb, offset, -1, ENC_NA);
242 } else if (tvb_reported_length_remaining(tvb, offset) > 0) {
243 proto_tree_add_item(main_tree, hf_service, tvb, offset, -1, ENC_NA | ENC_ASCII);
245 service = (guint8 *) wmem_alloc(wmem_packet_scope(), tvb_reported_length_remaining(tvb, offset) + 1);
246 tvb_memcpy(tvb, service, offset, tvb_reported_length_remaining(tvb, offset));
247 service[tvb_reported_length_remaining(tvb, offset)] = '\0';
248 col_append_fstr(pinfo->cinfo, COL_INFO, " Service=<%s>", service);
251 offset = tvb_captured_length(tvb);
253 } else if (pinfo->srcport == server_port) { /* Server sent to Client */
254 guint8 *service = SERVICE_NONE;
255 wmem_tree_t *subtree;
256 wmem_tree_key_t key[5];
257 client_request_t *client_request;
258 gint64 response_frame = -1;
259 guint8 status = STATUS_UNKNOWN;
261 direction = P2P_DIR_RECV;
264 key[0].key = &wireshark_interface_id;
266 key[1].key = &pinfo->destport;
268 key[2].key = &pinfo->srcport;
272 subtree = (wmem_tree_t *) wmem_tree_lookup32_array(client_requests, key);
273 client_request = (subtree) ? (client_request_t *) wmem_tree_lookup32_le(subtree, pinfo->fd->num - 1) : NULL;
274 if (client_request) {
275 service = client_request->service;
276 status = client_request->status;
277 length = client_request->data_length;
278 response_frame = client_request->response_frame;
281 p_item = proto_tree_add_uint(main_tree, hf_role, tvb, offset, 0, 0x01);
282 PROTO_ITEM_SET_GENERATED(p_item);
284 p_item = proto_tree_add_string(main_tree, hf_service, tvb, offset, 0, service);
285 PROTO_ITEM_SET_GENERATED(p_item);
287 col_add_fstr(pinfo->cinfo, COL_INFO, "Server");
290 col_append_fstr(pinfo->cinfo, COL_INFO, " Unknown service");
291 proto_tree_add_item(main_tree, hf_data, tvb, offset, -1, ENC_NA);
293 return tvb_captured_length(tvb);
296 if (response_frame == -1 || response_frame == (gint64) pinfo->fd->num) {
297 proto_tree_add_item(main_tree, hf_status, tvb, offset, 4, ENC_NA | ENC_ASCII);
298 col_append_fstr(pinfo->cinfo, COL_INFO, " Status=%c%c%c%c", tvb_get_guint8(tvb, offset),
299 tvb_get_guint8(tvb, offset + 1), tvb_get_guint8(tvb, offset + 2), tvb_get_guint8(tvb, offset + 3));
302 if (tvb_memeql(tvb, offset - 4, "FAIL", 4) == 0) {
305 offset = dissect_ascii_uint32(main_tree, hf_hex_ascii_length, ett_length, hf_length, tvb, offset, &ulength);
306 length = (gint64) ulength;
308 status = STATUS_FAIL;
309 } else if (tvb_memeql(tvb, offset - 4, "OKAY", 4) == 0) {
310 status = STATUS_OKAY;
314 if (!pinfo->fd->flags.visited && client_request) {
315 client_request->response_frame = pinfo->fd->num;
316 client_request->status = status;
317 client_request->data_length = length;
321 col_append_fstr(pinfo->cinfo, COL_INFO, " Service=<%s>", service);
323 if (tvb_reported_length_remaining(tvb, offset) <= 0) return offset;
325 if (status == STATUS_FAIL) {
326 sub_item = proto_tree_add_item(main_tree, hf_fail_reason, tvb, offset, -1, ENC_NA | ENC_ASCII);
327 if (length < tvb_reported_length_remaining(tvb, offset)) {
328 expert_add_info(pinfo, sub_item, &ei_incomplete_message);
331 col_append_fstr(pinfo->cinfo, COL_INFO, " Fail=<%s>", tvb_get_string_enc(wmem_packet_scope(), tvb, offset, tvb_reported_length_remaining(tvb, offset), ENC_ASCII));
332 return tvb_captured_length(tvb);
335 /* Decode services */
336 adb_service_data.service = service;
337 adb_service_data.direction = direction;
339 adb_service_data.session_key_length = 3;
340 adb_service_data.session_key = (guint32 *) wmem_alloc(wmem_packet_scope(), adb_service_data.session_key_length * sizeof(guint32));
341 adb_service_data.session_key[0] = wireshark_interface_id;
342 adb_service_data.session_key[1] = pinfo->destport;
343 adb_service_data.session_key[2] = pinfo->srcport;
345 next_tvb = tvb_new_subset(tvb, offset, tvb_captured_length_remaining(tvb, offset), tvb_captured_length_remaining(tvb, offset));
346 call_dissector_with_data(adb_service_handle, next_tvb, pinfo, tree, &adb_service_data);
347 offset = tvb_captured_length(tvb);
349 col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown role");
351 p_item = proto_tree_add_uint(main_tree, hf_role, tvb, offset, 0, 0x00);
352 PROTO_ITEM_SET_GENERATED(p_item);
354 next_tvb = tvb_new_subset_remaining(tvb, offset);
355 call_dissector(data_handle, next_tvb, pinfo, main_tree);
356 offset += tvb_captured_length_remaining(tvb, offset);
363 proto_register_adb_cs(void)
366 expert_module_t *expert_module;
368 static hf_register_info hf[] = {
370 { "Role", "adb_cs.role",
371 FT_UINT8, BASE_HEX, VALS(role_vals), 0x00,
374 { &hf_hex_ascii_length,
375 { "Hex ASCII Length", "adb_cs.hex_ascii_length",
376 FT_STRING, STR_ASCII, NULL, 0x00,
380 { "Length", "adb_cs.length",
381 FT_UINT32, BASE_DEC_HEX, NULL, 0x00,
385 { "Service", "adb_cs.service",
386 FT_STRING, STR_ASCII, NULL, 0x00,
390 { "Fail Reason", "adb_cs.fail_reason",
391 FT_STRING, STR_ASCII, NULL, 0x00,
395 { "Status", "adb_cs.status",
396 FT_STRING, STR_ASCII, NULL, 0x00,
400 { "Data", "adb_cs.data",
401 FT_BYTES, BASE_NONE, NULL, 0x00,
406 static gint *ett[] = {
411 static ei_register_info ei[] = {
412 { &ei_incomplete_message, { "adb_cs.expert.incomplete_message", PI_PROTOCOL, PI_WARN, "Incomplete message", EXPFILL }},
415 client_requests = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
417 proto_adb_cs = proto_register_protocol("Android Debug Bridge Client-Server", "ADB CS", "adb_cs");
418 adb_cs_handle = new_register_dissector("adb_cs", dissect_adb_cs, proto_adb_cs);
420 proto_register_field_array(proto_adb_cs, hf, array_length(hf));
421 proto_register_subtree_array(ett, array_length(ett));
422 expert_module = expert_register_protocol(proto_adb_cs);
423 expert_register_field_array(expert_module, ei, array_length(ei));
425 module = prefs_register_protocol(proto_adb_cs, NULL);
426 prefs_register_static_text_preference(module, "version",
427 "ADB CS protocol version is compatibile pior to: adb 1.0.31",
428 "Version of protocol supported by this dissector.");
430 prefs_register_uint_preference(module, "server_port",
437 proto_reg_handoff_adb_cs(void)
439 data_handle = find_dissector("data");
440 adb_service_handle = find_dissector("adb_service");
442 dissector_add_for_decode_as("tcp.port", adb_cs_handle);
446 * Editor modelines - http://www.wireshark.org/tools/modelines.html
451 * indent-tabs-mode: nil
454 * vi: set shiftwidth=4 tabstop=8 expandtab:
455 * :indentSize=4:tabSize=8:noTabs=true: