forked from osmocom/wireshark
[OSC] implement SLIP framing via TCP for OSC-1.1.
OSC-1.1 requires OSC packets to be double SLIP encoded on a TCP stream for framing, whereas OSC-1.0 frames packets via a int32 size prefix. As only either OSC-1.0 or OSC-1.1 will ever be used on the same connection, the tcp part of the OSC dissector should handle both. 'dissect_osc_tcp' now merely acts as a fork into one of both versions. Changes: * Reassembly for OSC-1.0 TCP is left untouched. * Reassembly for OSC-1.1 TCP is implemented in second reassembly mode. * OSC is no protocol per se, it's merely an encoding, renamed accordingly. * Fix logical vs binary OR typo in MIDI pitch bend calculation. Capture file: * Mixed framing (OSC-1.0, OSC-1.1) OSC TCP pcap: Bug 11976 Change-Id: I5d26db023ef3ee659ae5a668b1665abef40b54c3 Reviewed-on: https://code.wireshark.org/review/13112 Petri-Dish: Anders Broman <a.broman58@gmail.com> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
parent
fe7cbcad86
commit
f83e20202f
|
@ -22,14 +22,28 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* Specification 1.1 (http://opensoundcontrol.org/spec-1_1)
|
||||
* - TCP dissection with: SLIP framing
|
||||
* Specification 1.0 (http://opensoundcontrol.org/spec-1_0)
|
||||
* - based on default argument types: i,f,s,b
|
||||
* - including widely used extension types: T,F,N,I,h,d,t,S,c,r,m
|
||||
* - TCP dissection with: int32 size prefix framing
|
||||
* References
|
||||
* - Schmeder, A., Freed, A., and Wessel, D.,
|
||||
* "Best practices for Open Sound Control",
|
||||
* Linux Audio Conference, Utrecht, The Netherlands, 2010.
|
||||
* - Freed, A., Schmeder, A.,
|
||||
* "Features and Future of Open Sound Control version 1.1 for NIME",
|
||||
* NIME Conference 2009.
|
||||
* - Wright, M., Freed, A.,
|
||||
* "Open Sound Control: A New Protocol for Communicating with Sound Synthesizers",
|
||||
* International Computer Music Conference, Thessaloniki, Greece, 1997.
|
||||
* - https://tools.ietf.org/html/rfc1055 (SLIP)
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <epan/packet.h>
|
||||
#include <epan/prefs.h>
|
||||
#include <epan/exceptions.h>
|
||||
|
@ -604,7 +618,7 @@ dissect_osc_message(tvbuff_t *tvb, proto_item *ti, proto_tree *osc_tree, gint of
|
|||
}
|
||||
case MIDI_STATUS_PITCH_BENDER:
|
||||
{
|
||||
const gint bender = (((gint)data2 << 7) || (gint)data1) - 0x2000;
|
||||
const gint bender = (((gint)data2 << 7) | (gint)data1) - 0x2000;
|
||||
|
||||
mi = proto_tree_add_none_format(message_tree, hf_osc_message_midi_type, tvb, offset, 4,
|
||||
"MIDI: Port %i, Channel %i, %s, %i",
|
||||
|
@ -687,7 +701,7 @@ dissect_osc_message(tvbuff_t *tvb, proto_item *ti, proto_tree *osc_tree, gint of
|
|||
}
|
||||
case MIDI_STATUS_PITCH_BENDER:
|
||||
{
|
||||
const gint bender = (((gint)data2 << 7) || (gint)data1) - 0x2000;
|
||||
const gint bender = (((gint)data2 << 7) | (gint)data1) - 0x2000;
|
||||
|
||||
proto_tree_add_int(midi_tree, hf_osc_message_midi_bender_type, tvb, offset, 2, bender);
|
||||
offset += 2;
|
||||
|
@ -833,7 +847,7 @@ dissect_osc_pdu_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void
|
|||
}
|
||||
}
|
||||
|
||||
/* OSC TCP */
|
||||
/* OSC TCP (OSC-1.0) */
|
||||
|
||||
static guint
|
||||
get_osc_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
|
||||
|
@ -852,13 +866,178 @@ dissect_osc_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *d
|
|||
}
|
||||
|
||||
static int
|
||||
dissect_osc_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
||||
dissect_osc_tcp_1_0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
||||
{
|
||||
tcp_dissect_pdus(tvb, pinfo, tree, TRUE, 4, get_osc_pdu_len,
|
||||
dissect_osc_tcp_pdu, data);
|
||||
return tvb_reported_length(tvb);
|
||||
}
|
||||
|
||||
/* OSC TCP (OSC-1.1) */
|
||||
#define SLIP_END 0xC0 /* 300 (octal), 192 (decimal), indicates end of packet */
|
||||
#define SLIP_ESC 0xDB /* 333 (octal), 219 (decimal), indicates byte stuffing */
|
||||
#define SLIP_END_REPLACE 0xDC /* 334 (octal), 220 (decimal), ESC ESC_END means END data byte */
|
||||
#define SLIP_ESC_REPLACE 0xDD /* 335 (octal), 221 (decimal), ESC ESC_ESC means ESC data byte */
|
||||
|
||||
static inline gint
|
||||
slip_decoded_len(const guint8 *src, guint available)
|
||||
{
|
||||
const guint8 *ptr;
|
||||
const guint8 *end = src + available;
|
||||
gint decoded_len = 0;
|
||||
gboolean escaped = FALSE;
|
||||
|
||||
for(ptr = src; ptr < end; ptr++)
|
||||
{
|
||||
if(escaped)
|
||||
{
|
||||
switch(*ptr)
|
||||
{
|
||||
case SLIP_END_REPLACE:
|
||||
/* fall-through */
|
||||
case SLIP_ESC_REPLACE:
|
||||
escaped = FALSE;
|
||||
decoded_len++;
|
||||
break;
|
||||
default:
|
||||
return -1; /* decode failed */
|
||||
}
|
||||
}
|
||||
else /* !escaped */
|
||||
{
|
||||
switch(*ptr)
|
||||
{
|
||||
case SLIP_END:
|
||||
return decoded_len;
|
||||
case SLIP_ESC:
|
||||
escaped = TRUE;
|
||||
break;
|
||||
default:
|
||||
decoded_len++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1; /* decode failed */
|
||||
}
|
||||
|
||||
static inline void
|
||||
slip_decode(guint8 *dst, const guint8 *src, guint available)
|
||||
{
|
||||
const guint8 *ptr;
|
||||
guint8 *tar = dst;
|
||||
const guint8 *end = src + available;
|
||||
|
||||
for(ptr = src; ptr < end; ptr++)
|
||||
{
|
||||
switch(*ptr)
|
||||
{
|
||||
case SLIP_END:
|
||||
return;
|
||||
case SLIP_ESC:
|
||||
break;
|
||||
case SLIP_END_REPLACE:
|
||||
*tar++ = SLIP_END;
|
||||
break;
|
||||
case SLIP_ESC_REPLACE:
|
||||
*tar++ = SLIP_ESC;
|
||||
break;
|
||||
default:
|
||||
*tar++ = *ptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
dissect_osc_tcp_1_1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
||||
{
|
||||
guint offset = 0;
|
||||
|
||||
while(offset < tvb_reported_length(tvb))
|
||||
{
|
||||
const gint available = tvb_reported_length_remaining(tvb, offset);
|
||||
const guint8 *encoded_buf = tvb_get_ptr(tvb, offset, -1);
|
||||
const guint8 *slip_end_found = (const guint8 *)memchr(encoded_buf, SLIP_END, available);
|
||||
guint encoded_len;
|
||||
gint decoded_len;
|
||||
guint8 *decoded_buf;
|
||||
tvbuff_t *next_tvb;
|
||||
|
||||
if(!slip_end_found) /* no SLIP'd stream ending in this chunk */
|
||||
{
|
||||
/* we ran out of data: ask for more */
|
||||
pinfo->desegment_offset = offset;
|
||||
pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
|
||||
return (offset + available);
|
||||
}
|
||||
|
||||
encoded_len = (guint)(slip_end_found + 1 - encoded_buf);
|
||||
if(encoded_len > 1) /* we have a non-empty SLIP'd stream*/
|
||||
{
|
||||
decoded_len = slip_decoded_len(encoded_buf, encoded_len);
|
||||
if(decoded_len != -1) /* is a valid SLIP'd stream */
|
||||
{
|
||||
decoded_buf = (guint8 *)g_malloc(decoded_len);
|
||||
if(decoded_buf)
|
||||
{
|
||||
slip_decode(decoded_buf, encoded_buf, encoded_len);
|
||||
|
||||
next_tvb = tvb_new_child_real_data(tvb, decoded_buf, decoded_len, decoded_len);
|
||||
tvb_set_free_cb(next_tvb, g_free);
|
||||
|
||||
add_new_data_source(pinfo, next_tvb, "SLIP-decoded Data");
|
||||
dissect_osc_pdu_common(next_tvb, pinfo, tree, data, 0, decoded_len);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0; /* failed to allocate new buffer */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0; /* failed to decode SLIP'd stream */
|
||||
}
|
||||
}
|
||||
|
||||
offset += encoded_len;
|
||||
}
|
||||
|
||||
/* end of the tvb coincided with the end of a SLIP'd stream */
|
||||
return tvb_captured_length(tvb);
|
||||
}
|
||||
|
||||
/* OSC TCP (OSC-1.0, OSC-1.1 fork) */
|
||||
|
||||
static int
|
||||
dissect_osc_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
||||
{
|
||||
/*
|
||||
* int32 size prefix framing (OSC-1.0)
|
||||
* ... {(int32 size)(OSC packet)} ... {(int32 size)(OSC packet)} ...
|
||||
*/
|
||||
|
||||
/*
|
||||
* SLIP framing (OSC-1.1)
|
||||
* ... {SLIP'd(OSC packet)} ... {SLIP'd(OSC)} ...
|
||||
*/
|
||||
|
||||
const guint8 first_byte = tvb_get_guint8(tvb, 0);
|
||||
const gboolean slip_encoded = (first_byte == SLIP_END) /* empty SLIP frame*/
|
||||
|| (first_byte == '/') /* SLIP'd OSC message frame */
|
||||
|| (first_byte == '#'); /* SLIP'd OSC bundle frame */
|
||||
|
||||
if(slip_encoded)
|
||||
{
|
||||
/* assume SLIP framing (OSC-1.1) */
|
||||
return dissect_osc_tcp_1_1(tvb, pinfo, tree, data);
|
||||
}
|
||||
|
||||
/* assume int32 size-prefixed framing (OSC-1.0) */
|
||||
return dissect_osc_tcp_1_0(tvb, pinfo, tree, data);
|
||||
}
|
||||
|
||||
/* OSC UDP */
|
||||
|
||||
static int
|
||||
|
@ -1114,7 +1293,7 @@ proto_register_osc(void)
|
|||
|
||||
module_t *osc_module;
|
||||
|
||||
proto_osc = proto_register_protocol("Open Sound Control Protocol", "OSC", "osc");
|
||||
proto_osc = proto_register_protocol("Open Sound Control Encoding", "OSC", "osc");
|
||||
|
||||
proto_register_field_array(proto_osc, hf, array_length(hf));
|
||||
proto_register_subtree_array(ett, array_length(ett));
|
||||
|
|
Loading…
Reference in New Issue