Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-geonw.c
blob1fb640dfebf0d1f0bab880615bb565544a337bdc
1 /* packet-geonw.c
2 * Routines for GeoNetworking and BTP-A/B dissection
3 * Coyright 2018, C. Guerber <cguerber@yahoo.com>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
13 * The GeoNetworking protocol is a network layer protocol that provides packet
14 * routing in an ad hoc network. It makes use of geographical positions for
15 * packet transport. GeoNetworking supports the communication among individual
16 * ITS stations as well as the distribution of packets in geographical areas.
17 * (Extracted from ETSI EN 302 636-4-1)
19 * The Basic Transport Protocol (BTP) provides an end-to-end, connection-less
20 * transport service in the ITS ad hoc network. Its main purpose is the
21 * multiplexing of messages from different processes at the ITS facilities
22 * layer, e.g. CAM and DENM from the cooperative awareness basic service and
23 * the distributed environmental notification basic service, for the
24 * transmission of packets via the GeoNetworking protocol as well as the
25 * de-multiplexing at the destination.
26 * (Extracted from ETSI EN 302 636-5-1)
28 * Reference standards:
29 * ETSI EN 302 636-4-1 v1.2.0 (2013-10)
30 * Intelligent Transport Systems (ITS); Vehicular Communications; GeoNetworking;
31 * Part 4: Geographical addressing and forwarding for point-to-point and
32 * point-to-multipoint communications;
33 * Sub-part 1: Media-Independent Functionality
35 * ETSI EN 302 636-5-1 v1.2.1 (2014-08)
36 * Intelligent Transport Systems (ITS); Vehicular Communications; GeoNetworking;
37 * Part 5: Transport Protocols;
38 * Sub-part 1: Basic Transport Protocol
40 * ETSI EN 302 636-6-1 v1.2.1 (2014-05)
41 * Intelligent Transport Systems (ITS); Vehicular Communications; GeoNetworking;
42 * Part 6: Internet Integration;
43 * Sub-part 1: Transmission of IPv6 Packets over GeoNetworking Protocols
45 * ETSI TS 103 248 v1.2.1 (2018-08)
46 * Intelligent Transport Systems (ITS); GeoNetworking;
47 * Port Numbers for the Basic Transport Protocol (BTP)
49 * ETSI TS 103 097 v1.1.1, v1.2.1 and v1.3.1
50 * Intelligent Transport Systems (ITS); Security;
51 * Security header and certificate formats
55 #include <config.h>
56 #include <stdlib.h>
58 #include <epan/packet.h>
59 #include <epan/expert.h>
60 #include <epan/decode_as.h>
61 #include <epan/proto_data.h>
62 #include <epan/address_types.h>
63 #include <epan/addr_resolv.h>
64 #include <epan/to_str.h>
65 #include <epan/conversation.h>
66 #include <epan/tap.h>
67 #include <epan/etypes.h>
68 #include <epan/unit_strings.h>
70 #include <wsutil/utf8_entities.h>
72 #include "packet-e164.h"
73 #include "packet-ieee1609dot2.h"
74 #include "packet-geonw.h"
77 * Prototypes
79 void proto_reg_handoff_btpb(void);
80 void proto_register_btpb(void);
81 void proto_reg_handoff_btpa(void);
82 void proto_register_btpa(void);
83 void proto_reg_handoff_geonw(void);
84 void proto_register_geonw(void);
87 * Constants
89 #define HT_MASK 0xf0
90 #define HST_MASK 0x0f
92 // Definition of header types See section 8.7.4 table 9
93 #define HT_BEACON 0x10
94 #define HT_GEOUNICAST 0x20
95 #define HT_GEOANYCAST 0x30
96 #define HT_GEOBROADCAST 0x40
97 #define HT_TSB 0x50
98 #define HT_LS 0x60
100 // Area subtypes
101 #define HST_CIRCULAR 0x00
102 #define HST_RECTANGULAR 0x01
103 #define HST_ELLIPSOIDAL 0x02
105 // TSB subtype
106 #define HST_SINGLE_HOP 0x00
107 #define HST_MULTI_HOP 0x01
109 // LS subtypes
110 #define HST_REQUEST 0x00
111 #define HST_REPLY 0x01
113 // Types and subtype combined
114 #define HTST_BEACON (HT_BEACON)
115 #define HTST_GEOUNICAST (HT_GEOUNICAST)
116 #define HTST_GAC_CIRCLE (HT_GEOANYCAST|HST_CIRCULAR)
117 #define HTST_GAC_RECT (HT_GEOANYCAST|HST_RECTANGULAR)
118 #define HTST_GAC_ELLIPSE (HT_GEOANYCAST|HST_ELLIPSOIDAL)
119 #define HTST_GBC_CIRCLE (HT_GEOBROADCAST|HST_CIRCULAR)
120 #define HTST_GBC_RECT (HT_GEOBROADCAST|HST_RECTANGULAR)
121 #define HTST_GBC_ELLIPSE (HT_GEOBROADCAST|HST_ELLIPSOIDAL)
122 #define HTST_TSB_SINGLE (HT_TSB|HST_SINGLE_HOP)
123 #define HTST_TSB_MULT (HT_TSB|HST_MULTI_HOP)
124 #define HTST_LS_REQUEST (HT_LS|HST_REQUEST)
125 #define HTST_LS_REPLY (HT_LS|HST_REPLY)
127 #define HT_GET(ht) ((ht)&HT_MASK)
128 #define HST_GET(ht) ((ht)&HST_MASK)
129 #define IS_HT_KNOWN(ht) ((ht) <= 0x61) && (ht >= 0x10) && (HST_GET(ht) < 3) && ((HST_GET(ht) == 0) || ((HT_GET(ht) > 0x30) && ((HST_GET(ht) == 1) || ((HST_GET(ht) == 2) && (HT_GET(ht) < 0x43)))))
131 #define BH_LEN 4
132 #define BH_NH_COMMON_HDR 1
133 #define BH_NH_SECURED_PKT 2
135 #define CH_LEN 8
136 #define CH_NH_BTP_A 1
137 #define CH_NH_BTP_B 2
138 #define CH_NH_IPV6 3
140 #define GUC_LEN 48
141 #define TSB_LEN 28
142 #define GAC_LEN 44
143 #define GBC_LEN 44
144 #define BEACON_LEN 24
145 #define LS_REQUEST_LEN 36
146 #define LS_REPLY_LEN 48
148 #define TST_MAX 0xffffffff
150 #define SEC_TVB_KEY 0
153 * Variables
155 static wmem_map_t *geonw_hashtable;
157 static int proto_geonw;
158 static int proto_btpa;
159 static int proto_btpb;
161 static int geonw_tap;
162 static int btpa_tap;
163 static int btpa_follow_tap;
164 static int btpb_tap;
165 static int btpb_follow_tap;
167 static int hf_geonw_bh;
168 static int hf_geonw_bh_version;
169 static int hf_geonw_bh_next_header;
170 static int hf_geonw_bh_reserved;
171 static int hf_geonw_bh_life_time;
172 static int hf_geonw_bh_lt_mult;
173 static int hf_geonw_bh_lt_base;
174 static int hf_geonw_bh_remain_hop_limit;
176 static int hf_geonw_ch;
177 static int hf_geonw_ch_next_header;
178 static int hf_geonw_ch_reserved1;
179 static int hf_geonw_ch_header_type;
180 //static int hf_geonw_ch_header_subtype;
181 static int hf_geonw_ch_traffic_class;
182 static int hf_geonw_ch_tc_scf;
183 static int hf_geonw_ch_tc_offload;
184 static int hf_geonw_ch_tc_id;
185 static int hf_geonw_ch_flags;
186 static int hf_geonw_ch_flags_mob;
187 static int hf_geonw_ch_flags_reserved;
188 static int hf_geonw_ch_payload_length;
189 static int hf_geonw_ch_max_hop_limit;
190 static int hf_geonw_ch_reserved2;
192 static int hf_geonw_seq_num;
193 static int hf_geonw_reserved;
194 static int hf_geonw_so_pv;
195 static int hf_geonw_so_pv_addr;
196 static int hf_geonw_so_pv_addr_manual;
197 static int hf_geonw_so_pv_addr_type;
198 static int hf_geonw_so_pv_addr_country;
199 static int hf_geonw_so_pv_addr_mid;
200 static int hf_geonw_so_pv_time;
201 static int hf_geonw_so_pv_lat;
202 static int hf_geonw_so_pv_lon;
203 static int hf_geonw_so_pv_pai;
204 static int hf_geonw_so_pv_speed;
205 static int hf_geonw_so_pv_heading;
206 static int hf_geonw_de_pv;
207 static int hf_geonw_de_pv_addr;
208 static int hf_geonw_de_pv_addr_manual;
209 static int hf_geonw_de_pv_addr_type;
210 static int hf_geonw_de_pv_addr_country;
211 static int hf_geonw_de_pv_addr_mid;
212 static int hf_geonw_de_pv_time;
213 static int hf_geonw_de_pv_lat;
214 static int hf_geonw_de_pv_lon;
216 static int hf_geonw_gxc_latitude;
217 static int hf_geonw_gxc_longitude;
218 static int hf_geonw_gxc_radius;
219 static int hf_geonw_gxc_distancea;
220 static int hf_geonw_gxc_distanceb;
221 static int hf_geonw_gxc_angle;
222 static int hf_geonw_gxc_reserved;
224 static int hf_geonw_shb_reserved;
226 static int hf_geonw_lsrq_addr;
227 static int hf_geonw_lsrq_addr_manual;
228 static int hf_geonw_lsrq_addr_type;
229 static int hf_geonw_lsrq_addr_country;
230 static int hf_geonw_lsrq_addr_mid;
232 static int hf_geonw_beacon;
233 static int hf_geonw_guc;
234 static int hf_geonw_gac;
235 static int hf_geonw_gbc;
236 static int hf_geonw_tsb;
237 static int hf_geonw_ls;
238 static int hf_geonw_analysis_flags;
240 static int hf_btpa_dstport;
241 static int hf_btpa_srcport;
242 static int hf_btpa_port;
243 static int hf_btpb_dstport;
244 static int hf_btpb_dstport_info;
246 static int hf_geonw_resp_in;
247 static int hf_geonw_resp_to;
248 static int hf_geonw_no_resp;
249 static int hf_geonw_resptime;
251 static int hf_geonw_dccmco;
252 static int hf_geonw_dccmco_cbr_l_0_hop;
253 static int hf_geonw_dccmco_cbr_l_1_hop;
254 static int hf_geonw_dccmco_output_power;
255 static int hf_geonw_dccmco_reserved;
257 static int ett_geonw;
258 static int ett_geonw_bh;
259 static int ett_geonw_bh_lt;
260 static int ett_geonw_ch;
261 static int ett_geonw_ch_tc;
262 static int ett_geonw_sh;
263 static int ett_geonw_so;
264 static int ett_geonw_so_add;
265 static int ett_geonw_de;
266 static int ett_geonw_de_add;
267 static int ett_geonw_lsrq_add;
268 static int ett_geonw_analysis;
269 static int ett_geonw_dccmco;
270 static int ett_btpa;
271 static int ett_btpb;
273 static int geonw_address_type = -1;
275 static expert_field ei_geonw_nz_reserved;
276 static expert_field ei_geonw_version_err;
277 static expert_field ei_geonw_rhl_lncb;
278 static expert_field ei_geonw_rhl_too_low;
279 static expert_field ei_geonw_mhl_lt_rhl;
280 static expert_field ei_geonw_scc_too_big;
281 static expert_field ei_geonw_analysis_duplicate;
282 static expert_field ei_geonw_resp_not_found;
283 static expert_field ei_geonw_out_of_range;
284 static expert_field ei_geonw_payload_len;
285 static expert_field ei_geonw_intx_too_big;
287 static dissector_table_t geonw_subdissector_table;
288 static dissector_table_t ssp_subdissector_table;
289 static dissector_table_t btpa_subdissector_table;
290 static dissector_table_t btpb_subdissector_table;
292 static const value_string ch_header_type_names[] = {
293 { HTST_BEACON, "Beacon" },
294 { HTST_GEOUNICAST, "Geo Unicast" },
295 { HTST_GAC_CIRCLE, "Geo-scoped Anycast Circular area" },
296 { HTST_GAC_RECT, "Geo-scoped Anycast Rectangular area" },
297 { HTST_GAC_ELLIPSE, "Geo-scoped Anycast Ellipsoidal area" },
298 { HTST_GBC_CIRCLE, "Geo-scoped Broadcast Circular area" },
299 { HTST_GBC_RECT, "Geo-scoped Broadcast Rectangular area" },
300 { HTST_GBC_ELLIPSE, "Geo-scoped Broadcast Ellipsoidal area" },
301 { HTST_TSB_SINGLE, "Topologically-scoped broadcast Single-hop broadcast (SHB)" },
302 { HTST_TSB_MULT, "Topologically-scoped broadcast Multi-hop broadcast (TSB)" },
303 { HTST_LS_REQUEST, "Location Service Request" },
304 { HTST_LS_REPLY, "Location Service Reply" },
305 { 0x00, NULL}
308 static dissector_handle_t ieee1609dot2_handle;
309 static dissector_handle_t geonw_handle;
310 static dissector_handle_t btpa_handle;
311 static dissector_handle_t btpb_handle;
312 static dissector_handle_t ipv6_handle;
314 static heur_dissector_list_t btpa_heur_subdissector_list;
315 static heur_dissector_list_t btpb_heur_subdissector_list;
318 * Basic Transport Protocol A dissector
320 static int
321 dissect_btpa(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
323 heur_dtbl_entry_t *hdtbl_entry;
324 int low_port, high_port;
325 int dst_port, src_port;
326 proto_item *hidden_item;
327 struct btpaheader *btpah;
329 btpah = wmem_new0(pinfo->pool, struct btpaheader);
331 col_set_str(pinfo->cinfo, COL_PROTOCOL, "BTPA");
332 /* Clear out stuff in the info column */
333 col_clear(pinfo->cinfo,COL_INFO);
335 proto_item *ti = proto_tree_add_item(tree, proto_btpa, tvb, 0, 4, ENC_NA);
336 proto_tree *btpa_tree = proto_item_add_subtree(ti, ett_btpa);
338 proto_tree_add_item_ret_uint(btpa_tree, hf_btpa_dstport, tvb, 0, 2, ENC_BIG_ENDIAN, &dst_port);
339 proto_tree_add_item_ret_uint(btpa_tree, hf_btpa_srcport, tvb, 2, 2, ENC_BIG_ENDIAN, &src_port);
341 pinfo->srcport = src_port;
342 pinfo->destport = dst_port;
344 col_append_ports(pinfo->cinfo, COL_INFO, PT_NONE, pinfo->srcport, pinfo->destport);
346 // Add hidden port field
347 hidden_item = proto_tree_add_item(btpa_tree, hf_btpa_port, tvb, 0, 2, ENC_BIG_ENDIAN);
348 proto_item_set_hidden(hidden_item);
349 hidden_item = proto_tree_add_item(btpa_tree, hf_btpa_port, tvb, 2, 2, ENC_BIG_ENDIAN);
350 proto_item_set_hidden(hidden_item);
352 btpah->btp_psrc = src_port;
353 btpah->btp_pdst = dst_port;
354 copy_address_shallow(&btpah->gnw_src, &pinfo->src);
355 copy_address_shallow(&btpah->gnw_dst, &pinfo->dst);
356 tap_queue_packet(btpa_tap, pinfo, btpah);
358 tvbuff_t *next_tvb = tvb_new_subset_remaining(tvb, 4);
360 if (have_tap_listener(btpa_follow_tap))
361 tap_queue_packet(btpa_follow_tap, pinfo, next_tvb);
363 if (src_port > dst_port) {
364 low_port = dst_port;
365 high_port = src_port;
366 } else {
367 low_port = src_port;
368 high_port = dst_port;
371 if (dissector_try_uint_with_data(btpa_subdissector_table, low_port, next_tvb, pinfo, tree, true, NULL))
372 return tvb_captured_length(tvb);
374 if (dissector_try_uint_with_data(btpa_subdissector_table, high_port, next_tvb, pinfo, tree, true, NULL))
375 return tvb_captured_length(tvb);
377 if (dissector_try_heuristic(btpa_heur_subdissector_list, next_tvb, pinfo, tree, &hdtbl_entry, NULL))
378 return tvb_captured_length(tvb);
380 call_data_dissector(next_tvb, pinfo, tree);
381 return tvb_captured_length(tvb);
385 * Basic Transport Protocol B dissector
387 static int
388 dissect_btpb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
390 heur_dtbl_entry_t *hdtbl_entry;
391 uint32_t dst_port;
392 uint32_t dst_info;
393 struct btpbheader *btpbh;
395 btpbh = wmem_new0(pinfo->pool, struct btpbheader);
397 col_set_str(pinfo->cinfo, COL_PROTOCOL, "BTPB");
398 /* Clear out stuff in the info column */
399 col_clear(pinfo->cinfo,COL_INFO);
401 proto_item *ti = proto_tree_add_item(tree, proto_btpb, tvb, 0, 4, ENC_NA);
402 proto_tree *btpb_tree = proto_item_add_subtree(ti, ett_btpb);
404 proto_tree_add_item_ret_uint(btpb_tree, hf_btpb_dstport, tvb, 0, 2, ENC_BIG_ENDIAN, &dst_port);
405 proto_tree_add_item_ret_uint(btpb_tree, hf_btpb_dstport_info, tvb, 2, 2, ENC_BIG_ENDIAN, &dst_info);
407 pinfo->destport = dst_port;
409 col_append_fstr(pinfo->cinfo, COL_INFO, " " UTF8_RIGHTWARDS_ARROW " %u", dst_port);
411 btpbh->btp_pdst = dst_port;
412 btpbh->btp_idst = dst_info;
413 copy_address_shallow(&btpbh->gnw_src, &pinfo->src);
414 copy_address_shallow(&btpbh->gnw_dst, &pinfo->dst);
415 tap_queue_packet(btpb_tap, pinfo, btpbh);
417 tvbuff_t *next_tvb = tvb_new_subset_remaining(tvb, 4);
419 if (have_tap_listener(btpb_follow_tap))
420 tap_queue_packet(btpb_follow_tap, pinfo, next_tvb);
422 if (dissector_try_uint_with_data(btpb_subdissector_table, dst_port, next_tvb, pinfo, tree, true, NULL)) {
423 return tvb_captured_length(tvb);
425 if (dissector_try_heuristic(btpb_heur_subdissector_list, next_tvb, pinfo, tree, &hdtbl_entry, NULL)) {
426 return tvb_captured_length(tvb);
429 call_data_dissector(next_tvb, pinfo, tree);
430 return tvb_captured_length(tvb);
434 * ===========================================================================
435 * GeoNetworking dissector
436 * ===========================================================================
439 typedef struct _geonw_transaction_t {
440 uint32_t rqst_frame;
441 uint32_t resp_frame;
442 nstime_t rqst_time;
443 nstime_t resp_time;
444 } geonw_transaction_t;
446 typedef struct _geonw_conv_info_t {
447 wmem_stack_t *unmatched_pdus;
448 wmem_tree_t *matched_pdus;
449 } geonw_conv_info_t;
451 static const char * get_geonw_name(const uint8_t *addr);
452 static const char* geonw_name_resolution_str(const address* addr);
453 static int geonw_name_resolution_len(void);
455 static geonw_transaction_t *transaction_start(packet_info * pinfo, proto_tree * tree);
456 static geonw_transaction_t *transaction_end(packet_info * pinfo, proto_tree * tree);
458 static bool geonw_analyze_seq = true;
461 * GeoNetworking Address Type
464 /* Adapter from ethernet and ipv4 Address Type code */
465 struct hashgeonw;
466 typedef struct hashgeonw hashgeonw_t;
468 struct hashgeonw {
469 unsigned status;
470 uint8_t addr[8];
471 char hexaddr[28];
472 char resolved_name[MAXNAMELEN];
474 // Node follow up used for duplication detection
475 uint32_t timestamp;
476 uint32_t sequence_number;
480 static int
481 geonw_str_len(const address* addr _U_)
483 // (0/1)'.'(0..31)'.'(0..1023)'.'{eth}
484 return 28;
487 static int
488 _geonw_to_str(const uint8_t* addrdata, char *buf, int buf_len _U_)
490 address eth_addr;
492 // Initial or Manual
493 if (addrdata[0] & 0x80)
494 *buf++ = '1';
495 else
496 *buf++ = '0';
497 *buf++ = '.';
498 // Station Type
499 uint32_to_str_buf((addrdata[0] & 0x7C) >> 2, buf, 26);
500 buf += (unsigned) strlen(buf);
501 *buf++ = '.';
502 // Country Code
503 uint32_to_str_buf(((uint32_t)(addrdata[0] & 0x03) << 8) + addrdata[1], buf, 23); // > 23
504 buf += (unsigned) strlen(buf);
505 *buf++ = '.';
506 // LL_ADDR
507 set_address(&eth_addr, AT_ETHER, 6, &(addrdata[2]));
508 ether_to_str(&eth_addr, buf, 18);
510 return 28;
513 static int
514 geonw_to_str(const address* addr, char *buf, int buf_len _U_)
516 return _geonw_to_str((const uint8_t *)addr->data, buf, buf_len);
519 static const char*
520 geonw_col_filter_str(const address* addr _U_, bool is_src)
522 if (is_src)
523 return "geonw.src_pos.addr";
525 return "geonw.dst_pos.addr";
528 static int
529 geonw_len(void)
531 return 8;
534 static unsigned
535 geonw_addr_hash(const void *key)
537 return wmem_strong_hash((const uint8_t *)key, 8);
540 static gboolean
541 geonw_addr_cmp(const void *a, const void *b)
543 return (memcmp(a, b, 8) == 0);
547 * These two value_string are used for address resolv:
549 static const value_string itss_type_small_names[] = {
550 { 0, "unk" },
551 { 1, "ped" },
552 { 2, "cyc" },
553 { 3, "mop" },
554 { 4, "mot" },
555 { 5, "pas" },
556 { 6, "bus" },
557 { 7, "ltr" },
558 { 8, "htr" },
559 { 9, "trl" },
560 { 10, "spe" },
561 { 11, "trm" },
562 { 15, "rsu" },
563 { 0, NULL}
566 /* Resolve geonetworking address */
567 static hashgeonw_t *
568 geonw_addr_resolve(hashgeonw_t *tp) {
569 const uint8_t *addr = tp->addr;
570 uint16_t val;
571 char *rname = tp->resolved_name;
572 address eth_addr;
573 uint8_t l1, l2;
575 // Initial or Manual
576 if (addr[0] & 0x80)
577 *rname++ = 'm';
578 else
579 *rname++ = 'i';
580 *rname++ = '.';
581 // Station Type
582 val = (addr[0] & 0x7C) >> 2;
583 const char *string = try_val_to_str(val, itss_type_small_names);
584 if (string == NULL) {
585 uint32_to_str_buf(val, rname, MAXNAMELEN-2);
586 l1 = (uint8_t) strlen(rname);
588 else {
589 l1 = (uint8_t) g_strlcpy(rname, string, MAXNAMELEN-2);
591 rname += l1;
592 *rname++ = '.';
593 // Country Code
594 val = ((uint32_t)(addr[0] & 0x03) << 8) + addr[1];
595 string = try_val_to_str(val, E164_ISO3166_country_code_short_value);
596 if (string == NULL) {
597 uint32_to_str_buf(val, rname, MAXNAMELEN-12);
598 l2 = (uint8_t) strlen(rname);
600 else {
601 l2 = (uint8_t) g_strlcpy(rname, string, MAXNAMELEN-l1-3);
603 rname += l2;
604 //l1 += l2;
605 *rname++ = '.';
606 // LL_ADDR
607 set_address(&eth_addr, AT_ETHER, 6, &(addr[2]));
608 ether_to_str(&eth_addr, rname, 18);
609 // We could use ether_name_resolution_str:
610 // (void) g_strlcpy(rname, ether_name_resolution_str(&eth_addr), MAXNAMELEN-l1-4);
612 tp->status = 1;
614 return tp;
617 static hashgeonw_t *
618 geonw_hash_new_entry(const uint8_t *addr, bool resolve)
620 hashgeonw_t *tp;
622 tp = wmem_new(wmem_file_scope(), hashgeonw_t);
623 memcpy(tp->addr, addr, sizeof(tp->addr));
624 /* Values returned by bytes_to_hexstr_punct() are *not* null-terminated */
625 _geonw_to_str(addr, tp->hexaddr, 28);
626 tp->resolved_name[0] = '\0';
627 tp->status = 0;
628 tp->timestamp = 0;
629 tp->sequence_number = SN_MAX + 1;
631 if (resolve)
632 geonw_addr_resolve(tp);
634 wmem_map_insert(geonw_hashtable, tp->addr, tp);
636 return tp;
637 } /* geonw_hash_new_entry */
639 static hashgeonw_t *
640 geonw_name_lookup(const uint8_t *addr, bool resolve)
642 hashgeonw_t *tp;
644 tp = (hashgeonw_t *)wmem_map_lookup(geonw_hashtable, addr);
646 if (tp == NULL) {
647 tp = geonw_hash_new_entry(addr, resolve);
648 } else {
649 if (resolve && !tp->status) {
650 geonw_addr_resolve(tp); /* Found but needs to be resolved */
654 return tp;
656 } /* geonw_name_lookup */
658 const char *
659 get_geonw_name(const uint8_t *addr)
661 hashgeonw_t *tp;
662 bool resolve = gbl_resolv_flags.network_name;
664 tp = geonw_name_lookup(addr, resolve);
666 return resolve ? tp->resolved_name : tp->hexaddr;
668 } /* get_geonw_name */
670 const char* geonw_name_resolution_str(const address* addr)
672 return get_geonw_name((const uint8_t *)addr->data);
675 int geonw_name_resolution_len(void)
677 return MAX_ADDR_STR_LEN; /* XXX - This can be lower */
681 * Conversations for GeoNetworking
684 /* Adapted from ICMP echo request/reply code */
686 /* GeoNw LS request/reply transaction statistics ... */
687 static geonw_transaction_t *transaction_start(packet_info * pinfo, proto_tree * tree)
689 conversation_t *conversation;
690 geonw_conv_info_t *geonw_info;
691 geonw_transaction_t *geonw_trans;
692 wmem_tree_key_t geonw_key[3];
693 proto_item *it;
695 /* Handle the conversation tracking */
696 conversation = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst, conversation_pt_to_conversation_type(pinfo->ptype), HT_LS, HT_LS, 0);
697 if (conversation == NULL) {
698 /* No, this is a new conversation. */
699 conversation = conversation_new(pinfo->num, &pinfo->src, &pinfo->dst, conversation_pt_to_conversation_type(pinfo->ptype), HT_LS, HT_LS, 0);
701 geonw_info = (geonw_conv_info_t *)conversation_get_proto_data(conversation, proto_geonw);
702 if (geonw_info == NULL) {
703 geonw_info = wmem_new(wmem_file_scope(), geonw_conv_info_t);
704 geonw_info->unmatched_pdus = wmem_stack_new(wmem_file_scope());
705 geonw_info->matched_pdus = wmem_tree_new(wmem_file_scope());
706 conversation_add_proto_data(conversation, proto_geonw, geonw_info);
709 if (!PINFO_FD_VISITED(pinfo)) {
710 /* this is a new request, create a new transaction structure and map it to the
711 unmatched table
713 geonw_trans = wmem_new(wmem_file_scope(), geonw_transaction_t);
714 geonw_trans->rqst_frame = pinfo->num;
715 geonw_trans->resp_frame = 0;
716 geonw_trans->rqst_time = pinfo->abs_ts;
717 nstime_set_zero(&geonw_trans->resp_time);
718 wmem_stack_push(geonw_info->unmatched_pdus, (void *) geonw_trans);
719 } else {
720 /* Already visited this frame */
721 uint32_t frame_num = pinfo->num;
723 geonw_key[0].length = 1;
724 geonw_key[0].key = &frame_num;
725 geonw_key[1].length = 0;
726 geonw_key[1].key = NULL;
728 geonw_trans = (geonw_transaction_t *)wmem_tree_lookup32_array(geonw_info->matched_pdus, geonw_key);
730 if (geonw_trans == NULL) {
731 if (PINFO_FD_VISITED(pinfo)) {
732 /* No response found - add field and expert info */
733 it = proto_tree_add_item(tree, hf_geonw_no_resp, NULL, 0, 0, ENC_NA);
734 proto_item_set_generated(it);
736 col_append_str(pinfo->cinfo, COL_INFO, " (no response found!)");
738 /* Expert info. */
739 expert_add_info_format(pinfo, it, &ei_geonw_resp_not_found, "No response seen to LS Request");
742 return NULL;
745 /* Print state tracking in the tree */
746 if (geonw_trans->resp_frame) {
747 it = proto_tree_add_uint(tree, hf_geonw_resp_in, NULL, 0, 0, geonw_trans->resp_frame);
748 proto_item_set_generated(it);
750 col_append_frame_number(pinfo, COL_INFO, " (reply in %u)", geonw_trans->resp_frame);
753 return geonw_trans;
755 } /* transaction_start() */
757 static geonw_transaction_t *transaction_end(packet_info * pinfo, proto_tree * tree)
759 conversation_t *conversation;
760 geonw_conv_info_t *geonw_info;
761 geonw_transaction_t *geonw_trans;
762 wmem_tree_key_t geonw_key[3];
763 proto_item *it;
764 nstime_t ns;
765 double resp_time;
767 conversation = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst, conversation_pt_to_conversation_type(pinfo->ptype), HT_LS, HT_LS, 0);
768 if (conversation == NULL) {
769 return NULL;
772 geonw_info = (geonw_conv_info_t *)conversation_get_proto_data(conversation, proto_geonw);
773 if (geonw_info == NULL) {
774 return NULL;
777 if (!PINFO_FD_VISITED(pinfo)) {
778 uint32_t frame_num;
780 geonw_trans = (geonw_transaction_t *)wmem_stack_peek(geonw_info->unmatched_pdus);
781 if (geonw_trans == NULL) {
782 return NULL;
785 /* we have already seen this response, or an identical one */
786 if (geonw_trans->resp_frame != 0) {
787 return NULL;
790 geonw_trans->resp_frame = pinfo->num;
792 /* we found a match. Add entries to the matched table for both request and reply frames
794 geonw_key[0].length = 1;
795 geonw_key[0].key = &frame_num;
796 geonw_key[1].length = 0;
797 geonw_key[1].key = NULL;
799 frame_num = geonw_trans->rqst_frame;
800 wmem_tree_insert32_array(geonw_info->matched_pdus, geonw_key, (void *) geonw_trans);
802 frame_num = geonw_trans->resp_frame;
803 wmem_tree_insert32_array(geonw_info->matched_pdus, geonw_key, (void *) geonw_trans);
804 } else {
805 /* Already visited this frame */
806 uint32_t frame_num = pinfo->num;
808 geonw_key[0].length = 1;
809 geonw_key[0].key = &frame_num;
810 geonw_key[1].length = 0;
811 geonw_key[1].key = NULL;
813 geonw_trans = (geonw_transaction_t *)wmem_tree_lookup32_array(geonw_info->matched_pdus, geonw_key);
815 if (geonw_trans == NULL) {
816 return NULL;
821 it = proto_tree_add_uint(tree, hf_geonw_resp_to, NULL, 0, 0, geonw_trans->rqst_frame);
822 proto_item_set_generated(it);
824 nstime_delta(&ns, &pinfo->abs_ts, &geonw_trans->rqst_time);
825 geonw_trans->resp_time = ns;
826 resp_time = nstime_to_msec(&ns);
827 it = proto_tree_add_double_format_value(tree, hf_geonw_resptime, NULL, 0, 0, resp_time, "%.3f ms", resp_time);
828 proto_item_set_generated(it);
830 col_append_frame_number(pinfo, COL_INFO, " (request in %d)", geonw_trans->rqst_frame);
832 return geonw_trans;
834 } /* transaction_end() */
836 // Adapted from TCP sequence number analysis
838 // Conversation data
839 struct geonw_analysis {
840 // Node follow up used for duplication detection
841 uint32_t timestamp;
842 uint16_t sequence_number;
846 * Secured geonetworking
849 static int hf_geonw_sec;
850 static int hf_sgeonw_version;
851 static int hf_sgeonw_profile;
852 static int hf_sgeonw_hdr;
853 static int hf_sgeonw_pl;
854 static int hf_sgeonw_trl;
855 static int hf_sgeonw_var_len;
856 static int hf_sgeonw_var_len_det;
857 static int hf_sgeonw_var_len_val;
858 static int hf_sgeonw_header_field;
859 static int hf_sgeonw_header_field_type_v1;
860 static int hf_sgeonw_header_field_type_v2;
861 static int hf_sgeonw_opaque;
863 static int hf_sgeonw_payload_field;
864 static int hf_sgeonw_payload_field_type;
866 static int hf_sgeonw_trailer_field;
867 static int hf_sgeonw_trailer_field_type;
869 static int hf_sgeonw_certificate;
870 static int hf_sgeonw_encryption_parameter;
871 static int hf_sgeonw_signature;
872 static int hf_sgeonw_subject_info;
873 static int hf_sgeonw_subject_attribute;
875 static int hf_sgeonw_intx;
876 static int hf_sgeonw_time64;
877 static int hf_sgeonw_conf;
878 static int hf_sgeonw_time32;
879 static int hf_sgeonw_lat;
880 static int hf_sgeonw_lon;
881 static int hf_sgeonw_elev;
882 static int hf_sgeonw_hashedid3;
883 static int hf_sgeonw_hashedid8;
884 static int hf_sgeonw_duration;
885 static int hf_sgeonw_duration_unit;
886 static int hf_sgeonw_duration_value;
887 static int hf_sgeonw_encryption_parameter_nonce;
889 static int hf_sgeonw_msg_id;
890 static int hf_sgeonw_app_id;
892 static int ett_geonw_sec;
893 static int ett_sgeonw_hdr;
894 static int ett_sgeonw_field;
895 static int ett_sgeonw_var_len;
896 static int ett_sgeonw_intx;
897 static int ett_sgeonw_duration;
898 static int ett_sgeonw_encryption_parameter;
899 static int ett_sgeonw_signature;
900 static int ett_sgeonw_subject_info;
901 static int ett_sgeonw_subject_attribute;
902 static int ett_sgeonw_ssp;
904 static expert_field ei_sgeonw_len_unsupported;
905 static expert_field ei_sgeonw_len_too_long;
906 static expert_field ei_sgeonw_subj_info_too_long;
907 static expert_field ei_sgeonw_ssp_too_long;
908 static expert_field ei_sgeonw_bogus;
910 typedef enum {
911 generation_time = 0,
912 generation_time_confidence = 1,
913 expiration = 2,
914 generation_location = 3,
915 request_unrecognized_certificate = 4,
916 message_type = 5,
917 signer_info = 128,
918 recipient_info = 129,
919 encryption_parameters = 130,
921 last_hdr_type = (2<<8)-1
922 } HeaderFieldType;
924 static const value_string header_field_type_v1_names[] = {
925 { generation_time, "Generation time" },
926 { generation_time_confidence, "Generation time confidence" },
927 { expiration, "Expiration" },
928 { generation_location, "Generation location" },
929 { request_unrecognized_certificate, "Request unrecognized certificate" },
930 { message_type, "Message type" },
931 { signer_info, "Signer info" },
932 { recipient_info, "Recipient info" },
933 { encryption_parameters, "Encryption parameters" },
934 { 0x00, NULL}
937 static const value_string header_field_type_v2_names[] = {
938 { generation_time, "Generation time" },
939 { generation_time_confidence, "Generation time standard deviation" },
940 { expiration, "Expiration" },
941 { generation_location, "Generation location" },
942 { request_unrecognized_certificate, "Request unrecognized certificate" },
943 { message_type, "ITS Application ID" }, // Change in definition
944 { signer_info, "Signer info" },
945 { recipient_info, "Encryption parameters" }, // Change in definition
946 { encryption_parameters, "Recipient info" }, // Change in definition
947 { 0x00, NULL}
950 typedef enum {
951 unsecured = 0,
952 signed_pl = 1,
953 encrypted = 2,
954 signed_external = 3,
955 signed_and_encrypted = 4,
957 last_pl_type = (2<<8)-1
958 } PayloadType;
960 static const value_string payload_field_type_names[] = {
961 { unsecured, "Unsecured" },
962 { signed_pl, "Signed" },
963 { encrypted, "Encrypted" },
964 { signed_external, "Signed external" },
965 { signed_and_encrypted, "Signed and encrypted" },
966 { 0, NULL },
969 typedef enum {
970 signature = 1,
972 last_trl_type = (2<<8)-1
973 } TrailerFieldType;
975 static const value_string trailer_field_type_names[] = {
976 { signature, "signature" },
977 { 0, NULL },
980 static int hf_sgeonw_signer_info;
981 static int hf_sgeonw_signer_info_type;
983 typedef enum {
984 self = 0,
985 certificate_digest_with_ecdsap256 = 1,
986 certificate = 2,
987 certificate_chain = 3,
988 certificate_digest_with_other_algorithm = 4,
990 //reserved(240..255),
992 last_sif_type = (2<<8)-1
993 } SignerInfoType;
995 static const value_string signer_info_type_names[] = {
996 { self, "Self signed" },
997 { certificate_digest_with_ecdsap256, "Certificate digest with ecdsap256" },
998 { certificate, "Certificate" },
999 { certificate_chain, "Certificate chain" },
1000 { certificate_digest_with_other_algorithm, "Certificate digest with other algorithm" },
1001 { 0, NULL },
1004 static int hf_sgeonw_public_key;
1005 static int ett_sgeonw_public_key;
1006 static int hf_sgeonw_public_key_algorithm;
1007 static int hf_sgeonw_ecdsasignature_s;
1009 typedef enum {
1010 ecdsa_nistp256_with_sha256 = 0,
1011 ecies_nistp256 = 1,
1013 // reserved(240..255),
1015 last_pubkey_algo = (2<<8)-1
1016 } PublicKeyAlgorithm;
1018 static const value_string public_key_algorithm_names[] = {
1019 { ecdsa_nistp256_with_sha256, "ECDSA nistp256 with SHA256" },
1020 { ecies_nistp256, "ECIES nistp256" },
1021 { 0, NULL },
1024 static const int etsits103097_table_2[] = {
1025 32, // ecdsa_nistp256_with_sha256(0)
1026 32 // ecies_nistp256(1)
1029 static int hf_sgeonw_symmetric_algorithm;
1031 typedef enum {
1032 aes_128_ccm = 0,
1033 // reserved(240..255),
1034 last_sym_algo = (2<<8)-1
1035 } SymmetricAlgorithm;
1037 static const value_string symmetric_algorithm_names[] = {
1038 { aes_128_ccm, "aes_128_ccm" },
1039 { 0, NULL },
1042 static const int etsits103097_table_4[] = {
1043 16 // aes_128_ccm(0)
1046 static int hf_sgeonw_region_type;
1047 static int hf_sgeonw_radius;
1049 typedef enum {
1050 none = 0,
1051 circle = 1,
1052 rectangle = 2,
1053 polygon = 3,
1054 id = 4,
1056 // reserved(240..255),
1058 last_regiontype = (2<<8)-1
1059 } RegionType;
1061 static const value_string region_type_names[] = {
1062 { none, "none" },
1063 { circle, "circle" },
1064 { rectangle, "rectangle" },
1065 { polygon, "polygon" },
1066 { id, "id" },
1067 { 0, NULL },
1070 static int hf_sgeonw_region_dictionary;
1071 static int hf_sgeonw_region_identifier;
1072 static int hf_sgeonw_local_region;
1074 typedef enum {
1075 iso_3166_1 = 0,
1076 un_stats = 1,
1078 last_regiondictionary = (2<<8)-1
1079 } RegionDictionary;
1081 static const value_string region_dictionary_names[] = {
1082 { iso_3166_1, "Numeric country codes as in ISO 3166-1" },
1083 { un_stats, "Defined by UN Statistics Division" },
1084 { 0, NULL },
1087 static int hf_sgeonw_subject_type;
1089 typedef enum {
1090 enrollment_credential = 0,
1091 authorization_ticket = 1,
1092 authorization_authority = 2,
1093 enrollment_authority = 3,
1094 root_ca = 4,
1095 crl_signer = 5,
1097 last_subjecttype = (2<<8)-1
1098 } SubjectType;
1100 static const value_string subject_type_names[] = {
1101 { enrollment_credential, "enrollment_credential" },
1102 { authorization_ticket, "authorization_ticket" },
1103 { authorization_authority, "authorization_authority" },
1104 { enrollment_authority, "enrollment_authority" },
1105 { root_ca, "root_ca" },
1106 { crl_signer, "crl_signer" },
1108 { 0, NULL },
1111 static int hf_sgeonw_subject_attribute_type_v1;
1112 static int hf_sgeonw_subject_attribute_type_v2;
1114 typedef enum {
1115 verification_key = 0,
1116 encryption_key = 1,
1117 assurance_level = 2,
1118 reconstruction_value = 3,
1119 its_aid_list = 32,
1120 its_aid_ssp_list = 33,
1121 priority_its_aid_list = 34,
1122 priority_ssp_list = 35,
1124 last_subjectattributetype = (2<<8)-1
1125 } SubjectAttributeType;
1127 static const value_string subject_attribute_type_v1_names[] = {
1128 { verification_key, "verification_key" },
1129 { encryption_key, "encryption_key" },
1130 { assurance_level, "assurance_level" },
1131 { reconstruction_value, "reconstruction_value" },
1132 { its_aid_list, "its_aid_list" },
1133 { its_aid_ssp_list, "its_aid_ssp_list" },
1134 { priority_its_aid_list, "priority_its_aid_list" },
1135 { priority_ssp_list, "priority_ssp_list" },
1136 { 0, NULL },
1139 static const value_string subject_attribute_type_v2_names[] = {
1140 { verification_key, "verification_key" },
1141 { encryption_key, "encryption_key" },
1142 { assurance_level, "assurance_level" },
1143 { reconstruction_value, "reconstruction_value" },
1144 { its_aid_list, "its_aid_list" },
1145 { its_aid_ssp_list, "its_aid_ssp_list" },
1146 { 0, NULL },
1149 static int hf_sgeonw_validity_restriction_type;
1151 typedef enum {
1152 time_end = 0,
1153 time_start_and_end = 1,
1154 time_start_and_duration = 2,
1155 region = 3,
1157 last_validityrestrictiontype = (2<<8)-1
1158 } ValidityRestrictionType;
1160 static const value_string validity_restriction_type_names[] = {
1161 { time_end, "time_end" },
1162 { time_start_and_end, "time_start_and_end" },
1163 { time_start_and_duration, "time_start_and_duration" },
1164 { region, "region" },
1166 { 0, NULL },
1169 static int hf_sgeonw_eccpoint;
1170 static int ett_sgeonw_eccpoint;
1171 static int hf_sgeonw_eccpoint_type;
1172 static int hf_sgeonw_eccpoint_x;
1173 static int hf_sgeonw_eccpoint_y;
1175 typedef enum {
1176 x_coordinate_only = 0,
1177 compressed_lsb_y_0 = 2,
1178 compressed_lsb_y_1 = 3,
1179 uncompressed = 4,
1181 last_eccpointtype = (2<<8)-1
1182 } EccPointType;
1184 static const value_string eccpoint_type_names[] = {
1185 { x_coordinate_only, "x_coordinate_only" },
1186 { compressed_lsb_y_0, "compressed_lsb_y_0" },
1187 { compressed_lsb_y_1, "compressed_lsb_y_1" },
1188 { uncompressed, "uncompressed" },
1190 { 0, NULL },
1193 // Dissects a length and returns the value
1194 // The encoding of the length shall use at most 7 bits set to 1. We support only 3... 0xfffffff should be enough though to encode a length
1195 static uint32_t
1196 dissect_sec_var_len(tvbuff_t *tvb, int *offset, packet_info *pinfo, proto_tree *tree)
1198 uint32_t tmp_val;
1199 uint32_t var_len;
1200 uint32_t mask;
1201 int start = *offset;
1202 proto_item *ti;
1203 proto_tree *subtree;
1205 // Determine length
1206 var_len = tvb_get_uint8(tvb, *offset);
1207 *offset+=1;
1208 mask = 0x80;
1209 while(mask && (var_len & mask)) {
1210 tmp_val = tvb_get_uint8(tvb, *offset);
1211 *offset += 1;
1212 var_len = ((var_len & ~mask) << 8) + tmp_val;
1213 mask <<= 7;
1215 ti = proto_tree_add_item(tree, hf_sgeonw_var_len, tvb, start, (*offset) - start, ENC_NA); // Length cannot be determined now
1216 subtree = proto_item_add_subtree(ti, ett_sgeonw_var_len);
1217 proto_tree_add_bits_item(subtree, hf_sgeonw_var_len_det, tvb, start << 3, (*offset) - start, ENC_NA);
1218 proto_tree_add_uint_bits_format_value(subtree, hf_sgeonw_var_len_val, tvb, (start << 3) + (*offset) - start, (((*offset) - start) << 3) - ((*offset) - start),var_len,ENC_BIG_ENDIAN,"%u",var_len);
1219 // EI Error if !mask (more than 32 bits)
1220 if (!mask)
1221 expert_add_info(pinfo, ti, &ei_sgeonw_len_unsupported);
1222 return var_len;
1225 // IntX
1226 static int
1227 dissect_sec_intx(tvbuff_t *tvb, int *offset, packet_info *pinfo, proto_tree *tree, int hf, uint32_t *ret)
1229 //uint8_t var_len = 1;
1230 uint64_t tmp_val;
1231 uint64_t mask;
1232 int start = *offset;
1233 proto_item *ti;
1234 proto_tree *subtree;
1236 // Determine length
1237 tmp_val = tvb_get_uint8(tvb, *offset);
1238 *offset+=1;
1239 mask = 0x80;
1240 while(mask && (tmp_val & mask)) {
1241 tmp_val &= ~mask;
1242 tmp_val <<= 8;
1243 tmp_val += tvb_get_uint8(tvb, *offset);
1244 *offset += 1;
1245 mask <<= 7;
1246 //var_len++;
1248 ti = proto_tree_add_item(tree, hf_sgeonw_intx, tvb, start, (*offset) - start, ENC_NA);
1249 subtree = proto_item_add_subtree(ti, ett_sgeonw_intx);
1250 proto_tree_add_bits_item(subtree, hf_sgeonw_var_len_det, tvb, start << 3, (*offset) - start, ENC_NA);
1251 if ((hf != hf_sgeonw_app_id) || ((*offset) - start) > 4) {
1252 proto_tree_add_uint64_bits_format_value(subtree, hf, tvb, (start << 3) + (*offset) - start,
1253 (((*offset) - start) << 3) - ((*offset) - start), tmp_val, ENC_BIG_ENDIAN, "%" PRIu64, tmp_val);
1255 else {
1256 proto_tree_add_uint_bits_format_value(subtree, hf, tvb, (start << 3) + (*offset) - start,
1257 (((*offset) - start) << 3) - ((*offset) - start), (uint32_t)tmp_val, ENC_BIG_ENDIAN, "%s(%u)", val64_to_str_const(tmp_val, ieee1609dot2_Psid_vals, "Unknown") , (uint32_t)tmp_val);
1259 // ETSI TS 103 097 V1.2.1: The encoding of the length shall use at most 7 bits set to 1.
1260 if (!mask)
1261 // EI Error if more than 7
1262 expert_add_info(pinfo, ti, &ei_sgeonw_len_too_long);
1263 if (ret) {
1264 if(tmp_val & 0xffffffff00000000) {
1265 expert_add_info(pinfo, ti, &ei_geonw_intx_too_big);
1267 *ret = (uint32_t) tmp_val;
1270 return (*offset) - start;
1273 static int
1274 dissect_sec_eccpoint(tvbuff_t *tvb, int *offset, packet_info *pinfo, proto_tree *tree, PublicKeyAlgorithm algorithm)
1276 uint32_t tmp_val;
1277 uint32_t param_len;
1278 uint32_t start = *offset;
1279 proto_item *ti;
1280 proto_tree *subtree;
1281 int field_size = etsits103097_table_2[algorithm];
1283 ti = proto_tree_add_item(tree, hf_sgeonw_eccpoint, tvb, *offset, 0, ENC_NA);
1284 subtree = proto_item_add_subtree(ti, ett_sgeonw_eccpoint);
1285 proto_tree_add_item_ret_uint(subtree, hf_sgeonw_eccpoint_type, tvb, *offset, 1, ENC_BIG_ENDIAN, &tmp_val);
1286 // Opaque[field_size]
1287 proto_tree_add_item(subtree, hf_sgeonw_eccpoint_x, tvb, 1+(*offset), field_size, ENC_NA);
1288 *offset += field_size+1;
1289 switch(tmp_val) {
1290 case x_coordinate_only:
1291 case compressed_lsb_y_0:
1292 case compressed_lsb_y_1:
1293 break;
1294 case uncompressed:
1295 // Opaque[field_size]
1296 proto_tree_add_item(subtree, hf_sgeonw_eccpoint_y, tvb, *offset, field_size, ENC_NA);
1297 *offset += field_size;
1298 break;
1299 default:
1300 // Opaque<var>
1301 param_len = dissect_sec_var_len(tvb, offset, pinfo, subtree);
1302 proto_tree_add_item(subtree, hf_sgeonw_opaque, tvb, *offset, param_len, ENC_NA);
1303 *offset += param_len;
1305 proto_item_set_end(ti, tvb, *offset);
1306 return (*offset) - start;
1309 static int
1310 dissect_sec_publickey(tvbuff_t *tvb, int *offset, packet_info *pinfo, proto_tree *tree)
1312 uint32_t tmp_val;
1313 uint32_t param_len;
1314 int start = *offset;
1315 proto_item *part_item;
1316 proto_tree *part_tree;
1318 part_item = proto_tree_add_item(tree, hf_sgeonw_public_key, tvb, *offset, 0, ENC_NA); // Length cannot be determined now
1319 part_tree = proto_item_add_subtree(part_item, ett_sgeonw_public_key);
1320 proto_tree_add_item_ret_uint(part_tree, hf_sgeonw_public_key_algorithm, tvb, *offset, 1, ENC_BIG_ENDIAN, &tmp_val);
1321 *offset += 1;
1322 switch(tmp_val) {
1323 case ecdsa_nistp256_with_sha256:
1324 // EccPoint
1325 dissect_sec_eccpoint(tvb, offset, pinfo, part_tree, (PublicKeyAlgorithm) tmp_val);
1326 break;
1327 case ecies_nistp256:
1328 // SymAlgo + EccPoint
1329 proto_tree_add_item(part_tree, hf_sgeonw_symmetric_algorithm, tvb, *offset, 1, ENC_BIG_ENDIAN);
1330 *offset += 1;
1331 dissect_sec_eccpoint(tvb, offset, pinfo, part_tree, (PublicKeyAlgorithm) tmp_val);
1332 break;
1333 default:
1334 // Opaque
1335 param_len = dissect_sec_var_len(tvb, offset, pinfo, part_tree);
1336 proto_tree_add_item(part_tree, hf_sgeonw_opaque, tvb, *offset, param_len, ENC_NA);
1337 *offset += param_len;
1339 proto_item_set_end(part_item, tvb, *offset);
1340 return (*offset) - start;
1343 static int
1344 dissect_sec_encryption_parameters(tvbuff_t *tvb, int *offset, packet_info *pinfo, proto_tree *tree)
1346 uint32_t tmp_val;
1347 uint32_t param_len;
1348 uint32_t start = *offset;
1349 proto_item *part_item;
1350 proto_tree *part_tree;
1352 part_item = proto_tree_add_item(tree, hf_sgeonw_encryption_parameter, tvb, *offset, 0, ENC_NA); // Length cannot be determined now
1353 part_tree = proto_item_add_subtree(part_item, ett_sgeonw_encryption_parameter);
1354 proto_tree_add_item_ret_uint(part_tree, hf_sgeonw_symmetric_algorithm, tvb, *offset, 1, ENC_BIG_ENDIAN, &tmp_val);
1355 *offset += 1;
1356 switch(tmp_val) {
1357 case ecdsa_nistp256_with_sha256:
1358 // Opaque[12]
1359 proto_tree_add_item(part_tree, hf_sgeonw_encryption_parameter_nonce, tvb, *offset, 12, ENC_NA);
1360 *offset += 12;
1361 break;
1362 default:
1363 // Opaque
1364 param_len = dissect_sec_var_len(tvb, offset, pinfo, part_tree);
1365 proto_tree_add_item(part_tree, hf_sgeonw_opaque, tvb, *offset, param_len, ENC_NA);
1366 *offset += param_len;
1368 proto_item_set_end(part_item, tvb, *offset);
1369 return (*offset) - start;
1372 static int
1373 dissect_sec_ecdsasignature(tvbuff_t *tvb, int *offset, packet_info *pinfo, proto_tree *tree, PublicKeyAlgorithm algorithm)
1375 uint32_t start = *offset;
1376 int field_size = etsits103097_table_2[algorithm];
1378 dissect_sec_eccpoint(tvb, offset, pinfo, tree, algorithm);
1379 proto_tree_add_item(tree, hf_sgeonw_ecdsasignature_s, tvb, *offset, field_size, ENC_NA);
1380 *offset += field_size;
1381 return (*offset) - start;
1384 static int
1385 dissect_sec_signature(tvbuff_t *tvb, int *offset, packet_info *pinfo, proto_tree *tree)
1387 int start = *offset;
1388 uint32_t param_len;
1389 uint32_t tmp_val;
1390 proto_item *part_item;
1391 proto_tree *part_tree;
1393 part_item = proto_tree_add_item(tree, hf_sgeonw_signature, tvb, *offset, 0, ENC_NA); // Length cannot be determined now
1394 part_tree = proto_item_add_subtree(part_item, ett_sgeonw_signature);
1395 proto_tree_add_item_ret_uint(part_tree, hf_sgeonw_public_key_algorithm, tvb, *offset, 1, ENC_BIG_ENDIAN, &tmp_val);
1396 *offset += 1;
1397 switch(tmp_val) {
1398 case ecdsa_nistp256_with_sha256:
1399 // EcdsaSignature
1400 dissect_sec_ecdsasignature(tvb, offset, pinfo, part_tree, ecdsa_nistp256_with_sha256);
1401 break;
1402 default:
1403 // Opaque
1404 param_len = dissect_sec_var_len(tvb, offset, pinfo, part_tree);
1405 proto_tree_add_item(part_tree, hf_sgeonw_opaque, tvb, *offset, param_len, ENC_NA);
1406 *offset += param_len;
1408 proto_item_set_end(part_item, tvb, *offset);
1409 return (*offset) - start;
1412 inline static int
1413 dissect_sec_2dlocation(tvbuff_t *tvb, int *offset, proto_tree *tree)
1415 proto_tree_add_item(tree, hf_sgeonw_lat, tvb, *offset, 4, ENC_BIG_ENDIAN);
1416 proto_tree_add_item(tree, hf_sgeonw_lon, tvb, 4+*offset, 4, ENC_BIG_ENDIAN);
1417 *offset += 8;
1419 return 8;
1423 static int
1424 dissect_sec_subject_info(tvbuff_t *tvb, int *offset, packet_info *pinfo, proto_tree *tree)
1426 uint32_t param_len;
1427 int start = *offset;
1428 proto_item *ti;
1429 proto_item *part_item;
1430 proto_tree *part_tree;
1432 part_item = proto_tree_add_item(tree, hf_sgeonw_subject_info, tvb, *offset, 0, ENC_NA); // Length cannot be determined now
1433 part_tree = proto_item_add_subtree(part_item, ett_sgeonw_subject_info);
1434 proto_tree_add_item(part_tree, hf_sgeonw_subject_type, tvb, *offset, 1, ENC_BIG_ENDIAN);
1435 *offset += 1;
1436 param_len = dissect_sec_var_len(tvb, offset, pinfo, part_tree);
1437 ti = proto_tree_add_item(part_tree, hf_sgeonw_opaque, tvb, *offset, param_len, ENC_NA);
1438 // Expert info: shall be at most 255 bytes long
1439 if (param_len > 255)
1440 expert_add_info(pinfo, ti, &ei_sgeonw_subj_info_too_long);
1441 *offset += param_len;
1442 proto_item_set_end(part_item, tvb, *offset);
1444 return (*offset) - start;
1447 static int
1448 dissect_sec_itsaidssp(tvbuff_t *tvb, int *offset, packet_info *pinfo, proto_tree *tree)
1450 int start = *offset;
1451 uint32_t param_len;
1452 uint32_t appid;
1453 proto_item *ti;
1454 proto_tree *subtree;
1456 dissect_sec_intx(tvb, offset, pinfo, tree, hf_sgeonw_app_id, &appid);
1457 param_len = dissect_sec_var_len(tvb, offset, pinfo, tree);
1458 ti = proto_tree_add_item(tree, hf_sgeonw_opaque, tvb, *offset, param_len, ENC_NA);
1459 // Expert info: shall be at most 31 bytes long
1460 if (param_len > 31) {
1461 expert_add_info(pinfo, ti, &ei_sgeonw_ssp_too_long);
1463 else {
1464 subtree = proto_item_add_subtree(ti, ett_sgeonw_ssp);
1465 tvbuff_t *next_tvb = tvb_new_subset_length(tvb, *offset, param_len);
1466 dissector_try_uint(ssp_subdissector_table, appid, next_tvb, pinfo, subtree);
1468 *offset += param_len;
1470 return (*offset) - start;
1473 static int hf_sgeonw_priority;
1475 static int
1476 dissect_sec_itsaidpriority(tvbuff_t *tvb, int *offset, packet_info *pinfo, proto_tree *tree)
1478 int start = *offset;
1480 dissect_sec_intx(tvb, offset, pinfo, tree, hf_sgeonw_app_id, NULL);
1481 proto_tree_add_item(tree, hf_sgeonw_priority, tvb, *offset, 1, ENC_BIG_ENDIAN);
1482 *offset += 1;
1484 return (*offset) - start;
1487 static int
1488 dissect_sec_itsaidpriorityssp(tvbuff_t *tvb, int *offset, packet_info *pinfo, proto_tree *tree)
1490 int start = *offset;
1491 uint32_t param_len;
1492 proto_item *ti;
1494 dissect_sec_intx(tvb, offset, pinfo, tree, hf_sgeonw_app_id, NULL);
1495 proto_tree_add_item(tree, hf_sgeonw_priority, tvb, *offset, 1, ENC_BIG_ENDIAN);
1496 *offset += 1;
1497 param_len = dissect_sec_var_len(tvb, offset, pinfo, tree);
1498 ti = proto_tree_add_item(tree, hf_sgeonw_opaque, tvb, *offset, param_len, ENC_NA);
1499 // Expert info: shall be at most 31 bytes long
1500 if (param_len > 31)
1501 expert_add_info(pinfo, ti, &ei_sgeonw_ssp_too_long);
1502 *offset += param_len;
1504 return (*offset) - start;
1507 static int hf_sgeonw_subject_assurance;
1508 static int ett_sgeonw_subject_assurance;
1509 static int hf_sgeonw_subject_assurance_assurance;
1510 static int hf_sgeonw_subject_assurance_reserved;
1511 static int hf_sgeonw_subject_assurance_confidence;
1513 static int
1514 dissect_sec_subject_attributes(tvbuff_t *tvb, int *offset, packet_info *pinfo, proto_tree *tree, uint8_t version)
1516 int start = *offset;
1517 uint32_t tmp_val;
1518 uint32_t param_len;
1519 proto_item *ti;
1520 proto_item *part_item;
1521 proto_tree *subtree;
1523 part_item = proto_tree_add_item(tree, hf_sgeonw_subject_attribute, tvb, *offset, 0, ENC_NA);
1524 subtree = proto_item_add_subtree(part_item, ett_sgeonw_subject_attribute);
1525 ti = proto_tree_add_item_ret_uint(subtree, version == 1 ? hf_sgeonw_subject_attribute_type_v1 : hf_sgeonw_subject_attribute_type_v2, tvb, *offset, 1, ENC_BIG_ENDIAN, &tmp_val);
1526 *offset += 1;
1527 switch (tmp_val) {
1528 case verification_key:
1529 case encryption_key:
1530 dissect_sec_publickey(tvb,offset,pinfo,subtree);
1531 break;
1532 case assurance_level:
1533 ti = proto_tree_add_item(subtree, hf_sgeonw_subject_assurance, tvb, *offset, 1, ENC_NA);
1534 subtree = proto_item_add_subtree(ti, ett_sgeonw_subject_assurance);
1535 proto_tree_add_item(subtree, hf_sgeonw_subject_assurance_assurance, tvb, *offset, 1, ENC_BIG_ENDIAN);
1536 proto_tree_add_item(subtree, hf_sgeonw_subject_assurance_reserved, tvb, *offset, 1, ENC_BIG_ENDIAN);
1537 proto_tree_add_item(subtree, hf_sgeonw_subject_assurance_confidence, tvb, *offset, 1, ENC_BIG_ENDIAN);
1538 *offset += 1;
1539 break;
1540 case reconstruction_value:
1541 dissect_sec_eccpoint(tvb,offset,pinfo,subtree,ecdsa_nistp256_with_sha256); // XXX Which algorithm? hack as only one algo defined
1542 break;
1543 case its_aid_list:
1544 tmp_val = dissect_sec_var_len(tvb, offset, pinfo, subtree);
1545 while (tmp_val > 0) {
1546 param_len = dissect_sec_intx(tvb,offset,pinfo, subtree, hf_sgeonw_app_id, NULL);
1547 if(tmp_val < param_len) {
1548 expert_add_info(pinfo, ti, &ei_sgeonw_bogus);
1549 return *offset - start;
1551 tmp_val -= param_len;
1553 break;
1554 case its_aid_ssp_list:
1555 tmp_val = dissect_sec_var_len(tvb, offset, pinfo, subtree);
1556 while (tmp_val > 0) {
1557 param_len = dissect_sec_itsaidssp(tvb, offset, pinfo, subtree);
1558 if(tmp_val < param_len) {
1559 expert_add_info(pinfo, ti, &ei_sgeonw_bogus);
1560 return *offset - start;
1562 tmp_val -= param_len;
1564 break;
1565 case priority_its_aid_list:
1566 tmp_val = dissect_sec_var_len(tvb, offset, pinfo, subtree);
1567 while (tmp_val > 0) {
1568 param_len = dissect_sec_itsaidpriority(tvb, offset, pinfo, subtree);
1569 if(tmp_val < param_len) {
1570 expert_add_info(pinfo, ti, &ei_sgeonw_bogus);
1571 return *offset - start;
1573 tmp_val -= param_len;
1575 break;
1576 case priority_ssp_list:
1577 tmp_val = dissect_sec_var_len(tvb, offset, pinfo, subtree);
1578 while (tmp_val > 0) {
1579 param_len = dissect_sec_itsaidpriorityssp(tvb, offset, pinfo, subtree);
1580 if(tmp_val < param_len) {
1581 expert_add_info(pinfo, ti, &ei_sgeonw_bogus);
1582 return *offset - start;
1584 tmp_val -= param_len;
1586 break;
1587 default:
1588 // Opaque
1589 param_len = dissect_sec_var_len(tvb, offset, pinfo, subtree);
1590 proto_tree_add_item(subtree, hf_sgeonw_opaque, tvb, *offset, param_len, ENC_NA);
1591 *offset += param_len;
1593 proto_item_set_end(part_item, tvb, *offset);
1595 return (*offset) - start;
1598 static int
1599 dissect_sec_circularregion(tvbuff_t *tvb, int *offset, proto_tree *tree)
1601 dissect_sec_2dlocation(tvb, offset, tree);
1602 // uint16
1603 proto_tree_add_item(tree, hf_sgeonw_radius, tvb, *offset, 2, ENC_BIG_ENDIAN);
1604 *offset += 2;
1606 return 10;
1609 static int
1610 dissect_sec_rectangularregion(tvbuff_t *tvb, int *offset, proto_tree *tree)
1612 dissect_sec_2dlocation(tvb, offset, tree);
1613 dissect_sec_2dlocation(tvb, offset, tree);
1615 return 16;
1618 static int
1619 dissect_sec_polygonalregion(tvbuff_t *tvb, int *offset, packet_info *pinfo, proto_tree *tree)
1621 int start = *offset;
1622 uint32_t param_len;
1623 uint32_t tmp_val;
1625 tmp_val = dissect_sec_var_len(tvb, offset, pinfo, tree);
1626 while (tmp_val) {
1627 param_len = dissect_sec_2dlocation(tvb, offset, tree);
1628 if(tmp_val < param_len)
1629 return *offset - start;
1630 tmp_val -= param_len;
1633 return (*offset) - start;
1636 static int
1637 dissect_sec_identifiedregion(tvbuff_t *tvb, int *offset, packet_info *pinfo, proto_tree *tree)
1639 int start = *offset;
1641 proto_tree_add_item(tree, hf_sgeonw_region_dictionary, tvb, *offset, 1, ENC_BIG_ENDIAN);
1642 proto_tree_add_item(tree, hf_sgeonw_region_identifier, tvb, *offset, 2, ENC_BIG_ENDIAN);
1643 *offset += 3;
1644 dissect_sec_intx(tvb, offset, pinfo, tree, hf_sgeonw_local_region, NULL);
1646 return (*offset) - start;
1649 static int
1650 dissect_sec_geographicregion(tvbuff_t *tvb, int *offset, packet_info *pinfo, proto_tree *tree)
1652 int start = *offset;
1653 uint32_t param_len;
1654 uint32_t tmp_val;
1656 proto_tree_add_item_ret_uint(tree, hf_sgeonw_region_type, tvb, *offset, 1, ENC_BIG_ENDIAN, &tmp_val);
1657 *offset += 1;
1658 switch (tmp_val) {
1659 case none:
1660 break;
1661 case circle:
1662 dissect_sec_circularregion(tvb,offset,tree);
1663 break;
1664 case rectangle:
1665 dissect_sec_rectangularregion(tvb,offset,tree);
1666 break;
1667 case polygon:
1668 dissect_sec_polygonalregion(tvb, offset, pinfo, tree);
1669 break;
1670 case id:
1671 dissect_sec_identifiedregion(tvb, offset, pinfo, tree);
1672 break;
1673 default:
1674 // Opaque
1675 param_len = dissect_sec_var_len(tvb, offset, pinfo, tree);
1676 proto_tree_add_item(tree, hf_sgeonw_opaque, tvb, *offset, param_len, ENC_NA);
1677 *offset += param_len;
1680 return (*offset) - start;
1683 static const value_string sgeonw_duration_unit_names[] = {
1684 { 0, "Seconds" },
1685 { 1, "Minutes" },
1686 { 2, "Hours" },
1687 { 3, "60 Hours block" },
1688 { 4, "Years" },
1689 { 0, NULL }
1692 static int
1693 dissect_sec_validity_restrictions(tvbuff_t *tvb, int *offset, packet_info *pinfo, proto_tree *tree)
1695 int start = *offset;
1696 uint32_t tmp_val;
1697 uint32_t param_len;
1698 proto_item *ti;
1699 proto_tree *subtree;
1701 proto_tree_add_item_ret_uint(tree, hf_sgeonw_validity_restriction_type, tvb, *offset, 1, ENC_BIG_ENDIAN, &tmp_val);
1702 *offset += 1;
1703 switch (tmp_val) {
1704 case time_end:
1705 // Time32
1706 proto_tree_add_item(tree, hf_sgeonw_time32, tvb, *offset, 4, ENC_BIG_ENDIAN);
1707 *offset += 4;
1708 break;
1709 case time_start_and_end:
1710 // Time32
1711 proto_tree_add_item(tree, hf_sgeonw_time32, tvb, *offset, 4, ENC_BIG_ENDIAN);
1712 *offset += 4;
1713 // Time32
1714 proto_tree_add_item(tree, hf_sgeonw_time32, tvb, *offset, 4, ENC_BIG_ENDIAN);
1715 *offset += 4;
1716 break;
1717 case time_start_and_duration:
1718 // Time32
1719 proto_tree_add_item(tree, hf_sgeonw_time32, tvb, *offset, 4, ENC_BIG_ENDIAN);
1720 *offset += 4;
1721 // Duration
1722 ti = proto_tree_add_item(tree, hf_sgeonw_duration, tvb, *offset, 2, ENC_NA);
1723 subtree = proto_item_add_subtree(ti, ett_sgeonw_duration);
1724 proto_tree_add_item(subtree, hf_sgeonw_duration_unit, tvb, *offset, 2, ENC_BIG_ENDIAN);
1725 proto_tree_add_item(subtree, hf_sgeonw_duration_value, tvb, *offset, 2, ENC_BIG_ENDIAN);
1726 *offset += 2;
1727 break;
1728 case region:
1729 dissect_sec_geographicregion(tvb, offset, pinfo, tree);
1730 break;
1731 default:
1732 // Opaque
1733 param_len = dissect_sec_var_len(tvb, offset, pinfo, tree);
1734 proto_tree_add_item(tree, hf_sgeonw_opaque, tvb, *offset, param_len, ENC_NA);
1735 *offset += param_len;
1737 return (*offset) - start;
1740 static int dissect_sec_signer_info(tvbuff_t *tvb, int *offset, packet_info *pinfo, proto_tree *tree, uint8_t version);
1742 static int hf_sgeonw_certification_version;
1744 static int
1745 // NOLINTNEXTLINE(misc-no-recursion)
1746 dissect_sec_certificate(tvbuff_t *tvb, int *offset, packet_info *pinfo, proto_tree *tree, uint8_t version)
1748 uint32_t tmp_val;
1749 uint32_t param_len;
1750 int start = *offset;
1752 proto_tree_add_item_ret_uint(tree, hf_sgeonw_certification_version, tvb, *offset, 1, ENC_BIG_ENDIAN, &tmp_val);
1753 *offset += 1;
1754 if (version == 1) {
1755 tmp_val = dissect_sec_var_len(tvb, offset, pinfo, tree);
1756 while (tmp_val > 0) {
1757 param_len = dissect_sec_signer_info(tvb, offset, pinfo, tree, version);
1758 tmp_val -= param_len;
1761 else {
1762 dissect_sec_signer_info(tvb, offset, pinfo, tree, version);
1764 dissect_sec_subject_info(tvb, offset, pinfo, tree);
1765 tmp_val = dissect_sec_var_len(tvb, offset, pinfo, tree);
1766 while (tmp_val > 0) {
1767 param_len = dissect_sec_subject_attributes(tvb, offset, pinfo, tree, version);
1768 tmp_val -= param_len;
1770 tmp_val = dissect_sec_var_len(tvb, offset, pinfo, tree);
1771 while (tmp_val > 0) {
1772 param_len = dissect_sec_validity_restrictions(tvb, offset, pinfo, tree);
1773 tmp_val -= param_len;
1775 dissect_sec_signature(tvb, offset, pinfo, tree);
1777 return (*offset) - start;
1780 static int
1781 // NOLINTNEXTLINE(misc-no-recursion)
1782 dissect_sec_signer_info(tvbuff_t *tvb, int *offset, packet_info *pinfo, proto_tree *tree, uint8_t version)
1784 int start = *offset;
1785 uint32_t tmp_val;
1786 uint32_t param_len;
1787 proto_item *ti;
1788 proto_tree *subtree;
1789 proto_item *tinner;
1790 proto_tree *insidetree;
1792 increment_dissection_depth(pinfo);
1794 tmp_val = tvb_get_uint8(tvb, *offset);
1795 if (tmp_val == self) {
1796 // No additional data shall be given
1797 proto_tree_add_item(tree, hf_sgeonw_signer_info_type, tvb, *offset, 1, ENC_BIG_ENDIAN);
1798 *offset += 1;
1800 else {
1801 ti = proto_tree_add_item(tree, hf_sgeonw_signer_info, tvb, *offset, 0, ENC_NA);
1802 subtree = proto_item_add_subtree(ti, ett_sgeonw_field);
1803 proto_tree_add_item(subtree, hf_sgeonw_signer_info_type, tvb, *offset, 1, ENC_BIG_ENDIAN);
1804 *offset += 1;
1805 switch(tmp_val) {
1806 case certificate_digest_with_ecdsap256:
1807 // HashedId8
1808 proto_tree_add_item(subtree, hf_sgeonw_hashedid8, tvb, *offset, 8, ENC_NA);
1809 *offset += 8;
1810 break;
1811 case certificate:
1812 // Certificate
1813 tinner = proto_tree_add_item(subtree, hf_sgeonw_certificate, tvb, *offset, 0, ENC_NA);
1814 insidetree = proto_item_add_subtree(tinner, ett_sgeonw_field);
1815 dissect_sec_certificate(tvb, offset, pinfo, insidetree, version);
1816 proto_item_set_end(tinner, tvb, *offset);
1817 break;
1818 case certificate_chain:
1819 // variable-length vector of type Certificate
1820 tmp_val = dissect_sec_var_len(tvb, offset, pinfo, subtree);
1821 while (tmp_val > 0) {
1822 tinner = proto_tree_add_item(subtree, hf_sgeonw_certificate, tvb, *offset, 0, ENC_NA);
1823 insidetree = proto_item_add_subtree(tinner, ett_sgeonw_field);
1824 param_len = dissect_sec_certificate(tvb, offset, pinfo, insidetree, version);
1825 proto_item_set_end(tinner, tvb, *offset);
1826 tmp_val -= param_len;
1828 break;
1829 case certificate_digest_with_other_algorithm:
1830 // HashedId8
1831 proto_tree_add_item(subtree, hf_sgeonw_public_key_algorithm, tvb, *offset, 1, ENC_BIG_ENDIAN);
1832 proto_tree_add_item(subtree, hf_sgeonw_hashedid8, tvb, 1+(*offset), 8, ENC_NA);
1833 *offset += 9;
1834 break;
1835 default:
1836 // Opaque
1837 param_len = dissect_sec_var_len(tvb, offset, pinfo, subtree);
1838 proto_tree_add_item(subtree, hf_sgeonw_opaque, tvb, *offset, param_len, ENC_NA);
1839 *offset += param_len;
1841 proto_item_set_end(ti, tvb, *offset);
1843 decrement_dissection_depth(pinfo);
1844 return (*offset) - start;
1848 static int hf_sgeonw_encrypted_key;
1849 static int hf_sgeonw_auth_tag;
1851 // This structure defines how to transmit an EciesNistP256-encrypted symmetric key as defined in IEEE
1852 // Std 1363a-2004.
1853 // EciesNistP256EncryptedKey structure shall be preceded by an according
1854 // EncryptionParameters structure.
1855 static int
1856 dissect_sec_eciesnistp256entryptedkey(tvbuff_t *tvb, int *offset, packet_info *pinfo, proto_tree *tree, PublicKeyAlgorithm pub_alg, SymmetricAlgorithm symm_alg, uint8_t version)
1858 int start = *offset;
1859 uint8_t symm_key_len = etsits103097_table_4[symm_alg];
1861 dissect_sec_eccpoint(tvb, offset, pinfo, tree, pub_alg);
1862 proto_tree_add_item(tree, hf_sgeonw_encrypted_key, tvb, *offset, symm_key_len, ENC_NA);
1863 *offset += symm_key_len;
1864 proto_tree_add_item(tree, hf_sgeonw_auth_tag, tvb, *offset, version==1?20:16, ENC_NA);
1865 *offset += version==1?20:16;
1867 return (*offset) - start;
1871 static int
1872 dissect_sec_recipient_info(tvbuff_t *tvb, int *offset, packet_info *pinfo, proto_tree *tree, uint8_t version)
1874 int start = *offset;
1875 uint32_t tmp_val;
1876 uint32_t param_len;
1878 proto_tree_add_item(tree, hf_sgeonw_hashedid8, tvb, *offset, 8, ENC_NA);
1879 proto_tree_add_item_ret_uint(tree, hf_sgeonw_public_key_algorithm, tvb, 8+*offset, 1, ENC_BIG_ENDIAN, &tmp_val);
1880 *offset += 9;
1881 switch (tmp_val) {
1882 case ecies_nistp256:
1883 // EciesNistP256EncryptedKey
1884 // XXX SymmetricAlgorithm should be provided by preceding EncryptionParameter...
1885 dissect_sec_eciesnistp256entryptedkey(tvb, offset, pinfo, tree, (PublicKeyAlgorithm)tmp_val, aes_128_ccm, version);
1886 break;
1887 default:
1888 // Opaque
1889 param_len = dissect_sec_var_len(tvb, offset, pinfo, tree);
1890 proto_tree_add_item(tree, hf_sgeonw_opaque, tvb, *offset, param_len, ENC_NA);
1891 *offset += param_len;
1894 return (*offset) - start;
1898 static int
1899 dissect_sec_payload(tvbuff_t *tvb, int *offset, packet_info *pinfo, proto_tree *part_tree)
1901 int start = *offset;
1902 uint32_t tmp_val;
1903 uint32_t param_len;
1904 proto_tree *field_tree;
1905 proto_item *ti;
1907 tmp_val = tvb_get_uint8(tvb, *offset);
1908 if (tmp_val == signed_external) {
1909 proto_tree_add_item(part_tree, hf_sgeonw_payload_field_type, tvb, *offset, 1, ENC_BIG_ENDIAN);
1910 *offset += 1;
1912 else {
1913 ti = proto_tree_add_item(part_tree, hf_sgeonw_payload_field, tvb, *offset, 0, ENC_NA);
1914 field_tree = proto_item_add_subtree(ti, ett_sgeonw_field);
1915 proto_tree_add_item(field_tree, hf_sgeonw_payload_field_type, tvb, *offset, 1, ENC_BIG_ENDIAN);
1916 *offset += 1;
1917 switch(tmp_val) {
1918 case unsecured:
1919 case signed_pl:
1920 param_len = dissect_sec_var_len(tvb, offset, pinfo, field_tree);
1921 if (param_len) {
1922 tvbuff_t *next_tvb = tvb_new_subset_length(tvb, *offset, param_len);
1923 p_add_proto_data(pinfo->pool, pinfo, proto_geonw, SEC_TVB_KEY, next_tvb);
1925 *offset += param_len;
1926 break;
1927 case encrypted:
1928 case signed_and_encrypted:
1929 param_len = dissect_sec_var_len(tvb, offset, pinfo, field_tree);
1930 proto_tree_add_item(field_tree, hf_sgeonw_opaque, tvb, *offset, param_len, ENC_NA);
1931 *offset += param_len;
1932 break;
1933 default:
1934 // Opaque
1935 param_len = dissect_sec_var_len(tvb, offset, pinfo, field_tree);
1936 proto_tree_add_item(field_tree, hf_sgeonw_opaque, tvb, *offset, param_len, ENC_NA);
1937 *offset += param_len;
1939 proto_item_set_end(ti, tvb, *offset);
1942 return (*offset) - start;
1946 static int
1947 dissect_secured_message(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, void *data _U_)
1949 uint32_t msg_id; // Or Application ID, depending on version
1950 uint8_t version;
1951 uint32_t var_len;
1952 proto_item *ti;
1953 uint32_t tmp_val;
1954 uint32_t param_len;
1955 proto_item *secmsg_item;
1956 proto_item *part_item;
1957 proto_tree *part_tree;
1958 proto_tree *field_tree;
1959 int sec_start = offset;
1961 // Secured message subtree
1962 secmsg_item = proto_tree_add_item(tree, hf_geonw_sec, tvb, offset, 0, ENC_NA); // Length cannot be determined now
1963 proto_tree *secmsg_tree = proto_item_add_subtree(secmsg_item, ett_geonw_sec);
1965 version = tvb_get_uint8(tvb, offset);
1966 if (version == 3) {
1967 tvbuff_t *next_tvb = tvb_new_subset_remaining(tvb, offset);
1968 call_dissector(ieee1609dot2_handle, next_tvb, pinfo, secmsg_tree);
1969 // If unsecure or only signed, content is in private data
1970 return tvb_captured_length(tvb);
1973 proto_tree_add_item(secmsg_tree, hf_sgeonw_version, tvb, offset, 1, ENC_BIG_ENDIAN);
1974 offset+=1;
1975 if ((version < 1) || (version > 2))
1976 return 1;
1977 if (version == 1) {
1978 proto_tree_add_item_ret_uint(secmsg_tree, hf_sgeonw_profile, tvb, offset, 1, ENC_BIG_ENDIAN, &tmp_val);
1979 offset += 1;
1981 // Header Fields
1982 part_item = proto_tree_add_item(secmsg_tree, hf_sgeonw_hdr, tvb, offset, 0, ENC_NA); // Length cannot be determined now
1983 part_tree = proto_item_add_subtree(part_item, ett_sgeonw_hdr);
1985 var_len = dissect_sec_var_len(tvb, &offset, pinfo, part_tree);
1986 while (var_len > 0) {
1988 uint32_t start = offset;
1990 ti = proto_tree_add_item(part_tree, hf_sgeonw_header_field, tvb, offset, 0, ENC_NA);
1991 field_tree = proto_item_add_subtree(ti, ett_sgeonw_field);
1992 proto_tree_add_item_ret_uint(field_tree, version==1?hf_sgeonw_header_field_type_v1:hf_sgeonw_header_field_type_v2, tvb, offset, 1, ENC_BIG_ENDIAN, &tmp_val);
1993 offset += 1;
1994 switch(tmp_val) {
1995 case generation_time:
1996 // Time64
1997 proto_tree_add_item(field_tree, hf_sgeonw_time64, tvb, offset, 8, ENC_BIG_ENDIAN);
1998 offset += 8;
1999 break;
2000 case generation_time_confidence:
2001 // Time64WithStandardDeviation
2002 proto_tree_add_item(field_tree, hf_sgeonw_time64, tvb, offset, 8, ENC_BIG_ENDIAN);
2003 proto_tree_add_item(field_tree, hf_sgeonw_conf, tvb, offset+8, 1, ENC_BIG_ENDIAN);
2004 offset += 9;
2005 break;
2006 case expiration:
2007 // Time32
2008 proto_tree_add_item(field_tree, hf_sgeonw_time32, tvb, offset, 4, ENC_BIG_ENDIAN);
2009 offset += 4;
2010 break;
2011 case generation_location:
2012 // ThreeDLocation
2013 proto_tree_add_item(field_tree, hf_sgeonw_lat, tvb, offset, 4, ENC_BIG_ENDIAN);
2014 proto_tree_add_item(field_tree, hf_sgeonw_lon, tvb, offset+4, 4, ENC_BIG_ENDIAN);
2015 proto_tree_add_item(field_tree, hf_sgeonw_elev, tvb, offset+8, 2, ENC_BIG_ENDIAN);
2016 offset += 10;
2017 break;
2018 case request_unrecognized_certificate:
2019 // HashedId3
2020 param_len = dissect_sec_var_len(tvb, &offset, pinfo, field_tree);
2021 proto_item_set_len(ti, (offset-start) + param_len);
2022 while (param_len) {
2023 proto_tree_add_item(field_tree, hf_sgeonw_hashedid3, tvb, offset, 3, ENC_NA);
2024 offset += 3;
2025 param_len -= 3;
2027 break;
2028 case message_type:
2029 if (version == 1) {
2030 proto_tree_add_item_ret_uint(field_tree, hf_sgeonw_msg_id, tvb, offset, 2, ENC_BIG_ENDIAN, &msg_id);
2031 offset += 2;
2033 else {
2034 dissect_sec_intx(tvb, &offset, pinfo, field_tree, hf_sgeonw_app_id, &msg_id);
2036 break;
2037 case signer_info:
2038 // SignerInfo
2039 dissect_sec_signer_info(tvb, &offset, pinfo, field_tree, version);
2040 break;
2041 case recipient_info:
2042 // RecipientInfo
2043 param_len = dissect_sec_var_len(tvb, &offset, pinfo, field_tree);
2044 proto_item_set_len(ti, (offset-start) + param_len);
2045 while (param_len) {
2046 param_len -= dissect_sec_recipient_info(tvb, &offset, pinfo, field_tree, version);
2048 offset += param_len;
2049 break;
2050 case encryption_parameters:
2051 // EncryptionParameters
2052 dissect_sec_encryption_parameters(tvb, &offset, pinfo, field_tree);
2053 break;
2054 default:
2055 // Opaque
2056 param_len = dissect_sec_var_len(tvb, &offset, pinfo, field_tree);
2057 proto_item_set_len(ti, (offset-start) + param_len);
2058 proto_tree_add_item(field_tree, hf_sgeonw_opaque, tvb, offset, param_len, ENC_NA);
2059 offset += param_len;
2061 proto_item_set_end(ti, tvb, offset);
2062 /* EI var_len >= (offset-start) */
2063 var_len -= (offset - start);
2065 proto_item_set_end(part_item, tvb, offset);
2067 // Payload
2068 part_item = proto_tree_add_item(secmsg_tree, hf_sgeonw_pl, tvb, offset, 0, ENC_NA); // Length cannot be determined now
2069 part_tree = proto_item_add_subtree(part_item, ett_sgeonw_hdr);
2071 // Change in version 2: only one payload element here!
2072 if (version == 1) {
2073 var_len = dissect_sec_var_len(tvb, &offset, pinfo, part_tree);
2074 while (var_len > 0) {
2076 uint32_t start = offset;
2078 dissect_sec_payload(tvb, &offset, pinfo, part_tree);
2079 if (var_len < (offset-start))
2080 return 0;
2081 var_len -= (offset - start);
2084 else {
2085 dissect_sec_payload(tvb, &offset, pinfo, part_tree);
2087 proto_item_set_end(part_item, tvb, offset);
2089 // Trailer
2090 part_item = proto_tree_add_item(secmsg_tree, hf_sgeonw_trl, tvb, offset, 0, ENC_NA); // Length cannot be determined now
2091 part_tree = proto_item_add_subtree(part_item, ett_sgeonw_hdr);
2093 var_len = dissect_sec_var_len(tvb, &offset, pinfo, part_tree);
2094 while (var_len > 0) {
2096 uint32_t start = offset;
2098 ti = proto_tree_add_item(part_tree, hf_sgeonw_trailer_field, tvb, offset, 0, ENC_NA);
2099 field_tree = proto_item_add_subtree(ti, ett_sgeonw_field);
2100 proto_tree_add_item_ret_uint(field_tree, hf_sgeonw_trailer_field_type, tvb, offset, 1, ENC_BIG_ENDIAN, &tmp_val);
2101 offset += 1;
2102 switch(tmp_val) {
2103 case signature:
2104 // Signature
2105 dissect_sec_signature(tvb, &offset, pinfo, field_tree);
2106 break;
2107 default:
2108 // Opaque
2109 param_len = dissect_sec_var_len(tvb, &offset, pinfo, field_tree);
2110 proto_tree_add_item(field_tree, hf_sgeonw_opaque, tvb, offset, param_len, ENC_NA);
2111 offset += param_len;
2113 proto_item_set_end(ti, tvb, offset);
2114 var_len -= (offset - start);
2116 proto_item_set_end(part_item, tvb, offset);
2117 proto_item_set_end(secmsg_item, tvb, offset);
2119 return offset - sec_start;
2122 static int
2123 dissect_sgeonw(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, void *data _U_)
2125 // Just store the tvbuff for later, as it is embedded inside a secured geonetworking packet
2126 p_add_proto_data(pinfo->pool, pinfo, proto_geonw, SEC_TVB_KEY, tvb);
2128 return tvb_reported_length(tvb);
2131 // The actual dissector
2132 // skip_bh:
2133 // 0 - do not skip, complete GNW packet with Basic Header
2134 // BH_NH_COMMON_HDR - skip and continue to Common Header
2135 // BH_NH_SECURED_PKT - skip and continue to Secured Packet
2136 // XXX COL_INFO to be improved
2137 static int
2138 dissect_geonw_internal(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_, uint8_t skip_bh)
2140 uint8_t bh_next_header;
2141 uint32_t ch_next_header;
2142 uint32_t header_type;
2143 uint32_t rhl;
2144 uint32_t tmp_val;
2145 int offset = 0;
2146 proto_item *ti;
2147 proto_item *top_item;
2148 proto_item* rhl_ti = NULL;
2149 int hdr_len = 0;
2150 uint32_t payload_len = 0;
2151 uint32_t reserved;
2152 uint32_t timestamp;
2153 uint32_t sequence_number = SN_MAX + 1;
2154 struct geonwheader *geonwh;
2155 int32_t latlon;
2157 geonwh = wmem_new0(pinfo->pool, struct geonwheader);
2159 col_set_str(pinfo->cinfo, COL_PROTOCOL, "GEONW");
2160 /* Clear out stuff in the info column */
2161 col_clear(pinfo->cinfo,COL_INFO);
2163 if (!skip_bh) {
2164 bh_next_header = tvb_get_uint8(tvb, 0) & 0x0f;
2165 hdr_len = BH_LEN;
2166 } else {
2167 bh_next_header = skip_bh;
2170 if (bh_next_header == BH_NH_COMMON_HDR) {
2171 header_type = tvb_get_uint8(tvb, hdr_len + 1);
2172 hdr_len += CH_LEN;
2173 switch(header_type & HT_MASK) {
2174 case HT_BEACON:
2175 hdr_len += BEACON_LEN;
2176 break;
2177 case HT_GEOUNICAST:
2178 hdr_len += GUC_LEN;
2179 break;
2180 case HT_GEOANYCAST:
2181 hdr_len += GAC_LEN;
2182 break;
2183 case HT_GEOBROADCAST:
2184 hdr_len += GBC_LEN;
2185 break;
2186 case HT_TSB:
2187 hdr_len += TSB_LEN;
2188 break;
2189 case HT_LS:
2190 hdr_len += LS_REQUEST_LEN;
2191 if (header_type == HTST_LS_REPLY) {
2192 hdr_len += (LS_REPLY_LEN - LS_REQUEST_LEN);
2194 break;
2195 default:
2196 hdr_len = -1;
2200 top_item = proto_tree_add_item(tree, proto_geonw, tvb, 0, hdr_len, ENC_NA);
2201 proto_tree *geonw_tree = proto_item_add_subtree(top_item, ett_geonw);
2203 if (!skip_bh) {
2204 // Basic Header subtree
2205 ti = proto_tree_add_item(geonw_tree, hf_geonw_bh, tvb, 0, 4, ENC_NA);
2206 proto_tree* geonw_bh_tree = proto_item_add_subtree(ti, ett_geonw_bh);
2208 ti = proto_tree_add_item_ret_uint(geonw_bh_tree, hf_geonw_bh_version, tvb, offset, 1, ENC_BIG_ENDIAN, &tmp_val);
2209 geonwh->gnw_ver = tmp_val;
2210 // Shall be 0 or 1
2211 if (tmp_val > 1) {
2212 col_add_fstr(pinfo->cinfo, COL_INFO,
2213 "Bogus GeoNetworking version (%u, must be less than 2)", tmp_val);
2214 expert_add_info_format(pinfo, ti, &ei_geonw_version_err, "Bogus GeoNetworking version");
2215 return tvb_captured_length(tvb);
2217 proto_tree_add_item(geonw_bh_tree, hf_geonw_bh_next_header, tvb, offset, 1, ENC_BIG_ENDIAN);
2218 offset += 1;
2219 // Reserved byte
2220 // Expert info if not zero?
2221 ti = proto_tree_add_item_ret_uint(geonw_bh_tree, hf_geonw_bh_reserved, tvb, offset, 1, ENC_NA, &reserved);
2222 if (reserved) {
2223 expert_add_info(pinfo, ti, &ei_geonw_nz_reserved);
2225 offset += 1;
2227 // Subtree and lt_mult and lt_base
2228 ti = proto_tree_add_item_ret_uint(geonw_bh_tree, hf_geonw_bh_life_time, tvb, offset, 1, ENC_BIG_ENDIAN, &tmp_val);
2229 geonwh->gnw_lt = tmp_val;
2230 proto_tree* geonw_bh_lt_tree = proto_item_add_subtree(ti, ett_geonw_bh_lt);
2232 proto_tree_add_item(geonw_bh_lt_tree, hf_geonw_bh_lt_mult, tvb, offset, 1, ENC_BIG_ENDIAN);
2233 proto_tree_add_item(geonw_bh_lt_tree, hf_geonw_bh_lt_base, tvb, offset, 1, ENC_BIG_ENDIAN);
2234 offset += 1;
2236 rhl_ti = proto_tree_add_item_ret_uint(geonw_bh_tree, hf_geonw_bh_remain_hop_limit, tvb, offset, 1, ENC_BIG_ENDIAN, &rhl);
2237 geonwh->gnw_rhl = rhl;
2239 * Flag a low RHL if the next header is not a common header
2241 if (rhl < 5 && bh_next_header != BH_NH_COMMON_HDR) {
2242 expert_add_info_format(pinfo, rhl_ti, &ei_geonw_rhl_too_low, "\"Remain Hop Limit\" only %u", rhl);
2244 offset += 1;
2247 if (bh_next_header == BH_NH_SECURED_PKT) {
2248 dissect_secured_message(tvb, offset, pinfo, geonw_tree, NULL);
2249 tvbuff_t *next_tvb = (tvbuff_t*)p_get_proto_data(pinfo->pool, pinfo, proto_geonw, SEC_TVB_KEY);
2250 if (next_tvb) {
2251 tvb = next_tvb;
2252 bh_next_header = BH_NH_COMMON_HDR;
2253 offset = 0;
2254 header_type = tvb_get_uint8(tvb, 1);
2256 hdr_len = CH_LEN;
2257 switch(header_type & HT_MASK) {
2258 case HT_BEACON:
2259 hdr_len += BEACON_LEN;
2260 break;
2261 case HT_GEOUNICAST:
2262 hdr_len += GUC_LEN;
2263 break;
2264 case HT_GEOANYCAST:
2265 hdr_len += GAC_LEN;
2266 break;
2267 case HT_GEOBROADCAST:
2268 hdr_len += GBC_LEN;
2269 break;
2270 case HT_TSB:
2271 hdr_len += TSB_LEN;
2272 break;
2273 case HT_LS:
2274 hdr_len += LS_REQUEST_LEN;
2275 if (header_type == HTST_LS_REPLY) {
2276 hdr_len += (LS_REPLY_LEN - LS_REQUEST_LEN);
2278 break;
2279 default:
2280 hdr_len = -1;
2285 if (bh_next_header == BH_NH_COMMON_HDR) {
2286 // Common Header subtree
2287 ti = proto_tree_add_item(geonw_tree, hf_geonw_ch, tvb, offset, 8, ENC_NA);
2288 proto_tree *geonw_ch_tree = proto_item_add_subtree(ti, ett_geonw_ch);
2290 // Next Header
2291 proto_tree_add_item_ret_uint(geonw_ch_tree, hf_geonw_ch_next_header, tvb, offset, 1, ENC_BIG_ENDIAN, &ch_next_header);
2292 geonwh->gnw_proto = ch_next_header;
2293 // Reserved
2294 ti = proto_tree_add_item_ret_uint(geonw_ch_tree, hf_geonw_ch_reserved1, tvb, offset, 1, ENC_NA, &reserved);
2295 if (reserved) {
2296 expert_add_info(pinfo, ti, &ei_geonw_nz_reserved);
2298 offset += 1;
2300 // HT
2301 proto_tree_add_item_ret_uint(geonw_ch_tree, hf_geonw_ch_header_type, tvb, offset, 1, ENC_BIG_ENDIAN, &header_type);
2302 geonwh->gnw_htype = header_type;
2303 col_add_str(pinfo->cinfo, COL_INFO, val_to_str(header_type, ch_header_type_names, "Unknown (%u)"));
2304 offset += 1;
2306 if (!skip_bh) {
2307 /* Now that we know the header type, lets add expert info on RHL
2308 * RHL shall be
2309 * = 1 if parameter Packet transport type in the service primitive
2310 * GN-DATA.request is SHB, or if Header type HT = 1 (BEACON)
2311 * = Value of optional Maximum hop limit parameter from service
2312 * primitive GN-DATA.request
2313 * = Otherwise GN protocol constant itsGnDefaultHopLimit if
2314 * GN-DATA.request parameter Packet transport type is GUC, GBC, GBC
2315 * or TSB
2316 * Flag a low RHL if the packet is not BEACON or SHB.
2318 if (header_type == HTST_BEACON || header_type == HTST_TSB_SINGLE) {
2319 if (rhl > 1) {
2320 expert_add_info_format(pinfo, rhl_ti, &ei_geonw_rhl_lncb, "\"Remain Hop Limit\" != 1 for BEACON or SHB (%u)", rhl);
2323 else if (rhl < 5) {
2324 expert_add_info_format(pinfo, rhl_ti, &ei_geonw_rhl_too_low, "\"Remain Hop Limit\" only %u", rhl);
2328 // TC
2329 ti = proto_tree_add_item_ret_uint(geonw_ch_tree, hf_geonw_ch_traffic_class, tvb, offset, 1, ENC_BIG_ENDIAN, &tmp_val);
2330 geonwh->gnw_tc = tmp_val;
2331 proto_tree *geonw_ch_tc_tree = proto_item_add_subtree(ti, ett_geonw_ch_tc);
2333 proto_tree_add_item(geonw_ch_tc_tree, hf_geonw_ch_tc_scf, tvb, offset, 1, ENC_BIG_ENDIAN);
2334 proto_tree_add_item(geonw_ch_tc_tree, hf_geonw_ch_tc_offload, tvb, offset, 1, ENC_BIG_ENDIAN);
2335 proto_tree_add_item(geonw_ch_tc_tree, hf_geonw_ch_tc_id, tvb, offset, 1, ENC_BIG_ENDIAN);
2336 offset += 1;
2338 ti = proto_tree_add_item(geonw_ch_tree, hf_geonw_ch_flags, tvb, offset, 1, ENC_NA);
2339 proto_tree *geonw_ch_flag_tree = proto_item_add_subtree(ti, ett_geonw_ch_tc);
2340 // Flag (itsGnIsMobile)
2341 proto_tree_add_item_ret_uint(geonw_ch_flag_tree, hf_geonw_ch_flags_mob, tvb, offset, 1, ENC_BIG_ENDIAN, &tmp_val);
2342 geonwh->gnw_flags = tmp_val;
2343 ti = proto_tree_add_item_ret_uint(geonw_ch_flag_tree, hf_geonw_ch_flags_reserved, tvb, offset, 1, ENC_BIG_ENDIAN, &reserved);
2344 if (reserved & 0x7f) {
2345 expert_add_info(pinfo, ti, &ei_geonw_nz_reserved);
2347 offset += 1;
2349 // PL (16 bits)
2350 ti = proto_tree_add_item_ret_uint(geonw_ch_tree, hf_geonw_ch_payload_length, tvb, offset, 2, ENC_BIG_ENDIAN, &payload_len);
2351 geonwh->gnw_len = payload_len;
2352 if (hdr_len > 0) { // We know the length of the header
2353 if (payload_len) {
2354 if (((header_type & HT_MASK) == HT_LS) || (header_type == HT_BEACON)) {
2355 expert_add_info(pinfo, ti, &ei_geonw_nz_reserved);
2357 else if ((payload_len + (unsigned) hdr_len) > tvb_reported_length(tvb)) {
2358 expert_add_info(pinfo, ti, &ei_geonw_payload_len);
2360 else {
2362 * Now that we know that the total length of this GNW datagram isn't
2363 * obviously bogus, adjust the length of this tvbuff to include only
2364 * the GNW datagram.
2366 set_actual_length(tvb, hdr_len + payload_len);
2369 else {
2370 set_actual_length(tvb, hdr_len);
2373 offset += 2;
2375 // MHL
2376 proto_tree_add_item_ret_uint(geonw_ch_tree, hf_geonw_ch_max_hop_limit, tvb, offset, 1, ENC_BIG_ENDIAN, &tmp_val);
2377 geonwh->gnw_mhl = tmp_val;
2378 offset += 1;
2379 if (!skip_bh) {
2380 // Expert mhl < rhl: packet will be ignored
2381 if (tmp_val < rhl) {
2382 expert_add_info_format(pinfo, rhl_ti, &ei_geonw_mhl_lt_rhl, "Ignored: \"Remain Hop Limit\" > %u (mhl)", tmp_val);
2386 // Reserved...
2387 ti = proto_tree_add_item_ret_uint(geonw_ch_tree, hf_geonw_ch_reserved2, tvb, offset, 1, ENC_NA, &reserved);
2388 // Expert info if not zero
2389 if (reserved) {
2390 expert_add_info(pinfo, ti, &ei_geonw_nz_reserved);
2392 offset += 1;
2394 // Stop here if header_type unknown
2395 if (!IS_HT_KNOWN(header_type)) {
2396 // Update top level tree item
2397 proto_item_set_end(top_item, tvb, offset);
2398 return tvb_reported_length(tvb);
2401 geonwh->gnw_sn = SN_MAX+1;
2403 proto_tree *geonw_sh_tree;
2404 switch(header_type & HT_MASK) {
2405 case HT_BEACON:
2406 ti = proto_tree_add_item(geonw_tree, hf_geonw_beacon, tvb, offset, hdr_len-offset, ENC_NA);
2407 break;
2408 case HT_GEOUNICAST:
2409 ti = proto_tree_add_item(geonw_tree, hf_geonw_guc, tvb, offset, hdr_len-offset, ENC_NA);
2410 break;
2411 case HT_GEOANYCAST:
2412 ti = proto_tree_add_item(geonw_tree, hf_geonw_gac, tvb, offset, hdr_len-offset, ENC_NA);
2413 break;
2414 case HT_GEOBROADCAST:
2415 ti = proto_tree_add_item(geonw_tree, hf_geonw_gbc, tvb, offset, hdr_len-offset, ENC_NA);
2416 break;
2417 case HT_TSB:
2418 ti = proto_tree_add_item(geonw_tree, hf_geonw_tsb, tvb, offset, hdr_len-offset, ENC_NA);
2419 break;
2420 case HT_LS:
2421 ti = proto_tree_add_item(geonw_tree, hf_geonw_ls, tvb, offset, hdr_len-offset, ENC_NA);
2422 break;
2423 default:
2424 // Exit if header_type unknown?
2425 return tvb_captured_length(tvb);
2427 geonw_sh_tree = proto_item_add_subtree(ti, ett_geonw_sh);
2429 switch(header_type) {
2430 case HTST_GEOUNICAST:
2431 case HTST_GAC_CIRCLE:
2432 case HTST_GAC_RECT:
2433 case HTST_GAC_ELLIPSE:
2434 case HTST_GBC_CIRCLE:
2435 case HTST_GBC_RECT:
2436 case HTST_GBC_ELLIPSE:
2437 case HTST_TSB_MULT:
2438 case HTST_LS_REQUEST:
2439 case HTST_LS_REPLY:
2440 // Seq num
2441 proto_tree_add_item_ret_uint(geonw_sh_tree, hf_geonw_seq_num, tvb, offset, 2, ENC_BIG_ENDIAN, &sequence_number);
2442 geonwh->gnw_sn = sequence_number;
2443 offset += 2;
2444 // 16 bits reserved
2445 ti = proto_tree_add_item_ret_uint(geonw_sh_tree, hf_geonw_reserved, tvb, offset, 2, ENC_BIG_ENDIAN, &reserved);
2446 // Expert info if not zero?
2447 if (reserved) {
2448 expert_add_info(pinfo, ti, &ei_geonw_nz_reserved);
2450 offset += 2;
2451 case HTST_TSB_SINGLE:
2452 case HTST_BEACON:
2453 break;
2456 // Every packet has source address
2457 ti = proto_tree_add_item(geonw_sh_tree, hf_geonw_so_pv, tvb, offset, 24, ENC_NA);
2458 proto_tree *geonw_so_tree = proto_item_add_subtree(ti, ett_geonw_so);
2460 ti = proto_tree_add_item(geonw_so_tree, hf_geonw_so_pv_addr, tvb, offset, 8, ENC_NA);
2461 proto_tree *geonw_so_add_tree = proto_item_add_subtree(ti, ett_geonw_so);
2462 set_address_tvb(&pinfo->net_src, geonw_address_type, 8, tvb, offset);
2463 copy_address_shallow(&pinfo->src, &pinfo->net_src);
2464 copy_address_shallow(&geonwh->gnw_src, &pinfo->src);
2466 proto_tree_add_item(geonw_so_add_tree, hf_geonw_so_pv_addr_manual, tvb, offset, 1, ENC_BIG_ENDIAN);
2467 proto_tree_add_item(geonw_so_add_tree, hf_geonw_so_pv_addr_type, tvb, offset, 1, ENC_BIG_ENDIAN);
2468 ti = proto_tree_add_item_ret_uint(geonw_so_add_tree, hf_geonw_so_pv_addr_country, tvb, offset, 2, ENC_BIG_ENDIAN, &reserved);
2469 if (reserved > 999) {
2470 expert_add_info(pinfo, ti, &ei_geonw_scc_too_big);
2472 offset += 2;
2473 proto_tree_add_item(geonw_so_add_tree, hf_geonw_so_pv_addr_mid, tvb, offset, 6, ENC_NA);
2474 offset += 6;
2476 proto_tree_add_item_ret_uint(geonw_so_tree, hf_geonw_so_pv_time, tvb, offset, 4, ENC_BIG_ENDIAN, &timestamp);
2477 geonwh->gnw_tst = timestamp;
2479 // XXX Is it possible to "follow" a station when updating its GN_ADDR?
2481 if(geonw_analyze_seq && (geonwh->gnw_ver==0) && !(pinfo->fd->visited)) {
2482 // Duplication detection uses SN and TST or only TST (see Annex A of ETSI EN 302 636-4-1)
2483 // We rely on address type and hashtable as this shall be done on a per station basis (i.e. not over a conversation)
2484 // We do not try to consider GN_ADDR updates (due to duplicate address detection or anonymous setting)
2485 hashgeonw_t *tp = (hashgeonw_t *)wmem_map_lookup(geonw_hashtable, pinfo->net_src.data);
2486 if (tp == NULL) {
2487 tp = geonw_hash_new_entry((const uint8_t *)pinfo->net_src.data, false);
2488 tp->sequence_number = sequence_number;
2489 tp->timestamp = timestamp;
2490 } else {
2491 if ((sequence_number <= SN_MAX) && (tp->sequence_number > SN_MAX)) {
2492 tp->sequence_number = sequence_number;
2493 tp->timestamp = timestamp;
2495 else if (sequence_number <= SN_MAX) {
2497 * 1 P is the received GeoNetworking packet
2498 * 2 SN(P) is the sequence number in the received GeoNetworking packet
2499 * 3 SN(SO) is the last received sequence number from source SO
2500 * 4 SN_MAX is the maximum sequence number = 2^16 - 1
2501 * 5 TST(P) is the timestamp in the received GeoNetworking packet
2502 * 6 TST(SO) is the last received timestamp from source SO
2503 * 7 TST_MAX is the maximum value of the timestamp = 2^32 - 1
2505 * 9 IF (((TST(P) > TST(SO) AND ((TST(P) - TST(SO)) <= TST_MAX/2)) OR
2506 * ((TST(SO) > TST(P)) AND ((TST(SO) - TST(P)) > TST_MAX/2))) THEN
2507 * 10 # TST(P) is greater than TST(SO)
2508 * 11 TST(SO) = TST(P)
2509 * 12 SN(SO) = SN(P) # P is not a duplicate packet
2510 * 13 ELSEIF TST(P) = TST(SO) THEN
2511 * 14 IF (((SN(P) > SN(SO) AND ((SN(P) - SN(SO)) <= SN_MAX/2)) OR
2512 * ((SN(SO) > SN(P)) AND ((SN(SO) - SN(P)) > SN_MAX/2))) THEN
2513 * 15 # SN(P) is greater than SN(SO)
2514 * 16 TST(SO) = TST(P)
2515 * 17 SN(SO) = SN(P) # P is not a duplicate packet
2516 * 18 ELSE
2517 * 19 # SN(P) is not greater than SN(SO)
2518 * 20 # P is a duplicate
2519 * 21 ENDIF
2520 * 22 ELSE
2521 * 23 # TST(P) not greater than TST(SO)
2522 * 24 ENDIF
2524 if (((timestamp > tp->timestamp) && (((uint64_t)timestamp - (uint64_t)tp->timestamp) <= (uint64_t)TST_MAX/2)) ||
2525 ((tp->timestamp > timestamp) && (((uint64_t)tp->timestamp - (uint64_t)timestamp) > (uint64_t)TST_MAX/2))) {
2526 // TST(P) is greater than TST(SO)
2527 tp->sequence_number = sequence_number;
2528 tp->timestamp = timestamp; // P is not a duplicate packet
2529 } else if (timestamp == tp->timestamp) {
2530 if (((sequence_number > tp->sequence_number) && ((sequence_number - tp->sequence_number) <= SN_MAX/2)) ||
2531 ((tp->sequence_number > sequence_number) && ((tp->sequence_number - sequence_number) > SN_MAX/2))) {
2532 // SN(P) is greater than SN(SO)
2533 tp->timestamp = timestamp;
2534 tp->sequence_number = sequence_number; // P is not a duplicate packet
2535 } else {
2536 // SN(P) is not greater than SN(SO)
2537 // P is a duplicate
2538 ti = proto_tree_add_item(geonw_tree, hf_geonw_analysis_flags, tvb, 0, 0, ENC_NA);
2539 proto_item_set_generated(ti);
2540 expert_add_info(pinfo, ti, &ei_geonw_analysis_duplicate);
2541 col_prepend_fence_fstr(pinfo->cinfo, COL_INFO, "[Duplicate packet] ");
2543 } // else { # TST(P) not greater than TST(SO) }
2545 else {
2547 * 1 P is the received GeoNetworking packet
2548 * 2 TST(P) is the timestamp in the received GeoNetworking packet
2549 * 3 TST(SO) is the last received timestamp from source SO
2550 * 4 TS_MAX is the maximum value of the timestamp = 2^32 - 1
2552 * 6 IF (((TST(P) > TST(SO) AND ((TST(P) - TST(SO)) <= TST_MAX/2)) OR
2553 * ((TST(SO) > TST(P)) AND ((TST(SO) - TST(P)) > TST_MAX/2))) THEN
2554 * 7 # TST(P) is greater than TST(SO)
2555 * 8 TST(SO) = TST(P) # P is not a duplicate packet
2556 * 9 ELSE
2557 * 10 # P is a duplicate
2558 * 11 ENDIF
2560 if (((timestamp > tp->timestamp) && (((uint64_t)timestamp - (uint64_t)tp->timestamp) <= (uint64_t)TST_MAX/2)) ||
2561 ((tp->timestamp > timestamp) && (((uint64_t)tp->timestamp - (uint64_t)timestamp) > (uint64_t)TST_MAX/2))) {
2562 // TST(P) is greater than TST(SO)
2563 tp->timestamp = timestamp; // P is not a duplicate packet
2564 } else {
2565 // P is a duplicate
2566 ti = proto_tree_add_item(geonw_tree, hf_geonw_analysis_flags, tvb, 0, 0, ENC_NA);
2567 proto_item_set_generated(ti);
2568 expert_add_info(pinfo, ti, &ei_geonw_analysis_duplicate);
2569 col_prepend_fence_fstr(pinfo->cinfo, COL_INFO, "[Duplicate packet] ");
2574 // XXX Implement DPD if version == 1
2576 offset += 4;
2577 ti = proto_tree_add_item_ret_int(geonw_so_tree, hf_geonw_so_pv_lat, tvb, offset, 4, ENC_BIG_ENDIAN, &latlon);
2578 if (latlon < -900000000 || latlon > 900000000) {
2579 expert_add_info_format(pinfo, ti, &ei_geonw_out_of_range, "Latitude out of range (%f)", (float)latlon/10000000);
2581 geonwh->gnw_lat = latlon;
2582 offset += 4;
2583 ti = proto_tree_add_item_ret_int(geonw_so_tree, hf_geonw_so_pv_lon, tvb, offset, 4, ENC_BIG_ENDIAN, &latlon);
2584 if (latlon < -1800000000 || latlon > 1800000000) {
2585 expert_add_info_format(pinfo, ti, &ei_geonw_out_of_range, "Longitude out of range (%f)", (float)latlon/10000000);
2587 geonwh->gnw_lon = latlon;
2588 offset += 4;
2589 proto_tree_add_item(geonw_so_tree, hf_geonw_so_pv_pai, tvb, offset, 1, ENC_BIG_ENDIAN);
2590 proto_tree_add_item(geonw_so_tree, hf_geonw_so_pv_speed, tvb, offset, 2, ENC_BIG_ENDIAN);
2591 offset += 2;
2592 ti = proto_tree_add_item_ret_uint(geonw_so_tree, hf_geonw_so_pv_heading, tvb, offset, 2, ENC_BIG_ENDIAN, &tmp_val);
2593 if (tmp_val > 3600) {
2594 expert_add_info_format(pinfo, ti, &ei_geonw_out_of_range, "Out of range [0..360] (%f)", (float)tmp_val/10);
2596 offset += 2;
2598 proto_tree *geonw_de_tree = NULL;
2599 proto_tree *geonw_de_add_tree = NULL;
2600 switch(header_type) {
2601 case HTST_GEOUNICAST:
2602 case HTST_LS_REPLY:
2603 // Destination address
2604 ti = proto_tree_add_item(geonw_sh_tree, hf_geonw_de_pv, tvb, offset, 20, ENC_NA);
2605 geonw_de_tree = proto_item_add_subtree(ti, ett_geonw_de);
2607 ti = proto_tree_add_item(geonw_de_tree, hf_geonw_de_pv_addr, tvb, offset, 8, ENC_NA);
2608 geonw_de_add_tree = proto_item_add_subtree(ti, ett_geonw_de);
2609 set_address_tvb(&pinfo->net_dst, geonw_address_type, 8, tvb, offset);
2610 copy_address_shallow(&pinfo->dst, &pinfo->net_dst);
2611 copy_address_shallow(&geonwh->gnw_dst, &pinfo->dst);
2613 if (header_type == HTST_LS_REPLY) {
2614 transaction_end(pinfo, geonw_tree);
2617 proto_tree_add_item(geonw_de_add_tree, hf_geonw_de_pv_addr_manual, tvb, offset, 1, ENC_BIG_ENDIAN);
2618 proto_tree_add_item(geonw_de_add_tree, hf_geonw_de_pv_addr_type, tvb, offset, 1, ENC_BIG_ENDIAN);
2619 ti = proto_tree_add_item_ret_uint(geonw_de_add_tree, hf_geonw_de_pv_addr_country, tvb, offset, 2, ENC_BIG_ENDIAN, &reserved);
2620 if (reserved > 999) {
2621 expert_add_info(pinfo, ti, &ei_geonw_scc_too_big);
2623 offset += 2;
2624 proto_tree_add_item(geonw_de_add_tree, hf_geonw_de_pv_addr_mid, tvb, offset, 6, ENC_NA);
2625 offset += 6;
2627 proto_tree_add_item(geonw_de_tree, hf_geonw_de_pv_time, tvb, offset, 4, ENC_BIG_ENDIAN);
2628 offset += 4;
2629 ti = proto_tree_add_item_ret_int(geonw_de_tree, hf_geonw_de_pv_lat, tvb, offset, 4, ENC_BIG_ENDIAN, &latlon);
2630 if (latlon < -900000000 || latlon > 900000000) {
2631 expert_add_info_format(pinfo, ti, &ei_geonw_out_of_range, "Latitude out of range (%f)", (float)latlon/10000000);
2633 offset += 4;
2634 ti = proto_tree_add_item_ret_int(geonw_de_tree, hf_geonw_de_pv_lon, tvb, offset, 4, ENC_BIG_ENDIAN, &latlon);
2635 if (latlon < -1800000000 || latlon > 1800000000) {
2636 expert_add_info_format(pinfo, ti, &ei_geonw_out_of_range, "Longitude out of range (%f)", (float)latlon/10000000);
2638 offset += 4;
2639 break;
2640 case HTST_TSB_SINGLE:
2641 // Reserved 32 bits
2642 // See usage in 636-4 subpart 2 for ITS-5G
2643 reserved = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN);
2644 if (reserved) {
2645 ti = proto_tree_add_item(geonw_sh_tree, hf_geonw_dccmco, tvb, offset, 4, ENC_NA);
2646 proto_tree *dccmco = proto_item_add_subtree(ti, ett_geonw_dccmco);
2647 proto_tree_add_item(dccmco, hf_geonw_dccmco_cbr_l_0_hop, tvb, offset, 1, ENC_BIG_ENDIAN);
2648 proto_tree_add_item(dccmco, hf_geonw_dccmco_cbr_l_1_hop, tvb, offset+1, 1, ENC_BIG_ENDIAN);
2649 proto_tree_add_item(dccmco, hf_geonw_dccmco_output_power, tvb, offset+2, 1, ENC_BIG_ENDIAN);
2650 proto_tree_add_item(dccmco, hf_geonw_dccmco_reserved, tvb, offset+2, 1, ENC_BIG_ENDIAN);
2651 proto_tree_add_item(dccmco, hf_geonw_shb_reserved, tvb, offset+3, 1, ENC_BIG_ENDIAN);
2653 else {
2654 proto_tree_add_item(geonw_sh_tree, hf_geonw_shb_reserved, tvb, offset, 4, ENC_BIG_ENDIAN);
2656 offset += 4;
2657 break;
2658 case HTST_GAC_CIRCLE:
2659 case HTST_GAC_RECT:
2660 case HTST_GAC_ELLIPSE:
2661 case HTST_GBC_CIRCLE:
2662 case HTST_GBC_RECT:
2663 case HTST_GBC_ELLIPSE:
2664 ti = proto_tree_add_item_ret_int(geonw_sh_tree, hf_geonw_gxc_latitude, tvb, offset, 4, ENC_BIG_ENDIAN, &latlon);
2665 if (latlon < -900000000 || latlon > 900000000) {
2666 expert_add_info_format(pinfo, ti, &ei_geonw_out_of_range, "Latitude out of range (%f)", (float)latlon/10000000);
2668 offset += 4;
2669 ti = proto_tree_add_item_ret_int(geonw_sh_tree, hf_geonw_gxc_longitude, tvb, offset, 4, ENC_BIG_ENDIAN, &latlon);
2670 if (latlon < -1800000000 || latlon > 1800000000) {
2671 expert_add_info_format(pinfo, ti, &ei_geonw_out_of_range, "Longitude out of range (%f)", (float)latlon/10000000);
2673 offset += 4;
2674 switch(header_type&0x0f) {
2675 case HST_CIRCULAR:
2677 * According to EN 302 363-4-1:
2678 * In case of a circular area (GeoNetworking packet
2679 * sub-type HST = 0), the fields shall be set to the
2680 * following values:
2681 * 1) Distance a is set to the radius r.
2682 * 2) Distance b is set to 0.
2683 * 3) Angle is set to 0.
2685 proto_tree_add_item(geonw_sh_tree, hf_geonw_gxc_radius, tvb, offset, 2, ENC_BIG_ENDIAN);
2686 offset += 2;
2687 ti = proto_tree_add_item_ret_uint(geonw_sh_tree, hf_geonw_gxc_distanceb, tvb, offset, 2, ENC_BIG_ENDIAN, &reserved);
2688 if (reserved) {
2689 expert_add_info(pinfo, ti, &ei_geonw_nz_reserved);
2691 offset += 2;
2692 ti = proto_tree_add_item_ret_uint(geonw_sh_tree, hf_geonw_gxc_angle, tvb, offset, 2, ENC_BIG_ENDIAN, &reserved);
2693 if (reserved) {
2694 expert_add_info(pinfo, ti, &ei_geonw_nz_reserved);
2696 offset += 2;
2697 break;
2698 case HST_RECTANGULAR:
2699 case HST_ELLIPSOIDAL:
2700 proto_tree_add_item(geonw_sh_tree, hf_geonw_gxc_distancea, tvb, offset, 2, ENC_BIG_ENDIAN);
2701 offset += 2;
2702 proto_tree_add_item(geonw_sh_tree, hf_geonw_gxc_distanceb, tvb, offset, 2, ENC_BIG_ENDIAN);
2703 offset += 2;
2704 ti = proto_tree_add_item_ret_uint(geonw_sh_tree, hf_geonw_gxc_angle, tvb, offset, 2, ENC_BIG_ENDIAN, &tmp_val);
2705 if (tmp_val > 360) {
2706 expert_add_info_format(pinfo, ti, &ei_geonw_out_of_range, "Out of range [0..360] (%f)", (float)tmp_val);
2708 offset += 2;
2710 ti = proto_tree_add_item_ret_uint(geonw_sh_tree, hf_geonw_gxc_reserved, tvb, offset, 2, ENC_BIG_ENDIAN, &reserved);
2711 if (reserved) {
2712 expert_add_info(pinfo, ti, &ei_geonw_nz_reserved);
2714 offset += 2;
2715 break;
2716 case HTST_LS_REQUEST:
2717 // GN_ADDR
2718 ti = proto_tree_add_item(geonw_sh_tree, hf_geonw_lsrq_addr, tvb, offset, 8, ENC_NA);
2719 geonw_de_add_tree = proto_item_add_subtree(ti, ett_geonw_lsrq_add);
2720 set_address_tvb(&pinfo->net_dst, geonw_address_type, 8, tvb, offset);
2721 copy_address_shallow(&pinfo->dst, &pinfo->net_dst);
2723 proto_tree_add_item(geonw_de_add_tree, hf_geonw_lsrq_addr_manual, tvb, offset, 1, ENC_BIG_ENDIAN);
2724 proto_tree_add_item(geonw_de_add_tree, hf_geonw_lsrq_addr_type, tvb, offset, 1, ENC_BIG_ENDIAN);
2725 ti = proto_tree_add_item_ret_uint(geonw_de_add_tree, hf_geonw_lsrq_addr_country, tvb, offset, 2, ENC_BIG_ENDIAN, &reserved);
2726 if (reserved > 999) {
2727 expert_add_info(pinfo, ti, &ei_geonw_scc_too_big);
2729 offset += 2;
2730 proto_tree_add_item(geonw_de_add_tree, hf_geonw_lsrq_addr_mid, tvb, offset, 6, ENC_NA);
2731 offset += 6;
2732 transaction_start(pinfo, geonw_tree);
2733 break;
2734 //case HTST_BEACON:
2735 //case HTST_TSB_MULT:
2737 proto_item_set_end(top_item, tvb, offset);
2739 tap_queue_packet(geonw_tap, pinfo, geonwh);
2741 if (payload_len) {
2742 // TODO expert info if payload_len different from remaining
2743 tvbuff_t *next_tvb = tvb_new_subset_length(tvb, offset, payload_len);
2744 switch(ch_next_header) {
2745 case CH_NH_BTP_A:
2746 call_dissector(btpa_handle, next_tvb, pinfo, tree);
2747 break;
2748 case CH_NH_BTP_B:
2749 call_dissector(btpb_handle, next_tvb, pinfo, tree);
2750 break;
2751 case CH_NH_IPV6:
2752 call_dissector(ipv6_handle, next_tvb, pinfo, tree);
2753 break;
2754 default:
2755 if (!dissector_try_uint(geonw_subdissector_table, ch_next_header, next_tvb, pinfo, tree)) {
2756 call_data_dissector(next_tvb, pinfo, tree);
2763 return tvb_captured_length(tvb);
2767 * Decode_as
2769 static void
2770 btpa_src_prompt(packet_info *pinfo _U_, char* result)
2772 uint32_t port = GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, hf_btpa_srcport, pinfo->curr_layer_num));
2774 snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "source (%u%s)", port, UTF8_RIGHTWARDS_ARROW);
2777 static void *
2778 btpa_src_value(packet_info *pinfo _U_)
2780 return p_get_proto_data(pinfo->pool, pinfo, hf_btpa_srcport, pinfo->curr_layer_num);
2783 static void
2784 btpa_dst_prompt(packet_info *pinfo, char *result)
2786 uint32_t port = GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, hf_btpa_dstport, pinfo->curr_layer_num));
2788 snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "destination (%s%u)", UTF8_RIGHTWARDS_ARROW, port);
2791 static void *
2792 btpa_dst_value(packet_info *pinfo)
2794 return p_get_proto_data(pinfo->pool, pinfo, hf_btpa_dstport, pinfo->curr_layer_num);
2797 static void
2798 btpa_both_prompt(packet_info *pinfo, char *result)
2800 uint32_t srcport = GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, hf_btpa_srcport, pinfo->curr_layer_num)),
2801 destport = GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, hf_btpa_dstport, pinfo->curr_layer_num));
2802 snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "both (%u%s%u)", srcport, UTF8_LEFT_RIGHT_ARROW, destport);
2805 static void
2806 btpb_dst_prompt(packet_info *pinfo, char *result)
2808 uint32_t port = GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, hf_btpb_dstport, pinfo->curr_layer_num));
2810 snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "destination (%s%u)", UTF8_RIGHTWARDS_ARROW, port);
2813 static void *
2814 btpb_dst_value(packet_info *pinfo)
2816 return p_get_proto_data(pinfo->pool, pinfo, hf_btpb_dstport, pinfo->curr_layer_num);
2820 * Register
2822 void
2823 proto_register_btpa(void)
2825 static hf_register_info hf_btpa[] = {
2826 // BTP A
2827 { &hf_btpa_dstport,
2828 { "Destination Port", "btpa.dstport",
2829 FT_UINT16, BASE_PT_UDP, NULL, 0x0,
2830 NULL, HFILL }},
2832 { &hf_btpa_srcport,
2833 { "Source Port", "btpa.srcport",
2834 FT_UINT16, BASE_PT_UDP, NULL, 0x0,
2835 NULL, HFILL }},
2837 { &hf_btpa_port,
2838 { "Port", "btpa.port",
2839 FT_UINT16, BASE_PT_UDP, NULL, 0x0,
2840 NULL, HFILL }},
2843 static int *ett[] = {
2844 &ett_btpa,
2846 proto_btpa = proto_register_protocol("BTP-A", "BTPA", "btpa");
2847 btpa_handle = register_dissector("btpa", dissect_btpa, proto_btpa);
2848 proto_register_field_array(proto_btpa, hf_btpa, array_length(hf_btpa));
2850 proto_register_subtree_array(ett, array_length(ett));
2852 // Register subdissector table
2853 btpa_subdissector_table = register_dissector_table("btpa.port",
2854 "BTP-A port", proto_btpa, FT_UINT16, BASE_HEX);
2856 btpa_heur_subdissector_list = register_heur_dissector_list_with_description("btpa.payload", "BTP-A payload fallback", proto_btpa);
2858 // Decode as
2859 static build_valid_func btpa_da_src_values[1] = {btpa_src_value};
2860 static build_valid_func btpa_da_dst_values[1] = {btpa_dst_value};
2861 static build_valid_func btpa_da_both_values[2] = {btpa_src_value, btpa_dst_value};
2862 static decode_as_value_t btpa_da_values[3] = {{btpa_src_prompt, 1, btpa_da_src_values}, {btpa_dst_prompt, 1, btpa_da_dst_values}, {btpa_both_prompt, 2, btpa_da_both_values}};
2863 static decode_as_t btpa_da = {"btpa", "btpa.port", 3, 2, btpa_da_values, "BTP-A", "port(s) as",
2864 decode_as_default_populate_list, decode_as_default_reset, decode_as_default_change, NULL};
2866 register_decode_as(&btpa_da);
2868 btpa_tap = register_tap("btpa");
2869 btpa_follow_tap = register_tap("btpa_follow");
2872 void
2873 proto_reg_handoff_btpa(void)
2875 dissector_add_uint("geonw.ch.nh", 1, btpa_handle);
2877 find_dissector_add_dependency("gnw", proto_btpa);
2880 void
2881 proto_register_btpb(void)
2883 static hf_register_info hf_btpb[] = {
2884 // BTP B
2885 { &hf_btpb_dstport,
2886 { "Destination Port", "btpb.dstport",
2887 FT_UINT16, BASE_PT_UDP, NULL, 0x0,
2888 NULL, HFILL }},
2890 { &hf_btpb_dstport_info,
2891 { "Destination Port info", "btpb.dstportinf",
2892 FT_UINT16, BASE_HEX, NULL, 0x0,
2893 NULL, HFILL }},
2896 static int *ett[] = {
2897 &ett_btpb,
2899 proto_btpb = proto_register_protocol("BTP-B", "BTPB", "btpb");
2900 btpb_handle = register_dissector("btpb", dissect_btpb, proto_btpb);
2901 proto_register_field_array(proto_btpb, hf_btpb, array_length(hf_btpb));
2903 proto_register_subtree_array(ett, array_length(ett));
2905 // Register subdissector table
2906 btpb_subdissector_table = register_dissector_table("btpb.port",
2907 "BTP-B dst port", proto_btpb, FT_UINT16, BASE_HEX);
2909 btpb_heur_subdissector_list = register_heur_dissector_list_with_description("btpb.payload", "BTP-B payload fallback", proto_btpb);
2911 // Decode as
2912 static build_valid_func btpb_da_build_value[1] = {btpb_dst_value};
2913 static decode_as_value_t btpb_da_values = {btpb_dst_prompt, 1, btpb_da_build_value};
2914 static decode_as_t btpb_da = {"btpb", "btpb.port", 1, 0, &btpb_da_values, NULL, NULL,
2915 decode_as_default_populate_list, decode_as_default_reset, decode_as_default_change, NULL};
2917 register_decode_as(&btpb_da);
2919 btpb_tap = register_tap("btpb");
2920 btpb_follow_tap = register_tap("btpb_follow");
2923 void
2924 proto_reg_handoff_btpb(void)
2926 dissector_add_uint("geonw.ch.nh", 2, btpb_handle);
2928 find_dissector_add_dependency("gnw", proto_btpb);
2931 // Display functions
2932 static void
2933 display_latitude( char *result, int32_t hexver )
2935 snprintf( result, ITEM_LABEL_LENGTH, "%ud%u'%.2f\"%c (%d)",
2936 abs(hexver)/10000000,
2937 abs(hexver%10000000)*6/1000000,
2938 abs(hexver*6%1000000)*6./100000.,
2939 hexver>=0?'N':'S',
2940 hexver);
2943 static void
2944 display_longitude( char *result, int32_t hexver )
2946 snprintf( result, ITEM_LABEL_LENGTH, "%ud%u'%.2f\"%c (%d)",
2947 abs(hexver)/10000000,
2948 abs(hexver%10000000)*6/1000000,
2949 abs(hexver*6%1000000)*6./100000.,
2950 hexver>=0?'E':'W',
2951 hexver);
2954 static void
2955 display_speed( char *result, int32_t hexver )
2957 snprintf( result, ITEM_LABEL_LENGTH, "%.2f m/s", hexver/100.);
2960 static void
2961 display_heading( char *result, uint32_t hexver )
2963 snprintf( result, ITEM_LABEL_LENGTH, "%.1f degrees", hexver/10.);
2966 static void
2967 display_elevation( char *result, int32_t hexver )
2969 // 0x0000 to 0xEFFF: positive numbers with a range from 0 to +6 143,9 meters. All numbers above +6 143,9 are
2970 // also represented by 0xEFFF.
2971 // 0xF001 to 0xFFFF: negative numbers with a range from -409,5 to -0,1 meters. All numbers below -409,5 are
2972 // also represented by 0xF001.
2973 // 0xF000: an unknown elevation
2974 if (hexver == -4096)
2975 snprintf( result, ITEM_LABEL_LENGTH, "Unknown (%4x)", hexver);
2976 else
2977 snprintf( result, ITEM_LABEL_LENGTH, "%.1fm", hexver/10.);
2980 static int
2981 dissect_geonw(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data)
2983 return dissect_geonw_internal(tvb, pinfo, tree, data, 0);
2986 static int
2987 dissect_geonw_comm(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data)
2989 return dissect_geonw_internal(tvb, pinfo, tree, data, BH_NH_COMMON_HDR);
2992 static int
2993 dissect_geonw_sec(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data)
2995 return dissect_geonw_internal(tvb, pinfo, tree, data, BH_NH_SECURED_PKT);
2998 void
2999 proto_register_geonw(void)
3001 static const value_string bh_next_header_names[] = {
3002 { 0, "ANY" },
3003 { 1, "Common Header" },
3004 { 2, "Secured Packet" },
3005 { 0, NULL}
3008 static const value_string bh_lt_base_names[] = {
3009 { 0, "50 ms" },
3010 { 1, "1 s" },
3011 { 2, "10 s" },
3012 { 3, "100 s"},
3013 { 0, NULL}
3016 static const value_string ch_next_header_names[] = {
3017 { 0, "ANY" },
3018 { CH_NH_BTP_A, "BTP-A Transport protocol" },
3019 { CH_NH_BTP_B, "BTP-B Transport protocol" },
3020 { CH_NH_IPV6, "IPv6 header" },
3021 { 0, NULL}
3024 static const value_string traffic_classes_its_g5_names[] = {
3025 { 0, "ITS-G5 Access Category Voice" },
3026 { 1, "ITS-G5 Access Category Video" },
3027 { 2, "ITS-G5 Access Category Best effort" },
3028 { 3, "ITS-G5 Access Category Background" },
3029 { 0, NULL }
3032 static const value_string itss_type_names[] = {
3033 { 0, "Unknown" },
3034 { 1, "Pedestrian" },
3035 { 2, "Cyclist" },
3036 { 3, "Moped" },
3037 { 4, "Motorcycle" },
3038 { 5, "Passenger Car" },
3039 { 6, "Bus" },
3040 { 7, "Light Truck" },
3041 { 8, "Heavy Truck" },
3042 { 9, "Trailer" },
3043 { 10, "Special Vehicle" },
3044 { 11, "Tram" },
3045 { 15, "Road Side Unit" },
3046 { 0, NULL}
3049 static hf_register_info hf_geonw[] = {
3051 { &hf_geonw_bh,
3052 { "Basic Header", "geonw.bh", FT_NONE, BASE_NONE, NULL, 0x0,
3053 NULL, HFILL }},
3055 { &hf_geonw_bh_version,
3056 { "Version", "geonw.bh.version",
3057 FT_UINT8, BASE_DEC, NULL, 0xF0,
3058 NULL, HFILL }},
3060 { &hf_geonw_bh_reserved,
3061 { "Reserved", "geonw.bh.reserved", FT_UINT8,
3062 BASE_HEX, NULL, 0x0, "It SHOULD be set to 0", HFILL }},
3064 { &hf_geonw_bh_next_header,
3065 { "Next Header", "geonw.bh.nh",
3066 FT_UINT8, BASE_DEC, VALS(bh_next_header_names), 0x0F,
3067 NULL, HFILL }},
3069 { &hf_geonw_bh_life_time,
3070 { "Life Time", "geonw.bh.lt",
3071 FT_UINT8, BASE_DEC, NULL, 0x00,
3072 NULL, HFILL }},
3074 { &hf_geonw_bh_lt_mult,
3075 { "Life Time multiplier", "geonw.bh.lt.mult",
3076 FT_UINT8, BASE_DEC, NULL, 0xFC,
3077 NULL, HFILL }},
3079 { &hf_geonw_bh_lt_base,
3080 { "Life Time base", "geonw.bh.lt.base",
3081 FT_UINT8, BASE_DEC, VALS(bh_lt_base_names), 0x03,
3082 NULL, HFILL }},
3084 { &hf_geonw_bh_remain_hop_limit,
3085 { "Remaining Hop Limit", "geonw.bh.rhl",
3086 FT_UINT8, BASE_DEC, NULL, 0x00,
3087 NULL, HFILL }},
3089 { &hf_geonw_ch,
3090 { "Common Header", "geonw.ch", FT_NONE, BASE_NONE, NULL, 0x0,
3091 NULL, HFILL }},
3093 { &hf_geonw_ch_next_header,
3094 { "Next Header", "geonw.ch.nh",
3095 FT_UINT8, BASE_DEC, VALS(ch_next_header_names), 0xF0,
3096 NULL, HFILL }},
3098 { &hf_geonw_ch_reserved1,
3099 { "Reserved", "geonw.ch.reserved1", FT_UINT8,
3100 BASE_HEX, NULL, 0x0F, "It SHOULD be set to 0", HFILL }},
3102 { &hf_geonw_ch_header_type,
3103 { "Header type", "geonw.ch.htype",
3104 FT_UINT8, BASE_HEX, VALS(ch_header_type_names), 0x00,
3105 NULL, HFILL }},
3107 { &hf_geonw_ch_traffic_class,
3108 { "Traffic class", "geonw.ch.tclass",
3109 FT_UINT8, BASE_DEC, NULL, 0x00,
3110 NULL, HFILL }},
3112 { &hf_geonw_ch_tc_scf,
3113 { "Store Carry Forward", "geonw.ch.tc.buffer",
3114 FT_UINT8, BASE_DEC, NULL, 0x80,
3115 NULL, HFILL }},
3117 { &hf_geonw_ch_tc_offload,
3118 { "Channel offload", "geonw.ch.tc.offload",
3119 FT_UINT8, BASE_DEC, NULL, 0x40,
3120 NULL, HFILL }},
3122 { &hf_geonw_ch_tc_id,
3123 { "Traffic class ID", "geonw.ch.tc.id",
3124 FT_UINT8, BASE_DEC, VALS(traffic_classes_its_g5_names), 0x3F,
3125 NULL, HFILL }},
3127 { &hf_geonw_ch_flags,
3128 { "Flags", "geonw.ch.flags", FT_NONE,
3129 BASE_NONE, NULL, 0x0, NULL, HFILL }},
3131 { &hf_geonw_ch_flags_mob,
3132 { "Mobility flag", "geonw.ch.flags.mob",
3133 FT_UINT8, BASE_DEC, NULL, 0x80,
3134 NULL, HFILL }},
3136 { &hf_geonw_ch_flags_reserved,
3137 { "Reserved", "geonw.ch.flags.reserved",
3138 FT_UINT8, BASE_DEC, NULL, 0x7F,
3139 NULL, HFILL }},
3141 { &hf_geonw_ch_payload_length,
3142 { "Payload length", "geonw.ch.plength",
3143 FT_UINT16, BASE_DEC, NULL, 0x00,
3144 NULL, HFILL }},
3146 { &hf_geonw_ch_max_hop_limit,
3147 { "Maximum Hop Limit", "geonw.ch.mhl",
3148 FT_UINT8, BASE_DEC, NULL, 0x00,
3149 NULL, HFILL }},
3151 { &hf_geonw_ch_reserved2,
3152 { "Reserved", "geonw.ch.reserved2", FT_UINT8,
3153 BASE_HEX, NULL, 0x00, "It SHOULD be set to 0", HFILL }},
3155 { &hf_geonw_seq_num,
3156 { "Sequence number", "geonw.seq_num",
3157 FT_UINT16, BASE_DEC, NULL, 0x00,
3158 NULL, HFILL }},
3160 { &hf_geonw_reserved,
3161 { "Reserved", "geonw.reserved",
3162 FT_UINT16, BASE_DEC, NULL, 0x00,
3163 NULL, HFILL }},
3165 // Long Position
3166 { &hf_geonw_so_pv,
3167 { "Source position", "geonw.src_pos",
3168 FT_BYTES, BASE_NONE, NULL, 0x00,
3169 NULL, HFILL }},
3171 { &hf_geonw_so_pv_addr,
3172 { "GN_ADDR", "geonw.src_pos.addr",
3173 FT_BYTES, BASE_NONE, NULL, 0x00,
3174 NULL, HFILL }},
3176 { &hf_geonw_so_pv_addr_manual,
3177 { "Manual", "geonw.src_pos.addr.manual",
3178 FT_UINT8, BASE_DEC, NULL, 0x80,
3179 NULL, HFILL }},
3181 { &hf_geonw_so_pv_addr_type,
3182 { "ITS-S type", "geonw.src_pos.addr.type",
3183 FT_UINT8, BASE_DEC, VALS(itss_type_names), 0x7C,
3184 NULL, HFILL }},
3186 { &hf_geonw_so_pv_addr_country,
3187 { "ITS-S Country Code", "geonw.src_pos.addr.country",
3188 FT_UINT16, BASE_DEC, VALS(E164_country_code_value), 0x03FF,
3189 NULL, HFILL }},
3191 { &hf_geonw_so_pv_addr_mid,
3192 { "MID", "geonw.src_pos.addr.mid",
3193 FT_ETHER, BASE_NONE, NULL, 0x0,
3194 NULL, HFILL }},
3196 { &hf_geonw_so_pv_time,
3197 { "Timestamp", "geonw.src_pos.tst",
3198 FT_UINT32, BASE_DEC|BASE_UNIT_STRING, UNS(&units_milliseconds), 0x00,
3199 NULL, HFILL }},
3201 { &hf_geonw_so_pv_lat,
3202 { "Latitude", "geonw.src_pos.lat",
3203 FT_INT32, BASE_CUSTOM, CF_FUNC(display_latitude), 0x00,
3204 NULL, HFILL }},
3206 { &hf_geonw_so_pv_lon,
3207 { "Longitude", "geonw.src_pos.long",
3208 FT_INT32, BASE_CUSTOM, CF_FUNC(display_longitude), 0x00,
3209 NULL, HFILL }},
3211 { &hf_geonw_so_pv_pai,
3212 { "Position accuracy indicator", "geonw.src_pos.pai",
3213 FT_UINT8, BASE_DEC, NULL, 0x80,
3214 NULL, HFILL }},
3216 { &hf_geonw_so_pv_speed,
3217 { "Speed", "geonw.src_pos.speed",
3218 FT_INT16, BASE_CUSTOM, CF_FUNC(display_speed), 0x7FFF,
3219 NULL, HFILL }},
3221 { &hf_geonw_so_pv_heading,
3222 { "Heading", "geonw.src_pos.hdg",
3223 FT_UINT16, BASE_CUSTOM, CF_FUNC(display_heading), 0x00,
3224 NULL, HFILL }},
3226 // Decentralized Congestion Control - Multi Channel Operation
3227 { &hf_geonw_dccmco,
3228 { "Decentralized Congestion Control - Multi Channel Operation", "geonw.dccmco",
3229 FT_NONE, BASE_NONE, NULL, 0x00,
3230 NULL, HFILL }},
3232 { &hf_geonw_dccmco_cbr_l_0_hop,
3233 { "Local channel busy ratio", "geonw.cbr_l0hop",
3234 FT_UINT8, BASE_DEC, NULL, 0x80,
3235 NULL, HFILL }},
3237 { &hf_geonw_dccmco_cbr_l_1_hop,
3238 { "Max neighbouring CBR", "geonw.cbr_l1hop",
3239 FT_UINT8, BASE_DEC, NULL, 0x80,
3240 NULL, HFILL }},
3242 { &hf_geonw_dccmco_output_power,
3243 { "Output power", "geonw.outpower",
3244 FT_UINT8, BASE_DEC|BASE_UNIT_STRING, UNS(&units_dbm), 0xf8,
3245 NULL, HFILL }},
3247 { &hf_geonw_dccmco_reserved,
3248 { "Reserved", "geonw.dccmco.reserved",
3249 FT_UINT8, BASE_DEC, NULL, 0x07,
3250 NULL, HFILL }},
3252 // Short Position
3253 { &hf_geonw_de_pv,
3254 { "Destination position", "geonw.dst_pos",
3255 FT_BYTES, BASE_NONE, NULL, 0x00,
3256 NULL, HFILL }},
3258 { &hf_geonw_de_pv_addr,
3259 { "GN_ADDR", "geonw.dst_pos.addr",
3260 FT_BYTES, BASE_NONE, NULL, 0x00,
3261 NULL, HFILL }},
3263 { &hf_geonw_de_pv_addr_manual,
3264 { "Manual", "geonw.dst_pos.addr.manual",
3265 FT_UINT8, BASE_DEC, NULL, 0x80,
3266 NULL, HFILL }},
3268 { &hf_geonw_de_pv_addr_type,
3269 { "ITS-S type", "geonw.dst_pos.addr.type",
3270 FT_UINT8, BASE_DEC, VALS(itss_type_names), 0x7C,
3271 NULL, HFILL }},
3273 { &hf_geonw_de_pv_addr_country,
3274 { "ITS-S Country Code", "geonw.dst_pos.addr.country",
3275 FT_UINT16, BASE_DEC, VALS(E164_country_code_value), 0x03FF,
3276 NULL, HFILL }},
3278 { &hf_geonw_de_pv_addr_mid,
3279 { "MID", "geonw.dst_pos.addr.mid",
3280 FT_ETHER, BASE_NONE, NULL, 0x0,
3281 NULL, HFILL }},
3283 { &hf_geonw_de_pv_time,
3284 { "Timestamp", "geonw.dst_pos.tst",
3285 FT_UINT32, BASE_DEC|BASE_UNIT_STRING, UNS(&units_milliseconds), 0x00,
3286 NULL, HFILL }},
3288 { &hf_geonw_de_pv_lat,
3289 { "Latitude", "geonw.dst_pos.lat",
3290 FT_INT32, BASE_CUSTOM, CF_FUNC(display_latitude), 0x00,
3291 NULL, HFILL }},
3293 { &hf_geonw_de_pv_lon,
3294 { "Longitude", "geonw.dst_pos.long",
3295 FT_INT32, BASE_CUSTOM, CF_FUNC(display_longitude), 0x00,
3296 NULL, HFILL }},
3298 // GBC/GAC
3299 { &hf_geonw_gxc_latitude,
3300 { "Latitude", "geonw.gxc.latitude",
3301 FT_INT32, BASE_CUSTOM, CF_FUNC(display_latitude), 0x00,
3302 NULL, HFILL }},
3304 { &hf_geonw_gxc_longitude,
3305 { "Longitude", "geonw.gxc.longitude",
3306 FT_INT32, BASE_CUSTOM, CF_FUNC(display_longitude), 0x00,
3307 NULL, HFILL }},
3309 { &hf_geonw_gxc_radius,
3310 { "Radius r", "geonw.gxc.radius",
3311 FT_UINT16, BASE_DEC|BASE_UNIT_STRING, UNS(&units_meters), 0x00,
3312 NULL, HFILL }},
3314 { &hf_geonw_gxc_distancea,
3315 { "Distance a", "geonw.gxc.distancea",
3316 FT_UINT16, BASE_DEC|BASE_UNIT_STRING, UNS(&units_meters), 0x00,
3317 NULL, HFILL }},
3319 { &hf_geonw_gxc_distanceb,
3320 { "Distance b", "geonw.gxc.distanceb",
3321 FT_UINT16, BASE_DEC|BASE_UNIT_STRING, UNS(&units_meters), 0x00,
3322 NULL, HFILL }},
3324 { &hf_geonw_gxc_angle,
3325 { "Angle", "geonw.gxc.angle",
3326 FT_UINT16, BASE_DEC|BASE_UNIT_STRING, UNS(&units_degree_degrees), 0x00,
3327 NULL, HFILL }},
3329 { &hf_geonw_gxc_reserved,
3330 { "Reserved", "geonw.gxc.reserved",
3331 FT_UINT16, BASE_DEC, NULL, 0x00,
3332 NULL, HFILL }},
3334 // SHB
3335 { &hf_geonw_shb_reserved,
3336 { "Reserved", "geonw.shb.reserved",
3337 FT_UINT32, BASE_DEC, NULL, 0x00,
3338 NULL, HFILL }},
3340 // LS Request
3341 { &hf_geonw_lsrq_addr,
3342 { "GN_ADDR", "geonw.ls_req.addr",
3343 FT_BYTES, BASE_NONE, NULL, 0x00,
3344 NULL, HFILL }},
3346 { &hf_geonw_lsrq_addr_manual,
3347 { "Manual", "geonw.ls_req.addr.manual",
3348 FT_UINT8, BASE_DEC, NULL, 0x80,
3349 NULL, HFILL }},
3351 { &hf_geonw_lsrq_addr_type,
3352 { "ITS-S type", "geonw.ls_req.addr.type",
3353 FT_UINT8, BASE_DEC, VALS(itss_type_names), 0x7C,
3354 NULL, HFILL }},
3356 { &hf_geonw_lsrq_addr_country,
3357 { "ITS-S Country Code", "geonw.ls_req.addr.country",
3358 FT_UINT16, BASE_DEC, VALS(E164_country_code_value), 0x03FF,
3359 NULL, HFILL }},
3361 { &hf_geonw_lsrq_addr_mid,
3362 { "MID", "geonw.ls_req.addr.mid",
3363 FT_ETHER, BASE_NONE, NULL, 0x0,
3364 NULL, HFILL }},
3366 { &hf_geonw_beacon,
3367 { "Beacon Packet", "geonw.beacon", FT_NONE,
3368 BASE_NONE, NULL, 0x0, NULL, HFILL }},
3370 { &hf_geonw_guc,
3371 { "GeoUniCast Packet", "geonw.guc", FT_NONE,
3372 BASE_NONE, NULL, 0x0, NULL, HFILL }},
3374 { &hf_geonw_gac,
3375 { "GeoAnyCast Packet", "geonw.gac", FT_NONE,
3376 BASE_NONE, NULL, 0x0, NULL, HFILL }},
3378 { &hf_geonw_gbc,
3379 { "GeoBroadCast Packet", "geonw.gbc", FT_NONE,
3380 BASE_NONE, NULL, 0x0, NULL, HFILL }},
3382 { &hf_geonw_tsb,
3383 { "Topologically-Scoped Broadcast Packet", "geonw.tsb", FT_NONE,
3384 BASE_NONE, NULL, 0x0, NULL, HFILL }},
3386 { &hf_geonw_ls,
3387 { "Location Service Packet", "geonw.ls", FT_NONE,
3388 BASE_NONE, NULL, 0x0, NULL, HFILL }},
3390 { &hf_geonw_resp_in,
3391 { "Response frame", "geonw.resp_in", FT_FRAMENUM, BASE_NONE,
3392 FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0x0,
3393 "The frame number of the corresponding response",
3394 HFILL}},
3396 { &hf_geonw_no_resp,
3397 { "No response seen", "geonw.no_resp", FT_NONE, BASE_NONE,
3398 NULL, 0x0,
3399 "No corresponding response frame was seen",
3400 HFILL}},
3402 { &hf_geonw_resp_to,
3403 { "Request frame", "geonw.resp_to", FT_FRAMENUM, BASE_NONE,
3404 FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0x0,
3405 "The frame number of the corresponding request", HFILL}},
3407 { &hf_geonw_resptime,
3408 { "Response time", "geonw.resptime", FT_DOUBLE, BASE_NONE,
3409 NULL, 0x0,
3410 "The time between the request and the response, in ms.",
3411 HFILL}},
3413 { &hf_geonw_analysis_flags,
3414 { "GeoNetworking Analysis Flags", "geonw.analysis.flags", FT_NONE, BASE_NONE, NULL, 0x0,
3415 "This frame has some of the GeoNetworking analysis flags set", HFILL }},
3417 // Secures packets
3418 { &hf_geonw_sec,
3419 { "Secured Packet", "geonw.sec", FT_NONE, BASE_NONE, NULL, 0x0,
3420 NULL, HFILL }},
3422 { &hf_sgeonw_version,
3423 { "Version", "geonw.sec.version",
3424 FT_UINT8, BASE_DEC, NULL, 0x0,
3425 NULL, HFILL }},
3427 { &hf_sgeonw_profile,
3428 { "Profile", "geonw.sec.profile",
3429 FT_UINT8, BASE_DEC, NULL, 0x0,
3430 NULL, HFILL }},
3432 { &hf_sgeonw_hdr,
3433 { "Header fields", "geonw.sec.hdr", FT_NONE, BASE_NONE, NULL, 0x0,
3434 NULL, HFILL }},
3436 { &hf_sgeonw_pl,
3437 { "Payload fields", "geonw.sec.pl", FT_NONE, BASE_NONE, NULL, 0x0,
3438 NULL, HFILL }},
3440 { &hf_sgeonw_trl,
3441 { "Trailer fields", "geonw.sec.trl", FT_NONE, BASE_NONE, NULL, 0x0,
3442 NULL, HFILL }},
3444 { &hf_sgeonw_public_key,
3445 { "Public key", "geonw.sec.pub_key", FT_NONE, BASE_NONE, NULL, 0x0,
3446 NULL, HFILL }},
3448 { &hf_sgeonw_certificate,
3449 { "Certificate", "geonw.sec.certif", FT_NONE, BASE_NONE, NULL, 0x0,
3450 NULL, HFILL }},
3452 { &hf_sgeonw_var_len,
3453 { "Var length", "geonw.sec.var_len", FT_NONE, BASE_NONE, NULL, 0x0,
3454 NULL, HFILL }},
3456 { &hf_sgeonw_var_len_det,
3457 { "Var length determinant", "geonw.sec.var_len.det",
3458 FT_UINT8, BASE_HEX, NULL, 0x0,
3459 NULL, HFILL }},
3461 { &hf_sgeonw_var_len_val,
3462 { "Var length value", "geonw.sec.var_len.value",
3463 FT_UINT32, BASE_DEC, NULL, 0x0,
3464 NULL, HFILL }},
3466 { &hf_sgeonw_intx,
3467 { "IntX", "geonw.sec.intx", FT_NONE, BASE_NONE, NULL, 0x0,
3468 NULL, HFILL }},
3470 { &hf_sgeonw_header_field,
3471 { "Header field", "geonw.sec.hdr_field", FT_NONE, BASE_NONE, NULL, 0x0,
3472 NULL, HFILL }},
3474 { &hf_sgeonw_payload_field,
3475 { "Payload field", "geonw.sec.pl_field", FT_NONE, BASE_NONE, NULL, 0x0,
3476 NULL, HFILL }},
3478 { &hf_sgeonw_trailer_field,
3479 { "Trailer field", "geonw.sec.trl_field", FT_NONE, BASE_NONE, NULL, 0x0,
3480 NULL, HFILL }},
3482 { &hf_sgeonw_signer_info,
3483 { "Signer info", "geonw.sec.signer_info", FT_NONE, BASE_NONE, NULL, 0x0,
3484 NULL, HFILL }},
3486 { &hf_sgeonw_eccpoint,
3487 { "ECC Point", "geonw.sec.eccpoint", FT_NONE, BASE_NONE, NULL, 0x0,
3488 NULL, HFILL }},
3490 { &hf_sgeonw_duration,
3491 { "Duration", "geonw.sec.duration", FT_NONE, BASE_NONE, NULL, 0x0,
3492 NULL, HFILL }},
3494 { &hf_sgeonw_subject_assurance,
3495 { "Subject assurance", "geonw.sec.subj_assur", FT_NONE, BASE_NONE, NULL, 0x0,
3496 NULL, HFILL }},
3498 { &hf_sgeonw_encryption_parameter,
3499 { "Encryption parameter", "geonw.sec.encrypt_param", FT_NONE, BASE_NONE, NULL, 0x0,
3500 NULL, HFILL }},
3502 { &hf_sgeonw_signature,
3503 { "Signature", "geonw.sec.signature", FT_NONE, BASE_NONE, NULL, 0x0,
3504 NULL, HFILL }},
3506 { &hf_sgeonw_subject_info,
3507 { "Subject info", "geonw.sec.subj_info", FT_NONE, BASE_NONE, NULL, 0x0,
3508 NULL, HFILL }},
3510 { &hf_sgeonw_subject_attribute,
3511 { "Subject attribute", "geonw.sec.subj_attr", FT_NONE, BASE_NONE, NULL, 0x0,
3512 NULL, HFILL }},
3514 { &hf_sgeonw_opaque,
3515 { "Opaque", "geonw.sec.opaque", FT_BYTES, BASE_NONE, NULL, 0x0,
3516 NULL, HFILL }},
3518 { &hf_sgeonw_encrypted_key,
3519 { "Encrypted key", "geonw.sec.enc_key", FT_BYTES, BASE_NONE, NULL, 0x0,
3520 NULL, HFILL }},
3522 { &hf_sgeonw_auth_tag,
3523 { "Authentication tag", "geonw.sec.auth_tag", FT_BYTES, BASE_NONE, NULL, 0x0,
3524 NULL, HFILL }},
3526 { &hf_sgeonw_ecdsasignature_s,
3527 { "s", "geonw.sec.signature.s", FT_BYTES, BASE_NONE, NULL, 0x0,
3528 NULL, HFILL }},
3530 { &hf_sgeonw_eccpoint_x,
3531 { "x", "geonw.sec.eccpoint.x", FT_BYTES, BASE_NONE, NULL, 0x0,
3532 NULL, HFILL }},
3534 { &hf_sgeonw_eccpoint_y,
3535 { "y", "geonw.sec.eccpoint.y", FT_BYTES, BASE_NONE, NULL, 0x0,
3536 NULL, HFILL }},
3538 { &hf_sgeonw_hashedid8,
3539 { "Hashed ID 8", "geonw.sec.hashedid8", FT_BYTES, BASE_NONE, NULL, 0x0,
3540 NULL, HFILL }},
3542 { &hf_sgeonw_encryption_parameter_nonce,
3543 { "Nonce", "geonw.sec.nonce", FT_BYTES, BASE_NONE, NULL, 0x0,
3544 NULL, HFILL }},
3546 { &hf_sgeonw_header_field_type_v1, { "Header field type", "geonw.sec.hdr_fld_type", FT_UINT8, BASE_DEC, VALS(header_field_type_v1_names), 0x0, NULL, HFILL }},
3547 { &hf_sgeonw_header_field_type_v2, { "Header field type", "geonw.sec.hdr_fld_type", FT_UINT8, BASE_DEC, VALS(header_field_type_v2_names), 0x0, NULL, HFILL }},
3548 { &hf_sgeonw_payload_field_type, { "Payload field type", "geonw.sec.pl_fld_type", FT_UINT8, BASE_DEC, VALS(payload_field_type_names), 0x0, NULL, HFILL }},
3549 { &hf_sgeonw_trailer_field_type, { "Trailer field type", "geonw.sec.trl_fld_type", FT_UINT8, BASE_DEC, VALS(trailer_field_type_names), 0x0, NULL, HFILL }},
3550 { &hf_sgeonw_public_key_algorithm, { "Public key algorithm", "geonw.sec.pubkeyalgo", FT_UINT8, BASE_DEC, VALS(public_key_algorithm_names), 0x0, NULL, HFILL }},
3551 { &hf_sgeonw_eccpoint_type, { "EccPoint type", "geonw.sec.eccpoint_type", FT_UINT8, BASE_DEC, VALS(eccpoint_type_names), 0x0, NULL, HFILL }},
3552 { &hf_sgeonw_signer_info_type, { "Signer info type", "geonw.sec.signer_info_type", FT_UINT8, BASE_DEC, VALS(signer_info_type_names), 0x0, NULL, HFILL }},
3553 { &hf_sgeonw_validity_restriction_type, { "Validity restriction type", "geonw.sec.val_rest_type", FT_UINT8, BASE_DEC, VALS(validity_restriction_type_names), 0x0, NULL, HFILL }},
3554 { &hf_sgeonw_subject_type, { "Subject type", "geonw.sec.subject_type", FT_UINT8, BASE_DEC, VALS(subject_type_names), 0x0, NULL, HFILL }},
3555 { &hf_sgeonw_subject_attribute_type_v1, { "Subject attribute", "geonw.sec.subject_attr", FT_UINT8, BASE_DEC, VALS(subject_attribute_type_v1_names), 0x0, NULL, HFILL }},
3556 { &hf_sgeonw_subject_attribute_type_v2, { "Subject attribute", "geonw.sec.subject_attr", FT_UINT8, BASE_DEC, VALS(subject_attribute_type_v2_names), 0x0, NULL, HFILL }},
3557 { &hf_sgeonw_symmetric_algorithm, { "Symmetric algorithm", "geonw.sec.symalgo", FT_UINT8, BASE_DEC, VALS(symmetric_algorithm_names), 0x0, NULL, HFILL }},
3558 { &hf_sgeonw_region_type, { "Region type", "geonw.sec.regiontype", FT_UINT8, BASE_DEC, VALS(region_type_names), 0x0, NULL, HFILL }},
3559 { &hf_sgeonw_region_dictionary, { "Region dictionary", "geonw.sec.regiondict", FT_UINT8, BASE_DEC, VALS(region_dictionary_names), 0x0, NULL, HFILL }},
3561 { &hf_sgeonw_region_identifier, { "Region identifier", "geonw.sec.regionid", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3562 { &hf_sgeonw_local_region, { "Local region", "geonw.sec.local_region", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3564 { &hf_sgeonw_certification_version, { "Certification version", "geonw.sec.certif.version", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3566 { &hf_sgeonw_time64, { "Time64", "geonw.sec.time64", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3567 { &hf_sgeonw_conf, { "Confidence", "geonw.sec.confidence", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3568 { &hf_sgeonw_time32, { "Time32", "geonw.sec.time32", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3569 { &hf_sgeonw_lat, { "Latitude", "geonw.sec.lat", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3570 { &hf_sgeonw_lon, { "Longitude", "geonw.sec.lon", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3571 { &hf_sgeonw_elev, { "Elevation", "geonw.sec.elev", FT_INT16, BASE_CUSTOM, CF_FUNC(display_elevation), 0x0, NULL, HFILL }},
3572 { &hf_sgeonw_hashedid3, { "Hashed ID 3", "geonw.sec.hashedid3", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3573 { &hf_sgeonw_duration_unit, { "Unit", "geonw.sec.duration.unit", FT_UINT16, BASE_DEC, VALS(sgeonw_duration_unit_names), 0xe000, NULL, HFILL }},
3574 { &hf_sgeonw_duration_value, { "Value", "geonw.sec.duration.value", FT_UINT16, BASE_DEC, NULL, 0x1fff, NULL, HFILL }},
3575 { &hf_sgeonw_radius, { "Radius", "geonw.sec.radius", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3576 { &hf_sgeonw_priority, { "Priority", "geonw.sec.priority", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3577 { &hf_sgeonw_subject_assurance_assurance, { "Subject assurance", "geonw.sec.subj_assur.assurance", FT_UINT8, BASE_DEC, NULL, 0xe0, NULL, HFILL }},
3578 { &hf_sgeonw_subject_assurance_reserved, { "Reserved", "geonw.sec.subj_assur.reserved", FT_UINT8, BASE_DEC, NULL, 0x1c, NULL, HFILL }},
3579 { &hf_sgeonw_subject_assurance_confidence, { "Subject assurance", "geonw.sec.subj_assur.confidence", FT_UINT8, BASE_DEC, NULL, 0x03, NULL, HFILL }},
3580 { &hf_sgeonw_msg_id, { "Message ID", "geonw.sec.msg_id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3581 { &hf_sgeonw_app_id, { "Application ID", "geonw.sec.app_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3585 static ei_register_info ei[] = {
3586 { &ei_geonw_nz_reserved, { "geonw.reserved_not_zero", PI_PROTOCOL, PI_WARN, "Incorrect, should be 0", EXPFILL }},
3587 { &ei_geonw_version_err, { "geonw.bogus_version", PI_MALFORMED, PI_ERROR, "Bogus GeoNetworking Version", EXPFILL }},
3588 { &ei_geonw_rhl_lncb, { "geonw.rhl.lncb", PI_SEQUENCE, PI_NOTE, "Remaining Hop Limit", EXPFILL }},
3589 { &ei_geonw_rhl_too_low, { "geonw.rhl.too_small", PI_SEQUENCE, PI_NOTE, "Remaining Hop Limit Too Low", EXPFILL }},
3590 { &ei_geonw_mhl_lt_rhl, { "geonw.rhl.ht_mhl", PI_SEQUENCE, PI_WARN, "Remaining Hop Limit To Live", EXPFILL }},
3591 { &ei_geonw_scc_too_big, { "geonw.scc_too_big", PI_MALFORMED, PI_ERROR, "Country code should be less than 1000", EXPFILL }},
3592 { &ei_geonw_analysis_duplicate, { "geonw.analysis_duplicate", PI_SEQUENCE, PI_NOTE, "Duplicate packet", EXPFILL }},
3593 { &ei_geonw_resp_not_found, { "geonw.resp_not_found", PI_SEQUENCE, PI_WARN, "Response not found", EXPFILL }},
3594 { &ei_geonw_out_of_range, { "geonw.position_oor", PI_MALFORMED, PI_WARN, "Position out of range", EXPFILL }},
3595 { &ei_geonw_payload_len, { "geonw.bogus_geonw_length", PI_PROTOCOL, PI_ERROR, "Bogus GeoNetworking length", EXPFILL }},
3596 { &ei_sgeonw_len_unsupported, { "geonw.sec.len_unsup", PI_MALFORMED, PI_ERROR, "Length not supported", EXPFILL }},
3597 { &ei_sgeonw_len_too_long, { "geonw.sec.bogus_len", PI_MALFORMED, PI_ERROR, "Length of int shall be at most 7 bits long", EXPFILL }},
3598 { &ei_sgeonw_subj_info_too_long, { "geonw.sec.bogus_sinfo", PI_MALFORMED, PI_ERROR, "Subject info length shall be at most 255", EXPFILL }},
3599 { &ei_sgeonw_ssp_too_long, { "geonw.sec.bogus_ssp", PI_MALFORMED, PI_ERROR, "Service specific permission length shall be at most 31", EXPFILL }},
3600 { &ei_sgeonw_bogus, { "geonw.sec.bogus", PI_MALFORMED, PI_ERROR, "Malformed message (check length)", EXPFILL }},
3601 { &ei_geonw_intx_too_big, { "geonw.intx_too_big", PI_MALFORMED, PI_ERROR, "IntX value exceeds 32 bits", EXPFILL }},
3603 static int *ett[] = {
3604 &ett_geonw,
3605 &ett_geonw_bh,
3606 &ett_geonw_bh_lt,
3607 &ett_geonw_ch,
3608 &ett_geonw_ch_tc,
3609 &ett_geonw_sh,
3610 &ett_geonw_so,
3611 &ett_geonw_so_add,
3612 &ett_geonw_de,
3613 &ett_geonw_de_add,
3614 &ett_geonw_lsrq_add,
3615 &ett_geonw_analysis,
3616 &ett_geonw_dccmco,
3618 &ett_geonw_sec, // Secured packet
3619 &ett_sgeonw_hdr, // Parts (header, payload or trailer) subtree
3620 &ett_sgeonw_field, // Field subtree
3621 &ett_sgeonw_var_len, // Variable length subtree
3622 &ett_sgeonw_intx,
3623 &ett_sgeonw_duration,
3624 &ett_sgeonw_eccpoint,
3625 &ett_sgeonw_subject_assurance,
3626 &ett_sgeonw_public_key,
3627 &ett_sgeonw_encryption_parameter,
3628 &ett_sgeonw_signature,
3629 &ett_sgeonw_subject_info,
3630 &ett_sgeonw_subject_attribute,
3631 &ett_sgeonw_ssp,
3634 expert_module_t* expert_geonw;
3635 module_t *geonw_module;
3637 proto_geonw = proto_register_protocol("GeoNetworking", "GNW", "gnw");
3640 geonw_handle = register_dissector("gnw", dissect_geonw, proto_geonw);
3641 register_dissector("gnw.comm", dissect_geonw_comm, proto_geonw);
3642 register_dissector("gnw.sec", dissect_geonw_sec, proto_geonw);
3644 proto_register_field_array(proto_geonw, hf_geonw, array_length(hf_geonw));
3645 proto_register_subtree_array(ett, array_length(ett));
3647 expert_geonw = expert_register_protocol(proto_geonw);
3648 expert_register_field_array(expert_geonw, ei, array_length(ei));
3650 geonw_subdissector_table = register_dissector_table("geonw.ch.nh",
3651 "GeoNetworking Next Header", proto_geonw, FT_UINT8, BASE_HEX);
3653 ssp_subdissector_table = register_dissector_table("geonw.ssp",
3654 "ATS-AID/PSID based dissector for Service Specific Permissions (SSP)", proto_geonw, FT_UINT32, BASE_HEX);
3656 geonw_address_type = address_type_dissector_register("AT_GEONW", "GeoNetworking address", geonw_to_str, geonw_str_len, NULL, geonw_col_filter_str, geonw_len, geonw_name_resolution_str, geonw_name_resolution_len);
3658 /* Register configuration preferences */
3659 geonw_module = prefs_register_protocol(proto_geonw, NULL);
3660 prefs_register_bool_preference(geonw_module, "analyze_sequence_numbers",
3661 "Analyze GeoNetworking sequence numbers",
3662 "Make the GeoNetworking dissector analyze GeoNetworking sequence numbers to find and flag duplicate packet (Annex A)",
3663 &geonw_analyze_seq);
3665 geonw_hashtable = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), geonw_addr_hash, geonw_addr_cmp);
3667 geonw_tap = register_tap("geonw");
3670 void
3671 proto_reg_handoff_geonw(void)
3673 dissector_handle_t sgeonw_handle_;
3675 // This is a minimal dissector that just stores the tvbuff for later use;
3676 // not useful from outside a dissector table, so not using register_dissector()
3677 sgeonw_handle_ = create_dissector_handle(dissect_sgeonw, proto_geonw);
3679 dissector_add_uint_with_preference("ethertype", ETHERTYPE_GEONETWORKING, geonw_handle);
3681 // IPv6 over GeoNetworking Protocols
3682 ipv6_handle = find_dissector("ipv6");
3683 dissector_add_uint("geonw.ch.nh", 3, ipv6_handle);
3685 ieee1609dot2_handle = find_dissector_add_dependency("ieee1609dot2.data", proto_geonw);
3687 dissector_add_uint("ieee1609dot2.psid", psid_den_basic_services, sgeonw_handle_);
3688 dissector_add_uint("ieee1609dot2.psid", psid_ca_basic_services, sgeonw_handle_);
3689 dissector_add_uint("ieee1609dot2.psid", psid_traffic_light_manoeuver_service, sgeonw_handle_);
3690 dissector_add_uint("ieee1609dot2.psid", psid_road_and_lane_topology_service, sgeonw_handle_);
3691 dissector_add_uint("ieee1609dot2.psid", psid_infrastructure_to_vehicle_information_service, sgeonw_handle_);
3692 dissector_add_uint("ieee1609dot2.psid", psid_traffic_light_control_requests_service, sgeonw_handle_);
3693 dissector_add_uint("ieee1609dot2.psid", psid_geonetworking_management_communications, sgeonw_handle_);
3694 dissector_add_uint("ieee1609dot2.psid", psid_traffic_light_control_status_service, sgeonw_handle_);
3695 dissector_add_uint("ieee1609dot2.psid", psid_collective_perception_service, sgeonw_handle_);
3700 * Editor modelines - https://www.wireshark.org/tools/modelines.html
3702 * Local variables:
3703 * c-basic-offset: 4
3704 * tab-width: 8
3705 * indent-tabs-mode: nil
3706 * End:
3708 * vi: set shiftwidth=4 tabstop=8 expandtab:
3709 * :indentSize=4:tabSize=8:noTabs=true: