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>
6 *
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
10 *
11 * SPDX-License-Identifier: GPL-2.0-or-later
12 */
13
14 /*
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.
19 */
20
21 #include <config.h>
22
23 #include <epan/packet.h>
24 #include <epan/prefs.h>
25 #include <epan/uat.h>
26 #include "packet-socketcan.h"
27
28 void proto_reg_handoff_autosar_nm(void);
29 void proto_register_autosar_nm(void);
30
31 #define AUTOSAR_NM_NAME "AUTOSAR NM"
32
33 typedef struct _user_data_field_t {
34 gchar* udf_name;
35 gchar* udf_desc;
36 guint32 udf_offset;
37 guint32 udf_length;
38 guint64 udf_mask;
39 gchar* udf_value_desc;
40 } user_data_field_t;
41
42 static int proto_autosar_nm = -1;
43
44 static dissector_handle_t nm_handle;
45 static dissector_handle_t nm_handle_can;
46
47 /*** header fields ***/
48 static int hf_autosar_nm_source_node_identifier = -1;
49 static int hf_autosar_nm_control_bit_vector = -1;
50 static int hf_autosar_nm_control_bit_vector_repeat_msg_req = -1;
51 static int hf_autosar_nm_control_bit_vector_reserved1 = -1;
52 static int hf_autosar_nm_control_bit_vector_pn_shutdown_request = -1;
53 static int hf_autosar_nm_control_bit_vector_reserved2 = -1;
54 static int hf_autosar_nm_control_bit_vector_nm_coord_id = -1;
55 static int hf_autosar_nm_control_bit_vector_reserved3 = -1;
56 static int hf_autosar_nm_control_bit_vector_nm_coord_sleep = -1;
57 static int hf_autosar_nm_control_bit_vector_reserved4 = -1;
58 static int hf_autosar_nm_control_bit_vector_active_wakeup = -1;
59 static int hf_autosar_nm_control_bit_vector_reserved5 = -1;
60 static int hf_autosar_nm_control_bit_vector_pn_learning = -1;
61 static int hf_autosar_nm_control_bit_vector_pni = -1;
62 static int hf_autosar_nm_control_bit_vector_reserved6 = -1;
63 static int hf_autosar_nm_control_bit_vector_reserved7 = -1;
64 static int hf_autosar_nm_user_data = -1;
65
66 /*** protocol tree items ***/
67 static gint ett_autosar_nm = -1;
68 static gint ett_autosar_nm_cbv = -1;
69 static gint ett_autosar_nm_user_data = -1;
70
71 /*** Bit meanings ***/
72 static const true_false_string tfs_autosar_nm_control_rep_msg_req = {
73 "Repeat Message State requested", "Repeat Message State not requested" };
74
75 static const true_false_string tfs_autosar_nm_control_pn_shutdown_req= {
76 "NM message contains synchronized PN shutdown request", "NM message does not contain synchronized PN shutdown request" };
77
78 static const true_false_string tfs_autosar_nm_control_sleep_bit = {
79 "Start of synchronized shutdown requested", "Start of synchronized shutdown not requested" };
80
81 static const true_false_string tfs_autosar_nm_control_active_wakeup = {
82 "Node has woken up the network", "Node has not woken up the network" };
83
84 static const true_false_string tfs_autosar_nm_control_pn_learning = {
85 "PNC learning is requested", "PNC learning is not requested" };
86
87 static const true_false_string tfs_autosar_nm_control_pni = {
88 "NM message contains Partial Network request information", "NM message contains no Partial Network request information" };
89
90 /*** Configuration items ***/
91
92 enum parameter_byte_position_value {
93 byte_pos_off = -1,
94 byte_pos_0 = 0,
95 byte_pos_1 = 1
96 };
97
98 static const enum_val_t byte_position_vals[] = {
99 {"0", "Byte Position 0", byte_pos_0},
100 {"1", "Byte Position 1", byte_pos_1},
101 {"off", "Turned off", byte_pos_off},
102 {NULL, NULL, -1}
103 };
104
105 /* Set positions of the first two fields (Source Node Identifier and Control Bit Vector */
106 static gint g_autosar_nm_pos_cbv = (gint)byte_pos_0;
107 static gint g_autosar_nm_pos_sni = (gint)byte_pos_1;
108
109 enum parameter_cbv_version_value {
110 autosar_3_0_or_newer = 0,
111 autosar_3_2,
112 autosar_4_0,
113 autosar_4_1_or_newer,
114 autosar_20_11
115 };
116
117 static const enum_val_t cbv_version_vals[] = {
118 {"3.0", "AUTOSAR 3.0 or 3.1", autosar_3_0_or_newer},
119 {"3.2", "AUTOSAR 3.2", autosar_3_2},
120 {"4.0", "AUTOSAR 4.0", autosar_4_0},
121 {"4.1", "AUTOSAR 4.1 or newer", autosar_4_1_or_newer},
122 {"20-11", "AUTOSAR 20-11", autosar_20_11},
123 {NULL, NULL, -1}
124 };
125
126 static gint g_autosar_nm_cbv_version = (gint)autosar_4_1_or_newer;
127
128 /* Id and mask of CAN frames to be dissected */
129 static guint32 g_autosar_nm_can_id = 0;
130 static guint32 g_autosar_nm_can_id_mask = 0xffffffff;
131
132 /* Relevant PDUs */
133 static range_t *g_autosar_nm_pdus = NULL;
134
135 /*******************************
136 ****** User data fields ******
137 *******************************/
138
139 static user_data_field_t* user_data_fields;
140 static guint num_user_data_fields;
141 static GHashTable* user_data_fields_hash_hf;
142 static hf_register_info* dynamic_hf;
143 static guint dynamic_hf_size;
144 static wmem_map_t* user_data_fields_hash_ett;
145
146 static gboolean
user_data_fields_update_cb(void * r,char ** err)147 user_data_fields_update_cb(void *r, char **err)
148 {
149 user_data_field_t *rec = (user_data_field_t *)r;
150 char c;
151 *err = NULL;
152
153 if (rec->udf_length == 0) {
154 *err = g_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);
155 return (*err == NULL);
156 }
157
158 if (rec->udf_length > 8) {
159 *err = g_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);
160 return (*err == NULL);
161 }
162
163 if (rec->udf_mask >= G_MAXUINT64) {
164 *err = g_strdup_printf("mask can only be up to 64bits (name: %s)", rec->udf_name);
165 return (*err == NULL);
166 }
167
168 if (rec->udf_name == NULL) {
169 *err = g_strdup_printf("Name of user data field can't be empty");
170 return (*err == NULL);
171 }
172
173 g_strstrip(rec->udf_name);
174 if (rec->udf_name[0] == 0) {
175 *err = g_strdup_printf("Name of user data field can't be empty");
176 return (*err == NULL);
177 }
178
179 /* Check for invalid characters (to avoid asserting out when registering the field). */
180 c = proto_check_field_name(rec->udf_name);
181 if (c) {
182 *err = g_strdup_printf("Name of user data field can't contain '%c'", c);
183 return (*err == NULL);
184 }
185
186 return (*err == NULL);
187 }
188
189 static void *
user_data_fields_copy_cb(void * n,const void * o,size_t size _U_)190 user_data_fields_copy_cb(void* n, const void* o, size_t size _U_)
191 {
192 user_data_field_t* new_rec = (user_data_field_t*)n;
193 const user_data_field_t* old_rec = (const user_data_field_t*)o;
194
195 new_rec->udf_name = g_strdup(old_rec->udf_name);
196 new_rec->udf_desc = g_strdup(old_rec->udf_desc);
197 new_rec->udf_offset = old_rec->udf_offset;
198 new_rec->udf_length = old_rec->udf_length;
199 new_rec->udf_mask = old_rec->udf_mask;
200 new_rec->udf_value_desc = g_strdup(old_rec->udf_value_desc);
201
202 return new_rec;
203 }
204
205 static void
user_data_fields_free_cb(void * r)206 user_data_fields_free_cb(void*r)
207 {
208 user_data_field_t* rec = (user_data_field_t*)r;
209
210 g_free(rec->udf_name);
211 g_free(rec->udf_desc);
212 g_free(rec->udf_value_desc);
213 }
214
UAT_CSTRING_CB_DEF(user_data_fields,udf_name,user_data_field_t)215 UAT_CSTRING_CB_DEF(user_data_fields, udf_name, user_data_field_t)
216 UAT_CSTRING_CB_DEF(user_data_fields, udf_desc, user_data_field_t)
217 UAT_DEC_CB_DEF(user_data_fields, udf_offset, user_data_field_t)
218 UAT_DEC_CB_DEF(user_data_fields, udf_length, user_data_field_t)
219 UAT_HEX64_CB_DEF(user_data_fields, udf_mask, user_data_field_t)
220 UAT_CSTRING_CB_DEF(user_data_fields, udf_value_desc, user_data_field_t)
221
222 static guint64
223 calc_ett_key(guint32 offset, guint32 length)
224 {
225 guint64 ret = (guint64)offset;
226 return (ret << 32) ^ length;
227 }
228
229 /*
230 * This creates a string for you that can be used as key for the hash table.
231 * YOU must g_free that string!
232 */
233 static gchar*
calc_hf_key(user_data_field_t udf)234 calc_hf_key(user_data_field_t udf)
235 {
236 gchar* ret = NULL;
237 ret = g_strdup_printf("%i-%i-%" G_GUINT64_FORMAT "-%s", udf.udf_offset, udf.udf_length, udf.udf_mask, udf.udf_name);
238 return ret;
239 }
240
241 /*
242 * Lookup the hf for the user data based on the key
243 */
244 static gint*
get_hf_for_user_data(gchar * key)245 get_hf_for_user_data(gchar* key)
246 {
247 gint* hf_id = NULL;
248
249 if (user_data_fields_hash_hf) {
250 hf_id = (gint*)g_hash_table_lookup(user_data_fields_hash_hf, key);
251 }
252 else {
253 hf_id = NULL;
254 }
255
256 return hf_id;
257 }
258
259 /*
260 * Lookup the ett for the user data based on the key
261 */
262 static gint*
get_ett_for_user_data(guint32 offset,guint32 length)263 get_ett_for_user_data(guint32 offset, guint32 length)
264 {
265 gint* ett_id = NULL;
266
267 guint64 key = calc_ett_key(offset, length);
268
269 if (user_data_fields_hash_ett) {
270 ett_id = (gint*)wmem_map_lookup(user_data_fields_hash_ett, &key);
271 }
272 else {
273 ett_id = NULL;
274 }
275
276 return ett_id;
277 }
278
279 /*
280 * clean up user data
281 */
282 static void
deregister_user_data(void)283 deregister_user_data(void)
284 {
285 if (dynamic_hf) {
286 /* Unregister all fields */
287 for (guint i = 0; i < dynamic_hf_size; i++) {
288 proto_deregister_field(proto_autosar_nm, *(dynamic_hf[i].p_id));
289 g_free(dynamic_hf[i].p_id);
290 }
291
292 proto_add_deregistered_data(dynamic_hf);
293 dynamic_hf = NULL;
294 dynamic_hf_size = 0;
295 }
296
297 if (user_data_fields_hash_hf) {
298 g_hash_table_destroy(user_data_fields_hash_hf);
299 user_data_fields_hash_hf = NULL;
300 }
301 }
302
303 static void
user_data_post_update_cb(void)304 user_data_post_update_cb(void)
305 {
306 gint* hf_id;
307 gint *ett_id;
308 gchar* tmp = NULL;
309 guint64* key = NULL;
310
311 static gint ett_dummy = -1;
312 static gint *ett[] = {
313 &ett_dummy,
314 };
315
316 deregister_user_data();
317
318 /* we cannot unregister ETTs, so we should try to limit the damage of an update */
319 if (num_user_data_fields) {
320 user_data_fields_hash_hf = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
321 dynamic_hf = g_new0(hf_register_info, num_user_data_fields);
322 dynamic_hf_size = num_user_data_fields;
323
324 if (user_data_fields_hash_ett == NULL) {
325 user_data_fields_hash_ett = wmem_map_new(wmem_epan_scope(), g_int64_hash, g_int64_equal);
326 }
327
328 for (guint i = 0; i < dynamic_hf_size; i++) {
329 hf_id = g_new(gint, 1);
330 *hf_id = -1;
331
332 dynamic_hf[i].p_id = hf_id;
333 dynamic_hf[i].hfinfo.strings = NULL;
334 dynamic_hf[i].hfinfo.bitmask = user_data_fields[i].udf_mask;
335 dynamic_hf[i].hfinfo.same_name_next = NULL;
336 dynamic_hf[i].hfinfo.same_name_prev_id = -1;
337
338 if (user_data_fields[i].udf_mask == 0 || user_data_fields[i].udf_length <= 0 || user_data_fields[i].udf_length>8) {
339 dynamic_hf[i].hfinfo.name = g_strdup(user_data_fields[i].udf_name);
340 dynamic_hf[i].hfinfo.abbrev = g_strdup_printf("autosar-nm.user_data.%s", user_data_fields[i].udf_name);
341 dynamic_hf[i].hfinfo.type = FT_BYTES;
342 dynamic_hf[i].hfinfo.display = BASE_NONE;
343 dynamic_hf[i].hfinfo.bitmask = 0;
344 dynamic_hf[i].hfinfo.blurb = g_strdup(user_data_fields[i].udf_desc);
345 } else {
346 dynamic_hf[i].hfinfo.name = g_strdup(user_data_fields[i].udf_value_desc);
347 dynamic_hf[i].hfinfo.abbrev = g_strdup_printf("autosar-nm.user_data.%s.%s", user_data_fields[i].udf_name, user_data_fields[i].udf_value_desc);
348 dynamic_hf[i].hfinfo.type = FT_BOOLEAN;
349 dynamic_hf[i].hfinfo.display = 8 * (user_data_fields[i].udf_length);
350 /* dynamic_hf[i].hfinfo.bitmask = 0; */
351 dynamic_hf[i].hfinfo.blurb = g_strdup(user_data_fields[i].udf_value_desc);
352 }
353
354 tmp = calc_hf_key(user_data_fields[i]);
355 g_hash_table_insert(user_data_fields_hash_hf, tmp, hf_id);
356
357 /* generate etts for new fields only */
358 if (get_ett_for_user_data(user_data_fields[i].udf_offset, user_data_fields[i].udf_length) == NULL) {
359 ett_dummy = -1;
360 proto_register_subtree_array(ett, array_length(ett));
361
362 ett_id = wmem_new(wmem_epan_scope(), gint);
363 *ett_id = ett_dummy;
364
365 key = wmem_new(wmem_epan_scope(), guint64);
366 *key = calc_ett_key(user_data_fields[i].udf_offset, user_data_fields[i].udf_length);
367
368 wmem_map_insert(user_data_fields_hash_ett, key, ett_id);
369 }
370 }
371
372 proto_register_field_array(proto_autosar_nm, dynamic_hf, dynamic_hf_size);
373 }
374 }
375
376 static void
user_data_reset_cb(void)377 user_data_reset_cb(void)
378 {
379 deregister_user_data();
380 }
381
382
383 /**********************************
384 ****** The dissector itself ******
385 **********************************/
386
387 static gboolean
is_relevant_can_message(void * data)388 is_relevant_can_message(void *data)
389 {
390 const struct can_info *can_info = (struct can_info *)data;
391 DISSECTOR_ASSERT(can_info);
392
393 if (can_info->id & (CAN_ERR_FLAG | CAN_RTR_FLAG)) {
394 /* Error and RTR frames are not for us. */
395 return FALSE;
396 }
397
398 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)) {
399 /* Id doesn't match. The frame is not for us. */
400 return FALSE;
401 }
402
403 return TRUE;
404 }
405
406 static int
dissect_autosar_nm(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)407 dissect_autosar_nm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
408 {
409 proto_item *ti;
410 proto_tree *autosar_nm_tree;
411 proto_tree *autosar_nm_subtree = NULL;
412 gchar *tmp = NULL;
413 guint32 offset = 0;
414 guint32 length = 0;
415 guint32 msg_length = 0;
416 guint32 ctrl_bit_vector = 0;
417 guint32 src_node_id = 0;
418 guint i = 0;
419 int *hf_id;
420 int *ett_id;
421
422 static int * const control_bits_3_0[] = {
423 &hf_autosar_nm_control_bit_vector_repeat_msg_req,
424 &hf_autosar_nm_control_bit_vector_reserved1,
425 &hf_autosar_nm_control_bit_vector_reserved2,
426 &hf_autosar_nm_control_bit_vector_reserved3,
427 &hf_autosar_nm_control_bit_vector_reserved4,
428 &hf_autosar_nm_control_bit_vector_reserved5,
429 &hf_autosar_nm_control_bit_vector_reserved6,
430 &hf_autosar_nm_control_bit_vector_reserved7,
431 NULL
432 };
433
434 static int * const control_bits_3_2[] = {
435 &hf_autosar_nm_control_bit_vector_repeat_msg_req,
436 &hf_autosar_nm_control_bit_vector_nm_coord_id,
437 &hf_autosar_nm_control_bit_vector_nm_coord_sleep,
438 &hf_autosar_nm_control_bit_vector_active_wakeup,
439 &hf_autosar_nm_control_bit_vector_reserved5,
440 &hf_autosar_nm_control_bit_vector_pni,
441 &hf_autosar_nm_control_bit_vector_reserved7,
442 NULL
443 };
444
445 static int * const control_bits_4_0[] = {
446 &hf_autosar_nm_control_bit_vector_repeat_msg_req,
447 &hf_autosar_nm_control_bit_vector_reserved1,
448 &hf_autosar_nm_control_bit_vector_reserved2,
449 &hf_autosar_nm_control_bit_vector_nm_coord_sleep,
450 &hf_autosar_nm_control_bit_vector_reserved4,
451 &hf_autosar_nm_control_bit_vector_reserved5,
452 &hf_autosar_nm_control_bit_vector_reserved6,
453 &hf_autosar_nm_control_bit_vector_reserved7,
454 NULL
455 };
456
457 static int * const control_bits_4_1[] = {
458 &hf_autosar_nm_control_bit_vector_repeat_msg_req,
459 &hf_autosar_nm_control_bit_vector_reserved1,
460 &hf_autosar_nm_control_bit_vector_reserved2,
461 &hf_autosar_nm_control_bit_vector_nm_coord_sleep,
462 &hf_autosar_nm_control_bit_vector_active_wakeup,
463 &hf_autosar_nm_control_bit_vector_reserved5,
464 &hf_autosar_nm_control_bit_vector_pni,
465 &hf_autosar_nm_control_bit_vector_reserved7,
466 NULL
467 };
468
469 static int * const control_bits_20_11[] = {
470 &hf_autosar_nm_control_bit_vector_repeat_msg_req,
471 &hf_autosar_nm_control_bit_vector_pn_shutdown_request,
472 &hf_autosar_nm_control_bit_vector_reserved2,
473 &hf_autosar_nm_control_bit_vector_nm_coord_sleep,
474 &hf_autosar_nm_control_bit_vector_active_wakeup,
475 &hf_autosar_nm_control_bit_vector_pn_learning,
476 &hf_autosar_nm_control_bit_vector_pni,
477 &hf_autosar_nm_control_bit_vector_reserved7,
478 NULL
479 };
480
481 col_set_str(pinfo->cinfo, COL_PROTOCOL, AUTOSAR_NM_NAME);
482 col_clear(pinfo->cinfo, COL_INFO);
483
484 msg_length = tvb_reported_length(tvb);
485
486 ti = proto_tree_add_item(tree, proto_autosar_nm, tvb, 0, -1, ENC_NA);
487 autosar_nm_tree = proto_item_add_subtree(ti, ett_autosar_nm);
488
489 if (g_autosar_nm_pos_sni != byte_pos_off && g_autosar_nm_pos_sni < g_autosar_nm_pos_cbv) {
490 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);
491 }
492
493 if (g_autosar_nm_pos_cbv != byte_pos_off) {
494
495 switch (g_autosar_nm_cbv_version) {
496 case autosar_3_0_or_newer:
497 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);
498 break;
499 case autosar_3_2:
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_2, ENC_BIG_ENDIAN);
501 break;
502 case autosar_4_0:
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_4_0, ENC_BIG_ENDIAN);
504 break;
505 case autosar_4_1_or_newer:
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_1, ENC_BIG_ENDIAN);
507 break;
508 case autosar_20_11:
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_20_11, ENC_BIG_ENDIAN);
510 break;
511 }
512
513 ctrl_bit_vector = tvb_get_guint8(tvb, g_autosar_nm_pos_cbv);
514 }
515
516 if (g_autosar_nm_pos_sni != byte_pos_off && g_autosar_nm_pos_sni >= g_autosar_nm_pos_cbv) {
517 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);
518 }
519
520 if (g_autosar_nm_pos_cbv > g_autosar_nm_pos_sni) {
521 offset = g_autosar_nm_pos_cbv + 1;
522 } else {
523 /* This covers the case that both are turned off since -1 + 1 = 0 */
524 offset = g_autosar_nm_pos_sni + 1;
525 }
526
527 col_add_fstr(pinfo->cinfo, COL_INFO, "NM (");
528 if (g_autosar_nm_pos_cbv != byte_pos_off) {
529 col_append_fstr(pinfo->cinfo, COL_INFO, "CBV: 0x%02x", ctrl_bit_vector);
530 proto_item_append_text(ti, ", Control Bit Vector: 0x%02x", ctrl_bit_vector);
531 if (g_autosar_nm_pos_sni != byte_pos_off) {
532 col_append_fstr(pinfo->cinfo, COL_INFO, ", SNI: 0x%02x", src_node_id);
533 proto_item_append_text(ti, ", Source Node: %i", src_node_id);
534 }
535 } else {
536 if (g_autosar_nm_pos_sni != byte_pos_off) {
537 col_append_fstr(pinfo->cinfo, COL_INFO, "SNI: 0x%02x", src_node_id);
538 proto_item_append_text(ti, ", Source Node: %i", src_node_id);
539 }
540 }
541 col_append_fstr(pinfo->cinfo, COL_INFO, ")");
542
543 /* now we need to process the user defined fields ... */
544 ti = proto_tree_add_item(autosar_nm_tree, hf_autosar_nm_user_data, tvb, offset, msg_length - offset, ENC_NA);
545 autosar_nm_tree = proto_item_add_subtree(ti, ett_autosar_nm_user_data);
546
547 for (i = 0; i < num_user_data_fields; i++) {
548 tmp = calc_hf_key(user_data_fields[i]);
549 hf_id = get_hf_for_user_data(tmp);
550
551 offset = user_data_fields[i].udf_offset;
552 length = user_data_fields[i].udf_length;
553 ett_id = (get_ett_for_user_data(offset, length));
554
555 if (hf_id && msg_length >= length + offset) {
556 if (user_data_fields[i].udf_mask == 0) {
557 ti = proto_tree_add_item(autosar_nm_tree, *hf_id, tvb, offset, length, ENC_BIG_ENDIAN);
558 if (ett_id == NULL) {
559 autosar_nm_subtree = NULL;
560 } else {
561 autosar_nm_subtree = proto_item_add_subtree(ti, *ett_id);
562 }
563 } else {
564 if (autosar_nm_subtree != NULL) {
565 proto_tree_add_item(autosar_nm_subtree, *hf_id, tvb, offset, length, ENC_BIG_ENDIAN);
566 }
567 }
568 } else {
569 /* should we warn? */
570 }
571
572 g_free(tmp);
573 }
574
575 col_set_fence(pinfo->cinfo, COL_INFO);
576
577 return msg_length;
578 }
579
580 static int
dissect_autosar_nm_can(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)581 dissect_autosar_nm_can(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
582 {
583 if (!is_relevant_can_message(data)) {
584 return 0;
585 }
586 return dissect_autosar_nm(tvb, pinfo, tree, data);
587 }
588
589 static gboolean
dissect_autosar_nm_can_heur(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)590 dissect_autosar_nm_can_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
591 {
592 if (!is_relevant_can_message(data)) {
593 return FALSE;
594 }
595 dissect_autosar_nm(tvb, pinfo, tree, data);
596 return TRUE;
597 }
598
proto_register_autosar_nm(void)599 void proto_register_autosar_nm(void)
600 {
601 module_t *autosar_nm_module;
602 uat_t* user_data_fields_uat;
603
604 static hf_register_info hf_autosar_nm[] = {
605 { &hf_autosar_nm_control_bit_vector,
606 { "Control Bit Vector", "autosar-nm.ctrl", FT_UINT8, BASE_HEX, NULL, 0x0, "The Control Bit Vector", HFILL } },
607 { &hf_autosar_nm_control_bit_vector_repeat_msg_req,
608 { "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 } },
609 { &hf_autosar_nm_control_bit_vector_reserved1,
610 { "Reserved Bit 1", "autosar-nm.ctrl.reserved1", FT_UINT8, BASE_DEC, NULL, 0x02, "The Reserved Bit 1", HFILL } },
611 { &hf_autosar_nm_control_bit_vector_pn_shutdown_request,
612 { "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 } },
613 { &hf_autosar_nm_control_bit_vector_reserved2,
614 { "Reserved Bit 2", "autosar-nm.ctrl.reserved2", FT_UINT8, BASE_DEC, NULL, 0x04, "The Reserved Bit 2", HFILL } },
615 { &hf_autosar_nm_control_bit_vector_nm_coord_id,
616 { "NM Coordinator ID", "autosar-nm.ctrl.nm_coord_id", FT_UINT8, BASE_DEC, NULL, 0x06, "The NM Coordinator Identifier", HFILL } },
617 { &hf_autosar_nm_control_bit_vector_reserved3,
618 { "Reserved Bit 3", "autosar-nm.ctrl.reserved3", FT_UINT8, BASE_DEC, NULL, 0x08, "The Reserved Bit 3", HFILL } },
619 { &hf_autosar_nm_control_bit_vector_nm_coord_sleep,
620 { "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 } },
621 { &hf_autosar_nm_control_bit_vector_reserved4,
622 { "Reserved Bit 4", "autosar-nm.ctrl.reserved4", FT_UINT8, BASE_DEC, NULL, 0x10, "The Reserved Bit 4", HFILL } },
623 { &hf_autosar_nm_control_bit_vector_active_wakeup,
624 { "Active Wakeup", "autosar-nm.ctrl.active_wakeup", FT_BOOLEAN, 8, TFS(&tfs_autosar_nm_control_active_wakeup), 0x10, "Active Wakeup Bit", HFILL } },
625 { &hf_autosar_nm_control_bit_vector_reserved5,
626 { "Reserved Bit 5", "autosar-nm.ctrl.reserved5", FT_UINT8, BASE_DEC, NULL, 0x20, "The Reserved Bit 5", HFILL } },
627 { &hf_autosar_nm_control_bit_vector_pn_learning,
628 { "PN Learning", "autosar-nm.ctrl.pn_learning", FT_BOOLEAN, 8, TFS(&tfs_autosar_nm_control_pn_learning), 0x20, "The Partial Network Learning Bit", HFILL } },
629 { &hf_autosar_nm_control_bit_vector_reserved6,
630 { "Reserved Bit 6", "autosar-nm.ctrl.reserved6",FT_UINT8, BASE_DEC, NULL, 0x40, "Partial Network Information Bit", HFILL } },
631 { &hf_autosar_nm_control_bit_vector_pni,
632 { "Partial Network Information", "autosar-nm.ctrl.pni", FT_BOOLEAN, 8, TFS(&tfs_autosar_nm_control_pni), 0x40, "Partial Network Information Bit", HFILL } },
633 { &hf_autosar_nm_control_bit_vector_reserved7,
634 { "Reserved Bit 7", "autosar-nm.ctrl.reserved7", FT_UINT8, BASE_DEC, NULL, 0x80, "The Reserved Bit 7", HFILL } },
635
636 { &hf_autosar_nm_source_node_identifier,
637 { "Source Node Identifier", "autosar-nm.src", FT_UINT8, BASE_DEC, NULL, 0x0, "The identification of the sending node", HFILL } },
638
639 { &hf_autosar_nm_user_data,
640 { "User Data", "autosar-nm.user_data", FT_BYTES, BASE_NONE, NULL, 0x0, "The User Data", HFILL } },
641 };
642
643 static gint *ett[] = {
644 &ett_autosar_nm,
645 &ett_autosar_nm_cbv,
646 &ett_autosar_nm_user_data,
647 };
648
649 /* UAT for user_data fields */
650 static uat_field_t user_data_uat_fields[] = {
651 UAT_FLD_CSTRING(user_data_fields, udf_name, "User data name", "Name of user data field"),
652 UAT_FLD_CSTRING(user_data_fields, udf_desc, "User data desc", "Description of user data field"),
653 UAT_FLD_DEC(user_data_fields, udf_offset, "User data offset", "Offset of the user data field in the AUTOSAR-NM message (uint32)"),
654 UAT_FLD_DEC(user_data_fields, udf_length, "User data length", "Length of the user data field in the AUTOSAR-NM message (uint32)"),
655 UAT_FLD_HEX64(user_data_fields, udf_mask, "User data mask", "Relevant bits of the user data field in the AUTOSAR-NM message (uint64)"),
656 UAT_FLD_CSTRING(user_data_fields, udf_value_desc, "User data value", "Description what the masked bits mean"),
657 UAT_END_FIELDS
658 };
659
660 /* Register the protocol name and description */
661 proto_autosar_nm = proto_register_protocol("AUTOSAR Network Management", AUTOSAR_NM_NAME, "autosar-nm");
662 proto_register_field_array(proto_autosar_nm, hf_autosar_nm, array_length(hf_autosar_nm));
663 proto_register_alias(proto_autosar_nm, "nm");
664 proto_register_subtree_array(ett, array_length(ett));
665
666 /* Register configuration options */
667 autosar_nm_module = prefs_register_protocol(proto_autosar_nm, proto_reg_handoff_autosar_nm);
668
669 prefs_register_enum_preference(autosar_nm_module, "cbv_version",
670 "Control Bit Vector version",
671 "Define the standard version that applies to the CBV field",
672 &g_autosar_nm_cbv_version, cbv_version_vals, FALSE);
673
674 prefs_register_enum_preference(autosar_nm_module, "cbv_position",
675 "Control Bit Vector position",
676 "Make the NM dissector interpret this byte as Control Bit Vector (CBV)",
677 &g_autosar_nm_pos_cbv, byte_position_vals, FALSE);
678
679 prefs_register_enum_preference(autosar_nm_module, "sni_position",
680 "Source Node Identifier position",
681 "Make the NM dissector interpret this byte as Source Node Identifier (SNI)",
682 &g_autosar_nm_pos_sni, byte_position_vals, FALSE);
683
684 /* UAT */
685 user_data_fields_uat = uat_new("NM User Data Fields Table",
686 sizeof(user_data_field_t), /* record size */
687 "NM_user_data_fields", /* filename */
688 TRUE, /* from_profile */
689 &user_data_fields, /* data_ptr */
690 &num_user_data_fields, /* numitems_ptr */
691 UAT_AFFECTS_DISSECTION | UAT_AFFECTS_FIELDS, /* specifies named fields, so affects dissection and the set of named fields */
692 NULL, /* help */
693 user_data_fields_copy_cb, /* copy callback */
694 user_data_fields_update_cb, /* update callback */
695 user_data_fields_free_cb, /* free callback */
696 user_data_post_update_cb, /* post update callback */
697 user_data_reset_cb, /* reset callback */
698 user_data_uat_fields); /* UAT field definitions */
699
700 prefs_register_uat_preference(autosar_nm_module, "autosar_nm_user_data_fields", "User Data Field Configuration",
701 "A table to define user defined fields in the NM payload",
702 user_data_fields_uat);
703
704 prefs_register_uint_preference(
705 autosar_nm_module, "can_id",
706 "AUTOSAR NM CAN id",
707 "Identifier that is used to filter packets that should be dissected. "
708 "Set bit 31 when defining an extended id. "
709 "(works with the mask defined below)",
710 16, &g_autosar_nm_can_id);
711
712 prefs_register_uint_preference(
713 autosar_nm_module, "can_id_mask",
714 "AUTOSAR NM CAN id mask",
715 "Mask applied to CAN identifiers when decoding whether a packet should dissected. "
716 "Use 0xFFFFFFFF mask to require exact match.",
717 16, &g_autosar_nm_can_id_mask);
718
719 range_convert_str(wmem_epan_scope(), &g_autosar_nm_pdus, "", 0xffffffff);
720 prefs_register_range_preference(autosar_nm_module, "pdu_transport.ids", "AUTOSAR NM PDU IDs",
721 "PDU Transport IDs.",
722 &g_autosar_nm_pdus, 0xffffffff);
723 }
724
proto_reg_handoff_autosar_nm(void)725 void proto_reg_handoff_autosar_nm(void)
726 {
727 static gboolean initialized = FALSE;
728
729 if (!initialized) {
730 nm_handle = create_dissector_handle(dissect_autosar_nm, proto_autosar_nm);
731 dissector_add_for_decode_as_with_preference("udp.port", nm_handle);
732
733 nm_handle_can = create_dissector_handle(dissect_autosar_nm_can, proto_autosar_nm);
734 dissector_add_for_decode_as("can.subdissector", nm_handle_can);
735
736 /* heuristics default on since they do nothing without IDs being configured */
737 heur_dissector_add("can", dissect_autosar_nm_can_heur, "AUTOSAR_NM_Heuristic", "autosar_nm_can_heur", proto_autosar_nm, HEURISTIC_ENABLE);
738
739 initialized = TRUE;
740 } else {
741 dissector_delete_all("pdu_transport.id", nm_handle);
742 }
743
744 dissector_add_uint_range("pdu_transport.id", g_autosar_nm_pdus, nm_handle);
745 }
746
747 /*
748 * Editor modelines
749 *
750 * Local Variables:
751 * c-basic-offset: 2
752 * tab-width: 8
753 * indent-tabs-mode: nil
754 * End:
755 *
756 * ex: set shiftwidth=2 tabstop=8 expandtab:
757 * :indentSize=2:tabSize=8:noTabs=true:
758 */
759