/src/wireshark/epan/dissectors/packet-applemidi.c
Line | Count | Source |
1 | | /* packet-applemidi.c |
2 | | * Routines for dissection of Apple network-midi session establishment. |
3 | | * Copyright 2006-2012, Tobias Erichsen <t.erichsen@gmx.de> |
4 | | * |
5 | | * Wireshark - Network traffic analyzer |
6 | | * By Gerald Combs <gerald@wireshark.org> |
7 | | * Copyright 1998 Gerald Combs |
8 | | * |
9 | | * Copied from packet-data.c, README.developer, and various other files. |
10 | | * |
11 | | * SPDX-License-Identifier: GPL-2.0-or-later |
12 | | * |
13 | | * |
14 | | * Apple network-midi session establishment is a lightweight protocol for |
15 | | * providing a simple session establishment for MIDI-data sent in the form |
16 | | * of RTP-MIDI (RFC 4695 / 6295). Peers recognize each other using the |
17 | | * Apple Bonjour scheme with the service-name "_apple-midi._udp", establish |
18 | | * a connection using AppleMIDI (no official name, just an abbreviation) |
19 | | * and then send payload using RTP-MIDI. The implementation of this |
20 | | * dissector is based on the Apple implementation summary from May 6th, 2005 |
21 | | * and the extension from August 13th, 2010. |
22 | | * |
23 | | * 2010-11-29 |
24 | | * - initial version of dissector |
25 | | * 2012-02-24 |
26 | | * - implemented dynamic payloadtype support to automatically punt |
27 | | * the decoding to the RTP-MIDI dissector via the RTP dissector |
28 | | * - added new bitrate receive limit feature |
29 | | * |
30 | | * Here are some links: |
31 | | * |
32 | | * http://www.cs.berkeley.edu/~lazzaro/rtpmidi/ |
33 | | * https://tools.ietf.org/html/rfc4695 |
34 | | * https://tools.ietf.org/html/rfc6925 |
35 | | */ |
36 | | |
37 | | #include "config.h" |
38 | | |
39 | | #include <epan/packet.h> |
40 | | #include <epan/conversation.h> |
41 | | |
42 | | #include "packet-rtp.h" |
43 | | |
44 | | void proto_register_applemidi(void); |
45 | | void proto_reg_handoff_applemidi(void); |
46 | | |
47 | | /* Definitions for protocol name during dissector-register */ |
48 | 15 | #define APPLEMIDI_DISSECTOR_NAME "Apple Network-MIDI Session Protocol" |
49 | 15 | #define APPLEMIDI_DISSECTOR_SHORTNAME "AppleMIDI" |
50 | 15 | #define APPLEMIDI_DISSECTOR_ABBREVIATION "applemidi" |
51 | | |
52 | | /* Signature "Magic Value" for Apple network MIDI session establishment */ |
53 | 0 | #define APPLEMIDI_PROTOCOL_SIGNATURE 0xffff |
54 | | |
55 | | /* Apple network MIDI valid commands */ |
56 | 0 | #define APPLEMIDI_COMMAND_INVITATION 0x494e /* "IN" */ |
57 | 0 | #define APPLEMIDI_COMMAND_INVITATION_REJECTED 0x4e4f /* "NO" */ |
58 | 0 | #define APPLEMIDI_COMMAND_INVITATION_ACCEPTED 0x4f4b /* "OK" */ |
59 | 0 | #define APPLEMIDI_COMMAND_ENDSESSION 0x4259 /* "BY" */ |
60 | 0 | #define APPLEMIDI_COMMAND_SYNCHRONIZATION 0x434b /* "CK" */ |
61 | 0 | #define APPLEMIDI_COMMAND_RECEIVER_FEEDBACK 0x5253 /* "RS" */ |
62 | 0 | #define APPLEMIDI_COMMAND_BITRATE_RECEIVE_LIMIT 0x524c /* "RL" */ |
63 | | |
64 | | static int hf_applemidi_signature; |
65 | | static int hf_applemidi_command; |
66 | | static int hf_applemidi_protocol_version; |
67 | | static int hf_applemidi_token; |
68 | | static int hf_applemidi_ssrc; |
69 | | static int hf_applemidi_name; |
70 | | static int hf_applemidi_count; |
71 | | static int hf_applemidi_padding; |
72 | | static int hf_applemidi_timestamp1; |
73 | | static int hf_applemidi_timestamp2; |
74 | | static int hf_applemidi_timestamp3; |
75 | | static int hf_applemidi_sequence_num; |
76 | | static int hf_applemidi_rtp_sequence_num; |
77 | | static int hf_applemidi_rtp_bitrate_limit; |
78 | | static int hf_applemidi_unknown_data; |
79 | | |
80 | | |
81 | | static int ett_applemidi; |
82 | | static int ett_applemidi_seq_num; |
83 | | |
84 | | |
85 | | static const value_string applemidi_commands[] = { |
86 | | { APPLEMIDI_COMMAND_INVITATION, "Invitation" }, |
87 | | { APPLEMIDI_COMMAND_INVITATION_REJECTED, "Invitation Rejected" }, |
88 | | { APPLEMIDI_COMMAND_INVITATION_ACCEPTED, "Invitation Accepted" }, |
89 | | { APPLEMIDI_COMMAND_ENDSESSION, "End Session" }, |
90 | | { APPLEMIDI_COMMAND_SYNCHRONIZATION, "Synchronization" }, |
91 | | { APPLEMIDI_COMMAND_RECEIVER_FEEDBACK, "Receiver Feedback" }, |
92 | | { APPLEMIDI_COMMAND_BITRATE_RECEIVE_LIMIT, "Bitrate Receive Limit" }, |
93 | | { 0, NULL }, |
94 | | }; |
95 | | |
96 | | |
97 | | static int proto_applemidi; |
98 | | |
99 | | static dissector_handle_t applemidi_handle; |
100 | | static dissector_handle_t rtp_handle; |
101 | | |
102 | | static const char applemidi_unknown_command[] = "unknown command: 0x%04x"; |
103 | | |
104 | | static void |
105 | 0 | dissect_applemidi_common( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, uint16_t command ) { |
106 | |
|
107 | 0 | proto_item *ti; |
108 | 0 | uint16_t seq_num; |
109 | 0 | uint8_t count; |
110 | 0 | const char *name; |
111 | 0 | int offset = 0; |
112 | 0 | int len; |
113 | 0 | int string_size; |
114 | 0 | proto_tree *applemidi_tree; |
115 | 0 | proto_tree *applemidi_tree_seq_num; |
116 | | |
117 | |
|
118 | 0 | col_set_str( pinfo->cinfo, COL_PROTOCOL, APPLEMIDI_DISSECTOR_SHORTNAME ); |
119 | |
|
120 | 0 | col_add_str( pinfo->cinfo, COL_INFO, val_to_str(pinfo->pool, command, applemidi_commands, applemidi_unknown_command ) ); |
121 | |
|
122 | 0 | ti = proto_tree_add_item( tree, proto_applemidi, tvb, 0, -1, ENC_NA ); |
123 | 0 | applemidi_tree = proto_item_add_subtree( ti, ett_applemidi ); |
124 | |
|
125 | 0 | proto_tree_add_item( applemidi_tree, hf_applemidi_signature, tvb, offset, 2, ENC_BIG_ENDIAN ); |
126 | 0 | offset += 2; |
127 | |
|
128 | 0 | proto_tree_add_item( applemidi_tree, hf_applemidi_command, tvb, offset, 2, ENC_BIG_ENDIAN ); |
129 | 0 | offset += 2; |
130 | | |
131 | | /* the format of packets for "IN", "NO", "OK" and "BY" is identical and contains |
132 | | * the protocol version, a random number generated by the initiator of the session, |
133 | | * the SSRC that is used by the respective sides RTP-entity and optionally the |
134 | | * name of the participant */ |
135 | 0 | if ( ( APPLEMIDI_COMMAND_INVITATION == command ) || |
136 | 0 | ( APPLEMIDI_COMMAND_INVITATION_REJECTED == command ) || |
137 | 0 | ( APPLEMIDI_COMMAND_INVITATION_ACCEPTED == command ) || |
138 | 0 | ( APPLEMIDI_COMMAND_ENDSESSION == command ) ) { |
139 | |
|
140 | 0 | proto_tree_add_item( applemidi_tree, hf_applemidi_protocol_version, tvb, offset, 4, ENC_BIG_ENDIAN ); |
141 | 0 | offset += 4; |
142 | |
|
143 | 0 | proto_tree_add_item( applemidi_tree, hf_applemidi_token, tvb, offset, 4, ENC_BIG_ENDIAN ); |
144 | 0 | offset += 4; |
145 | |
|
146 | 0 | proto_tree_add_item( applemidi_tree, hf_applemidi_ssrc, tvb, offset, 4, ENC_BIG_ENDIAN ); |
147 | 0 | offset += 4; |
148 | |
|
149 | 0 | len = tvb_reported_length(tvb) - offset; |
150 | | |
151 | | /* Name is optional */ |
152 | 0 | if ( len > 0 ) { |
153 | 0 | name = (char *)tvb_get_string_enc( pinfo->pool, tvb, offset, len, ENC_UTF_8|ENC_NA ); |
154 | 0 | string_size = (int)( strlen( name ) + 1 ); |
155 | 0 | proto_tree_add_item( applemidi_tree, hf_applemidi_name, tvb, offset, string_size, ENC_UTF_8 ); |
156 | 0 | col_append_fstr( pinfo->cinfo, COL_INFO, ": peer = \"%s\"", name ); |
157 | 0 | offset += string_size; |
158 | 0 | } |
159 | | |
160 | | /* the synchronization packet contains three 64bit timestamps, and a value to define how |
161 | | * many of the timestamps transmitted are valid */ |
162 | 0 | } else if ( APPLEMIDI_COMMAND_SYNCHRONIZATION == command ) { |
163 | 0 | proto_tree_add_item( applemidi_tree, hf_applemidi_ssrc, tvb, offset, 4, ENC_BIG_ENDIAN ); |
164 | 0 | offset += 4; |
165 | |
|
166 | 0 | count = tvb_get_uint8( tvb, offset ); |
167 | 0 | proto_tree_add_item( applemidi_tree, hf_applemidi_count, tvb, offset, 1, ENC_BIG_ENDIAN ); |
168 | 0 | col_append_fstr( pinfo->cinfo, COL_INFO, ": count = %u", count ); |
169 | 0 | offset += 1; |
170 | |
|
171 | 0 | proto_tree_add_item( applemidi_tree, hf_applemidi_padding, tvb, offset, 3, ENC_BIG_ENDIAN ); |
172 | 0 | offset += 3; |
173 | |
|
174 | 0 | proto_tree_add_item( applemidi_tree, hf_applemidi_timestamp1, tvb, offset, 8, ENC_BIG_ENDIAN ); |
175 | 0 | offset += 8; |
176 | |
|
177 | 0 | proto_tree_add_item( applemidi_tree, hf_applemidi_timestamp2, tvb, offset, 8, ENC_BIG_ENDIAN ); |
178 | 0 | offset += 8; |
179 | |
|
180 | 0 | proto_tree_add_item( applemidi_tree, hf_applemidi_timestamp3, tvb, offset, 8, ENC_BIG_ENDIAN ); |
181 | 0 | offset += 8; |
182 | | /* With the receiver feedback packet, the recipient can tell the sender up to what sequence |
183 | | * number in the RTP-stream the packets have been received; this can be used to shorten the |
184 | | * recovery-journal-section in the RTP-session */ |
185 | 0 | } else if ( APPLEMIDI_COMMAND_RECEIVER_FEEDBACK == command ) { |
186 | 0 | proto_tree_add_item( applemidi_tree, hf_applemidi_ssrc, tvb, offset, 4, ENC_BIG_ENDIAN ); |
187 | 0 | offset += 4; |
188 | |
|
189 | 0 | ti = proto_tree_add_item( applemidi_tree, hf_applemidi_sequence_num, tvb, offset, 4, ENC_BIG_ENDIAN ); |
190 | | /* Apple includes a 32bit sequence-number, but the RTP-packet only specifies 16bit. |
191 | | * this subtree and subitem are added to be able to associate the sequence-number |
192 | | * here easier with the one specified in the corresponding RTP-packet */ |
193 | 0 | applemidi_tree_seq_num = proto_item_add_subtree( ti, ett_applemidi_seq_num ); |
194 | 0 | seq_num = tvb_get_ntohs( tvb, offset ); |
195 | 0 | proto_tree_add_uint( applemidi_tree_seq_num, hf_applemidi_rtp_sequence_num, tvb, offset, 2, seq_num ); |
196 | 0 | offset += 4; |
197 | |
|
198 | 0 | col_append_fstr( pinfo->cinfo, COL_INFO, ": seq = %u", seq_num ); |
199 | | /* With the bitrate receive limit packet, the recipient can tell the sender to limit |
200 | | the transmission to a certain bitrate. This is important if the peer is a gateway |
201 | | to a hardware-device that only supports a certain speed. Like the MIDI 1.0 DIN-cable |
202 | | MIDI-implementation which is limited to 31250. */ |
203 | 0 | } else if ( APPLEMIDI_COMMAND_BITRATE_RECEIVE_LIMIT == command ) { |
204 | 0 | proto_tree_add_item( applemidi_tree, hf_applemidi_ssrc, tvb, offset, 4, ENC_BIG_ENDIAN ); |
205 | 0 | offset += 4; |
206 | |
|
207 | 0 | proto_tree_add_item( applemidi_tree, hf_applemidi_rtp_bitrate_limit, |
208 | 0 | tvb, offset, 4, ENC_BIG_ENDIAN ); |
209 | 0 | offset += 4; |
210 | 0 | } |
211 | | /* If there is any remaining data (possibly because an unknown command was encountered), |
212 | | * we just dump it here */ |
213 | 0 | len = tvb_reported_length_remaining( tvb, offset ); |
214 | 0 | if ( len > 0 ) { |
215 | 0 | proto_tree_add_item( applemidi_tree, hf_applemidi_unknown_data, tvb, offset, len, ENC_NA ); |
216 | 0 | } |
217 | 0 | } |
218 | | |
219 | | static bool |
220 | 0 | test_applemidi(tvbuff_t *tvb, uint16_t *command_p, bool conversation_established ) { |
221 | |
|
222 | 0 | *command_p = 0xffff; |
223 | | |
224 | | /* An applemidi session protocol UDP-packet must start with the "magic value" of 0xffff ... */ |
225 | 0 | if ( APPLEMIDI_PROTOCOL_SIGNATURE != tvb_get_ntohs( tvb, 0 ) ) |
226 | 0 | return false; |
227 | | |
228 | 0 | *command_p = tvb_get_ntohs( tvb, 2 ); |
229 | | |
230 | | /* If the conversation is established (one prior packet with a valid known command) |
231 | | * we won't check the commands anymore - this way we still show new commands |
232 | | * Apple might introduce as "unknown" instead of punting to RTP-dissector */ |
233 | 0 | if ( conversation_established ) { |
234 | 0 | return true; |
235 | 0 | } |
236 | | |
237 | | |
238 | | /* ... followed by packet-command: "IN", "NO", "OK", "BY", "CK" and "RS" and "RL" */ |
239 | 0 | if ( ( APPLEMIDI_COMMAND_INVITATION == *command_p ) || |
240 | 0 | ( APPLEMIDI_COMMAND_INVITATION_REJECTED == *command_p ) || |
241 | 0 | ( APPLEMIDI_COMMAND_INVITATION_ACCEPTED == *command_p ) || |
242 | 0 | ( APPLEMIDI_COMMAND_ENDSESSION == *command_p ) || |
243 | 0 | ( APPLEMIDI_COMMAND_SYNCHRONIZATION == *command_p ) || |
244 | 0 | ( APPLEMIDI_COMMAND_RECEIVER_FEEDBACK == *command_p ) || |
245 | 0 | ( APPLEMIDI_COMMAND_BITRATE_RECEIVE_LIMIT == *command_p ) ) |
246 | 0 | return true; |
247 | | |
248 | 0 | return false; |
249 | 0 | } |
250 | | |
251 | | |
252 | | |
253 | | /* dissect_applemidi() is called when a packet is seen from a previously identified applemidi conversation */ |
254 | | /* If the packet isn't a valid applemidi packet, assume it's an RTP-MIDI packet. */ |
255 | | |
256 | | static int |
257 | 0 | dissect_applemidi( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_ ) { |
258 | 0 | uint16_t command; |
259 | |
|
260 | 0 | if ( test_applemidi( tvb, &command, true ) ) |
261 | 0 | dissect_applemidi_common( tvb, pinfo, tree, command ); |
262 | 0 | else |
263 | 0 | call_dissector( rtp_handle, tvb, pinfo, tree ); |
264 | |
|
265 | 0 | return tvb_captured_length(tvb); |
266 | 0 | } |
267 | | |
268 | | static bool |
269 | 0 | dissect_applemidi_heur( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_ ) { |
270 | |
|
271 | 0 | uint16_t command; |
272 | 0 | conversation_t *p_conv; |
273 | 0 | rtp_dyn_payload_t *rtp_dyn_payload; |
274 | |
|
275 | 0 | if ( tvb_captured_length( tvb ) < 4) |
276 | 0 | return false; /* not enough bytes to check */ |
277 | | |
278 | 0 | if ( !test_applemidi( tvb, &command, false ) ) { |
279 | 0 | return false; |
280 | 0 | } |
281 | | |
282 | | /* set dynamic payload-type 97 which is used by Apple for their RTP-MIDI implementation for this |
283 | | address/port-tuple to cause RTP-dissector to call the RTP-MIDI-dissector for payload-decoding */ |
284 | | |
285 | 0 | rtp_dyn_payload = rtp_dyn_payload_new(); |
286 | 0 | rtp_dyn_payload_insert(rtp_dyn_payload, 97, "rtp-midi", 10000, 1); |
287 | 0 | rtp_add_address( pinfo, PT_UDP, &pinfo->src, pinfo->srcport, 0, APPLEMIDI_DISSECTOR_SHORTNAME, |
288 | 0 | pinfo->num, false, rtp_dyn_payload); |
289 | | |
290 | | /* call dissect_applemidi() from now on for UDP packets on this "connection" |
291 | | it is important to do this step after calling rtp_add_address, otherwise |
292 | | all further packets will go directly to the RTP-dissector! */ |
293 | |
|
294 | 0 | p_conv = find_or_create_conversation(pinfo); |
295 | 0 | conversation_set_dissector( p_conv, applemidi_handle ); |
296 | | |
297 | | /* punt to actual decoding */ |
298 | |
|
299 | 0 | dissect_applemidi_common( tvb, pinfo, tree, command ); |
300 | 0 | return true; |
301 | |
|
302 | 0 | } |
303 | | |
304 | | |
305 | | void |
306 | | proto_register_applemidi( void ) |
307 | 15 | { |
308 | 15 | static hf_register_info hf[] = { |
309 | 15 | { |
310 | 15 | &hf_applemidi_signature, |
311 | 15 | { |
312 | 15 | "Signature", |
313 | 15 | "applemidi.signature", |
314 | 15 | FT_UINT16, |
315 | 15 | BASE_HEX, |
316 | 15 | NULL, |
317 | 15 | 0x0, |
318 | 15 | NULL, HFILL |
319 | 15 | } |
320 | 15 | }, |
321 | 15 | { |
322 | 15 | &hf_applemidi_command, |
323 | 15 | { |
324 | 15 | "Command", |
325 | 15 | "applemidi.command", |
326 | 15 | FT_UINT16, |
327 | 15 | BASE_HEX, |
328 | 15 | VALS( applemidi_commands ), |
329 | 15 | 0x0, |
330 | 15 | NULL, HFILL |
331 | 15 | } |
332 | 15 | }, |
333 | 15 | { |
334 | 15 | &hf_applemidi_protocol_version, |
335 | 15 | { |
336 | 15 | "Protocol Version", |
337 | 15 | "applemidi.protocol_version", |
338 | 15 | FT_UINT32, |
339 | 15 | BASE_DEC, |
340 | 15 | NULL, |
341 | 15 | 0x0, |
342 | 15 | NULL, HFILL |
343 | 15 | } |
344 | 15 | }, |
345 | 15 | { |
346 | 15 | &hf_applemidi_token, |
347 | 15 | { |
348 | 15 | "Initiator Token", |
349 | 15 | "applemidi.initiator_token", |
350 | 15 | FT_UINT32, |
351 | 15 | BASE_HEX, |
352 | 15 | NULL, |
353 | 15 | 0x0, |
354 | 15 | NULL, HFILL |
355 | 15 | } |
356 | 15 | }, |
357 | 15 | { |
358 | 15 | &hf_applemidi_ssrc, |
359 | 15 | { |
360 | 15 | "Sender SSRC", |
361 | 15 | "applemidi.sender_ssrc", |
362 | 15 | FT_UINT32, |
363 | 15 | BASE_HEX, |
364 | 15 | NULL, |
365 | 15 | 0x0, |
366 | 15 | NULL, HFILL |
367 | 15 | } |
368 | 15 | }, |
369 | 15 | { |
370 | 15 | &hf_applemidi_name, |
371 | 15 | { |
372 | 15 | "Name", |
373 | 15 | "applemidi.name", |
374 | 15 | FT_STRING, |
375 | 15 | BASE_NONE, |
376 | 15 | NULL, |
377 | 15 | 0x0, |
378 | 15 | NULL, HFILL |
379 | 15 | } |
380 | 15 | }, |
381 | 15 | { |
382 | 15 | &hf_applemidi_count, |
383 | 15 | { |
384 | 15 | "Count", |
385 | 15 | "applemidi.count", |
386 | 15 | FT_UINT8, |
387 | 15 | BASE_DEC, |
388 | 15 | NULL, |
389 | 15 | 0x0, |
390 | 15 | NULL, HFILL |
391 | 15 | } |
392 | 15 | }, |
393 | 15 | { |
394 | 15 | &hf_applemidi_padding, |
395 | 15 | { |
396 | 15 | "Padding", |
397 | 15 | "applemidi.padding", |
398 | 15 | FT_UINT24, |
399 | 15 | BASE_HEX, |
400 | 15 | NULL, |
401 | 15 | 0x0, |
402 | 15 | NULL, HFILL |
403 | 15 | } |
404 | 15 | }, |
405 | 15 | { |
406 | 15 | &hf_applemidi_timestamp1, |
407 | 15 | { |
408 | 15 | "Timestamp 1", |
409 | 15 | "applemidi.timestamp1", |
410 | 15 | FT_UINT64, |
411 | 15 | BASE_HEX, |
412 | 15 | NULL, |
413 | 15 | 0x0, |
414 | 15 | NULL, HFILL |
415 | 15 | } |
416 | 15 | }, |
417 | 15 | { |
418 | 15 | &hf_applemidi_timestamp2, |
419 | 15 | { |
420 | 15 | "Timestamp 2", |
421 | 15 | "applemidi.timestamp2", |
422 | 15 | FT_UINT64, |
423 | 15 | BASE_HEX, |
424 | 15 | NULL, |
425 | 15 | 0x0, |
426 | 15 | NULL, HFILL |
427 | 15 | } |
428 | 15 | }, |
429 | 15 | { |
430 | 15 | &hf_applemidi_timestamp3, |
431 | 15 | { |
432 | 15 | "Timestamp 3", |
433 | 15 | "applemidi.timestamp3", |
434 | 15 | FT_UINT64, |
435 | 15 | BASE_HEX, |
436 | 15 | NULL, |
437 | 15 | 0x0, |
438 | 15 | NULL, HFILL |
439 | 15 | } |
440 | 15 | }, |
441 | 15 | { |
442 | 15 | &hf_applemidi_sequence_num, |
443 | 15 | { |
444 | 15 | "Sequence Number", |
445 | 15 | "applemidi.sequence_number", |
446 | 15 | FT_UINT32, |
447 | 15 | BASE_HEX, |
448 | 15 | NULL, |
449 | 15 | 0x0, |
450 | 15 | NULL, HFILL |
451 | 15 | } |
452 | 15 | }, |
453 | 15 | { |
454 | 15 | &hf_applemidi_rtp_sequence_num, |
455 | 15 | { |
456 | 15 | "RTP Sequence Number", |
457 | 15 | "applemidi.rtp_sequence_number", |
458 | 15 | FT_UINT16, |
459 | 15 | BASE_DEC, |
460 | 15 | NULL, |
461 | 15 | 0x0, |
462 | 15 | NULL, HFILL |
463 | 15 | } |
464 | 15 | }, |
465 | 15 | { |
466 | 15 | &hf_applemidi_rtp_bitrate_limit, |
467 | 15 | { |
468 | 15 | "Bitrate limit", |
469 | 15 | "applemidi.bitrate_limit", |
470 | 15 | FT_UINT32, |
471 | 15 | BASE_DEC, |
472 | 15 | NULL, |
473 | 15 | 0x0, |
474 | 15 | NULL, HFILL |
475 | 15 | } |
476 | 15 | }, |
477 | 15 | { |
478 | 15 | &hf_applemidi_unknown_data, |
479 | 15 | { |
480 | 15 | "Unknown Data", |
481 | 15 | "applemidi.unknown_data", |
482 | 15 | FT_BYTES, |
483 | 15 | BASE_NONE, |
484 | 15 | NULL, |
485 | 15 | 0x00, |
486 | 15 | NULL, HFILL |
487 | 15 | } |
488 | 15 | }, |
489 | 15 | }; |
490 | | |
491 | | |
492 | 15 | static int *ett[] = { |
493 | 15 | &ett_applemidi, |
494 | 15 | &ett_applemidi_seq_num |
495 | 15 | }; |
496 | | |
497 | 15 | proto_applemidi = proto_register_protocol( APPLEMIDI_DISSECTOR_NAME, |
498 | 15 | APPLEMIDI_DISSECTOR_SHORTNAME, |
499 | 15 | APPLEMIDI_DISSECTOR_ABBREVIATION ); |
500 | 15 | proto_register_field_array( proto_applemidi, hf, array_length( hf ) ); |
501 | 15 | proto_register_subtree_array( ett, array_length( ett ) ); |
502 | | |
503 | 15 | applemidi_handle = register_dissector( "applemidi", dissect_applemidi, proto_applemidi ); |
504 | 15 | } |
505 | | |
506 | | void |
507 | 15 | proto_reg_handoff_applemidi( void ) { |
508 | | /* If we cannot decode the data it will be RTP-MIDI since the Apple session protocol uses |
509 | | * two ports: the control-port and the MIDI-port. On both ports an invitation is being sent. |
510 | | * The second port is then used for the RTP-MIDI-data. So if we can't find valid AppleMidi |
511 | | * packets, it will be most likely RTP-MIDI... |
512 | | */ |
513 | 15 | rtp_handle = find_dissector_add_dependency( "rtp", proto_applemidi ); |
514 | 15 | heur_dissector_add( "udp", dissect_applemidi_heur, "Apple MIDI over UDP", "applemidi_udp", proto_applemidi, HEURISTIC_DISABLE ); |
515 | 15 | } |
516 | | |
517 | | /* |
518 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
519 | | * |
520 | | * Local variables: |
521 | | * c-basic-offset: 8 |
522 | | * tab-width: 8 |
523 | | * indent-tabs-mode: t |
524 | | * End: |
525 | | * |
526 | | * vi: set shiftwidth=8 tabstop=8 noexpandtab: |
527 | | * :indentSize=8:tabSize=8:noTabs=false: |
528 | | */ |