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