epan/dissectors/pidl/samr/samr.cnf cnf_dissect_lsa_BinaryString => lsarpc_dissect_str...
[wireshark-sm.git] / epan / dissectors / packet-j1939.c
blobc1a0cd0e5f1a0a8470bc14ba4463212dd51073e4
1 /* packet-j1939.c
2 * Routines for dissection of SAE J1939
4 * Michael Mann
5 * Copyright 2013
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
13 #include "config.h"
15 #include <inttypes.h>
16 #include <epan/packet.h>
17 #include <epan/address_types.h>
18 #include <epan/to_str.h>
20 #include "packet-socketcan.h"
22 void proto_register_j1939(void);
23 void proto_reg_handoff_j1939(void);
25 static dissector_handle_t j1939_handle;
27 static int proto_j1939;
29 static int hf_j1939_can_id;
30 static int hf_j1939_priority;
31 static int hf_j1939_pgn;
32 static int hf_j1939_data_page;
33 static int hf_j1939_extended_data_page;
34 static int hf_j1939_pdu_format;
35 static int hf_j1939_pdu_specific;
36 static int hf_j1939_src_addr;
37 static int hf_j1939_dst_addr;
38 static int hf_j1939_group_extension;
39 static int hf_j1939_data;
41 static int ett_j1939;
42 static int ett_j1939_can;
43 static int ett_j1939_message;
45 static int j1939_address_type = -1;
46 static dissector_table_t subdissector_pgn_table;
48 static const value_string j1939_address_vals[] = {
49 {0,"Engine #1"},
50 {1,"Engine #2"},
51 {2,"Turbocharger"},
52 {3,"Transmission #1"},
53 {4,"Transmission #2"},
54 {5,"Shift Console - Primary"},
55 {6,"Shift Console - Secondary"},
56 {7,"Power TakeOff - (Main or Rear)"},
57 {8,"Axle - Steering"},
58 {9,"Axle - Drive #1"},
59 {10,"Axle - Drive #2"},
60 {11,"Brakes - System Controller"},
61 {12,"Brakes - Steer Axle"},
62 {13,"Brakes - Drive axle #1"},
63 {14,"Brakes - Drive Axle #2"},
64 {15,"Retarder - Engine"},
65 {16,"Retarder - Driveline"},
66 {17,"Cruise Control"},
67 {18,"Fuel System"},
68 {19,"Steering Controller"},
69 {20,"Suspension - Steer Axle"},
70 {21,"Suspension - Drive Axle #1"},
71 {22,"Suspension - Drive Axle #2"},
72 {23,"Instrument Cluster #1"},
73 {24,"Trip Recorder"},
74 {25,"Passenger-Operator Climate Control #1"},
75 {26,"Alternator/Electrical Charging System"},
76 {27,"Aerodynamic Control"},
77 {28,"Vehicle Navigation"},
78 {29,"Vehicle Security"},
79 {30,"Electrical System"},
80 {31,"Starter System"},
81 {32,"Tractor-Trailer Bridge #1"},
82 {33,"Body Controller"},
83 {34,"Auxiliary Valve Control or Engine Air System Valve Control"},
84 {35,"Hitch Control"},
85 {36,"Power TakeOff (Front or Secondary)"},
86 {37,"Off Vehicle Gateway"},
87 {38,"Virtual Terminal (in cab)"},
88 {39,"Management Computer #1"},
89 {40,"Cab Display #1"},
90 {41,"Retarder, Exhaust, Engine #1"},
91 {42,"Headway Controller"},
92 {43,"On-Board Diagnostic Unit"},
93 {44,"Retarder, Exhaust, Engine #2"},
94 {45,"Endurance Braking System"},
95 {46,"Hydraulic Pump Controller"},
96 {47,"Suspension - System Controller #1"},
97 {48,"Pneumatic - System Controller"},
98 {49,"Cab Controller - Primary"},
99 {50,"Cab Controller - Secondary"},
100 {51,"Tire Pressure Controller"},
101 {52,"Ignition Control Module #1"},
102 {53,"Ignition Control Module #2"},
103 {54,"Seat Control #1"},
104 {55,"Lighting - Operator Controls"},
105 {56,"Rear Axle Steering Controller #1"},
106 {57,"Water Pump Controller"},
107 {58,"Passenger-Operator Climate Control #2"},
108 {59,"Transmission Display - Primary"},
109 {60,"Transmission Display - Secondary"},
110 {61,"Exhaust Emission Controller"},
111 {62,"Vehicle Dynamic Stability Controller"},
112 {63,"Oil Sensor"},
113 {64,"Suspension - System Controller #2"},
114 {65,"Information System Controller #1"},
115 {66,"Ramp Control"},
116 {67,"Clutch/Converter Unit"},
117 {68,"Auxiliary Heater #1"},
118 {69,"Auxiliary Heater #2"},
119 {70,"Engine Valve Controller"},
120 {71,"Chassis Controller #1"},
121 {72,"Chassis Controller #2"},
122 {73,"Propulsion Battery Charger"},
123 {74,"Communications Unit, Cellular"},
124 {75,"Communications Unit, Satellite"},
125 {76,"Communications Unit, Radio"},
126 {77,"Steering Column Unit"},
127 {78,"Fan Drive Controller"},
128 {79,"Seat Control #2"},
129 {80,"Parking brake controller"},
130 {81,"Aftertreatment #1 system gas intake"},
131 {82,"Aftertreatment #1 system gas outlet"},
132 {83,"Safety Restraint System"},
133 {84,"Cab Display #2"},
134 {85,"Diesel Particulate Filter Controller"},
135 {86,"Aftertreatment #2 system gas intake"},
136 {87,"Aftertreatment #2 system gas outlet"},
137 {88,"Safety Restraint System #2"},
138 {89,"Atmospheric Sensor"},
139 {248,"File Server / Printer"},
140 {249,"Off Board Diagnostic-Service Tool #1"},
141 {250,"Off Board Diagnostic-Service Tool #2"},
142 {251,"On-Board Data Logger"},
143 {252,"Reserved for Experimental Use"},
144 {253,"Reserved for OEM"},
145 {254,"Null Address"},
146 {255,"GLOBAL"},
147 { 0, NULL }
150 static value_string_ext j1939_address_vals_ext = VALUE_STRING_EXT_INIT(j1939_address_vals);
152 static void
153 j1939_fmt_address(char *result, uint32_t addr )
155 if ((addr < 128) || (addr > 247))
156 snprintf(result, ITEM_LABEL_LENGTH, "%d (%s)", addr, val_to_str_ext_const(addr, &j1939_address_vals_ext, "Reserved"));
157 else
158 snprintf(result, ITEM_LABEL_LENGTH, "%d (Arbitrary)", addr);
161 static int dissect_j1939(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
163 proto_item *ti, *can_id_item;
164 proto_tree *j1939_tree, *can_tree, *msg_tree;
166 int offset = 0;
167 struct can_info can_info;
168 uint32_t data_length = tvb_reported_length(tvb);
169 uint32_t pgn;
170 uint8_t *src_addr, *dest_addr;
172 DISSECTOR_ASSERT(data);
173 can_info = *((struct can_info*)data);
175 if ((can_info.id & CAN_ERR_FLAG) ||
176 !(can_info.id & CAN_EFF_FLAG))
178 /* Error frames and frames with standards ids are not for us */
179 return 0;
182 col_set_str(pinfo->cinfo, COL_PROTOCOL, "J1939");
183 col_clear(pinfo->cinfo, COL_INFO);
185 ti = proto_tree_add_item(tree, proto_j1939, tvb, offset, tvb_reported_length(tvb), ENC_NA);
186 j1939_tree = proto_item_add_subtree(ti, ett_j1939);
188 can_tree = proto_tree_add_subtree_format(j1939_tree, tvb, 0, 0,
189 ett_j1939_can, NULL, "CAN Identifier: 0x%08x", can_info.id);
190 can_id_item = proto_tree_add_uint(can_tree, hf_j1939_can_id, tvb, 0, 0, can_info.id);
191 proto_item_set_generated(can_id_item);
192 ti = proto_tree_add_uint(can_tree, hf_j1939_priority, tvb, 0, 0, can_info.id);
193 proto_item_set_generated(ti);
194 ti = proto_tree_add_uint(can_tree, hf_j1939_extended_data_page, tvb, 0, 0, can_info.id);
195 proto_item_set_generated(ti);
196 ti = proto_tree_add_uint(can_tree, hf_j1939_data_page, tvb, 0, 0, can_info.id);
197 proto_item_set_generated(ti);
198 ti = proto_tree_add_uint(can_tree, hf_j1939_pdu_format, tvb, 0, 0, can_info.id);
199 proto_item_set_generated(ti);
200 ti = proto_tree_add_uint(can_tree, hf_j1939_pdu_specific, tvb, 0, 0, can_info.id);
201 proto_item_set_generated(ti);
202 ti = proto_tree_add_uint(can_tree, hf_j1939_src_addr, tvb, 0, 0, can_info.id);
203 proto_item_set_generated(ti);
205 /* Set source address */
206 src_addr = (uint8_t*)wmem_alloc(pinfo->pool, 1);
207 *src_addr = (uint8_t)(can_info.id & 0xFF);
208 set_address(&pinfo->src, j1939_address_type, 1, (const void*)src_addr);
210 pgn = (can_info.id & 0x3FFFF00) >> 8;
212 /* If PF < 240, PS is destination address, last byte of PGN is cleared */
213 if (((can_info.id & 0xFF0000) >> 16) < 240)
215 pgn &= 0x3FF00;
217 ti = proto_tree_add_uint(can_tree, hf_j1939_dst_addr, tvb, 0, 0, can_info.id);
218 proto_item_set_generated(ti);
220 else
222 ti = proto_tree_add_uint(can_tree, hf_j1939_group_extension, tvb, 0, 0, can_info.id);
223 proto_item_set_generated(ti);
226 /* Fill in "destination" address even if its "broadcast" */
227 dest_addr = (uint8_t*)wmem_alloc(pinfo->pool, 1);
228 *dest_addr = (uint8_t)((can_info.id & 0xFF00) >> 8);
229 set_address(&pinfo->dst, j1939_address_type, 1, (const void*)dest_addr);
231 col_add_fstr(pinfo->cinfo, COL_INFO, "PGN: %-6" PRIu32, pgn);
233 if (can_info.id & CAN_RTR_FLAG)
235 /* RTR frames don't have payload */
236 col_append_fstr(pinfo->cinfo, COL_INFO, " %s", "(Remote Transmission Request)");
238 else
240 /* For now just include raw bytes */
241 col_append_fstr(pinfo->cinfo, COL_INFO, " %s", tvb_bytes_to_str_punct(pinfo->pool, tvb, 0, data_length, ' '));
244 msg_tree = proto_tree_add_subtree(j1939_tree, tvb, 0, tvb_reported_length(tvb), ett_j1939_message, NULL, "Message");
246 ti = proto_tree_add_uint(msg_tree, hf_j1939_pgn, tvb, 0, 0, pgn);
247 proto_item_set_generated(ti);
249 if (!dissector_try_uint_new(subdissector_pgn_table, pgn, tvb, pinfo, msg_tree, true, data))
251 proto_tree_add_item(msg_tree, hf_j1939_data, tvb, 0, tvb_reported_length(tvb), ENC_NA);
254 return tvb_captured_length(tvb);
257 static int J1939_addr_to_str(const address* addr, char *buf, int buf_len)
259 const uint8_t *addrdata = (const uint8_t *)addr->data;
261 uint32_to_str_buf(*addrdata, buf, buf_len);
262 return (int)strlen(buf);
265 static int J1939_addr_str_len(const address* addr _U_)
267 return 11; /* Leaves required space (10 bytes) for uint_to_str_back() */
270 static const char* J1939_col_filter_str(const address* addr _U_, bool is_src)
272 if (is_src)
273 return "j1939.src_addr";
275 return "j1939.dst_addr";
278 static int J1939_addr_len(void)
280 return 1;
283 void proto_register_j1939(void)
285 static hf_register_info hf[] = {
286 { &hf_j1939_can_id,
287 {"CAN Identifier", "j1939.can_id",
288 FT_UINT32, BASE_HEX, NULL, CAN_EFF_MASK, NULL, HFILL }
290 { &hf_j1939_priority,
291 {"Priority", "j1939.priority",
292 FT_UINT32, BASE_DEC, NULL, 0x1C000000, NULL, HFILL }
294 { &hf_j1939_pgn,
295 {"PGN", "j1939.pgn",
296 FT_UINT32, BASE_DEC, NULL, 0x03FFFFFF, NULL, HFILL }
298 { &hf_j1939_extended_data_page,
299 {"Extended Data Page", "j1939.ex_data_page",
300 FT_UINT32, BASE_DEC, NULL, 0x02000000, NULL, HFILL }
302 { &hf_j1939_data_page,
303 {"Data Page", "j1939.data_page",
304 FT_UINT32, BASE_DEC, NULL, 0x01000000, NULL, HFILL }
306 { &hf_j1939_pdu_format,
307 {"PDU Format", "j1939.pdu_format",
308 FT_UINT32, BASE_DEC, NULL, 0x00FF0000, NULL, HFILL }
310 { &hf_j1939_pdu_specific,
311 {"PDU Specific", "j1939.pdu_specific",
312 FT_UINT32, BASE_DEC, NULL, 0x0000FF00, NULL, HFILL }
314 { &hf_j1939_src_addr,
315 {"Source Address", "j1939.src_addr",
316 FT_UINT32, BASE_CUSTOM, CF_FUNC(j1939_fmt_address), 0x000000FF, NULL, HFILL }
318 { &hf_j1939_dst_addr,
319 {"Destination Address", "j1939.dst_addr",
320 FT_UINT32, BASE_CUSTOM, CF_FUNC(j1939_fmt_address), 0x0000FF00, NULL, HFILL }
322 { &hf_j1939_group_extension,
323 {"Group Extension", "j1939.group_extension",
324 FT_UINT32, BASE_DEC, NULL, 0x0000FF00, NULL, HFILL }
326 { &hf_j1939_data,
327 {"Data", "j1939.data",
328 FT_BYTES, BASE_NONE|BASE_ALLOW_ZERO, NULL, 0x0, NULL, HFILL }
332 static int *ett[] = {
333 &ett_j1939,
334 &ett_j1939_can,
335 &ett_j1939_message
338 proto_j1939 = proto_register_protocol("SAE J1939", "J1939", "j1939");
340 proto_register_field_array(proto_j1939, hf, array_length(hf));
341 proto_register_subtree_array(ett, array_length(ett));
343 subdissector_pgn_table = register_dissector_table("j1939.pgn", "PGN Handle", proto_j1939, FT_UINT32, BASE_DEC);
345 j1939_address_type = address_type_dissector_register("AT_J1939", "J1939 Address", J1939_addr_to_str, J1939_addr_str_len, NULL, J1939_col_filter_str, J1939_addr_len, NULL, NULL);
347 j1939_handle = register_dissector("j1939", dissect_j1939, proto_j1939 );
350 void
351 proto_reg_handoff_j1939(void)
353 dissector_add_for_decode_as("can.subdissector", j1939_handle );
357 * Editor modelines - https://www.wireshark.org/tools/modelines.html
359 * Local variables:
360 * c-basic-offset: 4
361 * tab-width: 8
362 * indent-tabs-mode: nil
363 * End:
365 * vi: set shiftwidth=4 tabstop=8 expandtab:
366 * :indentSize=4:tabSize=8:noTabs=true: