1 /* packet-steam_ihs_discovery.c
2  * Routines for Steam In-Home Streaming Discovery Protocol dissection
3  * Copyright 2017, Jan Holthuis <jan.holthuis@ruhr-uni-bochum.de>
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * SPDX-License-Identifier: GPL-2.0-or-later
10  */
11 
12 /* Steam In-Home Streaming Discovery Protocol detects servers and negotiates
13  * connections to stream video games over the networks. It is used by
14  * Valve Software's Steam Client and Steam Link devices.
15  *
16  * Further Information:
17  * https://codingrange.com/blog/steam-in-home-streaming-discovery-protocol
18  * https://codingrange.com/blog/steam-in-home-streaming-control-protocol
19  */
20 
21 #include <config.h>
22 
23 #include <epan/packet.h>   /* Should be first Wireshark include (other than config.h) */
24 #include <epan/expert.h>   /* Include only as needed */
25 #include <epan/prefs.h>    /* Include only as needed */
26 
27 /* Prototypes */
28 /* (Required to prevent [-Wmissing-prototypes] warnings */
29 void proto_reg_handoff_steam_ihs_discovery(void);
30 void proto_register_steam_ihs_discovery(void);
31 
32 static int proto_steam_ihs_discovery = -1;
33 
34 static int hf_steam_ihs_discovery_signature = -1;
35 static int hf_steam_ihs_discovery_header_length = -1;
36 static int hf_steam_ihs_discovery_header_clientid = -1;
37 static int hf_steam_ihs_discovery_header_msgtype = -1;
38 static int hf_steam_ihs_discovery_header_instanceid = -1;
39 static int hf_steam_ihs_discovery_body_length = -1;
40 static int hf_steam_ihs_discovery_body_discovery_seqnum = -1;
41 static int hf_steam_ihs_discovery_body_discovery_clientids = -1;
42 static int hf_steam_ihs_discovery_body_status_version = -1;
43 static int hf_steam_ihs_discovery_body_status_minversion = -1;
44 static int hf_steam_ihs_discovery_body_status_connectport = -1;
45 static int hf_steam_ihs_discovery_body_status_hostname = -1;
46 static int hf_steam_ihs_discovery_body_status_enabledservices = -1;
47 static int hf_steam_ihs_discovery_body_status_ostype = -1;
48 static int hf_steam_ihs_discovery_body_status_is64bit = -1;
49 static int hf_steam_ihs_discovery_body_status_euniverse = -1;
50 static int hf_steam_ihs_discovery_body_status_timestamp = -1;
51 static int hf_steam_ihs_discovery_body_status_screenlocked = -1;
52 static int hf_steam_ihs_discovery_body_status_gamesrunning = -1;
53 static int hf_steam_ihs_discovery_body_status_macaddresses = -1;
54 static int hf_steam_ihs_discovery_body_status_user_steamid = -1;
55 static int hf_steam_ihs_discovery_body_status_user_authkeyid = -1;
56 static int hf_steam_ihs_discovery_body_authrequest_devicetoken = -1;
57 static int hf_steam_ihs_discovery_body_authrequest_devicename = -1;
58 static int hf_steam_ihs_discovery_body_authrequest_encryptedrequest = -1;
59 static int hf_steam_ihs_discovery_body_authresponse_authresult = -1;
60 static int hf_steam_ihs_discovery_body_streamingrequest_requestid = -1;
61 static int hf_steam_ihs_discovery_body_streamingrequest_maximumresolutionx = -1;
62 static int hf_steam_ihs_discovery_body_streamingrequest_maximumresolutiony = -1;
63 static int hf_steam_ihs_discovery_body_streamingrequest_audiochannelcount = -1;
64 static int hf_steam_ihs_discovery_body_streamingrequest_deviceversion = -1;
65 static int hf_steam_ihs_discovery_body_streamingrequest_streamdesktop = -1;
66 static int hf_steam_ihs_discovery_body_streamingrequest_devicetoken = -1;
67 static int hf_steam_ihs_discovery_body_streamingrequest_pin = -1;
68 static int hf_steam_ihs_discovery_body_streamingrequest_enablevideostreaming = -1;
69 static int hf_steam_ihs_discovery_body_streamingrequest_enableaudiostreaming = -1;
70 static int hf_steam_ihs_discovery_body_streamingrequest_enableinputstreaming = -1;
71 static int hf_steam_ihs_discovery_body_streamingcancelrequest_requestid = -1;
72 static int hf_steam_ihs_discovery_body_streamingresponse_requestid = -1;
73 static int hf_steam_ihs_discovery_body_streamingresponse_result = -1;
74 static int hf_steam_ihs_discovery_body_streamingresponse_port = -1;
75 static int hf_steam_ihs_discovery_body_streamingresponse_encryptedsessionkey = -1;
76 static int hf_steam_ihs_discovery_body_streamingresponse_virtualherelicenseddevicecount = -1;
77 static int hf_steam_ihs_discovery_body_proofrequest_challenge = -1;
78 static int hf_steam_ihs_discovery_body_proofresponse_response = -1;
79 static int hf_steam_ihs_discovery_unknown_data = -1;
80 static int hf_steam_ihs_discovery_unknown_number = -1;
81 
82 static const val64_string hf_steam_ihs_discovery_header_msgtype_strings[] = {
83     {  0, "Client Discovery" },
84     {  1, "Client Status" },
85     {  2, "Client Offline" },
86     {  3, "Device Authorization Request" },
87     {  4, "Device Authorization Response" },
88     {  5, "Device Streaming Request" },
89     {  6, "Device Streaming Response" },
90     {  7, "Device Proof Request" },
91     {  8, "Device Proof Response" },
92     {  9, "Device Authorization Cancel Request" },
93     { 10, "Device Streaming Cancel Request" },
94     {  0, NULL }
95 };
96 
97 static const val64_string hf_steam_ihs_discovery_body_authresponse_authresult_strings[] = {
98     { 0, "Success" },
99     { 1, "Denied" },
100     { 2, "Not Logged In" },
101     { 3, "Offline" },
102     { 4, "Busy" },
103     { 5, "In Progress" },
104     { 6, "TimedOut" },
105     { 7, "Failed" },
106     { 8, "Canceled" },
107     { 0, NULL }
108 };
109 
110 static const val64_string hf_steam_ihs_discovery_body_streamingresponse_result_strings[] = {
111     {  0, "Success" },
112     {  1, "Unauthorized" },
113     {  2, "Screen Locked" },
114     {  3, "Failed" },
115     {  4, "Busy" },
116     {  5, "In Progress" },
117     {  6, "Canceled" },
118     {  7, "Drivers Not Installed" },
119     {  8, "Disabled" },
120     {  9, "Broadcasting Active" },
121     { 10, "VR Active" },
122     { 11, "PIN Required" },
123     { 0, NULL }
124 };
125 
126 static expert_field ei_steam_ihs_discovery_unknown_data = EI_INIT;
127 static expert_field ei_steam_ihs_discovery_unknown_number = EI_INIT;
128 static expert_field ei_steam_ihs_discovery_unknown_lengthdelimited = EI_INIT;
129 static expert_field ei_steam_ihs_discovery_invalid_wiretype = EI_INIT;
130 static expert_field ei_steam_ihs_discovery_invalid_length = EI_INIT;
131 
132 #define STEAM_IHS_DISCOVERY_UDP_PORT 27036
133 static guint udp_port_pref = STEAM_IHS_DISCOVERY_UDP_PORT;
134 
135 /* Initialize the subtree pointers */
136 static gint ett_steam_ihs_discovery = -1;
137 static gint ett_steam_ihs_discovery_body_status_user = -1;
138 
139 #define STEAM_IHS_DISCOVERY_MIN_LENGTH 12
140 #define STEAM_IHS_DISCOVERY_SIGNATURE_LENGTH 8
141 #define STEAM_IHS_DISCOVERY_SIGNATURE_VALUE 0xFFFFFFFF214C5FA0
142 
143 /* Helper functions and structs for reading Protocol Buffers.
144  *
145  * Detailed information about protobuf message encoding can be found at:
146  * https://developers.google.com/protocol-buffers/docs/encoding#structure
147  */
148 #define PROTOBUF_WIRETYPE_VARINT          0
149 #define PROTOBUF_WIRETYPE_64BIT           1
150 #define PROTOBUF_WIRETYPE_LENGTHDELIMITED 2
151 #define PROTOBUF_WIRETYPE_32BIT           5
152 
153 static const char * const protobuf_wiretype_names[] = {"VarInt", "64-bit", "Length-delimited", "Start group", "End group", "32-bit"};
154 static const char protobuf_wiretype_name_unknown[] = "Unknown";
155 
protobuf_get_wiretype_name(guint8 wire_type)156 static const char* protobuf_get_wiretype_name(guint8 wire_type) {
157     if (wire_type <= 5) {
158         return protobuf_wiretype_names[wire_type];
159     }
160     return protobuf_wiretype_name_unknown;
161 }
162 
163 static gint64
get_varint64(tvbuff_t * tvb,gint offset,gint bytes_left,gint * len)164 get_varint64(tvbuff_t *tvb, gint offset, gint bytes_left, gint* len)
165 {
166     guint8 b;
167     gint64 result = 0;
168     *len = 0;
169     while ((*len) < bytes_left) {
170         b = tvb_get_guint8(tvb, offset+(*len));
171         result |= ((gint64)b & 0x7f) << ((*len)*7);
172         (*len)++;
173         if ((b & 0x80) == 0) {
174             break;
175         }
176     }
177     return result;
178 }
179 
180 typedef struct {
181     tvbuff_t *tvb;
182     gint offset;
183     gint bytes_left;
184 } protobuf_desc_t;
185 
186 typedef struct {
187     guint64 value;
188     guint64 field_number;
189     guint8 wire_type;
190 } protobuf_tag_t;
191 
192 static void
protobuf_seek_forward(protobuf_desc_t * pb,gint len)193 protobuf_seek_forward(protobuf_desc_t* pb, gint len)
194 {
195     pb->offset += len;
196     pb->bytes_left -= len;
197 }
198 
199 static gint
protobuf_iter_next(protobuf_desc_t * pb,protobuf_tag_t * tag)200 protobuf_iter_next(protobuf_desc_t* pb, protobuf_tag_t* tag)
201 {
202     gint len;
203     if (pb->bytes_left <= 0) {
204         return 0;
205     }
206     tag->value = get_varint64(pb->tvb, pb->offset, pb->bytes_left, &len);
207     tag->field_number = tag->value >> 3;
208     tag->wire_type = tag->value & 0x7;
209     protobuf_seek_forward(pb, len);
210     return pb->bytes_left;
211 }
212 
213 static gint
protobuf_dissect_unknown_field(protobuf_desc_t * pb,protobuf_tag_t * tag,packet_info * pinfo,proto_tree * tree,proto_item ** tiptr)214 protobuf_dissect_unknown_field(protobuf_desc_t *pb, protobuf_tag_t *tag, packet_info *pinfo, proto_tree *tree, proto_item** tiptr)
215 {
216     gint len;
217     gint64 value;
218     proto_item* ti;
219 
220     switch(tag->wire_type) {
221         case PROTOBUF_WIRETYPE_VARINT:
222             value = get_varint64(pb->tvb, pb->offset, pb->bytes_left, &len);
223             ti = proto_tree_add_uint64(tree, hf_steam_ihs_discovery_unknown_number, pb->tvb,
224                     pb->offset, len, (guint64)value);
225             expert_add_info_format(pinfo, ti, &ei_steam_ihs_discovery_unknown_number, "Unknown numeric protobuf field (wire type %d = %s)", tag->wire_type, protobuf_get_wiretype_name(tag->wire_type));
226             break;
227         case PROTOBUF_WIRETYPE_64BIT:
228             len = 8;
229             ti = proto_tree_add_item(tree, hf_steam_ihs_discovery_unknown_number, pb->tvb, pb->offset+len, len, ENC_LITTLE_ENDIAN);
230             expert_add_info_format(pinfo, ti, &ei_steam_ihs_discovery_unknown_number, "Unknown numeric protobuf field (wire type %d = %s)", tag->wire_type, protobuf_get_wiretype_name(tag->wire_type));
231             break;
232         case PROTOBUF_WIRETYPE_LENGTHDELIMITED:
233             value = get_varint64(pb->tvb, pb->offset, pb->bytes_left, &len);
234             if((guint64)value > (guint64)(pb->bytes_left-len)) {
235                 ti = proto_tree_add_item(tree, hf_steam_ihs_discovery_unknown_data, pb->tvb, pb->offset+len, pb->bytes_left-len, ENC_NA);
236                 expert_add_info_format(pinfo, ti, &ei_steam_ihs_discovery_invalid_length, "Length-delimited field %"G_GUINT64_FORMAT" has length prefix %"G_GUINT64_FORMAT", but buffer is only %d bytes long.", tag->field_number, (guint64)value, (pb->bytes_left-len));
237                 len = pb->bytes_left;
238             } else {
239                 ti = proto_tree_add_item(tree, hf_steam_ihs_discovery_unknown_data, pb->tvb, pb->offset+len, (gint)value, ENC_NA);
240                 len += (gint)value;
241             }
242             expert_add_info(pinfo, ti, &ei_steam_ihs_discovery_unknown_lengthdelimited);
243             break;
244         case PROTOBUF_WIRETYPE_32BIT:
245             len = 4;
246             ti = proto_tree_add_item(tree, hf_steam_ihs_discovery_unknown_number, pb->tvb, pb->offset+len, len, ENC_LITTLE_ENDIAN);
247             expert_add_info_format(pinfo, ti, &ei_steam_ihs_discovery_unknown_number, "Unknown numeric protobuf field (wire type %d = %s)", tag->wire_type, protobuf_get_wiretype_name(tag->wire_type));
248             break;
249         default:
250             len = pb->bytes_left;
251             ti = proto_tree_add_item(tree, hf_steam_ihs_discovery_unknown_data, pb->tvb, pb->offset, len, ENC_NA);
252             expert_add_info(pinfo, ti, &ei_steam_ihs_discovery_unknown_data);
253             break;
254     }
255     if(tiptr != NULL) {
256         *tiptr = ti;
257     }
258 
259     return len;
260 }
261 
262 static gint
protobuf_verify_wiretype(protobuf_desc_t * pb,protobuf_tag_t * tag,packet_info * pinfo,proto_tree * tree,guint8 expected_wire_type)263 protobuf_verify_wiretype(protobuf_desc_t *pb, protobuf_tag_t *tag, packet_info *pinfo, proto_tree *tree, guint8 expected_wire_type)
264 {
265     gint len;
266     gint64 len_prefix;
267     proto_item *ti = NULL;
268 
269     if(expected_wire_type == tag->wire_type) {
270         if(expected_wire_type == PROTOBUF_WIRETYPE_LENGTHDELIMITED) {
271             len_prefix = get_varint64(pb->tvb, pb->offset, pb->bytes_left, &len);
272             if(len_prefix < 0 || len_prefix > G_MAXINT) {
273                 ti = proto_tree_add_item(tree, hf_steam_ihs_discovery_unknown_data, pb->tvb, pb->offset+len, pb->bytes_left-len, ENC_NA);
274                 expert_add_info_format(pinfo, ti, &ei_steam_ihs_discovery_invalid_length, "Length-delimited field %"G_GUINT64_FORMAT" has length prefix %"G_GINT64_FORMAT" outside valid range (0 <= x <= G_MAXINT).", tag->field_number, len_prefix);
275                 return pb->bytes_left;
276             } else if(((gint)len_prefix) > (pb->bytes_left-len)) {
277                 ti = proto_tree_add_item(tree, hf_steam_ihs_discovery_unknown_data, pb->tvb, pb->offset+len, pb->bytes_left-len, ENC_NA);
278                 expert_add_info_format(pinfo, ti, &ei_steam_ihs_discovery_invalid_length, "Length-delimited field %"G_GUINT64_FORMAT" has length prefix %"G_GINT64_FORMAT", but buffer is only %d bytes long.", tag->field_number, len_prefix, (pb->bytes_left-len));
279                 return pb->bytes_left;
280             }
281         }
282         return 0;
283     }
284     len = protobuf_dissect_unknown_field(pb, tag, pinfo, tree, &ti);
285 
286     expert_add_info_format(pinfo, ti, &ei_steam_ihs_discovery_invalid_wiretype, "Expected wiretype %d (%s) for field %"G_GUINT64_FORMAT", but got %d (%s) instead.", expected_wire_type, protobuf_get_wiretype_name(expected_wire_type), tag->field_number, tag->wire_type, protobuf_get_wiretype_name(tag->wire_type));
287     return len;
288 }
289 
290 /* The actual protocol-specific stuff */
291 
292 #define STEAMDISCOVER_FN_HEADER_CLIENTID   1
293 #define STEAMDISCOVER_FN_HEADER_MSGTYPE    2
294 #define STEAMDISCOVER_FN_HEADER_INSTANCEID 3
295 
296 #define STEAMDISCOVER_FN_DISCOVERY_SEQNUM                       1
297 #define STEAMDISCOVER_FN_DISCOVERY_CLIENTIDS                    2
298 
299 #define STEAMDISCOVER_FN_STATUS_VERSION                         1
300 #define STEAMDISCOVER_FN_STATUS_MINVERSION                      2
301 #define STEAMDISCOVER_FN_STATUS_CONNECTPORT                     3
302 #define STEAMDISCOVER_FN_STATUS_HOSTNAME                        4
303 #define STEAMDISCOVER_FN_STATUS_ENABLEDSERVICES                 6
304 #define STEAMDISCOVER_FN_STATUS_OSTYPE                          7
305 #define STEAMDISCOVER_FN_STATUS_IS64BIT                         8
306 #define STEAMDISCOVER_FN_STATUS_USERS                           9
307 #define STEAMDISCOVER_FN_STATUS_EUNIVERSE                      11
308 #define STEAMDISCOVER_FN_STATUS_TIMESTAMP                      12
309 #define STEAMDISCOVER_FN_STATUS_SCREENLOCKED                   13
310 #define STEAMDISCOVER_FN_STATUS_GAMESRUNNING                   14
311 #define STEAMDISCOVER_FN_STATUS_MACADDRESSES                   15
312 #define STEAMDISCOVER_FN_STATUS_USER_STEAMID                    1
313 #define STEAMDISCOVER_FN_STATUS_USER_AUTHKEYID                  2
314 
315 #define STEAMDISCOVER_FN_AUTHREQUEST_DEVICETOKEN                1
316 #define STEAMDISCOVER_FN_AUTHREQUEST_DEVICENAME                 2
317 #define STEAMDISCOVER_FN_AUTHREQUEST_ENCRYPTEDREQUEST           3
318 
319 #define STEAMDISCOVER_FN_AUTHRESPONSE_AUTHRESULT                1
320 
321 #define STEAMDISCOVER_FN_STREAMINGREQUEST_REQUESTID             1
322 #define STEAMDISCOVER_FN_STREAMINGREQUEST_MAXIMUMRESOLUTIONX    2
323 #define STEAMDISCOVER_FN_STREAMINGREQUEST_MAXIMUMRESOLUTIONY    3
324 #define STEAMDISCOVER_FN_STREAMINGREQUEST_AUDIOCHANNELCOUNT     4
325 #define STEAMDISCOVER_FN_STREAMINGREQUEST_DEVICEVERSION         5
326 #define STEAMDISCOVER_FN_STREAMINGREQUEST_STREAMDESKTOP         6
327 #define STEAMDISCOVER_FN_STREAMINGREQUEST_DEVICETOKEN           7
328 #define STEAMDISCOVER_FN_STREAMINGREQUEST_PIN                   8
329 #define STEAMDISCOVER_FN_STREAMINGREQUEST_ENABLEVIDEOSTREAMING  9
330 #define STEAMDISCOVER_FN_STREAMINGREQUEST_ENABLEAUDIOSTREAMING 10
331 #define STEAMDISCOVER_FN_STREAMINGREQUEST_ENABLEINPUTSTREAMING 11
332 
333 #define STEAMDISCOVER_FN_STREAMINGCANCELREQUEST_REQUESTID       1
334 
335 #define STEAMDISCOVER_FN_STREAMINGRESPONSE_REQUESTID            1
336 #define STEAMDISCOVER_FN_STREAMINGRESPONSE_RESULT               2
337 #define STEAMDISCOVER_FN_STREAMINGRESPONSE_PORT                 3
338 #define STEAMDISCOVER_FN_STREAMINGRESPONSE_ENCRYPTEDSESSIONKEY  4
339 #define STEAMDISCOVER_FN_STREAMINGRESPONSE_VIRTUALHERELICENSEDDEVICECOUNT 5
340 
341 #define STEAMDISCOVER_FN_PROOFREQUEST_CHALLENGE                 1
342 #define STEAMDISCOVER_FN_PROOFRESPONSE_RESPONSE                 1
343 
344 #define STEAMDISCOVER_MSGTYPE_CLIENTBROADCASTMSGDISCOVERY       0
345 #define STEAMDISCOVER_MSGTYPE_CLIENTBROADCASTMSGSTATUS          1
346 #define STEAMDISCOVER_MSGTYPE_CLIENTBROADCASTMSGOFFLINE         2
347 #define STEAMDISCOVER_MSGTYPE_DEVICEAUTHORIZATIONREQUEST        3
348 #define STEAMDISCOVER_MSGTYPE_DEVICEAUTHORIZATIONRESPONSE       4
349 #define STEAMDISCOVER_MSGTYPE_DEVICESTREAMINGREQUEST            5
350 #define STEAMDISCOVER_MSGTYPE_DEVICESTREAMINGRESPONSE           6
351 #define STEAMDISCOVER_MSGTYPE_DEVICEPROOFREQUEST                7
352 #define STEAMDISCOVER_MSGTYPE_DEVICEPROOFRESPONSE               8
353 #define STEAMDISCOVER_MSGTYPE_DEVICEAUTHORIZATIONCANCELREQUEST  9
354 #define STEAMDISCOVER_MSGTYPE_DEVICESTREAMINGCANCELREQUEST     10
355 #define STEAMDISCOVER_MSGTYPES_MAX                             10
356 
357 #define STEAMDISCOVER_ENSURE_WIRETYPE(X) if((len = protobuf_verify_wiretype(&pb, &tag, pinfo, tree, X))) break;
358 
359 /* Dissect the header section of a packet. The header is a
360  * CMsgRemoteClientBroadcastHeader protobuf message.
361  *
362  *     enum ERemoteClientBroadcastMsg {
363  *         k_ERemoteClientBroadcastMsgDiscovery = 0;
364  *         k_ERemoteClientBroadcastMsgStatus = 1;
365  *         k_ERemoteClientBroadcastMsgOffline = 2;
366  *         k_ERemoteDeviceAuthorizationRequest = 3;
367  *         k_ERemoteDeviceAuthorizationResponse = 4;
368  *         k_ERemoteDeviceStreamingRequest = 5;
369  *         k_ERemoteDeviceStreamingResponse = 6;
370  *         k_ERemoteDeviceProofRequest = 7;
371  *         k_ERemoteDeviceProofResponse = 8;
372  *         k_ERemoteDeviceAuthorizationCancelRequest = 9;
373  *         k_ERemoteDeviceStreamingCancelRequest = 10;
374  *     }
375  *
376  *     message CMsgRemoteClientBroadcastHeader {
377  *         optional uint64 client_id = 1;
378  *         optional ERemoteClientBroadcastMsg msg_type = 2;
379  *         optional uint64 instance_id = 3;
380  *     }
381  */
382 static gint64
steamdiscover_dissect_header(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint bytes_left)383 steamdiscover_dissect_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
384                              gint offset, gint bytes_left)
385 {
386     gint len;
387     gint64 value;
388     gint64 msg_type = -1;
389     protobuf_desc_t pb = { tvb, offset, bytes_left };
390     protobuf_tag_t tag = { 0, 0, 0 };
391     while (protobuf_iter_next(&pb, &tag)) {
392         switch(tag.field_number) {
393             case STEAMDISCOVER_FN_HEADER_CLIENTID:
394                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_VARINT);
395                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
396                 proto_tree_add_uint64(tree, hf_steam_ihs_discovery_header_clientid, pb.tvb,
397                         pb.offset, len, (guint64)value);
398                 break;
399             case STEAMDISCOVER_FN_HEADER_MSGTYPE:
400                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_VARINT);
401                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
402                 msg_type = value;
403                 proto_tree_add_uint64(tree, hf_steam_ihs_discovery_header_msgtype, pb.tvb,
404                         pb.offset, len, (guint64)value);
405                 break;
406             case STEAMDISCOVER_FN_HEADER_INSTANCEID:
407                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_VARINT);
408                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
409                 proto_tree_add_uint64(tree, hf_steam_ihs_discovery_header_instanceid, pb.tvb,
410                         pb.offset, len, (guint64)value);
411                 break;
412             default:
413                 len = protobuf_dissect_unknown_field(&pb, &tag, pinfo, tree, NULL);
414                 break;
415         }
416         protobuf_seek_forward(&pb, len);
417     }
418     return msg_type;
419 }
420 
421 /* Dissect a CMsgRemoteClientBroadcastDiscovery protobuf message body.
422  *
423  *     message CMsgRemoteClientBroadcastDiscovery {
424  *          optional uint32 seq_num = 1;
425  *          repeated uint64 client_ids = 2;
426  *     }
427  */
428 static void
steamdiscover_dissect_body_discovery(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint bytes_left)429 steamdiscover_dissect_body_discovery(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
430                                      gint offset, gint bytes_left)
431 {
432     gint len;
433     gint64 value;
434     protobuf_desc_t pb = { tvb, offset, bytes_left };
435     protobuf_tag_t tag = { 0, 0, 0 };
436     while (protobuf_iter_next(&pb, &tag)) {
437         switch(tag.field_number) {
438             case STEAMDISCOVER_FN_DISCOVERY_SEQNUM:
439                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_VARINT);
440                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
441                 proto_tree_add_uint(tree, hf_steam_ihs_discovery_body_discovery_seqnum, pb.tvb,
442                         pb.offset, len, (guint32)value);
443                 col_append_fstr(pinfo->cinfo, COL_INFO, " Seq=%"G_GUINT32_FORMAT, (guint32)value);
444                 break;
445             case STEAMDISCOVER_FN_DISCOVERY_CLIENTIDS:
446                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_VARINT);
447                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
448                 proto_tree_add_uint64(tree, hf_steam_ihs_discovery_body_discovery_clientids, pb.tvb,
449                         pb.offset, len, value);
450                 break;
451             default:
452                 len = protobuf_dissect_unknown_field(&pb, &tag, pinfo, tree, NULL);
453                 break;
454         }
455         protobuf_seek_forward(&pb, len);
456     }
457 }
458 
459 /* Dissect a CMsgRemoteClientBroadcastStatus protobuf message body.
460  *
461  *     message CMsgRemoteClientBroadcastStatus {
462  *         message User {
463  *             optional fixed64 steamid = 1;
464  *             optional uint32 auth_key_id = 2;
465  *         }
466  *         optional int32 version = 1;
467  *         optional int32 min_version = 2;
468  *         optional uint32 connect_port = 3;
469  *         optional string hostname = 4;
470  *         optional uint32 enabled_services = 6;
471  *         optional int32 ostype = 7 [default = 0];
472  *         optional bool is64bit = 8 [default = false];
473  *         repeated CMsgRemoteClientBroadcastStatus.User users = 9;
474  *         optional int32 euniverse = 11;
475  *         optional uint32 timestamp = 12;
476  *         optional bool screen_locked = 13;
477  *         optional bool games_running = 14;
478  *         repeated string mac_addresses = 15;
479  *         optional uint32 download_lan_peer_group = 16;
480  *         optional bool broadcasting_active = 17;
481  *         optional bool vr_active = 18;
482  *     }
483  */
484 static void
steamdiscover_dissect_body_status(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint bytes_left)485 steamdiscover_dissect_body_status(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
486                                      gint offset, gint bytes_left)
487 {
488     gint64 value;
489     gint len;
490     gint len2;
491     protobuf_desc_t pb = { tvb, offset, bytes_left };
492     protobuf_desc_t pb2 = { tvb, 0, 0 };
493     protobuf_tag_t tag = { 0, 0, 0 };
494     guint8 *hostname;
495     nstime_t timestamp;
496     proto_tree *user_tree;
497     proto_item *user_it;
498     while (protobuf_iter_next(&pb, &tag)) {
499         switch(tag.field_number) {
500             case STEAMDISCOVER_FN_STATUS_VERSION:
501                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_VARINT);
502                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
503                 proto_tree_add_int(tree, hf_steam_ihs_discovery_body_status_version, pb.tvb,
504                         pb.offset, len, (gint32)value);
505                 break;
506             case STEAMDISCOVER_FN_STATUS_MINVERSION:
507                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_VARINT);
508                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
509                 proto_tree_add_int(tree, hf_steam_ihs_discovery_body_status_minversion, pb.tvb,
510                         pb.offset, len, (gint32)value);
511                 break;
512             case STEAMDISCOVER_FN_STATUS_CONNECTPORT:
513                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_VARINT);
514                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
515                 proto_tree_add_uint(tree, hf_steam_ihs_discovery_body_status_connectport, pb.tvb,
516                         pb.offset, len, (guint32)value);
517                 break;
518             case STEAMDISCOVER_FN_STATUS_HOSTNAME:
519                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_LENGTHDELIMITED);
520                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
521                 proto_tree_add_item(tree, hf_steam_ihs_discovery_body_status_hostname, pb.tvb,
522                         pb.offset+len, (gint)value, ENC_UTF_8|ENC_NA);
523                 hostname = tvb_get_string_enc(pinfo->pool, pb.tvb, pb.offset+len, (gint)value, ENC_UTF_8);
524                 if(hostname && strlen(hostname)) {
525                     col_add_fstr(pinfo->cinfo, COL_INFO, "%s from %s", hf_steam_ihs_discovery_header_msgtype_strings[STEAMDISCOVER_MSGTYPE_CLIENTBROADCASTMSGSTATUS].strptr, hostname);
526                 }
527                 len += (gint)value;
528                 break;
529             case STEAMDISCOVER_FN_STATUS_ENABLEDSERVICES:
530                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_VARINT);
531                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
532                 proto_tree_add_uint(tree, hf_steam_ihs_discovery_body_status_enabledservices, pb.tvb,
533                         pb.offset, len, (guint32)value);
534                 break;
535             case STEAMDISCOVER_FN_STATUS_OSTYPE:
536                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_VARINT);
537                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
538                 proto_tree_add_int(tree, hf_steam_ihs_discovery_body_status_ostype, pb.tvb,
539                         pb.offset, len, (gint32)value);
540                 break;
541             case STEAMDISCOVER_FN_STATUS_IS64BIT:
542                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_VARINT);
543                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
544                 proto_tree_add_boolean(tree, hf_steam_ihs_discovery_body_status_is64bit, pb.tvb,
545                         pb.offset, len, (gint32)value);
546                 break;
547             case STEAMDISCOVER_FN_STATUS_USERS:
548                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_LENGTHDELIMITED);
549                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
550                 pb2.offset = pb.offset+len;
551                 pb2.bytes_left = (gint)value;
552                 len += (gint)value;
553                 user_tree = proto_tree_add_subtree(tree, pb.tvb, pb.offset, len, ett_steam_ihs_discovery_body_status_user, &user_it, "User");
554                 while (protobuf_iter_next(&pb2, &tag)) {
555                     switch(tag.field_number) {
556                         case STEAMDISCOVER_FN_STATUS_USER_STEAMID:
557                             if((len2 = protobuf_verify_wiretype(&pb2, &tag, pinfo, user_tree, PROTOBUF_WIRETYPE_64BIT))) break;
558                             len2 = 8;
559                             value = tvb_get_letoh64(pb2.tvb, pb2.offset);
560                             proto_tree_add_uint64(user_tree, hf_steam_ihs_discovery_body_status_user_steamid, pb2.tvb,
561                                     pb2.offset, len2, (guint64)value);
562                             proto_item_append_text(user_it, ", Steam ID: %"G_GUINT64_FORMAT, (guint64)value);
563                             break;
564                         case STEAMDISCOVER_FN_STATUS_USER_AUTHKEYID:
565                             if((len2 = protobuf_verify_wiretype(&pb2, &tag, pinfo, user_tree, PROTOBUF_WIRETYPE_VARINT))) break;
566                             value = get_varint64(pb2.tvb, pb2.offset, pb2.bytes_left, &len2);
567                             proto_tree_add_uint(user_tree, hf_steam_ihs_discovery_body_status_user_authkeyid, pb2.tvb,
568                                     pb2.offset, len2, (guint32)value);
569                             proto_item_append_text(user_it, ", Auth Key ID: %"G_GUINT32_FORMAT, (guint32)value);
570                             break;
571                         default:
572                             len2 = protobuf_dissect_unknown_field(&pb2, &tag, pinfo, tree, NULL);
573                             break;
574                     }
575                     protobuf_seek_forward(&pb2, len2);
576                 }
577                 break;
578             case STEAMDISCOVER_FN_STATUS_EUNIVERSE:
579                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_VARINT);
580                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
581                 proto_tree_add_int(tree, hf_steam_ihs_discovery_body_status_euniverse, pb.tvb,
582                         pb.offset, len, (gint32)value);
583                 break;
584             case STEAMDISCOVER_FN_STATUS_TIMESTAMP:
585                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_VARINT);
586                 timestamp.secs = (time_t)get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
587                 timestamp.nsecs = 0;
588                 proto_tree_add_time(tree, hf_steam_ihs_discovery_body_status_timestamp, pb.tvb,
589                         pb.offset, len, &timestamp);
590                 break;
591             case STEAMDISCOVER_FN_STATUS_SCREENLOCKED:
592                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_VARINT);
593                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
594                 proto_tree_add_boolean(tree, hf_steam_ihs_discovery_body_status_screenlocked, pb.tvb,
595                         pb.offset, len, (gint32)value);
596                 break;
597             case STEAMDISCOVER_FN_STATUS_GAMESRUNNING:
598                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_VARINT);
599                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
600                 proto_tree_add_boolean(tree, hf_steam_ihs_discovery_body_status_gamesrunning, pb.tvb,
601                         pb.offset, len, (gint32)value);
602                 break;
603             case STEAMDISCOVER_FN_STATUS_MACADDRESSES:
604                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_LENGTHDELIMITED);
605                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
606                 proto_tree_add_item(tree, hf_steam_ihs_discovery_body_status_macaddresses, pb.tvb,
607                         pb.offset+len, (gint)value, ENC_UTF_8|ENC_NA);
608                 len += (gint)value;
609                 break;
610             default:
611                 len = protobuf_dissect_unknown_field(&pb, &tag, pinfo, tree, NULL);
612                 break;
613         }
614         protobuf_seek_forward(&pb, len);
615     }
616 }
617 
618 /* Dissect a CMsgRemoteDeviceAuthorizationRequest protobuf message body.
619  *
620  *     message CMsgRemoteDeviceAuthorizationRequest {
621  *         message CKeyEscrow_Ticket {
622  *             optional bytes password = 1;
623  *             optional uint64 identifier = 2;
624  *             optional bytes payload = 3;
625  *             optional uint32 timestamp = 4;
626  *             optional CMsgRemoteDeviceAuthorizationRequest.EKeyEscrowUsage usage = 5;
627  *             optional string device_name = 6;
628  *             optional string device_model = 7;
629  *             optional string device_serial = 8;
630  *             optional uint32 device_provisioning_id = 9;
631  *         }
632  *         enum EKeyEscrowUsage {
633  *             k_EKeyEscrowUsageStreamingDevice = 0;
634  *         }
635  *         required bytes device_token = 1;
636  *         optional string device_name = 2;
637  *         required bytes encrypted_request = 3;
638  *     }
639  */
640 static void
steamdiscover_dissect_body_authrequest(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint bytes_left)641 steamdiscover_dissect_body_authrequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
642                                        gint offset, gint bytes_left)
643 {
644     guint len;
645     gint64 value;
646     protobuf_desc_t pb = { tvb, offset, bytes_left };
647     protobuf_tag_t tag = { 0, 0, 0 };
648     guint8* devicename;
649     while (protobuf_iter_next(&pb, &tag)) {
650         switch(tag.field_number) {
651             case STEAMDISCOVER_FN_AUTHREQUEST_DEVICETOKEN:
652                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_LENGTHDELIMITED);
653                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
654                 proto_tree_add_item(tree, hf_steam_ihs_discovery_body_authrequest_devicetoken, pb.tvb,
655                         pb.offset+len, (gint)value, ENC_NA);
656                 len += (gint)value;
657                 break;
658             case STEAMDISCOVER_FN_AUTHREQUEST_DEVICENAME:
659                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_LENGTHDELIMITED);
660                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
661                 proto_tree_add_item(tree, hf_steam_ihs_discovery_body_authrequest_devicename, pb.tvb,
662                         pb.offset+len, (gint)value, ENC_UTF_8|ENC_NA);
663                 devicename = tvb_get_string_enc(pinfo->pool, pb.tvb, pb.offset+len, (gint)value, ENC_UTF_8);
664                 if (devicename && strlen(devicename)) {
665                     col_append_fstr(pinfo->cinfo, COL_INFO, " from %s", devicename);
666                 }
667                 len += (gint)value;
668                 break;
669             case STEAMDISCOVER_FN_AUTHREQUEST_ENCRYPTEDREQUEST:
670                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_LENGTHDELIMITED);
671                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
672                 proto_tree_add_item(tree, hf_steam_ihs_discovery_body_authrequest_encryptedrequest, pb.tvb,
673                         pb.offset+len, (gint)value, ENC_NA);
674                 len += (gint)value;
675                 break;
676             default:
677                 len = protobuf_dissect_unknown_field(&pb, &tag, pinfo, tree, NULL);
678                 break;
679         }
680         protobuf_seek_forward(&pb, len);
681     }
682 }
683 
684 /* Dissect a CMsgRemoteDeviceAuthorizationResponse protobuf message body.
685  *
686  *     message CMsgRemoteDeviceAuthorizationResponse {
687  *         required ERemoteDeviceAuthorizationResult result = 1;
688  *     }
689  */
690 static void
steamdiscover_dissect_body_authresponse(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint bytes_left)691 steamdiscover_dissect_body_authresponse(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
692                                         gint offset, gint bytes_left)
693 {
694     gint len;
695     gint64 value;
696     protobuf_desc_t pb = { tvb, offset, bytes_left };
697     protobuf_tag_t tag = { 0, 0, 0 };
698     while (protobuf_iter_next(&pb, &tag)) {
699         switch(tag.field_number) {
700             case STEAMDISCOVER_FN_AUTHRESPONSE_AUTHRESULT:
701                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_VARINT);
702                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
703                 proto_tree_add_uint64(tree, hf_steam_ihs_discovery_body_authresponse_authresult, pb.tvb,
704                         pb.offset, len, (guint64)value);
705                 col_add_fstr(pinfo->cinfo, COL_INFO, "%s Result=%"G_GUINT64_FORMAT"(%s)", hf_steam_ihs_discovery_header_msgtype_strings[STEAMDISCOVER_MSGTYPE_DEVICEAUTHORIZATIONRESPONSE].strptr,
706                         (guint64)value, val64_to_str_const((guint64)value, hf_steam_ihs_discovery_body_authresponse_authresult_strings, "Unknown"));
707                 break;
708             default:
709                 len = protobuf_dissect_unknown_field(&pb, &tag, pinfo, tree, NULL);
710                 break;
711         }
712         protobuf_seek_forward(&pb, len);
713     }
714 }
715 
716 /* Dissect a CMsgRemoteDeviceStreamingRequest protobuf message body.
717  *
718  *     message CMsgRemoteDeviceStreamingRequest {
719  *         required uint32 request_id = 1;
720  *         optional int32 maximum_resolution_x = 2;
721  *         optional int32 maximum_resolution_y = 3;
722  *         optional int32 audio_channel_count = 4 [default = 2];
723  *         optional string device_version = 5;
724  *         optional bool stream_desktop = 6;
725  *         optional bytes device_token = 7;
726  *         optional bytes pin = 8;
727  *         optional bool enable_video_streaming = 9 [default = true];
728  *         optional bool enable_audio_streaming = 10 [default = true];
729  *         optional bool enable_input_streaming = 11 [default = true];
730  *     }
731  */
732 static void
steamdiscover_dissect_body_streamingrequest(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint bytes_left)733 steamdiscover_dissect_body_streamingrequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
734                                             gint offset, gint bytes_left)
735 {
736     gint len;
737     gint64 value;
738     protobuf_desc_t pb = { tvb, offset, bytes_left };
739     protobuf_tag_t tag = { 0, 0, 0 };
740     while (protobuf_iter_next(&pb, &tag)) {
741         switch(tag.field_number) {
742             case STEAMDISCOVER_FN_STREAMINGREQUEST_REQUESTID:
743                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_VARINT);
744                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
745                 proto_tree_add_uint(tree, hf_steam_ihs_discovery_body_streamingrequest_requestid, pb.tvb,
746                         pb.offset, len, (guint32)value);
747                 col_add_fstr(pinfo->cinfo, COL_INFO, "%s ID=%08x", hf_steam_ihs_discovery_header_msgtype_strings[STEAMDISCOVER_MSGTYPE_DEVICESTREAMINGREQUEST].strptr, (guint32)value);
748                 break;
749             case STEAMDISCOVER_FN_STREAMINGREQUEST_MAXIMUMRESOLUTIONX:
750                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_VARINT);
751                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
752                 proto_tree_add_int(tree, hf_steam_ihs_discovery_body_streamingrequest_maximumresolutionx, pb.tvb,
753                         pb.offset, len, (gint32)value);
754                 break;
755             case STEAMDISCOVER_FN_STREAMINGREQUEST_MAXIMUMRESOLUTIONY:
756                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_VARINT);
757                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
758                 proto_tree_add_int(tree, hf_steam_ihs_discovery_body_streamingrequest_maximumresolutiony, pb.tvb,
759                         pb.offset, len, (gint32)value);
760                 break;
761             case STEAMDISCOVER_FN_STREAMINGREQUEST_AUDIOCHANNELCOUNT:
762                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_VARINT);
763                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
764                 proto_tree_add_int(tree, hf_steam_ihs_discovery_body_streamingrequest_audiochannelcount, pb.tvb,
765                         pb.offset, len, (gint32)value);
766                 break;
767             case STEAMDISCOVER_FN_STREAMINGREQUEST_DEVICEVERSION:
768                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_LENGTHDELIMITED);
769                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
770                 proto_tree_add_item(tree, hf_steam_ihs_discovery_body_streamingrequest_deviceversion, pb.tvb, pb.offset+len, (gint)value, ENC_UTF_8|ENC_NA);
771                 len += (gint)value;
772                 break;
773             case STEAMDISCOVER_FN_STREAMINGREQUEST_STREAMDESKTOP:
774                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_VARINT);
775                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
776                 proto_tree_add_boolean(tree, hf_steam_ihs_discovery_body_streamingrequest_streamdesktop, pb.tvb,
777                         pb.offset, len, (gint32)value);
778                 break;
779             case STEAMDISCOVER_FN_STREAMINGREQUEST_DEVICETOKEN:
780                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_LENGTHDELIMITED);
781                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
782                 proto_tree_add_item(tree, hf_steam_ihs_discovery_body_streamingrequest_devicetoken, pb.tvb, pb.offset+len, (gint)value, ENC_NA);
783                 len += (gint)value;
784                 break;
785             case STEAMDISCOVER_FN_STREAMINGREQUEST_PIN:
786                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_LENGTHDELIMITED);
787                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
788                 proto_tree_add_item(tree, hf_steam_ihs_discovery_body_streamingrequest_pin, pb.tvb, pb.offset+len, (gint)value, ENC_NA);
789                 len += (gint)value;
790                 break;
791             case STEAMDISCOVER_FN_STREAMINGREQUEST_ENABLEVIDEOSTREAMING:
792                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_VARINT);
793                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
794                 proto_tree_add_boolean(tree, hf_steam_ihs_discovery_body_streamingrequest_enablevideostreaming, pb.tvb,
795                         pb.offset, len, (gint32)value);
796                 break;
797             case STEAMDISCOVER_FN_STREAMINGREQUEST_ENABLEAUDIOSTREAMING:
798                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_VARINT);
799                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
800                 proto_tree_add_boolean(tree, hf_steam_ihs_discovery_body_streamingrequest_enableaudiostreaming, pb.tvb,
801                         pb.offset, len, (gint32)value);
802                 break;
803             case STEAMDISCOVER_FN_STREAMINGREQUEST_ENABLEINPUTSTREAMING:
804                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_VARINT);
805                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
806                 proto_tree_add_boolean(tree, hf_steam_ihs_discovery_body_streamingrequest_enableinputstreaming, pb.tvb,
807                         pb.offset, len, (gint32)value);
808                 break;
809             default:
810                 len = protobuf_dissect_unknown_field(&pb, &tag, pinfo, tree, NULL);
811                 break;
812         }
813         protobuf_seek_forward(&pb, len);
814     }
815 }
816 
817 /* Dissect a CMsgRemoteDeviceStreamingCancelRequest protobuf message body.
818  *
819  *     message CMsgRemoteDeviceStreamingCancelRequest {
820  *         required uint32 request_id = 1;
821  *     }
822  */
823 static void
steamdiscover_dissect_body_streamingcancelrequest(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint bytes_left)824 steamdiscover_dissect_body_streamingcancelrequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
825                                                   gint offset, gint bytes_left)
826 {
827     guint len;
828     gint64 value;
829     protobuf_desc_t pb = { tvb, offset, bytes_left };
830     protobuf_tag_t tag = { 0, 0, 0 };
831     while (protobuf_iter_next(&pb, &tag)) {
832         switch(tag.field_number) {
833             case STEAMDISCOVER_FN_STREAMINGCANCELREQUEST_REQUESTID:
834                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_VARINT);
835                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
836                 proto_tree_add_uint(tree, hf_steam_ihs_discovery_body_streamingcancelrequest_requestid, pb.tvb,
837                         pb.offset, len, (guint32)value);
838                 col_add_fstr(pinfo->cinfo, COL_INFO, "%s, ID=%08x", hf_steam_ihs_discovery_header_msgtype_strings[STEAMDISCOVER_MSGTYPE_DEVICESTREAMINGCANCELREQUEST].strptr, (guint32)value);
839                 break;
840             default:
841                 len = protobuf_dissect_unknown_field(&pb, &tag, pinfo, tree, NULL);
842                 break;
843         }
844         protobuf_seek_forward(&pb, len);
845     }
846 }
847 
848 /* Dissect a CMsgRemoteDeviceStreamingResponse protobuf message body.
849  *
850  *     enum ERemoteDeviceStreamingResult {
851  *         k_ERemoteDeviceStreamingSuccess = 0;
852  *         k_ERemoteDeviceStreamingUnauthorized = 1;
853  *         k_ERemoteDeviceStreamingScreenLocked = 2;
854  *         k_ERemoteDeviceStreamingFailed = 3;
855  *         k_ERemoteDeviceStreamingBusy = 4;
856  *         k_ERemoteDeviceStreamingInProgress = 5;
857  *         k_ERemoteDeviceStreamingCanceled = 6;
858  *         k_ERemoteDeviceStreamingDriversNotInstalled = 7;
859  *         k_ERemoteDeviceStreamingDisabled = 8;
860  *         k_ERemoteDeviceStreamingBroadcastingActive = 9;
861  *         k_ERemoteDeviceStreamingVRActive = 10;
862  *         k_ERemoteDeviceStreamingPINRequired = 11;
863  *     }
864  *
865  *     message CMsgRemoteDeviceStreamingResponse {
866  *         required uint32 request_id = 1;
867  *         required ERemoteDeviceStreamingResult result = 2;
868  *         optional uint32 port = 3;
869  *         optional bytes encrypted_session_key = 4;
870  *         optional int32 virtualhere_licensed_device_count_OBSOLETE = 5;
871  *     }
872  */
873 static void
steamdiscover_dissect_body_streamingresponse(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint bytes_left)874 steamdiscover_dissect_body_streamingresponse(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
875                                                   gint offset, gint bytes_left)
876 {
877     guint len;
878     gint64 value;
879     protobuf_desc_t pb = { tvb, offset, bytes_left };
880     protobuf_tag_t tag = { 0, 0, 0 };
881     while (protobuf_iter_next(&pb, &tag)) {
882         switch(tag.field_number) {
883             case STEAMDISCOVER_FN_STREAMINGRESPONSE_REQUESTID:
884                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_VARINT);
885                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
886                 proto_tree_add_uint(tree, hf_steam_ihs_discovery_body_streamingresponse_requestid, pb.tvb,
887                         pb.offset, len, (guint32)value);
888                 col_append_fstr(pinfo->cinfo, COL_INFO, " ID=%08x", (guint32)value);
889                 break;
890             case STEAMDISCOVER_FN_STREAMINGRESPONSE_RESULT:
891                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_VARINT);
892                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
893                 proto_tree_add_uint64(tree, hf_steam_ihs_discovery_body_streamingresponse_result, pb.tvb,
894                         pb.offset, len, (guint64)value);
895                 col_append_fstr(pinfo->cinfo, COL_INFO, " Result=%"G_GUINT64_FORMAT"(%s)", (guint64)value, val64_to_str_const((guint64)value, hf_steam_ihs_discovery_body_streamingresponse_result_strings, "Unknown"));
896                 break;
897             case STEAMDISCOVER_FN_STREAMINGRESPONSE_PORT:
898                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_VARINT);
899                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
900                 proto_tree_add_uint(tree, hf_steam_ihs_discovery_body_streamingresponse_port, pb.tvb,
901                         pb.offset, len, (guint32)value);
902                 col_append_fstr(pinfo->cinfo, COL_INFO, " Port=%"G_GUINT32_FORMAT, (guint32)value);
903                 break;
904             case STEAMDISCOVER_FN_STREAMINGRESPONSE_ENCRYPTEDSESSIONKEY:
905                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_LENGTHDELIMITED);
906                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
907                 proto_tree_add_item(tree, hf_steam_ihs_discovery_body_streamingresponse_encryptedsessionkey, pb.tvb, pb.offset+len, (gint)value, ENC_NA);
908                 len += (gint)value;
909                 break;
910             case STEAMDISCOVER_FN_STREAMINGRESPONSE_VIRTUALHERELICENSEDDEVICECOUNT:
911                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_VARINT);
912                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
913                 proto_tree_add_int(tree, hf_steam_ihs_discovery_body_streamingresponse_virtualherelicenseddevicecount, pb.tvb,
914                         pb.offset, len, (gint32)value);
915                 break;
916             default:
917                 len = protobuf_dissect_unknown_field(&pb, &tag, pinfo, tree, NULL);
918                 break;
919         }
920         protobuf_seek_forward(&pb, len);
921     }
922 }
923 
924 /* Dissect a CMsgRemoteDeviceProofRequest protobuf message body.
925  *
926  *     message CMsgRemoteDeviceProofRequest {
927  *         required bytes challenge = 1;
928  *     }
929  */
930 static void
steamdiscover_dissect_body_proofrequest(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint bytes_left)931 steamdiscover_dissect_body_proofrequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
932                                                   gint offset, gint bytes_left)
933 {
934     gint len;
935     gint64 value;
936     protobuf_desc_t pb = { tvb, offset, bytes_left };
937     protobuf_tag_t tag = { 0, 0, 0 };
938     while (protobuf_iter_next(&pb, &tag)) {
939         switch(tag.field_number) {
940             case STEAMDISCOVER_FN_PROOFREQUEST_CHALLENGE:
941                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_LENGTHDELIMITED);
942                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
943                 proto_tree_add_item(tree, hf_steam_ihs_discovery_body_proofrequest_challenge, pb.tvb, pb.offset+len, (gint)value, ENC_NA);
944                 len += (gint)value;
945                 break;
946             default:
947                 len = protobuf_dissect_unknown_field(&pb, &tag, pinfo, tree, NULL);
948                 break;
949         }
950         protobuf_seek_forward(&pb, len);
951     }
952 }
953 
954 /* Dissect a CMsgRemoteDeviceProofResponse protobuf message body.
955  *
956  *     message CMsgRemoteDeviceProofResponse {
957  *         required bytes response = 1;
958  *     }
959  */
960 static void
steamdiscover_dissect_body_proofresponse(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint bytes_left)961 steamdiscover_dissect_body_proofresponse(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
962                                          gint offset, gint bytes_left)
963 {
964     gint len;
965     gint64 value;
966     protobuf_desc_t pb = { tvb, offset, bytes_left };
967     protobuf_tag_t tag = { 0, 0, 0 };
968     while (protobuf_iter_next(&pb, &tag)) {
969         switch(tag.field_number) {
970             case STEAMDISCOVER_FN_PROOFRESPONSE_RESPONSE:
971                 STEAMDISCOVER_ENSURE_WIRETYPE(PROTOBUF_WIRETYPE_LENGTHDELIMITED);
972                 value = get_varint64(pb.tvb, pb.offset, pb.bytes_left, &len);
973                 proto_tree_add_item(tree, hf_steam_ihs_discovery_body_proofresponse_response, pb.tvb, pb.offset+len, (gint)value, ENC_NA);
974                 len += (gint)value;
975                 break;
976             default:
977                 len = protobuf_dissect_unknown_field(&pb, &tag, pinfo, tree, NULL);
978                 break;
979         }
980         protobuf_seek_forward(&pb, len);
981     }
982 }
983 
984 static void
steamdiscover_dissect_body_unknown(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint bytes_left)985 steamdiscover_dissect_body_unknown(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
986                                          gint offset, gint bytes_left)
987 {
988     gint len;
989     protobuf_desc_t pb = { tvb, offset, bytes_left };
990     protobuf_tag_t tag = { 0, 0, 0 };
991     while (protobuf_iter_next(&pb, &tag)) {
992         len = protobuf_dissect_unknown_field(&pb, &tag, pinfo, tree, NULL);
993         protobuf_seek_forward(&pb, len);
994     }
995 }
996 
997 /* Code to actually dissect the packets */
998 static int
dissect_steam_ihs_discovery(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)999 dissect_steam_ihs_discovery(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1000         void *data _U_)
1001 {
1002     /* Set up structures needed to add the protocol subtree and manage it */
1003     proto_item *ti;
1004     proto_tree *steam_ihs_discovery_tree;
1005     /* Other misc. local variables. */
1006     gint offset = 0;
1007     gint header_length = 0;
1008     gint body_length = 0;
1009     gint total_length = 0;
1010     gint64 msg_type;
1011 
1012     /* Check that the packet is long enough for it to belong to us. */
1013     if (tvb_reported_length(tvb) < STEAM_IHS_DISCOVERY_MIN_LENGTH)
1014         return 0;
1015 
1016     if (tvb_captured_length(tvb) < STEAM_IHS_DISCOVERY_MIN_LENGTH)
1017         return 0;
1018 
1019     /* Check if packet starts with the 8 byte signature value. */
1020     if (tvb_get_ntoh64(tvb, 0) != STEAM_IHS_DISCOVERY_SIGNATURE_VALUE)
1021         return 0;
1022 
1023     /* Parse header and body lengths.
1024      *
1025      * A packet looks like this:
1026      *   1. Signature Value (8 bytes)
1027      *   2. Header length (4 bytes)
1028      *   3. Header
1029      *   4. Body length (4 bytes)
1030      *   6. Body
1031      * */
1032     header_length = tvb_get_letohl(tvb, STEAM_IHS_DISCOVERY_SIGNATURE_LENGTH);
1033     body_length = tvb_get_letohl(tvb, STEAM_IHS_DISCOVERY_SIGNATURE_LENGTH + 4 + header_length);
1034     total_length = STEAM_IHS_DISCOVERY_SIGNATURE_LENGTH + 4 + header_length + 4 + body_length;
1035 
1036     /* Check if expected and captured packet length are equal. */
1037     if (tvb_reported_length(tvb) != (guint)total_length)
1038         return 0;
1039 
1040     if (tvb_captured_length(tvb) != (guint)total_length)
1041         return 0;
1042 
1043     /* Set the Protocol column to the constant string of steam_ihs_discovery */
1044     col_set_str(pinfo->cinfo, COL_PROTOCOL, "STEAMDISCOVER");
1045 
1046     col_clear(pinfo->cinfo, COL_INFO);
1047 
1048     /* create display subtree for the protocol */
1049     ti = proto_tree_add_item(tree, proto_steam_ihs_discovery, tvb, 0, -1, ENC_NA);
1050 
1051     steam_ihs_discovery_tree = proto_item_add_subtree(ti, ett_steam_ihs_discovery);
1052 
1053     proto_tree_add_item(steam_ihs_discovery_tree, hf_steam_ihs_discovery_signature, tvb,
1054             offset, STEAM_IHS_DISCOVERY_SIGNATURE_LENGTH, ENC_LITTLE_ENDIAN);
1055     offset += STEAM_IHS_DISCOVERY_SIGNATURE_LENGTH;
1056 
1057     proto_tree_add_item(steam_ihs_discovery_tree, hf_steam_ihs_discovery_header_length, tvb,
1058             offset, 4, ENC_LITTLE_ENDIAN);
1059     offset += 4;
1060 
1061     msg_type = steamdiscover_dissect_header(tvb, pinfo, steam_ihs_discovery_tree, offset, header_length);
1062 
1063     if ((0 <= msg_type) && (msg_type <= STEAMDISCOVER_MSGTYPES_MAX)) {
1064         col_set_str(pinfo->cinfo, COL_INFO, hf_steam_ihs_discovery_header_msgtype_strings[msg_type].strptr);
1065     } else {
1066         col_set_str(pinfo->cinfo, COL_INFO, "Unknown Message");
1067     }
1068 
1069     offset += header_length;
1070 
1071     proto_tree_add_item(steam_ihs_discovery_tree, hf_steam_ihs_discovery_body_length, tvb,
1072             offset, 4, ENC_LITTLE_ENDIAN);
1073     offset += 4;
1074 
1075     switch(msg_type)
1076     {
1077         case STEAMDISCOVER_MSGTYPE_CLIENTBROADCASTMSGDISCOVERY:
1078             steamdiscover_dissect_body_discovery(tvb, pinfo, steam_ihs_discovery_tree, offset, body_length);
1079             break;
1080         case STEAMDISCOVER_MSGTYPE_CLIENTBROADCASTMSGSTATUS:
1081             steamdiscover_dissect_body_status(tvb, pinfo, steam_ihs_discovery_tree, offset, body_length);
1082             break;
1083         case STEAMDISCOVER_MSGTYPE_CLIENTBROADCASTMSGOFFLINE:
1084             /* Message seems to have no body */
1085             break;
1086         case STEAMDISCOVER_MSGTYPE_DEVICEAUTHORIZATIONREQUEST:
1087             steamdiscover_dissect_body_authrequest(tvb, pinfo, steam_ihs_discovery_tree, offset, body_length);
1088             break;
1089         case STEAMDISCOVER_MSGTYPE_DEVICEAUTHORIZATIONCANCELREQUEST:
1090             /* Message seems to have no body */
1091             break;
1092         case STEAMDISCOVER_MSGTYPE_DEVICEAUTHORIZATIONRESPONSE:
1093             steamdiscover_dissect_body_authresponse(tvb, pinfo, steam_ihs_discovery_tree, offset, body_length);
1094             break;
1095         case STEAMDISCOVER_MSGTYPE_DEVICESTREAMINGREQUEST:
1096             steamdiscover_dissect_body_streamingrequest(tvb, pinfo, steam_ihs_discovery_tree, offset, body_length);
1097             break;
1098         case STEAMDISCOVER_MSGTYPE_DEVICESTREAMINGCANCELREQUEST:
1099             steamdiscover_dissect_body_streamingcancelrequest(tvb, pinfo, steam_ihs_discovery_tree, offset, body_length);
1100             break;
1101         case STEAMDISCOVER_MSGTYPE_DEVICESTREAMINGRESPONSE:
1102             steamdiscover_dissect_body_streamingresponse(tvb, pinfo, steam_ihs_discovery_tree, offset, body_length);
1103             break;
1104         case STEAMDISCOVER_MSGTYPE_DEVICEPROOFREQUEST:
1105             steamdiscover_dissect_body_proofrequest(tvb, pinfo, steam_ihs_discovery_tree, offset, body_length);
1106             break;
1107         case STEAMDISCOVER_MSGTYPE_DEVICEPROOFRESPONSE:
1108             steamdiscover_dissect_body_proofresponse(tvb, pinfo, steam_ihs_discovery_tree, offset, body_length);
1109             break;
1110         default:
1111             steamdiscover_dissect_body_unknown(tvb, pinfo, steam_ihs_discovery_tree, offset, body_length);
1112             break;
1113     }
1114 
1115     return tvb_captured_length(tvb);
1116 }
1117 
1118 /* Register the protocol with Wireshark. */
1119 void
proto_register_steam_ihs_discovery(void)1120 proto_register_steam_ihs_discovery(void)
1121 {
1122     module_t        *steam_ihs_discovery_module;
1123     expert_module_t *expert_steam_ihs_discovery;
1124 
1125     static hf_register_info hf[] = {
1126         /* Non-protobuf header fields */
1127         { &hf_steam_ihs_discovery_signature,
1128           { "Signature", "steam_ihs_discovery.signature",
1129             FT_UINT64, BASE_HEX, NULL, 0,
1130             "Every packet of the Steam In-Home Streaming Discovery Protocol begins with this signature.", HFILL }
1131         },
1132         { &hf_steam_ihs_discovery_header_length,
1133           { "Header Length", "steam_ihs_discovery.header_length",
1134             FT_UINT32, BASE_DEC, NULL, 0,
1135             NULL, HFILL }
1136         },
1137         { &hf_steam_ihs_discovery_body_length,
1138           { "Body Length", "steam_ihs_discovery.body_length",
1139             FT_UINT32, BASE_DEC, NULL, 0,
1140             NULL, HFILL }
1141         },
1142         { &hf_steam_ihs_discovery_unknown_data,
1143           { "Unknown Data", "steam_ihs_discovery.unknown_data",
1144             FT_BYTES, BASE_NONE, NULL, 0,
1145             NULL, HFILL }
1146         },
1147         { &hf_steam_ihs_discovery_unknown_number,
1148           { "Unknown Number", "steam_ihs_discovery.unknown_number",
1149             FT_UINT64, BASE_DEC_HEX, NULL, 0,
1150             NULL, HFILL }
1151         },
1152         /* CMsgRemoteClientBroadcastHeader */
1153         { &hf_steam_ihs_discovery_header_clientid,
1154           { "Client ID", "steam_ihs_discovery.header_client_id",
1155             FT_UINT64, BASE_DEC_HEX, NULL, 0,
1156             NULL, HFILL }
1157         },
1158         { &hf_steam_ihs_discovery_header_msgtype,
1159           { "Message Type", "steam_ihs_discovery.header_msg_type",
1160             FT_UINT64, BASE_DEC|BASE_VAL64_STRING, VALS64(hf_steam_ihs_discovery_header_msgtype_strings), 0,
1161             NULL, HFILL }
1162         },
1163         { &hf_steam_ihs_discovery_header_instanceid,
1164           { "Instance ID", "steam_ihs_discovery.header_instance_id",
1165             FT_UINT64, BASE_DEC_HEX, NULL, 0,
1166             NULL, HFILL }
1167         },
1168         /* CMsgRemoteClientBroadcastDiscovery message */
1169         { &hf_steam_ihs_discovery_body_discovery_seqnum,
1170           { "Sequence Number", "steam_ihs_discovery.body_discovery_seqnum",
1171             FT_UINT32, BASE_DEC, NULL, 0,
1172             NULL, HFILL }
1173         },
1174         { &hf_steam_ihs_discovery_body_discovery_clientids,
1175           { "Client IDs", "steam_ihs_discovery.body_discovery_clientids",
1176             FT_UINT64, BASE_HEX, NULL, 0,
1177             NULL, HFILL }
1178         },
1179         /* CMsgRemoteClientBroadcastStatus message */
1180         { &hf_steam_ihs_discovery_body_status_version,
1181           { "Version", "steam_ihs_discovery.body_status_version",
1182             FT_INT32, BASE_DEC, NULL, 0,
1183             NULL, HFILL }
1184         },
1185         { &hf_steam_ihs_discovery_body_status_minversion,
1186           { "Minimum Version", "steam_ihs_discovery.body_status_minversion",
1187             FT_INT32, BASE_DEC, NULL, 0,
1188             NULL, HFILL }
1189         },
1190         { &hf_steam_ihs_discovery_body_status_connectport,
1191           { "Connect Port", "steam_ihs_discovery.body_status_connectport",
1192             FT_UINT32, BASE_DEC, NULL, 0,
1193             NULL, HFILL }
1194         },
1195         { &hf_steam_ihs_discovery_body_status_hostname,
1196           { "Hostname", "steam_ihs_discovery.body_status_hostname",
1197             FT_STRING, STR_UNICODE, NULL, 0,
1198             NULL, HFILL }
1199         },
1200         { &hf_steam_ihs_discovery_body_status_enabledservices,
1201           { "Enabled Services", "steam_ihs_discovery.body_status_enabledservices",
1202             FT_UINT32, BASE_HEX, NULL, 0,
1203             NULL, HFILL }
1204         },
1205         { &hf_steam_ihs_discovery_body_status_ostype,
1206           { "OS Type", "steam_ihs_discovery.body_status_ostype",
1207             FT_INT32, BASE_DEC, NULL, 0,
1208             NULL, HFILL }
1209         },
1210         { &hf_steam_ihs_discovery_body_status_is64bit,
1211           { "Is 64 Bit", "steam_ihs_discovery.body_status_is64bit",
1212             FT_BOOLEAN, BASE_NONE, NULL, 0,
1213             NULL, HFILL }
1214         },
1215         { &hf_steam_ihs_discovery_body_status_euniverse,
1216           { "EUniverse", "steam_ihs_discovery.body_status_euniverse",
1217             FT_INT32, BASE_DEC, NULL, 0,
1218             NULL, HFILL }
1219         },
1220         { &hf_steam_ihs_discovery_body_status_timestamp,
1221           { "Timestamp", "steam_ihs_discovery.body_status_timestamp",
1222             FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0,
1223             NULL, HFILL }
1224         },
1225         { &hf_steam_ihs_discovery_body_status_screenlocked,
1226           { "Screen Locked", "steam_ihs_discovery.body_status_screenlocked",
1227             FT_BOOLEAN, BASE_NONE, NULL, 0,
1228             NULL, HFILL }
1229         },
1230         { &hf_steam_ihs_discovery_body_status_gamesrunning,
1231           { "Games Running", "steam_ihs_discovery.body_status_gamesrunning",
1232             FT_BOOLEAN, BASE_NONE, NULL, 0,
1233             NULL, HFILL }
1234         },
1235         { &hf_steam_ihs_discovery_body_status_macaddresses,
1236           { "MAC Addresses", "steam_ihs_discovery.body_status_macaddresses",
1237             FT_STRING, STR_ASCII, NULL, 0,
1238             NULL, HFILL }
1239         },
1240         /* CMsgRemoteClientBroadcastStatus.User */
1241         { &hf_steam_ihs_discovery_body_status_user_steamid,
1242           { "Steam ID", "steam_ihs_discovery.body_status_user_steamid",
1243             FT_UINT64, BASE_DEC, NULL, 0,
1244             NULL, HFILL }
1245         },
1246         { &hf_steam_ihs_discovery_body_status_user_authkeyid,
1247           { "Auth Key ID", "steam_ihs_discovery.body_status_user_authkeyid",
1248             FT_UINT32, BASE_DEC, NULL, 0,
1249             NULL, HFILL }
1250         },
1251         /* CMsgRemoteDeviceAuthorizationRequest */
1252         { &hf_steam_ihs_discovery_body_authrequest_devicetoken,
1253           { "Device Token", "steam_ihs_discovery.body_authrequest_devicetoken",
1254             FT_BYTES, BASE_NONE, NULL, 0,
1255             NULL, HFILL }
1256         },
1257         { &hf_steam_ihs_discovery_body_authrequest_devicename,
1258           { "Device Name", "steam_ihs_discovery.body_authrequest_devicename",
1259             FT_STRING, STR_UNICODE, NULL, 0,
1260             NULL, HFILL }
1261         },
1262         { &hf_steam_ihs_discovery_body_authrequest_encryptedrequest,
1263           { "Encrypted Request", "steam_ihs_discovery.body_authrequest_encryptedrequest",
1264             FT_BYTES, BASE_NO_DISPLAY_VALUE, NULL, 0,
1265             NULL, HFILL }
1266         },
1267         /* CMsgRemoteDeviceAuthorizationResponse */
1268         { &hf_steam_ihs_discovery_body_authresponse_authresult,
1269           { "Result", "steam_ihs_discovery.body_authresponse_authresult",
1270             FT_UINT64, BASE_DEC|BASE_VAL64_STRING, VALS64(hf_steam_ihs_discovery_body_authresponse_authresult_strings), 0,
1271             NULL, HFILL }
1272         },
1273         /* CMsgRemoteDeviceStreamingRequest */
1274         { &hf_steam_ihs_discovery_body_streamingrequest_requestid,
1275           { "Request ID", "steam_ihs_discovery.body_streamingrequest_requestid",
1276             FT_UINT32, BASE_HEX, NULL, 0,
1277             NULL, HFILL }
1278         },
1279         { &hf_steam_ihs_discovery_body_streamingrequest_maximumresolutionx,
1280           { "Maximum Resolution X", "steam_ihs_discovery.body_streamingrequest_maximumresolutionx",
1281             FT_INT32, BASE_DEC, NULL, 0,
1282             NULL, HFILL }
1283         },
1284         { &hf_steam_ihs_discovery_body_streamingrequest_maximumresolutiony,
1285           { "Maximum Resolution Y", "steam_ihs_discovery.body_streamingrequest_maximumresolutiony",
1286             FT_INT32, BASE_DEC, NULL, 0,
1287             NULL, HFILL }
1288         },
1289         { &hf_steam_ihs_discovery_body_streamingrequest_audiochannelcount,
1290           { "Audio Channel Count", "steam_ihs_discovery.body_streamingrequest_audiochannelcount",
1291             FT_INT32, BASE_DEC, NULL, 0,
1292             NULL, HFILL }
1293         },
1294         { &hf_steam_ihs_discovery_body_streamingrequest_deviceversion,
1295           { "Device Version", "steam_ihs_discovery.body_streamingrequest_deviceversion",
1296             FT_STRING, STR_UNICODE, NULL, 0,
1297             NULL, HFILL }
1298         },
1299         { &hf_steam_ihs_discovery_body_streamingrequest_streamdesktop,
1300           { "Stream Desktop", "steam_ihs_discovery.body_streamingrequest_streamdesktop",
1301             FT_BOOLEAN, BASE_NONE, NULL, 0,
1302             NULL, HFILL }
1303         },
1304         { &hf_steam_ihs_discovery_body_streamingrequest_devicetoken,
1305           { "Device Token", "steam_ihs_discovery.body_streamingrequest_devicetoken",
1306             FT_BYTES, BASE_NONE, NULL, 0,
1307             NULL, HFILL }
1308         },
1309         { &hf_steam_ihs_discovery_body_streamingrequest_pin,
1310           { "PIN", "steam_ihs_discovery.body_streamingrequest_pin",
1311             FT_BYTES, BASE_NONE, NULL, 0,
1312             NULL, HFILL }
1313         },
1314         { &hf_steam_ihs_discovery_body_streamingrequest_enablevideostreaming,
1315           { "Enable Video Streaming", "steam_ihs_discovery.body_streamingrequest_enablevideostreaming",
1316             FT_BOOLEAN, BASE_NONE, NULL, 0,
1317             NULL, HFILL }
1318         },
1319         { &hf_steam_ihs_discovery_body_streamingrequest_enableaudiostreaming,
1320           { "Enable Audio Streaming", "steam_ihs_discovery.body_streamingrequest_enableaudiostreaming",
1321             FT_BOOLEAN, BASE_NONE, NULL, 0,
1322             NULL, HFILL }
1323         },
1324         { &hf_steam_ihs_discovery_body_streamingrequest_enableinputstreaming,
1325           { "Enable Input Streaming", "steam_ihs_discovery.body_streamingrequest_enableinputstreaming",
1326             FT_BOOLEAN, BASE_NONE, NULL, 0,
1327             NULL, HFILL }
1328         },
1329         /* CMsgRemoteDeviceStreamingCancelRequest */
1330         { &hf_steam_ihs_discovery_body_streamingcancelrequest_requestid,
1331           { "Request ID", "steam_ihs_discovery.body_streamingcancelrequest_requestid",
1332             FT_UINT32, BASE_HEX, NULL, 0,
1333             NULL, HFILL }
1334         },
1335         /* CMsgRemoteDeviceStreamingResponse */
1336         { &hf_steam_ihs_discovery_body_streamingresponse_requestid,
1337           { "Request ID", "steam_ihs_discovery.body_streamingresponse_requestid",
1338             FT_UINT32, BASE_HEX, NULL, 0,
1339             NULL, HFILL }
1340         },
1341         { &hf_steam_ihs_discovery_body_streamingresponse_result,
1342           { "Result", "steam_ihs_discovery.body_streamingresponse_result",
1343             FT_UINT64, BASE_DEC|BASE_VAL64_STRING, VALS64(hf_steam_ihs_discovery_body_streamingresponse_result_strings), 0,
1344             NULL, HFILL }
1345         },
1346         { &hf_steam_ihs_discovery_body_streamingresponse_port,
1347           { "Port", "steam_ihs_discovery.body_streamingresponse_port",
1348             FT_UINT32, BASE_DEC, NULL, 0,
1349             NULL, HFILL }
1350         },
1351         { &hf_steam_ihs_discovery_body_streamingresponse_encryptedsessionkey,
1352           { "Encrypted Session Key", "steam_ihs_discovery.body_streamingresponse_encryptedsessionkey",
1353             FT_BYTES, BASE_NONE, NULL, 0,
1354             NULL, HFILL }
1355         },
1356         { &hf_steam_ihs_discovery_body_streamingresponse_virtualherelicenseddevicecount,
1357           { "VirtualHere Licensed Device Count", "steam_ihs_discovery.body_streamingresponse_virtualherelicenseddevicecount",
1358             FT_INT32, BASE_DEC, NULL, 0,
1359             NULL, HFILL }
1360         },
1361         /* CMsgRemoteDeviceProofRequest */
1362         { &hf_steam_ihs_discovery_body_proofrequest_challenge,
1363           { "Challenge", "steam_ihs_discovery.body_proofrequest_challenge",
1364             FT_BYTES, BASE_NONE, NULL, 0,
1365             NULL, HFILL }
1366         },
1367         /* CMsgRemoteDeviceProofResponse */
1368         { &hf_steam_ihs_discovery_body_proofresponse_response,
1369           { "Response", "steam_ihs_discovery.body_proofresponse_response",
1370             FT_BYTES, BASE_NONE, NULL, 0,
1371             NULL, HFILL }
1372         }
1373     };
1374 
1375     /* Setup protocol subtree array */
1376     static gint *ett[] = {
1377         &ett_steam_ihs_discovery,
1378         &ett_steam_ihs_discovery_body_status_user
1379     };
1380 
1381     /* Setup protocol expert items */
1382     static ei_register_info ei[] = {
1383         { &ei_steam_ihs_discovery_unknown_data,
1384           { "steam_ihs_discovery.unknowndata", PI_UNDECODED, PI_WARN,
1385             "Unknown data section", EXPFILL }
1386         },
1387         { &ei_steam_ihs_discovery_unknown_number,
1388           { "steam_ihs_discovery.unknownnumber", PI_UNDECODED, PI_WARN,
1389             "Unknown numeric protobuf field", EXPFILL }
1390         },
1391         { &ei_steam_ihs_discovery_unknown_lengthdelimited,
1392           { "steam_ihs_discovery.unknownlengthdelimited", PI_UNDECODED, PI_WARN,
1393             "Unknown length-delimited protobuf field", EXPFILL }
1394         },
1395         { &ei_steam_ihs_discovery_invalid_wiretype,
1396           { "steam_ihs_discovery.invalid_wiretype", PI_MALFORMED, PI_ERROR,
1397             "Unexpected wire type", EXPFILL }
1398         },
1399         { &ei_steam_ihs_discovery_invalid_length,
1400           { "steam_ihs_discovery.invalid_length", PI_MALFORMED, PI_ERROR,
1401             "Length-delimited field has invalid length", EXPFILL }
1402         }
1403     };
1404 
1405     /* Register the protocol name and description */
1406     proto_steam_ihs_discovery = proto_register_protocol("Steam In-Home Streaming Discovery Protocol",
1407             "Steam IHS Discovery", "steam_ihs_discovery");
1408 
1409     /* Required function calls to register the header fields and subtrees */
1410     proto_register_field_array(proto_steam_ihs_discovery, hf, array_length(hf));
1411     proto_register_subtree_array(ett, array_length(ett));
1412 
1413     /* Required function calls to register expert items */
1414     expert_steam_ihs_discovery = expert_register_protocol(proto_steam_ihs_discovery);
1415     expert_register_field_array(expert_steam_ihs_discovery, ei, array_length(ei));
1416 
1417     /* Register a preferences module. */
1418     steam_ihs_discovery_module = prefs_register_protocol(proto_steam_ihs_discovery,
1419             proto_reg_handoff_steam_ihs_discovery);
1420 
1421     /* Register an example port preference */
1422     prefs_register_uint_preference(steam_ihs_discovery_module, "udp.port", "steam_ihs_discovery UDP Port",
1423             " Steam IHS Discovery UDP port if other than the default",
1424             10, &udp_port_pref);
1425 }
1426 
1427 void
proto_reg_handoff_steam_ihs_discovery(void)1428 proto_reg_handoff_steam_ihs_discovery(void)
1429 {
1430     static gboolean initialized = FALSE;
1431     static dissector_handle_t steam_ihs_discovery_handle;
1432     static int current_port;
1433 
1434     if (!initialized) {
1435         steam_ihs_discovery_handle = create_dissector_handle(dissect_steam_ihs_discovery,
1436                 proto_steam_ihs_discovery);
1437         initialized = TRUE;
1438 
1439     } else {
1440         dissector_delete_uint("udp.port", current_port, steam_ihs_discovery_handle);
1441     }
1442 
1443     current_port = udp_port_pref;
1444 
1445     dissector_add_uint("udp.port", current_port, steam_ihs_discovery_handle);
1446 }
1447 
1448 /*
1449  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1450  *
1451  * Local variables:
1452  * c-basic-offset: 4
1453  * tab-width: 8
1454  * indent-tabs-mode: nil
1455  * End:
1456  *
1457  * vi: set shiftwidth=4 tabstop=8 expandtab:
1458  * :indentSize=4:tabSize=8:noTabs=true:
1459  */
1460