1 /* packet-osc.c
2  * Routines for "Open Sound Control" packet dissection
3  * Copyright 2014-2016 Hanspeter Portner <dev@open-music-kontrollers.ch>
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  * Specification 1.1 (http://opensoundcontrol.org/spec-1_1)
14  * - TCP dissection with: SLIP framing
15  * Specification 1.0 (http://opensoundcontrol.org/spec-1_0)
16  * - based on default argument types: i,f,s,b
17  * - including widely used extension types: T,F,N,I,h,d,t,S,c,r,m
18  * - TCP dissection with: int32 size prefix framing
19  * References
20  * - Schmeder, A., Freed, A., and Wessel, D.,
21  *   "Best practices for Open Sound Control",
22  *   Linux Audio Conference, Utrecht, The Netherlands, 2010.
23  * - Freed, A., Schmeder, A.,
24  *   "Features and Future of Open Sound Control version 1.1 for NIME",
25  *   NIME Conference 2009.
26  * - Wright, M., Freed, A.,
27  *   "Open Sound Control: A New Protocol for Communicating with Sound Synthesizers",
28  *   International Computer Music Conference, Thessaloniki, Greece, 1997.
29  * - https://tools.ietf.org/html/rfc1055 (SLIP)
30  */
31 
32 #include "config.h"
33 
34 #include <string.h>
35 #include <epan/packet.h>
36 #include <epan/exceptions.h>
37 #include "packet-tcp.h"
38 
39 void proto_register_osc(void);
40 void proto_reg_handoff_osc(void);
41 
42 /* Open Sound Control (OSC) argument types enumeration */
43 typedef enum _OSC_Type {
44     OSC_INT32   = 'i',
45     OSC_FLOAT   = 'f',
46     OSC_STRING  = 's',
47     OSC_BLOB    = 'b',
48 
49     OSC_TRUE    = 'T',
50     OSC_FALSE   = 'F',
51     OSC_NIL     = 'N',
52     OSC_BANG    = 'I',
53 
54     OSC_INT64   = 'h',
55     OSC_DOUBLE  = 'd',
56     OSC_TIMETAG = 't',
57 
58     OSC_SYMBOL  = 'S',
59     OSC_CHAR    = 'c',
60     OSC_RGBA    = 'r',
61     OSC_MIDI    = 'm'
62 } OSC_Type;
63 
64 /* characters not allowed in OSC path string */
65 static const char invalid_path_chars [] = {
66     ' ', '#',
67     '\0'
68 };
69 
70 /* allowed characters in OSC format string */
71 static const char valid_format_chars [] = {
72     OSC_INT32,  OSC_FLOAT,  OSC_STRING,  OSC_BLOB,
73     OSC_TRUE,   OSC_FALSE,  OSC_NIL,     OSC_BANG,
74     OSC_INT64,  OSC_DOUBLE, OSC_TIMETAG,
75     OSC_SYMBOL, OSC_CHAR,   OSC_RGBA,    OSC_MIDI,
76     '\0'
77 };
78 
79 typedef enum _MIDI_Status_Type {
80     MIDI_STATUS_NOTE_OFF                = 0x8,
81     MIDI_STATUS_NOTE_ON                 = 0x9,
82     MIDI_STATUS_NOTE_PRESSURE           = 0xA,
83     MIDI_STATUS_CONTROLLER              = 0xB,
84     MIDI_STATUS_PROGRAM_CHANGE          = 0xC,
85     MIDI_STATUS_CHANNEL_PRESSURE        = 0xD,
86     MIDI_STATUS_PITCH_BENDER            = 0xE
87 } MIDI_Status_Type;
88 
89 /* Standard MIDI Message Type */
90 static const value_string MIDI_status [] = {
91     { 0x0, "Invalid Message" },
92     { MIDI_STATUS_NOTE_OFF, "Note Off" },
93     { MIDI_STATUS_NOTE_ON, "Note On" },
94     { MIDI_STATUS_NOTE_PRESSURE, "Note Pressure" },
95     { MIDI_STATUS_CONTROLLER, "Controller" },
96     { MIDI_STATUS_PROGRAM_CHANGE, "Program Change" },
97     { MIDI_STATUS_CHANNEL_PRESSURE, "Channel Pressure" },
98     { MIDI_STATUS_PITCH_BENDER, "Pitch Bender" },
99 
100     {0, NULL }
101 };
102 static value_string_ext MIDI_status_ext = VALUE_STRING_EXT_INIT(MIDI_status);
103 
104 /* Standard MIDI Message Type */
105 static const value_string MIDI_system [] = {
106     { 0xF0, "System Exclusive Begin" },
107     { 0xF1, "MTC Quarter Frame" },
108     { 0xF2, "Song Position" },
109     { 0xF3, "Song Select" },
110     { 0xF6, "Tune Request" },
111     { 0xF8, "Clock" },
112     { 0xFA, "Start" },
113     { 0xFB, "Continue" },
114     { 0xFC, "Stop" },
115     { 0xFE, "Active Sensing" },
116     { 0xFF, "Reset" },
117 
118     {0, NULL }
119 };
120 static value_string_ext MIDI_system_ext = VALUE_STRING_EXT_INIT(MIDI_system);
121 
122 /* Standard MIDI Note Numbers */
123 static const value_string MIDI_note [] = {
124     { 0x00, "C-0" }, { 0x01, "#C-0" },
125     { 0x02, "D-0" }, { 0x03, "#D-0" },
126     { 0x04, "E-0" },
127     { 0x05, "F-0" }, { 0x06, "#F-0" },
128     { 0x07, "G-0" }, { 0x08, "#G-0" },
129     { 0x09, "A-0" }, { 0x0A, "#A-0" },
130     { 0x0B, "H-0" },
131 
132     { 0x0C, "C-1" }, { 0x0D, "#C-1" },
133     { 0x0E, "D-1" }, { 0x0F, "#D-1" },
134     { 0x10, "E-1" },
135     { 0x11, "F-1" }, { 0x12, "#F-1" },
136     { 0x13, "G-1" }, { 0x14, "#G-1" },
137     { 0x15, "A-1" }, { 0x16, "#A-1" },
138     { 0x17, "H-1" },
139 
140     { 0x18, "C-2" }, { 0x19, "#C-2" },
141     { 0x1A, "D-2" }, { 0x1B, "#D-2" },
142     { 0x1C, "E-2" },
143     { 0x1D, "F-2" }, { 0x1E, "#F-2" },
144     { 0x1F, "G-2" }, { 0x20, "#G-2" },
145     { 0x21, "A-2" }, { 0x22, "#A-2" },
146     { 0x23, "H-2" },
147 
148     { 0x24, "C-3" }, { 0x25, "#C-3" },
149     { 0x26, "D-3" }, { 0x27, "#D-3" },
150     { 0x28, "E-3" },
151     { 0x29, "F-3" }, { 0x2A, "#F-3" },
152     { 0x2B, "G-3" }, { 0x2C, "#G-3" },
153     { 0x2D, "A-3" }, { 0x2E, "#A-3" },
154     { 0x2F, "H-3" },
155 
156     { 0x30, "C-4" }, { 0x31, "#C-4" },
157     { 0x32, "D-4" }, { 0x33, "#D-4" },
158     { 0x34, "E-4" },
159     { 0x35, "F-4" }, { 0x36, "#F-4" },
160     { 0x37, "G-4" }, { 0x38, "#G-4" },
161     { 0x39, "A-4" }, { 0x3A, "#A-4" },
162     { 0x3B, "H-4" },
163 
164     { 0x3C, "C-5" }, { 0x3D, "#C-5" },
165     { 0x3E, "D-5" }, { 0x3F, "#D-5" },
166     { 0x40, "E-5" },
167     { 0x41, "F-5" }, { 0x42, "#F-5" },
168     { 0x43, "G-5" }, { 0x44, "#G-5" },
169     { 0x45, "A-5" }, { 0x46, "#A-5" },
170     { 0x47, "H-5" },
171 
172     { 0x48, "C-6" }, { 0x49, "#C-6" },
173     { 0x4A, "D-6" }, { 0x4B, "#D-6" },
174     { 0x4C, "E-6" },
175     { 0x4D, "F-6" }, { 0x4E, "#F-6" },
176     { 0x4F, "G-6" }, { 0x50, "#G-6" },
177     { 0x51, "A-6" }, { 0x52, "#A-6" },
178     { 0x53, "H-6" },
179 
180     { 0x54, "C-7" }, { 0x55, "#C-7" },
181     { 0x56, "D-7" }, { 0x57, "#D-7" },
182     { 0x58, "E-7" },
183     { 0x59, "F-7" }, { 0x5A, "#F-7" },
184     { 0x5B, "G-7" }, { 0x5C, "#G-7" },
185     { 0x5D, "A-7" }, { 0x5E, "#A-7" },
186     { 0x5F, "H-7" },
187 
188     { 0x60, "C-8" }, { 0x61, "#C-8" },
189     { 0x62, "D-8" }, { 0x63, "#D-8" },
190     { 0x64, "E-8" },
191     { 0x65, "F-8" }, { 0x66, "#F-8" },
192     { 0x67, "G-8" }, { 0x68, "#G-8" },
193     { 0x69, "A-8" }, { 0x6A, "#A-8" },
194     { 0x6B, "H-8" },
195 
196     { 0x6C, "C-9" }, { 0x6D, "#C-9" },
197     { 0x6E, "D-9" }, { 0x6F, "#D-9" },
198     { 0x70, "E-9" },
199     { 0x71, "F-9" }, { 0x72, "#F-9" },
200     { 0x73, "G-9" }, { 0x74, "#G-9" },
201     { 0x75, "A-9" }, { 0x76, "#A-9" },
202     { 0x77, "H-9" },
203 
204     { 0x78, "C-10" }, { 0x79, "#C-10" },
205     { 0x7A, "D-10" }, { 0x7B, "#D-10" },
206     { 0x7C, "E-10" },
207     { 0x7D, "F-10" }, { 0x7E, "#F-10" },
208     { 0x7F, "G-10" },
209 
210     { 0, NULL }
211 };
212 static value_string_ext MIDI_note_ext = VALUE_STRING_EXT_INIT(MIDI_note);
213 
214 /* Standard MIDI Controller Numbers */
215 static const value_string MIDI_control [] = {
216     { 0x00, "Bank Selection" },
217     { 0x01, "Modulation" },
218     { 0x02, "Breath" },
219     { 0x04, "Foot" },
220     { 0x05, "Portamento Time" },
221     { 0x06, "Data Entry" },
222     { 0x07, "Main Volume" },
223     { 0x08, "Balance" },
224     { 0x0A, "Panpot" },
225     { 0x0B, "Expression" },
226     { 0x0C, "Effect1" },
227     { 0x0D, "Effect2" },
228     { 0x10, "General Purpose 1" },
229     { 0x11, "General Purpose 2" },
230     { 0x12, "General Purpose 3" },
231     { 0x13, "General Purpose 4" },
232     { 0x20, "Bank Selection" },
233     { 0x21, "Modulation" },
234     { 0x22, "Breath" },
235     { 0x24, "Foot" },
236     { 0x25, "Portamento Time" },
237     { 0x26, "Data Entry" },
238     { 0x27, "Main Volume" },
239     { 0x28, "Balance" },
240     { 0x2A, "Panpot" },
241     { 0x2B, "Expression" },
242     { 0x2C, "Effect1" },
243     { 0x2D, "Effect2" },
244     { 0x30, "General Purpose 1" },
245     { 0x31, "General Purpose 2" },
246     { 0x32, "General Purpose 3" },
247     { 0x33, "General Purpose 4" },
248     { 0x40, "Sustain Pedal" },
249     { 0x41, "Portamento" },
250     { 0x42, "Sostenuto" },
251     { 0x43, "Soft Pedal" },
252     { 0x44, "Legato Foot Switch" },
253     { 0x45, "Hold2" },
254     { 0x46, "SC1 Sound Variation" },
255     { 0x47, "SC2 Timbre" },
256     { 0x48, "SC3 Release Time" },
257     { 0x49, "SC4 Attack Time" },
258     { 0x4A, "SC5 Brightness" },
259     { 0x4B, "SC6" },
260     { 0x4C, "SC7" },
261     { 0x4D, "SC8" },
262     { 0x4E, "SC9" },
263     { 0x4F, "SC10" },
264     { 0x50, "General Purpose 5" },
265     { 0x51, "General Purpose 6" },
266     { 0x52, "General Purpose 7" },
267     { 0x53, "General Purpose 8" },
268     { 0x54, "Portamento Control" },
269     { 0x5B, "E1 Reverb Depth" },
270     { 0x5C, "E2 Tremolo Depth" },
271     { 0x5D, "E3 Chorus Depth" },
272     { 0x5E, "E4 Detune Depth" },
273     { 0x5F, "E5 Phaser Depth" },
274     { 0x60, "Data Increment" },
275     { 0x61, "Data Decrement" },
276     { 0x62, "Non-registered Parameter Number" },
277     { 0x63, "Non-registered Parameter Number" },
278     { 0x64, "Registered Parameter Number" },
279     { 0x65, "Registered Parameter Number" },
280     { 0x78, "All Sounds Off" },
281     { 0x79, "Reset Controllers" },
282     { 0x7A, "Local Control Switch" },
283     { 0x7B, "All Notes Off" },
284     { 0x7C, "Omni Off" },
285     { 0x7D, "Omni On" },
286     { 0x7E, "Mono1" },
287     { 0x7F, "Mono2" },
288 
289     { 0, NULL }
290 };
291 static value_string_ext MIDI_control_ext = VALUE_STRING_EXT_INIT(MIDI_control);
292 
293 static const char *immediate_fmt = "%s";
294 static const char *immediate_str = "Immediate";
295 static const char *bundle_str = "#bundle";
296 
297 /* Initialize the protocol and registered fields */
298 static dissector_handle_t osc_udp_handle = NULL;
299 
300 static int proto_osc = -1;
301 
302 static int hf_osc_bundle_type = -1;
303 static int hf_osc_message_type = -1;
304 static int hf_osc_message_header_type = -1;
305 static int hf_osc_message_blob_type = -1;
306 static int hf_osc_message_midi_type = -1;
307 static int hf_osc_message_rgba_type = -1;
308 
309 static int hf_osc_bundle_timetag_type = -1;
310 static int hf_osc_bundle_element_size_type = -1;
311 
312 static int hf_osc_message_path_type = -1;
313 static int hf_osc_message_format_type = -1;
314 
315 static int hf_osc_message_int32_type = -1;
316 static int hf_osc_message_float_type = -1;
317 static int hf_osc_message_string_type = -1;
318 static int hf_osc_message_blob_size_type = -1;
319 static int hf_osc_message_blob_data_type = -1;
320 
321 static int hf_osc_message_true_type = -1;
322 static int hf_osc_message_false_type = -1;
323 static int hf_osc_message_nil_type = -1;
324 static int hf_osc_message_bang_type = -1;
325 
326 static int hf_osc_message_int64_type = -1;
327 static int hf_osc_message_double_type = -1;
328 static int hf_osc_message_timetag_type = -1;
329 
330 static int hf_osc_message_symbol_type = -1;
331 static int hf_osc_message_char_type = -1;
332 
333 static int hf_osc_message_rgba_red_type = -1;
334 static int hf_osc_message_rgba_green_type = -1;
335 static int hf_osc_message_rgba_blue_type = -1;
336 static int hf_osc_message_rgba_alpha_type = -1;
337 
338 static int hf_osc_message_midi_port_type = -1;
339 static int hf_osc_message_midi_system_type = -1;
340 static int hf_osc_message_midi_channel_type = -1;
341 static int hf_osc_message_midi_status_type = -1;
342 static int hf_osc_message_midi_data1_type = -1;
343 static int hf_osc_message_midi_data2_type = -1;
344 static int hf_osc_message_midi_velocity_type = -1;
345 static int hf_osc_message_midi_pressure_type = -1;
346 static int hf_osc_message_midi_note_type = -1;
347 static int hf_osc_message_midi_controller_type = -1;
348 static int hf_osc_message_midi_bender_type = -1;
349 
350 /* Initialize the subtree pointers */
351 static int ett_osc_packet = -1;
352 static int ett_osc_bundle = -1;
353 static int ett_osc_message = -1;
354 static int ett_osc_message_header = -1;
355 static int ett_osc_blob = -1;
356 static int ett_osc_rgba = -1;
357 static int ett_osc_midi = -1;
358 
359 /* check for valid path string */
360 static gboolean
is_valid_path(const char * path)361 is_valid_path(const char *path)
362 {
363     const char *ptr;
364     if(path[0] != '/')
365         return FALSE;
366     for(ptr=path+1; *ptr!='\0'; ptr++)
367         if(!g_ascii_isprint(*ptr) || (strchr(invalid_path_chars, *ptr) != NULL) )
368             return FALSE;
369     return TRUE;
370 }
371 
372 /* check for valid format string */
373 static gboolean
is_valid_format(const char * format)374 is_valid_format(const char *format)
375 {
376     const char *ptr;
377     if(format[0] != ',')
378         return FALSE;
379     for(ptr=format+1; *ptr!='\0'; ptr++)
380         if(strchr(valid_format_chars, *ptr) == NULL)
381             return FALSE;
382     return TRUE;
383 }
384 
385 /* Dissect OSC message */
386 static int
dissect_osc_message(tvbuff_t * tvb,proto_item * ti,proto_tree * osc_tree,gint offset,gint len)387 dissect_osc_message(tvbuff_t *tvb, proto_item *ti, proto_tree *osc_tree, gint offset, gint len)
388 {
389     proto_tree  *message_tree;
390     proto_tree  *header_tree;
391     gint         slen;
392     gint         rem;
393     gint         end = offset + len;
394     const gchar *path;
395     gint         path_len;
396     gint         path_offset;
397     const gchar *format;
398     gint         format_offset;
399     gint         format_len;
400     const gchar *ptr;
401 
402     /* peek/read path */
403     path_offset = offset;
404     path = tvb_get_const_stringz(tvb, path_offset, &path_len);
405     if( (rem = path_len%4) ) path_len += 4-rem;
406 
407     if(!is_valid_path(path))
408         return -1;
409 
410     /* peek/read fmt */
411     format_offset = path_offset + path_len;
412     format = tvb_get_const_stringz(tvb, format_offset, &format_len);
413     if( (rem = format_len%4) ) format_len += 4-rem;
414 
415     if(!is_valid_format(format))
416         return -1;
417 
418     /* create message */
419     ti = proto_tree_add_none_format(osc_tree, hf_osc_message_type, tvb, offset, len, "Message: %s %s", path, format);
420     message_tree = proto_item_add_subtree(ti, ett_osc_message);
421 
422     /* append header */
423     ti = proto_tree_add_item(message_tree, hf_osc_message_header_type, tvb, offset, path_len+format_len, ENC_NA);
424     header_tree = proto_item_add_subtree(ti, ett_osc_message_header);
425 
426     /* append path */
427     proto_tree_add_item(header_tree, hf_osc_message_path_type, tvb, path_offset, path_len, ENC_ASCII | ENC_NA);
428 
429     /* append format */
430     proto_tree_add_item(header_tree, hf_osc_message_format_type, tvb, format_offset, format_len, ENC_ASCII | ENC_NA);
431 
432     offset += path_len + format_len;
433 
434     /* ::parse argument:: */
435     ptr = format + 1; /* skip ',' */
436     while( (*ptr != '\0') && (offset < end) )
437     {
438         switch(*ptr)
439         {
440             case OSC_INT32:
441                 proto_tree_add_item(message_tree, hf_osc_message_int32_type, tvb, offset, 4, ENC_BIG_ENDIAN);
442                 offset += 4;
443                 break;
444             case OSC_FLOAT:
445                 proto_tree_add_item(message_tree, hf_osc_message_float_type, tvb, offset, 4, ENC_BIG_ENDIAN);
446                 offset += 4;
447                 break;
448             case OSC_STRING:
449                 slen = tvb_strsize(tvb, offset);
450                 if( (rem = slen%4) ) slen += 4-rem;
451                 proto_tree_add_item(message_tree, hf_osc_message_string_type, tvb, offset, slen, ENC_ASCII | ENC_NA);
452                 offset += slen;
453                 break;
454             case OSC_BLOB:
455             {
456                 proto_item *bi;
457                 proto_tree *blob_tree;
458 
459                 gint32 blen = tvb_get_ntohl(tvb, offset);
460                 slen = blen;
461                 if( (rem = slen%4) ) slen += 4-rem;
462 
463                 bi = proto_tree_add_none_format(message_tree, hf_osc_message_blob_type, tvb, offset, 4+slen, "Blob: %i bytes", blen);
464                 blob_tree = proto_item_add_subtree(bi, ett_osc_blob);
465 
466                 proto_tree_add_int(blob_tree, hf_osc_message_blob_size_type, tvb, offset, 4, blen);
467                 offset += 4;
468 
469                 /* check for zero length blob */
470                 if(blen == 0)
471                     break;
472 
473                 proto_tree_add_item(blob_tree, hf_osc_message_blob_data_type, tvb, offset, slen, ENC_NA);
474                 offset += slen;
475                 break;
476             }
477 
478             case OSC_TRUE:
479                 proto_tree_add_item(message_tree, hf_osc_message_true_type, tvb, offset, 0, ENC_NA);
480                 break;
481             case OSC_FALSE:
482                 proto_tree_add_item(message_tree, hf_osc_message_false_type, tvb, offset, 0, ENC_NA);
483                 break;
484             case OSC_NIL:
485                 proto_tree_add_item(message_tree, hf_osc_message_nil_type, tvb, offset, 0, ENC_NA);
486                 break;
487             case OSC_BANG:
488                 proto_tree_add_item(message_tree, hf_osc_message_bang_type, tvb, offset, 0, ENC_NA);
489                 break;
490 
491             case OSC_INT64:
492                 proto_tree_add_item(message_tree, hf_osc_message_int64_type, tvb, offset, 8, ENC_BIG_ENDIAN);
493                 offset += 8;
494                 break;
495             case OSC_DOUBLE:
496                 proto_tree_add_item(message_tree, hf_osc_message_double_type, tvb, offset, 8, ENC_BIG_ENDIAN);
497                 offset += 8;
498                 break;
499             case OSC_TIMETAG:
500             {
501                 guint32  sec  = tvb_get_ntohl(tvb, offset);
502                 guint32  frac = tvb_get_ntohl(tvb, offset+4);
503                 nstime_t ns;
504                 if( (sec == 0) && (frac == 1) )
505                     proto_tree_add_time_format_value(message_tree, hf_osc_message_timetag_type, tvb, offset, 8, &ns, immediate_fmt, immediate_str);
506                 else
507                     proto_tree_add_item(message_tree, hf_osc_message_timetag_type, tvb, offset, 8, ENC_TIME_NTP | ENC_BIG_ENDIAN);
508                 offset += 8;
509             }
510                 break;
511 
512             case OSC_SYMBOL:
513                 slen = tvb_strsize(tvb, offset);
514                 if( (rem = slen%4) ) slen += 4-rem;
515                 proto_tree_add_item(message_tree, hf_osc_message_symbol_type, tvb, offset, slen, ENC_ASCII | ENC_NA);
516                 offset += slen;
517                 break;
518             case OSC_CHAR:
519                 offset += 3;
520                 proto_tree_add_item(message_tree, hf_osc_message_char_type, tvb, offset, 1, ENC_ASCII | ENC_NA);
521                 offset += 1;
522                 break;
523             case OSC_RGBA:
524             {
525                 proto_item *ri;
526                 proto_tree *rgba_tree;
527 
528                 ri = proto_tree_add_item(message_tree, hf_osc_message_rgba_type, tvb, offset, 4, ENC_BIG_ENDIAN);
529                 rgba_tree = proto_item_add_subtree(ri, ett_osc_rgba);
530 
531                 proto_tree_add_item(rgba_tree, hf_osc_message_rgba_red_type, tvb, offset, 1, ENC_BIG_ENDIAN);
532                 offset += 1;
533                 proto_tree_add_item(rgba_tree, hf_osc_message_rgba_green_type, tvb, offset, 1, ENC_BIG_ENDIAN);
534                 offset += 1;
535                 proto_tree_add_item(rgba_tree, hf_osc_message_rgba_blue_type, tvb, offset, 1, ENC_BIG_ENDIAN);
536                 offset += 1;
537                 proto_tree_add_item(rgba_tree, hf_osc_message_rgba_alpha_type, tvb, offset, 1, ENC_BIG_ENDIAN);
538                 offset += 1;
539                 break;
540             }
541             case OSC_MIDI:
542             {
543                 const gchar *status_str;
544                 proto_item  *mi = NULL;
545                 proto_tree  *midi_tree;
546                 guint8       port;
547                 guint8       command;
548                 guint8       data1;
549                 guint8       data2;
550                 guint8       status;
551                 guint8       channel;
552                 gboolean     system_msg;
553                 guint8       status_shifted;
554 
555                 port = tvb_get_guint8(tvb, offset);
556                 command  = tvb_get_guint8(tvb, offset+1);
557                 data1   = tvb_get_guint8(tvb, offset+2);
558                 data2   = tvb_get_guint8(tvb, offset+3);
559 
560                 status  = command & 0xF0;
561                 channel = command & 0x0F;
562 
563                 system_msg = status == 0xF0; /* is system message */
564                 status_shifted = status >> 4;
565 
566                 if(system_msg)
567                     status_str = val_to_str_ext_const(command, &MIDI_system_ext, "Unknown");
568                 else
569                     status_str = val_to_str_ext_const(status_shifted, &MIDI_status_ext, "Unknown");
570 
571                 if(system_msg)
572                 {
573                     mi = proto_tree_add_none_format(message_tree, hf_osc_message_midi_type, tvb, offset, 4,
574                             "MIDI: Port %i, %s, %i, %i",
575                             port, status_str, data1, data2);
576                 }
577                 else
578                 {
579                     switch(status_shifted)
580                     {
581                         case MIDI_STATUS_NOTE_ON:
582                         case MIDI_STATUS_NOTE_OFF:
583                         case MIDI_STATUS_NOTE_PRESSURE:
584                         {
585                             const gchar *note_str;
586                             note_str = val_to_str_ext_const(data1, &MIDI_note_ext, "Unknown");
587 
588                             mi = proto_tree_add_none_format(message_tree, hf_osc_message_midi_type, tvb, offset, 4,
589                                     "MIDI: Port %i, Channel %i, %s, %s, %i",
590                                     port, channel, status_str, note_str, data2);
591                             break;
592                         }
593                         case MIDI_STATUS_CONTROLLER:
594                         {
595                             const gchar *control_str;
596                             control_str = val_to_str_ext_const(data1, &MIDI_control_ext, "Unknown");
597 
598                             mi = proto_tree_add_none_format(message_tree, hf_osc_message_midi_type, tvb, offset, 4,
599                                     "MIDI: Port %i, Channel %i, %s, %s, %i",
600                                     port, channel, status_str, control_str, data2);
601                             break;
602                         }
603                         case MIDI_STATUS_PITCH_BENDER:
604                         {
605                             const gint bender = (((gint)data2 << 7) | (gint)data1) - 0x2000;
606 
607                             mi = proto_tree_add_none_format(message_tree, hf_osc_message_midi_type, tvb, offset, 4,
608                                     "MIDI: Port %i, Channel %i, %s, %i",
609                                     port, channel, status_str, bender);
610                             break;
611                         }
612                         default:
613                         {
614                             mi = proto_tree_add_none_format(message_tree, hf_osc_message_midi_type, tvb, offset, 4,
615                                     "MIDI: Port %i, Channel %i, %s, %i, %i",
616                                     port, channel, status_str, data1, data2);
617                             break;
618                         }
619                     }
620                 }
621                 midi_tree = proto_item_add_subtree(mi, ett_osc_midi);
622 
623                 proto_tree_add_item(midi_tree, hf_osc_message_midi_port_type, tvb, offset, 1, ENC_BIG_ENDIAN);
624                 offset += 1;
625 
626                 if(system_msg)
627                 {
628                     proto_tree_add_item(midi_tree, hf_osc_message_midi_system_type, tvb, offset, 1, ENC_BIG_ENDIAN);
629                     offset += 1;
630 
631                     proto_tree_add_item(midi_tree, hf_osc_message_midi_data1_type, tvb, offset, 1, ENC_BIG_ENDIAN);
632                     offset += 1;
633 
634                     proto_tree_add_item(midi_tree, hf_osc_message_midi_data2_type, tvb, offset, 1, ENC_BIG_ENDIAN);
635                     offset += 1;
636                 }
637                 else
638                 {
639                     proto_tree_add_item(midi_tree, hf_osc_message_midi_status_type, tvb, offset, 1, ENC_BIG_ENDIAN);
640                     proto_tree_add_item(midi_tree, hf_osc_message_midi_channel_type, tvb, offset, 1, ENC_BIG_ENDIAN);
641                     offset += 1;
642 
643                     switch(status_shifted)
644                     {
645                         case MIDI_STATUS_NOTE_ON:
646                         case MIDI_STATUS_NOTE_OFF:
647                         {
648                             proto_tree_add_item(midi_tree, hf_osc_message_midi_note_type, tvb, offset, 1, ENC_BIG_ENDIAN);
649                             offset += 1;
650 
651                             proto_tree_add_item(midi_tree, hf_osc_message_midi_velocity_type, tvb, offset, 1, ENC_BIG_ENDIAN);
652                             offset += 1;
653 
654                             break;
655                         }
656                         case MIDI_STATUS_NOTE_PRESSURE:
657                         {
658                             proto_tree_add_item(midi_tree, hf_osc_message_midi_note_type, tvb, offset, 1, ENC_BIG_ENDIAN);
659                             offset += 1;
660 
661                             proto_tree_add_item(midi_tree, hf_osc_message_midi_pressure_type, tvb, offset, 1, ENC_BIG_ENDIAN);
662                             offset += 1;
663 
664                             break;
665                         }
666                         case MIDI_STATUS_CONTROLLER:
667                         {
668                             proto_tree_add_item(midi_tree, hf_osc_message_midi_controller_type, tvb, offset, 1, ENC_BIG_ENDIAN);
669                             offset += 1;
670 
671                             proto_tree_add_item(midi_tree, hf_osc_message_midi_data2_type, tvb, offset, 1, ENC_BIG_ENDIAN);
672                             offset += 1;
673 
674                             break;
675                         }
676                         case MIDI_STATUS_CHANNEL_PRESSURE:
677                         {
678                             proto_tree_add_item(midi_tree, hf_osc_message_midi_pressure_type, tvb, offset, 1, ENC_BIG_ENDIAN);
679                             offset += 1;
680 
681                             proto_tree_add_item(midi_tree, hf_osc_message_midi_data2_type, tvb, offset, 1, ENC_BIG_ENDIAN);
682                             offset += 1;
683 
684                             break;
685                         }
686                         case MIDI_STATUS_PITCH_BENDER:
687                         {
688                             const gint bender = (((gint)data2 << 7) | (gint)data1) - 0x2000;
689 
690                             proto_tree_add_int(midi_tree, hf_osc_message_midi_bender_type, tvb, offset, 2, bender);
691                             offset += 2;
692 
693                             break;
694                         }
695                         default:
696                         {
697                             proto_tree_add_item(midi_tree, hf_osc_message_midi_data1_type, tvb, offset, 1, ENC_BIG_ENDIAN);
698                             offset += 1;
699 
700                             proto_tree_add_item(midi_tree, hf_osc_message_midi_data2_type, tvb, offset, 1, ENC_BIG_ENDIAN);
701                             offset += 1;
702 
703                             break;
704                         }
705                     }
706                 }
707 
708                 break;
709             }
710 
711             default:
712                 /* if we get here, there must be a bug in the dissector  */
713                 DISSECTOR_ASSERT_NOT_REACHED();
714                 break;
715         }
716         ptr++;
717     }
718 
719     if(offset != end)
720         return -1;
721     else
722         return 0;
723 }
724 
725 /* Dissect OSC bundle */
726 static int
dissect_osc_bundle(tvbuff_t * tvb,proto_item * ti,proto_tree * osc_tree,gint offset,gint len)727 dissect_osc_bundle(tvbuff_t *tvb, proto_item *ti, proto_tree *osc_tree, gint offset, gint len)
728 {
729     proto_tree  *bundle_tree;
730     gint         end = offset + len;
731     guint32      sec;
732     guint32      frac;
733     nstime_t     ns;
734 
735     /* check for valid #bundle */
736     if(tvb_strneql(tvb, offset, bundle_str, 8) != 0)
737         return -1;
738 
739     /* create bundle */
740     ti = proto_tree_add_item(osc_tree, hf_osc_bundle_type, tvb, offset, len, ENC_NA);
741 
742     bundle_tree = proto_item_add_subtree(ti, ett_osc_bundle);
743 
744     offset += 8; /* skip bundle_str */
745 
746     /* read timetag */
747     sec  = tvb_get_ntohl(tvb, offset);
748     frac = tvb_get_ntohl(tvb, offset+4);
749     if( (sec == 0) && (frac == 1) )
750         proto_tree_add_time_format_value(bundle_tree, hf_osc_bundle_timetag_type, tvb, offset, 8, &ns, immediate_fmt, immediate_str);
751     else
752         proto_tree_add_item(bundle_tree, hf_osc_bundle_timetag_type, tvb, offset, 8, ENC_TIME_NTP | ENC_BIG_ENDIAN);
753     offset += 8;
754 
755     /* ::read size, read block:: */
756     while(offset < end)
757     {
758         /* peek bundle element size */
759         gint32 size;
760 
761         /* read bundle element size */
762         proto_tree_add_item_ret_int(bundle_tree, hf_osc_bundle_element_size_type, tvb, offset, 4, ENC_BIG_ENDIAN, &size);
763         offset += 4;
764 
765         /* check for zero size bundle element */
766         if(size == 0)
767             continue;
768 
769         /* peek first bundle element char */
770         switch(tvb_get_guint8(tvb, offset))
771         {
772             case '#': /* this is a bundle */
773                 if(dissect_osc_bundle(tvb, ti, bundle_tree, offset, size))
774                     return -1;
775                 else
776                     break;
777             case '/': /* this is a message */
778                 if(dissect_osc_message(tvb, ti, bundle_tree, offset, size))
779                     return -1;
780                 else
781                     break;
782             default:
783                 return -1; /* neither message nor bundle */
784         }
785 
786         /* check for integer overflow */
787         if(size > G_MAXINT - offset)
788             return -1;
789         else
790             offset += size;
791     }
792 
793     if(offset != end)
794         return -1;
795     else
796         return 0;
797 }
798 
799 /* Dissect OSC PDU */
800 static void
dissect_osc_pdu_common(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_,gint offset,gint len)801 dissect_osc_pdu_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_, gint offset, gint len)
802 {
803     col_set_str(pinfo->cinfo, COL_PROTOCOL, "OSC");
804     col_clear(pinfo->cinfo, COL_INFO);
805 
806     if(tree) /* we are being asked for details */
807     {
808         proto_item *ti;
809         proto_tree *osc_tree;
810 
811         /* create OSC packet */
812         ti = proto_tree_add_item(tree, proto_osc, tvb, 0, -1, ENC_NA);
813         osc_tree = proto_item_add_subtree(ti, ett_osc_packet);
814 
815         /* peek first bundle element char */
816         switch(tvb_get_guint8(tvb, offset))
817         {
818             case '#': /* this is a bundle */
819                 if(dissect_osc_bundle(tvb, ti, osc_tree, offset, len))
820                     return;
821                 else
822                     break;
823             case '/': /* this is a message */
824                 if(dissect_osc_message(tvb, ti, osc_tree, offset, len))
825                     return;
826                 else
827                     break;
828             default: /* neither message nor bundle */
829                 return;
830         }
831     }
832 }
833 
834 /* OSC TCP (OSC-1.0) */
835 
836 static guint
get_osc_pdu_len(packet_info * pinfo _U_,tvbuff_t * tvb,int offset,void * data _U_)837 get_osc_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
838 {
839     return tvb_get_ntohl(tvb, offset) + 4;
840 }
841 
842 static int
dissect_osc_tcp_pdu(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)843 dissect_osc_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
844 {
845     gint pdu_len;
846 
847     pdu_len = tvb_get_ntohl(tvb, 0);
848     dissect_osc_pdu_common(tvb, pinfo, tree, data, 4, pdu_len);
849     return pdu_len;
850 }
851 
852 static int
dissect_osc_tcp_1_0(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)853 dissect_osc_tcp_1_0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
854 {
855     tcp_dissect_pdus(tvb, pinfo, tree, TRUE, 4, get_osc_pdu_len,
856                      dissect_osc_tcp_pdu, data);
857     return tvb_reported_length(tvb);
858 }
859 
860 /* OSC TCP (OSC-1.1) */
861 #define SLIP_END                0xC0 /* 300 (octal), 192 (decimal), indicates end of packet */
862 #define SLIP_ESC                0xDB /* 333 (octal), 219 (decimal), indicates byte stuffing */
863 #define SLIP_END_REPLACE        0xDC /* 334 (octal), 220 (decimal), ESC ESC_END means END data byte */
864 #define SLIP_ESC_REPLACE        0xDD /* 335 (octal), 221 (decimal), ESC ESC_ESC means ESC data byte */
865 
866 static inline gint
slip_decoded_len(const guint8 * src,guint available)867 slip_decoded_len(const guint8 *src, guint available)
868 {
869     const guint8 *ptr;
870     const guint8 *end = src + available;
871     gint decoded_len = 0;
872     gboolean escaped = FALSE;
873 
874     for(ptr = src; ptr < end; ptr++)
875     {
876         if(escaped)
877         {
878             switch(*ptr)
879             {
880                 case SLIP_END_REPLACE:
881                     /* fall-through */
882                 case SLIP_ESC_REPLACE:
883                     escaped = FALSE;
884                     decoded_len++;
885                     break;
886                 default:
887                     return -1; /* decode failed */
888             }
889         }
890         else /* !escaped */
891         {
892             switch(*ptr)
893             {
894                 case SLIP_END:
895                     return decoded_len;
896                 case SLIP_ESC:
897                     escaped = TRUE;
898                     break;
899                 default:
900                     decoded_len++;
901                     break;
902             }
903         }
904     }
905 
906     return -1; /* decode failed */
907 }
908 
909 static inline void
slip_decode(guint8 * dst,const guint8 * src,guint available)910 slip_decode(guint8 *dst, const guint8 *src, guint available)
911 {
912     const guint8 *ptr;
913     guint8 *tar = dst;
914     const guint8 *end = src + available;
915 
916     for(ptr = src; ptr < end; ptr++)
917     {
918         switch(*ptr)
919         {
920             case SLIP_END:
921                 return;
922             case SLIP_ESC:
923                 break;
924             case SLIP_END_REPLACE:
925                 *tar++ = SLIP_END;
926                 break;
927             case SLIP_ESC_REPLACE:
928                 *tar++ = SLIP_ESC;
929                 break;
930             default:
931                 *tar++ = *ptr;
932                 break;
933         }
934     }
935 }
936 
937 static int
dissect_osc_tcp_1_1(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)938 dissect_osc_tcp_1_1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
939 {
940     guint offset = 0;
941 
942     while(offset < tvb_reported_length(tvb))
943     {
944         const gint available = tvb_reported_length_remaining(tvb, offset);
945         const guint8 *encoded_buf = tvb_get_ptr(tvb, offset, -1);
946         const guint8 *slip_end_found = (const guint8 *)memchr(encoded_buf, SLIP_END, available);
947         guint encoded_len;
948         gint decoded_len;
949         guint8 *decoded_buf;
950         tvbuff_t *next_tvb;
951 
952         if(!slip_end_found) /* no SLIP'd stream ending in this chunk */
953         {
954             /* we ran out of data: ask for more */
955             pinfo->desegment_offset = offset;
956             pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
957             return (offset + available);
958         }
959 
960         encoded_len = (guint)(slip_end_found + 1 - encoded_buf);
961         if(encoded_len > 1) /* we have a non-empty SLIP'd stream*/
962         {
963             decoded_len = slip_decoded_len(encoded_buf, encoded_len);
964             if(decoded_len != -1) /* is a valid SLIP'd stream */
965             {
966                 decoded_buf = (guint8 *)wmem_alloc(pinfo->pool, decoded_len);
967 
968                 slip_decode(decoded_buf, encoded_buf, encoded_len);
969 
970                 next_tvb = tvb_new_child_real_data(tvb, decoded_buf, decoded_len, decoded_len);
971 
972                 add_new_data_source(pinfo, next_tvb, "SLIP-decoded Data");
973                 dissect_osc_pdu_common(next_tvb, pinfo, tree, data, 0, decoded_len);
974             }
975             else
976             {
977                 return 0; /* failed to decode SLIP'd stream */
978             }
979         }
980 
981         offset += encoded_len;
982     }
983 
984     /* end of the tvb coincided with the end of a SLIP'd stream */
985     return tvb_captured_length(tvb);
986 }
987 
988 /* OSC TCP (OSC-1.0, OSC-1.1 fork) */
989 
990 static int
dissect_osc_tcp(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)991 dissect_osc_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
992 {
993     /*
994      * int32 size prefix framing (OSC-1.0)
995      * ... {(int32 size)(OSC packet)} ... {(int32 size)(OSC packet)} ...
996      */
997 
998     /*
999      * SLIP framing (OSC-1.1)
1000      * ... {SLIP'd(OSC packet)} ... {SLIP'd(OSC)} ...
1001      */
1002 
1003     const guint8 first_byte = tvb_get_guint8(tvb, 0);
1004     const gboolean slip_encoded = (first_byte == SLIP_END) /* empty SLIP frame*/
1005         || (first_byte == '/') /* SLIP'd OSC message frame */
1006         || (first_byte == '#'); /* SLIP'd OSC bundle frame */
1007 
1008     if(slip_encoded)
1009     {
1010         /* assume SLIP framing (OSC-1.1) */
1011         return dissect_osc_tcp_1_1(tvb, pinfo, tree, data);
1012     }
1013 
1014     /* assume int32 size-prefixed framing (OSC-1.0) */
1015     return dissect_osc_tcp_1_0(tvb, pinfo, tree, data);
1016 }
1017 
1018 /* OSC UDP */
1019 
1020 static int
dissect_osc_udp(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)1021 dissect_osc_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1022 {
1023     gint pdu_len;
1024 
1025     pdu_len = tvb_reported_length(tvb);
1026     dissect_osc_pdu_common(tvb,pinfo, tree, data, 0, pdu_len);
1027     return pdu_len;
1028 }
1029 
1030 /* UDP Heuristic */
1031 static gboolean
dissect_osc_heur_udp(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)1032 dissect_osc_heur_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1033 {
1034     conversation_t *conversation;
1035 
1036     if(tvb_captured_length(tvb) < 8)
1037         return FALSE;
1038 
1039     /* peek first string */
1040     if(tvb_strneql(tvb, 0, bundle_str, 8) != 0) /* no OSC bundle */
1041     {
1042         gint               offset = 0;
1043         gint               slen;
1044         gint               rem;
1045         const gchar       *str;
1046         volatile gboolean  valid  = FALSE;
1047 
1048         /* Check for valid path */
1049         /* Don't propagate any exceptions upwards during heuristics check  */
1050         /* XXX: this check is a bit expensive; Consider: use UDP port pref ? */
1051         TRY {
1052             str = tvb_get_const_stringz(tvb, offset, &slen);
1053             if(is_valid_path(str)) {
1054 
1055                 /* skip path */
1056                 if( (rem = slen%4) ) slen += 4-rem;
1057                 offset += slen;
1058 
1059                 /* peek next string */
1060                 str = tvb_get_const_stringz(tvb, offset, &slen);
1061 
1062                 /* check for valid format */
1063                 if(is_valid_format(str))
1064                     valid = TRUE;
1065             }
1066         }
1067         CATCH_ALL {
1068             valid = FALSE;
1069         }
1070         ENDTRY;
1071 
1072         if(! valid)
1073             return FALSE;
1074     }
1075 
1076     /* if we get here, then it's an Open Sound Control packet (bundle or message) */
1077 
1078     /* specify that dissect_osc is to be called directly from now on for packets for this connection */
1079     conversation = find_or_create_conversation(pinfo);
1080     conversation_set_dissector(conversation, osc_udp_handle);
1081 
1082     /* do the dissection */
1083     dissect_osc_udp(tvb, pinfo, tree, data);
1084 
1085     return TRUE; /* OSC heuristics was matched */
1086 }
1087 
1088 /* Register the protocol with Wireshark */
1089 void
proto_register_osc(void)1090 proto_register_osc(void)
1091 {
1092     static hf_register_info hf[] = {
1093         { &hf_osc_bundle_type, { "Bundle", "osc.bundle",
1094                 FT_NONE, BASE_NONE,
1095                 NULL, 0x0,
1096                 "Bundle structure", HFILL } },
1097         { &hf_osc_bundle_timetag_type, { "Timetag", "osc.bundle.timetag",
1098                 FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC,
1099                 NULL, 0x0,
1100                 "Scheduled bundle execution time", HFILL } },
1101 
1102         { &hf_osc_bundle_element_size_type, { "Size", "osc.bundle.element.size",
1103                 FT_INT32, BASE_DEC|BASE_UNIT_STRING,
1104                 &units_byte_bytes, 0x0,
1105                 "Bundle element size", HFILL } },
1106 
1107         { &hf_osc_message_type, { "Message", "osc.message",
1108                 FT_NONE, BASE_NONE,
1109                 NULL, 0x0,
1110                 "Message structure", HFILL } },
1111         { &hf_osc_message_header_type, { "Header", "osc.message.header",
1112                 FT_NONE, BASE_NONE,
1113                 NULL, 0x0,
1114                 "Message header", HFILL } },
1115         { &hf_osc_message_path_type, { "Path", "osc.message.header.path",
1116                 FT_STRING, BASE_NONE,
1117                 NULL, 0x0,
1118                 "Message path", HFILL } },
1119         { &hf_osc_message_format_type, { "Format", "osc.message.header.format",
1120                 FT_STRING, BASE_NONE,
1121                 NULL, 0x0,
1122                 "Message format", HFILL } },
1123 
1124         { &hf_osc_message_int32_type, { "Int32", "osc.message.int32",
1125                 FT_INT32, BASE_DEC,
1126                 NULL, 0x0,
1127                 "32bit integer value", HFILL } },
1128         { &hf_osc_message_float_type, { "Float", "osc.message.float",
1129                 FT_FLOAT, BASE_NONE,
1130                 NULL, 0x0,
1131                 "Floating point value", HFILL } },
1132         { &hf_osc_message_string_type, { "String", "osc.message.string",
1133                 FT_STRING, BASE_NONE,
1134                 NULL, 0x0,
1135                 "String value", HFILL } },
1136 
1137         { &hf_osc_message_blob_type, { "Blob", "osc.message.blob",
1138                 FT_NONE, BASE_NONE,
1139                 NULL, 0x0,
1140                 "Binary blob value", HFILL } },
1141         { &hf_osc_message_blob_size_type, { "Size", "osc.message.blob.size",
1142                 FT_INT32, BASE_DEC|BASE_UNIT_STRING,
1143                 &units_byte_bytes, 0x0,
1144                 "Binary blob size", HFILL } },
1145         { &hf_osc_message_blob_data_type, { "Data", "osc.message.blob.data",
1146                 FT_BYTES, BASE_NONE,
1147                 NULL, 0x0,
1148                 "Binary blob data", HFILL } },
1149 
1150         { &hf_osc_message_true_type, { "True", "osc.message.true",
1151                 FT_NONE, BASE_NONE,
1152                 NULL, 0x0,
1153                 "Boolean true value", HFILL } },
1154         { &hf_osc_message_false_type, { "False", "osc.message.false",
1155                 FT_NONE, BASE_NONE,
1156                 NULL, 0x0,
1157                 "Boolean false value", HFILL } },
1158         { &hf_osc_message_nil_type, { "Nil", "osc.message.nil",
1159                 FT_NONE, BASE_NONE,
1160                 NULL, 0x0,
1161                 "Nil value", HFILL } },
1162         { &hf_osc_message_bang_type, { "Bang", "osc.message.bang",
1163                 FT_NONE, BASE_NONE,
1164                 NULL, 0x0,
1165                 "Infinity, Impulse or Bang value", HFILL } },
1166 
1167         { &hf_osc_message_int64_type, { "Int64", "osc.message.int64",
1168                 FT_INT64, BASE_DEC,
1169                 NULL, 0x0,
1170                 "64bit integer value", HFILL } },
1171         { &hf_osc_message_double_type, { "Double", "osc.message.double",
1172                 FT_DOUBLE, BASE_NONE,
1173                 NULL, 0x0,
1174                 "Double value", HFILL } },
1175         { &hf_osc_message_timetag_type, { "Timetag", "osc.message.timetag",
1176                 FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC,
1177                 NULL, 0x0,
1178                 "NTP time value", HFILL } },
1179 
1180         { &hf_osc_message_symbol_type, { "Symbol", "osc.message.symbol",
1181                 FT_STRING, BASE_NONE,
1182                 NULL, 0x0,
1183                 "Symbol value", HFILL } },
1184         { &hf_osc_message_char_type, { "Char", "osc.message.char",
1185                 FT_STRING, BASE_NONE,
1186                 NULL, 0x0,
1187                 "Character value", HFILL } },
1188 
1189         { &hf_osc_message_rgba_type, { "RGBA", "osc.message.rgba",
1190                 FT_UINT32, BASE_HEX,
1191                 NULL, 0x0,
1192                 "RGBA color value", HFILL } },
1193         { &hf_osc_message_rgba_red_type, { "Red", "osc.message.rgba.red",
1194                 FT_UINT8, BASE_DEC,
1195                 NULL, 0x0,
1196                 "Red color component", HFILL } },
1197         { &hf_osc_message_rgba_green_type, { "Green", "osc.message.rgba.green",
1198                 FT_UINT8, BASE_DEC,
1199                 NULL, 0x0,
1200                 "Green color component", HFILL } },
1201         { &hf_osc_message_rgba_blue_type, { "Blue", "osc.message.rgba.blue",
1202                 FT_UINT8, BASE_DEC,
1203                 NULL, 0x0,
1204                 "Blue color component", HFILL } },
1205         { &hf_osc_message_rgba_alpha_type, { "Alpha", "osc.message.rgba.alpha",
1206                 FT_UINT8, BASE_DEC,
1207                 NULL, 0x0,
1208                 "Alpha transparency component", HFILL } },
1209 
1210         { &hf_osc_message_midi_type, { "MIDI", "osc.message.midi",
1211                 FT_NONE, BASE_NONE,
1212                 NULL, 0x0,
1213                 "MIDI value", HFILL } },
1214         { &hf_osc_message_midi_port_type, { "Port", "osc.message.midi.port",
1215                 FT_UINT8, BASE_DEC,
1216                 NULL, 0x0,
1217                 "MIDI port", HFILL } },
1218         { &hf_osc_message_midi_system_type, { "System", "osc.message.midi.system",
1219                 FT_UINT8, BASE_HEX | BASE_EXT_STRING,
1220                 &MIDI_system_ext, 0x0,
1221                 "MIDI system", HFILL } },
1222         { &hf_osc_message_midi_status_type, { "Status", "osc.message.midi.status",
1223                 FT_UINT8, BASE_HEX | BASE_EXT_STRING,
1224                 &MIDI_status_ext, 0xF0,
1225                 "MIDI status", HFILL } },
1226         { &hf_osc_message_midi_channel_type, { "Channel", "osc.message.midi.channel",
1227                 FT_UINT8, BASE_DEC,
1228                 NULL, 0x0F,
1229                 "MIDI channel", HFILL } },
1230         { &hf_osc_message_midi_data1_type, { "Data1", "osc.message.midi.data1",
1231                 FT_UINT8, BASE_DEC,
1232                 NULL, 0x7F,
1233                 "MIDI data 1", HFILL } },
1234         { &hf_osc_message_midi_data2_type, { "Data2", "osc.message.midi.data2",
1235                 FT_UINT8, BASE_DEC,
1236                 NULL, 0x7F,
1237                 "MIDI data 2", HFILL } },
1238         { &hf_osc_message_midi_velocity_type, { "Velocity", "osc.message.midi.velocity",
1239                 FT_UINT8, BASE_DEC,
1240                 NULL, 0x7F,
1241                 "MIDI note velocity", HFILL } },
1242         { &hf_osc_message_midi_pressure_type, { "Pressure", "osc.message.midi.pressure",
1243                 FT_UINT8, BASE_DEC,
1244                 NULL, 0x7F,
1245                 "MIDI note/channel pressure", HFILL } },
1246         { &hf_osc_message_midi_note_type, { "Note", "osc.message.midi.note",
1247                 FT_UINT8, BASE_DEC | BASE_EXT_STRING,
1248                 &MIDI_note_ext, 0x7F,
1249                 "MIDI note", HFILL } },
1250         { &hf_osc_message_midi_controller_type, { "Controller", "osc.message.midi.controller",
1251                 FT_UINT8, BASE_DEC | BASE_EXT_STRING,
1252                 &MIDI_control_ext, 0x7F,
1253                 "MIDI controller", HFILL } },
1254         { &hf_osc_message_midi_bender_type, { "Bender", "osc.message.midi.bender",
1255                 FT_INT16, BASE_DEC,
1256                 NULL, 0x7F7F,
1257                 "MIDI bender", HFILL } }
1258     };
1259 
1260     /* Setup protocol subtree array */
1261     static gint *ett[] = {
1262         &ett_osc_packet,
1263         &ett_osc_bundle,
1264         &ett_osc_message,
1265         &ett_osc_message_header,
1266         &ett_osc_blob,
1267         &ett_osc_rgba,
1268         &ett_osc_midi
1269     };
1270 
1271     proto_osc = proto_register_protocol("Open Sound Control Encoding", "OSC", "osc");
1272 
1273     proto_register_field_array(proto_osc, hf, array_length(hf));
1274     proto_register_subtree_array(ett, array_length(ett));
1275 }
1276 
1277 void
proto_reg_handoff_osc(void)1278 proto_reg_handoff_osc(void)
1279 {
1280     dissector_handle_t osc_tcp_handle;
1281 
1282     osc_tcp_handle = create_dissector_handle(dissect_osc_tcp, proto_osc);
1283 
1284     /* XXX: Add port pref and  "decode as" for UDP ? */
1285     /*      (The UDP heuristic is a bit expensive    */
1286     osc_udp_handle = create_dissector_handle(dissect_osc_udp, proto_osc);
1287     /* register as heuristic dissector for UDP connections */
1288     heur_dissector_add("udp", dissect_osc_heur_udp, "Open Sound Control over UDP", "osc_udp", proto_osc, HEURISTIC_DISABLE);
1289 
1290     dissector_add_for_decode_as_with_preference("tcp.port", osc_tcp_handle);
1291 }
1292 
1293 /*
1294  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1295  *
1296  * Local variables:
1297  * c-basic-offset: 4
1298  * tab-width: 8
1299  * indent-tabs-mode: nil
1300  * End:
1301  *
1302  * vi: set shiftwidth=4 tabstop=8 expandtab:
1303  * :indentSize=4:tabSize=8:noTabs=true:
1304  */
1305