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