1 /* packet-ar_drone.c
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
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * SPDX-License-Identifier: GPL-2.0-or-later
13  */
14 
15 #include "config.h"
16 
17 #include <epan/packet.h>
18 #include <epan/expert.h>
19 
20 void proto_register_ar_drone(void);
21 void proto_reg_handoff_ar_drone(void);
22 
23 /* ************************************************ */
24 /* Begin static variable declaration/initialization */
25 /* ************************************************ */
26 
27 /* ar_drone Protocol */
28 static int proto_ar_drone = -1;
29 
30 /* Headers */
31 static int hf_command = -1;
32 static int hf_PCMD_id = -1;
33 static int hf_PCMD_flag = -1;
34 static int hf_PCMD_roll = -1;
35 static int hf_PCMD_pitch = -1;
36 static int hf_PCMD_gaz = -1;
37 static int hf_PCMD_yaw = -1;
38 static int hf_REF_id = -1;
39 static int hf_REF_ctrl = -1;
40 static int hf_FTRIM_seq = -1;
41 static int hf_CONFIG_seq = -1;
42 static int hf_CONFIG_name = -1;
43 static int hf_CONFIG_val = -1;
44 static int hf_CONFIG_ID_seq = -1;
45 static int hf_CONFIG_ID_session = -1;
46 static int hf_CONFIG_ID_user = -1;
47 static int hf_CONFIG_ID_app = -1;
48 static int hf_COMWDG = -1;
49 static int hf_LED_seq = -1;
50 static int hf_LED_anim = -1;
51 static int hf_LED_freq = -1;
52 static int hf_LED_sec = -1;
53 static int hf_ANIM_seq = -1;
54 static int hf_ANIM_anim = -1;
55 static int hf_ANIM_sec = -1;
56 static int hf_CTRL_seq = -1;
57 static int hf_CTRL_mode = -1;
58 static int hf_CTRL_fsize = -1;
59 
60 /**Subtrees */
61 static gint ett_FTRIM = -1;
62 static gint ett_ar_drone = -1;
63 static gint ett_PCMD = -1;
64 static gint ett_REF = -1;
65 static gint ett_CONFIG = -1;
66 static gint ett_CONFIG_ID = -1;
67 static gint ett_COMWDG = -1;
68 static gint ett_LED = -1;
69 static gint ett_ANIM = -1;
70 static gint ett_CTRL = -1;
71 
72 static expert_field ei_NO_COMMA = EI_INIT;
73 static expert_field ei_NO_CR = EI_INIT;
74 
75 /* Value String */
76 #if 0 /* TODO: Delete these?  Or make use of them? */
77 static const value_string REF_types_vs[] = {
78     { 0x38323038, "FLYING MODE" },
79     { 0x37393532, "EMERGENCY LANDING" },
80     { 0x37363936, "LANDING MODE" },
81     { 0, NULL }
82 };
83 static const value_string PCMD_flag_vs[] = {
84     { 0x30 , "DO NOT ALLOW ROLL/PITCH" },
85     { 0x31 , "ALLOW ROLL/PITCH" },
86     { 0 , NULL }
87 };
88 #endif
89 
90 static const string_string CTRL_mode_vs[] = {
91     { "4" , " (CFG_GET_CONTROL_MODE)" },
92     { "5" , " (ACK_CONTROL_MODE)" },
93     { "6" , " (CUSTOM_CFG_GET_CONTROL_MODE)" },
94     { 0, NULL }
95 };
96 
97 /* ********************************************** */
98 /* End static variable declaration/initialization */
99 /* ********************************************** */
100 static int
dissect_ar_drone(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)101 dissect_ar_drone(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
102 {
103     gint        offset, length;
104     gint        master_offset = 0;
105     proto_item *ti, *sub_item;
106     proto_tree *ar_tree, *sub_tree;
107     char       *command;
108     guint8     *complete_str;
109     guint32     dword;
110 
111     if (tvb_captured_length(tvb) < 4)
112         return 0;
113 
114     /* Make sure the packet we're dissecting is a ar_drone packet
115      *  Cheap string check for 'AT*'
116      */
117     dword = tvb_get_ntoh24(tvb, 0);
118     if (dword != 0x41542a)
119         return 0;
120 
121     col_set_str(pinfo->cinfo, COL_PROTOCOL, "ar_drone");
122     col_set_str(pinfo->cinfo, COL_INFO, "AR Drone Packet");
123 
124     /* Initialize ar_drone Packet tree with subtrees */
125     ti = proto_tree_add_item(tree, proto_ar_drone, tvb, 0, -1, ENC_NA);
126     ar_tree = proto_item_add_subtree(ti, ett_ar_drone);
127 
128     while (tvb_reported_length_remaining(tvb, master_offset) > 3)
129     {
130         /* Get a string to compare our command strings (aka "AT*PCMD", etc.) to */
131         offset = tvb_find_guint8(tvb, master_offset, -1, '=');
132         if (offset < master_offset)
133             return master_offset;
134 
135         command = tvb_get_string_enc(pinfo->pool, tvb, master_offset, offset-master_offset, ENC_ASCII|ENC_NA);
136         complete_str = tvb_get_string_enc(pinfo->pool, tvb, master_offset+3, offset-master_offset-3, ENC_ASCII|ENC_NA);
137         sub_item = proto_tree_add_string(ar_tree, hf_command, tvb, master_offset, -1, complete_str);
138 
139         if (!strncmp(command, "AT*PCMD", 7))
140         {
141             /** Parse according the PCMD layout: */
142             guint8      PCMD_byte;
143             const char *PCMD_str;
144 
145             sub_tree = proto_item_add_subtree(sub_item, ett_PCMD);
146 
147             offset = master_offset + 8;
148 
149             /* Add PCMD ID */
150             length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
151             if (length < 0) {
152                 expert_add_info(pinfo, sub_item, &ei_NO_COMMA);
153                 return offset;
154             }
155             proto_tree_add_item(sub_tree, hf_PCMD_id, tvb, offset, length, ENC_ASCII|ENC_NA);
156             offset += (length + 1);
157 
158             /* Add PCMD Flag */
159             length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
160             if (length < 0) {
161                 expert_add_info(pinfo, sub_item, &ei_NO_COMMA);
162                 return offset;
163             }
164             proto_tree_add_item(sub_tree, hf_PCMD_flag, tvb, offset, length, ENC_ASCII|ENC_NA);
165             offset += (length + 1);
166 
167             /* Add PCMD Roll */
168             length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
169             if (length < 0) {
170                 expert_add_info(pinfo, sub_item, &ei_NO_COMMA);
171                 return offset;
172             }
173             ti = proto_tree_add_item(sub_tree, hf_PCMD_roll, tvb, offset, length, ENC_ASCII|ENC_NA);
174 
175             PCMD_byte = tvb_get_guint8(tvb, offset);
176             if (PCMD_byte == 0x30)
177             {
178                 PCMD_str = " (NO CHANGE)";
179             }
180             else if (PCMD_byte == 0x2d)
181             {
182                 PCMD_byte = tvb_get_guint8(tvb, offset + 1);
183                 if (PCMD_byte == 0x30)
184                 {
185                     PCMD_str = " (NO CHANGE)";
186                 }
187                 else
188                 {
189                     PCMD_str = " (ROLL LEFT)";
190                 }
191             }
192             else
193             {
194                 PCMD_str = " (ROLL RIGHT)";
195             }
196             proto_item_append_text(ti, "%s", PCMD_str);
197             offset += (length + 1);
198 
199             /* Add PCMD Pitch */
200             length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
201             if (length < 0) {
202                 expert_add_info(pinfo, sub_item, &ei_NO_COMMA);
203                 return offset;
204             }
205             ti = proto_tree_add_item(sub_tree, hf_PCMD_pitch, tvb, offset, length, ENC_ASCII|ENC_NA);
206 
207             PCMD_byte = tvb_get_guint8(tvb, offset);
208             if (PCMD_byte == 0x30)
209             {
210                 PCMD_str = " (NO CHANGE)";
211             }
212             else if (PCMD_byte == 0x2d)
213             {
214                 PCMD_byte = tvb_get_guint8(tvb, offset + 1);
215                 if (PCMD_byte == 0x30)
216                 {
217                     PCMD_str = " (NO CHANGE)";
218                 }
219                 else
220                 {
221                     PCMD_str = " (PITCH FORWARD)";
222                 }
223             }
224             else
225             {
226                 PCMD_str = " (PITCH BACKWARD)";
227             }
228             proto_item_append_text(ti, "%s", PCMD_str);
229             offset += (length + 1);
230 
231             /* Add PCMD Gaz */
232             length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
233             if (length < 0) {
234                 expert_add_info(pinfo, sub_item, &ei_NO_COMMA);
235                 return offset;
236             }
237             ti = proto_tree_add_item(sub_tree, hf_PCMD_gaz, tvb, offset, length, ENC_ASCII|ENC_NA);
238 
239             PCMD_byte = tvb_get_guint8(tvb, offset);
240             if (PCMD_byte == 0x30)
241             {
242                 PCMD_str = " (NO CHANGE)";
243             }
244             else if (PCMD_byte == 0x2d)
245             {
246                 PCMD_byte = tvb_get_guint8(tvb, offset + 1);
247                 if (PCMD_byte == 0x30)
248                 {
249                     PCMD_str = " (NO CHANGE)";
250                 }
251                 else
252                 {
253                     PCMD_str = " (DECREASE VERT SPEED)";
254                 }
255             }
256             else
257             {
258                 PCMD_str = " (INCREASE VERT SPEED)";
259             }
260             proto_item_append_text(ti, "%s", PCMD_str);
261             offset += (length + 1);
262 
263             /* Add PCMD Yaw */
264             length = tvb_find_guint8(tvb, offset, -1, 0x0d) - offset;
265             if (length < 0) {
266                 expert_add_info(pinfo, sub_item, &ei_NO_CR);
267                 return offset;
268             }
269             ti = proto_tree_add_item(sub_tree, hf_PCMD_yaw, tvb, offset, length, ENC_ASCII|ENC_NA);
270 
271             PCMD_byte = tvb_get_guint8(tvb, offset);
272             if (PCMD_byte == 0x30)
273             {
274                 PCMD_str = " (NO CHANGE)";
275             }
276             else if (PCMD_byte == 0x2d)
277             {
278                 PCMD_byte = tvb_get_guint8(tvb, offset + 1);
279                 if (PCMD_byte == 0x30)
280                 {
281                     PCMD_str = " (NO CHANGE)";
282                 }
283                 else
284                 {
285                     PCMD_str = " (ROTATE LEFT)";
286                 }
287             }
288             else
289             {
290                 PCMD_str = " (ROTATE RIGHT)";
291             }
292             proto_item_append_text(ti, "%s", PCMD_str);
293             offset += (length + 1);
294         }
295         else if (!strncmp(command, "AT*REF", 6))
296         {
297             /** Parse according to the REF layout: */
298             sub_tree = proto_item_add_subtree(sub_item, ett_REF);
299 
300             offset = master_offset + 7;
301 
302             /* Add REF ID */
303             length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
304             if (length < 0) {
305                 expert_add_info(pinfo, sub_item, &ei_NO_COMMA);
306                 return offset;
307             }
308             proto_tree_add_item(sub_tree, hf_REF_id, tvb, offset, length, ENC_ASCII|ENC_NA);
309             offset += (length + 1);
310 
311             /* Add REF ctrl */
312             length = tvb_find_guint8(tvb, offset, -1, 0x0d) - offset;
313             if (length < 0) {
314                 expert_add_info(pinfo, sub_item, &ei_NO_CR);
315                 return offset;
316             }
317             proto_tree_add_item(sub_tree, hf_REF_ctrl, tvb, offset, length, ENC_ASCII|ENC_NA);
318             offset += (length + 1);
319 
320         } else if (!strncmp(command, "AT*CONFIG_IDS", 13))
321         {
322             /** Parse according to the CONFIG_ID layout:  */
323             sub_tree = proto_item_add_subtree(sub_item, ett_CONFIG_ID);
324 
325             offset = master_offset + 14;
326 
327             /* Add Sequence Number */
328             length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
329             if (length < 0) {
330                 expert_add_info(pinfo, sub_item, &ei_NO_COMMA);
331                 return offset;
332             }
333             proto_tree_add_item(sub_tree, hf_CONFIG_ID_seq, tvb, offset, length, ENC_ASCII|ENC_NA);
334             offset += (length + 1);
335 
336             /* Add Session ID */
337             length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
338             if (length < 0) {
339                 expert_add_info(pinfo, sub_item, &ei_NO_COMMA);
340                 return offset;
341             }
342             proto_tree_add_item(sub_tree, hf_CONFIG_ID_session, tvb, offset, length, ENC_ASCII|ENC_NA);
343             offset += (length + 1);
344 
345             /* Add User ID */
346             length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
347             if (length < 0) {
348                 expert_add_info(pinfo, sub_item, &ei_NO_COMMA);
349                 return offset;
350             }
351             proto_tree_add_item(sub_tree, hf_CONFIG_ID_user, tvb, offset, length, ENC_ASCII|ENC_NA);
352             offset += (length + 1);
353 
354             /* Add Application ID */
355             length = tvb_find_guint8(tvb, offset, -1, 0x0d) - offset;
356             if (length < 0) {
357                 expert_add_info(pinfo, sub_item, &ei_NO_CR);
358                 return offset;
359             }
360             proto_tree_add_item(sub_tree, hf_CONFIG_ID_app, tvb, offset, length, ENC_ASCII|ENC_NA);
361             offset += (length + 1);
362 
363         } else if (!strncmp(command, "AT*ANIM", 7))
364         {
365             /** Parse according to the ANIM layout: */
366             sub_tree = proto_item_add_subtree(sub_item, ett_ANIM);
367 
368             offset = master_offset + 8;
369 
370             /* Add sequence */
371             length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
372             if (length < 0) {
373                 expert_add_info(pinfo, sub_item, &ei_NO_COMMA);
374                 return offset;
375             }
376             proto_tree_add_item(sub_tree, hf_ANIM_seq, tvb, offset, length, ENC_ASCII|ENC_NA);
377             offset += (length + 1);
378 
379             /* Add Animation */
380             length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
381             if (length < 0) {
382                 expert_add_info(pinfo, sub_item, &ei_NO_COMMA);
383                 return offset;
384             }
385             proto_tree_add_item(sub_tree, hf_ANIM_anim, tvb, offset, length, ENC_ASCII|ENC_NA);
386             offset += (length + 1);
387 
388             /* Add animation time(sec) */
389             length = tvb_find_guint8(tvb, offset, -1, 0x0d) - offset;
390             if (length < 0) {
391                 expert_add_info(pinfo, sub_item, &ei_NO_CR);
392                 return offset;
393             }
394             proto_tree_add_item(sub_tree, hf_ANIM_sec, tvb, offset, length, ENC_ASCII|ENC_NA);
395             offset += (length + 1);
396 
397         } else if (!strncmp(command, "AT*FTRIM", 8))
398         {
399             /** Parse according to the FTRIM layout: */
400             sub_tree = proto_item_add_subtree(sub_item, ett_FTRIM);
401 
402             offset = master_offset + 9;
403 
404             /* Add sequence number */
405             length = tvb_find_guint8(tvb, offset, -1, 0x0d) - offset;
406             if (length < 0) {
407                 expert_add_info(pinfo, sub_item, &ei_NO_CR);
408                 return offset;
409             }
410             proto_item_append_text(sub_item, " (Sets the reference for the horizontal plane)");
411             proto_tree_add_item(sub_tree, hf_FTRIM_seq, tvb, offset, length, ENC_ASCII|ENC_NA);
412             offset += (length + 1);
413         } else if (!strncmp(command, "AT*CONFIG", 9))
414         {
415             /** Parse according to the CONFIG layout: */
416             sub_tree = proto_item_add_subtree(sub_item, ett_CONFIG);
417 
418             offset = master_offset + 10;
419 
420             /* Add sequence */
421             length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
422             if (length < 0) {
423                 expert_add_info(pinfo, sub_item, &ei_NO_COMMA);
424                 return offset;
425             }
426             proto_tree_add_item(sub_tree, hf_CONFIG_seq, tvb, offset, length, ENC_ASCII|ENC_NA);
427             offset += (length + 1);
428 
429             /* Add Name */
430             length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
431             if (length < 0) {
432                 expert_add_info(pinfo, sub_item, &ei_NO_COMMA);
433                 return offset;
434             }
435             proto_tree_add_item(sub_tree, hf_CONFIG_name, tvb, offset, length, ENC_ASCII|ENC_NA);
436             offset += (length + 1);
437 
438             /* Add Value */
439             length = tvb_find_guint8(tvb, offset, -1, 0x0d) - offset;
440             if (length < 0) {
441                 expert_add_info(pinfo, sub_item, &ei_NO_CR);
442                 return offset;
443             }
444             proto_tree_add_item(sub_tree, hf_CONFIG_val, tvb, offset, length, ENC_ASCII|ENC_NA);
445             offset += (length + 1);
446 
447         } else if (!strncmp(command, "AT*LED", 6))
448         {
449             /** Parse according to the LED layout: */
450             sub_tree = proto_item_add_subtree(sub_item, ett_LED);
451 
452             offset = master_offset + 7;
453 
454             /* Add sequence */
455             length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
456             if (length < 0) {
457                 expert_add_info(pinfo, sub_item, &ei_NO_COMMA);
458                 return offset;
459             }
460             proto_tree_add_item(sub_tree, hf_LED_seq, tvb, offset, length, ENC_ASCII|ENC_NA);
461             offset += (length + 1);
462 
463             /* Add animation to play */
464             length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
465             if (length < 0) {
466                 expert_add_info(pinfo, sub_item, &ei_NO_COMMA);
467                 return offset;
468             }
469             proto_tree_add_item(sub_tree, hf_LED_anim, tvb, offset, length, ENC_ASCII|ENC_NA);
470             offset += (length + 1);
471 
472             /* Add frequency */
473             length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
474             if (length < 0) {
475                 expert_add_info(pinfo, sub_item, &ei_NO_COMMA);
476                 return offset;
477             }
478             proto_tree_add_item(sub_tree, hf_LED_freq, tvb, offset, length, ENC_ASCII|ENC_NA);
479             offset += (length + 1);
480 
481             /* Add Time to play in sec  */
482             length = tvb_find_guint8(tvb, offset, -1, 0x0d) - offset;
483             if (length < 0) {
484                 expert_add_info(pinfo, sub_item, &ei_NO_CR);
485                 return offset;
486             }
487             proto_tree_add_item(sub_tree, hf_LED_sec, tvb, offset, length, ENC_ASCII|ENC_NA);
488             offset += (length + 1);
489 
490         } else if (!strncmp(command, "AT*COMWDG", 9))
491         {
492             /** Parse according to the COMWDG layout: */
493             sub_tree = proto_item_add_subtree(sub_item, ett_COMWDG);
494 
495             offset = master_offset + 10;
496 
497             /* Add sequence number */
498             length = tvb_find_guint8(tvb, offset, -1, 0x0d) - offset;
499             if (length < 0) {
500                 expert_add_info(pinfo, sub_item, &ei_NO_CR);
501                 return offset;
502             }
503             proto_tree_add_item(sub_tree, hf_COMWDG, tvb, offset, length, ENC_ASCII|ENC_NA);
504             offset += (length + 1);
505 
506         }else if (!strncmp(command, "AT*CTRL", 7))
507         {
508             const guint8* CTRL_mode_str;
509 
510             /** Parse according to the CTRL layout: */
511             sub_tree = proto_item_add_subtree(sub_item, ett_CTRL);
512 
513             offset = master_offset + 8;
514 
515             /* Add sequence */
516             length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
517             if (length < 0) {
518                 expert_add_info(pinfo, sub_item, &ei_NO_COMMA);
519                 return offset;
520             }
521             proto_tree_add_item(sub_tree, hf_CTRL_seq, tvb, offset, length, ENC_ASCII|ENC_NA);
522             offset += (length + 1);
523 
524             /* Add Mode */
525             length = tvb_find_guint8(tvb, offset, -1, ',') - offset;
526             if (length < 0) {
527                 expert_add_info(pinfo, sub_item, &ei_NO_COMMA);
528                 return offset;
529             }
530             ti = proto_tree_add_item_ret_string(sub_tree, hf_CTRL_mode, tvb, offset, length, ENC_ASCII|ENC_NA, pinfo->pool, &CTRL_mode_str);
531             proto_item_append_text(ti, "%s", str_to_str(CTRL_mode_str, CTRL_mode_vs, " (Unknown Mode)"));
532             offset += (length + 1);
533 
534             /* Add File Size */
535             length = tvb_find_guint8(tvb, offset, -1, 0x0d) - offset;
536             if (length < 0) {
537                 expert_add_info(pinfo, sub_item, &ei_NO_CR);
538                 return offset;
539             }
540             proto_tree_add_item(sub_tree, hf_CTRL_fsize, tvb, offset, length, ENC_ASCII|ENC_NA);
541             offset += (length + 1);
542         }
543         else
544         {
545             /* Unknown command, just abort */
546             return master_offset;
547         }
548 
549         proto_item_set_len(sub_item, offset-master_offset);
550         master_offset = offset;
551     }
552 
553     return master_offset;
554 }
555 
556 void
proto_register_ar_drone(void)557 proto_register_ar_drone(void)
558 {
559     /* Setup protocol header array */
560     static hf_register_info hf[] = {
561     { &hf_command,
562         { "Command", "ar_drone.command",
563         FT_STRING, BASE_NONE,
564         NULL, 0x0,
565         NULL, HFILL }
566     },
567     { &hf_PCMD_id,
568         { "Sequence Number", "ar_drone.pcmd.id",
569         FT_STRING, BASE_NONE,
570         NULL, 0x0,
571         "Progressive Command ID", HFILL }
572     },
573     { &hf_PCMD_flag,
574         { "Flag", "ar_drone.pcmd.flag",
575         FT_STRING, BASE_NONE,
576         NULL/*VALS(PCMD_flag_vs)*/, 0x0,
577         "Progressive Command Flag", HFILL }
578     },
579     { &hf_PCMD_roll,
580         { "Roll", "ar_drone.pcmd.roll",
581         FT_STRING, BASE_NONE,
582         NULL, 0x0,
583         "Progressive Command Roll", HFILL }
584     },
585     { &hf_PCMD_pitch,
586         { "Pitch", "ar_drone.pcmd.pitch",
587         FT_STRING, BASE_NONE,
588         NULL, 0x0,
589         "Progressive Command Pitch", HFILL }
590     },
591     { &hf_PCMD_gaz,
592         { "Gaz", "ar_drone.pcmd.gaz",
593         FT_STRING, BASE_NONE,
594         NULL, 0x0,
595         "Progressive Command Gaz", HFILL }
596         },
597     { &hf_PCMD_yaw,
598         { "Yaw", "ar_drone.pcmd.yaw",
599         FT_STRING, BASE_NONE,
600         NULL, 0x0,
601         "Progressive Command Yaw", HFILL }
602         },
603     { &hf_REF_id,
604         { "Sequence Number", "ar_drone.ref.id",
605         FT_STRING, BASE_NONE,
606         NULL, 0x0,
607         "Reference ID", HFILL }
608     },
609     { &hf_REF_ctrl,
610         { "Control Command", "ar_drone.ref.ctrl",
611         FT_STRING, BASE_NONE,
612         NULL/*VALS(REF_types_vs)*/, 0x0,
613         NULL, HFILL }
614     },
615     { &hf_FTRIM_seq,
616         { "Sequence Number", "ar_drone.ftrim.seq",
617         FT_STRING, BASE_NONE,
618         NULL, 0x0,
619         "Flap Trim / Horizontal Plane Reference", HFILL }
620     },
621     { &hf_CONFIG_ID_seq,
622         { "Sequence Number", "ar_drone.configids.seq",
623         FT_STRING, BASE_NONE,
624         NULL, 0x0,
625         "Configuration ID sequence number", HFILL }
626     },
627     { &hf_CONFIG_ID_session,
628         { "Current Session ID", "ar_drone.configids.session",
629         FT_STRING, BASE_NONE,
630         NULL, 0x0,
631         "Configuration ID current session ID", HFILL }
632     },
633     { &hf_CONFIG_ID_user,
634         { "Current User ID", "ar_drone.configids.user",
635         FT_STRING, BASE_NONE,
636         NULL, 0x0,
637         "Configuration ID current user ID", HFILL }
638     },
639     { &hf_CONFIG_ID_app,
640         { "Current Application ID", "ar_drone.configids.app",
641         FT_STRING, BASE_NONE,
642         NULL, 0x0,
643         "Configuration ID current application ID", HFILL }
644     },
645     { &hf_COMWDG,
646         { "Command WatchDog Request", "ar_drone.comwdg",
647         FT_STRING, BASE_NONE,
648         NULL, 0x0,
649         "Command WatchDog Reset request", HFILL }
650     },
651     { &hf_CONFIG_seq,
652         { "Sequence Number", "ar_drone.config.seq",
653         FT_STRING, BASE_NONE,
654         NULL, 0x0,
655         "Configuration Seq Num", HFILL }
656     },
657     { &hf_CONFIG_name,
658         { "Option Name", "ar_drone.config.name",
659         FT_STRING, BASE_NONE,
660         NULL, 0x0,
661         NULL, HFILL }
662     },
663     { &hf_CONFIG_val,
664         { "Option Parameter", "ar_drone.config.val",
665         FT_STRING, BASE_NONE,
666         NULL, 0x0,
667         NULL, HFILL }
668     },
669     { &hf_LED_seq,
670         { "Sequence Number", "ar_drone.led.seq",
671         FT_STRING, BASE_NONE,
672         NULL, 0x0,
673         "LED Sequence Number", HFILL }
674     },
675     { &hf_LED_anim,
676         { "Selected Animation", "ar_drone.led.anim",
677         FT_STRING, BASE_NONE,
678         NULL, 0x0,
679         "Selected LED Animation", HFILL }
680     },
681     { &hf_LED_freq,
682         { "Animation Frequency", "ar_drone.led.freq",
683         FT_STRING, BASE_NONE,
684         NULL, 0x0,
685         "LED Animation Frequency", HFILL }
686     },
687     { &hf_LED_sec,
688         { "LED Animation Length (Seconds)", "ar_drone.led.sec",
689         FT_STRING, BASE_NONE,
690         NULL, 0x0,
691         "LED Anim Length", HFILL }
692     },
693     { &hf_ANIM_seq,
694         { "Animation Sequence Number", "ar_drone.anim.seq",
695         FT_STRING, BASE_NONE,
696         NULL, 0x0,
697         "Movement(Animation) Sequence #", HFILL }
698     },
699     { &hf_ANIM_anim,
700         { "Selected Animation Number", "ar_drone.anim.num",
701         FT_STRING, BASE_NONE,
702         NULL, 0x0,
703         "Movement(Animation) to Play", HFILL }
704     },
705     { &hf_ANIM_sec,
706         { "Animation Duration (seconds)", "ar_drone.anim.sec",
707         FT_STRING, BASE_NONE,
708         NULL, 0x0,
709         "Movement(Animation) Time in Seconds", HFILL }
710     },
711     { &hf_CTRL_seq,
712         { "Sequence Number", "ar_drone.ctrl.seq",
713         FT_STRING, BASE_NONE,
714         NULL, 0x0,
715         NULL, HFILL }
716     },
717     { &hf_CTRL_mode,
718         { "Control Mode", "ar_drone.ctrl.mode",
719         FT_STRING, BASE_NONE,
720         NULL, 0x0,
721         NULL, HFILL }
722     },
723     { &hf_CTRL_fsize,
724         { "Firmware Update File Size (0 for no update)", "ar_drone.ctrl.filesize",
725         FT_STRING, BASE_NONE,
726         NULL, 0x0,
727         NULL, HFILL }
728     }
729     };
730 
731     /* Setup protocol subtree array */
732     static gint *ett[] = {
733     &ett_ar_drone,
734     &ett_PCMD,
735     &ett_REF,
736     &ett_FTRIM,
737     &ett_CONFIG,
738     &ett_CONFIG_ID,
739     &ett_COMWDG,
740     &ett_LED,
741     &ett_ANIM,
742     &ett_CTRL
743     };
744 
745     static ei_register_info ei[] = {
746         { &ei_NO_COMMA, { "ar_drone.no_comma", PI_MALFORMED, PI_ERROR, "Comma delimiter not found", EXPFILL }},
747         { &ei_NO_CR,    { "ar_drone.no_cr",    PI_MALFORMED, PI_ERROR, "Carriage return delimiter (0x0d) not found", EXPFILL }},
748     };
749 
750     expert_module_t*  expert_drone;
751 
752     /* Setup protocol info */
753     proto_ar_drone = proto_register_protocol("AR Drone Packet", "AR Drone", "ar_drone");
754 
755     proto_register_field_array(proto_ar_drone, hf, array_length(hf));
756     proto_register_subtree_array(ett, array_length(ett));
757 
758     expert_drone = expert_register_protocol(proto_ar_drone);
759     expert_register_field_array(expert_drone, ei, array_length(ei));
760 }
761 
762 void
proto_reg_handoff_ar_drone(void)763 proto_reg_handoff_ar_drone(void)
764 {
765     dissector_handle_t ar_drone_handle;
766 
767     ar_drone_handle = create_dissector_handle(dissect_ar_drone, proto_ar_drone);
768 
769     heur_dissector_add("udp", dissect_ar_drone, "AR Drone over UDP", "ar_drone_udp", proto_ar_drone, HEURISTIC_ENABLE);
770     dissector_add_for_decode_as_with_preference("udp.port", ar_drone_handle);
771 }
772 
773 /*
774  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
775  *
776  * Local variables:
777  * c-basic-offset: 4
778  * tab-width: 8
779  * indent-tabs-mode: nil
780  * End:
781  *
782  * vi: set shiftwidth=4 tabstop=8 expandtab:
783  * :indentSize=4:tabSize=8:noTabs=true:
784  */
785