2 * Routines for AR ar_drone protocol packet disassembly
3 * By Paul Hoisington <hoisingtonp@bit-sys.com>,
4 * Tom Hildesheim <hildesheimt@bit-sys.com>,
5 * and Claire Brantley <brantleyc@bit-sys.com>
6 * Copyright 2012 BIT Systems
10 * Wireshark - Network traffic analyzer
11 * By Gerald Combs <gerald@wireshark.org>
12 * Copyright 1998 Gerald Combs
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
33 #include <epan/packet.h>
34 #include <epan/prefs.h>
36 static guint ar_drone_port = 0;
38 /* ************************************************ */
39 /* Begin static variable declaration/initialization */
40 /* ************************************************ */
42 /* ar_drone Protocol */
43 static int proto_ar_drone = -1;
46 static int hf_command = -1;
47 static int hf_PCMD_id = -1;
48 static int hf_PCMD_flag = -1;
49 static int hf_PCMD_roll = -1;
50 static int hf_PCMD_pitch = -1;
51 static int hf_PCMD_gaz = -1;
52 static int hf_PCMD_yaw = -1;
53 static int hf_REF_id = -1;
54 static int hf_REF_ctrl = -1;
55 static int hf_FTRIM_seq = -1;
56 static int hf_CONFIG_seq = -1;
57 static int hf_CONFIG_name = -1;
58 static int hf_CONFIG_val = -1;
59 static int hf_CONFIG_ID_seq = -1;
60 static int hf_CONFIG_ID_session = -1;
61 static int hf_CONFIG_ID_user = -1;
62 static int hf_CONFIG_ID_app = -1;
63 static int hf_COMWDG = -1;
64 static int hf_LED_seq = -1;
65 static int hf_LED_anim = -1;
66 static int hf_LED_freq = -1;
67 static int hf_LED_sec = -1;
68 static int hf_ANIM_seq = -1;
69 static int hf_ANIM_anim = -1;
70 static int hf_ANIM_sec = -1;
71 static int hf_CTRL_seq = -1;
72 static int hf_CTRL_mode = -1;
73 static int hf_CTRL_fsize = -1;
76 static gint ett_FTRIM = -1;
77 static gint ett_ar_drone = -1;
78 static gint ett_PCMD = -1;
79 static gint ett_REF = -1;
80 static gint ett_CONFIG = -1;
81 static gint ett_CONFIG_ID = -1;
82 static gint ett_COMWDG = -1;
83 static gint ett_LED = -1;
84 static gint ett_ANIM = -1;
85 static gint ett_CTRL = -1;
88 static const value_string REF_types_vs[] = {
89 { 0x38323038, "FLYING MODE" },
90 { 0x37393532, "EMERGENCY LANDING" },
91 { 0x37363936, "LANDING MODE" },
94 static const value_string PCMD_flag_vs[] = {
95 { 0x30 , "DO NOT ALLOW ROLL/PITCH" },
96 { 0x31 , "ALLOW ROLL/PITCH" },
100 static const string_string CTRL_mode_vs[] = {
101 { "4" , " (CFG_GET_CONTROL_MODE)" },
102 { "5" , " (ACK_CONTROL_MODE)" },
103 { "6" , " (CUSTOM_CFG_GET_CONTROL_MODE)" },
107 /* ********************************************** */
108 /* End static variable declaration/initialization */
109 /* ********************************************** */
111 dissect_ar_drone(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
115 proto_item *ti, *sub_item;
116 proto_tree *ar_tree, *sub_tree;
119 if (!tvb_bytes_exist(tvb, 0, 3))
122 /* Make sure the packet we're dissecting is a ar_drone packet */
123 if(strcmp(tvb_get_ephemeral_string(tvb,0,3),"AT*"))
126 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ar_drone");
127 col_set_str(pinfo->cinfo, COL_INFO,"AR Drone Packet");
129 /* Initialize ar_drone Packet tree with subtrees */
130 ti = proto_tree_add_item(tree, proto_ar_drone, tvb, 0, -1, ENC_NA);
131 ar_tree = proto_item_add_subtree(ti, ett_ar_drone);
133 while(tvb_reported_length_remaining(tvb, master_offset) > 3)
135 /* Get a string to compare our command strings (aka "AT*PCMD", etc.) to */
136 offset = tvb_find_guint8(tvb, master_offset, -1, '=');
137 if (offset < master_offset)
138 return master_offset;
140 command = tvb_get_ephemeral_string(tvb, master_offset, offset-master_offset);
141 sub_item = proto_tree_add_string(ar_tree, hf_command, tvb, master_offset, -1,
142 tvb_get_ephemeral_string(tvb, master_offset+3, offset-master_offset-3));
145 if(!strncmp(command,"AT*PCMD",7))
147 /** Parse according the PCMD layout: */
151 sub_tree = proto_item_add_subtree(sub_item, ett_PCMD);
153 offset = master_offset + 8;
156 length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
157 proto_tree_add_item(sub_tree, hf_PCMD_id, tvb, offset, length, ENC_ASCII|ENC_NA);
158 offset += (length + 1);
161 length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
162 proto_tree_add_item(sub_tree, hf_PCMD_flag, tvb, offset, length, ENC_ASCII|ENC_NA);
163 offset += (length + 1);
166 length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
167 ti = proto_tree_add_item(sub_tree, hf_PCMD_roll, tvb, offset, length, ENC_ASCII|ENC_NA);
169 PCMD_byte = tvb_get_guint8(tvb, offset);
170 if (PCMD_byte == 0x30)
172 PCMD_str = " (NO CHANGE)";
174 else if(PCMD_byte == 0x2d)
176 PCMD_byte = tvb_get_guint8(tvb, offset + 1);
177 if(PCMD_byte == 0x30)
179 PCMD_str = " (NO CHANGE)";
183 PCMD_str = " (ROLL LEFT)";
188 PCMD_str = " (ROLL RIGHT)";
190 proto_item_append_string(ti, PCMD_str);
191 offset += (length + 1);
194 length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
195 ti = proto_tree_add_item(sub_tree, hf_PCMD_pitch, tvb, offset, length, ENC_ASCII|ENC_NA);
197 PCMD_byte = tvb_get_guint8(tvb, offset);
198 if (PCMD_byte == 0x30)
200 PCMD_str = " (NO CHANGE)";
202 else if(PCMD_byte == 0x2d)
204 PCMD_byte = tvb_get_guint8(tvb, offset + 1);
205 if(PCMD_byte == 0x30)
207 PCMD_str = " (NO CHANGE)";
211 PCMD_str = " (PITCH FORWARD)";
216 PCMD_str = " (PITCH BACKWARD)";
218 proto_item_append_string(ti, PCMD_str);
219 offset += (length + 1);
222 length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
223 ti = proto_tree_add_item(sub_tree, hf_PCMD_gaz, tvb, offset, length, ENC_ASCII|ENC_NA);
225 PCMD_byte = tvb_get_guint8(tvb, offset);
226 if (PCMD_byte == 0x30)
228 PCMD_str = " (NO CHANGE)";
230 else if(PCMD_byte == 0x2d)
232 PCMD_byte = tvb_get_guint8(tvb, offset + 1);
233 if(PCMD_byte == 0x30)
235 PCMD_str = " (NO CHANGE)";
239 PCMD_str = " (DECREASE VERT SPEED)";
244 PCMD_str = " (INCREASE VERT SPEED)";
246 proto_item_append_string(ti, PCMD_str);
247 offset += (length + 1);
250 length = tvb_find_guint8(tvb, offset, -1, 0x0d) - offset;
251 ti = proto_tree_add_item(sub_tree, hf_PCMD_yaw, tvb, offset, length, ENC_ASCII|ENC_NA);
253 PCMD_byte = tvb_get_guint8(tvb, offset);
254 if (PCMD_byte == 0x30)
256 PCMD_str = " (NO CHANGE)";
258 else if(PCMD_byte == 0x2d)
260 PCMD_byte = tvb_get_guint8(tvb, offset + 1);
261 if(PCMD_byte == 0x30)
263 PCMD_str = " (NO CHANGE)";
267 PCMD_str = " (ROTATE LEFT)";
272 PCMD_str = " (ROTATE RIGHT)";
274 proto_item_append_string(ti, PCMD_str);
275 offset += (length + 1);
277 else if(!strncmp(command, "AT*REF",6))
279 /** Parse according to the REF layout: */
280 sub_tree = proto_item_add_subtree(sub_item, ett_REF);
282 offset = master_offset + 7;
285 length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
286 proto_tree_add_item(sub_tree, hf_REF_id, tvb, offset, length, ENC_ASCII|ENC_NA);
287 offset += (length + 1);
290 length = tvb_find_guint8(tvb, offset, -1, 0x0d) - offset;
291 proto_tree_add_item(sub_tree, hf_REF_ctrl, tvb, offset, length, ENC_ASCII|ENC_NA);
292 offset += (length + 1);
294 } else if(!strncmp(command, "AT*CONFIG_IDS", 13))
296 /** Parse according to the CONFIG_ID layout: */
297 sub_tree = proto_item_add_subtree(sub_item, ett_CONFIG_ID);
299 offset = master_offset + 14;
301 /* Add Sequence Number */
302 length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
303 proto_tree_add_item(sub_tree, hf_CONFIG_ID_seq, tvb, offset, length, ENC_ASCII|ENC_NA);
304 offset += (length + 1);
307 length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
308 proto_tree_add_item(sub_tree, hf_CONFIG_ID_session, tvb, offset, length, ENC_ASCII|ENC_NA);
309 offset += (length + 1);
312 length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
313 proto_tree_add_item(sub_tree, hf_CONFIG_ID_user, tvb, offset, length, ENC_ASCII|ENC_NA);
314 offset += (length + 1);
316 /* Add Application ID */
317 length = tvb_find_guint8(tvb, offset, -1, 0x0d) - offset;
318 proto_tree_add_item(sub_tree, hf_CONFIG_ID_app, tvb, offset, length, ENC_ASCII|ENC_NA);
319 offset += (length + 1);
321 } else if(!strncmp(command, "AT*ANIM", 7))
323 /** Parse according to the ANIM layout: */
324 sub_tree = proto_item_add_subtree(sub_item, ett_ANIM);
326 offset = master_offset + 8;
329 length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
330 proto_tree_add_item(sub_tree, hf_ANIM_seq, tvb, offset, length, ENC_ASCII|ENC_NA);
331 offset += (length + 1);
334 length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
335 proto_tree_add_item(sub_tree, hf_ANIM_anim, tvb, offset, length, ENC_ASCII|ENC_NA);
336 offset += (length + 1);
338 /* Add animation time(sec) */
339 length = tvb_find_guint8(tvb, offset, -1, 0x0d) - offset;
340 proto_tree_add_item(sub_tree, hf_ANIM_sec, tvb, offset, length, ENC_ASCII|ENC_NA);
341 offset += (length + 1);
343 } else if(!strncmp(command, "AT*FTRIM", 8))
345 /** Parse according to the FTRIM layout: */
346 sub_tree = proto_item_add_subtree(sub_item, ett_FTRIM);
348 offset = master_offset + 9;
350 /* Add sequence number */
351 length = tvb_find_guint8(tvb, offset, -1, 0x0d) - offset;
352 ti = proto_tree_add_text(sub_tree, tvb, master_offset, length, "(Sets the reference for the horizontal plane)");
353 proto_tree_add_item(sub_tree, hf_FTRIM_seq, tvb, offset, length, ENC_ASCII|ENC_NA);
354 offset += (length + 1);\
355 } else if(!strncmp(command, "AT*CONFIG", 9))
357 /** Parse according to the CONFIG layout: */
358 sub_tree = proto_item_add_subtree(sub_item, ett_CONFIG);
360 offset = master_offset + 10;
363 length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
364 proto_tree_add_item(sub_tree, hf_CONFIG_seq, tvb, offset, length, ENC_ASCII|ENC_NA);
365 offset += (length + 1);
368 length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
369 proto_tree_add_item(sub_tree, hf_CONFIG_name, tvb, offset, length, ENC_ASCII|ENC_NA);
370 offset += (length + 1);
373 length = tvb_find_guint8(tvb, offset, -1, 0x0d) - offset;
374 proto_tree_add_item(sub_tree, hf_CONFIG_val, tvb, offset, length, ENC_ASCII|ENC_NA);
375 offset += (length + 1);
377 } else if(!strncmp(command, "AT*LED", 6))
379 /** Parse according to the LED layout: */
380 sub_tree = proto_item_add_subtree(sub_item, ett_LED);
382 offset = master_offset + 7;
385 length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
386 proto_tree_add_item(sub_tree, hf_LED_seq, tvb, offset, length, ENC_ASCII|ENC_NA);
387 offset += (length + 1);
389 /* Add animation to play */
390 length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
391 proto_tree_add_item(sub_tree, hf_LED_anim, tvb, offset, length, ENC_ASCII|ENC_NA);
392 offset += (length + 1);
395 length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
396 proto_tree_add_item(sub_tree, hf_LED_freq, tvb, offset, length, ENC_ASCII|ENC_NA);
397 offset += (length + 1);
399 /* Add Time to play in sec */
400 length = tvb_find_guint8(tvb, offset, -1, 0x0d) - offset;
401 proto_tree_add_item(sub_tree, hf_LED_sec, tvb, offset, length, ENC_ASCII|ENC_NA);
402 offset += (length + 1);
404 }else if(!strncmp(command, "AT*COMWDG", 9))
406 /** Parse according to the COMWDG layout: */
407 sub_tree = proto_item_add_subtree(sub_item, ett_COMWDG);
409 offset = master_offset + 10;
411 /* Add sequence number */
412 length = tvb_find_guint8(tvb, offset, -1, 0x0d) - offset;
413 proto_tree_add_item(sub_tree, hf_COMWDG, tvb, offset, length, ENC_ASCII|ENC_NA);
414 offset += (length + 1);
416 }else if(!strncmp(command, "AT*CTRL", 7))
418 /** Parse according to the CTRL layout: */
419 sub_tree = proto_item_add_subtree(sub_item, ett_CTRL);
421 offset = master_offset + 8;
424 length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
425 proto_tree_add_item(sub_tree, hf_CTRL_seq, tvb, offset, length, ENC_ASCII|ENC_NA);
426 offset += (length + 1);
429 length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
430 ti = proto_tree_add_item(sub_tree, hf_CTRL_mode, tvb, offset, length, ENC_ASCII|ENC_NA);
431 proto_item_append_text(ti, "%s",
432 str_to_str(tvb_get_ephemeral_string(tvb, offset, length), CTRL_mode_vs, " (Unknown Mode)"));
433 offset += (length + 1);
436 length = tvb_find_guint8(tvb, offset, -1, 0x0d) - offset;
437 proto_tree_add_item(sub_tree, hf_CTRL_fsize, tvb, offset, length, ENC_ASCII|ENC_NA);
438 offset += (length + 1);
442 /* Unknown command, just abort */
443 return master_offset;
446 proto_item_set_len(sub_item, offset-master_offset);
447 master_offset = offset;
450 return master_offset;
454 proto_register_ar_drone(void)
456 /* Setup protocol header array */
457 static hf_register_info hf[] = {
459 { "Command", "ar_drone.command",
460 FT_STRING, BASE_NONE,
465 { "Sequence Number", "ar_drone.pcmd.id",
466 FT_STRING, BASE_NONE,
468 "Progressive Command ID", HFILL }
471 { "Flag", "ar_drone.pcmd.flag",
472 FT_STRING, BASE_NONE,
473 NULL/*VALS(PCMD_flag_vs)*/, 0x0,
474 "Progressive Command Flag", HFILL }
477 { "Roll", "ar_drone.pcmd.roll",
478 FT_STRING, BASE_NONE,
480 "Progressive Command Roll", HFILL }
483 { "Pitch", "ar_drone.pcmd.pitch",
484 FT_STRING, BASE_NONE,
486 "Progressive Command Pitch", HFILL }
489 { "Gaz", "ar_drone.pcmd.gaz",
490 FT_STRING, BASE_NONE,
492 "Progressive Command Gaz", HFILL }
495 { "Yaw", "ar_drone.pcmd.yaw",
496 FT_STRING, BASE_NONE,
498 "Progressive Command Yaw", HFILL }
501 { "Sequence Number", "ar_drone.ref.id",
502 FT_STRING, BASE_NONE,
504 "Reference ID", HFILL }
507 { "Control Command", "ar_drone.ref.ctrl",
508 FT_STRING, BASE_NONE,
509 NULL/*VALS(REF_types_vs)*/, 0x0,
513 { "Sequence Number", "ar_drone.ftrim.seq",
514 FT_STRING, BASE_NONE,
516 "Flap Trim / Horizontal Plane Reference", HFILL }
519 { "Sequence Number", "ar_drone.configids.seq",
520 FT_STRING, BASE_NONE,
522 "Configuration ID sequence number", HFILL }
524 { &hf_CONFIG_ID_session,
525 { "Current Session ID", "ar_drone.configids.session",
526 FT_STRING, BASE_NONE,
528 "Configuration ID current session ID", HFILL }
530 { &hf_CONFIG_ID_user,
531 { "Current User ID", "ar_drone.configids.user",
532 FT_STRING, BASE_NONE,
534 "Configuration ID current user ID", HFILL }
537 { "Current Application ID", "ar_drone.configids.app",
538 FT_STRING, BASE_NONE,
540 "Configuration ID current application ID", HFILL }
543 { "Command WatchDog Request", "ar_drone.comwdg",
544 FT_STRING, BASE_NONE,
546 "Command WatchDog Reset request", HFILL }
549 { "Sequence Number", "ar_drone.config.seq",
550 FT_STRING, BASE_NONE,
552 "Configuration Seq Num", HFILL }
555 { "Option Name", "ar_drone.config.name",
556 FT_STRING, BASE_NONE,
561 { "Option Parameter", "ar_drone.config.val",
562 FT_STRING, BASE_NONE,
567 { "Sequence Number", "ar_drone.led.seq",
568 FT_STRING, BASE_NONE,
570 "LED Sequence Number", HFILL }
573 { "Selected Animation", "ar_drone.led.anim",
574 FT_STRING, BASE_NONE,
576 "Selected LED Animation", HFILL }
579 { "Animation Frequency", "ar_drone.led.freq",
580 FT_STRING, BASE_NONE,
582 "LED Animation Frequency", HFILL }
585 { "LED Animation Length (Seconds)", "ar_drone.led.sec",
586 FT_STRING, BASE_NONE,
588 "LED Anim Length", HFILL }
591 { "Animation Sequence Number", "ar_drone.anim.seq",
592 FT_STRING, BASE_NONE,
594 "Movment(Animation) Sequence #", HFILL }
597 { "Selected Animation Number", "ar_drone.anim.num",
598 FT_STRING, BASE_NONE,
600 "Movment(Animation) to Play", HFILL }
603 { "Animation Duration (seconds)", "ar_drone.anim.sec",
604 FT_STRING, BASE_NONE,
606 "Movment(Animation) Time in Seconds", HFILL }
609 { "Sequence Number", "ar_drone.ctrl.seq",
610 FT_STRING, BASE_NONE,
615 { "Control Mode", "ar_drone.ctrl.mode",
616 FT_STRING, BASE_NONE,
621 { "Firmware Update File Size (0 for no update)", "ar_drone.ctrl.filesize",
622 FT_STRING, BASE_NONE,
628 /* Setup protocol subtree array */
629 static gint *ett[] = {
642 module_t *drone_module;
645 /* Setup protocol info */
646 proto_ar_drone = proto_register_protocol (
647 "AR Drone Packet", /* name */
648 "ar drone", /* short name */
649 "ar_drone" /* abbrev */
652 proto_register_field_array(proto_ar_drone, hf, array_length(hf));
653 proto_register_subtree_array(ett, array_length(ett));
655 drone_module = prefs_register_protocol(proto_ar_drone, NULL);
657 prefs_register_uint_preference(drone_module, "udp.port",
666 proto_reg_handoff_ar_drone(void)
668 static dissector_handle_t ar_drone_handle;
669 static guint old_port = 0;
670 static gboolean initialized = FALSE;
672 if (initialized == FALSE) {
673 ar_drone_handle = new_create_dissector_handle(dissect_ar_drone, proto_ar_drone);
675 heur_dissector_add("udp", dissect_ar_drone, proto_ar_drone);
680 /* Register UDP port for dissection */
681 if(old_port != 0 && old_port != ar_drone_port){
682 dissector_delete_uint("udp.port", old_port, ar_drone_handle);
685 if(ar_drone_port != 0 && old_port != ar_drone_port) {
686 dissector_add_uint("udp.port", ar_drone_port, ar_drone_handle);
689 old_port = ar_drone_port;
692 * Editor modelines - http://www.wireshark.org/tools/modelines.html
697 * indent-tabs-mode: nil
700 * vi: set shiftwidth=4 tabstop=4 expandtab:
701 * :indentSize=4:tabSize=4:noTabs=true: