epan/dissectors/pidl/samr/samr.cnf cnf_dissect_lsa_BinaryString => lsarpc_dissect_str...
[wireshark-sm.git] / epan / dissectors / packet-srt.c
blob33391b4e6317a679d65c070ee72c3056a3aed8fb
1 /* packet-srt.c
2 * Routines for Secure Reliable Transport Protocol dissection
3 * Copyright (c) 2018 Haivision Systems Inc. <info@srtalliance.org>
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 * SRT is an open source video transport protocol and technology stack
14 * that optimizes streaming performance across unpredictable networks
15 * with secure streams and easy firewall traversal, bringing the best
16 * quality live video over the worst networks.
18 * Internet draft:
19 * https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-01
21 * Open-source implementation:
22 * https://github.com/Haivision/srt
25 #include <config.h>
27 #include <epan/packet.h>
28 #include <epan/expert.h>
29 #include <epan/conversation.h>
30 #include <epan/tfs.h>
31 #include <epan/unit_strings.h>
33 #include <wsutil/array.h>
34 #include <wsutil/inet_addr.h>
36 /* Prototypes */
37 void proto_reg_handoff_srt(void);
38 void proto_register_srt(void);
40 /* Initialize the protocol */
41 static int proto_srt;
42 static int hf_srt_iscontrol;
43 static int hf_srt_type;
44 static int hf_srt_exttype;
45 static int hf_srt_exttype_none;
46 static int hf_srt_seqno;
47 static int hf_srt_ack_seqno;
48 static int hf_srt_ackno;
49 static int hf_srt_msgno;
50 static int hf_srt_msgno_pb;
51 static int hf_srt_msgno_inorder;
52 static int hf_srt_msgno_enctypes;
53 static int hf_srt_msgno_rexmit;
54 static int hf_srt_timestamp;
55 static int hf_srt_id;
56 static int hf_srt_addinfo;
57 static int hf_srt_rtt;
58 static int hf_srt_rttvar;
59 static int hf_srt_bufavail;
60 static int hf_srt_rate;
61 static int hf_srt_bandwidth;
62 static int hf_srt_rcvrate;
64 /* SRT Handshake */
65 static int hf_srt_handshake_version;
66 static int hf_srt_handshake_type_v4;
67 static int hf_srt_handshake_enc_field_v5;
68 static int hf_srt_handshake_ext_field_v5;
69 static int hf_srt_handshake_ext_field_v5_flag_hsreq;
70 static int hf_srt_handshake_ext_field_v5_flag_kmreq;
71 static int hf_srt_handshake_ext_field_v5_flag_config;
72 static int hf_srt_handshake_isn;
73 static int hf_srt_handshake_mtu;
74 static int hf_srt_handshake_flow_window;
75 static int hf_srt_handshake_reqtype;
76 static int hf_srt_handshake_failure_type;
77 static int hf_srt_handshake_id;
78 static int hf_srt_handshake_cookie;
79 static int hf_srt_handshake_peerip;
80 /* SRT Handshake Extension */
81 static int hf_srt_handshake_ext_version;
82 static int hf_srt_handshake_ext_flags;
83 static int hf_srt_handshake_ext_flag_tsbpd_snd;
84 static int hf_srt_handshake_ext_flag_tsbpd_rcv;
85 static int hf_srt_handshake_ext_flag_haicrypt;
86 static int hf_srt_handshake_ext_flag_tlpkt_drop;
87 static int hf_srt_handshake_ext_flag_nak_report;
88 static int hf_srt_handshake_ext_flag_rexmit;
89 static int hf_srt_handshake_ext_flag_stream;
91 /* Key Material (KM) */
92 static int hf_srt_km;
93 static int hf_srt_km_s;
94 static int hf_srt_km_v;
95 static int hf_srt_km_pt;
96 static int hf_srt_km_sign;
97 static int hf_srt_km_resv1;
98 static int hf_srt_km_kk;
99 static int hf_srt_km_keki;
100 static int hf_srt_km_cipher;
101 static int hf_srt_km_auth;
102 static int hf_srt_km_se;
103 static int hf_srt_km_resv2;
104 static int hf_srt_km_resv3;
105 static int hf_srt_km_slen;
106 static int hf_srt_km_klen;
107 static int hf_srt_km_salt;
108 static int hf_srt_km_wrap;
110 /* HS Extension: Group */
111 static int hf_srt_hs_ext_group_id;
112 static int hf_srt_hs_ext_group_type;
113 static int hf_srt_hs_ext_group_flags;
114 static int hf_srt_hs_ext_group_weight;
116 static int hf_srt_srths_blocktype;
117 static int hf_srt_srths_blocklen;
118 static int hf_srt_srths_agent_latency; // TSBPD delay
119 static int hf_srt_srths_peer_latency; // TSBPD delay
120 static int hf_srt_srtkm_msg;
121 static int hf_srt_srtkm_error;
122 static int hf_srt_srths_sid;
123 static int hf_srt_srths_congestcontrol;
124 static int hf_srt_hs_ext_filter;
126 static int ett_srt;
127 static int ett_srt_handshake_ext_flags;
128 static int ett_srt_handshake_ext_field_flags;
130 static expert_field ei_srt_nak_seqno;
131 static expert_field ei_srt_hs_ext_hsreq_len;
132 static expert_field ei_srt_hs_ext_type;
133 static expert_field ei_srt_hs_ext_group_len;
135 static dissector_handle_t srt_udp_handle;
138 /* This defines the firstmost bit of the packet, so it can stay this way. */
139 #define SRT_TYPE_DATA 0
140 #define SRT_TYPE_CONTROL 1
141 #define SRT_CONTROL_MASK (~0x80000000)
143 #define SRT_KM_S_MASK 0x80
144 #define SRT_KM_V_MASK 0x70
145 #define SRT_KM_PT_MASK 0x0F
146 #define SRT_KM_KK_MASK 0x03
147 #define SRT_KM_RESV1_MASK 0xFC
149 #define SRT_LOSS_SEQUENCE_FIRST 0x80000000
150 #define SRT_LOSS_SEQUENCE_MASK (~SRT_LOSS_SEQUENCE_FIRST)
152 enum UDTSockType
154 SRT_UNDEFINED = 0, /* initial trap representation */
155 SRT_STREAM = 1,
156 SRT_DGRAM = 2,
157 SRT_MAGIC_CODE = 0x4A17
160 /* Handshake Extended Field Flags */
161 #define SRT_OPT_FIELD_LEN 32
162 #define SRT_OPT_TSBPDSND (1 << 0)
163 #define SRT_OPT_TSBPDRCV (1 << 1)
164 #define SRT_OPT_HAICRYPT (1 << 2)
165 #define SRT_OPT_TLPKTDROP (1 << 3)
166 #define SRT_OPT_NAKREPORT (1 << 4)
167 #define SRT_OPT_REXMITFLG (1 << 5)
168 #define SRT_OPT_STREAM (1 << 6)
171 /* Extended Handshake Flags */
172 #define SRT_HS_V5_EXT_FIELD_LEN 16
173 #define SRT_HS_V5_EXT_FIELD_HSREQ (1 << 0)
174 #define SRT_HS_V5_EXT_FIELD_KMREQ (1 << 1)
175 #define SRT_HS_V5_EXT_FIELD_CONFIG (1 << 2)
176 #define SRT_HS_V5_EXT_FIELD_MAGIC SRT_MAGIC_CODE
178 /* Message number field and single bit flags */
179 #define SRT_MSGNO_FF_FIRST_B (2 << (32-2))
180 #define SRT_MSGNO_FF_LAST_B (1 << (32-2))
181 #define SRT_MSGNO_FF_MASK (SRT_MSGNO_FF_FIRST_B | SRT_MSGNO_FF_LAST_B)
183 enum PacketBoundary
185 PB_SUBSEQUENT = 0,
186 /* 01: last packet of a message */
187 PB_LAST = 1,
188 /* 10: first packet of a message */
189 PB_FIRST = 2,
190 /* 11: solo message packet */
191 PB_SOLO = 3,
195 #define SRT_MSGNO_INORDER (1 << (32-3)) /* 0x20000000 */
197 #define SRT_MSGNO_ENCTYPE (3 << (32-5)) /* 0x18000000 */
199 #define SRT_MSGNO_EK_NONE 0
200 #define SRT_MSGNO_EK_EVEN 1
201 #define SRT_MSGNO_EK_ODD 2
203 #define SRT_MSGNO_REXMIT (1 << (32-6)) /* 0x04000000 */
205 /* Rest of the bits are for message sequence number */
206 #define SRT_MSGNO_MSGNO_MASK 0x03ffffff
207 #define SRT_MSGNO_REXMIT_FLG 0x04000000
210 /* The message types used by SRT protocol. This is a part of SRT
211 * protocol and should never be changed.
213 enum UDTMessageType
215 UMSG_HANDSHAKE = 0, // Connection Handshake. Control: see @a CHandShake.
216 UMSG_KEEPALIVE = 1, // Keep-alive.
217 UMSG_ACK = 2, // Acknowledgement. Control: past-the-end sequence number up to which packets have been received.
218 UMSG_LOSSREPORT = 3, // Negative Acknowledgement (NACK). Control: Loss list.
219 UMSG_CGWARNING = 4, // Congestion warning.
220 UMSG_SHUTDOWN = 5, // Shutdown.
221 UMSG_ACKACK = 6, // Acknowledgement of Acknowledgement. Add info: The ACK sequence number
222 UMSG_DROPREQ = 7, // Message Drop Request. Add info: Message ID. Control Info: (first, last) number of the message.
223 UMSG_PEERERROR = 8, // Signal from the Peer side. Add info: Error code.
224 /* ... add extra code types here */
225 UMSG_END_OF_TYPES,
226 UMSG_EXT = 0x7FFF // For the use of user-defined control packets.
229 // Adapted constants
230 #define SRT_CMD_HSREQ 1
231 #define SRT_CMD_HSRSP 2
232 #define SRT_CMD_KMREQ 3
233 #define SRT_CMD_KMRSP 4
234 #define SRT_CMD_SID 5
235 #define SRT_CMD_CONGESTION 6
236 #define SRT_CMD_FILTER 7
237 #define SRT_CMD_GROUP 8
239 enum SrtDataStruct
241 SRT_HS_VERSION = 0,
242 SRT_HS_FLAGS,
243 SRT_HS_EXTRAS,
245 // Keep it always last
246 SRT_HS__SIZE
250 enum UDTRequestType
252 URQ_AGREEMENT = -2,
253 URQ_CONCLUSION = -1,
254 URQ_WAVEAHAND = 0,
255 URQ_INDUCTION = 1,
257 URQ_FAILURE_TYPES = 1000
261 enum SRT_KM_STATE
263 SRT_KM_S_UNSECURED = 0, ///< No encryption
264 SRT_KM_S_SECURING = 1, ///< Stream encrypted, exchanging Keying Material
265 SRT_KM_S_SECURED = 2, ///< Stream encrypted, keying Material exchanged, decrypting ok.
266 SRT_KM_S_NOSECRET = 3, ///< Stream encrypted and no secret to decrypt Keying Material
267 SRT_KM_S_BADSECRET = 4 ///< Stream encrypted and wrong secret, cannot decrypt Keying Material
270 static const value_string srt_ctrlmsg_types[] = {
271 {UMSG_HANDSHAKE, "HANDSHAKE"},
272 {UMSG_KEEPALIVE, "KEEPALIVE"},
273 {UMSG_ACK, "ACK"},
274 {UMSG_LOSSREPORT, "LOSSREPORT"},
275 {UMSG_CGWARNING, "CGWARNING"},
276 {UMSG_SHUTDOWN, "SHUTDOWN"},
277 {UMSG_ACKACK, "ACKACK"},
278 {UMSG_DROPREQ, "DROPREQ"},
279 {UMSG_PEERERROR, "PEERERROR"},
280 {UMSG_EXT, "EXT"},
282 {0, NULL},
285 static const value_string srt_ctrlmsg_exttypes[] = {
286 {SRT_CMD_HSREQ, "HSREQ"},
287 {SRT_CMD_HSRSP, "HSRSP"},
288 {SRT_CMD_KMREQ, "KMREQ"},
289 {SRT_CMD_KMRSP, "KMRSP"},
290 {SRT_CMD_SID, "SID"},
291 {SRT_CMD_CONGESTION, "CONGESTION"},
292 {SRT_CMD_FILTER, "FILTER"},
293 {SRT_CMD_GROUP, "GROUP"},
295 { 0, NULL },
298 static const value_string srt_hs_ext_group_type[] = {
299 { 0, "Undefined" },
300 { 1, "Broadcast" },
301 { 2, "Main/Backup" },
302 { 3, "Balancing"},
303 { 0, NULL }
306 static const value_string srt_hsv4_socket_types[] = {
307 {SRT_STREAM, "SRT_STREAM"},
308 {SRT_DGRAM, "SRT_DGRAM"},
309 {0, NULL},
313 static const value_string srt_handshake_enc_field[] = {
314 {0, "PBKEYLEN not advertised"},
315 {2, "AES-128" },
316 {3, "AES-192" },
317 {4, "AES-256" },
318 {0, NULL},
322 static const true_false_string srt_packet_types = {
323 "CONTROL", /* 1 */
324 "DATA" /* 0 */
327 static const value_string srt_pb_types[] = {
328 {PB_SUBSEQUENT, "PB_SUBSEQUENT"},
329 {PB_LAST, "PB_LAST"},
330 {PB_FIRST, "PB_FIRST"},
331 {PB_SOLO, "PB_SOLO"},
332 {0, NULL},
335 static const value_string srt_msgno_enctypes[] = {
336 {SRT_MSGNO_EK_NONE, "Not encrypted"},
337 {SRT_MSGNO_EK_EVEN, "Encrypted (even key)"},
338 {SRT_MSGNO_EK_ODD, "Encrypted (odd key)"},
339 {0, NULL},
342 static const true_false_string srt_msgno_rexmit = {
343 "Retransmitted", /* 1 */
344 "Original" /* 0 */
347 static const value_string srt_hs_request_types[] = {
348 {URQ_INDUCTION, "URQ_INDUCTION (c/l invocation)"},
349 {URQ_CONCLUSION, "URQ_CONCLUSION"},
350 {URQ_WAVEAHAND, "URQ_WAVEAHAND (rendezvous invocation)"},
351 {URQ_AGREEMENT, "URQ_AGREEMENT (rendezvous finalization)"},
352 {0, NULL}
355 static const value_string srt_enc_kmstate[] = {
356 {SRT_KM_S_UNSECURED, "UNSECURED"},
357 {SRT_KM_S_SECURING, "SECURING"},
358 {SRT_KM_S_SECURED, "SECURED"},
359 {SRT_KM_S_NOSECRET, "NOSECRET"},
360 {SRT_KM_S_BADSECRET, "BADSECRET"},
362 {0, NULL},
367 * XXX To be added later to extract correct IPv4/IPv6 address from 16 bytes of data
368 * static void srt_tree_add_ipaddr( proto_tree *tree, const int hf, tvbuff_t *tvb, int offset)
374 #define IP_BUFFER_SIZE 64
376 static void srt_format_ip_address(char* dest, size_t dest_size, const char* ptr)
378 /* Initial IPv4 check.
379 * The address is considered IPv4 if:
380 * byte[0] and byte[3] != 0
381 * bytes[4...16] == 0
384 ws_in4_addr ia4;
385 ws_in6_addr ia6;
386 uint32_t* p;
387 int i, j;
389 if (ptr[0] != 0 && ptr[3] != 0)
391 for (i = 4; i < 16; ++i)
393 if (ptr[i] == 0)
394 continue;
396 /* This is not an IP4 */
397 p = (uint32_t*)&ia6;
398 for (j = 0; j < 4; ++j)
399 p[j] = g_ntohl(((uint32_t*)ptr)[j]);
401 ws_inet_ntop6(&ia6, dest, (unsigned)dest_size);
402 return;
406 // There's one small problem: the contents of the handshake
407 // goes in LITTLE ENDIAN. That's an initial problem of UDT.
408 // The address must be inverted.
410 // Here's IPv4, so invert only one l.
411 ia4 = g_ntohl(*((const uint32_t*)ptr));
413 ws_inet_ntop4(&ia4, dest, (unsigned)dest_size);
414 return;
418 static void srt_format_hs_ext_hsreq(proto_tree* tree, tvbuff_t* tvb, int baseoff)
420 proto_item* pi;
421 uint32_t version = 0;
422 pi = proto_tree_add_item_ret_uint(tree, hf_srt_handshake_ext_version, tvb, baseoff, 4, ENC_BIG_ENDIAN, &version);
424 const int vminor = (version >> 8) & 0xff;
425 const int vmajor = (version >> 16) & 0xff;
426 const int vpatch = version & 0xff;
427 proto_item_append_text(pi, " (%d.%d.%d)", vmajor, vminor, vpatch);
429 static int * const ext_hs_flags[] = {
430 &hf_srt_handshake_ext_flag_tsbpd_snd,
431 &hf_srt_handshake_ext_flag_tsbpd_rcv,
432 &hf_srt_handshake_ext_flag_haicrypt,
433 &hf_srt_handshake_ext_flag_tlpkt_drop,
434 &hf_srt_handshake_ext_flag_nak_report,
435 &hf_srt_handshake_ext_flag_rexmit,
436 &hf_srt_handshake_ext_flag_stream,
437 NULL
440 proto_tree_add_bitmask_with_flags(tree, tvb, baseoff + 4, hf_srt_handshake_ext_flags,
441 ett_srt_handshake_ext_flags, ext_hs_flags, ENC_NA, BMT_NO_APPEND);
443 proto_tree_add_item(tree, hf_srt_srths_peer_latency, tvb, baseoff + 8, 2, ENC_BIG_ENDIAN);
444 proto_tree_add_item(tree, hf_srt_srths_agent_latency, tvb, baseoff + 10, 2, ENC_BIG_ENDIAN);
447 static void srt_format_km(proto_tree* tree, tvbuff_t* tvb, int baseoff, int blocklen)
449 // 0 1 2 3
450 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
451 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
452 // |S| V | PT | Sign | Resv1 | KK|
453 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
454 // | KEKI |
455 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
456 // | Cipher | Auth | SE | Resv2 |
457 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
458 // | Resv3 | SLen/4 | KLen/4 |
459 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
460 // | Salt |
461 // | (16 bytes) |
462 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
463 // | |
464 // + Wrapped Key +
465 // | |
466 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
467 unsigned u8bits = 0;
468 uint32_t slen = 0;
470 proto_tree_add_item(tree, hf_srt_km_s, tvb, baseoff, 1, ENC_BIG_ENDIAN);
471 proto_tree_add_item(tree, hf_srt_km_v, tvb, baseoff, 1, ENC_BIG_ENDIAN);
472 proto_tree_add_item(tree, hf_srt_km_pt, tvb, baseoff, 1, ENC_BIG_ENDIAN);
474 proto_tree_add_item(tree, hf_srt_km_sign, tvb, baseoff + 1, 2, ENC_NA);
476 proto_tree_add_item(tree, hf_srt_km_resv1, tvb, baseoff + 3, 1, ENC_NA);
478 static const value_string kk_desc[] = {
479 { 0, "No SEK is provided - invalid KM" },
480 { 1, "Even key is provided" },
481 { 2, "Odd key is provided" },
482 { 3, "Both even and odd keys are provided"},
483 { 0, NULL }
486 u8bits = tvb_get_uint8(tvb, baseoff + 3);
487 proto_tree_add_uint_format_value(tree, hf_srt_km_kk, tvb, baseoff + 3, 1,
488 u8bits, "%u (%s)", (u8bits & SRT_KM_KK_MASK), try_val_to_str(u8bits & SRT_KM_KK_MASK, kk_desc));
490 static const value_string cipher_desc[] = {
491 { 0, "None or KEKI indexed crypto context" },
492 { 1, "AES-ECB (reserved, not supported)" },
493 { 2, "AES-CTR" },
494 { 3, "AES-CBC (reserved, not supported)" },
495 { 4, "AES-GCM" },
496 { 0, NULL }
498 proto_tree_add_item(tree, hf_srt_km_keki, tvb, baseoff + 4, 4, ENC_BIG_ENDIAN);
500 u8bits = tvb_get_uint8(tvb, baseoff + 8);
501 proto_tree_add_uint_format_value(tree, hf_srt_km_cipher, tvb, baseoff + 8, 1,
502 u8bits, "%u (%s)", u8bits, try_val_to_str(u8bits, cipher_desc));
504 proto_tree_add_item(tree, hf_srt_km_auth, tvb, baseoff + 9, 1, ENC_BIG_ENDIAN);
506 static const value_string se_desc[] = {
507 { 0, "Unspecified" },
508 { 1, "MPEG2-TS/UDP" },
509 { 2, "MPEG2-TS/SRT" },
510 { 0, NULL }
512 u8bits = tvb_get_uint8(tvb, baseoff + 10); // km.se
513 proto_tree_add_uint_format_value(tree, hf_srt_km_se, tvb, baseoff + 10, 1,
514 u8bits, "%u (%s)", u8bits, try_val_to_str(u8bits, se_desc));
516 proto_tree_add_item(tree, hf_srt_km_resv2, tvb, baseoff + 11, 1, ENC_NA);
517 proto_tree_add_item(tree, hf_srt_km_resv3, tvb, baseoff + 12, 2, ENC_NA);
519 u8bits = tvb_get_uint8(tvb, baseoff + 14); // km.slen
520 slen = 4 * u8bits;
521 proto_tree_add_uint_format_value(tree, hf_srt_km_slen, tvb, baseoff + 14, 1,
522 u8bits, "%u (%d bytes)", u8bits, slen);
524 u8bits = tvb_get_uint8(tvb, baseoff + 15); // km.klen
525 proto_tree_add_uint_format_value(tree, hf_srt_km_klen, tvb, baseoff + 15, 1,
526 u8bits, "%u (%d bytes)", u8bits, 4 * u8bits);
528 proto_tree_add_item(tree, hf_srt_km_salt, tvb, baseoff + 16, slen, ENC_NA);
530 const int wrap_offset = 16 + slen;
531 proto_tree_add_item(tree, hf_srt_km_wrap, tvb, baseoff + wrap_offset, blocklen - wrap_offset, ENC_NA);
534 static void srt_format_kmx(proto_tree* tree, tvbuff_t* tvb, int baseoff, int blocklen)
536 if (blocklen == 4)
538 // Error report. Format as KMX state.
539 proto_tree_add_item(tree, hf_srt_srtkm_error, tvb, baseoff, 4, ENC_NA);
541 else
543 srt_format_km(tree, tvb, baseoff, blocklen);
547 static void srt_format_hs_ext_group(proto_tree* tree, tvbuff_t* tvb, packet_info* pinfo, int baseoff, int blocklen)
549 // 0 1 2 3
550 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
551 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
552 // | Group ID |
553 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
554 // | Type | Flags | Weight |
555 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
556 if (blocklen < 8)
558 proto_tree_add_expert_format(tree, pinfo, &ei_srt_hs_ext_hsreq_len,
559 tvb, baseoff, blocklen, "Actual length is %u", blocklen);
560 return;
563 proto_tree_add_item(tree, hf_srt_hs_ext_group_id, tvb, baseoff, 4, ENC_BIG_ENDIAN);
564 proto_tree_add_item(tree, hf_srt_hs_ext_group_type, tvb, baseoff + 4, 1, ENC_BIG_ENDIAN);
565 proto_tree_add_item(tree, hf_srt_hs_ext_group_flags, tvb, baseoff + 5, 1, ENC_BIG_ENDIAN);
566 proto_tree_add_item(tree, hf_srt_hs_ext_group_weight, tvb, baseoff + 6, 2, ENC_BIG_ENDIAN);
568 if (blocklen > 8)
570 proto_tree_add_expert_format(tree, pinfo, &ei_srt_hs_ext_hsreq_len,
571 tvb, baseoff, blocklen, "Actual length is %u", blocklen);
575 // Wireshark dissector doesn't have a possibility to format enum-collected flags.
576 static void dissect_srt_hs_ext_field(proto_tree* tree,
577 tvbuff_t* tvb, int baseoff)
579 static const int ext_field_len = 2;
581 const int bits = tvb_get_ntohs(tvb, baseoff);
582 if (bits == SRT_HS_V5_EXT_FIELD_MAGIC)
584 proto_item* pi = proto_tree_add_item(tree, hf_srt_handshake_ext_field_v5,
585 tvb, baseoff, ext_field_len, ENC_BIG_ENDIAN);
586 proto_item_append_text(pi, ": HSv5 MAGIC");
587 return;
590 static int * const ext_hs_ext_field_flags[] = {
591 &hf_srt_handshake_ext_field_v5_flag_hsreq,
592 &hf_srt_handshake_ext_field_v5_flag_kmreq,
593 &hf_srt_handshake_ext_field_v5_flag_config,
594 NULL
597 proto_tree_add_bitmask_with_flags(tree, tvb, baseoff, hf_srt_handshake_ext_field_v5,
598 ett_srt_handshake_ext_field_flags, ext_hs_ext_field_flags, ENC_NA, BMT_NO_APPEND);
600 return;
605 * UTF-8 string packed as 32 bit little endian words (what?!)
606 * https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-01#section-3.2.1.3
608 * THe spec says
610 * The actual size is determined by the Extension Length field,
611 * which defines the length in four byte blocks. If the actual
612 * payload is less than the declared length, the remaining bytes
613 * are set to zeros.
615 * The content is stored as 32-bit little endian words.
617 * This means that the octets of the string are in the rather peculiar
618 * order:
620 * octet 3
621 * octet 2
622 * octet 1
623 * octet 0
624 * octet 8
625 * octet 7
626 * octet 6
627 * octet 5
629 * and so on, with null padding (not null termination).
631 static void format_text_reorder_32(proto_tree* tree, tvbuff_t* tvb, packet_info *pinfo, int hfinfo, int baseoff, int blocklen)
633 wmem_strbuf_t *sid = wmem_strbuf_create(pinfo->pool);
634 for (int ii = 0; ii < blocklen; ii += 4)
637 // Yes, this is fetching the 32-bit word as big-endian
638 // rather than little-endian.
640 // However, it's then taking the low-order byte of the
641 // result as the first octet, followed by the byte above
642 // that, followed by the byte above that, followed by
643 // the high-order byte.
645 // This is equivalent t fetching the 32-bit word as little-endian
646 // and then taking the high-order byte of the result as the
647 // first octet, etc.
649 // And both of those implement what's described above.
651 // No, I have no idea why they chose this representation for
652 // strings.
654 const uint32_t u = tvb_get_ntohl(tvb, baseoff + ii);
655 wmem_strbuf_append_c(sid, 0xFF & (u >> 0));
656 wmem_strbuf_append_c(sid, 0xFF & (u >> 8));
657 wmem_strbuf_append_c(sid, 0xFF & (u >> 16));
658 wmem_strbuf_append_c(sid, 0xFF & (u >> 24));
660 if (!wmem_strbuf_utf8_validate(sid, NULL))
661 wmem_strbuf_utf8_make_valid(sid);
662 proto_tree_add_string(tree, hfinfo, tvb,
663 baseoff, blocklen, wmem_strbuf_get_str(sid));
667 /* Code to actually dissect the packets
670 static void
671 dissect_srt_control_packet(tvbuff_t *tvb, packet_info* pinfo,
672 proto_tree *tree, proto_item *srt_item)
674 uint32_t type = 0;
675 uint32_t exttype = 0;
677 proto_tree_add_item_ret_uint(tree, hf_srt_type, tvb, 0, 2,
678 ENC_BIG_ENDIAN, &type);
680 if ( type != UMSG_EXT )
681 proto_tree_add_item(tree, hf_srt_exttype_none, tvb, 2, 2,
682 ENC_BIG_ENDIAN);
683 else
684 proto_tree_add_item_ret_uint(tree, hf_srt_exttype, tvb, 2, 2,
685 ENC_BIG_ENDIAN, &exttype);
687 switch (type)
689 case UMSG_EXT:
690 col_add_fstr(pinfo->cinfo, COL_INFO, "Control/ext: %s socket: %d",
691 val_to_str(exttype, srt_ctrlmsg_exttypes,
692 "Unknown EXT Control Type (%d)"),
693 tvb_get_ntohl(tvb, 12));
694 break;
695 case UMSG_ACK:
696 col_add_fstr(pinfo->cinfo, COL_INFO, "Control: ACK %d seqno: %u socket: %d",
697 tvb_get_ntohl(tvb, 4),
698 tvb_get_ntohl(tvb, 16),
699 tvb_get_ntohl(tvb, 12));
700 break;
701 case UMSG_ACKACK:
702 col_add_fstr(pinfo->cinfo, COL_INFO, "Control: ACKACK %d socket: %d",
703 tvb_get_ntohl(tvb, 4),
704 tvb_get_ntohl(tvb, 12));
705 break;
706 default:
707 col_add_fstr(pinfo->cinfo, COL_INFO, "Control: %s socket: %d",
708 val_to_str(type, srt_ctrlmsg_types,
709 "Unknown Control Type (%d)"),
710 tvb_get_ntohl(tvb, 12));
711 break;
714 switch (type)
716 case UMSG_ACK:
717 case UMSG_ACKACK:
718 proto_tree_add_item(tree, hf_srt_ackno, tvb, 4, 4,
719 ENC_BIG_ENDIAN);
720 break;
721 case UMSG_DROPREQ:
722 proto_tree_add_item(tree, hf_srt_msgno, tvb, 4, 4,
723 ENC_BIG_ENDIAN);
724 break;
725 default:
726 proto_tree_add_item(tree, hf_srt_addinfo, tvb, 4, 4,
727 ENC_BIG_ENDIAN);
728 break;
730 proto_tree_add_item(tree, hf_srt_timestamp, tvb, 8, 4,
731 ENC_BIG_ENDIAN);
732 proto_tree_add_item(tree, hf_srt_id, tvb, 12, 4,
733 ENC_BIG_ENDIAN);
735 switch (type)
737 case UMSG_HANDSHAKE:
739 char ipbuf[IP_BUFFER_SIZE];
741 const int version = tvb_get_ntohl(tvb, 16);
742 const int final_length = tvb_reported_length(tvb);
743 int baselen = 64;
744 int handshake_reqtype;
746 /* This contains the handshake version (currently 4 or 5) */
747 proto_tree_add_item(tree, hf_srt_handshake_version, tvb,
748 16, 4, ENC_BIG_ENDIAN);
750 /* Version 4 embraces both HSv4 listener URQ_INDUCTION response
751 * and HSv5 caller URQ_INDUCTION request. In both these cases the
752 * value is interpreted as socket type (UDT legacy). With version 5
753 * the first message is the listener's URQ_INDUCTION response, where
754 * the layout in the type is already the MAGIC in the lower block,
755 * and ENC FLAGS in the upper block. The next caller's URQ_CONCLUSION
756 * will have SRT HS Extension block flags in the lower block.
758 if (version == 4)
760 proto_tree_add_item(tree, hf_srt_handshake_type_v4, tvb,
761 20, 4, ENC_BIG_ENDIAN);
763 else
765 /* Both the PBKEYLEN-ad and magic are used in HSv5 induction. */
766 proto_tree_add_item(tree, hf_srt_handshake_enc_field_v5, tvb,
767 20, 2, ENC_BIG_ENDIAN);
769 dissect_srt_hs_ext_field(tree, tvb, 22); /* 2 bytes */
772 proto_tree_add_item(tree, hf_srt_handshake_isn, tvb,
773 24, 4, ENC_BIG_ENDIAN);
774 proto_tree_add_item(tree, hf_srt_handshake_mtu, tvb,
775 28, 4, ENC_BIG_ENDIAN);
776 proto_tree_add_item(tree, hf_srt_handshake_flow_window, tvb,
777 32, 4, ENC_BIG_ENDIAN);
778 handshake_reqtype = tvb_get_ntohl(tvb, 36);
779 if (handshake_reqtype < URQ_FAILURE_TYPES)
781 proto_tree_add_item(tree, hf_srt_handshake_reqtype, tvb,
782 36, 4, ENC_BIG_ENDIAN);
784 else
786 static const range_string rej_codes_rvals[] = {
787 { 0, 0, "REJ_UNKNOWN" },
788 { 1, 1, "REJ_SYSTEM" },
789 { 2, 2, "REJ_PEER" },
790 { 3, 3, "REJ_RESOURCE" },
791 { 4, 4, "REJ_ROGUE" },
792 { 5, 5, "REJ_BACKLOG" },
793 { 6, 6, "REJ_IPE" },
794 { 7, 7, "REJ_CLOSE" },
795 { 8, 8, "REJ_VERSION" },
796 { 9, 9, "REJ_RDVCOOKIE" },
797 { 10, 10, "REJ_BADSECRET" },
798 { 11, 11, "REJ_UNSECURE" },
799 { 12, 12, "REJ_MESSAGEAPI" },
800 { 13, 13, "REJ_CONGESTION" },
801 { 14, 14, "REJ_FILTER" },
802 { 15, 15, "REJ_GROUP" },
803 { 16, 16, "REJ_TIMEOUT" },
804 { 17, 17, "REJ_CRYPTO" },
805 { 18, 999, "SRT Internal Rejection Reason"},
806 { 1000, 1999, "SRT Predefined Rejection Reason"},
807 { 2000, INT32_MAX, "User Defined Rejection Reason"},
809 { 0x00, 0x00, NULL },
812 const int error_code = handshake_reqtype - URQ_FAILURE_TYPES;
813 proto_tree_add_uint_format_value(tree, hf_srt_handshake_failure_type, tvb, 36, 4, handshake_reqtype,
814 "%d (%s)", error_code, rval_to_str_const(error_code, rej_codes_rvals, "Unknown"));
817 proto_tree_add_item(tree, hf_srt_handshake_id, tvb,
818 40, 4, ENC_BIG_ENDIAN);
819 proto_tree_add_item(tree, hf_srt_handshake_cookie, tvb,
820 44, 4, ENC_BIG_ENDIAN);
822 srt_format_ip_address(ipbuf, sizeof ipbuf, (const char *)tvb_memdup(pinfo->pool, tvb, 48, 16));
824 proto_tree_add_string(tree, hf_srt_handshake_peerip, tvb,
825 48, 16, ipbuf);
826 if (final_length > baselen)
828 /* Extract SRT handshake extension blocks
829 * and increase baselen accordingly.
831 int begin = baselen;
832 for (;;)
834 const uint16_t blockid = tvb_get_ntohs(tvb, begin);
835 const uint16_t blocklen = tvb_get_ntohs(tvb, begin + 2);
837 proto_tree_add_item(tree, hf_srt_srths_blocktype, tvb,
838 begin, 2, ENC_BIG_ENDIAN);
839 proto_tree_add_item(tree, hf_srt_srths_blocklen, tvb,
840 begin+2, 2, ENC_BIG_ENDIAN);
842 // Shift to the payload
843 begin += 4;
845 switch (blockid)
847 case SRT_CMD_HSREQ:
848 case SRT_CMD_HSRSP:
849 if (blocklen == 3)
851 srt_format_hs_ext_hsreq(tree, tvb, begin);
853 else
855 /* blocklen should be 3, that corresponds to (3 * 4) = 12 bytes.
856 * Otherwise the format is unknown.*/
857 proto_tree_add_expert_format(tree, pinfo, &ei_srt_hs_ext_hsreq_len,
858 tvb, begin, 4 * blocklen, "Actual length is %u",
859 blocklen);
861 break;
863 case SRT_CMD_KMREQ:
864 case SRT_CMD_KMRSP:
865 // Rely on the extracted blocklen
866 srt_format_kmx(tree, tvb, begin, blocklen*4);
867 break;
869 case SRT_CMD_SID:
870 format_text_reorder_32(tree, tvb, pinfo, hf_srt_srths_sid, begin, 4 * blocklen);
871 break;
873 case SRT_CMD_CONGESTION:
874 format_text_reorder_32(tree, tvb, pinfo, hf_srt_srths_congestcontrol, begin, 4 * blocklen);
875 break;
877 case SRT_CMD_FILTER:
878 format_text_reorder_32(tree, tvb, pinfo, hf_srt_hs_ext_filter, begin, 4 * blocklen);
879 break;
881 case SRT_CMD_GROUP:
882 srt_format_hs_ext_group(tree, tvb, pinfo, begin, blocklen * 4);
883 break;
885 default:
886 proto_tree_add_expert_format(tree, pinfo, &ei_srt_hs_ext_type,
887 tvb, begin, 4 * blocklen, "Ext Type value is %u",
888 blockid);
889 break;
892 /* Move the index pointer past the block and repeat. */
893 begin += blocklen * 4;
895 /* OK, once one block is done, interrupt the loop. */
896 if (begin >= final_length)
897 break;
900 baselen = begin;
903 proto_item_set_len(srt_item, baselen);
905 break;
906 case UMSG_ACK:
908 unsigned len = tvb_reported_length(tvb);
910 proto_tree_add_item(tree, hf_srt_ack_seqno, tvb, 4 * 4, 4,
911 ENC_BIG_ENDIAN);
913 // Check for "Lite ACK" (size 4)
914 if (len <= (4 + 1) * 4)
916 proto_item_set_len(srt_item, (4 + 1) * 4);
918 else
920 proto_tree_add_item(tree, hf_srt_rtt, tvb, (4+1)*4, 4,
921 ENC_BIG_ENDIAN);
922 proto_tree_add_item(tree, hf_srt_rttvar, tvb, (4+2)*4, 4,
923 ENC_BIG_ENDIAN);
924 proto_tree_add_item(tree, hf_srt_bufavail, tvb, (4+3)*4, 4,
925 ENC_BIG_ENDIAN);
926 /* if not a light ack, decode the rate and link capacity */
928 if (len > (4 + 4) * 4)
930 proto_tree_add_item(tree, hf_srt_rate, tvb, (4 + 4) * 4, 4, ENC_BIG_ENDIAN);
931 proto_tree_add_item(tree, hf_srt_bandwidth, tvb, (4 + 5) * 4, 4, ENC_BIG_ENDIAN);
933 // SRT Extra data. This can be version dependent, so
934 // test the length for each field.
935 if (len > (4 + 6) * 4)
937 proto_tree_add_item(tree, hf_srt_rcvrate, tvb, (4 + 6) * 4, 4, ENC_BIG_ENDIAN);
938 len = (4 + 7) * 4;
941 proto_item_set_len(srt_item, (int) len);
943 else
945 proto_item_set_len(srt_item, (4 + 4) * 4);
949 break;
950 case UMSG_DROPREQ:
952 unsigned len = tvb_reported_length(tvb);
953 if (len > (4 + 0) * 4)
955 unsigned lo = tvb_get_ntohl(tvb, (4 + 0) * 4);
956 unsigned hi = tvb_get_ntohl(tvb, (4 + 1) * 4);
958 proto_tree_add_expert_format(tree, pinfo, &ei_srt_nak_seqno,
959 tvb, 16, 8, "Drop sequence range: %u-%u",
960 lo, hi);
961 proto_item_set_len(srt_item, (int) len);
964 break;
965 case UMSG_LOSSREPORT:
967 unsigned len = tvb_reported_length(tvb);
968 unsigned pos;
969 uint32_t val;
970 unsigned prev = 0;
971 for (pos = 16; pos < len; pos += 4)
973 val = tvb_get_ntohl(tvb, pos);
974 if (val & SRT_LOSS_SEQUENCE_FIRST) {
975 // Remember this as a beginning range
976 prev = val;
977 continue;
980 // We have either a single value, or end-range here.
981 if (prev & SRT_LOSS_SEQUENCE_FIRST) {
982 // Was a range. Display as range and clear the state.
983 proto_tree_add_expert_format(tree, pinfo, &ei_srt_nak_seqno,
984 tvb, pos-4, 8, "Loss sequence range: %u-%u",
985 (prev & SRT_LOSS_SEQUENCE_MASK), val);
986 prev = 0;
987 } else {
988 // No from, so this is a freestanding loss value
989 proto_tree_add_expert_format(tree, pinfo, &ei_srt_nak_seqno,
990 tvb, pos, 4, "Loss sequence: %u", val);
994 // Report possible errors
995 if (prev)
997 proto_tree_add_expert_format(tree, pinfo, &ei_srt_nak_seqno,
998 tvb, pos-4, 4, "ERROR: loss sequence range begin only: %u (%x)",
999 val & SRT_LOSS_SEQUENCE_MASK, val);
1002 proto_item_set_len(srt_item, len);
1004 break;
1006 case UMSG_EXT:
1007 switch (exttype)
1009 case SRT_CMD_HSREQ:
1010 case SRT_CMD_HSRSP:
1011 srt_format_hs_ext_hsreq(tree, tvb, 16);
1012 break;
1014 case SRT_CMD_KMREQ:
1015 case SRT_CMD_KMRSP:
1017 // This relies on value of HCRYPT_MSG_KM_MAX_SZ resulting from this above.
1018 // Too strongly dependent on devel API, so using explicit 104.
1019 int plen = tvb_reported_length(tvb) - 16;
1020 if (plen > 104)
1021 plen = 104;
1022 srt_format_kmx(tree, tvb, 16, plen);
1024 break;
1026 default:
1027 break;
1029 break;
1031 default:
1032 // All other types have kinda "extra padding"
1033 proto_tree_add_item(tree, hf_srt_addinfo, tvb, 16, 4, ENC_BIG_ENDIAN);
1034 break;
1039 /* Code to actually dissect the packets
1041 * @return the amount of data this dissector was able to dissect
1043 static int
1044 dissect_srt_udp(tvbuff_t *tvb, packet_info* pinfo, proto_tree *parent_tree,
1045 void *data _U_)
1047 /* Other misc. local variables. */
1048 bool is_control = 0;
1050 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SRT");
1051 col_clear (pinfo->cinfo, COL_INFO);
1053 proto_item *srt_item = proto_tree_add_item(parent_tree, proto_srt, tvb,
1054 0 /*start*/, -1 /*length*/, ENC_NA);
1055 proto_tree *tree = proto_item_add_subtree(srt_item, ett_srt);
1056 proto_tree_add_item_ret_boolean(tree, hf_srt_iscontrol, tvb, 0, 4, ENC_BIG_ENDIAN, &is_control);
1058 if (is_control)
1060 dissect_srt_control_packet(tvb, pinfo, tree, srt_item);
1062 else
1064 /* otherwise, a data packet */
1065 tvbuff_t *next_tvb;
1067 col_add_fstr(pinfo->cinfo, COL_INFO,
1068 "DATA: seqno: %u msgno: #%u socket: %d %s",
1069 tvb_get_ntohl(tvb, 0),
1070 tvb_get_ntohl(tvb, 4) & SRT_MSGNO_MSGNO_MASK,
1071 tvb_get_ntohl(tvb, 12),
1072 tvb_get_ntohl(tvb, 4) & SRT_MSGNO_REXMIT_FLG ? "R" : "");
1074 if (tree)
1076 // Sequence number
1077 proto_tree_add_item(tree, hf_srt_seqno, tvb, 0, 4, ENC_BIG_ENDIAN);
1079 proto_tree_add_item(tree, hf_srt_msgno_pb, tvb, 4, 4, ENC_BIG_ENDIAN);
1080 proto_tree_add_item(tree, hf_srt_msgno_inorder, tvb, 4, 4, ENC_BIG_ENDIAN);
1081 proto_tree_add_item(tree, hf_srt_msgno_enctypes, tvb, 4, 4, ENC_BIG_ENDIAN);
1082 proto_tree_add_item(tree, hf_srt_msgno_rexmit, tvb, 4, 4, ENC_BIG_ENDIAN);
1083 proto_tree_add_item(tree, hf_srt_msgno, tvb, 4, 4, ENC_BIG_ENDIAN);
1085 proto_tree_add_item(tree, hf_srt_timestamp, tvb, 8, 4, ENC_BIG_ENDIAN);
1086 proto_tree_add_item(tree, hf_srt_id, tvb, 12, 4, ENC_BIG_ENDIAN);
1090 next_tvb = tvb_new_subset_remaining(tvb, 16);
1091 call_data_dissector(next_tvb, pinfo, tree);
1094 return tvb_reported_length(tvb);
1098 static bool
1099 dissect_srt_heur_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1101 conversation_t *conv;
1103 /* Must have at least 24 captured bytes for heuristic check */
1104 if (tvb_captured_length(tvb) < 24)
1105 return false;
1107 /* detect handshake control packet */
1108 if (tvb_get_ntohl(tvb, 0) != (0x80000000 | UMSG_HANDSHAKE))
1109 return false;
1111 /* must be version 4 or 5*/
1112 const uint32_t version = tvb_get_ntohl(tvb, 16);
1113 if (version != 4 && version != 5)
1114 return false;
1116 /* SRT: must be DGRAM. STREAM is not supported in SRT */
1117 if (version == 4 && tvb_get_ntohl(tvb, 20) != SRT_DGRAM)
1118 return false;
1120 conv = find_or_create_conversation(pinfo);
1121 conversation_set_dissector(conv, srt_udp_handle);
1122 dissect_srt_udp(tvb, pinfo, tree, data);
1124 return true;
1128 /* Register the protocol with Wireshark.
1130 * This format is required because a script is used to build the C function that
1131 * calls all the protocol registration.
1133 void proto_register_srt(void)
1135 expert_module_t *expert_srt;
1137 /* Setup list of header fields See Section 1.5 of README.dissector for
1138 * details. */
1139 static hf_register_info hf[] = {
1140 {&hf_srt_iscontrol, {
1141 "Content", "srt.iscontrol",
1142 FT_BOOLEAN, 32,
1143 TFS(&srt_packet_types), 0x80000000, NULL, HFILL }},
1145 {&hf_srt_type, {
1146 "Msg Type", "srt.type",
1147 FT_UINT16, BASE_HEX,
1148 VALS(srt_ctrlmsg_types), 0x7fff, NULL, HFILL}},
1150 {&hf_srt_exttype, {
1151 "Extended type", "srt.exttype",
1152 FT_UINT16, BASE_HEX,
1153 VALS(srt_ctrlmsg_exttypes), 0, NULL, HFILL}},
1155 {&hf_srt_exttype_none, {
1156 "(no extended type)", "srt.exttype_none",
1157 FT_UINT16, BASE_HEX,
1158 NULL, 0, NULL, HFILL}},
1160 {&hf_srt_seqno, {
1161 "Sequence Number", "srt.seqno",
1162 FT_UINT32, BASE_DEC,
1163 NULL, SRT_CONTROL_MASK, NULL, HFILL}},
1165 {&hf_srt_addinfo, {
1166 "(Unused)", "srt.addinfo",
1167 FT_UINT32, BASE_DEC,
1168 NULL, 0, NULL, HFILL}},
1170 {&hf_srt_msgno, {
1171 "Message Number", "srt.msgno",
1172 FT_UINT32, BASE_DEC,
1173 NULL, SRT_MSGNO_MSGNO_MASK, NULL, HFILL}},
1175 {&hf_srt_msgno_pb, {
1176 "Packet Boundary", "srt.pb",
1177 FT_UINT32, BASE_DEC,
1178 VALS(srt_pb_types), SRT_MSGNO_FF_MASK, NULL, HFILL}},
1180 {&hf_srt_msgno_inorder, {
1181 "In-Order Indicator", "srt.msg.order",
1182 FT_UINT32, BASE_DEC,
1183 NULL, SRT_MSGNO_INORDER, NULL, HFILL}},
1185 {&hf_srt_msgno_enctypes, {
1186 "Encryption Status", "srt.msg.enc",
1187 FT_UINT32, BASE_DEC,
1188 VALS(srt_msgno_enctypes), SRT_MSGNO_ENCTYPE, NULL, HFILL }},
1190 {&hf_srt_msgno_rexmit, {
1191 "Sent as", "srt.msg.rexmit",
1192 FT_BOOLEAN, 32,
1193 TFS(&srt_msgno_rexmit), SRT_MSGNO_REXMIT, NULL, HFILL }},
1195 {&hf_srt_timestamp, {
1196 "Time Stamp", "srt.timestamp",
1197 FT_UINT32, BASE_DEC_HEX,
1198 NULL, 0, NULL, HFILL}},
1200 {&hf_srt_id, {
1201 "Destination Socket ID", "srt.id",
1202 FT_UINT32, BASE_DEC,
1203 NULL, 0, NULL, HFILL}},
1205 {&hf_srt_ack_seqno, {
1206 "ACKD_RCVLASTACK", "srt.ack_seqno",
1207 FT_UINT32, BASE_DEC,
1208 NULL, 0, NULL, HFILL}},
1210 {&hf_srt_ackno, {
1211 "Ack Number", "srt.ackno",
1212 FT_UINT32, BASE_DEC,
1213 NULL, 0, NULL, HFILL}},
1215 {&hf_srt_rtt, {
1216 "ACKD_RTT", "srt.rtt",
1217 FT_UINT32, BASE_DEC | BASE_UNIT_STRING,
1218 UNS(&units_microseconds), 0, NULL, HFILL}},
1220 {&hf_srt_rttvar, {
1221 "ACKD_RTTVAR", "srt.rttvar",
1222 FT_UINT32, BASE_DEC | BASE_UNIT_STRING,
1223 UNS(&units_microseconds), 0, NULL, HFILL}},
1225 {&hf_srt_bufavail, {
1226 "ACKD_BUFFERLEFT", "srt.bufavail",
1227 FT_UINT32, BASE_DEC | BASE_UNIT_STRING,
1228 UNS(&units_pkts), 0, NULL, HFILL}},
1230 {&hf_srt_rate, {
1231 "ACKD_RCVSPEED", "srt.rate",
1232 FT_UINT32, BASE_DEC | BASE_UNIT_STRING,
1233 UNS(&units_pkts_per_sec), 0, NULL, HFILL}},
1235 {&hf_srt_bandwidth, {
1236 "ACKD_BANDWIDTH", "srt.bw",
1237 FT_UINT32, BASE_DEC | BASE_UNIT_STRING,
1238 UNS(&units_pkts_per_sec), 0, NULL, HFILL}},
1240 {&hf_srt_rcvrate, {
1241 "ACKD_RCVRATE", "srt.rcvrate",
1242 FT_UINT32, BASE_DEC | BASE_UNIT_STRING,
1243 UNS(&units_byte_bytespsecond), 0, NULL, HFILL}},
1245 {&hf_srt_handshake_version, {
1246 "Handshake Version", "srt.hs.version",
1247 FT_UINT32, BASE_DEC,
1248 NULL, 0, NULL, HFILL}},
1250 {&hf_srt_handshake_type_v4, {
1251 "(Legacy) Socket type", "srt.hs.socktype",
1252 FT_UINT32, BASE_DEC,
1253 VALS(srt_hsv4_socket_types), 0, NULL,
1254 HFILL}},
1256 {&hf_srt_handshake_enc_field_v5, {
1257 "Crypto Key Field", "srt.hs.enckeyfield",
1258 FT_UINT16, BASE_HEX,
1259 VALS(srt_handshake_enc_field), 0, NULL,
1260 HFILL}},
1262 {&hf_srt_handshake_ext_field_v5, {
1263 "Extended Field", "srt.hs.extfield",
1264 FT_UINT16, BASE_HEX,
1265 NULL, 0, NULL,
1266 HFILL}},
1268 {&hf_srt_handshake_ext_field_v5_flag_hsreq, {
1269 "HS_EXT_FIELD_HSREQ", "srt.hs.extfield.hsreq",
1270 FT_BOOLEAN, SRT_HS_V5_EXT_FIELD_LEN, TFS(&tfs_set_notset),
1271 SRT_HS_V5_EXT_FIELD_HSREQ,
1272 "Handshake request",
1273 HFILL}},
1275 {&hf_srt_handshake_ext_field_v5_flag_kmreq, {
1276 "HS_EXT_FIELD_KMREQ", "srt.hs.extfield.kmreq",
1277 FT_BOOLEAN, SRT_HS_V5_EXT_FIELD_LEN, TFS(&tfs_set_notset),
1278 SRT_HS_V5_EXT_FIELD_KMREQ,
1279 "KM request",
1280 HFILL}},
1282 {&hf_srt_handshake_ext_field_v5_flag_config, {
1283 "HS_EXT_FIELD_CONFIG", "srt.hs.extfield.config",
1284 FT_BOOLEAN, SRT_HS_V5_EXT_FIELD_LEN, TFS(&tfs_set_notset),
1285 SRT_HS_V5_EXT_FIELD_CONFIG,
1286 "Handshake has configuration",
1287 HFILL}},
1289 {&hf_srt_handshake_isn, {
1290 "Initial Sequence Number", "srt.hs.isn",
1291 FT_UINT32, BASE_DEC,
1292 NULL, 0, NULL, HFILL}},
1294 {&hf_srt_handshake_mtu, {
1295 "MTU", "srt.hs.mtu",
1296 FT_UINT32, BASE_DEC,
1297 NULL, 0, NULL, HFILL}},
1299 {&hf_srt_handshake_flow_window, {
1300 "Flow Window", "srt.hs.flow_window",
1301 FT_UINT32, BASE_DEC,
1302 NULL, 0, NULL, HFILL}},
1304 {&hf_srt_handshake_reqtype, {
1305 "Handshake Type", "srt.hs.reqtype",
1306 FT_INT32, BASE_DEC,
1307 VALS(srt_hs_request_types), 0, NULL, HFILL}},
1309 {&hf_srt_handshake_failure_type, {
1310 "Handshake FAILURE code", "srt.hs.failtype",
1311 FT_UINT32, BASE_DEC,
1312 NULL, 0, NULL, HFILL}},
1314 {&hf_srt_handshake_id, {
1315 "Socket ID", "srt.hs.id",
1316 FT_UINT32, BASE_DEC,
1317 NULL, 0, NULL, HFILL}},
1319 {&hf_srt_handshake_cookie, {
1320 "SYN Cookie", "srt.hs.cookie",
1321 FT_UINT32, BASE_HEX,
1322 NULL, 0, NULL, HFILL}},
1324 {&hf_srt_handshake_peerip, {
1325 /* FT_STRINGZ is used because the value
1326 * is formatted to a temporary buffer first */
1327 "Peer IP Address", "srt.hs.peerip",
1328 FT_STRINGZ, BASE_NONE,
1329 NULL, 0, NULL, HFILL}},
1331 {&hf_srt_handshake_ext_version, {
1332 "SRT Version", "srt.hs.version",
1333 FT_UINT32, BASE_HEX,
1334 NULL, 0, NULL, HFILL}},
1336 {&hf_srt_handshake_ext_flags, {
1337 /* This uses custom format by appending the flag format string,
1338 * while the value in hex is still printed. */
1339 "SRT Flags", "srt.hs.srtflags",
1340 FT_UINT32, BASE_HEX,
1341 NULL, 0, NULL, HFILL}},
1343 {&hf_srt_handshake_ext_flag_tsbpd_snd, {
1344 "TSBPDSND", "srt.hs.srtflags.tsbpd_snd",
1345 FT_BOOLEAN, SRT_OPT_FIELD_LEN, TFS(&tfs_set_notset),
1346 SRT_OPT_TSBPDSND,
1347 "The party will be sending in TSBPD (Time Stamp Based Packet Delivery) mode",
1348 HFILL}},
1350 {&hf_srt_handshake_ext_flag_tsbpd_rcv, {
1351 "TSBPDRCV", "srt.hs.srtflags.tsbpd_rcv",
1352 FT_BOOLEAN, SRT_OPT_FIELD_LEN, TFS(&tfs_set_notset),
1353 SRT_OPT_TSBPDRCV,
1354 "The party expects to receive in TSBPD (Time Stamp Based Packet Delivery) mode",
1355 HFILL}},
1357 {&hf_srt_handshake_ext_flag_haicrypt, {
1358 "HAICRYPT", "srt.hs.srtflags.haicrypt",
1359 FT_BOOLEAN, SRT_OPT_FIELD_LEN, TFS(&tfs_set_notset),
1360 SRT_OPT_HAICRYPT,
1361 "The party includes haicrypt (legacy flag)",
1362 HFILL}},
1364 {&hf_srt_handshake_ext_flag_tlpkt_drop, {
1365 "TLPKTDROP", "srt.hs.srtflags.tlpkt_drop",
1366 FT_BOOLEAN, SRT_OPT_FIELD_LEN, TFS(&tfs_set_notset),
1367 SRT_OPT_TLPKTDROP,
1368 "The party will do the Too-Late Packet Drop",
1369 HFILL}},
1371 {&hf_srt_handshake_ext_flag_nak_report, {
1372 "NAKREPORT", "srt.hs.srtflags.nak_report",
1373 FT_BOOLEAN, SRT_OPT_FIELD_LEN, TFS(&tfs_set_notset),
1374 SRT_OPT_NAKREPORT,
1375 "The party will do periodic NAK reporting",
1376 HFILL}},
1378 {&hf_srt_handshake_ext_flag_rexmit, {
1379 "REXMITFLG", "srt.hs.srtflags.rexmit",
1380 FT_BOOLEAN, SRT_OPT_FIELD_LEN, TFS(&tfs_set_notset),
1381 SRT_OPT_REXMITFLG,
1382 "The party uses the REXMIT flag",
1383 HFILL}},
1385 {&hf_srt_handshake_ext_flag_stream, {
1386 "STREAM", "srt.hs.srtflags.stream",
1387 FT_BOOLEAN, SRT_OPT_FIELD_LEN, TFS(&tfs_set_notset),
1388 SRT_OPT_STREAM,
1389 "The party uses stream type transmission",
1390 HFILL}},
1392 {&hf_srt_srths_blocktype, {
1393 "SRT HS Extension type", "srt.hs.blocktype",
1394 FT_UINT16, BASE_HEX,
1395 VALS(srt_ctrlmsg_exttypes), 0, NULL, HFILL}},
1397 {&hf_srt_srths_blocklen, {
1398 "SRT HS Extension size (4-byte blocks)", "srt.hs.blocklen",
1399 FT_UINT16, BASE_DEC,
1400 NULL, 0, NULL, HFILL}},
1402 {&hf_srt_srths_agent_latency, {
1403 "Latency", "srt.hs.agent_latency",
1404 FT_UINT16, BASE_DEC | BASE_UNIT_STRING,
1405 UNS(&units_milliseconds), 0, NULL, HFILL}},
1407 {&hf_srt_srths_peer_latency, {
1408 "Peer Latency", "srt.hs.peer_latency",
1409 FT_UINT16, BASE_DEC | BASE_UNIT_STRING,
1410 UNS(&units_milliseconds), 0, NULL, HFILL}},
1412 {&hf_srt_srtkm_msg, {
1413 "KMX Message (or KM State if 4 bytes)", "srt.km.msg",
1414 FT_BYTES, BASE_NONE,
1415 NULL, 0, NULL, HFILL}},
1417 {&hf_srt_srtkm_error, {
1418 "KM State", "srt.km.error",
1419 FT_UINT32, BASE_DEC,
1420 VALS(srt_enc_kmstate), 0, NULL, HFILL}},
1422 {&hf_srt_srths_sid, {
1423 "Stream ID", "srt.hs.sid",
1424 FT_STRING, BASE_NONE,
1425 NULL, 0, NULL, HFILL}},
1427 {&hf_srt_srths_congestcontrol, {
1428 "Congestion Control Type", "srt.hs.congestctrl",
1429 FT_STRING, BASE_NONE,
1430 NULL, 0, NULL, HFILL}},
1432 {&hf_srt_hs_ext_filter, {
1433 "Packet Filter Type", "srt.hs.filter",
1434 FT_STRING, BASE_NONE,
1435 NULL, 0, NULL, HFILL}},
1437 {&hf_srt_km, {
1438 "Key Material", "srt.km",
1439 FT_BYTES, BASE_NONE,
1440 NULL, 0, NULL, HFILL}},
1442 {&hf_srt_km_s, {
1443 "Reserved 'S' Bit", "srt.km.s",
1444 FT_UINT8, BASE_DEC, NULL,
1445 SRT_KM_S_MASK, NULL, HFILL}},
1447 {&hf_srt_km_v, {
1448 "KM Version", "srt.km.v",
1449 FT_UINT8, BASE_DEC,
1450 NULL, SRT_KM_V_MASK, NULL,
1451 HFILL} },
1453 {&hf_srt_km_pt, {
1454 "KM Payload Type", "srt.km.pt",
1455 FT_UINT8, BASE_DEC,
1456 NULL, SRT_KM_PT_MASK, NULL,
1457 HFILL} },
1459 {&hf_srt_km_sign, {
1460 "KM Signature", "srt.km.sign",
1461 FT_BYTES, BASE_NONE,
1462 NULL, 0, NULL,
1463 HFILL} },
1465 {&hf_srt_km_resv1, {
1466 "Reserved1", "srt.km.resv1",
1467 FT_UINT8, BASE_DEC,
1468 NULL, SRT_KM_RESV1_MASK, NULL,
1469 HFILL} },
1471 {&hf_srt_km_kk, {
1472 "Encryption Keys", "srt.km.kk",
1473 FT_UINT8, BASE_DEC,
1474 NULL, SRT_KM_KK_MASK, NULL,
1475 HFILL} },
1477 {&hf_srt_km_keki, {
1478 "KEK index", "srt.km.keki",
1479 FT_UINT32, BASE_DEC,
1480 NULL, 0, NULL,
1481 HFILL} },
1483 {&hf_srt_km_cipher, {
1484 "Cipher", "srt.km.cipher",
1485 FT_UINT8, BASE_DEC,
1486 NULL, 0, NULL,
1487 HFILL} },
1489 {&hf_srt_km_auth, {
1490 "Auth", "srt.km.auth",
1491 FT_UINT8, BASE_DEC,
1492 NULL, 0, NULL,
1493 HFILL} },
1495 {&hf_srt_km_se, {
1496 "Stream Encapsulation", "srt.km.se",
1497 FT_UINT8, BASE_DEC,
1498 NULL, 0, NULL,
1499 HFILL} },
1501 {&hf_srt_km_resv2, {
1502 "Reserved2", "srt.km.resv2",
1503 FT_UINT8, BASE_DEC,
1504 NULL, 0, NULL,
1505 HFILL} },
1507 { &hf_srt_km_resv3, {
1508 "Reserved3", "srt.km.resv3",
1509 FT_UINT16, BASE_DEC,
1510 NULL, 0, NULL,
1511 HFILL} },
1513 {&hf_srt_km_slen, {
1514 "Salt Length (4-byte blocks)", "srt.km.slen",
1515 FT_UINT8, BASE_DEC,
1516 NULL, 0, NULL,
1517 HFILL} },
1519 {&hf_srt_km_klen, {
1520 "SEK Length (4-byte blocks)", "srt.km.klen",
1521 FT_UINT8, BASE_DEC,
1522 NULL, 0, NULL,
1523 HFILL} },
1525 {&hf_srt_km_salt, {
1526 "Salt", "srt.km.salt",
1527 FT_BYTES, BASE_NONE,
1528 NULL, 0, NULL, HFILL}},
1530 {&hf_srt_km_wrap, {
1531 "Key wrap", "srt.km.wrap",
1532 FT_BYTES, BASE_NONE,
1533 NULL, 0, NULL, HFILL}},
1535 {&hf_srt_hs_ext_group_id, {
1536 "Group ID", "srt.hs_ext_group.id",
1537 FT_UINT32, BASE_DEC,
1538 NULL, 0, NULL, HFILL}},
1540 { &hf_srt_hs_ext_group_type, {
1541 "Group Type", "srt.hs_ext_group.type",
1542 FT_UINT8, BASE_DEC,
1543 VALS(srt_hs_ext_group_type), 0, NULL, HFILL}},
1545 { &hf_srt_hs_ext_group_flags, {
1546 "Group Flags", "srt.hs_ext_group.flags",
1547 FT_UINT8, BASE_DEC,
1548 NULL, 0, NULL, HFILL}},
1550 { &hf_srt_hs_ext_group_weight, {
1551 "Member Weight", "srt.hs_ext_group.member_weight",
1552 FT_UINT16, BASE_DEC,
1553 NULL, 0, NULL, HFILL}}
1557 static int *ett[] = {
1558 &ett_srt,
1559 &ett_srt_handshake_ext_flags,
1560 &ett_srt_handshake_ext_field_flags
1563 static ei_register_info ei[] = {
1564 { &ei_srt_nak_seqno,
1565 { "srt.nak_seqno", PI_SEQUENCE, PI_NOTE,
1566 "Missing Sequence Number(s)", EXPFILL }},
1568 { &ei_srt_hs_ext_hsreq_len,
1569 { "srt.hs.ext.hsreq", PI_PROTOCOL, PI_WARN,
1570 "Unknown HS Ext HSREQ length", EXPFILL }},
1572 { &ei_srt_hs_ext_type,
1573 { "srt.hs.ext.type", PI_PROTOCOL, PI_WARN,
1574 "Unknown HS Ext Type", EXPFILL }},
1576 { &ei_srt_hs_ext_group_len,
1577 { "srt.hs.ext.group", PI_PROTOCOL, PI_WARN,
1578 "Wrong HS Ext Group length", EXPFILL }},
1581 proto_srt = proto_register_protocol("SRT Protocol", "SRT", "srt");
1582 proto_register_field_array(proto_srt, hf, array_length(hf));
1583 proto_register_subtree_array(ett, array_length(ett));
1585 expert_srt = expert_register_protocol(proto_srt);
1586 expert_register_field_array(expert_srt, ei, array_length(ei));
1588 srt_udp_handle = register_dissector("srt", dissect_srt_udp, proto_srt);
1592 void proto_reg_handoff_srt(void)
1594 /* register as heuristic dissector for UDP */
1595 heur_dissector_add("udp", dissect_srt_heur_udp, "SRT over UDP",
1596 "srt_udp", proto_srt, HEURISTIC_ENABLE);
1598 /* Add a handle to the list of handles that *could* be used with this
1599 table. That list is used by the "Decode As"/"-d" code in the UI. */
1600 dissector_add_for_decode_as("udp.port", srt_udp_handle);
1605 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1607 * Local variables:
1608 * c-basic-offset: 4
1609 * tab-width: 8
1610 * indent-tabs-mode: nil
1611 * End:
1613 * vi: set shiftwidth=4 tabstop=8 expandtab:
1614 * :indentSize=4:tabSize=8:noTabs=true: