Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-someip-sd.c
blobdb1f643d63990a576bfb2f4c3221a243befa0a38
1 /* packet-someip-sd.c
2 * SOME/IP-SD dissector.
3 * By Dr. Lars Voelker <lars.voelker@technica-engineering.de> / <lars.voelker@bmw.de>
4 * Copyright 2012-2024 Dr. Lars Voelker
5 * Copyright 2020 Ayoub Kaanich
6 * Copyright 2019 Ana Pantar
7 * Copyright 2019 Guenter Ebermann
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * SPDX-License-Identifier: GPL-2.0-or-later
16 #include <config.h>
18 #include <epan/prefs.h>
19 #include <epan/expert.h>
20 #include <epan/to_str.h>
21 #include <epan/stats_tree.h>
22 #include <epan/tfs.h>
23 #include <wsutil/array.h>
24 #include "packet-udp.h"
25 #include "packet-someip.h"
28 * Dissector for SOME/IP Service Discovery (SOME/IP-SD).
30 * See
31 * http://www.some-ip.com
34 #define SOMEIP_SD_NAME "SOME/IP-SD"
35 #define SOMEIP_SD_NAME_LONG "SOME/IP Service Discovery Protocol"
36 #define SOMEIP_SD_NAME_FILTER "someipsd"
38 #define SOMEIP_SD_MESSAGEID 0xffff8100
39 #define SOMEIP_SD_SERVICE_ID_OTHER_SERVICE 0xfffe
42 /* Header */
43 #define SOMEIP_SD_REBOOT_FLAG 0x80
44 #define SOMEIP_SD_UNICAST_FLAG 0x40
45 #define SOMEIP_SD_EXPL_INIT_EVENT_REQ_FLAG 0x20
46 #define SOMEIP_SD_MIN_LENGTH 12
48 /* Entries */
49 #define SD_ENTRY_LENGTH 16
51 #define SD_ENTRY_UNKNOWN 0x00
52 #define SD_ENTRY_SERVICE 0x01
53 #define SD_ENTRY_EVENTGROUP 0x02
54 /* TTL>0 */
55 #define SD_ENTRY_FIND_SERVICE 0x00
56 #define SD_ENTRY_OFFER_SERVICE 0x01
57 #define SD_ENTRY_SUBSCRIBE_EVENTGROUP 0x06
58 #define SD_ENTRY_SUBSCRIBE_EVENTGROUP_ACK 0x07
59 /* TTL=0 */
60 #define SD_ENTRY_STOP_OFFER_SERVICE 0x01
61 #define SD_ENTRY_STOP_SUBSCRIBE_EVENTGROUP 0x06
62 #define SD_ENTRY_SUBSCRIBE_EVENTGROUP_NACK 0x07
64 #define SD_EVENTGROUP_ENTRY_COUNTER_MASK 0x0f
65 #define SD_EVENTGROUP_ENTRY_RES2_MASK 0x70
66 #define SD_ENTRY_INIT_EVENT_REQ_MASK 0x80
68 /* Options */
69 #define SD_OPTION_MINLENGTH 3
70 #define SD_OPTION_IPV4_LENGTH 12
71 #define SD_OPTION_IPV6_LENGTH 24
73 #define SD_OPTION_UNKNOWN 0x00
74 #define SD_OPTION_CONFIGURATION 0x01
75 #define SD_OPTION_LOADBALANCING 0x02
76 #define SD_OPTION_IPV4_ENDPOINT 0x04
77 #define SD_OPTION_IPV6_ENDPOINT 0x06
78 #define SD_OPTION_IPV4_MULTICAST 0x14
79 #define SD_OPTION_IPV6_MULTICAST 0x16
80 #define SD_OPTION_IPV4_SD_ENDPOINT 0x24
81 #define SD_OPTION_IPV6_SD_ENDPOINT 0x26
83 #define SD_OPTION_L4PROTO_TCP 6
84 #define SD_OPTION_L4PROTO_UDP 17
86 /* option start 0..255, num 0..15 -> 0..270 */
87 #define SD_MAX_NUM_OPTIONS 271
89 /* ID wireshark identifies the dissector by */
90 static int proto_someip_sd;
92 /* header field */
93 static int hf_someip_sd_flags;
94 static int hf_someip_sd_rebootflag;
95 static int hf_someip_sd_unicastflag;
96 static int hf_someip_sd_explicitiniteventflag;
97 static int hf_someip_sd_reserved;
99 static int hf_someip_sd_length_entriesarray;
100 static int hf_someip_sd_entries;
102 static int hf_someip_sd_entry;
103 static int hf_someip_sd_entry_type;
104 static int hf_someip_sd_entry_type_offerservice;
105 static int hf_someip_sd_entry_type_stopofferservice;
106 static int hf_someip_sd_entry_type_findservice;
107 static int hf_someip_sd_entry_type_subscribeeventgroup;
108 static int hf_someip_sd_entry_type_stopsubscribeeventgroup;
109 static int hf_someip_sd_entry_type_subscribeeventgroupack;
110 static int hf_someip_sd_entry_type_subscribeeventgroupnack;
111 static int hf_someip_sd_entry_index1;
112 static int hf_someip_sd_entry_index2;
113 static int hf_someip_sd_entry_numopt1;
114 static int hf_someip_sd_entry_numopt2;
115 static int hf_someip_sd_entry_opts_referenced;
116 static int hf_someip_sd_entry_serviceid;
117 static int hf_someip_sd_entry_servicename;
118 static int hf_someip_sd_entry_instanceid;
119 static int hf_someip_sd_entry_majorver;
120 static int hf_someip_sd_entry_ttl;
121 static int hf_someip_sd_entry_minorver;
122 static int hf_someip_sd_entry_eventgroupid;
123 static int hf_someip_sd_entry_eventgroupname;
124 static int hf_someip_sd_entry_reserved;
125 static int hf_someip_sd_entry_counter;
126 static int hf_someip_sd_entry_intial_event_flag;
127 static int hf_someip_sd_entry_reserved2;
129 static int hf_someip_sd_length_optionsarray;
130 static int hf_someip_sd_options;
132 static int hf_someip_sd_option_type;
133 static int hf_someip_sd_option_length;
134 static int hf_someip_sd_option_reserved;
135 static int hf_someip_sd_option_ipv4;
136 static int hf_someip_sd_option_ipv6;
137 static int hf_someip_sd_option_port;
138 static int hf_someip_sd_option_proto;
139 static int hf_someip_sd_option_reserved2;
140 static int hf_someip_sd_option_data;
141 static int hf_someip_sd_option_config_string;
142 static int hf_someip_sd_option_config_string_element;
143 static int hf_someip_sd_option_lb_priority;
144 static int hf_someip_sd_option_lb_weight;
146 /* protocol tree items */
147 static int ett_someip_sd;
148 static int ett_someip_sd_flags;
149 static int ett_someip_sd_entries;
150 static int ett_someip_sd_entry;
151 static int ett_someip_sd_options;
152 static int ett_someip_sd_option;
153 static int ett_someip_sd_config_string;
156 /*** Taps ***/
157 static int tap_someip_sd_entries = -1;
159 typedef struct _someip_sd_entries_tap {
160 uint8_t entry_type;
161 uint16_t service_id;
162 uint8_t major_version;
163 uint32_t minor_version;
164 uint16_t instance_id;
165 uint16_t eventgroup_id;
166 uint32_t ttl;
167 } someip_sd_entries_tap_t;
170 /*** Stats ***/
171 static const char *st_str_ip_src = "Source Addresses";
172 static const char *st_str_ip_dst = "Destination Addresses";
174 static int st_node_ip_src = -1;
175 static int st_node_ip_dst = -1;
177 /*** Preferences ***/
178 static range_t *someip_ignore_ports_udp;
179 static range_t *someip_ignore_ports_tcp;
181 /* SOME/IP-SD Entry Names for TTL>0 */
182 static const value_string sd_entry_type_positive[] = {
183 {SD_ENTRY_FIND_SERVICE, "Find Service"},
184 {SD_ENTRY_OFFER_SERVICE, "Offer Service"},
185 {SD_ENTRY_SUBSCRIBE_EVENTGROUP, "Subscribe Eventgroup"},
186 {SD_ENTRY_SUBSCRIBE_EVENTGROUP_ACK, "Subscribe Eventgroup Ack"},
187 {0, NULL}
190 /* SOME/IP-SD Entry Names for TTL=0 */
191 static const value_string sd_entry_type_negative[] = {
192 {SD_ENTRY_STOP_OFFER_SERVICE, "Stop Offer Service"},
193 {SD_ENTRY_STOP_SUBSCRIBE_EVENTGROUP, "Stop Subscribe Eventgroup"},
194 {SD_ENTRY_SUBSCRIBE_EVENTGROUP_NACK, "Subscribe Eventgroup Negative Ack"},
195 {0, NULL}
198 static const value_string sd_serviceid_vs[] = {
199 {0xFFFF, "ANY"},
200 {0, NULL}
203 static const value_string sd_instanceid_vs[] = {
204 {0xFFFF, "ANY"},
205 {0, NULL}
208 static const value_string sd_majorversion_vs[] = {
209 {0xFF, "ANY"},
210 {0, NULL}
213 static const value_string sd_minorversion_vs[] = {
214 {0xFFFFFFFF, "ANY"},
215 {0, NULL}
218 static const value_string sd_eventgroupid_vs[] = {
219 {0xFFFF, "ANY"},
220 {0, NULL}
223 /* SOME/IP-SD Option Names */
224 static const value_string sd_option_type[] = {
225 {SD_OPTION_UNKNOWN, "Unknown"},
226 {SD_OPTION_CONFIGURATION, "Configuration"},
227 {SD_OPTION_LOADBALANCING, "Load Balancing"},
228 {SD_OPTION_IPV4_ENDPOINT, "IPv4 Endpoint"},
229 {SD_OPTION_IPV6_ENDPOINT, "IPv6 Endpoint"},
230 {SD_OPTION_IPV4_MULTICAST, "IPv4 Multicast"},
231 {SD_OPTION_IPV6_MULTICAST, "IPv6 Multicast"},
232 {SD_OPTION_IPV4_SD_ENDPOINT, "IPv4 SD Endpoint"},
233 {SD_OPTION_IPV6_SD_ENDPOINT, "IPv6 SD Endpoint"},
234 {0, NULL}
237 /* L4 Protocol Names for SOME/IP-SD Endpoints */
238 static const value_string sd_option_l4protos[] = {
239 {SD_OPTION_L4PROTO_TCP, "TCP"},
240 {SD_OPTION_L4PROTO_UDP, "UDP"},
241 {0, NULL}
244 static const true_false_string sd_reboot_flag = {
245 "Session ID did not roll over since last reboot",
246 "Session ID rolled over since last reboot"
249 static const true_false_string sd_unicast_flag = {
250 "Unicast messages support",
251 "Unicast messages not supported (deprecated)"
254 static const true_false_string sd_eiec_flag = {
255 "Explicit Initial Event control supported",
256 "Explicit Initial Event control not supported"
259 /*** expert info items ***/
260 static expert_field ei_someipsd_message_truncated;
261 static expert_field ei_someipsd_entry_array_malformed;
262 static expert_field ei_someipsd_entry_array_empty;
263 static expert_field ei_someipsd_entry_unknown;
264 static expert_field ei_someipsd_offer_without_endpoint;
265 static expert_field ei_someipsd_entry_stopsubsub;
266 static expert_field ei_someipsd_option_array_truncated;
267 static expert_field ei_someipsd_option_array_bytes_left;
268 static expert_field ei_someipsd_option_unknown;
269 static expert_field ei_someipsd_option_wrong_length;
270 static expert_field ei_someipsd_L4_protocol_unsupported;
271 static expert_field ei_someipsd_config_string_malformed;
273 /*** prototypes ***/
274 void proto_register_someip_sd(void);
275 void proto_reg_handoff_someip_sd(void);
277 static dissector_handle_t someip_sd_handle;
279 /**************************************
280 ******** SOME/IP-SD Dissector ********
281 *************************************/
283 static void
284 someip_sd_register_ports(uint32_t opt_index, uint32_t opt_num, uint32_t option_count, uint32_t option_ports[]) {
285 unsigned i;
287 for (i = opt_index; i < opt_index + opt_num && i < option_count; i++) {
288 uint32_t l4port = 0x0000ffff & option_ports[i];
289 uint32_t l4proto = (0xff000000 & option_ports[i]) >> 24;
291 if (l4proto == SD_OPTION_L4PROTO_UDP && !value_is_in_range(someip_ignore_ports_udp, l4port)) {
292 register_someip_port_udp(l4port);
294 if (l4proto == SD_OPTION_L4PROTO_TCP && !value_is_in_range(someip_ignore_ports_tcp, l4port)) {
295 register_someip_port_tcp(l4port);
298 /* delete port from list to ensure only registering once per SD message */
299 option_ports[i] = 0;
303 static void
304 dissect_someip_sd_pdu_option_configuration(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, uint32_t offset, uint32_t length, int optionnum) {
305 uint32_t offset_orig = offset;
306 const uint8_t *config_string;
307 proto_item *ti;
308 proto_tree *subtree;
310 tree = proto_tree_add_subtree_format(tree, tvb, offset, length, ett_someip_sd_option, NULL, "%d: Configuration Option", optionnum);
312 /* Add common fields */
313 proto_tree_add_item(tree, hf_someip_sd_option_length, tvb, offset, 2, ENC_BIG_ENDIAN);
314 offset += 2;
316 proto_tree_add_item(tree, hf_someip_sd_option_type, tvb, offset, 1, ENC_NA);
317 offset += 1;
319 proto_tree_add_item(tree, hf_someip_sd_option_reserved, tvb, offset, 1, ENC_NA);
320 offset += 1;
322 int config_string_length = length - offset + offset_orig;
323 ti = proto_tree_add_item_ret_string(tree, hf_someip_sd_option_config_string, tvb, offset, config_string_length, ENC_ASCII | ENC_NA, pinfo->pool, &config_string);
324 subtree = proto_item_add_subtree(ti, ett_someip_sd_config_string);
326 uint8_t pos = 0;
327 uint8_t element_length;
328 while (config_string != NULL && config_string_length - pos > 0) {
329 element_length = config_string[pos];
330 pos++;
332 if (element_length == 0) {
333 break;
336 if (element_length > config_string_length - pos) {
337 expert_add_info(pinfo, ti, &ei_someipsd_config_string_malformed);
338 break;
341 proto_tree_add_item(subtree, hf_someip_sd_option_config_string_element, tvb, offset + pos, element_length, ENC_ASCII | ENC_NA);
342 pos += element_length;
346 static void
347 dissect_someip_sd_pdu_option_loadbalancing(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, uint32_t offset, uint32_t length, int optionnum) {
348 tree = proto_tree_add_subtree_format(tree, tvb, offset, length, ett_someip_sd_option, NULL, "%d: Load Balancing Option", optionnum);
350 /* Add common fields */
351 proto_tree_add_item(tree, hf_someip_sd_option_length, tvb, offset, 2, ENC_BIG_ENDIAN);
352 offset += 2;
354 proto_tree_add_item(tree, hf_someip_sd_option_type, tvb, offset, 1, ENC_NA);
355 offset += 1;
357 proto_tree_add_item(tree, hf_someip_sd_option_reserved, tvb, offset, 1, ENC_NA);
358 offset += 1;
360 proto_tree_add_item(tree, hf_someip_sd_option_lb_priority, tvb, offset, 2, ENC_BIG_ENDIAN);
361 offset += 2;
363 proto_tree_add_item(tree, hf_someip_sd_option_lb_weight, tvb, offset, 2, ENC_BIG_ENDIAN);
366 static void
367 dissect_someip_sd_pdu_option_ipv4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, uint32_t offset, uint32_t length, int optionnum, uint32_t option_ports[]) {
368 uint8_t type = 255;
369 const char *description = NULL;
370 uint32_t l4port = 0;
371 uint32_t l4proto = 0;
372 const char *l4protoname = NULL;
373 const char *ipstring = NULL;
375 proto_item *ti = NULL;
376 proto_item *ti_top = NULL;
378 type = tvb_get_uint8(tvb, offset + 2);
379 description = val_to_str(type, sd_option_type, "(Unknown Option: %d)");
380 tree = proto_tree_add_subtree_format(tree, tvb, offset, length, ett_someip_sd_option, &ti_top, "%d: %s Option", optionnum, description);
382 if (length != SD_OPTION_IPV4_LENGTH) {
383 expert_add_info(pinfo, ti_top, &ei_someipsd_option_wrong_length);
384 return;
387 /* Add common fields */
388 proto_tree_add_item(tree, hf_someip_sd_option_length, tvb, offset, 2, ENC_BIG_ENDIAN);
389 offset += 2;
391 proto_tree_add_item(tree, hf_someip_sd_option_type, tvb, offset, 1, ENC_NA);
392 offset += 1;
394 proto_tree_add_item(tree, hf_someip_sd_option_reserved, tvb, offset, 1, ENC_NA);
395 offset += 1;
397 proto_tree_add_item(tree, hf_someip_sd_option_ipv4, tvb, offset, 4, ENC_NA);
398 ipstring = tvb_ip_to_str(pinfo->pool, tvb, offset);
399 offset += 4;
401 proto_tree_add_item(tree, hf_someip_sd_option_reserved2, tvb, offset, 1, ENC_NA);
402 offset += 1;
404 ti = proto_tree_add_item_ret_uint(tree, hf_someip_sd_option_proto, tvb, offset, 1, ENC_NA, &l4proto);
405 l4protoname = val_to_str(l4proto, sd_option_l4protos, "Unknown Transport Protocol: %d");
406 proto_item_append_text(ti, " (%s)", l4protoname);
408 if (type != SD_OPTION_IPV4_ENDPOINT && l4proto == SD_OPTION_L4PROTO_TCP) {
409 expert_add_info(pinfo, ti_top, &ei_someipsd_L4_protocol_unsupported);
411 offset += 1;
413 proto_tree_add_item_ret_uint(tree, hf_someip_sd_option_port, tvb, offset, 2, ENC_BIG_ENDIAN, &l4port);
415 proto_item_append_text(ti_top, " (%s:%d (%s))", ipstring, l4port, l4protoname);
417 option_ports[optionnum] = ((uint32_t)l4proto << 24) + l4port;
420 static void
421 dissect_someip_sd_pdu_option_ipv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, uint32_t offset, uint32_t length, int optionnum, uint32_t option_ports[]) {
422 uint8_t type = 255;
423 const char *description = NULL;
424 uint32_t l4port = 0;
425 uint32_t l4proto = 0;
426 const char *l4protoname = NULL;
427 const char *ipstring = NULL;
428 proto_item *ti = NULL;
429 proto_item *ti_top = NULL;
431 type = tvb_get_uint8(tvb, offset + 2);
432 description = val_to_str(type, sd_option_type, "(Unknown Option: %d)");
434 tree = proto_tree_add_subtree_format(tree, tvb, offset, length, ett_someip_sd_option, &ti_top, "%d: %s Option", optionnum, description);
436 if (length != SD_OPTION_IPV6_LENGTH) {
437 expert_add_info(pinfo, ti_top, &ei_someipsd_option_wrong_length);
438 return;
441 proto_tree_add_item(tree, hf_someip_sd_option_length, tvb, offset, 2, ENC_BIG_ENDIAN);
442 offset += 2;
444 proto_tree_add_item(tree, hf_someip_sd_option_type, tvb, offset, 1, ENC_NA);
445 offset += 1;
447 proto_tree_add_item(tree, hf_someip_sd_option_reserved, tvb, offset, 1, ENC_NA);
448 offset += 1;
450 proto_tree_add_item(tree, hf_someip_sd_option_ipv6, tvb, offset, 16, ENC_NA);
451 ipstring = tvb_ip6_to_str(pinfo->pool, tvb, offset);
452 offset += 16;
454 proto_tree_add_item(tree, hf_someip_sd_option_reserved2, tvb, offset, 1, ENC_NA);
455 offset += 1;
457 ti = proto_tree_add_item_ret_uint(tree, hf_someip_sd_option_proto, tvb, offset, 1, ENC_NA, &l4proto);
458 l4protoname = val_to_str(l4proto, sd_option_l4protos, "(Unknown Transport Protocol: %d)");
459 proto_item_append_text(ti, " (%s)", l4protoname);
461 if (type != SD_OPTION_IPV6_ENDPOINT && l4proto == SD_OPTION_L4PROTO_TCP) {
462 expert_add_info(pinfo, ti_top, &ei_someipsd_L4_protocol_unsupported);
464 offset += 1;
466 proto_tree_add_item_ret_uint(tree, hf_someip_sd_option_port, tvb, offset, 2, ENC_BIG_ENDIAN, &l4port);
468 proto_item_append_text(ti_top, " (%s:%d (%s))", ipstring, l4port, l4protoname);
470 option_ports[optionnum] = ((uint32_t)l4proto << 24) + l4port;
473 static void
474 dissect_someip_sd_pdu_option_unknown(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, uint32_t offset, uint32_t length, int optionnum) {
475 uint32_t len = 0;
476 proto_item *ti;
478 tree = proto_tree_add_subtree_format(tree, tvb, offset, length, ett_someip_sd_option, &ti, "%d: %s Option", optionnum,
479 val_to_str_const(tvb_get_uint8(tvb, offset + 2), sd_option_type, "Unknown"));
481 expert_add_info(pinfo, ti, &ei_someipsd_option_unknown);
483 proto_tree_add_item_ret_uint(tree, hf_someip_sd_option_length, tvb, offset, 2, ENC_BIG_ENDIAN, &len);
484 offset += 2;
486 proto_tree_add_item(tree, hf_someip_sd_option_type, tvb, offset, 1, ENC_NA);
487 offset += 1;
489 if (length > 3) {
490 proto_tree_add_item(tree, hf_someip_sd_option_reserved, tvb, offset, 1, ENC_NA);
491 offset += 1;
493 if (length > 4) {
494 proto_tree_add_item(tree, hf_someip_sd_option_data, tvb, offset, length - 4, ENC_NA);
499 static int
500 dissect_someip_sd_pdu_options(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_item *ti, uint32_t offset_orig, uint32_t length, uint32_t option_ports[], unsigned *option_count) {
501 uint16_t real_length = 0;
502 uint8_t option_type = 0;
503 int optionnum = 0;
504 tvbuff_t *subtvb = NULL;
506 uint32_t offset = offset_orig;
508 if (!tvb_bytes_exist(tvb, offset, SD_OPTION_MINLENGTH) || !tvb_bytes_exist(tvb, offset, length)) {
509 expert_add_info(pinfo, ti, &ei_someipsd_option_array_truncated);
510 return offset;
513 while (tvb_bytes_exist(tvb, offset, SD_OPTION_MINLENGTH)) {
514 ws_assert(optionnum >= 0 && optionnum < SD_MAX_NUM_OPTIONS);
515 option_ports[optionnum] = 0;
517 real_length = tvb_get_ntohs(tvb, offset) + 3;
518 option_type = tvb_get_uint8(tvb, offset + 2);
520 if (!tvb_bytes_exist(tvb, offset, (int)real_length) || offset - offset_orig + real_length > length) {
521 expert_add_info(pinfo, ti, &ei_someipsd_option_array_truncated);
522 return offset;
525 subtvb = tvb_new_subset_length(tvb, offset, (int)real_length);
527 switch (option_type) {
528 case SD_OPTION_CONFIGURATION:
529 dissect_someip_sd_pdu_option_configuration(subtvb, pinfo, tree, 0, real_length, optionnum);
530 break;
531 case SD_OPTION_LOADBALANCING:
532 dissect_someip_sd_pdu_option_loadbalancing(subtvb, pinfo, tree, 0, real_length, optionnum);
533 break;
534 case SD_OPTION_IPV4_ENDPOINT:
535 case SD_OPTION_IPV4_MULTICAST:
536 case SD_OPTION_IPV4_SD_ENDPOINT:
537 dissect_someip_sd_pdu_option_ipv4(subtvb, pinfo, tree, 0, real_length, optionnum, option_ports);
538 break;
540 case SD_OPTION_IPV6_ENDPOINT:
541 case SD_OPTION_IPV6_MULTICAST:
542 case SD_OPTION_IPV6_SD_ENDPOINT:
543 dissect_someip_sd_pdu_option_ipv6(subtvb, pinfo, tree, 0, real_length, optionnum, option_ports);
544 break;
546 default:
547 dissect_someip_sd_pdu_option_unknown(subtvb, pinfo, tree, 0, real_length, optionnum);
548 break;
550 optionnum++;
551 offset += real_length;
554 *option_count = optionnum;
556 return offset;
559 static void
560 someip_sd_pdu_entry_append_text(proto_item *ti_entry, uint8_t category, uint16_t serviceid, uint16_t instanceid, uint8_t majorver, uint32_t minorver, uint16_t eventgroupid, char *buf_opt_ref) {
561 if (category != SD_ENTRY_SERVICE && category != SD_ENTRY_EVENTGROUP) {
562 return;
565 if (serviceid == 0xffff) {
566 proto_item_append_text(ti_entry, " (Service ID ANY");
567 } else {
568 proto_item_append_text(ti_entry, " (Service ID 0x%04x", serviceid);
571 if (instanceid == 0xffff) {
572 proto_item_append_text(ti_entry, ", Instance ID ANY");
573 } else {
574 proto_item_append_text(ti_entry, ", Instance ID 0x%04x", instanceid);
577 if (majorver == 0xff) {
578 proto_item_append_text(ti_entry, ", Version ANY");
579 } else {
580 proto_item_append_text(ti_entry, ", Version %u", majorver);
583 switch (category) {
584 case SD_ENTRY_SERVICE:
585 if (minorver == 0xffffffff) {
586 proto_item_append_text(ti_entry, ".ANY");
587 } else {
588 proto_item_append_text(ti_entry, ".%u", minorver);
590 break;
592 case SD_ENTRY_EVENTGROUP:
593 if (eventgroupid == 0xffff) {
594 proto_item_append_text(ti_entry, ", Eventgroup ID ANY");
595 } else {
596 proto_item_append_text(ti_entry, ", Eventgroup ID 0x%04x", eventgroupid);
598 break;
601 proto_item_append_text(ti_entry, ", Options: %s)", buf_opt_ref);
604 static void
605 dissect_someip_sd_pdu_entry(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, uint32_t offset_orig, uint32_t length, uint8_t *type, uint32_t *ttl, uint64_t *uniqueid, uint32_t option_ports[], unsigned option_count, proto_item **ti_entry) {
606 uint32_t serviceid = 0;
607 uint32_t instanceid = 0;
608 uint32_t eventgroupid = 0;
609 uint32_t majorver = 0;
610 uint32_t minorver = 0;
611 uint32_t opt_index1;
612 uint32_t opt_index2;
613 uint32_t opt_num1;
614 uint32_t opt_num2;
616 uint8_t category = SD_ENTRY_UNKNOWN;
618 const char *description = NULL;
619 static char buf_opt_ref[32];
621 proto_item *ti;
623 uint32_t offset = offset_orig;
625 *uniqueid = 0;
626 *type = 255;
627 *ttl = 0;
629 if (length < SD_ENTRY_LENGTH || !tvb_bytes_exist(tvb, offset, length)) {
630 return;
633 /* lets look ahead and find out the type and ttl */
634 *type = tvb_get_uint8(tvb, offset);
635 *ttl = tvb_get_ntoh24(tvb, offset + 9);
637 if (*type < 4) {
638 category = SD_ENTRY_SERVICE;
639 } else if (*type >= 4 && *type < 8) {
640 category = SD_ENTRY_EVENTGROUP;
641 } else {
642 *ti_entry = proto_tree_add_none_format(tree, hf_someip_sd_entry, tvb, offset, SD_ENTRY_LENGTH, "Unknown Entry (Type: %d)", *type);
643 expert_add_info(pinfo, *ti_entry, &ei_someipsd_entry_unknown);
644 return;
647 description = val_to_str_const(*type,
648 (*ttl == 0) ? sd_entry_type_negative : sd_entry_type_positive,
649 "Unknown");
651 *ti_entry = proto_tree_add_none_format(tree, hf_someip_sd_entry, tvb, offset, SD_ENTRY_LENGTH, "%s Entry", description);
652 tree = proto_item_add_subtree(*ti_entry, ett_someip_sd_entry);
654 proto_tree_add_uint_format_value(tree, hf_someip_sd_entry_type, tvb, offset, 1, *type, "0x%02x (%s)", *type, description);
655 offset += 1;
657 proto_tree_add_item_ret_uint(tree, hf_someip_sd_entry_index1, tvb, offset, 1, ENC_BIG_ENDIAN, &opt_index1);
658 offset += 1;
659 proto_tree_add_item_ret_uint(tree, hf_someip_sd_entry_index2, tvb, offset, 1, ENC_BIG_ENDIAN, &opt_index2);
660 offset += 1;
662 proto_tree_add_item_ret_uint(tree, hf_someip_sd_entry_numopt1, tvb, offset, 1, ENC_NA, &opt_num1);
663 proto_tree_add_item_ret_uint(tree, hf_someip_sd_entry_numopt2, tvb, offset, 1, ENC_NA, &opt_num2);
664 offset += 1;
666 if (opt_num1 != 0 && opt_num2 == 0) {
667 snprintf(buf_opt_ref, 32, "%d-%d", opt_index1, opt_index1 + opt_num1 - 1);
668 } else if (opt_num1 == 0 && opt_num2 != 0) {
669 snprintf(buf_opt_ref, 32, "%d-%d", opt_index2, opt_index2 + opt_num2 - 1);
670 } else if (opt_num1 != 0 && opt_num2 != 0) {
671 snprintf(buf_opt_ref, 32, "%d-%d,%d-%d", opt_index1, opt_index1 + opt_num1 - 1, opt_index2, opt_index2 + opt_num2 - 1);
672 } else {
673 snprintf(buf_opt_ref, 32, "None");
676 ti = proto_tree_add_string(tree, hf_someip_sd_entry_opts_referenced, tvb, offset - 3, 3, buf_opt_ref);
677 proto_item_set_generated(ti);
679 ti = proto_tree_add_item_ret_uint(tree, hf_someip_sd_entry_serviceid, tvb, offset, 2, ENC_BIG_ENDIAN, &serviceid);
680 description = someip_lookup_service_name((uint16_t)serviceid);
681 if (description != NULL) {
682 proto_item_append_text(ti, " (%s)", description);
683 ti = proto_tree_add_string(tree, hf_someip_sd_entry_servicename, tvb, offset, 2, description);
684 proto_item_set_generated(ti);
685 proto_item_set_hidden(ti);
687 offset += 2;
689 proto_tree_add_item_ret_uint(tree, hf_someip_sd_entry_instanceid, tvb, offset, 2, ENC_BIG_ENDIAN, &instanceid);
690 offset += 2;
692 proto_tree_add_item_ret_uint(tree, hf_someip_sd_entry_majorver, tvb, offset, 1, ENC_BIG_ENDIAN, &majorver);
693 offset += 1;
695 proto_tree_add_item(tree, hf_someip_sd_entry_ttl, tvb, offset, 3, ENC_BIG_ENDIAN);
696 offset += 3;
698 /* Add specific fields - i.e. the last line */
699 if (category == SD_ENTRY_SERVICE) {
700 proto_tree_add_item_ret_uint(tree, hf_someip_sd_entry_minorver, tvb, offset, 4, ENC_BIG_ENDIAN, &minorver);
701 someip_sd_pdu_entry_append_text(*ti_entry, category, serviceid, instanceid, majorver, minorver, 0, buf_opt_ref);
702 } else if (category == SD_ENTRY_EVENTGROUP) {
703 proto_tree_add_item(tree, hf_someip_sd_entry_reserved, tvb, offset, 1, ENC_NA);
704 offset += 1;
706 proto_tree_add_item(tree, hf_someip_sd_entry_intial_event_flag, tvb, offset, 1, ENC_NA);
707 proto_tree_add_item(tree, hf_someip_sd_entry_reserved2, tvb, offset, 1, ENC_NA);
708 proto_tree_add_item(tree, hf_someip_sd_entry_counter, tvb, offset, 1, ENC_NA);
709 offset += 1;
711 ti = proto_tree_add_item_ret_uint(tree, hf_someip_sd_entry_eventgroupid, tvb, offset, 2, ENC_BIG_ENDIAN, &eventgroupid);
712 description = someip_lookup_eventgroup_name((uint16_t)serviceid, (uint16_t)eventgroupid);
713 if (description != NULL) {
714 proto_item_append_text(ti, " (%s)", description);
715 ti = proto_tree_add_string(tree, hf_someip_sd_entry_eventgroupname, tvb, offset, 2, description);
716 proto_item_set_generated(ti);
717 proto_item_set_hidden(ti);
720 someip_sd_pdu_entry_append_text(*ti_entry, category, serviceid, instanceid, majorver, 0, eventgroupid, buf_opt_ref);
723 /* lets add some combined filtering term */
724 *uniqueid = (((uint64_t)serviceid) << 32) | (uint64_t)instanceid << 16 | (uint64_t)eventgroupid;
726 ti = NULL;
727 if (*ttl > 0) {
728 switch (*type) {
729 case SD_ENTRY_FIND_SERVICE:
730 ti = proto_tree_add_uint64_format_value(tree, hf_someip_sd_entry_type_findservice, tvb, offset_orig, SD_ENTRY_LENGTH, *uniqueid, "on 0x%012" PRIx64, *uniqueid);
731 break;
732 case SD_ENTRY_OFFER_SERVICE:
733 ti = proto_tree_add_uint64_format_value(tree, hf_someip_sd_entry_type_offerservice, tvb, offset_orig, SD_ENTRY_LENGTH, *uniqueid, "on 0x%012" PRIx64, *uniqueid);
734 break;
735 case SD_ENTRY_SUBSCRIBE_EVENTGROUP:
736 ti = proto_tree_add_uint64_format_value(tree, hf_someip_sd_entry_type_subscribeeventgroup, tvb, offset_orig, SD_ENTRY_LENGTH, *uniqueid, "on 0x%012" PRIx64, *uniqueid);
737 break;
738 case SD_ENTRY_SUBSCRIBE_EVENTGROUP_ACK:
739 ti = proto_tree_add_uint64_format_value(tree, hf_someip_sd_entry_type_subscribeeventgroupack, tvb, offset_orig, SD_ENTRY_LENGTH, *uniqueid, "on 0x%012" PRIx64, *uniqueid);
740 break;
742 } else {
743 switch (*type) {
744 case SD_ENTRY_STOP_OFFER_SERVICE:
745 ti = proto_tree_add_uint64_format_value(tree, hf_someip_sd_entry_type_stopofferservice, tvb, offset_orig, SD_ENTRY_LENGTH, *uniqueid, "on 0x%012" PRIx64, *uniqueid);
746 break;
747 case SD_ENTRY_STOP_SUBSCRIBE_EVENTGROUP:
748 ti = proto_tree_add_uint64_format_value(tree, hf_someip_sd_entry_type_stopsubscribeeventgroup, tvb, offset_orig, SD_ENTRY_LENGTH, *uniqueid, "on 0x%012" PRIx64, *uniqueid);
749 break;
750 case SD_ENTRY_SUBSCRIBE_EVENTGROUP_NACK:
751 ti = proto_tree_add_uint64_format_value(tree, hf_someip_sd_entry_type_subscribeeventgroupnack, tvb, offset_orig, SD_ENTRY_LENGTH, *uniqueid, "on 0x%012" PRIx64, *uniqueid);
752 break;
756 proto_item_set_hidden(ti);
758 /* check for Offer Entry without referenced Endpoints */
759 if (opt_num1 == 0 && opt_num2 == 0 && *type == SD_ENTRY_OFFER_SERVICE && *ttl > 0) {
760 expert_add_info(pinfo, *ti_entry, &ei_someipsd_offer_without_endpoint);
763 /* register ports but we skip 0xfffe because of other-serv */
764 if (serviceid != SOMEIP_SD_SERVICE_ID_OTHER_SERVICE && !PINFO_FD_VISITED(pinfo)) {
765 someip_sd_register_ports(opt_index1, opt_num1, option_count, option_ports);
766 someip_sd_register_ports(opt_index2, opt_num2, option_count, option_ports);
769 /* TAP */
770 if (have_tap_listener(tap_someip_sd_entries)) {
771 someip_sd_entries_tap_t *data = wmem_alloc(pinfo->pool, sizeof(someip_sd_entries_tap_t));
772 data->entry_type = *type;
773 data->service_id = (uint16_t)serviceid;
774 data->major_version = (uint8_t)majorver;
775 data->minor_version = minorver;
776 data->instance_id = (uint16_t)instanceid;
777 data->eventgroup_id = (uint16_t)eventgroupid;
778 data->ttl = *ttl;
780 tap_queue_packet(tap_someip_sd_entries, pinfo, data);
784 static int
785 dissect_someip_sd_pdu_entries(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_item *ti, uint32_t offset, uint32_t length, uint32_t option_ports[], unsigned option_count) {
786 proto_item *ti_entry;
788 uint8_t type;
789 uint32_t ttl;
790 uint32_t entry_flags = 0;
791 uint32_t stop_entry_flags = 0;
793 uint64_t uniqueid;
794 uint64_t last_uniqueid = 0xffffffffffffffff;
797 while (length >= SD_ENTRY_LENGTH) {
798 dissect_someip_sd_pdu_entry(tvb, pinfo, tree, offset, SD_ENTRY_LENGTH, &type, &ttl, &uniqueid, option_ports, option_count, &ti_entry);
799 offset += SD_ENTRY_LENGTH;
800 length -= SD_ENTRY_LENGTH;
802 /* mark for attaching to info column */
803 if (type < 32) {
804 if (ttl == 0) {
805 stop_entry_flags = stop_entry_flags | (1 << type);
806 } else {
807 entry_flags = entry_flags | (1 << type);
811 if (type == SD_ENTRY_SUBSCRIBE_EVENTGROUP && ttl == 0) {
812 last_uniqueid = uniqueid;
813 } else {
814 if ( (type == SD_ENTRY_SUBSCRIBE_EVENTGROUP && ttl > 0) && last_uniqueid == uniqueid ) {
815 expert_add_info(pinfo, ti_entry, &ei_someipsd_entry_stopsubsub);
818 last_uniqueid = 0xffffffffffffffff;
822 /* Add entry flags */
823 if (stop_entry_flags != 0 || entry_flags != 0) {
824 col_append_str(pinfo->cinfo, COL_INFO, " ");
827 if (entry_flags & (1 << SD_ENTRY_FIND_SERVICE)) {
828 col_append_str(pinfo->cinfo, COL_INFO, "[Find]");
831 if (stop_entry_flags & (1 << SD_ENTRY_OFFER_SERVICE)) {
832 col_append_str(pinfo->cinfo, COL_INFO, "[StopOffer]");
835 if (entry_flags & (1 << SD_ENTRY_OFFER_SERVICE)) {
836 col_append_str(pinfo->cinfo, COL_INFO, "[Offer]");
839 if (stop_entry_flags & (1 << SD_ENTRY_SUBSCRIBE_EVENTGROUP)) {
840 col_append_str(pinfo->cinfo, COL_INFO, "[StopSubscribe]");
843 if (entry_flags & (1 << SD_ENTRY_SUBSCRIBE_EVENTGROUP)) {
844 col_append_str(pinfo->cinfo, COL_INFO, "[Subscribe]");
847 if (stop_entry_flags & (1 << SD_ENTRY_SUBSCRIBE_EVENTGROUP_ACK)) {
848 col_append_str(pinfo->cinfo, COL_INFO, "[SubscribeNack]");
851 if (entry_flags & (1 << SD_ENTRY_SUBSCRIBE_EVENTGROUP_ACK)) {
852 col_append_str(pinfo->cinfo, COL_INFO, "[SubscribeAck]");
855 if (length != 0) {
856 expert_add_info(pinfo, ti, &ei_someipsd_entry_array_malformed);
859 return length;
862 static int
863 dissect_someip_sd_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
864 uint32_t offset = 0;
865 uint32_t length_entriesarray = 0;
866 uint32_t length_optionsarray = 0;
868 proto_item *ti = NULL;
869 proto_item *ti_sd_entries = NULL;
871 proto_tree *someip_sd_entries_tree = NULL;
872 proto_tree *someip_sd_options_tree = NULL;
873 bool stop_parsing_after_entries = false;
874 uint32_t offset_entriesarray;
876 /* format for option_ports entries: 1 byte proto | 1 byte reserved | 2 byte port number*/
877 static uint32_t option_ports[SD_MAX_NUM_OPTIONS];
878 unsigned option_count = 0;
880 static int * const someipsd_flags[] = {
881 &hf_someip_sd_rebootflag,
882 &hf_someip_sd_unicastflag,
883 &hf_someip_sd_explicitiniteventflag,
884 NULL
887 col_set_str(pinfo->cinfo, COL_PROTOCOL, SOMEIP_SD_NAME);
888 col_set_str(pinfo->cinfo, COL_INFO, SOMEIP_SD_NAME);
890 ti = proto_tree_add_item(tree, proto_someip_sd, tvb, offset, -1, ENC_NA);
891 tree = proto_item_add_subtree(ti, ett_someip_sd);
893 if (!tvb_bytes_exist(tvb, offset, SOMEIP_SD_MIN_LENGTH)) {
894 expert_add_info(pinfo, ti, &ei_someipsd_message_truncated);
895 return tvb_reported_length(tvb);
898 /* add flags */
899 proto_tree_add_bitmask(tree, tvb, offset, hf_someip_sd_flags, ett_someip_sd_flags, someipsd_flags, ENC_BIG_ENDIAN);
900 offset += 1;
902 /* add reserved */
903 proto_tree_add_item(tree, hf_someip_sd_reserved, tvb, offset, 3, ENC_BIG_ENDIAN);
904 offset += 3;
906 /* add length of entries */
907 proto_tree_add_item_ret_uint(tree, hf_someip_sd_length_entriesarray, tvb, offset, 4, ENC_BIG_ENDIAN, &length_entriesarray);
908 offset += 4;
910 if (!tvb_bytes_exist(tvb, offset, length_entriesarray)) {
911 expert_add_info(pinfo, ti , &ei_someipsd_message_truncated);
912 return tvb_reported_length(tvb);
915 if (!tvb_bytes_exist(tvb, offset, length_entriesarray)) {
916 /* truncated SD message - need to shorten buffer */
917 length_entriesarray = tvb_captured_length_remaining(tvb, offset);
918 expert_add_info(pinfo, ti, &ei_someipsd_message_truncated);
919 stop_parsing_after_entries = true;
922 /* preparing entries array but not parsing it yet */
923 ti_sd_entries = proto_tree_add_item(tree, hf_someip_sd_entries, tvb, offset, length_entriesarray, ENC_NA);
924 someip_sd_entries_tree = proto_item_add_subtree(ti_sd_entries, ett_someip_sd_entries);
925 /* save offset to parse entries later since we need to parse options first */
926 offset_entriesarray = offset;
927 offset += length_entriesarray;
929 if (!stop_parsing_after_entries) {
930 /* make sure we have a length field */
931 if (tvb_bytes_exist(tvb, offset, 4)) {
933 /* add options length */
934 proto_tree_add_item_ret_uint(tree, hf_someip_sd_length_optionsarray, tvb, offset, 4, ENC_BIG_ENDIAN, &length_optionsarray);
935 offset += 4;
937 if (length_optionsarray > 0) {
938 if (tvb_bytes_exist(tvb, offset, 1)) {
939 ti = proto_tree_add_item(tree, hf_someip_sd_options, tvb, offset, -1, ENC_NA);
940 someip_sd_options_tree = proto_item_add_subtree(ti, ett_someip_sd_options);
942 /* check, if enough bytes are left for optionsarray */
943 if (!tvb_bytes_exist(tvb, offset, length_optionsarray)) {
944 length_optionsarray = tvb_captured_length_remaining(tvb, offset);
945 expert_add_info(pinfo, ti, &ei_someipsd_message_truncated);
946 proto_item_append_text(ti, " (truncated!)");
949 /* updating to length we will work with */
950 if (length_optionsarray > 0) {
951 proto_item_set_len(ti, length_optionsarray);
954 dissect_someip_sd_pdu_options(tvb, pinfo, someip_sd_options_tree, ti, offset, length_optionsarray, option_ports, &option_count);
955 offset += length_optionsarray;
956 } else {
957 expert_add_info(pinfo, ti, &ei_someipsd_message_truncated);
963 if (length_entriesarray >= SD_ENTRY_LENGTH) {
964 offset += dissect_someip_sd_pdu_entries(tvb, pinfo, someip_sd_entries_tree, ti_sd_entries, offset_entriesarray, length_entriesarray, option_ports, option_count);
965 } else {
966 expert_add_info(pinfo, ti_sd_entries, &ei_someipsd_entry_array_empty);
968 return offset;
971 /*******************************************
972 **************** Statistics ***************
973 *******************************************/
975 static void
976 someipsd_entries_stats_tree_init(stats_tree *st) {
977 st_node_ip_src = stats_tree_create_node(st, st_str_ip_src, 0, STAT_DT_INT, true);
978 stat_node_set_flags(st, st_str_ip_src, 0, false, ST_FLG_SORT_TOP);
979 st_node_ip_dst = stats_tree_create_node(st, st_str_ip_dst, 0, STAT_DT_INT, true);
982 static void
983 stat_number_to_string_with_any(uint32_t value, unsigned max, char *format_string, char *ret, size_t size_limit) {
984 if (value == max) {
985 snprintf(ret, size_limit, "%s", "MAX");
986 } else {
987 snprintf(ret, size_limit, format_string, value);
991 static void
992 stat_create_entry_summary_string(const someip_sd_entries_tap_t *data, char *ret, size_t size_limit) {
993 char service_str[128];
994 char instance_str[128];
995 char majorver_str[128];
996 char minorver_str[128];
997 char eventgrp_str[128];
998 char tmp[128];
1000 char *service_name = someip_lookup_service_name(data->service_id);
1001 char *eventgrp_name = someip_lookup_eventgroup_name(data->service_id, data->eventgroup_id);
1003 stat_number_to_string_with_any(data->service_id, UINT32_MAX, "0x%04x", service_str, sizeof(service_str) - 1);
1004 stat_number_to_string_with_any(data->instance_id, UINT32_MAX, "0x%04x", instance_str, sizeof(instance_str) - 1);
1005 stat_number_to_string_with_any(data->major_version, UINT8_MAX, "%d", majorver_str, sizeof(majorver_str) - 1);
1007 switch (data->entry_type) {
1008 case SD_ENTRY_FIND_SERVICE:
1009 case SD_ENTRY_OFFER_SERVICE:
1010 stat_number_to_string_with_any(data->minor_version, UINT32_MAX, "%d", minorver_str, sizeof(minorver_str) - 1);
1011 if (service_name != NULL) {
1012 snprintf(ret, size_limit, "Service %s (%s) Version %s.%s Instance %s", service_str, service_name, majorver_str, minorver_str, instance_str);
1013 } else {
1014 snprintf(ret, size_limit, "Service %s Version %s.%s Instance %s", service_str, majorver_str, minorver_str, instance_str);
1016 break;
1018 case SD_ENTRY_SUBSCRIBE_EVENTGROUP:
1019 case SD_ENTRY_SUBSCRIBE_EVENTGROUP_ACK:
1020 stat_number_to_string_with_any(data->eventgroup_id, UINT32_MAX, "0x%04x", eventgrp_str, sizeof(eventgrp_str) - 1);
1021 if (service_name != NULL) {
1022 snprintf(tmp, sizeof(tmp) - 1, "Service %s (%s) Version %s Instance %s Eventgroup %s", service_str, service_name, majorver_str, instance_str, eventgrp_str);
1023 } else {
1024 snprintf(tmp, sizeof(tmp) - 1, "Service %s Version %s Instance %s Eventgroup %s", service_str, majorver_str, instance_str, eventgrp_str);
1026 if (eventgrp_name != NULL) {
1027 snprintf(ret, size_limit, "%s (%s)", tmp, eventgrp_name);
1029 break;
1033 static tap_packet_status
1034 someipsd_entries_stats_tree_packet(stats_tree *st, packet_info *pinfo, epan_dissect_t *edt _U_, const void *p, tap_flags_t flags _U_) {
1035 DISSECTOR_ASSERT(p);
1036 const someip_sd_entries_tap_t *data = (const someip_sd_entries_tap_t *)p;
1037 static char tmp_addr_str[256];
1039 snprintf(tmp_addr_str, sizeof(tmp_addr_str) - 1, "%s (%s)", address_to_str(pinfo->pool, &pinfo->net_src), address_to_name(&pinfo->net_src));
1040 tick_stat_node(st, st_str_ip_src, 0, false);
1041 int src_id = tick_stat_node(st, tmp_addr_str, st_node_ip_src, true);
1043 snprintf(tmp_addr_str, sizeof(tmp_addr_str) - 1, "%s (%s)", address_to_str(pinfo->pool, &pinfo->net_dst), address_to_name(&pinfo->net_dst));
1044 tick_stat_node(st, st_str_ip_dst, 0, false);
1045 int dst_id = tick_stat_node(st, tmp_addr_str, st_node_ip_dst, true);
1047 int tmp_id;
1048 static char tmp_str[128];
1050 if (data->ttl == 0) {
1051 switch (data->entry_type) {
1052 case SD_ENTRY_STOP_OFFER_SERVICE:
1053 stat_create_entry_summary_string(data, tmp_str, sizeof(tmp_str) - 1);
1054 tmp_id = tick_stat_node(st, "Stop Offer Service", src_id, true);
1055 tick_stat_node(st, tmp_str, tmp_id, false);
1056 tmp_id = tick_stat_node(st, "Stop Offer Service", dst_id, true);
1057 tick_stat_node(st, tmp_str, tmp_id, false);
1058 break;
1059 case SD_ENTRY_STOP_SUBSCRIBE_EVENTGROUP:
1060 stat_create_entry_summary_string(data, tmp_str, sizeof(tmp_str) - 1);
1061 tmp_id = tick_stat_node(st, "Stop Subscribe Eventgroup", src_id, true);
1062 tick_stat_node(st, tmp_str, tmp_id, false);
1063 tmp_id = tick_stat_node(st, "Stop Subscribe Eventgroup", dst_id, true);
1064 tick_stat_node(st, tmp_str, tmp_id, false);
1065 break;
1066 case SD_ENTRY_SUBSCRIBE_EVENTGROUP_NACK:
1067 stat_create_entry_summary_string(data, tmp_str, sizeof(tmp_str) - 1);
1068 tmp_id = tick_stat_node(st, "Subscribe Eventgroup Nack", src_id, true);
1069 tick_stat_node(st, tmp_str, tmp_id, false);
1070 tmp_id = tick_stat_node(st, "Subscribe Eventgroup Nack", dst_id, true);
1071 tick_stat_node(st, tmp_str, tmp_id, false);
1072 break;
1074 } else {
1075 switch (data->entry_type) {
1076 case SD_ENTRY_FIND_SERVICE:
1077 stat_create_entry_summary_string(data, tmp_str, sizeof(tmp_str) - 1);
1078 tmp_id = tick_stat_node(st, "Find Service", src_id, true);
1079 tick_stat_node(st, tmp_str, tmp_id, false);
1080 tmp_id = tick_stat_node(st, "Find Service", dst_id, true);
1081 tick_stat_node(st, tmp_str, tmp_id, false);
1082 break;
1083 case SD_ENTRY_OFFER_SERVICE:
1084 stat_create_entry_summary_string(data, tmp_str, sizeof(tmp_str) - 1);
1085 tmp_id = tick_stat_node(st, "Offer Service", src_id, true);
1086 tick_stat_node(st, tmp_str, tmp_id, false);
1087 tmp_id = tick_stat_node(st, "Offer Service", dst_id, true);
1088 tick_stat_node(st, tmp_str, tmp_id, false);
1089 break;
1090 case SD_ENTRY_SUBSCRIBE_EVENTGROUP:
1091 stat_create_entry_summary_string(data, tmp_str, sizeof(tmp_str) - 1);
1092 tmp_id = tick_stat_node(st, "Subscribe Eventgroup", src_id, true);
1093 tick_stat_node(st, tmp_str, tmp_id, false);
1094 tmp_id = tick_stat_node(st, "Subscribe Eventgroup", dst_id, true);
1095 tick_stat_node(st, tmp_str, tmp_id, false);
1096 break;
1097 case SD_ENTRY_SUBSCRIBE_EVENTGROUP_ACK:
1098 stat_create_entry_summary_string(data, tmp_str, sizeof(tmp_str) - 1);
1099 tmp_id = tick_stat_node(st, "Subscribe Eventgroup Ack", src_id, true);
1100 tick_stat_node(st, tmp_str, tmp_id, false);
1101 tmp_id = tick_stat_node(st, "Subscribe Eventgroup Ack", dst_id, true);
1102 tick_stat_node(st, tmp_str, tmp_id, false);
1103 break;
1107 return TAP_PACKET_REDRAW;
1110 void
1111 proto_register_someip_sd(void) {
1112 module_t *someipsd_module;
1114 expert_module_t *expert_module_someip_sd;
1116 /* data fields */
1117 static hf_register_info hf_sd[] = {
1118 { &hf_someip_sd_flags,
1119 { "Flags", "someipsd.flags",
1120 FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1121 { &hf_someip_sd_rebootflag,
1122 { "Reboot Flag", "someipsd.flags.reboot",
1123 FT_BOOLEAN, 8, TFS(&sd_reboot_flag), SOMEIP_SD_REBOOT_FLAG, NULL, HFILL }},
1124 { &hf_someip_sd_unicastflag,
1125 { "Unicast Flag", "someipsd.flags.unicast",
1126 FT_BOOLEAN, 8, TFS(&sd_unicast_flag), SOMEIP_SD_UNICAST_FLAG, NULL, HFILL }},
1127 { &hf_someip_sd_explicitiniteventflag,
1128 { "Explicit Initial Events Flag", "someipsd.flags.exp_init_events",
1129 FT_BOOLEAN, 8, TFS(&sd_eiec_flag), SOMEIP_SD_EXPL_INIT_EVENT_REQ_FLAG, NULL, HFILL }},
1130 { &hf_someip_sd_reserved,
1131 { "Reserved", "someipsd.reserved",
1132 FT_UINT24, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1134 { &hf_someip_sd_length_entriesarray,
1135 { "Length of Entries Array", "someipsd.length_entriesarray",
1136 FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1137 { &hf_someip_sd_entries,
1138 { "Entries Array", "someipsd.entries",
1139 FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1140 { &hf_someip_sd_entry,
1141 { "Entry", "someipsd.entry",
1142 FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1143 { &hf_someip_sd_entry_type,
1144 { "Type", "someipsd.entry.type",
1145 FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1146 { &hf_someip_sd_entry_index1,
1147 { "Index 1", "someipsd.entry.index1",
1148 FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1149 { &hf_someip_sd_entry_index2,
1150 { "Index 2", "someipsd.entry.index2",
1151 FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1152 { &hf_someip_sd_entry_numopt1,
1153 { "Number of Opts 1", "someipsd.entry.numopt1",
1154 FT_UINT8, BASE_HEX, NULL, 0xf0, NULL, HFILL }},
1155 { &hf_someip_sd_entry_numopt2,
1156 { "Number of Opts 2", "someipsd.entry.numopt2",
1157 FT_UINT8, BASE_HEX, NULL, 0x0f, NULL, HFILL }},
1158 { &hf_someip_sd_entry_opts_referenced,
1159 { "Options referenced", "someipsd.entry.optionsreferenced",
1160 FT_STRING, BASE_NONE, NULL, 0x00, NULL, HFILL }},
1162 { &hf_someip_sd_entry_serviceid,
1163 { "Service ID", "someipsd.entry.serviceid",
1164 FT_UINT16, BASE_HEX | BASE_SPECIAL_VALS, VALS(sd_serviceid_vs), 0x0, NULL, HFILL }},
1165 { &hf_someip_sd_entry_servicename,
1166 { "Service Name", "someipsd.entry.servicename",
1167 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1168 { &hf_someip_sd_entry_instanceid,
1169 { "Instance ID", "someipsd.entry.instanceid",
1170 FT_UINT16, BASE_HEX | BASE_SPECIAL_VALS, VALS(sd_instanceid_vs), 0x0, NULL, HFILL }},
1171 { &hf_someip_sd_entry_majorver,
1172 { "Major Version", "someipsd.entry.majorver",
1173 FT_UINT8, BASE_DEC | BASE_SPECIAL_VALS, VALS(sd_majorversion_vs), 0x0, NULL, HFILL }},
1174 { &hf_someip_sd_entry_ttl,
1175 { "TTL", "someipsd.entry.ttl",
1176 FT_UINT24, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1177 { &hf_someip_sd_entry_minorver,
1178 { "Minor Version", "someipsd.entry.minorver",
1179 FT_UINT32, BASE_DEC | BASE_SPECIAL_VALS, VALS(sd_minorversion_vs), 0x0, NULL, HFILL }},
1180 { &hf_someip_sd_entry_eventgroupid,
1181 { "Eventgroup ID", "someipsd.entry.eventgroupid",
1182 FT_UINT16, BASE_HEX | BASE_SPECIAL_VALS, VALS(sd_eventgroupid_vs), 0x0, NULL, HFILL }},
1183 { &hf_someip_sd_entry_eventgroupname,
1184 { "Eventgroup Name", "someipsd.entry.eventgroupname",
1185 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1186 { &hf_someip_sd_entry_reserved,
1187 { "Reserved", "someipsd.entry.reserved",
1188 FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
1189 { &hf_someip_sd_entry_counter,
1190 { "Counter", "someipsd.entry.counter",
1191 FT_UINT8, BASE_HEX, NULL, SD_EVENTGROUP_ENTRY_COUNTER_MASK, NULL, HFILL } },
1192 { &hf_someip_sd_entry_reserved2,
1193 { "Reserved", "someipsd.entry.reserved2",
1194 FT_UINT8, BASE_HEX, NULL, SD_EVENTGROUP_ENTRY_RES2_MASK, NULL, HFILL } },
1195 { &hf_someip_sd_entry_intial_event_flag,
1196 { "Initial Event Request", "someipsd.entry.initialevents",
1197 FT_BOOLEAN, 8, NULL, SD_ENTRY_INIT_EVENT_REQ_MASK, NULL, HFILL } },
1199 { &hf_someip_sd_length_optionsarray,
1200 { "Length of Options Array", "someipsd.length_optionsarray",
1201 FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1202 { &hf_someip_sd_options,
1203 { "Options Array", "someipsd.options",
1204 FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1206 { &hf_someip_sd_option_type,
1207 { "Type", "someipsd.option.type",
1208 FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1209 { &hf_someip_sd_option_length,
1210 { "Length", "someipsd.option.length",
1211 FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1212 { &hf_someip_sd_option_reserved,
1213 { "Reserved", "someipsd.option.reserved",
1214 FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1215 { &hf_someip_sd_option_ipv4,
1216 { "IPv4 Address", "someipsd.option.ipv4address",
1217 FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1218 { &hf_someip_sd_option_ipv6,
1219 { "IPv6 Address", "someipsd.option.ipv6address",
1220 FT_IPv6, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1221 { &hf_someip_sd_option_port,
1222 { "Port", "someipsd.option.port",
1223 FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1224 { &hf_someip_sd_option_proto,
1225 { "Protocol", "someipsd.option.proto",
1226 FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1227 { &hf_someip_sd_option_reserved2,
1228 { "Reserved 2", "someipsd.option.reserved2",
1229 FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
1230 { &hf_someip_sd_option_data,
1231 { "Unknown Data", "someipsd.option.unknown_data",
1232 FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
1233 { &hf_someip_sd_option_config_string,
1234 { "Configuration String", "someipsd.option.config_string",
1235 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } },
1236 { &hf_someip_sd_option_config_string_element,
1237 { "Configuration String Element", "someipsd.option.config_string_element",
1238 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } },
1239 { &hf_someip_sd_option_lb_priority,
1240 { "Priority", "someipsd.option.priority",
1241 FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
1242 { &hf_someip_sd_option_lb_weight,
1243 { "Weight", "someipsd.option.weight",
1244 FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
1245 { &hf_someip_sd_entry_type_offerservice,
1246 { "Offer Service", "someipsd.entry.offerservice",
1247 FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1248 { &hf_someip_sd_entry_type_stopofferservice,
1249 { "Stop Offer Service", "someipsd.entry.stopofferservice",
1250 FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1251 { &hf_someip_sd_entry_type_findservice,
1252 { "Find Service", "someipsd.entry.findservice",
1253 FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1255 { &hf_someip_sd_entry_type_subscribeeventgroup,
1256 { "Subscribe Eventgroup", "someipsd.entry.subscribeeventgroup",
1257 FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1258 { &hf_someip_sd_entry_type_stopsubscribeeventgroup,
1259 { "Stop Subscribe Eventgroup", "someipsd.entry.stopsubscribeeventgroup",
1260 FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1262 { &hf_someip_sd_entry_type_subscribeeventgroupack,
1263 { "Subscribe Eventgroup ACK", "someipsd.entry.subscribeeventgroupack",
1264 FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1265 { &hf_someip_sd_entry_type_subscribeeventgroupnack,
1266 { "Subscribe Eventgroup NACK", "someipsd.entry.subscribeeventgroupnack",
1267 FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1270 static int *ett_sd[] = {
1271 &ett_someip_sd,
1272 &ett_someip_sd_flags,
1273 &ett_someip_sd_entries,
1274 &ett_someip_sd_entry,
1275 &ett_someip_sd_options,
1276 &ett_someip_sd_option,
1277 &ett_someip_sd_config_string,
1280 static ei_register_info ei_sd[] = {
1281 { &ei_someipsd_message_truncated,{ "someipsd.message_truncated", PI_MALFORMED, PI_ERROR, "SOME/IP-SD Truncated message!", EXPFILL } },
1282 { &ei_someipsd_entry_array_malformed,{ "someipsd.entry_array_malformed", PI_MALFORMED, PI_ERROR, "SOME/IP-SD Entry Array length not multiple of 16 bytes!", EXPFILL } },
1283 { &ei_someipsd_entry_array_empty,{ "someipsd.entry_array_empty", PI_MALFORMED, PI_ERROR, "SOME/IP-SD Empty Entry Array!", EXPFILL } },
1284 { &ei_someipsd_entry_unknown,{ "someipsd.entry_unknown", PI_MALFORMED, PI_WARN, "SOME/IP-SD Unknown Entry!", EXPFILL } },
1285 { &ei_someipsd_offer_without_endpoint,{ "someipsd.offer_no_endpoints", PI_MALFORMED, PI_ERROR, "SOME/IP-SD Offer Service references no endpoints!", EXPFILL } },
1286 { &ei_someipsd_entry_stopsubsub,{ "someipsd.stopsub_sub", PI_PROTOCOL, PI_WARN, "SOME/IP-SD Subscribe after Stop Subscribe!", EXPFILL } },
1287 { &ei_someipsd_option_array_truncated,{ "someipsd.option_array_truncated", PI_MALFORMED, PI_ERROR, "SOME/IP-SD Option Array truncated!", EXPFILL } },
1288 { &ei_someipsd_option_array_bytes_left,{ "someipsd.option_array_bytes_left", PI_MALFORMED, PI_WARN, "SOME/IP-SD Option Array bytes left after parsing options!", EXPFILL } },
1289 { &ei_someipsd_option_unknown,{ "someipsd.option_unknown", PI_MALFORMED, PI_WARN, "SOME/IP-SD Unknown Option!", EXPFILL } },
1290 { &ei_someipsd_option_wrong_length,{ "someipsd.option_wrong_length", PI_MALFORMED, PI_ERROR, "SOME/IP-SD Option length is incorrect!", EXPFILL } },
1291 { &ei_someipsd_L4_protocol_unsupported,{ "someipsd.L4_protocol_unsupported", PI_MALFORMED, PI_ERROR, "SOME/IP-SD Unsupported Layer 4 Protocol!", EXPFILL } },
1292 { &ei_someipsd_config_string_malformed,{ "someipsd.config_string_malformed", PI_MALFORMED, PI_ERROR, "SOME/IP-SD Configuration String malformed!", EXPFILL } },
1295 /* Register Protocol, Fields, ETTs, Expert Info, Taps, Dissector */
1296 proto_someip_sd = proto_register_protocol(SOMEIP_SD_NAME_LONG, SOMEIP_SD_NAME, SOMEIP_SD_NAME_FILTER);
1297 proto_register_field_array(proto_someip_sd, hf_sd, array_length(hf_sd));
1298 proto_register_subtree_array(ett_sd, array_length(ett_sd));
1299 expert_module_someip_sd = expert_register_protocol(proto_someip_sd);
1300 expert_register_field_array(expert_module_someip_sd, ei_sd, array_length(ei_sd));
1301 tap_someip_sd_entries = register_tap("someipsd_entries");
1302 someip_sd_handle = register_dissector(SOMEIP_SD_NAME_FILTER, dissect_someip_sd_pdu, proto_someip_sd);
1304 /* Register preferences */
1305 someipsd_module = prefs_register_protocol(proto_someip_sd, NULL);
1307 range_convert_str(wmem_epan_scope(), &someip_ignore_ports_udp, "", 65535);
1308 prefs_register_range_preference(someipsd_module, "ports.udp.ignore", "UDP Ports ignored",
1309 "SOME/IP Ignore Port Ranges UDP. These ports are not automatically added by the SOME/IP-SD.",
1310 &someip_ignore_ports_udp, 65535);
1312 range_convert_str(wmem_epan_scope(), &someip_ignore_ports_tcp, "", 65535);
1313 prefs_register_range_preference(someipsd_module, "ports.tcp.ignore", "TCP Ports ignored",
1314 "SOME/IP Ignore Port Ranges TCP. These ports are not automatically added by the SOME/IP-SD.",
1315 &someip_ignore_ports_tcp, 65535);
1318 void
1319 proto_reg_handoff_someip_sd(void) {
1320 dissector_add_uint("someip.messageid", SOMEIP_SD_MESSAGEID, someip_sd_handle);
1321 stats_tree_register("someipsd_entries", "someipsd_entries", "SOME/IP-SD Entries", 0, someipsd_entries_stats_tree_packet, someipsd_entries_stats_tree_init, NULL);
1325 * Editor modelines
1327 * Local Variables:
1328 * c-basic-offset: 4
1329 * tab-width: 8
1330 * indent-tabs-mode: nil
1331 * End:
1333 * ex: set shiftwidth=4 tabstop=8 expandtab:
1334 * :indentSize=4:tabSize=8:noTabs=true: