Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-autosar-nm.c
blob32910d70143977ad022395a1685fea18dd6a9582
1 /* packet-autosar-nm.c
2 * AUTOSAR-NM Dissector
3 * By Dr. Lars Voelker <lars.voelker@technica-engineering.de> / <lars.voelker@bmw.de>
4 * Copyright 2014-2021 Dr. Lars Voelker
5 * Copyright 2019 Maksim Salau <maksim.salau@gmail.com>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * SPDX-License-Identifier: GPL-2.0-or-later
15 * AUTOSAR-NM is an automotive communication protocol as standardized by
16 * AUTOSAR (www.autosar.org) and is specified in AUTOSAR_SWS_UDPNetworkManagement.pdf
17 * and AUTOSAR_SWS_CANNetworkManagement.pdf which can be accessed on:
18 * autosar.org -> Classic Platform -> Software Arch -> Comm Stack.
21 #include <config.h>
23 #include <epan/packet.h>
24 #include <epan/prefs.h>
25 #include <epan/tfs.h>
26 #include <epan/uat.h>
27 #include "packet-socketcan.h"
29 void proto_reg_handoff_autosar_nm(void);
30 void proto_register_autosar_nm(void);
32 #define AUTOSAR_NM_NAME "AUTOSAR NM"
34 typedef struct _user_data_field_t {
35 char* udf_name;
36 char* udf_desc;
37 uint32_t udf_offset;
38 uint32_t udf_length;
39 uint64_t udf_mask;
40 char* udf_value_desc;
41 } user_data_field_t;
43 static int proto_autosar_nm;
45 static dissector_handle_t nm_handle;
46 static dissector_handle_t nm_handle_can;
48 /*** header fields ***/
49 static int hf_autosar_nm_source_node_identifier;
50 static int hf_autosar_nm_control_bit_vector;
51 static int hf_autosar_nm_control_bit_vector_repeat_msg_req;
52 static int hf_autosar_nm_control_bit_vector_reserved1;
53 static int hf_autosar_nm_control_bit_vector_pn_shutdown_request;
54 static int hf_autosar_nm_control_bit_vector_reserved2;
55 static int hf_autosar_nm_control_bit_vector_nm_coord_id;
56 static int hf_autosar_nm_control_bit_vector_reserved3;
57 static int hf_autosar_nm_control_bit_vector_nm_coord_sleep;
58 static int hf_autosar_nm_control_bit_vector_reserved4;
59 static int hf_autosar_nm_control_bit_vector_active_wakeup;
60 static int hf_autosar_nm_control_bit_vector_reserved5;
61 static int hf_autosar_nm_control_bit_vector_pn_learning;
62 static int hf_autosar_nm_control_bit_vector_pni;
63 static int hf_autosar_nm_control_bit_vector_reserved6;
64 static int hf_autosar_nm_control_bit_vector_reserved7;
65 static int hf_autosar_nm_user_data;
67 /*** protocol tree items ***/
68 static int ett_autosar_nm;
69 static int ett_autosar_nm_cbv;
70 static int ett_autosar_nm_user_data;
72 /*** Bit meanings ***/
73 static const true_false_string tfs_autosar_nm_control_rep_msg_req = {
74 "Repeat Message State requested", "Repeat Message State not requested" };
76 static const true_false_string tfs_autosar_nm_control_pn_shutdown_req= {
77 "NM message contains synchronized PN shutdown request", "NM message does not contain synchronized PN shutdown request" };
79 static const true_false_string tfs_autosar_nm_control_sleep_bit = {
80 "Start of synchronized shutdown requested", "Start of synchronized shutdown not requested" };
82 static const true_false_string tfs_autosar_nm_control_active_wakeup = {
83 "Node has woken up the network", "Node has not woken up the network" };
85 static const true_false_string tfs_autosar_nm_control_pn_learning = {
86 "PNC learning is requested", "PNC learning is not requested" };
88 static const true_false_string tfs_autosar_nm_control_pni = {
89 "NM message contains Partial Network request information", "NM message contains no Partial Network request information" };
91 /*** Configuration items ***/
93 enum parameter_byte_position_value {
94 byte_pos_off = -1,
95 byte_pos_0 = 0,
96 byte_pos_1 = 1
99 static const enum_val_t byte_position_vals[] = {
100 {"0", "Byte Position 0", byte_pos_0},
101 {"1", "Byte Position 1", byte_pos_1},
102 {"off", "Turned off", byte_pos_off},
103 {NULL, NULL, -1}
106 /* Set positions of the first two fields (Source Node Identifier and Control Bit Vector */
107 static int g_autosar_nm_pos_cbv = (int)byte_pos_0;
108 static int g_autosar_nm_pos_sni = (int)byte_pos_1;
110 enum parameter_cbv_version_value {
111 autosar_3_0_or_newer = 0,
112 autosar_3_2,
113 autosar_4_0,
114 autosar_4_1_or_newer,
115 autosar_20_11
118 static const enum_val_t cbv_version_vals[] = {
119 {"3.0", "AUTOSAR 3.0 or 3.1", autosar_3_0_or_newer},
120 {"3.2", "AUTOSAR 3.2", autosar_3_2},
121 {"4.0", "AUTOSAR 4.0", autosar_4_0},
122 {"4.1", "AUTOSAR 4.1 or newer", autosar_4_1_or_newer},
123 {"20-11", "AUTOSAR 20-11", autosar_20_11},
124 {NULL, NULL, -1}
127 static int g_autosar_nm_cbv_version = (int)autosar_4_1_or_newer;
129 /* Id and mask of CAN frames to be dissected */
130 static uint32_t g_autosar_nm_can_id;
131 static uint32_t g_autosar_nm_can_id_mask = 0xffffffff;
133 /* Relevant PDUs */
134 static range_t *g_autosar_nm_pdus;
135 static range_t *g_autosar_nm_ipdum_pdus;
138 /*******************************
139 ****** User data fields ******
140 *******************************/
142 static user_data_field_t* user_data_fields;
143 static unsigned num_user_data_fields;
144 static GHashTable* user_data_fields_hash_hf;
145 static hf_register_info* dynamic_hf;
146 static unsigned dynamic_hf_size;
147 static wmem_map_t* user_data_fields_hash_ett;
149 static bool
150 user_data_fields_update_cb(void *r, char **err)
152 user_data_field_t *rec = (user_data_field_t *)r;
153 char c;
154 *err = NULL;
156 if (rec->udf_length == 0) {
157 *err = ws_strdup_printf("length of user data field can't be 0 Bytes (name: %s offset: %i length: %i)", rec->udf_name, rec->udf_offset, rec->udf_length);
158 return (*err == NULL);
161 if (rec->udf_length > 8) {
162 *err = ws_strdup_printf("length of user data field can't be greater 8 Bytes (name: %s offset: %i length: %i)", rec->udf_name, rec->udf_offset, rec->udf_length);
163 return (*err == NULL);
166 if (rec->udf_mask >= UINT64_MAX) {
167 *err = ws_strdup_printf("mask can only be up to 64bits (name: %s)", rec->udf_name);
168 return (*err == NULL);
171 if (rec->udf_name == NULL) {
172 *err = ws_strdup_printf("Name of user data field can't be empty");
173 return (*err == NULL);
176 g_strstrip(rec->udf_name);
177 if (rec->udf_name[0] == 0) {
178 *err = ws_strdup_printf("Name of user data field can't be empty");
179 return (*err == NULL);
182 /* Check for invalid characters (to avoid asserting out when registering the field). */
183 c = proto_check_field_name(rec->udf_name);
184 if (c) {
185 *err = ws_strdup_printf("Name of user data field can't contain '%c'", c);
186 return (*err == NULL);
189 return (*err == NULL);
192 static void *
193 user_data_fields_copy_cb(void* n, const void* o, size_t size _U_)
195 user_data_field_t* new_rec = (user_data_field_t*)n;
196 const user_data_field_t* old_rec = (const user_data_field_t*)o;
198 new_rec->udf_name = g_strdup(old_rec->udf_name);
199 new_rec->udf_desc = g_strdup(old_rec->udf_desc);
200 new_rec->udf_offset = old_rec->udf_offset;
201 new_rec->udf_length = old_rec->udf_length;
202 new_rec->udf_mask = old_rec->udf_mask;
203 new_rec->udf_value_desc = g_strdup(old_rec->udf_value_desc);
205 return new_rec;
208 static void
209 user_data_fields_free_cb(void*r)
211 user_data_field_t* rec = (user_data_field_t*)r;
213 g_free(rec->udf_name);
214 g_free(rec->udf_desc);
215 g_free(rec->udf_value_desc);
218 UAT_CSTRING_CB_DEF(user_data_fields, udf_name, user_data_field_t)
219 UAT_CSTRING_CB_DEF(user_data_fields, udf_desc, user_data_field_t)
220 UAT_DEC_CB_DEF(user_data_fields, udf_offset, user_data_field_t)
221 UAT_DEC_CB_DEF(user_data_fields, udf_length, user_data_field_t)
222 UAT_HEX64_CB_DEF(user_data_fields, udf_mask, user_data_field_t)
223 UAT_CSTRING_CB_DEF(user_data_fields, udf_value_desc, user_data_field_t)
225 static uint64_t
226 calc_ett_key(uint32_t offset, uint32_t length)
228 uint64_t ret = (uint64_t)offset;
229 return (ret << 32) ^ length;
233 * This creates a string for you that can be used as key for the hash table.
234 * YOU must g_free that string!
236 static char*
237 calc_hf_key(user_data_field_t udf)
239 char* ret = NULL;
240 ret = ws_strdup_printf("%i-%i-%" PRIu64 "-%s", udf.udf_offset, udf.udf_length, udf.udf_mask, udf.udf_name);
241 return ret;
245 * Lookup the hf for the user data based on the key
247 static int*
248 get_hf_for_user_data(char* key)
250 int* hf_id = NULL;
252 if (user_data_fields_hash_hf) {
253 hf_id = (int*)g_hash_table_lookup(user_data_fields_hash_hf, key);
255 else {
256 hf_id = NULL;
259 return hf_id;
263 * Lookup the ett for the user data based on the key
265 static int*
266 get_ett_for_user_data(uint32_t offset, uint32_t length)
268 int* ett_id = NULL;
270 uint64_t key = calc_ett_key(offset, length);
272 if (user_data_fields_hash_ett) {
273 ett_id = (int*)wmem_map_lookup(user_data_fields_hash_ett, &key);
275 else {
276 ett_id = NULL;
279 return ett_id;
283 * clean up user data
285 static void
286 deregister_user_data(void)
288 if (dynamic_hf) {
289 /* Unregister all fields */
290 for (unsigned i = 0; i < dynamic_hf_size; i++) {
291 proto_deregister_field(proto_autosar_nm, *(dynamic_hf[i].p_id));
292 g_free(dynamic_hf[i].p_id);
295 proto_add_deregistered_data(dynamic_hf);
296 dynamic_hf = NULL;
297 dynamic_hf_size = 0;
300 if (user_data_fields_hash_hf) {
301 g_hash_table_destroy(user_data_fields_hash_hf);
302 user_data_fields_hash_hf = NULL;
306 static void
307 user_data_post_update_cb(void)
309 int* hf_id;
310 int *ett_id;
311 char* tmp = NULL;
312 uint64_t* key = NULL;
314 static int ett_dummy = -1;
315 static int *ett[] = {
316 &ett_dummy,
319 deregister_user_data();
321 /* we cannot unregister ETTs, so we should try to limit the damage of an update */
322 if (num_user_data_fields) {
323 user_data_fields_hash_hf = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
324 dynamic_hf = g_new0(hf_register_info, num_user_data_fields);
325 dynamic_hf_size = num_user_data_fields;
327 if (user_data_fields_hash_ett == NULL) {
328 user_data_fields_hash_ett = wmem_map_new(wmem_epan_scope(), g_int64_hash, g_int64_equal);
331 for (unsigned i = 0; i < dynamic_hf_size; i++) {
332 hf_id = g_new(int, 1);
333 *hf_id = -1;
335 dynamic_hf[i].p_id = hf_id;
336 dynamic_hf[i].hfinfo.strings = NULL;
337 dynamic_hf[i].hfinfo.bitmask = user_data_fields[i].udf_mask;
338 dynamic_hf[i].hfinfo.same_name_next = NULL;
339 dynamic_hf[i].hfinfo.same_name_prev_id = -1;
341 if (user_data_fields[i].udf_mask == 0 || user_data_fields[i].udf_length <= 0 || user_data_fields[i].udf_length>8) {
342 dynamic_hf[i].hfinfo.name = g_strdup(user_data_fields[i].udf_name);
343 dynamic_hf[i].hfinfo.abbrev = ws_strdup_printf("autosar-nm.user_data.%s", user_data_fields[i].udf_name);
344 dynamic_hf[i].hfinfo.type = FT_BYTES;
345 dynamic_hf[i].hfinfo.display = BASE_NONE;
346 dynamic_hf[i].hfinfo.bitmask = 0;
347 dynamic_hf[i].hfinfo.blurb = g_strdup(user_data_fields[i].udf_desc);
348 } else {
349 dynamic_hf[i].hfinfo.name = g_strdup(user_data_fields[i].udf_value_desc);
350 dynamic_hf[i].hfinfo.abbrev = ws_strdup_printf("autosar-nm.user_data.%s.%s", user_data_fields[i].udf_name, user_data_fields[i].udf_value_desc);
351 dynamic_hf[i].hfinfo.type = FT_BOOLEAN;
352 dynamic_hf[i].hfinfo.display = 8 * (user_data_fields[i].udf_length);
353 /* dynamic_hf[i].hfinfo.bitmask = 0; */
354 dynamic_hf[i].hfinfo.blurb = g_strdup(user_data_fields[i].udf_value_desc);
357 tmp = calc_hf_key(user_data_fields[i]);
358 g_hash_table_insert(user_data_fields_hash_hf, tmp, hf_id);
360 /* generate etts for new fields only */
361 if (get_ett_for_user_data(user_data_fields[i].udf_offset, user_data_fields[i].udf_length) == NULL) {
362 ett_dummy = -1;
363 proto_register_subtree_array(ett, array_length(ett));
365 ett_id = wmem_new(wmem_epan_scope(), int);
366 *ett_id = ett_dummy;
368 key = wmem_new(wmem_epan_scope(), uint64_t);
369 *key = calc_ett_key(user_data_fields[i].udf_offset, user_data_fields[i].udf_length);
371 wmem_map_insert(user_data_fields_hash_ett, key, ett_id);
375 proto_register_field_array(proto_autosar_nm, dynamic_hf, dynamic_hf_size);
379 static void
380 user_data_reset_cb(void)
382 deregister_user_data();
386 /**********************************
387 ****** The dissector itself ******
388 **********************************/
390 static bool
391 is_relevant_can_message(void *data)
393 const struct can_info *can_info = (struct can_info *)data;
394 DISSECTOR_ASSERT(can_info);
396 if (can_info->id & (CAN_ERR_FLAG | CAN_RTR_FLAG)) {
397 /* Error and RTR frames are not for us. */
398 return false;
401 if ((can_info->id & CAN_EFF_MASK & g_autosar_nm_can_id_mask) != (g_autosar_nm_can_id & CAN_EFF_MASK & g_autosar_nm_can_id_mask)) {
402 /* Id doesn't match. The frame is not for us. */
403 return false;
406 return true;
409 static int
410 dissect_autosar_nm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
412 proto_item *ti;
413 proto_tree *autosar_nm_tree;
414 proto_tree *autosar_nm_subtree = NULL;
415 char *tmp = NULL;
416 uint32_t offset = 0;
417 uint32_t length = 0;
418 uint32_t msg_length = 0;
419 uint32_t ctrl_bit_vector = 0;
420 uint32_t src_node_id = 0;
421 unsigned i = 0;
422 int *hf_id;
423 int *ett_id;
425 static int * const control_bits_3_0[] = {
426 &hf_autosar_nm_control_bit_vector_repeat_msg_req,
427 &hf_autosar_nm_control_bit_vector_reserved1,
428 &hf_autosar_nm_control_bit_vector_reserved2,
429 &hf_autosar_nm_control_bit_vector_reserved3,
430 &hf_autosar_nm_control_bit_vector_reserved4,
431 &hf_autosar_nm_control_bit_vector_reserved5,
432 &hf_autosar_nm_control_bit_vector_reserved6,
433 &hf_autosar_nm_control_bit_vector_reserved7,
434 NULL
437 static int * const control_bits_3_2[] = {
438 &hf_autosar_nm_control_bit_vector_repeat_msg_req,
439 &hf_autosar_nm_control_bit_vector_nm_coord_id,
440 &hf_autosar_nm_control_bit_vector_nm_coord_sleep,
441 &hf_autosar_nm_control_bit_vector_active_wakeup,
442 &hf_autosar_nm_control_bit_vector_reserved5,
443 &hf_autosar_nm_control_bit_vector_pni,
444 &hf_autosar_nm_control_bit_vector_reserved7,
445 NULL
448 static int * const control_bits_4_0[] = {
449 &hf_autosar_nm_control_bit_vector_repeat_msg_req,
450 &hf_autosar_nm_control_bit_vector_reserved1,
451 &hf_autosar_nm_control_bit_vector_reserved2,
452 &hf_autosar_nm_control_bit_vector_nm_coord_sleep,
453 &hf_autosar_nm_control_bit_vector_reserved4,
454 &hf_autosar_nm_control_bit_vector_reserved5,
455 &hf_autosar_nm_control_bit_vector_reserved6,
456 &hf_autosar_nm_control_bit_vector_reserved7,
457 NULL
460 static int * const control_bits_4_1[] = {
461 &hf_autosar_nm_control_bit_vector_repeat_msg_req,
462 &hf_autosar_nm_control_bit_vector_reserved1,
463 &hf_autosar_nm_control_bit_vector_reserved2,
464 &hf_autosar_nm_control_bit_vector_nm_coord_sleep,
465 &hf_autosar_nm_control_bit_vector_active_wakeup,
466 &hf_autosar_nm_control_bit_vector_reserved5,
467 &hf_autosar_nm_control_bit_vector_pni,
468 &hf_autosar_nm_control_bit_vector_reserved7,
469 NULL
472 static int * const control_bits_20_11[] = {
473 &hf_autosar_nm_control_bit_vector_repeat_msg_req,
474 &hf_autosar_nm_control_bit_vector_pn_shutdown_request,
475 &hf_autosar_nm_control_bit_vector_reserved2,
476 &hf_autosar_nm_control_bit_vector_nm_coord_sleep,
477 &hf_autosar_nm_control_bit_vector_active_wakeup,
478 &hf_autosar_nm_control_bit_vector_pn_learning,
479 &hf_autosar_nm_control_bit_vector_pni,
480 &hf_autosar_nm_control_bit_vector_reserved7,
481 NULL
484 col_set_str(pinfo->cinfo, COL_PROTOCOL, AUTOSAR_NM_NAME);
485 col_clear(pinfo->cinfo, COL_INFO);
487 msg_length = tvb_reported_length(tvb);
489 ti = proto_tree_add_item(tree, proto_autosar_nm, tvb, 0, -1, ENC_NA);
490 autosar_nm_tree = proto_item_add_subtree(ti, ett_autosar_nm);
492 if (g_autosar_nm_pos_sni != byte_pos_off && g_autosar_nm_pos_sni < g_autosar_nm_pos_cbv) {
493 proto_tree_add_item_ret_uint(autosar_nm_tree, hf_autosar_nm_source_node_identifier, tvb, g_autosar_nm_pos_sni, 1, ENC_BIG_ENDIAN, &src_node_id);
496 if (g_autosar_nm_pos_cbv != byte_pos_off) {
498 switch (g_autosar_nm_cbv_version) {
499 case autosar_3_0_or_newer:
500 proto_tree_add_bitmask(autosar_nm_tree, tvb, g_autosar_nm_pos_cbv, hf_autosar_nm_control_bit_vector, ett_autosar_nm_cbv, control_bits_3_0, ENC_BIG_ENDIAN);
501 break;
502 case autosar_3_2:
503 proto_tree_add_bitmask(autosar_nm_tree, tvb, g_autosar_nm_pos_cbv, hf_autosar_nm_control_bit_vector, ett_autosar_nm_cbv, control_bits_3_2, ENC_BIG_ENDIAN);
504 break;
505 case autosar_4_0:
506 proto_tree_add_bitmask(autosar_nm_tree, tvb, g_autosar_nm_pos_cbv, hf_autosar_nm_control_bit_vector, ett_autosar_nm_cbv, control_bits_4_0, ENC_BIG_ENDIAN);
507 break;
508 case autosar_4_1_or_newer:
509 proto_tree_add_bitmask(autosar_nm_tree, tvb, g_autosar_nm_pos_cbv, hf_autosar_nm_control_bit_vector, ett_autosar_nm_cbv, control_bits_4_1, ENC_BIG_ENDIAN);
510 break;
511 case autosar_20_11:
512 proto_tree_add_bitmask(autosar_nm_tree, tvb, g_autosar_nm_pos_cbv, hf_autosar_nm_control_bit_vector, ett_autosar_nm_cbv, control_bits_20_11, ENC_BIG_ENDIAN);
513 break;
516 ctrl_bit_vector = tvb_get_uint8(tvb, g_autosar_nm_pos_cbv);
519 if (g_autosar_nm_pos_sni != byte_pos_off && g_autosar_nm_pos_sni >= g_autosar_nm_pos_cbv) {
520 proto_tree_add_item_ret_uint(autosar_nm_tree, hf_autosar_nm_source_node_identifier, tvb, g_autosar_nm_pos_sni, 1, ENC_BIG_ENDIAN, &src_node_id);
523 if (g_autosar_nm_pos_cbv > g_autosar_nm_pos_sni) {
524 offset = g_autosar_nm_pos_cbv + 1;
525 } else {
526 /* This covers the case that both are turned off since -1 + 1 = 0 */
527 offset = g_autosar_nm_pos_sni + 1;
530 col_set_str(pinfo->cinfo, COL_INFO, "NM (");
531 if (g_autosar_nm_pos_cbv != byte_pos_off) {
532 col_append_fstr(pinfo->cinfo, COL_INFO, "CBV: 0x%02x", ctrl_bit_vector);
533 proto_item_append_text(ti, ", Control Bit Vector: 0x%02x", ctrl_bit_vector);
534 if (g_autosar_nm_pos_sni != byte_pos_off) {
535 col_append_fstr(pinfo->cinfo, COL_INFO, ", SNI: 0x%02x", src_node_id);
536 proto_item_append_text(ti, ", Source Node: %i", src_node_id);
538 } else {
539 if (g_autosar_nm_pos_sni != byte_pos_off) {
540 col_append_fstr(pinfo->cinfo, COL_INFO, "SNI: 0x%02x", src_node_id);
541 proto_item_append_text(ti, ", Source Node: %i", src_node_id);
544 col_append_str(pinfo->cinfo, COL_INFO, ")");
546 /* now we need to process the user defined fields ... */
547 ti = proto_tree_add_item(autosar_nm_tree, hf_autosar_nm_user_data, tvb, offset, msg_length - offset, ENC_NA);
548 autosar_nm_tree = proto_item_add_subtree(ti, ett_autosar_nm_user_data);
550 for (i = 0; i < num_user_data_fields; i++) {
551 tmp = calc_hf_key(user_data_fields[i]);
552 hf_id = get_hf_for_user_data(tmp);
554 offset = user_data_fields[i].udf_offset;
555 length = user_data_fields[i].udf_length;
556 ett_id = (get_ett_for_user_data(offset, length));
558 if (hf_id && msg_length >= length + offset) {
559 if (user_data_fields[i].udf_mask == 0) {
560 ti = proto_tree_add_item(autosar_nm_tree, *hf_id, tvb, offset, length, ENC_BIG_ENDIAN);
561 if (ett_id == NULL) {
562 autosar_nm_subtree = NULL;
563 } else {
564 autosar_nm_subtree = proto_item_add_subtree(ti, *ett_id);
566 } else {
567 if (autosar_nm_subtree != NULL) {
568 proto_tree_add_item(autosar_nm_subtree, *hf_id, tvb, offset, length, ENC_BIG_ENDIAN);
571 } else {
572 /* should we warn? */
575 g_free(tmp);
578 col_set_fence(pinfo->cinfo, COL_INFO);
580 return msg_length;
583 static int
584 dissect_autosar_nm_can(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
586 if (!is_relevant_can_message(data)) {
587 return 0;
589 return dissect_autosar_nm(tvb, pinfo, tree, data);
592 static bool
593 dissect_autosar_nm_can_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
595 if (!is_relevant_can_message(data)) {
596 return false;
598 dissect_autosar_nm(tvb, pinfo, tree, data);
599 return true;
602 void proto_register_autosar_nm(void)
604 module_t *autosar_nm_module;
605 uat_t* user_data_fields_uat;
607 static hf_register_info hf_autosar_nm[] = {
608 { &hf_autosar_nm_control_bit_vector,
609 { "Control Bit Vector", "autosar-nm.ctrl", FT_UINT8, BASE_HEX, NULL, 0x0, "The Control Bit Vector", HFILL } },
610 { &hf_autosar_nm_control_bit_vector_repeat_msg_req,
611 { "Repeat Message Request", "autosar-nm.ctrl.repeat_msg_req", FT_BOOLEAN, 8, TFS(&tfs_autosar_nm_control_rep_msg_req), 0x01, "The Repeat Message Request Bit", HFILL } },
612 { &hf_autosar_nm_control_bit_vector_reserved1,
613 { "Reserved Bit 1", "autosar-nm.ctrl.reserved1", FT_UINT8, BASE_DEC, NULL, 0x02, "The Reserved Bit 1", HFILL } },
614 { &hf_autosar_nm_control_bit_vector_pn_shutdown_request,
615 { "PN Shutdown Request", "autosar-nm.ctrl.pn_shutdown_request", FT_BOOLEAN, 8, TFS(&tfs_autosar_nm_control_pn_shutdown_req), 0x02, "The Partial Network Shutdown Request Bit", HFILL } },
616 { &hf_autosar_nm_control_bit_vector_reserved2,
617 { "Reserved Bit 2", "autosar-nm.ctrl.reserved2", FT_UINT8, BASE_DEC, NULL, 0x04, "The Reserved Bit 2", HFILL } },
618 { &hf_autosar_nm_control_bit_vector_nm_coord_id,
619 { "NM Coordinator ID", "autosar-nm.ctrl.nm_coord_id", FT_UINT8, BASE_DEC, NULL, 0x06, "The NM Coordinator Identifier", HFILL } },
620 { &hf_autosar_nm_control_bit_vector_reserved3,
621 { "Reserved Bit 3", "autosar-nm.ctrl.reserved3", FT_UINT8, BASE_DEC, NULL, 0x08, "The Reserved Bit 3", HFILL } },
622 { &hf_autosar_nm_control_bit_vector_nm_coord_sleep,
623 { "NM Coordinator Sleep Ready", "autosar-nm.ctrl.nm_coord_sleep", FT_BOOLEAN, 8, TFS(&tfs_autosar_nm_control_sleep_bit), 0x08, "NM Coordinator Sleep Ready Bit", HFILL } },
624 { &hf_autosar_nm_control_bit_vector_reserved4,
625 { "Reserved Bit 4", "autosar-nm.ctrl.reserved4", FT_UINT8, BASE_DEC, NULL, 0x10, "The Reserved Bit 4", HFILL } },
626 { &hf_autosar_nm_control_bit_vector_active_wakeup,
627 { "Active Wakeup", "autosar-nm.ctrl.active_wakeup", FT_BOOLEAN, 8, TFS(&tfs_autosar_nm_control_active_wakeup), 0x10, "Active Wakeup Bit", HFILL } },
628 { &hf_autosar_nm_control_bit_vector_reserved5,
629 { "Reserved Bit 5", "autosar-nm.ctrl.reserved5", FT_UINT8, BASE_DEC, NULL, 0x20, "The Reserved Bit 5", HFILL } },
630 { &hf_autosar_nm_control_bit_vector_pn_learning,
631 { "PN Learning", "autosar-nm.ctrl.pn_learning", FT_BOOLEAN, 8, TFS(&tfs_autosar_nm_control_pn_learning), 0x20, "The Partial Network Learning Bit", HFILL } },
632 { &hf_autosar_nm_control_bit_vector_reserved6,
633 { "Reserved Bit 6", "autosar-nm.ctrl.reserved6",FT_UINT8, BASE_DEC, NULL, 0x40, "Partial Network Information Bit", HFILL } },
634 { &hf_autosar_nm_control_bit_vector_pni,
635 { "Partial Network Information", "autosar-nm.ctrl.pni", FT_BOOLEAN, 8, TFS(&tfs_autosar_nm_control_pni), 0x40, "Partial Network Information Bit", HFILL } },
636 { &hf_autosar_nm_control_bit_vector_reserved7,
637 { "Reserved Bit 7", "autosar-nm.ctrl.reserved7", FT_UINT8, BASE_DEC, NULL, 0x80, "The Reserved Bit 7", HFILL } },
639 { &hf_autosar_nm_source_node_identifier,
640 { "Source Node Identifier", "autosar-nm.src", FT_UINT8, BASE_DEC, NULL, 0x0, "The identification of the sending node", HFILL } },
642 { &hf_autosar_nm_user_data,
643 { "User Data", "autosar-nm.user_data", FT_BYTES, BASE_NONE, NULL, 0x0, "The User Data", HFILL } },
646 static int *ett[] = {
647 &ett_autosar_nm,
648 &ett_autosar_nm_cbv,
649 &ett_autosar_nm_user_data,
652 /* UAT for user_data fields */
653 static uat_field_t user_data_uat_fields[] = {
654 UAT_FLD_CSTRING(user_data_fields, udf_name, "User data name", "Name of user data field"),
655 UAT_FLD_CSTRING(user_data_fields, udf_desc, "User data desc", "Description of user data field"),
656 UAT_FLD_DEC(user_data_fields, udf_offset, "User data offset", "Offset of the user data field in the AUTOSAR-NM message (uint32)"),
657 UAT_FLD_DEC(user_data_fields, udf_length, "User data length", "Length of the user data field in the AUTOSAR-NM message (uint32)"),
658 UAT_FLD_HEX64(user_data_fields, udf_mask, "User data mask", "Relevant bits of the user data field in the AUTOSAR-NM message (uint64)"),
659 UAT_FLD_CSTRING(user_data_fields, udf_value_desc, "User data value", "Description what the masked bits mean"),
660 UAT_END_FIELDS
663 /* Register the protocol name and description */
664 proto_autosar_nm = proto_register_protocol("AUTOSAR Network Management", AUTOSAR_NM_NAME, "autosar-nm");
665 proto_register_field_array(proto_autosar_nm, hf_autosar_nm, array_length(hf_autosar_nm));
666 proto_register_alias(proto_autosar_nm, "nm");
667 proto_register_subtree_array(ett, array_length(ett));
669 /* Register configuration options */
670 autosar_nm_module = prefs_register_protocol(proto_autosar_nm, proto_reg_handoff_autosar_nm);
672 prefs_register_enum_preference(autosar_nm_module, "cbv_version",
673 "Control Bit Vector version",
674 "Define the standard version that applies to the CBV field",
675 &g_autosar_nm_cbv_version, cbv_version_vals, false);
677 prefs_register_enum_preference(autosar_nm_module, "cbv_position",
678 "Control Bit Vector position",
679 "Make the NM dissector interpret this byte as Control Bit Vector (CBV)",
680 &g_autosar_nm_pos_cbv, byte_position_vals, false);
682 prefs_register_enum_preference(autosar_nm_module, "sni_position",
683 "Source Node Identifier position",
684 "Make the NM dissector interpret this byte as Source Node Identifier (SNI)",
685 &g_autosar_nm_pos_sni, byte_position_vals, false);
687 /* UAT */
688 user_data_fields_uat = uat_new("NM User Data Fields Table",
689 sizeof(user_data_field_t), /* record size */
690 "NM_user_data_fields", /* filename */
691 true, /* from_profile */
692 &user_data_fields, /* data_ptr */
693 &num_user_data_fields, /* numitems_ptr */
694 UAT_AFFECTS_DISSECTION | UAT_AFFECTS_FIELDS, /* specifies named fields, so affects dissection and the set of named fields */
695 NULL, /* help */
696 user_data_fields_copy_cb, /* copy callback */
697 user_data_fields_update_cb, /* update callback */
698 user_data_fields_free_cb, /* free callback */
699 user_data_post_update_cb, /* post update callback */
700 user_data_reset_cb, /* reset callback */
701 user_data_uat_fields); /* UAT field definitions */
703 prefs_register_uat_preference(autosar_nm_module, "autosar_nm_user_data_fields", "User Data Field Configuration",
704 "A table to define user defined fields in the NM payload",
705 user_data_fields_uat);
707 prefs_register_uint_preference(
708 autosar_nm_module, "can_id",
709 "AUTOSAR NM CAN id",
710 "Identifier that is used to filter packets that should be dissected. "
711 "Set bit 31 when defining an extended id. "
712 "(works with the mask defined below)",
713 16, &g_autosar_nm_can_id);
715 prefs_register_uint_preference(
716 autosar_nm_module, "can_id_mask",
717 "AUTOSAR NM CAN id mask",
718 "Mask applied to CAN identifiers when decoding whether a packet should dissected. "
719 "Use 0xFFFFFFFF mask to require exact match.",
720 16, &g_autosar_nm_can_id_mask);
722 range_convert_str(wmem_epan_scope(), &g_autosar_nm_pdus, "", 0xffffffff);
723 prefs_register_range_preference(autosar_nm_module, "pdu_transport.ids", "AUTOSAR NM PDU IDs",
724 "PDU Transport IDs.",
725 &g_autosar_nm_pdus, 0xffffffff);
727 range_convert_str(wmem_epan_scope(), &g_autosar_nm_ipdum_pdus, "", 0xffffffff);
728 prefs_register_range_preference(autosar_nm_module, "ipdum.pdu.id", "AUTOSAR I-PduM PDU IDs",
729 "I-PDU Multiplexer PDU IDs.",
730 &g_autosar_nm_ipdum_pdus, 0xffffffff);
732 nm_handle = register_dissector("autosar-nm", dissect_autosar_nm, proto_autosar_nm);
733 nm_handle_can = register_dissector("autosar-nm.can", dissect_autosar_nm_can, proto_autosar_nm);
736 void proto_reg_handoff_autosar_nm(void)
738 static bool initialized = false;
740 if (!initialized) {
741 dissector_add_for_decode_as_with_preference("udp.port", nm_handle);
743 dissector_add_for_decode_as("can.subdissector", nm_handle_can);
745 /* heuristics default on since they do nothing without IDs being configured */
746 heur_dissector_add("can", dissect_autosar_nm_can_heur, "AUTOSAR NM over CAN", "autosar_nm_can_heur", proto_autosar_nm, HEURISTIC_ENABLE);
748 initialized = true;
749 } else {
750 dissector_delete_all("pdu_transport.id", nm_handle);
751 dissector_delete_all("ipdum.pdu.id", nm_handle);
754 dissector_add_uint_range("pdu_transport.id", g_autosar_nm_pdus, nm_handle);
755 dissector_add_uint_range("ipdum.pdu.id", g_autosar_nm_ipdum_pdus, nm_handle);
759 * Editor modelines
761 * Local Variables:
762 * c-basic-offset: 2
763 * tab-width: 8
764 * indent-tabs-mode: nil
765 * End:
767 * ex: set shiftwidth=2 tabstop=8 expandtab:
768 * :indentSize=2:tabSize=8:noTabs=true: