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