Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-srt.c
blob54733ad891651d1c4a45739228400a8ef99187f7
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>
35 #include <wsutil/str_util.h>
37 /* Prototypes */
38 void proto_reg_handoff_srt(void);
39 void proto_register_srt(void);
41 /* Initialize the protocol */
42 static int proto_srt;
43 static int hf_srt_iscontrol;
44 static int hf_srt_type;
45 static int hf_srt_exttype;
46 static int hf_srt_exttype_none;
47 static int hf_srt_seqno;
48 static int hf_srt_ack_seqno;
49 static int hf_srt_ackno;
50 static int hf_srt_msgno;
51 static int hf_srt_msgno_pb;
52 static int hf_srt_msgno_inorder;
53 static int hf_srt_msgno_enctypes;
54 static int hf_srt_msgno_rexmit;
55 static int hf_srt_timestamp;
56 static int hf_srt_id;
57 static int hf_srt_addinfo;
58 static int hf_srt_rtt;
59 static int hf_srt_rttvar;
60 static int hf_srt_bufavail;
61 static int hf_srt_rate;
62 static int hf_srt_bandwidth;
63 static int hf_srt_rcvrate;
65 /* SRT Handshake */
66 static int hf_srt_handshake_version;
67 static int hf_srt_handshake_type_v4;
68 static int hf_srt_handshake_enc_field_v5;
69 static int hf_srt_handshake_ext_field_v5;
70 static int hf_srt_handshake_ext_field_v5_flag_hsreq;
71 static int hf_srt_handshake_ext_field_v5_flag_kmreq;
72 static int hf_srt_handshake_ext_field_v5_flag_config;
73 static int hf_srt_handshake_isn;
74 static int hf_srt_handshake_mtu;
75 static int hf_srt_handshake_flow_window;
76 static int hf_srt_handshake_reqtype;
77 static int hf_srt_handshake_failure_type;
78 static int hf_srt_handshake_id;
79 static int hf_srt_handshake_cookie;
80 static int hf_srt_handshake_peerip;
81 /* SRT Handshake Extension */
82 static int hf_srt_handshake_ext_version;
83 static int hf_srt_handshake_ext_flags;
84 static int hf_srt_handshake_ext_flag_tsbpd_snd;
85 static int hf_srt_handshake_ext_flag_tsbpd_rcv;
86 static int hf_srt_handshake_ext_flag_haicrypt;
87 static int hf_srt_handshake_ext_flag_tlpkt_drop;
88 static int hf_srt_handshake_ext_flag_nak_report;
89 static int hf_srt_handshake_ext_flag_rexmit;
90 static int hf_srt_handshake_ext_flag_stream;
92 /* Key Material (KM) */
93 static int hf_srt_km;
94 static int hf_srt_km_s;
95 static int hf_srt_km_v;
96 static int hf_srt_km_pt;
97 static int hf_srt_km_sign;
98 static int hf_srt_km_resv1;
99 static int hf_srt_km_kk;
100 static int hf_srt_km_keki;
101 static int hf_srt_km_cipher;
102 static int hf_srt_km_auth;
103 static int hf_srt_km_se;
104 static int hf_srt_km_resv2;
105 static int hf_srt_km_resv3;
106 static int hf_srt_km_slen;
107 static int hf_srt_km_klen;
108 static int hf_srt_km_salt;
109 static int hf_srt_km_wrap;
111 /* HS Extension: Group */
112 static int hf_srt_hs_ext_group_id;
113 static int hf_srt_hs_ext_group_type;
114 static int hf_srt_hs_ext_group_flags;
115 static int hf_srt_hs_ext_group_weight;
117 static int hf_srt_srths_blocktype;
118 static int hf_srt_srths_blocklen;
119 static int hf_srt_srths_agent_latency; // TSBPD delay
120 static int hf_srt_srths_peer_latency; // TSBPD delay
121 static int hf_srt_srtkm_msg;
122 static int hf_srt_srtkm_error;
123 static int hf_srt_srths_sid;
124 static int hf_srt_srths_congestcontrol;
125 static int hf_srt_hs_ext_filter;
127 static int ett_srt;
128 static int ett_srt_handshake_ext_flags;
129 static int ett_srt_handshake_ext_field_flags;
131 static expert_field ei_srt_nak_seqno;
132 static expert_field ei_srt_hs_ext_hsreq_len;
133 static expert_field ei_srt_hs_ext_type;
134 static expert_field ei_srt_hs_ext_group_len;
136 static dissector_handle_t srt_udp_handle;
139 /* This defines the firstmost bit of the packet, so it can stay this way. */
140 #define SRT_TYPE_DATA 0
141 #define SRT_TYPE_CONTROL 1
142 #define SRT_CONTROL_MASK (~0x80000000)
144 #define SRT_KM_S_MASK 0x80
145 #define SRT_KM_V_MASK 0x70
146 #define SRT_KM_PT_MASK 0x0F
147 #define SRT_KM_KK_MASK 0x03
148 #define SRT_KM_RESV1_MASK 0xFC
150 #define SRT_LOSS_SEQUENCE_FIRST 0x80000000
151 #define SRT_LOSS_SEQUENCE_MASK (~SRT_LOSS_SEQUENCE_FIRST)
153 enum UDTSockType
155 SRT_UNDEFINED = 0, /* initial trap representation */
156 SRT_STREAM = 1,
157 SRT_DGRAM = 2,
158 SRT_MAGIC_CODE = 0x4A17
161 /* Handshake Extended Field Flags */
162 #define SRT_OPT_FIELD_LEN 32
163 #define SRT_OPT_TSBPDSND (1 << 0)
164 #define SRT_OPT_TSBPDRCV (1 << 1)
165 #define SRT_OPT_HAICRYPT (1 << 2)
166 #define SRT_OPT_TLPKTDROP (1 << 3)
167 #define SRT_OPT_NAKREPORT (1 << 4)
168 #define SRT_OPT_REXMITFLG (1 << 5)
169 #define SRT_OPT_STREAM (1 << 6)
172 /* Extended Handshake Flags */
173 #define SRT_HS_V5_EXT_FIELD_LEN 16
174 #define SRT_HS_V5_EXT_FIELD_HSREQ (1 << 0)
175 #define SRT_HS_V5_EXT_FIELD_KMREQ (1 << 1)
176 #define SRT_HS_V5_EXT_FIELD_CONFIG (1 << 2)
177 #define SRT_HS_V5_EXT_FIELD_MAGIC SRT_MAGIC_CODE
179 /* Message number field and single bit flags */
180 #define SRT_MSGNO_FF_FIRST_B (2 << (32-2))
181 #define SRT_MSGNO_FF_LAST_B (1 << (32-2))
182 #define SRT_MSGNO_FF_MASK (SRT_MSGNO_FF_FIRST_B | SRT_MSGNO_FF_LAST_B)
184 enum PacketBoundary
186 PB_SUBSEQUENT = 0,
187 /* 01: last packet of a message */
188 PB_LAST = 1,
189 /* 10: first packet of a message */
190 PB_FIRST = 2,
191 /* 11: solo message packet */
192 PB_SOLO = 3,
196 #define SRT_MSGNO_INORDER (1 << (32-3)) /* 0x20000000 */
198 #define SRT_MSGNO_ENCTYPE (3 << (32-5)) /* 0x18000000 */
200 #define SRT_MSGNO_EK_NONE 0
201 #define SRT_MSGNO_EK_EVEN 1
202 #define SRT_MSGNO_EK_ODD 2
204 #define SRT_MSGNO_REXMIT (1 << (32-6)) /* 0x04000000 */
206 /* Rest of the bits are for message sequence number */
207 #define SRT_MSGNO_MSGNO_MASK 0x03ffffff
208 #define SRT_MSGNO_REXMIT_FLG 0x04000000
211 /* The message types used by SRT protocol. This is a part of SRT
212 * protocol and should never be changed.
214 enum UDTMessageType
216 UMSG_HANDSHAKE = 0, // Connection Handshake. Control: see @a CHandShake.
217 UMSG_KEEPALIVE = 1, // Keep-alive.
218 UMSG_ACK = 2, // Acknowledgement. Control: past-the-end sequence number up to which packets have been received.
219 UMSG_LOSSREPORT = 3, // Negative Acknowledgement (NACK). Control: Loss list.
220 UMSG_CGWARNING = 4, // Congestion warning.
221 UMSG_SHUTDOWN = 5, // Shutdown.
222 UMSG_ACKACK = 6, // Acknowledgement of Acknowledgement. Add info: The ACK sequence number
223 UMSG_DROPREQ = 7, // Message Drop Request. Add info: Message ID. Control Info: (first, last) number of the message.
224 UMSG_PEERERROR = 8, // Signal from the Peer side. Add info: Error code.
225 /* ... add extra code types here */
226 UMSG_END_OF_TYPES,
227 UMSG_EXT = 0x7FFF // For the use of user-defined control packets.
230 // Adapted constants
231 #define SRT_CMD_HSREQ 1
232 #define SRT_CMD_HSRSP 2
233 #define SRT_CMD_KMREQ 3
234 #define SRT_CMD_KMRSP 4
235 #define SRT_CMD_SID 5
236 #define SRT_CMD_CONGESTION 6
237 #define SRT_CMD_FILTER 7
238 #define SRT_CMD_GROUP 8
240 enum SrtDataStruct
242 SRT_HS_VERSION = 0,
243 SRT_HS_FLAGS,
244 SRT_HS_EXTRAS,
246 // Keep it always last
247 SRT_HS__SIZE
251 enum UDTRequestType
253 URQ_AGREEMENT = -2,
254 URQ_CONCLUSION = -1,
255 URQ_WAVEAHAND = 0,
256 URQ_INDUCTION = 1,
258 URQ_FAILURE_TYPES = 1000
262 enum SRT_KM_STATE
264 SRT_KM_S_UNSECURED = 0, ///< No encryption
265 SRT_KM_S_SECURING = 1, ///< Stream encrypted, exchanging Keying Material
266 SRT_KM_S_SECURED = 2, ///< Stream encrypted, keying Material exchanged, decrypting ok.
267 SRT_KM_S_NOSECRET = 3, ///< Stream encrypted and no secret to decrypt Keying Material
268 SRT_KM_S_BADSECRET = 4 ///< Stream encrypted and wrong secret, cannot decrypt Keying Material
271 static const value_string srt_ctrlmsg_types[] = {
272 {UMSG_HANDSHAKE, "HANDSHAKE"},
273 {UMSG_KEEPALIVE, "KEEPALIVE"},
274 {UMSG_ACK, "ACK"},
275 {UMSG_LOSSREPORT, "LOSSREPORT"},
276 {UMSG_CGWARNING, "CGWARNING"},
277 {UMSG_SHUTDOWN, "SHUTDOWN"},
278 {UMSG_ACKACK, "ACKACK"},
279 {UMSG_DROPREQ, "DROPREQ"},
280 {UMSG_PEERERROR, "PEERERROR"},
281 {UMSG_EXT, "EXT"},
283 {0, NULL},
286 static const value_string srt_ctrlmsg_exttypes[] = {
287 {SRT_CMD_HSREQ, "HSREQ"},
288 {SRT_CMD_HSRSP, "HSRSP"},
289 {SRT_CMD_KMREQ, "KMREQ"},
290 {SRT_CMD_KMRSP, "KMRSP"},
291 {SRT_CMD_SID, "SID"},
292 {SRT_CMD_CONGESTION, "CONGESTION"},
293 {SRT_CMD_FILTER, "FILTER"},
294 {SRT_CMD_GROUP, "GROUP"},
296 { 0, NULL },
299 static const value_string srt_hs_ext_group_type[] = {
300 { 0, "Undefined" },
301 { 1, "Broadcast" },
302 { 2, "Main/Backup" },
303 { 3, "Balancing"},
304 { 0, NULL }
307 static const value_string srt_hsv4_socket_types[] = {
308 {SRT_STREAM, "SRT_STREAM"},
309 {SRT_DGRAM, "SRT_DGRAM"},
310 {0, NULL},
314 static const value_string srt_handshake_enc_field[] = {
315 {0, "PBKEYLEN not advertised"},
316 {2, "AES-128" },
317 {3, "AES-192" },
318 {4, "AES-256" },
319 {0, NULL},
323 static const true_false_string srt_packet_types = {
324 "CONTROL", /* 1 */
325 "DATA" /* 0 */
328 static const value_string srt_pb_types[] = {
329 {PB_SUBSEQUENT, "PB_SUBSEQUENT"},
330 {PB_LAST, "PB_LAST"},
331 {PB_FIRST, "PB_FIRST"},
332 {PB_SOLO, "PB_SOLO"},
333 {0, NULL},
336 static const value_string srt_msgno_enctypes[] = {
337 {SRT_MSGNO_EK_NONE, "Not encrypted"},
338 {SRT_MSGNO_EK_EVEN, "Encrypted (even key)"},
339 {SRT_MSGNO_EK_ODD, "Encrypted (odd key)"},
340 {0, NULL},
343 static const true_false_string srt_msgno_rexmit = {
344 "Retransmitted", /* 1 */
345 "Original" /* 0 */
348 static const value_string srt_hs_request_types[] = {
349 {URQ_INDUCTION, "URQ_INDUCTION (c/l invocation)"},
350 {URQ_CONCLUSION, "URQ_CONCLUSION"},
351 {URQ_WAVEAHAND, "URQ_WAVEAHAND (rendezvous invocation)"},
352 {URQ_AGREEMENT, "URQ_AGREEMENT (rendezvous finalization)"},
353 {0, NULL}
356 static const value_string srt_enc_kmstate[] = {
357 {SRT_KM_S_UNSECURED, "UNSECURED"},
358 {SRT_KM_S_SECURING, "SECURING"},
359 {SRT_KM_S_SECURED, "SECURED"},
360 {SRT_KM_S_NOSECRET, "NOSECRET"},
361 {SRT_KM_S_BADSECRET, "BADSECRET"},
363 {0, NULL},
368 * XXX To be added later to extract correct IPv4/IPv6 address from 16 bytes of data
369 * static void srt_tree_add_ipaddr( proto_tree *tree, const int hf, tvbuff_t *tvb, int offset)
375 #define IP_BUFFER_SIZE 64
377 static void srt_format_ip_address(char* dest, size_t dest_size, const char* ptr)
379 /* Initial IPv4 check.
380 * The address is considered IPv4 if:
381 * byte[0] and byte[3] != 0
382 * bytes[4...16] == 0
385 ws_in4_addr ia4;
386 ws_in6_addr ia6;
387 uint32_t* p;
388 int i, j;
390 if (ptr[0] != 0 && ptr[3] != 0)
392 for (i = 4; i < 16; ++i)
394 if (ptr[i] == 0)
395 continue;
397 /* This is not an IP4 */
398 p = (uint32_t*)&ia6;
399 for (j = 0; j < 4; ++j)
400 p[j] = g_ntohl(((uint32_t*)ptr)[j]);
402 ws_inet_ntop6(&ia6, dest, (unsigned)dest_size);
403 return;
407 // There's one small problem: the contents of the handshake
408 // goes in LITTLE ENDIAN. That's an initial problem of UDT.
409 // The address must be inverted.
411 // Here's IPv4, so invert only one l.
412 ia4 = g_ntohl(*((const uint32_t*)ptr));
414 ws_inet_ntop4(&ia4, dest, (unsigned)dest_size);
415 return;
419 static void srt_format_hs_ext_hsreq(proto_tree* tree, tvbuff_t* tvb, int baseoff)
421 proto_item* pi;
422 uint32_t version = 0;
423 pi = proto_tree_add_item_ret_uint(tree, hf_srt_handshake_ext_version, tvb, baseoff, 4, ENC_BIG_ENDIAN, &version);
425 const int vminor = (version >> 8) & 0xff;
426 const int vmajor = (version >> 16) & 0xff;
427 const int vpatch = version & 0xff;
428 proto_item_append_text(pi, " (%d.%d.%d)", vmajor, vminor, vpatch);
430 static int * const ext_hs_flags[] = {
431 &hf_srt_handshake_ext_flag_tsbpd_snd,
432 &hf_srt_handshake_ext_flag_tsbpd_rcv,
433 &hf_srt_handshake_ext_flag_haicrypt,
434 &hf_srt_handshake_ext_flag_tlpkt_drop,
435 &hf_srt_handshake_ext_flag_nak_report,
436 &hf_srt_handshake_ext_flag_rexmit,
437 &hf_srt_handshake_ext_flag_stream,
438 NULL
441 proto_tree_add_bitmask_with_flags(tree, tvb, baseoff + 4, hf_srt_handshake_ext_flags,
442 ett_srt_handshake_ext_flags, ext_hs_flags, ENC_NA, BMT_NO_APPEND);
444 proto_tree_add_item(tree, hf_srt_srths_peer_latency, tvb, baseoff + 8, 2, ENC_BIG_ENDIAN);
445 proto_tree_add_item(tree, hf_srt_srths_agent_latency, tvb, baseoff + 10, 2, ENC_BIG_ENDIAN);
448 static void srt_format_km(proto_tree* tree, tvbuff_t* tvb, int baseoff, int blocklen)
450 // 0 1 2 3
451 // 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
452 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
453 // |S| V | PT | Sign | Resv1 | KK|
454 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
455 // | KEKI |
456 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
457 // | Cipher | Auth | SE | Resv2 |
458 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
459 // | Resv3 | SLen/4 | KLen/4 |
460 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
461 // | Salt |
462 // | (16 bytes) |
463 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
464 // | |
465 // + Wrapped Key +
466 // | |
467 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
468 unsigned u8bits = 0;
469 uint32_t slen = 0;
471 proto_tree_add_item(tree, hf_srt_km_s, tvb, baseoff, 1, ENC_BIG_ENDIAN);
472 proto_tree_add_item(tree, hf_srt_km_v, tvb, baseoff, 1, ENC_BIG_ENDIAN);
473 proto_tree_add_item(tree, hf_srt_km_pt, tvb, baseoff, 1, ENC_BIG_ENDIAN);
475 proto_tree_add_item(tree, hf_srt_km_sign, tvb, baseoff + 1, 2, ENC_NA);
477 proto_tree_add_item(tree, hf_srt_km_resv1, tvb, baseoff + 3, 1, ENC_NA);
479 static const value_string kk_desc[] = {
480 { 0, "No SEK is provided - invalid KM" },
481 { 1, "Even key is provided" },
482 { 2, "Odd key is provided" },
483 { 3, "Both even and odd keys are provided"},
484 { 0, NULL }
487 u8bits = tvb_get_uint8(tvb, baseoff + 3);
488 proto_tree_add_uint_format_value(tree, hf_srt_km_kk, tvb, baseoff + 3, 1,
489 u8bits, "%u (%s)", (u8bits & SRT_KM_KK_MASK), try_val_to_str(u8bits & SRT_KM_KK_MASK, kk_desc));
491 static const value_string cipher_desc[] = {
492 { 0, "None or KEKI indexed crypto context" },
493 { 1, "AES-ECB (reserved, not supported)" },
494 { 2, "AES-CTR" },
495 { 3, "AES-CBC (reserved, not supported)" },
496 { 4, "AES-GCM" },
497 { 0, NULL }
499 proto_tree_add_item(tree, hf_srt_km_keki, tvb, baseoff + 4, 4, ENC_BIG_ENDIAN);
501 u8bits = tvb_get_uint8(tvb, baseoff + 8);
502 proto_tree_add_uint_format_value(tree, hf_srt_km_cipher, tvb, baseoff + 8, 1,
503 u8bits, "%u (%s)", u8bits, try_val_to_str(u8bits, cipher_desc));
505 proto_tree_add_item(tree, hf_srt_km_auth, tvb, baseoff + 9, 1, ENC_BIG_ENDIAN);
507 static const value_string se_desc[] = {
508 { 0, "Unspecified" },
509 { 1, "MPEG2-TS/UDP" },
510 { 2, "MPEG2-TS/SRT" },
511 { 0, NULL }
513 u8bits = tvb_get_uint8(tvb, baseoff + 10); // km.se
514 proto_tree_add_uint_format_value(tree, hf_srt_km_se, tvb, baseoff + 10, 1,
515 u8bits, "%u (%s)", u8bits, try_val_to_str(u8bits, se_desc));
517 proto_tree_add_item(tree, hf_srt_km_resv2, tvb, baseoff + 11, 1, ENC_NA);
518 proto_tree_add_item(tree, hf_srt_km_resv3, tvb, baseoff + 12, 2, ENC_NA);
520 u8bits = tvb_get_uint8(tvb, baseoff + 14); // km.slen
521 slen = 4 * u8bits;
522 proto_tree_add_uint_format_value(tree, hf_srt_km_slen, tvb, baseoff + 14, 1,
523 u8bits, "%u (%d bytes)", u8bits, slen);
525 u8bits = tvb_get_uint8(tvb, baseoff + 15); // km.klen
526 proto_tree_add_uint_format_value(tree, hf_srt_km_klen, tvb, baseoff + 15, 1,
527 u8bits, "%u (%d bytes)", u8bits, 4 * u8bits);
529 proto_tree_add_item(tree, hf_srt_km_salt, tvb, baseoff + 16, slen, ENC_NA);
531 const int wrap_offset = 16 + slen;
532 proto_tree_add_item(tree, hf_srt_km_wrap, tvb, baseoff + wrap_offset, blocklen - wrap_offset, ENC_NA);
535 static void srt_format_kmx(proto_tree* tree, tvbuff_t* tvb, int baseoff, int blocklen)
537 if (blocklen == 4)
539 // Error report. Format as KMX state.
540 proto_tree_add_item(tree, hf_srt_srtkm_error, tvb, baseoff, 4, ENC_NA);
542 else
544 srt_format_km(tree, tvb, baseoff, blocklen);
548 static void srt_format_hs_ext_group(proto_tree* tree, tvbuff_t* tvb, packet_info* pinfo, int baseoff, int blocklen)
550 // 0 1 2 3
551 // 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
552 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
553 // | Group ID |
554 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
555 // | Type | Flags | Weight |
556 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
557 if (blocklen < 8)
559 proto_tree_add_expert_format(tree, pinfo, &ei_srt_hs_ext_hsreq_len,
560 tvb, baseoff, blocklen, "Actual length is %u", blocklen);
561 return;
564 proto_tree_add_item(tree, hf_srt_hs_ext_group_id, tvb, baseoff, 4, ENC_BIG_ENDIAN);
565 proto_tree_add_item(tree, hf_srt_hs_ext_group_type, tvb, baseoff + 4, 1, ENC_BIG_ENDIAN);
566 proto_tree_add_item(tree, hf_srt_hs_ext_group_flags, tvb, baseoff + 5, 1, ENC_BIG_ENDIAN);
567 proto_tree_add_item(tree, hf_srt_hs_ext_group_weight, tvb, baseoff + 6, 2, ENC_BIG_ENDIAN);
569 if (blocklen > 8)
571 proto_tree_add_expert_format(tree, pinfo, &ei_srt_hs_ext_hsreq_len,
572 tvb, baseoff, blocklen, "Actual length is %u", blocklen);
576 // Wireshark dissector doesn't have a possibility to format enum-collected flags.
577 static void dissect_srt_hs_ext_field(proto_tree* tree,
578 tvbuff_t* tvb, int baseoff)
580 static const int ext_field_len = 2;
582 const int bits = tvb_get_ntohs(tvb, baseoff);
583 if (bits == SRT_HS_V5_EXT_FIELD_MAGIC)
585 proto_item* pi = proto_tree_add_item(tree, hf_srt_handshake_ext_field_v5,
586 tvb, baseoff, ext_field_len, ENC_BIG_ENDIAN);
587 proto_item_append_text(pi, ": HSv5 MAGIC");
588 return;
591 static int * const ext_hs_ext_field_flags[] = {
592 &hf_srt_handshake_ext_field_v5_flag_hsreq,
593 &hf_srt_handshake_ext_field_v5_flag_kmreq,
594 &hf_srt_handshake_ext_field_v5_flag_config,
595 NULL
598 proto_tree_add_bitmask_with_flags(tree, tvb, baseoff, hf_srt_handshake_ext_field_v5,
599 ett_srt_handshake_ext_field_flags, ext_hs_ext_field_flags, ENC_NA, BMT_NO_APPEND);
601 return;
606 * UTF-8 string packed as 32 bit little endian words (what?!)
607 * https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-01#section-3.2.1.3
609 * THe spec says
611 * The actual size is determined by the Extension Length field,
612 * which defines the length in four byte blocks. If the actual
613 * payload is less than the declared length, the remaining bytes
614 * are set to zeros.
616 * The content is stored as 32-bit little endian words.
618 * This means that the octets of the string are in the rather peculiar
619 * order:
621 * octet 3
622 * octet 2
623 * octet 1
624 * octet 0
625 * octet 8
626 * octet 7
627 * octet 6
628 * octet 5
630 * and so on, with null padding (not null termination).
632 static void format_text_reorder_32(proto_tree* tree, tvbuff_t* tvb, packet_info *pinfo, int hfinfo, int baseoff, int blocklen)
634 wmem_strbuf_t *sid = wmem_strbuf_create(pinfo->pool);
635 const char *str;
636 size_t len;
637 for (int ii = 0; ii < blocklen; ii += 4)
640 // Yes, this is fetching the 32-bit word as big-endian
641 // rather than little-endian.
643 // However, it's then taking the low-order byte of the
644 // result as the first octet, followed by the byte above
645 // that, followed by the byte above that, followed by
646 // the high-order byte.
648 // This is equivalent t fetching the 32-bit word as little-endian
649 // and then taking the high-order byte of the result as the
650 // first octet, etc.
652 // And both of those implement what's described above.
654 // No, I have no idea why they chose this representation for
655 // strings.
657 const uint32_t u = tvb_get_ntohl(tvb, baseoff + ii);
658 wmem_strbuf_append_c(sid, 0xFF & (u >> 0));
659 wmem_strbuf_append_c(sid, 0xFF & (u >> 8));
660 wmem_strbuf_append_c(sid, 0xFF & (u >> 16));
661 wmem_strbuf_append_c(sid, 0xFF & (u >> 24));
663 if (!wmem_strbuf_utf8_validate(sid, NULL))
664 wmem_strbuf_utf8_make_valid(sid);
665 str = wmem_strbuf_get_str(sid);
666 len = wmem_strbuf_get_len(sid);
667 while (len > 0 && str[len-1] == '\0')
668 len--;
669 proto_tree_add_string(tree, hfinfo, tvb, baseoff, blocklen,
670 format_text(pinfo->pool, str, len));
674 /* Code to actually dissect the packets
677 static void
678 dissect_srt_control_packet(tvbuff_t *tvb, packet_info* pinfo,
679 proto_tree *tree, proto_item *srt_item)
681 uint32_t type = 0;
682 uint32_t exttype = 0;
684 proto_tree_add_item_ret_uint(tree, hf_srt_type, tvb, 0, 2,
685 ENC_BIG_ENDIAN, &type);
687 if ( type != UMSG_EXT )
688 proto_tree_add_item(tree, hf_srt_exttype_none, tvb, 2, 2,
689 ENC_BIG_ENDIAN);
690 else
691 proto_tree_add_item_ret_uint(tree, hf_srt_exttype, tvb, 2, 2,
692 ENC_BIG_ENDIAN, &exttype);
694 switch (type)
696 case UMSG_EXT:
697 col_add_fstr(pinfo->cinfo, COL_INFO, "Control/ext: %s socket: %d",
698 val_to_str(exttype, srt_ctrlmsg_exttypes,
699 "Unknown EXT Control Type (%d)"),
700 tvb_get_ntohl(tvb, 12));
701 break;
702 case UMSG_ACK:
703 col_add_fstr(pinfo->cinfo, COL_INFO, "Control: ACK %d seqno: %u socket: %d",
704 tvb_get_ntohl(tvb, 4),
705 tvb_get_ntohl(tvb, 16),
706 tvb_get_ntohl(tvb, 12));
707 break;
708 case UMSG_ACKACK:
709 col_add_fstr(pinfo->cinfo, COL_INFO, "Control: ACKACK %d socket: %d",
710 tvb_get_ntohl(tvb, 4),
711 tvb_get_ntohl(tvb, 12));
712 break;
713 default:
714 col_add_fstr(pinfo->cinfo, COL_INFO, "Control: %s socket: %d",
715 val_to_str(type, srt_ctrlmsg_types,
716 "Unknown Control Type (%d)"),
717 tvb_get_ntohl(tvb, 12));
718 break;
721 switch (type)
723 case UMSG_ACK:
724 case UMSG_ACKACK:
725 proto_tree_add_item(tree, hf_srt_ackno, tvb, 4, 4,
726 ENC_BIG_ENDIAN);
727 break;
728 case UMSG_DROPREQ:
729 proto_tree_add_item(tree, hf_srt_msgno, tvb, 4, 4,
730 ENC_BIG_ENDIAN);
731 break;
732 default:
733 proto_tree_add_item(tree, hf_srt_addinfo, tvb, 4, 4,
734 ENC_BIG_ENDIAN);
735 break;
737 proto_tree_add_item(tree, hf_srt_timestamp, tvb, 8, 4,
738 ENC_BIG_ENDIAN);
739 proto_tree_add_item(tree, hf_srt_id, tvb, 12, 4,
740 ENC_BIG_ENDIAN);
742 switch (type)
744 case UMSG_HANDSHAKE:
746 char ipbuf[IP_BUFFER_SIZE];
748 const int version = tvb_get_ntohl(tvb, 16);
749 const int final_length = tvb_reported_length(tvb);
750 int baselen = 64;
751 int handshake_reqtype;
753 /* This contains the handshake version (currently 4 or 5) */
754 proto_tree_add_item(tree, hf_srt_handshake_version, tvb,
755 16, 4, ENC_BIG_ENDIAN);
757 /* Version 4 embraces both HSv4 listener URQ_INDUCTION response
758 * and HSv5 caller URQ_INDUCTION request. In both these cases the
759 * value is interpreted as socket type (UDT legacy). With version 5
760 * the first message is the listener's URQ_INDUCTION response, where
761 * the layout in the type is already the MAGIC in the lower block,
762 * and ENC FLAGS in the upper block. The next caller's URQ_CONCLUSION
763 * will have SRT HS Extension block flags in the lower block.
765 if (version == 4)
767 proto_tree_add_item(tree, hf_srt_handshake_type_v4, tvb,
768 20, 4, ENC_BIG_ENDIAN);
770 else
772 /* Both the PBKEYLEN-ad and magic are used in HSv5 induction. */
773 proto_tree_add_item(tree, hf_srt_handshake_enc_field_v5, tvb,
774 20, 2, ENC_BIG_ENDIAN);
776 dissect_srt_hs_ext_field(tree, tvb, 22); /* 2 bytes */
779 proto_tree_add_item(tree, hf_srt_handshake_isn, tvb,
780 24, 4, ENC_BIG_ENDIAN);
781 proto_tree_add_item(tree, hf_srt_handshake_mtu, tvb,
782 28, 4, ENC_BIG_ENDIAN);
783 proto_tree_add_item(tree, hf_srt_handshake_flow_window, tvb,
784 32, 4, ENC_BIG_ENDIAN);
785 handshake_reqtype = tvb_get_ntohl(tvb, 36);
786 if (handshake_reqtype < URQ_FAILURE_TYPES)
788 proto_tree_add_item(tree, hf_srt_handshake_reqtype, tvb,
789 36, 4, ENC_BIG_ENDIAN);
791 else
793 static const range_string rej_codes_rvals[] = {
794 { 0, 0, "REJ_UNKNOWN" },
795 { 1, 1, "REJ_SYSTEM" },
796 { 2, 2, "REJ_PEER" },
797 { 3, 3, "REJ_RESOURCE" },
798 { 4, 4, "REJ_ROGUE" },
799 { 5, 5, "REJ_BACKLOG" },
800 { 6, 6, "REJ_IPE" },
801 { 7, 7, "REJ_CLOSE" },
802 { 8, 8, "REJ_VERSION" },
803 { 9, 9, "REJ_RDVCOOKIE" },
804 { 10, 10, "REJ_BADSECRET" },
805 { 11, 11, "REJ_UNSECURE" },
806 { 12, 12, "REJ_MESSAGEAPI" },
807 { 13, 13, "REJ_CONGESTION" },
808 { 14, 14, "REJ_FILTER" },
809 { 15, 15, "REJ_GROUP" },
810 { 16, 16, "REJ_TIMEOUT" },
811 { 17, 17, "REJ_CRYPTO" },
812 { 18, 999, "SRT Internal Rejection Reason"},
813 { 1000, 1999, "SRT Predefined Rejection Reason"},
814 { 2000, INT32_MAX, "User Defined Rejection Reason"},
816 { 0x00, 0x00, NULL },
819 const int error_code = handshake_reqtype - URQ_FAILURE_TYPES;
820 proto_tree_add_uint_format_value(tree, hf_srt_handshake_failure_type, tvb, 36, 4, handshake_reqtype,
821 "%d (%s)", error_code, rval_to_str_const(error_code, rej_codes_rvals, "Unknown"));
824 proto_tree_add_item(tree, hf_srt_handshake_id, tvb,
825 40, 4, ENC_BIG_ENDIAN);
826 proto_tree_add_item(tree, hf_srt_handshake_cookie, tvb,
827 44, 4, ENC_BIG_ENDIAN);
829 srt_format_ip_address(ipbuf, sizeof ipbuf, (const char *)tvb_memdup(pinfo->pool, tvb, 48, 16));
831 proto_tree_add_string(tree, hf_srt_handshake_peerip, tvb,
832 48, 16, ipbuf);
833 if (final_length > baselen)
835 /* Extract SRT handshake extension blocks
836 * and increase baselen accordingly.
838 int begin = baselen;
839 for (;;)
841 const uint16_t blockid = tvb_get_ntohs(tvb, begin);
842 const uint16_t blocklen = tvb_get_ntohs(tvb, begin + 2);
844 proto_tree_add_item(tree, hf_srt_srths_blocktype, tvb,
845 begin, 2, ENC_BIG_ENDIAN);
846 proto_tree_add_item(tree, hf_srt_srths_blocklen, tvb,
847 begin+2, 2, ENC_BIG_ENDIAN);
849 // Shift to the payload
850 begin += 4;
852 switch (blockid)
854 case SRT_CMD_HSREQ:
855 case SRT_CMD_HSRSP:
856 if (blocklen == 3)
858 srt_format_hs_ext_hsreq(tree, tvb, begin);
860 else
862 /* blocklen should be 3, that corresponds to (3 * 4) = 12 bytes.
863 * Otherwise the format is unknown.*/
864 proto_tree_add_expert_format(tree, pinfo, &ei_srt_hs_ext_hsreq_len,
865 tvb, begin, 4 * blocklen, "Actual length is %u",
866 blocklen);
868 break;
870 case SRT_CMD_KMREQ:
871 case SRT_CMD_KMRSP:
872 // Rely on the extracted blocklen
873 srt_format_kmx(tree, tvb, begin, blocklen*4);
874 break;
876 case SRT_CMD_SID:
877 format_text_reorder_32(tree, tvb, pinfo, hf_srt_srths_sid, begin, 4 * blocklen);
878 break;
880 case SRT_CMD_CONGESTION:
881 format_text_reorder_32(tree, tvb, pinfo, hf_srt_srths_congestcontrol, begin, 4 * blocklen);
882 break;
884 case SRT_CMD_FILTER:
885 format_text_reorder_32(tree, tvb, pinfo, hf_srt_hs_ext_filter, begin, 4 * blocklen);
886 break;
888 case SRT_CMD_GROUP:
889 srt_format_hs_ext_group(tree, tvb, pinfo, begin, blocklen * 4);
890 break;
892 default:
893 proto_tree_add_expert_format(tree, pinfo, &ei_srt_hs_ext_type,
894 tvb, begin, 4 * blocklen, "Ext Type value is %u",
895 blockid);
896 break;
899 /* Move the index pointer past the block and repeat. */
900 begin += blocklen * 4;
902 /* OK, once one block is done, interrupt the loop. */
903 if (begin >= final_length)
904 break;
907 baselen = begin;
910 proto_item_set_len(srt_item, baselen);
912 break;
913 case UMSG_ACK:
915 unsigned len = tvb_reported_length(tvb);
917 proto_tree_add_item(tree, hf_srt_ack_seqno, tvb, 4 * 4, 4,
918 ENC_BIG_ENDIAN);
920 // Check for "Lite ACK" (size 4)
921 if (len <= (4 + 1) * 4)
923 proto_item_set_len(srt_item, (4 + 1) * 4);
925 else
927 proto_tree_add_item(tree, hf_srt_rtt, tvb, (4+1)*4, 4,
928 ENC_BIG_ENDIAN);
929 proto_tree_add_item(tree, hf_srt_rttvar, tvb, (4+2)*4, 4,
930 ENC_BIG_ENDIAN);
931 proto_tree_add_item(tree, hf_srt_bufavail, tvb, (4+3)*4, 4,
932 ENC_BIG_ENDIAN);
933 /* if not a light ack, decode the rate and link capacity */
935 if (len > (4 + 4) * 4)
937 proto_tree_add_item(tree, hf_srt_rate, tvb, (4 + 4) * 4, 4, ENC_BIG_ENDIAN);
938 proto_tree_add_item(tree, hf_srt_bandwidth, tvb, (4 + 5) * 4, 4, ENC_BIG_ENDIAN);
940 // SRT Extra data. This can be version dependent, so
941 // test the length for each field.
942 if (len > (4 + 6) * 4)
944 proto_tree_add_item(tree, hf_srt_rcvrate, tvb, (4 + 6) * 4, 4, ENC_BIG_ENDIAN);
945 len = (4 + 7) * 4;
948 proto_item_set_len(srt_item, (int) len);
950 else
952 proto_item_set_len(srt_item, (4 + 4) * 4);
956 break;
957 case UMSG_DROPREQ:
959 unsigned len = tvb_reported_length(tvb);
960 if (len > (4 + 0) * 4)
962 unsigned lo = tvb_get_ntohl(tvb, (4 + 0) * 4);
963 unsigned hi = tvb_get_ntohl(tvb, (4 + 1) * 4);
965 proto_tree_add_expert_format(tree, pinfo, &ei_srt_nak_seqno,
966 tvb, 16, 8, "Drop sequence range: %u-%u",
967 lo, hi);
968 proto_item_set_len(srt_item, (int) len);
971 break;
972 case UMSG_LOSSREPORT:
974 unsigned len = tvb_reported_length(tvb);
975 unsigned pos;
976 uint32_t val;
977 unsigned prev = 0;
978 for (pos = 16; pos < len; pos += 4)
980 val = tvb_get_ntohl(tvb, pos);
981 if (val & SRT_LOSS_SEQUENCE_FIRST) {
982 // Remember this as a beginning range
983 prev = val;
984 continue;
987 // We have either a single value, or end-range here.
988 if (prev & SRT_LOSS_SEQUENCE_FIRST) {
989 // Was a range. Display as range and clear the state.
990 proto_tree_add_expert_format(tree, pinfo, &ei_srt_nak_seqno,
991 tvb, pos-4, 8, "Loss sequence range: %u-%u",
992 (prev & SRT_LOSS_SEQUENCE_MASK), val);
993 prev = 0;
994 } else {
995 // No from, so this is a freestanding loss value
996 proto_tree_add_expert_format(tree, pinfo, &ei_srt_nak_seqno,
997 tvb, pos, 4, "Loss sequence: %u", val);
1001 // Report possible errors
1002 if (prev)
1004 proto_tree_add_expert_format(tree, pinfo, &ei_srt_nak_seqno,
1005 tvb, pos-4, 4, "ERROR: loss sequence range begin only: %u (%x)",
1006 val & SRT_LOSS_SEQUENCE_MASK, val);
1009 proto_item_set_len(srt_item, len);
1011 break;
1013 case UMSG_EXT:
1014 switch (exttype)
1016 case SRT_CMD_HSREQ:
1017 case SRT_CMD_HSRSP:
1018 srt_format_hs_ext_hsreq(tree, tvb, 16);
1019 break;
1021 case SRT_CMD_KMREQ:
1022 case SRT_CMD_KMRSP:
1024 // This relies on value of HCRYPT_MSG_KM_MAX_SZ resulting from this above.
1025 // Too strongly dependent on devel API, so using explicit 104.
1026 int plen = tvb_reported_length(tvb) - 16;
1027 if (plen > 104)
1028 plen = 104;
1029 srt_format_kmx(tree, tvb, 16, plen);
1031 break;
1033 default:
1034 break;
1036 break;
1038 default:
1039 // All other types have kinda "extra padding"
1040 proto_tree_add_item(tree, hf_srt_addinfo, tvb, 16, 4, ENC_BIG_ENDIAN);
1041 break;
1046 /* Code to actually dissect the packets
1048 * @return the amount of data this dissector was able to dissect
1050 static int
1051 dissect_srt_udp(tvbuff_t *tvb, packet_info* pinfo, proto_tree *parent_tree,
1052 void *data _U_)
1054 /* Other misc. local variables. */
1055 bool is_control = 0;
1057 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SRT");
1058 col_clear (pinfo->cinfo, COL_INFO);
1060 proto_item *srt_item = proto_tree_add_item(parent_tree, proto_srt, tvb,
1061 0 /*start*/, -1 /*length*/, ENC_NA);
1062 proto_tree *tree = proto_item_add_subtree(srt_item, ett_srt);
1063 proto_tree_add_item_ret_boolean(tree, hf_srt_iscontrol, tvb, 0, 4, ENC_BIG_ENDIAN, &is_control);
1065 if (is_control)
1067 dissect_srt_control_packet(tvb, pinfo, tree, srt_item);
1069 else
1071 /* otherwise, a data packet */
1072 tvbuff_t *next_tvb;
1074 col_add_fstr(pinfo->cinfo, COL_INFO,
1075 "DATA: seqno: %u msgno: #%u socket: %d %s",
1076 tvb_get_ntohl(tvb, 0),
1077 tvb_get_ntohl(tvb, 4) & SRT_MSGNO_MSGNO_MASK,
1078 tvb_get_ntohl(tvb, 12),
1079 tvb_get_ntohl(tvb, 4) & SRT_MSGNO_REXMIT_FLG ? "R" : "");
1081 if (tree)
1083 // Sequence number
1084 proto_tree_add_item(tree, hf_srt_seqno, tvb, 0, 4, ENC_BIG_ENDIAN);
1086 proto_tree_add_item(tree, hf_srt_msgno_pb, tvb, 4, 4, ENC_BIG_ENDIAN);
1087 proto_tree_add_item(tree, hf_srt_msgno_inorder, tvb, 4, 4, ENC_BIG_ENDIAN);
1088 proto_tree_add_item(tree, hf_srt_msgno_enctypes, tvb, 4, 4, ENC_BIG_ENDIAN);
1089 proto_tree_add_item(tree, hf_srt_msgno_rexmit, tvb, 4, 4, ENC_BIG_ENDIAN);
1090 proto_tree_add_item(tree, hf_srt_msgno, tvb, 4, 4, ENC_BIG_ENDIAN);
1092 proto_tree_add_item(tree, hf_srt_timestamp, tvb, 8, 4, ENC_BIG_ENDIAN);
1093 proto_tree_add_item(tree, hf_srt_id, tvb, 12, 4, ENC_BIG_ENDIAN);
1097 next_tvb = tvb_new_subset_remaining(tvb, 16);
1098 call_data_dissector(next_tvb, pinfo, tree);
1101 return tvb_reported_length(tvb);
1105 static bool
1106 dissect_srt_heur_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1108 conversation_t *conv;
1110 /* Must have at least 24 captured bytes for heuristic check */
1111 if (tvb_captured_length(tvb) < 24)
1112 return false;
1114 /* detect handshake control packet */
1115 if (tvb_get_ntohl(tvb, 0) != (0x80000000 | UMSG_HANDSHAKE))
1116 return false;
1118 /* must be version 4 or 5*/
1119 const uint32_t version = tvb_get_ntohl(tvb, 16);
1120 if (version != 4 && version != 5)
1121 return false;
1123 /* SRT: must be DGRAM. STREAM is not supported in SRT */
1124 if (version == 4 && tvb_get_ntohl(tvb, 20) != SRT_DGRAM)
1125 return false;
1127 conv = find_or_create_conversation(pinfo);
1128 conversation_set_dissector(conv, srt_udp_handle);
1129 dissect_srt_udp(tvb, pinfo, tree, data);
1131 return true;
1135 /* Register the protocol with Wireshark.
1137 * This format is required because a script is used to build the C function that
1138 * calls all the protocol registration.
1140 void proto_register_srt(void)
1142 expert_module_t *expert_srt;
1144 /* Setup list of header fields See Section 1.5 of README.dissector for
1145 * details. */
1146 static hf_register_info hf[] = {
1147 {&hf_srt_iscontrol, {
1148 "Content", "srt.iscontrol",
1149 FT_BOOLEAN, 32,
1150 TFS(&srt_packet_types), 0x80000000, NULL, HFILL }},
1152 {&hf_srt_type, {
1153 "Msg Type", "srt.type",
1154 FT_UINT16, BASE_HEX,
1155 VALS(srt_ctrlmsg_types), 0x7fff, NULL, HFILL}},
1157 {&hf_srt_exttype, {
1158 "Extended type", "srt.exttype",
1159 FT_UINT16, BASE_HEX,
1160 VALS(srt_ctrlmsg_exttypes), 0, NULL, HFILL}},
1162 {&hf_srt_exttype_none, {
1163 "(no extended type)", "srt.exttype_none",
1164 FT_UINT16, BASE_HEX,
1165 NULL, 0, NULL, HFILL}},
1167 {&hf_srt_seqno, {
1168 "Sequence Number", "srt.seqno",
1169 FT_UINT32, BASE_DEC,
1170 NULL, SRT_CONTROL_MASK, NULL, HFILL}},
1172 {&hf_srt_addinfo, {
1173 "(Unused)", "srt.addinfo",
1174 FT_UINT32, BASE_DEC,
1175 NULL, 0, NULL, HFILL}},
1177 {&hf_srt_msgno, {
1178 "Message Number", "srt.msgno",
1179 FT_UINT32, BASE_DEC,
1180 NULL, SRT_MSGNO_MSGNO_MASK, NULL, HFILL}},
1182 {&hf_srt_msgno_pb, {
1183 "Packet Boundary", "srt.pb",
1184 FT_UINT32, BASE_DEC,
1185 VALS(srt_pb_types), SRT_MSGNO_FF_MASK, NULL, HFILL}},
1187 {&hf_srt_msgno_inorder, {
1188 "In-Order Indicator", "srt.msg.order",
1189 FT_UINT32, BASE_DEC,
1190 NULL, SRT_MSGNO_INORDER, NULL, HFILL}},
1192 {&hf_srt_msgno_enctypes, {
1193 "Encryption Status", "srt.msg.enc",
1194 FT_UINT32, BASE_DEC,
1195 VALS(srt_msgno_enctypes), SRT_MSGNO_ENCTYPE, NULL, HFILL }},
1197 {&hf_srt_msgno_rexmit, {
1198 "Sent as", "srt.msg.rexmit",
1199 FT_BOOLEAN, 32,
1200 TFS(&srt_msgno_rexmit), SRT_MSGNO_REXMIT, NULL, HFILL }},
1202 {&hf_srt_timestamp, {
1203 "Time Stamp", "srt.timestamp",
1204 FT_UINT32, BASE_DEC_HEX,
1205 NULL, 0, NULL, HFILL}},
1207 {&hf_srt_id, {
1208 "Destination Socket ID", "srt.id",
1209 FT_UINT32, BASE_DEC,
1210 NULL, 0, NULL, HFILL}},
1212 {&hf_srt_ack_seqno, {
1213 "ACKD_RCVLASTACK", "srt.ack_seqno",
1214 FT_UINT32, BASE_DEC,
1215 NULL, 0, NULL, HFILL}},
1217 {&hf_srt_ackno, {
1218 "Ack Number", "srt.ackno",
1219 FT_UINT32, BASE_DEC,
1220 NULL, 0, NULL, HFILL}},
1222 {&hf_srt_rtt, {
1223 "ACKD_RTT", "srt.rtt",
1224 FT_UINT32, BASE_DEC | BASE_UNIT_STRING,
1225 UNS(&units_microseconds), 0, NULL, HFILL}},
1227 {&hf_srt_rttvar, {
1228 "ACKD_RTTVAR", "srt.rttvar",
1229 FT_UINT32, BASE_DEC | BASE_UNIT_STRING,
1230 UNS(&units_microseconds), 0, NULL, HFILL}},
1232 {&hf_srt_bufavail, {
1233 "ACKD_BUFFERLEFT", "srt.bufavail",
1234 FT_UINT32, BASE_DEC | BASE_UNIT_STRING,
1235 UNS(&units_pkts), 0, NULL, HFILL}},
1237 {&hf_srt_rate, {
1238 "ACKD_RCVSPEED", "srt.rate",
1239 FT_UINT32, BASE_DEC | BASE_UNIT_STRING,
1240 UNS(&units_pkts_per_sec), 0, NULL, HFILL}},
1242 {&hf_srt_bandwidth, {
1243 "ACKD_BANDWIDTH", "srt.bw",
1244 FT_UINT32, BASE_DEC | BASE_UNIT_STRING,
1245 UNS(&units_pkts_per_sec), 0, NULL, HFILL}},
1247 {&hf_srt_rcvrate, {
1248 "ACKD_RCVRATE", "srt.rcvrate",
1249 FT_UINT32, BASE_DEC | BASE_UNIT_STRING,
1250 UNS(&units_byte_bytespsecond), 0, NULL, HFILL}},
1252 {&hf_srt_handshake_version, {
1253 "Handshake Version", "srt.hs.version",
1254 FT_UINT32, BASE_DEC,
1255 NULL, 0, NULL, HFILL}},
1257 {&hf_srt_handshake_type_v4, {
1258 "(Legacy) Socket type", "srt.hs.socktype",
1259 FT_UINT32, BASE_DEC,
1260 VALS(srt_hsv4_socket_types), 0, NULL,
1261 HFILL}},
1263 {&hf_srt_handshake_enc_field_v5, {
1264 "Crypto Key Field", "srt.hs.enckeyfield",
1265 FT_UINT16, BASE_HEX,
1266 VALS(srt_handshake_enc_field), 0, NULL,
1267 HFILL}},
1269 {&hf_srt_handshake_ext_field_v5, {
1270 "Extended Field", "srt.hs.extfield",
1271 FT_UINT16, BASE_HEX,
1272 NULL, 0, NULL,
1273 HFILL}},
1275 {&hf_srt_handshake_ext_field_v5_flag_hsreq, {
1276 "HS_EXT_FIELD_HSREQ", "srt.hs.extfield.hsreq",
1277 FT_BOOLEAN, SRT_HS_V5_EXT_FIELD_LEN, TFS(&tfs_set_notset),
1278 SRT_HS_V5_EXT_FIELD_HSREQ,
1279 "Handshake request",
1280 HFILL}},
1282 {&hf_srt_handshake_ext_field_v5_flag_kmreq, {
1283 "HS_EXT_FIELD_KMREQ", "srt.hs.extfield.kmreq",
1284 FT_BOOLEAN, SRT_HS_V5_EXT_FIELD_LEN, TFS(&tfs_set_notset),
1285 SRT_HS_V5_EXT_FIELD_KMREQ,
1286 "KM request",
1287 HFILL}},
1289 {&hf_srt_handshake_ext_field_v5_flag_config, {
1290 "HS_EXT_FIELD_CONFIG", "srt.hs.extfield.config",
1291 FT_BOOLEAN, SRT_HS_V5_EXT_FIELD_LEN, TFS(&tfs_set_notset),
1292 SRT_HS_V5_EXT_FIELD_CONFIG,
1293 "Handshake has configuration",
1294 HFILL}},
1296 {&hf_srt_handshake_isn, {
1297 "Initial Sequence Number", "srt.hs.isn",
1298 FT_UINT32, BASE_DEC,
1299 NULL, 0, NULL, HFILL}},
1301 {&hf_srt_handshake_mtu, {
1302 "MTU", "srt.hs.mtu",
1303 FT_UINT32, BASE_DEC,
1304 NULL, 0, NULL, HFILL}},
1306 {&hf_srt_handshake_flow_window, {
1307 "Flow Window", "srt.hs.flow_window",
1308 FT_UINT32, BASE_DEC,
1309 NULL, 0, NULL, HFILL}},
1311 {&hf_srt_handshake_reqtype, {
1312 "Handshake Type", "srt.hs.reqtype",
1313 FT_INT32, BASE_DEC,
1314 VALS(srt_hs_request_types), 0, NULL, HFILL}},
1316 {&hf_srt_handshake_failure_type, {
1317 "Handshake FAILURE code", "srt.hs.failtype",
1318 FT_UINT32, BASE_DEC,
1319 NULL, 0, NULL, HFILL}},
1321 {&hf_srt_handshake_id, {
1322 "Socket ID", "srt.hs.id",
1323 FT_UINT32, BASE_DEC,
1324 NULL, 0, NULL, HFILL}},
1326 {&hf_srt_handshake_cookie, {
1327 "SYN Cookie", "srt.hs.cookie",
1328 FT_UINT32, BASE_HEX,
1329 NULL, 0, NULL, HFILL}},
1331 {&hf_srt_handshake_peerip, {
1332 /* FT_STRINGZ is used because the value
1333 * is formatted to a temporary buffer first */
1334 "Peer IP Address", "srt.hs.peerip",
1335 FT_STRINGZ, BASE_NONE,
1336 NULL, 0, NULL, HFILL}},
1338 {&hf_srt_handshake_ext_version, {
1339 "SRT Version", "srt.hs.version",
1340 FT_UINT32, BASE_HEX,
1341 NULL, 0, NULL, HFILL}},
1343 {&hf_srt_handshake_ext_flags, {
1344 /* This uses custom format by appending the flag format string,
1345 * while the value in hex is still printed. */
1346 "SRT Flags", "srt.hs.srtflags",
1347 FT_UINT32, BASE_HEX,
1348 NULL, 0, NULL, HFILL}},
1350 {&hf_srt_handshake_ext_flag_tsbpd_snd, {
1351 "TSBPDSND", "srt.hs.srtflags.tsbpd_snd",
1352 FT_BOOLEAN, SRT_OPT_FIELD_LEN, TFS(&tfs_set_notset),
1353 SRT_OPT_TSBPDSND,
1354 "The party will be sending in TSBPD (Time Stamp Based Packet Delivery) mode",
1355 HFILL}},
1357 {&hf_srt_handshake_ext_flag_tsbpd_rcv, {
1358 "TSBPDRCV", "srt.hs.srtflags.tsbpd_rcv",
1359 FT_BOOLEAN, SRT_OPT_FIELD_LEN, TFS(&tfs_set_notset),
1360 SRT_OPT_TSBPDRCV,
1361 "The party expects to receive in TSBPD (Time Stamp Based Packet Delivery) mode",
1362 HFILL}},
1364 {&hf_srt_handshake_ext_flag_haicrypt, {
1365 "HAICRYPT", "srt.hs.srtflags.haicrypt",
1366 FT_BOOLEAN, SRT_OPT_FIELD_LEN, TFS(&tfs_set_notset),
1367 SRT_OPT_HAICRYPT,
1368 "The party includes haicrypt (legacy flag)",
1369 HFILL}},
1371 {&hf_srt_handshake_ext_flag_tlpkt_drop, {
1372 "TLPKTDROP", "srt.hs.srtflags.tlpkt_drop",
1373 FT_BOOLEAN, SRT_OPT_FIELD_LEN, TFS(&tfs_set_notset),
1374 SRT_OPT_TLPKTDROP,
1375 "The party will do the Too-Late Packet Drop",
1376 HFILL}},
1378 {&hf_srt_handshake_ext_flag_nak_report, {
1379 "NAKREPORT", "srt.hs.srtflags.nak_report",
1380 FT_BOOLEAN, SRT_OPT_FIELD_LEN, TFS(&tfs_set_notset),
1381 SRT_OPT_NAKREPORT,
1382 "The party will do periodic NAK reporting",
1383 HFILL}},
1385 {&hf_srt_handshake_ext_flag_rexmit, {
1386 "REXMITFLG", "srt.hs.srtflags.rexmit",
1387 FT_BOOLEAN, SRT_OPT_FIELD_LEN, TFS(&tfs_set_notset),
1388 SRT_OPT_REXMITFLG,
1389 "The party uses the REXMIT flag",
1390 HFILL}},
1392 {&hf_srt_handshake_ext_flag_stream, {
1393 "STREAM", "srt.hs.srtflags.stream",
1394 FT_BOOLEAN, SRT_OPT_FIELD_LEN, TFS(&tfs_set_notset),
1395 SRT_OPT_STREAM,
1396 "The party uses stream type transmission",
1397 HFILL}},
1399 {&hf_srt_srths_blocktype, {
1400 "SRT HS Extension type", "srt.hs.blocktype",
1401 FT_UINT16, BASE_HEX,
1402 VALS(srt_ctrlmsg_exttypes), 0, NULL, HFILL}},
1404 {&hf_srt_srths_blocklen, {
1405 "SRT HS Extension size (4-byte blocks)", "srt.hs.blocklen",
1406 FT_UINT16, BASE_DEC,
1407 NULL, 0, NULL, HFILL}},
1409 {&hf_srt_srths_agent_latency, {
1410 "Latency", "srt.hs.agent_latency",
1411 FT_UINT16, BASE_DEC | BASE_UNIT_STRING,
1412 UNS(&units_milliseconds), 0, NULL, HFILL}},
1414 {&hf_srt_srths_peer_latency, {
1415 "Peer Latency", "srt.hs.peer_latency",
1416 FT_UINT16, BASE_DEC | BASE_UNIT_STRING,
1417 UNS(&units_milliseconds), 0, NULL, HFILL}},
1419 {&hf_srt_srtkm_msg, {
1420 "KMX Message (or KM State if 4 bytes)", "srt.km.msg",
1421 FT_BYTES, BASE_NONE,
1422 NULL, 0, NULL, HFILL}},
1424 {&hf_srt_srtkm_error, {
1425 "KM State", "srt.km.error",
1426 FT_UINT32, BASE_DEC,
1427 VALS(srt_enc_kmstate), 0, NULL, HFILL}},
1429 {&hf_srt_srths_sid, {
1430 "Stream ID", "srt.hs.sid",
1431 FT_STRING, BASE_NONE,
1432 NULL, 0, NULL, HFILL}},
1434 {&hf_srt_srths_congestcontrol, {
1435 "Congestion Control Type", "srt.hs.congestctrl",
1436 FT_STRING, BASE_NONE,
1437 NULL, 0, NULL, HFILL}},
1439 {&hf_srt_hs_ext_filter, {
1440 "Packet Filter Type", "srt.hs.filter",
1441 FT_STRING, BASE_NONE,
1442 NULL, 0, NULL, HFILL}},
1444 {&hf_srt_km, {
1445 "Key Material", "srt.km",
1446 FT_BYTES, BASE_NONE,
1447 NULL, 0, NULL, HFILL}},
1449 {&hf_srt_km_s, {
1450 "Reserved 'S' Bit", "srt.km.s",
1451 FT_UINT8, BASE_DEC, NULL,
1452 SRT_KM_S_MASK, NULL, HFILL}},
1454 {&hf_srt_km_v, {
1455 "KM Version", "srt.km.v",
1456 FT_UINT8, BASE_DEC,
1457 NULL, SRT_KM_V_MASK, NULL,
1458 HFILL} },
1460 {&hf_srt_km_pt, {
1461 "KM Payload Type", "srt.km.pt",
1462 FT_UINT8, BASE_DEC,
1463 NULL, SRT_KM_PT_MASK, NULL,
1464 HFILL} },
1466 {&hf_srt_km_sign, {
1467 "KM Signature", "srt.km.sign",
1468 FT_BYTES, BASE_NONE,
1469 NULL, 0, NULL,
1470 HFILL} },
1472 {&hf_srt_km_resv1, {
1473 "Reserved1", "srt.km.resv1",
1474 FT_UINT8, BASE_DEC,
1475 NULL, SRT_KM_RESV1_MASK, NULL,
1476 HFILL} },
1478 {&hf_srt_km_kk, {
1479 "Encryption Keys", "srt.km.kk",
1480 FT_UINT8, BASE_DEC,
1481 NULL, SRT_KM_KK_MASK, NULL,
1482 HFILL} },
1484 {&hf_srt_km_keki, {
1485 "KEK index", "srt.km.keki",
1486 FT_UINT32, BASE_DEC,
1487 NULL, 0, NULL,
1488 HFILL} },
1490 {&hf_srt_km_cipher, {
1491 "Cipher", "srt.km.cipher",
1492 FT_UINT8, BASE_DEC,
1493 NULL, 0, NULL,
1494 HFILL} },
1496 {&hf_srt_km_auth, {
1497 "Auth", "srt.km.auth",
1498 FT_UINT8, BASE_DEC,
1499 NULL, 0, NULL,
1500 HFILL} },
1502 {&hf_srt_km_se, {
1503 "Stream Encapsulation", "srt.km.se",
1504 FT_UINT8, BASE_DEC,
1505 NULL, 0, NULL,
1506 HFILL} },
1508 {&hf_srt_km_resv2, {
1509 "Reserved2", "srt.km.resv2",
1510 FT_UINT8, BASE_DEC,
1511 NULL, 0, NULL,
1512 HFILL} },
1514 { &hf_srt_km_resv3, {
1515 "Reserved3", "srt.km.resv3",
1516 FT_UINT16, BASE_DEC,
1517 NULL, 0, NULL,
1518 HFILL} },
1520 {&hf_srt_km_slen, {
1521 "Salt Length (4-byte blocks)", "srt.km.slen",
1522 FT_UINT8, BASE_DEC,
1523 NULL, 0, NULL,
1524 HFILL} },
1526 {&hf_srt_km_klen, {
1527 "SEK Length (4-byte blocks)", "srt.km.klen",
1528 FT_UINT8, BASE_DEC,
1529 NULL, 0, NULL,
1530 HFILL} },
1532 {&hf_srt_km_salt, {
1533 "Salt", "srt.km.salt",
1534 FT_BYTES, BASE_NONE,
1535 NULL, 0, NULL, HFILL}},
1537 {&hf_srt_km_wrap, {
1538 "Key wrap", "srt.km.wrap",
1539 FT_BYTES, BASE_NONE,
1540 NULL, 0, NULL, HFILL}},
1542 {&hf_srt_hs_ext_group_id, {
1543 "Group ID", "srt.hs_ext_group.id",
1544 FT_UINT32, BASE_DEC,
1545 NULL, 0, NULL, HFILL}},
1547 { &hf_srt_hs_ext_group_type, {
1548 "Group Type", "srt.hs_ext_group.type",
1549 FT_UINT8, BASE_DEC,
1550 VALS(srt_hs_ext_group_type), 0, NULL, HFILL}},
1552 { &hf_srt_hs_ext_group_flags, {
1553 "Group Flags", "srt.hs_ext_group.flags",
1554 FT_UINT8, BASE_DEC,
1555 NULL, 0, NULL, HFILL}},
1557 { &hf_srt_hs_ext_group_weight, {
1558 "Member Weight", "srt.hs_ext_group.member_weight",
1559 FT_UINT16, BASE_DEC,
1560 NULL, 0, NULL, HFILL}}
1564 static int *ett[] = {
1565 &ett_srt,
1566 &ett_srt_handshake_ext_flags,
1567 &ett_srt_handshake_ext_field_flags
1570 static ei_register_info ei[] = {
1571 { &ei_srt_nak_seqno,
1572 { "srt.nak_seqno", PI_SEQUENCE, PI_NOTE,
1573 "Missing Sequence Number(s)", EXPFILL }},
1575 { &ei_srt_hs_ext_hsreq_len,
1576 { "srt.hs.ext.hsreq", PI_PROTOCOL, PI_WARN,
1577 "Unknown HS Ext HSREQ length", EXPFILL }},
1579 { &ei_srt_hs_ext_type,
1580 { "srt.hs.ext.type", PI_PROTOCOL, PI_WARN,
1581 "Unknown HS Ext Type", EXPFILL }},
1583 { &ei_srt_hs_ext_group_len,
1584 { "srt.hs.ext.group", PI_PROTOCOL, PI_WARN,
1585 "Wrong HS Ext Group length", EXPFILL }},
1588 proto_srt = proto_register_protocol("SRT Protocol", "SRT", "srt");
1589 proto_register_field_array(proto_srt, hf, array_length(hf));
1590 proto_register_subtree_array(ett, array_length(ett));
1592 expert_srt = expert_register_protocol(proto_srt);
1593 expert_register_field_array(expert_srt, ei, array_length(ei));
1595 srt_udp_handle = register_dissector("srt", dissect_srt_udp, proto_srt);
1599 void proto_reg_handoff_srt(void)
1601 /* register as heuristic dissector for UDP */
1602 heur_dissector_add("udp", dissect_srt_heur_udp, "SRT over UDP",
1603 "srt_udp", proto_srt, HEURISTIC_ENABLE);
1605 /* Add a handle to the list of handles that *could* be used with this
1606 table. That list is used by the "Decode As"/"-d" code in the UI. */
1607 dissector_add_for_decode_as("udp.port", srt_udp_handle);
1612 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1614 * Local variables:
1615 * c-basic-offset: 4
1616 * tab-width: 8
1617 * indent-tabs-mode: nil
1618 * End:
1620 * vi: set shiftwidth=4 tabstop=8 expandtab:
1621 * :indentSize=4:tabSize=8:noTabs=true: