4 * By Dr. Lars Voelker <lars.voelker@technica-engineering.de>
5 * Copyright 2021-2023 Dr. Lars Voelker
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
16 #include <epan/packet.h>
17 #include <epan/decode_as.h>
18 #include <epan/prefs.h>
19 #include <wiretap/wtap.h>
20 #include <epan/expert.h>
23 #include "packet-lin.h"
26 * Dissector for the Local Interconnect Network (LIN) bus.
28 * see ISO 17987 or search for "LIN Specification 2.2a" online.
31 #define LIN_NAME "LIN"
32 #define LIN_NAME_LONG "LIN Protocol"
33 #define LIN_NAME_FILTER "lin"
35 static heur_dissector_list_t heur_subdissector_list
;
36 static heur_dtbl_entry_t
*heur_dtbl_entry
;
40 static dissector_handle_t lin_handle
;
43 static int hf_lin_msg_format_rev
;
44 static int hf_lin_reserved1
;
45 static int hf_lin_payload_length
;
46 static int hf_lin_message_type
;
47 static int hf_lin_checksum_type
;
48 static int hf_lin_pid
;
50 static int hf_lin_parity
;
51 static int hf_lin_checksum
;
52 static int hf_lin_err_errors
;
53 static int hf_lin_err_no_slave_response
;
54 static int hf_lin_err_framing
;
55 static int hf_lin_err_parity
;
56 static int hf_lin_err_checksum
;
57 static int hf_lin_err_invalidid
;
58 static int hf_lin_err_overflow
;
59 static int hf_lin_event_id
;
62 static int ett_lin_pid
;
63 static int ett_errors
;
65 static int * const error_fields
[] = {
67 &hf_lin_err_invalidid
,
71 &hf_lin_err_no_slave_response
,
75 static dissector_table_t subdissector_table
;
77 #define LIN_MSG_TYPE_FRAME 0
78 #define LIN_MSG_TYPE_EVENT 3
80 static const value_string lin_msg_type_names
[] = {
81 { LIN_MSG_TYPE_FRAME
, "Frame" },
82 { LIN_MSG_TYPE_EVENT
, "Event" },
86 #define LIN_CHKSUM_TYPE_UNKN_ERR 0
87 #define LIN_CHKSUM_TYPE_CLASSIC 1
88 #define LIN_CHKSUM_TYPE_ENHANCED 2
89 #define LIN_CHKSUM_TYPE_UNDEF 3
91 static const value_string lin_checksum_type_names
[] = {
92 { LIN_CHKSUM_TYPE_UNKN_ERR
, "Unknown/Error" },
93 { LIN_CHKSUM_TYPE_CLASSIC
, "Classic" },
94 { LIN_CHKSUM_TYPE_ENHANCED
, "Enhanced" },
95 { LIN_CHKSUM_TYPE_UNDEF
, "Undefined" },
99 #define LIN_EVENT_TYPE_GO_TO_SLEEP_EVENT_BY_GO_TO_SLEEP 0xB0B00001
100 #define LIN_EVENT_TYPE_GO_TO_SLEEP_EVENT_BY_INACTIVITY 0xB0B00002
101 #define LIN_EVENT_TYPE_WAKE_UP_BY_WAKE_UP_SIGNAL 0xB0B00004
103 static const value_string lin_event_type_names
[] = {
104 { LIN_EVENT_TYPE_GO_TO_SLEEP_EVENT_BY_GO_TO_SLEEP
, "Go-to-Sleep event by Go-to-Sleep frame" },
105 { LIN_EVENT_TYPE_GO_TO_SLEEP_EVENT_BY_INACTIVITY
, "Go-to-Sleep event by Inactivity for more than 4s" },
106 { LIN_EVENT_TYPE_WAKE_UP_BY_WAKE_UP_SIGNAL
, "Wake-up event by Wake-up signal" },
110 void proto_reg_handoff_lin(void);
111 void proto_register_lin(void);
113 /********* UATs *********/
115 /* Interface Config UAT */
116 typedef struct _interface_config
{
117 unsigned interface_id
;
118 char *interface_name
;
120 } interface_config_t
;
122 #define DATAFILE_LIN_INTERFACE_MAPPING "LIN_interface_mapping"
124 static GHashTable
*data_lin_interfaces_by_id
;
125 static GHashTable
*data_lin_interfaces_by_name
;
126 static interface_config_t
* interface_configs
;
127 static unsigned interface_config_num
;
129 UAT_HEX_CB_DEF(interface_configs
, interface_id
, interface_config_t
)
130 UAT_CSTRING_CB_DEF(interface_configs
, interface_name
, interface_config_t
)
131 UAT_HEX_CB_DEF(interface_configs
, bus_id
, interface_config_t
)
134 copy_interface_config_cb(void *n
, const void *o
, size_t size _U_
) {
135 interface_config_t
*new_rec
= (interface_config_t
*)n
;
136 const interface_config_t
*old_rec
= (const interface_config_t
*)o
;
138 new_rec
->interface_id
= old_rec
->interface_id
;
139 new_rec
->interface_name
= g_strdup(old_rec
->interface_name
);
140 new_rec
->bus_id
= old_rec
->bus_id
;
145 update_interface_config(void *r
, char **err
) {
146 interface_config_t
*rec
= (interface_config_t
*)r
;
148 if (rec
->interface_id
> 0xffffffff) {
149 *err
= ws_strdup_printf("We currently only support 32 bit identifiers (ID: 0x%x Name: %s)",
150 rec
->interface_id
, rec
->interface_name
);
154 if (rec
->bus_id
> 0xffff) {
155 *err
= ws_strdup_printf("We currently only support 16 bit bus identifiers (ID: 0x%x Name: %s Bus-ID: 0x%x)",
156 rec
->interface_id
, rec
->interface_name
, rec
->bus_id
);
164 free_interface_config_cb(void *r
) {
165 interface_config_t
*rec
= (interface_config_t
*)r
;
166 /* freeing result of g_strdup */
167 g_free(rec
->interface_name
);
168 rec
->interface_name
= NULL
;
172 post_update_lin_interfaces_cb(void) {
175 /* destroy old hash tables, if they exist */
176 if (data_lin_interfaces_by_id
) {
177 g_hash_table_destroy(data_lin_interfaces_by_id
);
179 if (data_lin_interfaces_by_name
) {
180 g_hash_table_destroy(data_lin_interfaces_by_name
);
183 /* create new hash table */
184 data_lin_interfaces_by_id
= g_hash_table_new_full(g_direct_hash
, g_direct_equal
, NULL
, NULL
);
185 data_lin_interfaces_by_name
= g_hash_table_new_full(g_str_hash
, g_str_equal
, NULL
, NULL
);
187 for (i
= 0; i
< interface_config_num
; i
++) {
188 if (interface_configs
[i
].interface_id
!= 0xfffffff) {
189 g_hash_table_insert(data_lin_interfaces_by_id
, GUINT_TO_POINTER(interface_configs
[i
].interface_id
), &interface_configs
[i
]);
192 if (interface_configs
[i
].interface_name
!= NULL
&& interface_configs
[i
].interface_name
[0] != 0) {
193 g_hash_table_insert(data_lin_interfaces_by_name
, interface_configs
[i
].interface_name
, &interface_configs
[i
]);
198 /* We match based on the config in the following order:
199 * - interface_name matches and interface_id matches
200 * - interface_name matches and interface_id = 0xffffffff
201 * - interface_name = "" and interface_id matches
205 get_bus_id(packet_info
*pinfo
) {
206 if (!(pinfo
->rec
->presence_flags
& WTAP_HAS_INTERFACE_ID
)) {
210 uint32_t interface_id
= pinfo
->rec
->rec_header
.packet_header
.interface_id
;
211 unsigned section_number
= pinfo
->rec
->presence_flags
& WTAP_HAS_SECTION_NUMBER
? pinfo
->rec
->section_number
: 0;
212 const char *interface_name
= epan_get_interface_name(pinfo
->epan
, interface_id
, section_number
);
213 interface_config_t
*tmp
= NULL
;
215 if (interface_name
!= NULL
&& interface_name
[0] != 0) {
216 tmp
= g_hash_table_lookup(data_lin_interfaces_by_name
, interface_name
);
218 if (tmp
!= NULL
&& (tmp
->interface_id
== 0xffffffff || tmp
->interface_id
== interface_id
)) {
219 /* name + id match or name match and id = any */
223 tmp
= g_hash_table_lookup(data_lin_interfaces_by_id
, GUINT_TO_POINTER(interface_id
));
225 if (tmp
!= NULL
&& (tmp
->interface_name
== NULL
|| tmp
->interface_name
[0] == 0)) {
226 /* id matches and name is any */
231 /* we found nothing */
235 /* Senders and Receivers UAT */
236 typedef struct _sender_receiver_config
{
241 } sender_receiver_config_t
;
243 #define DATAFILE_LIN_SENDER_RECEIVER "LIN_senders_receivers"
245 static GHashTable
*data_sender_receiver
;
246 static sender_receiver_config_t
* sender_receiver_configs
;
247 static unsigned sender_receiver_config_num
;
249 UAT_HEX_CB_DEF(sender_receiver_configs
, bus_id
, sender_receiver_config_t
)
250 UAT_HEX_CB_DEF(sender_receiver_configs
, lin_id
, sender_receiver_config_t
)
251 UAT_CSTRING_CB_DEF(sender_receiver_configs
, sender_name
, sender_receiver_config_t
)
252 UAT_CSTRING_CB_DEF(sender_receiver_configs
, receiver_name
, sender_receiver_config_t
)
255 copy_sender_receiver_config_cb(void *n
, const void *o
, size_t size _U_
) {
256 sender_receiver_config_t
*new_rec
= (sender_receiver_config_t
*)n
;
257 const sender_receiver_config_t
*old_rec
= (const sender_receiver_config_t
*)o
;
259 new_rec
->bus_id
= old_rec
->bus_id
;
260 new_rec
->lin_id
= old_rec
->lin_id
;
261 new_rec
->sender_name
= g_strdup(old_rec
->sender_name
);
262 new_rec
->receiver_name
= g_strdup(old_rec
->receiver_name
);
267 update_sender_receiver_config(void *r
, char **err
) {
268 sender_receiver_config_t
*rec
= (sender_receiver_config_t
*)r
;
270 if (rec
->lin_id
> 0x3f) {
271 *err
= ws_strdup_printf("LIN IDs need to be between 0x00 and 0x3f (Bus ID: %i LIN ID: %i)", rec
->bus_id
, rec
->lin_id
);
275 if (rec
->bus_id
> 0xffff) {
276 *err
= ws_strdup_printf("We currently only support 16 bit bus identifiers (Bus ID: %i LIN ID: %i)", rec
->bus_id
, rec
->lin_id
);
284 free_sender_receiver_config_cb(void *r
) {
285 sender_receiver_config_t
*rec
= (sender_receiver_config_t
*)r
;
286 /* freeing result of g_strdup */
287 g_free(rec
->sender_name
);
288 rec
->sender_name
= NULL
;
289 g_free(rec
->receiver_name
);
290 rec
->receiver_name
= NULL
;
294 sender_receiver_key(uint16_t bus_id
, uint32_t lin_id
) {
295 return ((uint64_t)bus_id
<< 32) | lin_id
;
298 static sender_receiver_config_t
*
299 ht_lookup_sender_receiver_config(uint16_t bus_id
, uint32_t lin_id
) {
300 sender_receiver_config_t
*tmp
;
303 key
= sender_receiver_key(bus_id
, lin_id
);
304 tmp
= g_hash_table_lookup(data_sender_receiver
, &key
);
307 key
= sender_receiver_key(0, lin_id
);
308 tmp
= g_hash_table_lookup(data_sender_receiver
, &key
);
315 post_update_sender_receiver_cb(void) {
319 /* destroy old hash table, if it exist */
320 if (data_sender_receiver
) {
321 g_hash_table_destroy(data_sender_receiver
);
324 /* create new hash table */
325 data_sender_receiver
= g_hash_table_new_full(g_int64_hash
, g_int64_equal
, g_free
, NULL
);
327 for (i
= 0; i
< sender_receiver_config_num
; i
++) {
328 key
= g_new(uint64_t, 1);
329 *key
= sender_receiver_key(sender_receiver_configs
[i
].bus_id
, sender_receiver_configs
[i
].lin_id
);
330 g_hash_table_insert(data_sender_receiver
, key
, &sender_receiver_configs
[i
]);
335 lin_set_source_and_destination_columns(packet_info
* pinfo
, lin_info_t
*lininfo
) {
336 sender_receiver_config_t
*tmp
= ht_lookup_sender_receiver_config(lininfo
->bus_id
, lininfo
->id
);
339 /* remove all addresses to support LIN as payload (e.g., TECMP) */
340 clear_address(&pinfo
->net_src
);
341 clear_address(&pinfo
->dl_src
);
342 clear_address(&pinfo
->src
);
343 clear_address(&pinfo
->net_dst
);
344 clear_address(&pinfo
->dl_dst
);
345 clear_address(&pinfo
->dst
);
347 col_add_str(pinfo
->cinfo
, COL_DEF_SRC
, tmp
->sender_name
);
348 col_add_str(pinfo
->cinfo
, COL_DEF_DST
, tmp
->receiver_name
);
355 dissect_lin(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
) {
358 proto_tree
*lin_tree
;
359 proto_tree
*lin_id_tree
;
362 unsigned payload_length
;
367 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, LIN_NAME
);
368 col_clear(pinfo
->cinfo
, COL_INFO
);
370 ti_root
= proto_tree_add_item(tree
, proto_lin
, tvb
, 0, -1, ENC_NA
);
371 lin_tree
= proto_item_add_subtree(ti_root
, ett_lin
);
373 proto_tree_add_item(lin_tree
, hf_lin_msg_format_rev
, tvb
, 0, 1, ENC_BIG_ENDIAN
);
374 ti
= proto_tree_add_item(lin_tree
, hf_lin_reserved1
, tvb
, 1, 3, ENC_BIG_ENDIAN
);
375 proto_item_set_hidden(ti
);
377 proto_tree_add_item_ret_uint(lin_tree
, hf_lin_payload_length
, tvb
, 4, 1, ENC_BIG_ENDIAN
, &payload_length
);
378 proto_tree_add_item_ret_uint(lin_tree
, hf_lin_message_type
, tvb
, 4, 1, ENC_BIG_ENDIAN
, &msg_type
);
379 if (msg_type
!= LIN_MSG_TYPE_EVENT
) {
380 proto_tree_add_item(lin_tree
, hf_lin_checksum_type
, tvb
, 4, 1, ENC_BIG_ENDIAN
);
382 ti
= proto_tree_add_item(lin_tree
, hf_lin_pid
, tvb
, 5, 1, ENC_BIG_ENDIAN
);
383 lin_id_tree
= proto_item_add_subtree(ti
, ett_lin_pid
);
384 proto_tree_add_item(lin_id_tree
, hf_lin_parity
, tvb
, 5, 1, ENC_BIG_ENDIAN
);
385 proto_tree_add_item_ret_uint(lin_id_tree
, hf_lin_id
, tvb
, 5, 1, ENC_BIG_ENDIAN
, &(lininfo
.id
));
387 proto_tree_add_item(lin_tree
, hf_lin_checksum
, tvb
, 6, 1, ENC_BIG_ENDIAN
);
389 lininfo
.bus_id
= (uint16_t)get_bus_id(pinfo
);
391 lin_set_source_and_destination_columns(pinfo
, &lininfo
);
393 proto_tree_add_bitmask_ret_uint64(lin_tree
, tvb
, 7, hf_lin_err_errors
, ett_errors
, error_fields
, ENC_BIG_ENDIAN
, &errors
);
395 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "LIN %s", val_to_str(msg_type
, lin_msg_type_names
, "(0x%02x)"));
398 col_append_str(pinfo
->cinfo
, COL_INFO
, " - ERR");
399 proto_item_set_end(ti_root
, tvb
, 8);
404 case LIN_MSG_TYPE_EVENT
: {
406 proto_tree_add_item_ret_uint(lin_tree
, hf_lin_event_id
, tvb
, 8, 4, ENC_BIG_ENDIAN
, &event_id
);
407 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ": %s", val_to_str(event_id
, lin_event_type_names
, "0x%08x"));
408 proto_item_set_end(ti_root
, tvb
, 12);
409 return 12; /* 8 Byte header + 4 Byte payload */
413 case LIN_MSG_TYPE_FRAME
:
414 if (payload_length
> 0) {
415 next_tvb
= tvb_new_subset_length(tvb
, 8, payload_length
);
416 proto_item_set_end(ti_root
, tvb
, 8 + payload_length
);
417 lininfo
.len
= (uint16_t)payload_length
;
419 uint32_t bus_frame_id
= lininfo
.id
| (lininfo
.bus_id
<< 16);
420 if (!dissector_try_uint_with_data(subdissector_table
, bus_frame_id
, next_tvb
, pinfo
, tree
, true, &lininfo
)) {
421 if (!dissector_try_uint_with_data(subdissector_table
, lininfo
.id
, next_tvb
, pinfo
, tree
, true, &lininfo
)) {
422 if (!dissector_try_heuristic(heur_subdissector_list
, next_tvb
, pinfo
, tree
, &heur_dtbl_entry
, &lininfo
)) {
423 call_data_dissector(next_tvb
, pinfo
, tree
);
431 /* format pads to 4 bytes*/
432 if (payload_length
<= 4) {
433 proto_item_set_end(ti_root
, tvb
, 12);
435 } else if (payload_length
<= 8) {
436 proto_item_set_end(ti_root
, tvb
, 16);
439 return tvb_captured_length(tvb
);
444 proto_register_lin(void) {
445 module_t
*lin_module
;
446 uat_t
*lin_interface_uat
= NULL
;
447 uat_t
*sender_receiver_uat
= NULL
;
449 static hf_register_info hf
[] = {
450 { &hf_lin_msg_format_rev
,
451 { "Message Format Revision", "lin.message_format",
452 FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
454 { "Reserved", "lin.reserved",
455 FT_UINT24
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
456 { &hf_lin_payload_length
,
457 { "Length", "lin.length",
458 FT_UINT8
, BASE_DEC
, NULL
, 0xf0, NULL
, HFILL
}},
459 { &hf_lin_message_type
,
460 { "Message Type", "lin.message_type",
461 FT_UINT8
, BASE_DEC
, VALS(lin_msg_type_names
), 0x0c, NULL
, HFILL
}},
462 { &hf_lin_checksum_type
,
463 { "Checksum Type", "lin.checksum_type",
464 FT_UINT8
, BASE_DEC
, VALS(lin_checksum_type_names
), 0x03, NULL
, HFILL
}},
466 { "Protected ID", "lin.protected_id",
467 FT_UINT8
, BASE_HEX_DEC
, NULL
, 0x00, NULL
, HFILL
}},
469 { "Frame ID", "lin.frame_id",
470 FT_UINT8
, BASE_HEX_DEC
, NULL
, 0x3f, NULL
, HFILL
}},
472 { "Parity", "lin.frame_parity",
473 FT_UINT8
, BASE_HEX_DEC
, NULL
, 0xc0, NULL
, HFILL
}},
475 { "Checksum", "lin.checksum",
476 FT_UINT8
, BASE_HEX
, NULL
, 0x00, NULL
, HFILL
}},
477 { &hf_lin_err_errors
,
478 { "Errors", "lin.errors",
479 FT_UINT8
, BASE_HEX
, NULL
, 0x00, NULL
, HFILL
}},
480 { &hf_lin_err_no_slave_response
,
481 { "No Slave Response Error", "lin.errors.no_slave_response",
482 FT_BOOLEAN
, 8, NULL
, 0x01, NULL
, HFILL
}},
483 { &hf_lin_err_framing
,
484 { "Framing Error", "lin.errors.framing_error",
485 FT_BOOLEAN
, 8, NULL
, 0x02, NULL
, HFILL
}},
486 { &hf_lin_err_parity
,
487 { "Parity Error", "lin.errors.parity_error",
488 FT_BOOLEAN
, 8, NULL
, 0x04, NULL
, HFILL
}},
489 { &hf_lin_err_checksum
,
490 { "Checksum Error", "lin.errors.checksum_error",
491 FT_BOOLEAN
, 8, NULL
, 0x08, NULL
, HFILL
}},
492 { &hf_lin_err_invalidid
,
493 { "Invalid ID Error", "lin.errors.invalid_id_error",
494 FT_BOOLEAN
, 8, NULL
, 0x10, NULL
, HFILL
}},
495 { &hf_lin_err_overflow
,
496 { "Overflow Error", "lin.errors.overflow_error",
497 FT_BOOLEAN
, 8, NULL
, 0x20, NULL
, HFILL
}},
499 { "Event ID", "lin.event_id",
500 FT_UINT32
, BASE_HEX_DEC
, VALS(lin_event_type_names
), 0x00, NULL
, HFILL
}},
503 static int *ett
[] = {
509 proto_lin
= proto_register_protocol(LIN_NAME_LONG
, LIN_NAME
, LIN_NAME_FILTER
);
510 lin_module
= prefs_register_protocol(proto_lin
, NULL
);
512 proto_register_field_array(proto_lin
, hf
, array_length(hf
));
513 proto_register_subtree_array(ett
, array_length(ett
));
515 lin_handle
= register_dissector(LIN_NAME_FILTER
, dissect_lin
, proto_lin
);
517 /* the lin.frame_id subdissector table carries the bus id in the higher 16 bits */
518 subdissector_table
= register_dissector_table("lin.frame_id", "LIN Frame ID", proto_lin
, FT_UINT8
, BASE_HEX
);
519 heur_subdissector_list
= register_heur_dissector_list_with_description(LIN_NAME_FILTER
, "LIN Message data fallback", proto_lin
);
521 static uat_field_t lin_interface_mapping_uat_fields
[] = {
522 UAT_FLD_HEX(interface_configs
, interface_id
, "Interface ID", "ID of the Interface with 0xffffffff = any (hex uint32 without leading 0x)"),
523 UAT_FLD_CSTRING(interface_configs
, interface_name
, "Interface Name", "Name of the Interface, empty = any (string)"),
524 UAT_FLD_HEX(interface_configs
, bus_id
, "Bus ID", "Bus ID of the Interface (hex uint16 without leading 0x)"),
528 lin_interface_uat
= uat_new("LIN Interface Mapping",
529 sizeof(interface_config_t
), /* record size */
530 DATAFILE_LIN_INTERFACE_MAPPING
, /* filename */
531 true, /* from profile */
532 (void**)&interface_configs
, /* data_ptr */
533 &interface_config_num
, /* numitems_ptr */
534 UAT_AFFECTS_DISSECTION
, /* but not fields */
536 copy_interface_config_cb
, /* copy callback */
537 update_interface_config
, /* update callback */
538 free_interface_config_cb
, /* free callback */
539 post_update_lin_interfaces_cb
, /* post update callback */
540 NULL
, /* reset callback */
541 lin_interface_mapping_uat_fields
/* UAT field definitions */
544 prefs_register_uat_preference(lin_module
, "_lin_interface_mapping", "Interface Mapping",
545 "A table to define the mapping between interface and Bus ID.", lin_interface_uat
);
547 static uat_field_t sender_receiver_mapping_uat_fields
[] = {
548 UAT_FLD_HEX(sender_receiver_configs
, bus_id
, "Bus ID", "Bus ID of the Interface with 0 meaning any (hex uint16 without leading 0x)."),
549 UAT_FLD_HEX(sender_receiver_configs
, lin_id
, "LIN ID", "ID of the LIN Message (hex uint6 without leading 0x)"),
550 UAT_FLD_CSTRING(sender_receiver_configs
, sender_name
, "Sender Name", "Name of Sender(s)"),
551 UAT_FLD_CSTRING(sender_receiver_configs
, receiver_name
, "Receiver Name", "Name of Receiver(s)"),
555 sender_receiver_uat
= uat_new("Sender Receiver Config",
556 sizeof(sender_receiver_config_t
), /* record size */
557 DATAFILE_LIN_SENDER_RECEIVER
, /* filename */
558 true, /* from profile */
559 (void**)&sender_receiver_configs
, /* data_ptr */
560 &sender_receiver_config_num
, /* numitems_ptr */
561 UAT_AFFECTS_DISSECTION
, /* but not fields */
563 copy_sender_receiver_config_cb
, /* copy callback */
564 update_sender_receiver_config
, /* update callback */
565 free_sender_receiver_config_cb
, /* free callback */
566 post_update_sender_receiver_cb
, /* post update callback */
567 NULL
, /* reset callback */
568 sender_receiver_mapping_uat_fields
/* UAT field definitions */
571 prefs_register_uat_preference(lin_module
, "_sender_receiver_config", "Sender Receiver Config",
572 "A table to define the mapping between Bus ID and LIN ID to Sender and Receiver.", sender_receiver_uat
);
576 proto_reg_handoff_lin(void) {
577 dissector_add_uint("wtap_encap", WTAP_ENCAP_LIN
, lin_handle
);
581 * Editor modelines - https://www.wireshark.org/tools/modelines.html
586 * indent-tabs-mode: nil
589 * vi: set shiftwidth=4 tabstop=8 expandtab:
590 * :indentSize=4:tabSize=8:noTabs=true: