Coverage Report

Created: 2026-06-30 07:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-canopen.c
Line
Count
Source
1
/* packet-canopen.c
2
 * Routines for CANopen dissection
3
 * Copyright 2011, Yegor Yefremov <yegorslists@googlemail.com>
4
 *
5
 * Wireshark - Network traffic analyzer
6
 * By Gerald Combs <gerald@wireshark.org>
7
 * Copyright 1998 Gerald Combs
8
 *
9
 * SPDX-License-Identifier: GPL-2.0-or-later
10
 */
11
12
#include "config.h"
13
14
#include <epan/packet.h>
15
16
#include "packet-socketcan.h"
17
18
void proto_register_canopen(void);
19
void proto_reg_handoff_canopen(void);
20
21
static dissector_handle_t canopen_handle;
22
23
/* Initialize the protocol and registered fields */
24
static int proto_canopen;
25
static int hf_canopen_cob_id;
26
static int hf_canopen_function_code;
27
static int hf_canopen_node_id;
28
static int hf_canopen_pdo_data;
29
static int hf_canopen_pdo_data_string;
30
static int hf_canopen_sdo_cmd;
31
static int hf_canopen_sdo_cmd_ccs;
32
static int hf_canopen_sdo_cmd_scs;
33
static int hf_canopen_sdo_cmd_ccs5_subcommand;
34
static int hf_canopen_sdo_cmd_scs5_subcommand;
35
static int hf_canopen_sdo_cmd_ccs6_subcommand;
36
static int hf_canopen_sdo_cmd_scs6_subcommand;
37
static int hf_canopen_sdo_cmd_block_crc_support;
38
static int hf_canopen_sdo_cmd_block_s;
39
static int hf_canopen_sdo_cmd_block_n;
40
static int hf_canopen_sdo_cmd_block_blksize;
41
static int hf_canopen_sdo_cmd_block_pst;
42
static int hf_canopen_sdo_cmd_block_ackseq;
43
static int hf_canopen_sdo_cmd_toggle;
44
static int hf_canopen_sdo_cmd_updown_n;
45
static int hf_canopen_sdo_cmd_updown_c;
46
static int hf_canopen_sdo_cmd_init_n;
47
static int hf_canopen_sdo_cmd_init_e;
48
static int hf_canopen_sdo_cmd_init_s;
49
static int hf_canopen_sdo_main_idx;
50
static int hf_canopen_sdo_sub_idx;
51
static int hf_canopen_sdo_data;
52
static int hf_canopen_sdo_abort_code;
53
static int hf_canopen_reserved;
54
static int hf_canopen_em_err_code;
55
static int hf_canopen_em_err_reg;
56
static int hf_canopen_em_err_reg_ge;
57
static int hf_canopen_em_err_reg_cu;
58
static int hf_canopen_em_err_reg_vo;
59
static int hf_canopen_em_err_reg_te;
60
static int hf_canopen_em_err_reg_co;
61
static int hf_canopen_em_err_reg_de;
62
static int hf_canopen_em_err_reg_re;
63
static int hf_canopen_em_err_reg_ma;
64
static int hf_canopen_em_err_field;
65
static int hf_canopen_nmt_ctrl_cs;
66
static int hf_canopen_nmt_ctrl_node_id;
67
static int hf_canopen_nmt_guard_state;
68
static int hf_canopen_nmt_guard_toggle;
69
static int hf_canopen_sync_counter;
70
static int hf_canopen_lss_cs;
71
static int hf_canopen_lss_addr_vendor;
72
static int hf_canopen_lss_addr_product;
73
static int hf_canopen_lss_addr_revision;
74
static int hf_canopen_lss_addr_revision_low;
75
static int hf_canopen_lss_addr_revision_high;
76
static int hf_canopen_lss_addr_serial;
77
static int hf_canopen_lss_addr_serial_low;
78
static int hf_canopen_lss_addr_serial_high;
79
static int* hf_canopen_lss_addr_ident[] = {
80
        &hf_canopen_lss_addr_vendor,
81
        &hf_canopen_lss_addr_product,
82
        &hf_canopen_lss_addr_revision_low,
83
        &hf_canopen_lss_addr_revision_high,
84
        &hf_canopen_lss_addr_serial_low,
85
        &hf_canopen_lss_addr_serial_high
86
};
87
static int* hf_canopen_lss_addr_inquire[] = {
88
        &hf_canopen_lss_addr_vendor,
89
        &hf_canopen_lss_addr_product,
90
        &hf_canopen_lss_addr_revision,
91
        &hf_canopen_lss_addr_serial
92
};
93
static int hf_canopen_lss_fastscan_id;
94
static int hf_canopen_lss_fastscan_check;
95
static int hf_canopen_lss_fastscan_sub;
96
static int hf_canopen_lss_fastscan_next;
97
static int hf_canopen_lss_switch_mode;
98
static int hf_canopen_lss_nid;
99
static int hf_canopen_lss_conf_id_err_code;
100
static int hf_canopen_lss_conf_bt_err_code;
101
static int hf_canopen_lss_store_conf_err_code;
102
static int hf_canopen_lss_spec_err;
103
static int hf_canopen_lss_bt_tbl_selector;
104
static int hf_canopen_lss_bt_tbl_index;
105
static int hf_canopen_lss_abt_delay;
106
static int hf_canopen_time_stamp;
107
static int hf_canopen_time_stamp_ms;
108
static int hf_canopen_time_stamp_days;
109
110
111
  /* Download segment request (ccs=0) decode mask */
112
static int * const sdo_cmd_fields_ccs0[] = {
113
  &hf_canopen_sdo_cmd_ccs,
114
  &hf_canopen_sdo_cmd_toggle,
115
  &hf_canopen_sdo_cmd_updown_n,
116
  &hf_canopen_sdo_cmd_updown_c,
117
  NULL
118
};
119
/* Initiate download request (ccs=1) decode mask */
120
static int * const sdo_cmd_fields_ccs1[] = {
121
  &hf_canopen_sdo_cmd_ccs,
122
  &hf_canopen_sdo_cmd_init_n,
123
  &hf_canopen_sdo_cmd_init_e,
124
  &hf_canopen_sdo_cmd_init_s,
125
  NULL
126
};
127
/* Initiate upload request (ccs=2) decode mask */
128
static int * const sdo_cmd_fields_ccs2[] = {
129
  &hf_canopen_sdo_cmd_ccs,
130
  NULL
131
};
132
/* Download segment request (ccs=3) decode mask */
133
static int * const sdo_cmd_fields_ccs3[] = {
134
  &hf_canopen_sdo_cmd_ccs,
135
  &hf_canopen_sdo_cmd_toggle,
136
  NULL
137
};
138
/*  */
139
static int * const sdo_cmd_fields_ccs4[] = {
140
  &hf_canopen_sdo_cmd_ccs,
141
  NULL
142
};
143
/* Block upload (ccs=5,cs=0) decode mask */
144
static int * const sdo_cmd_fields_ccs5_subcommand0[] = {
145
  &hf_canopen_sdo_cmd_ccs,
146
  &hf_canopen_sdo_cmd_block_crc_support,
147
  &hf_canopen_sdo_cmd_ccs5_subcommand,
148
  NULL
149
};
150
/* Block upload (ccs=5,cs=1,2,3) decode mask */
151
static int * const sdo_cmd_fields_ccs5_subcommand1[] = {
152
  &hf_canopen_sdo_cmd_ccs,
153
  &hf_canopen_sdo_cmd_ccs5_subcommand,
154
  NULL
155
};
156
157
/* Block download (ccs=6,cs=0) decode mask */
158
static int * const sdo_cmd_fields_ccs6_subcommand0[] = {
159
  &hf_canopen_sdo_cmd_ccs,
160
  &hf_canopen_sdo_cmd_block_crc_support,
161
  &hf_canopen_sdo_cmd_block_s,
162
  &hf_canopen_sdo_cmd_ccs6_subcommand,
163
  NULL
164
};
165
/* Block download (ccs=6,cs=1) decode mask */
166
static int * const sdo_cmd_fields_ccs6_subcommand1[] = {
167
  &hf_canopen_sdo_cmd_ccs,
168
  &hf_canopen_sdo_cmd_block_n,
169
  &hf_canopen_sdo_cmd_ccs6_subcommand,
170
  NULL
171
};
172
173
static int * const *_sdo_cmd_fields_ccs[] = {
174
  sdo_cmd_fields_ccs0,
175
  sdo_cmd_fields_ccs1,
176
  sdo_cmd_fields_ccs2,
177
  sdo_cmd_fields_ccs3,
178
  sdo_cmd_fields_ccs4,
179
};
180
181
static int * const *_sdo_cmd_fields_ccs5[] = {
182
  sdo_cmd_fields_ccs5_subcommand0,
183
  sdo_cmd_fields_ccs5_subcommand1,
184
  sdo_cmd_fields_ccs5_subcommand1,
185
  sdo_cmd_fields_ccs5_subcommand1
186
};
187
188
static int * const *_sdo_cmd_fields_ccs6[] = {
189
  sdo_cmd_fields_ccs6_subcommand0,
190
  sdo_cmd_fields_ccs6_subcommand1
191
};
192
193
/* Emergency error register decode mask */
194
static int * const em_err_reg_fields[] = {
195
  &hf_canopen_em_err_reg_ge,
196
  &hf_canopen_em_err_reg_cu,
197
  &hf_canopen_em_err_reg_vo,
198
  &hf_canopen_em_err_reg_te,
199
  &hf_canopen_em_err_reg_co,
200
  &hf_canopen_em_err_reg_de,
201
  &hf_canopen_em_err_reg_re,
202
  &hf_canopen_em_err_reg_ma,
203
  NULL
204
};
205
206
/* (scs=0) decode mask */
207
static int * const sdo_cmd_fields_scs0[] = {
208
  &hf_canopen_sdo_cmd_scs,
209
  &hf_canopen_sdo_cmd_toggle,
210
  &hf_canopen_sdo_cmd_updown_n,
211
  &hf_canopen_sdo_cmd_updown_c,
212
  NULL
213
};
214
/* (scs=1) decode mask */
215
static int * const sdo_cmd_fields_scs1[] = {
216
  &hf_canopen_sdo_cmd_scs,
217
  &hf_canopen_sdo_cmd_toggle,
218
  NULL
219
};
220
/* (scs=2) decode mask */
221
static int * const sdo_cmd_fields_scs2[] = {
222
  &hf_canopen_sdo_cmd_scs,
223
  &hf_canopen_sdo_cmd_init_n,
224
  &hf_canopen_sdo_cmd_init_e,
225
  &hf_canopen_sdo_cmd_init_s,
226
  NULL
227
};
228
/* (scs=3) decode mask */
229
static int * const sdo_cmd_fields_scs3[] = {
230
  &hf_canopen_sdo_cmd_scs,
231
  NULL
232
};
233
/* (scs=4) decode mask */
234
static int * const sdo_cmd_fields_scs4[] = {
235
  &hf_canopen_sdo_cmd_scs,
236
  NULL
237
};
238
/* (scs=5,ss=0) decode mask */
239
static int * const sdo_cmd_fields_scs5_subcommand0[] = {
240
  &hf_canopen_sdo_cmd_scs,
241
  &hf_canopen_sdo_cmd_block_crc_support,
242
  &hf_canopen_sdo_cmd_scs5_subcommand,
243
  NULL
244
};
245
/* (scs=5,ss=1,2) decode mask */
246
static int * const sdo_cmd_fields_scs5_subcommand1[] = {
247
  &hf_canopen_sdo_cmd_scs,
248
  &hf_canopen_sdo_cmd_scs5_subcommand,
249
  NULL
250
};
251
252
/* (scs=6,ss=0) decode mask */
253
static int * const sdo_cmd_fields_scs6_subcommand0[] = {
254
  &hf_canopen_sdo_cmd_scs,
255
  &hf_canopen_sdo_cmd_block_crc_support,
256
  &hf_canopen_sdo_cmd_block_s,
257
  &hf_canopen_sdo_cmd_scs6_subcommand,
258
  NULL
259
};
260
/* (scs=6,ss=1) decode mask */
261
static int * const sdo_cmd_fields_scs6_subcommand1[] = {
262
  &hf_canopen_sdo_cmd_scs,
263
  &hf_canopen_sdo_cmd_block_n,
264
  &hf_canopen_sdo_cmd_scs6_subcommand,
265
  NULL
266
};
267
268
269
static int * const *_sdo_cmd_fields_scs[] = {
270
  sdo_cmd_fields_scs0,
271
  sdo_cmd_fields_scs1,
272
  sdo_cmd_fields_scs2,
273
  sdo_cmd_fields_scs3,
274
  sdo_cmd_fields_scs4
275
};
276
277
static int * const *_sdo_cmd_fields_scs5[] = {
278
  sdo_cmd_fields_scs5_subcommand0,
279
  sdo_cmd_fields_scs5_subcommand1,
280
  sdo_cmd_fields_scs5_subcommand1,
281
};
282
283
static int * const *_sdo_cmd_fields_scs6[] = {
284
  sdo_cmd_fields_scs6_subcommand0,
285
  sdo_cmd_fields_scs6_subcommand1
286
};
287
288
/* Initialize the subtree pointers */
289
static int ett_canopen;
290
static int ett_canopen_cob;
291
static int ett_canopen_type;
292
static int ett_canopen_sdo_cmd;
293
static int ett_canopen_em_er;
294
295
/* broadcast messages */
296
0
#define FC_NMT                  0x0
297
0
#define FC_SYNC                 0x1
298
0
#define FC_TIME_STAMP           0x2
299
300
/* point-to-point messages */
301
#define FC_EMERGENCY            0x1
302
0
#define FC_PDO1_TX              0x3
303
0
#define FC_PDO1_RX              0x4
304
0
#define FC_PDO2_TX              0x5
305
0
#define FC_PDO2_RX              0x6
306
0
#define FC_PDO3_TX              0x7
307
0
#define FC_PDO3_RX              0x8
308
0
#define FC_PDO4_TX              0x9
309
0
#define FC_PDO4_RX              0xA
310
0
#define FC_DEFAULT_SDO_TX       0xB
311
0
#define FC_DEFAULT_SDO_RX       0xC
312
0
#define FC_NMT_ERR_CONTROL      0xE
313
314
static const value_string CAN_open_bcast_msg_type_vals[] = {
315
    { FC_NMT,              "NMT"},
316
    { FC_SYNC,             "SYNC"},
317
    { FC_TIME_STAMP,       "TIME STAMP"},
318
    { 0, NULL}
319
};
320
321
static const value_string CAN_open_p2p_msg_type_vals[] = {
322
    { FC_EMERGENCY,        "EMCY"},
323
    { FC_PDO1_TX,          "PDO1 (tx)"},
324
    { FC_PDO1_RX,          "PDO1 (rx)"},
325
    { FC_PDO2_TX,          "PDO2 (tx)"},
326
    { FC_PDO2_RX,          "PDO2 (rx)"},
327
    { FC_PDO3_TX,          "PDO3 (tx)"},
328
    { FC_PDO3_RX,          "PDO3 (rx)"},
329
    { FC_PDO4_TX,          "PDO4 (tx)"},
330
    { FC_PDO4_RX,          "PDO4 (rx)"},
331
    { FC_DEFAULT_SDO_TX,   "Default-SDO (tx)"},
332
    { FC_DEFAULT_SDO_RX,   "Default-SDO (rx)"},
333
    { FC_NMT_ERR_CONTROL,  "NMT Error Control"},
334
    { 0, NULL}
335
};
336
337
/* message types */
338
0
#define MT_UNKNOWN                       0
339
0
#define MT_NMT_CTRL                      1
340
0
#define MT_SYNC                          2
341
0
#define MT_TIME_STAMP                    3
342
0
#define MT_EMERGENCY                     4
343
0
#define MT_PDO                           5
344
0
#define MT_SDO                           6
345
0
#define MT_NMT_ERR_CTRL                  7
346
0
#define MT_LSS_MASTER                    10
347
0
#define MT_LSS_SLAVE                     11
348
349
/* TIME STAMP conversion defines */
350
0
#define TS_DAYS_BETWEEN_1970_AND_1984   5113
351
0
#define TS_SECONDS_IN_PER_DAY           86400
352
0
#define TS_NANOSEC_PER_MSEC             1000000
353
354
/* SDO command specifier */
355
0
#define SDO_CCS_DOWN_SEG_REQ    0
356
0
#define SDO_CCS_INIT_DOWN_REQ   1
357
0
#define SDO_CCS_INIT_UP_REQ     2
358
0
#define SDO_CCS_UP_SEQ_REQ      3
359
0
#define SDO_CCS_BLOCK_UP        5
360
0
#define SDO_CCS_BLOCK_DOWN      6
361
362
0
#define SDO_SCS_UP_SEQ_RESP     0
363
0
#define SDO_SCS_DOWN_SEG_RESP   1
364
0
#define SDO_SCS_INIT_UP_RESP    2
365
0
#define SDO_SCS_INIT_DOWN_RESP  3
366
0
#define SDO_SCS_BLOCK_DOWN      5
367
0
#define SDO_SCS_BLOCK_UP        6
368
369
0
#define SDO_CS_ABORT_TRANSFER   4
370
371
static const range_string obj_dict[] = {
372
    { 0x0000, 0x0000, "not used"},
373
    { 0x0001, 0x001F, "Static data types"},
374
    { 0x0020, 0x003F, "Complex data types"},
375
    { 0x0040, 0x005F, "Manufacturer-specific complex data types"},
376
    { 0x0060, 0x025F, "Device profile specific data types"},
377
    { 0x0260, 0x03FF, "reserved"},
378
    { 0x0400, 0x0FFF, "reserved"},
379
    { 0x1000, 0x1000, "Device type"},
380
    { 0x1001, 0x1001, "Error register"},
381
    { 0x1002, 0x1002, "Manufacturer status register"},
382
    { 0x1003, 0x1003, "Pre-defined error field"},
383
    { 0x1004, 0x1004, "Communication profile area"},
384
    { 0x1005, 0x1005, "COB-ID SYNC message"},
385
    { 0x1006, 0x1006, "Communication cycle period"},
386
    { 0x1007, 0x1007, "Synchronous window length"},
387
    { 0x1008, 0x1008, "Manufacturer device name"},
388
    { 0x1009, 0x1009, "Manufacturer hardware version"},
389
    { 0x100A, 0x100A, "Manufacturer software version"},
390
    { 0x100B, 0x100B, "Communication profile area"},
391
    { 0x100C, 0x100C, "Guard time"},
392
    { 0x100D, 0x100D, "Life time factor"},
393
    { 0x100E, 0x100F, "Communication profile area"},
394
    { 0x1010, 0x1010, "Store parameters"},
395
    { 0x1011, 0x1011, "Restore default parameters"},
396
    { 0x1012, 0x1012, "COB-ID time stamp object"},
397
    { 0x1013, 0x1013, "High resolution time stamp"},
398
    { 0x1014, 0x1014, "COB-ID EMCY"},
399
    { 0x1015, 0x1015, "Inhibit time EMCY"},
400
    { 0x1016, 0x1016, "Consumer heartbeat time"},
401
    { 0x1017, 0x1017, "Producer heartbeat time"},
402
    { 0x1018, 0x1018, "Identity object"},
403
    { 0x1019, 0x1019, "Synchronous counter overflow value"},
404
    { 0x101A, 0x101F, "Communication profile area"},
405
    { 0x1020, 0x1020, "Verify configuration"},
406
    { 0x1021, 0x1021, "Store EDS"},
407
    { 0x1022, 0x1022, "Store format"},
408
    { 0x1023, 0x1023, "OS command"},
409
    { 0x1024, 0x1024, "OS command mode"},
410
    { 0x1025, 0x1025, "OS debugger interface"},
411
    { 0x1026, 0x1026, "OS prompt"},
412
    { 0x1027, 0x1027, "Module list"},
413
    { 0x1028, 0x1028, "Emergency consumer object"},
414
    { 0x1029, 0x1029, "Error behavior object"},
415
    { 0x102A, 0x11FF, "Communication profile area"},
416
    { 0x1200, 0x127F, "SDO server parameter"},
417
    { 0x1280, 0x12FF, "SDO client parameter"},
418
    { 0x1300, 0x13FF, "Communication profile area"},
419
    { 0x1400, 0x15FF, "RPDO communication parameter"},
420
    { 0x1600, 0x17FF, "RPDO mapping parameter"},
421
    { 0x1800, 0x19FF, "TPDO communication parameter"},
422
    { 0x1A00, 0x1BFF, "TPDO mapping parameter"},
423
    { 0x1C00, 0x1FBF, "Communication profile area"},
424
    { 0x1FA0, 0x1FCF, "Object scanner list"},
425
    { 0x1FD0, 0x1FFF, "Object dispatching list"},
426
    { 0x2000, 0x5FFF, "Manufacturer-specific profile area"},
427
    { 0x6000, 0x67FF, "Standardized profile area 1st logical device"},
428
    { 0x6800, 0x6FFF, "Standardized profile area 2nd logical device"},
429
    { 0x7000, 0x77FF, "Standardized profile area 3rd logical device"},
430
    { 0x7800, 0x7FFF, "Standardized profile area 4th logical device"},
431
    { 0x8000, 0x87FF, "Standardized profile area 5th logical device"},
432
    { 0x8800, 0x8FFF, "Standardized profile area 6th logical device"},
433
    { 0x9000, 0x97FF, "Standardized profile area 7th logical device"},
434
    { 0x9800, 0x9FFF, "Standardized profile area 8th logical device"},
435
    { 0xA000, 0xAFFF, "Standardized network variable area"},
436
    { 0xB000, 0xBFFF, "Standardized system variable area"},
437
    { 0xC000, 0xFFFF, "reserved"},
438
    { 0,      0,      NULL}
439
};
440
441
/* EMCY error codes */
442
static const range_string em_err_code[] = {
443
    { 0x0000, 0x00FF, "Error reset or no error"},
444
    { 0x1000, 0x10FF, "Generic error"},
445
    { 0x2000, 0x20FF, "Current"},
446
    { 0x2100, 0x21FF, "Current, CANopen device input side"},
447
    { 0x2200, 0x22FF, "Current inside the CANopen device"},
448
    { 0x2300, 0x23FF, "Current, CANopen device output side"},
449
    { 0x3000, 0x30FF, "Voltage"},
450
    { 0x3100, 0x31FF, "Mains voltage"},
451
    { 0x3200, 0x32FF, "Voltage inside the CANopen device"},
452
    { 0x3300, 0x33FF, "Output voltage"},
453
    { 0x4000, 0x40FF, "Temperature"},
454
    { 0x4100, 0x41FF, "Ambient temperature"},
455
    { 0x4200, 0x42FF, "CANopen device temperature"},
456
    { 0x5000, 0x50FF, "CANopen device hardware"},
457
    { 0x6000, 0x60FF, "CANopen device software"},
458
    { 0x6100, 0x61FF, "Internal software"},
459
    { 0x6200, 0x62FF, "User software"},
460
    { 0x6300, 0x63FF, "Data set"},
461
    { 0x7000, 0x70FF, "Additional modules"},
462
    { 0x8000, 0x80FF, "Monitoring"},
463
    { 0x8100, 0x810F, "Communication"},
464
    { 0x8110, 0x8110, "Communication - CAN overrun (objects lost)"},
465
    { 0x8111, 0x811F, "Communication"},
466
    { 0x8120, 0x8120, "Communication - CAN in error passive mode"},
467
    { 0x8121, 0x812F, "Communication"},
468
    { 0x8130, 0x8130, "Communication - Life guard error or heartbeat error"},
469
    { 0x8131, 0x813F, "Communication"},
470
    { 0x8140, 0x8140, "Communication - recovered from bus off"},
471
    { 0x8141, 0x814F, "Communication"},
472
    { 0x8150, 0x8150, "Communication - CAN-ID collision"},
473
    { 0x8151, 0x81FF, "Communication"},
474
    { 0x8200, 0x820F, "Protocol error"},
475
    { 0x8210, 0x8210, "Protocol error - PDO not processed due to length error"},
476
    { 0x8211, 0x821F, "Protocol error"},
477
    { 0x8220, 0x8220, "Protocol error - PDO length exceeded"},
478
    { 0x8221, 0x822F, "Protocol error"},
479
    { 0x8230, 0x8230, "Protocol error - DAM MPDO not processed, destination object not available"},
480
    { 0x8231, 0x823F, "Protocol error"},
481
    { 0x8240, 0x8240, "Protocol error - Unexpected SYNC data length"},
482
    { 0x8241, 0x824F, "Protocol error"},
483
    { 0x8250, 0x8250, "Protocol error - RPDO timeout"},
484
    { 0x8251, 0x82FF, "Protocol error"},
485
    { 0x9000, 0x90FF, "External error"},
486
    { 0xF000, 0xF0FF, "Additional functions"},
487
    { 0xFF00, 0xFFFF, "CANopen device specific"},
488
    { 0,      0,      NULL}
489
};
490
491
/* NMT command specifiers */
492
static const value_string nmt_ctrl_cs[] = {
493
    { 0x01, "Start remote node"},
494
    { 0x02, "Stop remote node"},
495
    { 0x80, "Enter pre-operational state"},
496
    { 0x81, "Reset node"},
497
    { 0x82, "Reset communication"},
498
    { 0, NULL}
499
};
500
501
/* NMT states */
502
static const value_string nmt_guard_state[] = {
503
    { 0x00, "Boot-up"},
504
    { 0x04, "Stopped"},
505
    { 0x05, "Operational"},
506
    { 0x7F, "Pre-operational"},
507
    { 0, NULL}
508
};
509
510
/* SDO Client command specifier */
511
static const value_string sdo_ccs[] = {
512
    { 0x00, "Download segment request"},
513
    { 0x01, "Initiate download request"},
514
    { 0x02, "Initiate upload request"},
515
    { 0x03, "Upload segment request"},
516
    { 0x04, "Abort transfer"},
517
    { 0x05, "Block upload"},
518
    { 0x06, "Block download"},
519
    { 0, NULL}
520
};
521
522
/* SDO Server command specifier */
523
static const value_string sdo_scs[] = {
524
    { 0x00, "Upload segment response"},
525
    { 0x01, "Download segment response"},
526
    { 0x02, "Initiate upload response"},
527
    { 0x03, "Initiate download response"},
528
    { 0x04, "Abort transfer"},
529
    { 0x05, "Block download"},
530
    { 0x06, "Block upload"},
531
    { 0, NULL}
532
};
533
534
/* SDO client subcommand meaning */
535
static const value_string sdo_client_subcommand_meaning[] = {
536
    { 0x00, "Initiate upload/download request"},
537
    { 0x01, "End block upload/download request"},
538
    { 0x02, "Block upload response"},
539
    { 0x03, "Start upload"},
540
    { 0, NULL}
541
};
542
543
/* SDO server subcommand meaning */
544
static const value_string sdo_server_subcommand_meaning[] = {
545
    { 0x00, "Initiate upload/download response"},
546
    { 0x01, "End block upload/download response"},
547
    { 0x02, "Block download response"},
548
    { 0, NULL}
549
};
550
551
static const value_string sdo_abort_code[] = {
552
    { 0x05030000, "Toggle bit not alternated"},
553
    { 0x05040000, "SDO protocol timed out"},
554
    { 0x05040001, "Client/server command specifier not valid or unknown"},
555
    { 0x05040002, "Invalid block size"},
556
    { 0x05040003, "Invalid sequence number"},
557
    { 0x05040004, "CRC error"},
558
    { 0x05040005, "Out of memory"},
559
    { 0x06010000, "Unsupported access to an object"},
560
    { 0x06010001, "Attempt to read a write only object"},
561
    { 0x06010002, "Attempt to write a read only object"},
562
    { 0x06020000, "Object does not exist in the object dictionary"},
563
    { 0x06040041, "Object cannot be mapped to the PDO"},
564
    { 0x06040042, "The number and length of the objects to be mapped would exceed PDO length"},
565
    { 0x06040043, "General parameter incompatibility reason"},
566
    { 0x06040047, "General internal incompatibility in the device"},
567
    { 0x06060000, "Access failed due to an hardware error"},
568
    { 0x06070010, "Data type does not match, length of service parameter does not match"},
569
    { 0x06070012, "Data type does not match, length of service parameter too high"},
570
    { 0x06070013, "Data type does not match, length of service parameter too low"},
571
    { 0x06090011, "Sub-index does not exist"},
572
    { 0x06090030, "Invalid value for parameter"},
573
    { 0x06090031, "Value of parameter written too high"},
574
    { 0x06090032, "Value of parameter written too low"},
575
    { 0x06090036, "Maximum value is less than minimum value"},
576
    { 0x060A0023, "Resource not available: SDO connection"},
577
    { 0x08000000, "General error"},
578
    { 0x08000020, "Data cannot be transferred or stored to the application"},
579
    { 0x08000021, "Data cannot be transferred or stored to the application because of local control"},
580
    { 0x08000022, "Data cannot be transferred or stored to the application because of the present device state"},
581
    { 0x08000023, "Object dictionary dynamic generation fails or no object dictionary is present"},
582
    { 0x08000024, "No data available"},
583
    { 0, NULL}
584
};
585
586
/* LSS COB-IDs */
587
0
#define LSS_MASTER_CAN_ID                  0x7E5
588
0
#define LSS_SLAVE_CAN_ID                   0x7E4
589
590
/* LSS Switch state services */
591
0
#define LSS_CS_SWITCH_GLOBAL               0x04
592
0
#define LSS_CS_SWITCH_SELECTIVE_VENDOR     0x40
593
0
#define LSS_CS_SWITCH_SELECTIVE_PRODUCT    0x41
594
0
#define LSS_CS_SWITCH_SELECTIVE_REVISION   0x42
595
0
#define LSS_CS_SWITCH_SELECTIVE_SERIAL     0x43
596
0
#define LSS_CS_SWITCH_SELECTIVE_RESP       0x44
597
/* LSS Configuration services */
598
0
#define LSS_CS_CONF_NODE_ID                0x11
599
0
#define LSS_CS_CONF_BIT_TIMING             0x13
600
0
#define LSS_CS_CONF_ACT_BIT_TIMING         0x15
601
0
#define LSS_CS_CONF_STORE                  0x17
602
/* LSS Inquire services */
603
0
#define LSS_CS_INQ_VENDOR_ID               0x5A
604
0
#define LSS_CS_INQ_PRODUCT_CODE            0x5B
605
0
#define LSS_CS_INQ_REV_NUMBER              0x5C
606
0
#define LSS_CS_INQ_SERIAL_NUMBER           0x5D
607
0
#define LSS_CS_INQ_NODE_ID                 0x5E
608
/* LSS Identification services */
609
0
#define LSS_CS_IDENT_REMOTE_VENDOR         0x46
610
0
#define LSS_CS_IDENT_REMOTE_PRODUCT        0x47
611
0
#define LSS_CS_IDENT_REMOTE_REV_LOW        0x48
612
0
#define LSS_CS_IDENT_REMOTE_REV_HIGH       0x49
613
0
#define LSS_CS_IDENT_REMOTE_SERIAL_LOW     0x4A
614
0
#define LSS_CS_IDENT_REMOTE_SERIAL_HIGH    0x4B
615
0
#define LSS_CS_IDENT_REMOTE_NON_CONF       0x4C
616
0
#define LSS_CS_IDENT_SLAVE                 0x4F
617
0
#define LSS_CS_IDENT_NON_CONF_SLAVE        0x50
618
0
#define LSS_CS_IDENT_FASTSCAN              0x51
619
620
621
/* LSS command specifier */
622
static const value_string lss_cs_code[] = {
623
    { 0x04, "Switch state global protocol"},
624
    { 0x11, "Configure node-ID protocol"},
625
    { 0x13, "Configure bit timing protocol"},
626
    { 0x15, "Activate bit timing parameters protocol"},
627
    { 0x17, "Store configuration protocol"},
628
    { 0x40, "Switch state selective protocol"},
629
    { 0x41, "Switch state selective protocol"},
630
    { 0x42, "Switch state selective protocol"},
631
    { 0x43, "Switch state selective protocol"},
632
    { 0x44, "Switch state selective protocol"},
633
    { 0x46, "Identify remote slave protocol"},
634
    { 0x47, "Identify remote slave protocol"},
635
    { 0x48, "Identify remote slave protocol"},
636
    { 0x49, "Identify remote slave protocol"},
637
    { 0x4A, "Identify remote slave protocol"},
638
    { 0x4B, "Identify remote slave protocol"},
639
    { 0x4C, "Identify non-configured remote slave protocol"},
640
    { 0x4F, "Identify slave protocol"},
641
    { 0x50, "Identify non-configured slave protocol"},
642
    { 0x51, "LSS Fastscan protocol"},
643
    { 0x5A, "Inquire identity vendor-ID protocol"},
644
    { 0x5B, "Inquire identity product code protocol"},
645
    { 0x5C, "Inquire identity revision number protocol"},
646
    { 0x5D, "Inquire identity serial number protocol"},
647
    { 0x5E, "Inquire node-ID protocol"},
648
    { 0, NULL}
649
};
650
651
static const value_string lss_fastscan_subnext[] = {
652
    { 0x0, "Vendor-ID"},
653
    { 0x1, "Product code"},
654
    { 0x2, "Revision number"},
655
    { 0x3, "Serial number"},
656
    { 0, NULL}
657
};
658
659
static const value_string lss_switch_mode[] = {
660
    { 0x0, "Waiting state"},
661
    { 0x1, "Configuration state"},
662
    { 0, NULL}
663
};
664
665
static const value_string lss_conf_id_err_code[] = {
666
    { 0x00, "Protocol successfully completed"},
667
    { 0x01, "NID out of range"},
668
    { 0xFF, "Implementation specific error"},
669
    { 0, NULL}
670
};
671
672
static const value_string lss_conf_bt_err_code[] = {
673
    { 0x00, "Protocol successfully completed"},
674
    { 0x01, "Bit rate not supported"},
675
    { 0xFF, "Implementation specific error"},
676
    { 0, NULL}
677
};
678
679
static const value_string lss_store_conf_err_code[] = {
680
    { 0x00, "Protocol successfully completed"},
681
    { 0x01, "Store configuration not supported"},
682
    { 0x02, "Storage media access erro"},
683
    { 0xFF, "Implementation specific error"},
684
    { 0, NULL}
685
};
686
687
static const value_string bit_timing_tbl[] = {
688
    { 0x00, "1000 kbit/s"},
689
    { 0x01, "800 kbit/s"},
690
    { 0x02, "500 kbit/s"},
691
    { 0x03, "250 kbit/s"},
692
    { 0x04, "125 kbit/s"},
693
    { 0x05, "Reserved"},
694
    { 0x06, "50 kbit/s"},
695
    { 0x07, "20 kbit/s"},
696
    { 0x08, "10 kbit/s"},
697
    { 0x09, "Auto bit rate detection"},
698
    { 0, NULL}
699
};
700
701
702
static const value_string lss_id_remote_slave[] = {
703
    { 0x46, "Vendor-ID"},
704
    { 0x47, "Product-code"},
705
    { 0x48, "Revision-number (low)"},
706
    { 0x49, "Revision-number (high)"},
707
    { 0x4A, "Serial-number (low)"},
708
    { 0x4B, "Serial-number (high)"},
709
    { 0, NULL}
710
};
711
712
static const value_string lss_inquire_id[] = {
713
    { 0x5A, "Vendor-ID"},
714
    { 0x5B, "Product-code"},
715
    { 0x5C, "Revision-number"},
716
    { 0x5D, "Serial-number"},
717
    { 0x5E, "Node-ID"},
718
    { 0, NULL}
719
};
720
721
static unsigned
722
canopen_detect_msg_type(unsigned function_code, unsigned node_id)
723
0
{
724
0
    switch (function_code) {
725
0
        case FC_NMT:
726
0
            return MT_NMT_CTRL;
727
0
        case FC_SYNC:
728
0
            if (node_id == 0) {
729
0
                return MT_SYNC;
730
0
            } else {
731
0
                return MT_EMERGENCY;
732
0
            }
733
0
            break;
734
0
        case FC_TIME_STAMP:
735
0
            return MT_TIME_STAMP;
736
0
        case FC_PDO1_TX:
737
0
            return MT_PDO;
738
0
        case FC_PDO1_RX:
739
0
            return MT_PDO;
740
0
        case FC_PDO2_TX:
741
0
            return MT_PDO;
742
0
        case FC_PDO2_RX:
743
0
            return MT_PDO;
744
0
        case FC_PDO3_TX:
745
0
            return MT_PDO;
746
0
        case FC_PDO3_RX:
747
0
            return MT_PDO;
748
0
        case FC_PDO4_TX:
749
0
            return MT_PDO;
750
0
        case FC_PDO4_RX:
751
0
            return MT_PDO;
752
0
        case FC_DEFAULT_SDO_TX:
753
0
            return MT_SDO;
754
0
        case FC_DEFAULT_SDO_RX:
755
0
            return MT_SDO;
756
0
        case FC_NMT_ERR_CONTROL:
757
0
            return MT_NMT_ERR_CTRL;
758
0
        case LSS_MASTER_CAN_ID >> 7:
759
0
            if (node_id == (LSS_MASTER_CAN_ID & 0x7F)) {
760
0
                return MT_LSS_MASTER;
761
0
            } else if (node_id == (LSS_SLAVE_CAN_ID & 0x7F)) {
762
0
                return MT_LSS_SLAVE;
763
0
            }
764
0
            return MT_UNKNOWN;
765
0
        default:
766
0
            return MT_UNKNOWN;
767
0
    }
768
0
}
769
770
771
static inline int * const *
772
sdo_cmd_fields_scs(unsigned cs, unsigned subcommand)
773
0
{
774
0
    if (cs < array_length(_sdo_cmd_fields_scs))
775
0
        return _sdo_cmd_fields_scs[cs];
776
0
    else if(cs == SDO_SCS_BLOCK_DOWN && subcommand < array_length(_sdo_cmd_fields_scs5))
777
0
        return _sdo_cmd_fields_scs5[subcommand];
778
0
    else if(cs == SDO_SCS_BLOCK_UP  && subcommand < array_length(_sdo_cmd_fields_scs6))
779
0
        return _sdo_cmd_fields_scs6[subcommand];
780
0
    return NULL;
781
0
}
782
783
static inline int * const *
784
sdo_cmd_fields_ccs(unsigned cs, unsigned subcommand)
785
0
{
786
0
    if (cs < array_length(_sdo_cmd_fields_ccs))
787
0
        return _sdo_cmd_fields_ccs[cs];
788
0
    else if (cs == SDO_CCS_BLOCK_UP && subcommand < array_length(_sdo_cmd_fields_ccs5))
789
0
        return _sdo_cmd_fields_ccs5[subcommand];
790
0
    else if (cs == SDO_CCS_BLOCK_DOWN && subcommand < array_length(_sdo_cmd_fields_ccs6))
791
0
        return _sdo_cmd_fields_ccs6[subcommand];
792
0
    return NULL;
793
0
}
794
795
static void
796
dissect_sdo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *canopen_type_tree, unsigned function_code)
797
0
{
798
0
    unsigned offset = 0;
799
    /*number of data bytes*/
800
0
    uint8_t sdo_data = 0;
801
    /*Field existence*/
802
0
    uint8_t sdo_mux = 0, sdo_pst = 0;
803
    /*sdo values used to choose dissector*/
804
0
    uint8_t sdo_cs = 0, sdo_subcommand = 0;
805
0
    int * const *sdo_cmd_fields;
806
807
    /* get SDO command specifier */
808
0
    sdo_cs = tvb_get_bits8(tvb, 0, 3);
809
810
0
    if (function_code == FC_DEFAULT_SDO_RX) {
811
0
        col_append_fstr(pinfo->cinfo, COL_INFO,
812
0
                ": %s", val_to_str(pinfo->pool, sdo_cs, sdo_ccs,
813
0
                    "Unknown (0x%x)"));
814
815
0
        switch (sdo_cs) {
816
0
            case SDO_CCS_DOWN_SEG_REQ:
817
0
                sdo_mux = 0;
818
0
                sdo_data = 7;
819
0
                break;
820
0
            case SDO_CCS_INIT_DOWN_REQ:
821
0
                sdo_mux = 1;
822
0
                sdo_data = 4;
823
0
                break;
824
0
            case SDO_CCS_INIT_UP_REQ:
825
0
                sdo_mux = 1;
826
0
                sdo_data = 0;
827
0
                break;
828
0
            case SDO_CCS_UP_SEQ_REQ:
829
0
                sdo_mux = 0;
830
0
                sdo_data = 0;
831
0
                break;
832
0
            case SDO_CS_ABORT_TRANSFER:
833
0
                sdo_mux = 1;
834
0
                sdo_data = 4;
835
0
                break;
836
0
            case SDO_CCS_BLOCK_UP:
837
0
                sdo_subcommand = tvb_get_bits8(tvb, 6, 2);
838
0
                if(sdo_subcommand == 0)
839
0
                {
840
0
                  sdo_mux = 1;
841
                  /*only the client sends pst*/
842
0
                  sdo_pst = 1;
843
0
                }
844
                /*check unused field is empty, otherwise it could be a data block segment
845
                 (TODO: add segment decoding)*/
846
0
                if(tvb_get_bits8(tvb, 3, 3) != 0)
847
0
                  return;
848
0
                break;
849
0
            case SDO_CCS_BLOCK_DOWN:
850
0
                sdo_subcommand = tvb_get_bits8(tvb, 7, 1);
851
0
                if(sdo_subcommand == 0)
852
0
                {
853
0
                  sdo_mux = 1;
854
0
                  sdo_data = 4;
855
                  /*check unused field is empty, otherwise it could be a data block segment
856
                   (TODO: add segment decoding)*/
857
0
                  if(tvb_get_bits8(tvb, 3, 3) != 0)
858
0
                    return;
859
0
                }
860
0
                else
861
0
                {
862
0
                  sdo_data = 2;
863
                  /*check unused field is empty, otherwise it could be a data block segment
864
                   (TODO: add segment decoding)*/
865
0
                  if(tvb_get_bits8(tvb, 6, 1) != 0)
866
0
                    return;
867
0
                }
868
0
                break;
869
0
            default:
870
0
                return;
871
0
        }
872
873
0
        sdo_cmd_fields = sdo_cmd_fields_ccs(sdo_cs,sdo_subcommand);
874
875
0
    } else {
876
0
        col_append_fstr(pinfo->cinfo, COL_INFO,
877
0
                ": %s", val_to_str(pinfo->pool, sdo_cs, sdo_scs,
878
0
                    "Unknown (0x%x)"));
879
880
0
        switch (sdo_cs) {
881
0
            case SDO_SCS_UP_SEQ_RESP:
882
0
                sdo_mux = 0;
883
0
                sdo_data = 7;
884
0
                break;
885
0
            case SDO_SCS_DOWN_SEG_RESP:
886
0
                sdo_mux = 0;
887
0
                sdo_data = 0;
888
0
                break;
889
0
            case SDO_SCS_INIT_UP_RESP:
890
0
                sdo_mux = 1;
891
0
                sdo_data = 4;
892
0
                break;
893
0
            case SDO_SCS_INIT_DOWN_RESP:
894
0
                sdo_mux = 1;
895
0
                sdo_data = 0;
896
0
                break;
897
0
            case SDO_CS_ABORT_TRANSFER:
898
0
                sdo_mux = 1;
899
0
                sdo_data = 4;
900
0
                break;
901
0
            case SDO_SCS_BLOCK_DOWN:
902
0
                sdo_subcommand = tvb_get_bits8(tvb, 6, 2);
903
0
                if(sdo_subcommand == 0)
904
0
                {
905
0
                  sdo_mux = 1;
906
0
                }
907
                 /*check unused field is empty, otherwise it could be a data block segment
908
                  (TODO: add segment decoding)*/
909
0
                if(tvb_get_bits8(tvb, 3, 3) != 0)
910
0
                  return;
911
0
                break;
912
0
            case SDO_SCS_BLOCK_UP:
913
0
                sdo_subcommand = tvb_get_bits8(tvb, 7, 1);
914
0
                if(sdo_subcommand == 0)
915
0
                {
916
0
                  sdo_mux = 1;
917
0
                  sdo_data = 4;
918
                  /*check unused field is empty, otherwise it could be a data block segment
919
                   (TODO: add segment decoding)*/
920
0
                  if(tvb_get_bits8(tvb, 3, 3) != 0)
921
0
                    return;
922
0
                }
923
0
                else
924
0
                {
925
0
                  sdo_data = 2;
926
                  /*check unused field is empty, otherwise it could be a data block segment
927
                   (TODO: add segment decoding)*/
928
0
                  if(tvb_get_bits8(tvb, 6, 1) != 0)
929
0
                    return;
930
0
                }
931
0
                break;
932
0
            default:
933
0
                return;
934
0
        }
935
936
0
        sdo_cmd_fields = sdo_cmd_fields_scs(sdo_cs,sdo_subcommand);
937
0
    }
938
939
0
    if (sdo_cmd_fields == NULL) {
940
0
        proto_tree_add_item(canopen_type_tree, hf_canopen_sdo_cmd, tvb, 0, 1, ENC_LITTLE_ENDIAN);
941
        /* XXX Add expert info */
942
0
        return;
943
0
    }
944
945
0
    proto_tree_add_bitmask(canopen_type_tree, tvb, offset,
946
0
            hf_canopen_sdo_cmd, ett_canopen_sdo_cmd, sdo_cmd_fields, ENC_LITTLE_ENDIAN);
947
948
0
    offset++;
949
950
0
    if (sdo_mux) {
951
        /* decode mux */
952
0
        proto_tree_add_item(canopen_type_tree,
953
0
                hf_canopen_sdo_main_idx, tvb, offset, 2, ENC_LITTLE_ENDIAN);
954
0
        offset += 2;
955
956
0
        proto_tree_add_item(canopen_type_tree,
957
0
                hf_canopen_sdo_sub_idx, tvb, offset, 1, ENC_LITTLE_ENDIAN);
958
0
        offset++;
959
0
    }
960
961
0
    if (sdo_cs == SDO_CS_ABORT_TRANSFER) {
962
        /* SDO abort transfer */
963
0
        proto_tree_add_item(canopen_type_tree,
964
0
                hf_canopen_sdo_abort_code, tvb, offset, 4, ENC_LITTLE_ENDIAN);
965
0
        return;
966
0
    }
967
968
0
    if (sdo_cs == 5) {
969
        /*SDO_SCS_BLOCK_DOWN or SDO_CCS_BLOCK_UP*/
970
0
        if(sdo_subcommand == 2)
971
0
        {
972
          /*decode ackseq byte)*/
973
0
          proto_tree_add_item(canopen_type_tree,
974
0
                  hf_canopen_sdo_cmd_block_ackseq, tvb, offset, 1, ENC_LITTLE_ENDIAN);
975
0
          offset++;
976
0
        }
977
978
0
        if(sdo_subcommand == 0 || sdo_subcommand == 2)
979
0
        {
980
          /*decode blksize byte)*/
981
0
          proto_tree_add_item(canopen_type_tree,
982
0
                  hf_canopen_sdo_cmd_block_blksize, tvb, offset, 1, ENC_LITTLE_ENDIAN);
983
0
          offset++;
984
0
        }
985
0
    }
986
987
0
    if (sdo_pst) {
988
        /*decode pst byte)*/
989
0
        proto_tree_add_item(canopen_type_tree,
990
0
                hf_canopen_sdo_cmd_block_pst, tvb, offset, 1, ENC_LITTLE_ENDIAN);
991
0
        offset++;
992
0
    }
993
994
0
    if (sdo_data) {
995
0
        proto_tree_add_item(canopen_type_tree,
996
0
                hf_canopen_sdo_data, tvb, offset, sdo_data, ENC_NA);
997
0
        offset += sdo_data;
998
0
    }
999
1000
0
    if(offset < 8)
1001
0
    {
1002
      /* Reserved */
1003
0
      proto_tree_add_item(canopen_type_tree,
1004
0
          hf_canopen_reserved, tvb, offset, 8 - offset, ENC_NA);
1005
0
    }
1006
0
}
1007
1008
static void
1009
dissect_lss(tvbuff_t *tvb, packet_info *pinfo, proto_tree *canopen_type_tree, unsigned msg_type_id)
1010
0
{
1011
0
    unsigned offset = 0;
1012
0
    int reserved = 0;
1013
0
    uint8_t lss_cs;
1014
0
    uint8_t lss_bc_mask;
1015
0
    uint16_t lss_abt_delay;
1016
1017
    /* LSS command specifier */
1018
0
    proto_tree_add_item_ret_uint8(canopen_type_tree,
1019
0
            hf_canopen_lss_cs, tvb, offset, 1, ENC_LITTLE_ENDIAN, &lss_cs);
1020
0
    col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", val_to_str(pinfo->pool, lss_cs, lss_cs_code, "Unknown (0x%x)"));
1021
0
    offset++;
1022
1023
0
    if (msg_type_id == MT_LSS_MASTER) {
1024
1025
        /* Master commands */
1026
0
        switch (lss_cs) {
1027
0
            case LSS_CS_SWITCH_GLOBAL:
1028
0
                col_append_fstr(pinfo->cinfo, COL_INFO,
1029
0
                        ": %s", val_to_str(pinfo->pool, tvb_get_uint8(tvb, offset), lss_switch_mode, "Unknown (0x%x)"));
1030
1031
0
                proto_tree_add_item(canopen_type_tree,
1032
0
                        hf_canopen_lss_switch_mode, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1033
0
                offset++;
1034
0
                reserved = 6;
1035
0
                break;
1036
0
            case LSS_CS_SWITCH_SELECTIVE_VENDOR:
1037
0
                proto_tree_add_item(canopen_type_tree,
1038
0
                        hf_canopen_lss_addr_vendor, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1039
0
                offset += 4;
1040
0
                reserved = 3;
1041
0
                break;
1042
0
            case LSS_CS_SWITCH_SELECTIVE_PRODUCT:
1043
0
                proto_tree_add_item(canopen_type_tree,
1044
0
                        hf_canopen_lss_addr_product, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1045
0
                offset += 4;
1046
0
                reserved = 3;
1047
0
                break;
1048
0
            case LSS_CS_SWITCH_SELECTIVE_REVISION:
1049
0
                proto_tree_add_item(canopen_type_tree,
1050
0
                        hf_canopen_lss_addr_revision, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1051
0
                offset += 4;
1052
0
                reserved = 3;
1053
0
                break;
1054
0
            case LSS_CS_SWITCH_SELECTIVE_SERIAL:
1055
0
                proto_tree_add_item(canopen_type_tree,
1056
0
                        hf_canopen_lss_addr_serial, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1057
0
                offset += 4;
1058
0
                reserved = 3;
1059
0
                break;
1060
0
            case LSS_CS_CONF_NODE_ID:
1061
0
                col_append_fstr(pinfo->cinfo, COL_INFO, ": 0x%02x", tvb_get_uint8(tvb, offset));
1062
1063
0
                proto_tree_add_item(canopen_type_tree,
1064
0
                        hf_canopen_lss_nid, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1065
0
                offset++;
1066
0
                reserved = 6;
1067
0
                break;
1068
0
            case LSS_CS_CONF_BIT_TIMING:
1069
0
                proto_tree_add_item(canopen_type_tree,
1070
0
                        hf_canopen_lss_bt_tbl_selector, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1071
0
                offset++;
1072
1073
                /* XXX Note that current dissector only works for table selector 0x00 (CiA 301 Table 1) */
1074
0
                col_append_fstr(pinfo->cinfo, COL_INFO,
1075
0
                        ": %s", val_to_str(pinfo->pool, tvb_get_uint8(tvb, offset), bit_timing_tbl, "Unknown (0x%x)"));
1076
0
                proto_tree_add_item(canopen_type_tree,
1077
0
                        hf_canopen_lss_bt_tbl_index, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1078
0
                offset++;
1079
0
                reserved = 5;
1080
0
                break;
1081
0
            case LSS_CS_CONF_ACT_BIT_TIMING:
1082
0
                lss_abt_delay = tvb_get_letohl(tvb, offset);
1083
1084
0
                col_append_fstr(pinfo->cinfo, COL_INFO, ": %d ms", lss_abt_delay);
1085
1086
0
                proto_tree_add_uint_format_value(canopen_type_tree,
1087
0
                        hf_canopen_lss_abt_delay, tvb, offset, 2, lss_abt_delay,
1088
0
                        "%d ms (0x%02x)", lss_abt_delay, lss_abt_delay);
1089
1090
1091
0
                offset += 2;
1092
0
                reserved = 5;
1093
0
                break;
1094
0
            case LSS_CS_CONF_STORE:
1095
0
            case LSS_CS_INQ_VENDOR_ID:
1096
0
            case LSS_CS_INQ_PRODUCT_CODE:
1097
0
            case LSS_CS_INQ_REV_NUMBER:
1098
0
            case LSS_CS_INQ_SERIAL_NUMBER:
1099
0
            case LSS_CS_INQ_NODE_ID:
1100
0
                reserved = 7;
1101
0
                break;
1102
0
            case LSS_CS_IDENT_REMOTE_VENDOR:
1103
0
            case LSS_CS_IDENT_REMOTE_PRODUCT:
1104
0
            case LSS_CS_IDENT_REMOTE_REV_LOW:
1105
0
            case LSS_CS_IDENT_REMOTE_REV_HIGH:
1106
0
            case LSS_CS_IDENT_REMOTE_SERIAL_LOW:
1107
0
            case LSS_CS_IDENT_REMOTE_SERIAL_HIGH:
1108
0
                col_append_fstr(pinfo->cinfo, COL_INFO, ", %s 0x%08x",
1109
0
                        val_to_str_const(lss_cs, lss_id_remote_slave, "(Unknown)"), tvb_get_letohl(tvb, offset));
1110
1111
0
                proto_tree_add_item(canopen_type_tree,
1112
0
                        *hf_canopen_lss_addr_ident[lss_cs - LSS_CS_IDENT_REMOTE_VENDOR], tvb, offset, 4, ENC_LITTLE_ENDIAN);
1113
0
                offset += 4;
1114
0
                reserved = 3;
1115
0
                break;
1116
0
            case LSS_CS_IDENT_REMOTE_NON_CONF:
1117
0
                reserved = 7;
1118
0
                break;
1119
0
            case LSS_CS_IDENT_FASTSCAN:
1120
0
                proto_tree_add_item(canopen_type_tree,
1121
0
                        hf_canopen_lss_fastscan_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1122
0
                offset += 4;
1123
0
                lss_bc_mask = tvb_get_uint8(tvb, offset);
1124
0
                if (lss_bc_mask == 0x80) {
1125
0
                    proto_tree_add_uint_format_value(canopen_type_tree,
1126
0
                            hf_canopen_lss_fastscan_check, tvb, offset, 1, lss_bc_mask,
1127
0
                            "All LSS slaves (0x%02x)", lss_bc_mask);
1128
0
                } else if (lss_bc_mask < 32) {
1129
0
                    proto_tree_add_uint_format_value(canopen_type_tree,
1130
0
                            hf_canopen_lss_fastscan_check, tvb, offset, 1,
1131
0
                            lss_bc_mask, "0x%x (0x%02x)",
1132
0
                            ~((1 << lss_bc_mask) - 1),
1133
0
                            lss_bc_mask);
1134
0
                } else {
1135
0
                    proto_tree_add_uint_format_value(canopen_type_tree,
1136
0
                            hf_canopen_lss_fastscan_check, tvb, offset, 1, lss_bc_mask,
1137
0
                            "Reserved (0x%02x)", lss_bc_mask);
1138
0
                }
1139
0
                offset++;
1140
0
                proto_tree_add_item(canopen_type_tree,
1141
0
                        hf_canopen_lss_fastscan_sub, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1142
0
                offset++;
1143
0
                proto_tree_add_item(canopen_type_tree,
1144
0
                        hf_canopen_lss_fastscan_next, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1145
0
                break;
1146
0
            default: /* invalid command specifier */
1147
0
                return;
1148
0
        }
1149
1150
0
    } else {
1151
1152
        /* Slave commands */
1153
0
        switch (lss_cs) {
1154
0
            case LSS_CS_SWITCH_SELECTIVE_RESP:
1155
0
                reserved = 7;
1156
0
                break;
1157
0
            case LSS_CS_CONF_NODE_ID:
1158
0
                proto_tree_add_item(canopen_type_tree,
1159
0
                        hf_canopen_lss_conf_id_err_code, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1160
0
                offset++;
1161
0
                proto_tree_add_item(canopen_type_tree,
1162
0
                        hf_canopen_lss_spec_err, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1163
0
                offset++;
1164
0
                reserved = 5;
1165
0
                break;
1166
0
            case LSS_CS_CONF_BIT_TIMING:
1167
0
                proto_tree_add_item(canopen_type_tree,
1168
0
                        hf_canopen_lss_conf_bt_err_code, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1169
1170
0
                offset++;
1171
0
                proto_tree_add_item(canopen_type_tree,
1172
0
                        hf_canopen_lss_spec_err, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1173
1174
0
                offset++;
1175
0
                reserved = 5;
1176
0
                break;
1177
0
            case LSS_CS_CONF_STORE:
1178
0
                proto_tree_add_item(canopen_type_tree,
1179
0
                        hf_canopen_lss_store_conf_err_code, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1180
0
                offset++;
1181
0
                proto_tree_add_item(canopen_type_tree,
1182
0
                        hf_canopen_lss_spec_err, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1183
0
                offset++;
1184
0
                reserved = 5;
1185
0
                break;
1186
0
            case LSS_CS_INQ_VENDOR_ID:
1187
0
            case LSS_CS_INQ_PRODUCT_CODE:
1188
0
            case LSS_CS_INQ_REV_NUMBER:
1189
0
            case LSS_CS_INQ_SERIAL_NUMBER:
1190
0
                col_append_fstr(pinfo->cinfo, COL_INFO,
1191
0
                        ", %s 0x%08x", val_to_str_const(lss_cs, lss_inquire_id, "(Unknown)"), tvb_get_letohl(tvb, offset));
1192
1193
0
                proto_tree_add_item(canopen_type_tree,
1194
0
                        *hf_canopen_lss_addr_inquire[lss_cs - LSS_CS_INQ_VENDOR_ID], tvb, offset, 4, ENC_LITTLE_ENDIAN);
1195
0
                offset += 4;
1196
0
                reserved = 3;
1197
0
                break;
1198
0
            case LSS_CS_INQ_NODE_ID:
1199
0
                col_append_fstr(pinfo->cinfo, COL_INFO,
1200
0
                        ", %s 0x%08x", val_to_str_const(lss_cs, lss_inquire_id, "(Unknown)"), tvb_get_letohl(tvb, offset));
1201
1202
0
                proto_tree_add_item(canopen_type_tree,
1203
0
                        hf_canopen_lss_nid, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1204
0
                offset++;
1205
0
                reserved = 6;
1206
0
                break;
1207
0
            case LSS_CS_IDENT_SLAVE:
1208
0
                reserved = 7;
1209
0
                break;
1210
0
            case LSS_CS_IDENT_NON_CONF_SLAVE:
1211
0
                reserved = 7;
1212
0
                break;
1213
0
            default: /* invalid command specifier */
1214
0
                return;
1215
0
        }
1216
1217
0
    }
1218
1219
0
    if (reserved) {
1220
0
        proto_tree_add_item(canopen_type_tree,
1221
0
                hf_canopen_reserved, tvb, offset, reserved, ENC_NA);
1222
0
    }
1223
1224
0
}
1225
1226
/* Code to actually dissect the packets */
1227
static int
1228
dissect_canopen(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
1229
0
{
1230
0
    unsigned     function_code;
1231
0
    unsigned     node_id;
1232
0
    uint32_t     time_stamp_msec;
1233
0
    uint32_t     time_stamp_days;
1234
0
    struct can_info can_info;
1235
0
    unsigned     msg_type_id;
1236
0
    nstime_t     time_stamp;
1237
0
    int          can_data_len = tvb_reported_length(tvb);
1238
0
    const char *function_code_str;
1239
0
    unsigned offset = 0;
1240
0
    uint8_t nmt_node_id;
1241
1242
0
    proto_item *ti, *cob_ti;
1243
0
    proto_tree *canopen_tree;
1244
0
    proto_tree *canopen_cob_tree;
1245
0
    proto_tree *canopen_type_tree;
1246
1247
0
    DISSECTOR_ASSERT(data);
1248
0
    can_info = *((struct can_info*)data);
1249
1250
0
    if (can_info.id & (CAN_ERR_FLAG | CAN_RTR_FLAG | CAN_EFF_FLAG))
1251
0
    {
1252
        /* Error, RTR and frames with extended ids are not for us. */
1253
0
        return 0;
1254
0
    }
1255
1256
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "CANopen");
1257
0
    col_clear(pinfo->cinfo, COL_INFO);
1258
1259
0
    node_id       = can_info.id & 0x7F;
1260
0
    function_code = (can_info.id >> 7) & 0x0F;
1261
1262
0
    msg_type_id = canopen_detect_msg_type(function_code, node_id);
1263
1264
0
    if (msg_type_id == MT_LSS_MASTER) {
1265
0
        function_code_str = "LSS (Master)";
1266
0
        col_add_str(pinfo->cinfo, COL_INFO, function_code_str);
1267
0
    } else if (msg_type_id == MT_LSS_SLAVE) {
1268
0
        function_code_str = "LSS (Slave)";
1269
0
        col_add_str(pinfo->cinfo, COL_INFO, function_code_str);
1270
0
    } else {
1271
1272
0
        if (node_id == 0 ) {
1273
            /* broadcast */
1274
0
            function_code_str = val_to_str(pinfo->pool, function_code, CAN_open_bcast_msg_type_vals, "Unknown (%u)");
1275
0
            col_add_str(pinfo->cinfo, COL_INFO, function_code_str);
1276
0
        } else {
1277
            /* point-to-point */
1278
0
            function_code_str = val_to_str(pinfo->pool, function_code, CAN_open_p2p_msg_type_vals, "Unknown (%u)");
1279
0
            col_add_str(pinfo->cinfo, COL_INFO, function_code_str);
1280
0
        }
1281
0
    }
1282
1283
0
    ti = proto_tree_add_item(tree, proto_canopen, tvb, 0, tvb_reported_length(tvb), ENC_NA);
1284
0
    canopen_tree = proto_item_add_subtree(ti, ett_canopen);
1285
1286
    /* add COB-ID with function code and node id */
1287
0
    cob_ti = proto_tree_add_uint(canopen_tree, hf_canopen_cob_id, tvb, 0, 0, can_info.id);
1288
0
    canopen_cob_tree = proto_item_add_subtree(cob_ti, ett_canopen_cob);
1289
1290
    /* add function code */
1291
0
    ti = proto_tree_add_uint(canopen_cob_tree, hf_canopen_function_code, tvb, 0, 0, can_info.id);
1292
0
    proto_item_set_generated(ti);
1293
1294
    /* add node id */
1295
0
    ti = proto_tree_add_uint(canopen_cob_tree, hf_canopen_node_id, tvb, 0, 0, can_info.id);
1296
0
    proto_item_set_generated(ti);
1297
1298
    /* add CANopen frame type */
1299
1300
0
    canopen_type_tree = proto_tree_add_subtree_format(canopen_tree, tvb, 0,
1301
0
                                  tvb_reported_length(tvb),
1302
0
                                  ett_canopen_type, NULL, "Type: %s", function_code_str);
1303
0
    switch(msg_type_id)
1304
0
    {
1305
0
    case MT_NMT_CTRL:
1306
0
        col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", val_to_str(pinfo->pool, tvb_get_uint8(tvb, offset), nmt_ctrl_cs, "Unknown (0x%x)"));
1307
1308
0
        proto_tree_add_item(canopen_type_tree,
1309
0
            hf_canopen_nmt_ctrl_cs, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1310
0
        offset++;
1311
1312
0
        nmt_node_id = tvb_get_uint8(tvb, offset);
1313
0
        if (nmt_node_id == 0x00) {
1314
0
            col_append_str(pinfo->cinfo, COL_INFO, " [All]");
1315
0
        } else {
1316
0
            col_append_fstr(pinfo->cinfo, COL_INFO, " [0x%x]", nmt_node_id);
1317
0
        }
1318
1319
0
        proto_tree_add_item(canopen_type_tree,
1320
0
            hf_canopen_nmt_ctrl_node_id, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1321
0
        break;
1322
0
    case MT_NMT_ERR_CTRL:
1323
0
        if (tvb_reported_length(tvb) > 0) {
1324
0
            col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", val_to_str_const(tvb_get_bits8(tvb, 1, 7), nmt_guard_state, "(Unknown)"));
1325
1326
0
            proto_tree_add_item(canopen_type_tree,
1327
0
                hf_canopen_nmt_guard_toggle, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1328
0
            proto_tree_add_item(canopen_type_tree,
1329
0
                hf_canopen_nmt_guard_state, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1330
0
        }
1331
1332
0
        col_append_fstr(pinfo->cinfo, COL_INFO, " [0x%x]", node_id);
1333
0
        break;
1334
0
    case MT_SYNC:
1335
        /* Show optional counter parameter if present */
1336
0
        if (tvb_reported_length(tvb) > 0) {
1337
0
            col_append_fstr(pinfo->cinfo, COL_INFO, " [%d]", tvb_get_uint8(tvb, offset));
1338
1339
0
            proto_tree_add_item(canopen_type_tree,
1340
0
                hf_canopen_sync_counter, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1341
0
        }
1342
0
        break;
1343
0
    case MT_TIME_STAMP:
1344
        /* calculate the real time stamp */
1345
0
        time_stamp_msec = tvb_get_letohl(tvb, offset);
1346
0
        time_stamp_days = tvb_get_letohs(tvb, offset + 4);
1347
0
        time_stamp.secs = (time_stamp_days + TS_DAYS_BETWEEN_1970_AND_1984)
1348
0
            * TS_SECONDS_IN_PER_DAY + (time_stamp_msec / 1000);
1349
0
        time_stamp.nsecs = (time_stamp_msec % 1000) * TS_NANOSEC_PER_MSEC;
1350
1351
0
        proto_tree_add_time(canopen_type_tree,
1352
0
            hf_canopen_time_stamp, tvb, offset, 6, &time_stamp);
1353
1354
0
        proto_tree_add_uint(canopen_type_tree,
1355
0
            hf_canopen_time_stamp_ms, tvb, offset, 4, time_stamp_msec);
1356
0
        offset += 4;
1357
1358
0
        proto_tree_add_uint(canopen_type_tree,
1359
0
            hf_canopen_time_stamp_days, tvb, offset, 2, time_stamp_days);
1360
1361
0
        break;
1362
0
    case MT_EMERGENCY:
1363
0
        proto_tree_add_item(canopen_type_tree,
1364
0
            hf_canopen_em_err_code, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1365
0
        offset += 2;
1366
1367
0
        proto_tree_add_bitmask(canopen_type_tree, tvb, offset,
1368
0
                hf_canopen_em_err_reg, ett_canopen_em_er, em_err_reg_fields, ENC_LITTLE_ENDIAN);
1369
0
        offset++;
1370
1371
0
        proto_tree_add_item(canopen_type_tree,
1372
0
            hf_canopen_em_err_field, tvb, offset, 5, ENC_NA);
1373
0
        break;
1374
0
    case MT_PDO:
1375
0
        if (can_data_len != 0) {
1376
0
            proto_tree_add_item(canopen_type_tree,
1377
0
                hf_canopen_pdo_data, tvb, offset, can_data_len, ENC_NA);
1378
0
        }
1379
0
        else {
1380
0
            proto_tree_add_string(canopen_type_tree,
1381
0
                hf_canopen_pdo_data_string, tvb, offset, 0, "empty");
1382
0
        }
1383
0
        break;
1384
0
    case MT_SDO:
1385
1386
0
        dissect_sdo(tvb, pinfo, canopen_type_tree, function_code);
1387
1388
0
        break;
1389
0
    case MT_LSS_MASTER:
1390
0
    case MT_LSS_SLAVE:
1391
1392
0
        dissect_lss(tvb, pinfo, canopen_type_tree, msg_type_id);
1393
1394
0
        break;
1395
0
    }
1396
1397
0
    return tvb_reported_length(tvb);
1398
0
}
1399
1400
1401
/* Register the protocol with Wireshark */
1402
void
1403
proto_register_canopen(void)
1404
14
{
1405
14
    static hf_register_info hf[] = {
1406
        /* COB-ID */
1407
14
        { &hf_canopen_cob_id,
1408
14
          { "COB-ID",           "canopen.cob_id",
1409
14
            FT_UINT32, BASE_HEX, NULL, 0x0,
1410
14
            NULL, HFILL }
1411
14
        },
1412
14
        { &hf_canopen_function_code,
1413
14
          { "Function code", "canopen.function_code",
1414
14
            FT_UINT32, BASE_HEX, NULL, 0x00000780,
1415
14
            NULL, HFILL }
1416
14
        },
1417
14
        { &hf_canopen_node_id,
1418
14
          { "Node-ID", "canopen.node_id",
1419
14
            FT_UINT32, BASE_HEX, NULL, 0x7F,
1420
14
            NULL, HFILL }
1421
14
        },
1422
14
        { &hf_canopen_pdo_data,
1423
14
          { "Data", "canopen.pdo.data.bytes",
1424
14
            FT_BYTES, BASE_NONE, NULL, 0x0,
1425
14
            NULL, HFILL }
1426
14
        },
1427
14
        { &hf_canopen_pdo_data_string,
1428
14
          { "Data", "canopen.pdo.data.string",
1429
14
            FT_STRINGZ, BASE_NONE, NULL, 0x0,
1430
14
            NULL, HFILL }
1431
14
        },
1432
        /* SDO */
1433
14
        { &hf_canopen_sdo_cmd,
1434
14
          { "SDO command byte", "canopen.sdo.cmd",
1435
14
            FT_UINT8, BASE_HEX, NULL, 0x0,
1436
14
            NULL, HFILL }
1437
14
        },
1438
14
        { &hf_canopen_sdo_cmd_ccs,
1439
14
          { "Client command specifier", "canopen.sdo.ccs",
1440
14
            FT_UINT8, BASE_DEC, VALS(sdo_ccs), 0xE0,
1441
14
            NULL, HFILL }
1442
14
        },
1443
14
        { &hf_canopen_sdo_cmd_scs,
1444
14
          { "Server command specifier", "canopen.sdo.scs",
1445
14
            FT_UINT8, BASE_DEC, VALS(sdo_scs), 0xE0,
1446
14
            NULL, HFILL }
1447
14
        },
1448
14
        { &hf_canopen_sdo_cmd_ccs5_subcommand,
1449
14
          { "Client subcommand", "canopen.sdo.cs",
1450
14
            FT_UINT8, BASE_DEC, VALS(sdo_client_subcommand_meaning), 0x03,
1451
14
            NULL, HFILL }
1452
14
        },
1453
14
        { &hf_canopen_sdo_cmd_scs5_subcommand,
1454
14
          { "Server command specifier", "canopen.sdo.ss",
1455
14
            FT_UINT8, BASE_DEC, VALS(sdo_server_subcommand_meaning), 0x03,
1456
14
            NULL, HFILL }
1457
14
        },
1458
14
        { &hf_canopen_sdo_cmd_ccs6_subcommand,
1459
14
          { "Client subcommand", "canopen.sdo.cs",
1460
14
            FT_UINT8, BASE_DEC, VALS(sdo_client_subcommand_meaning), 0x01,
1461
14
            NULL, HFILL }
1462
14
        },
1463
14
        { &hf_canopen_sdo_cmd_scs6_subcommand,
1464
14
          { "Server command specifier", "canopen.sdo.ss",
1465
14
            FT_UINT8, BASE_DEC, VALS(sdo_server_subcommand_meaning), 0x01,
1466
14
            NULL, HFILL }
1467
14
        },
1468
14
        { &hf_canopen_sdo_cmd_block_crc_support,
1469
14
          { "CRC support", "canopen.sdo.crc_support",
1470
14
            FT_BOOLEAN, 8, NULL, 0x04,
1471
14
            "toggle", HFILL }
1472
14
        },
1473
14
        { &hf_canopen_sdo_cmd_block_s,
1474
14
          { "Data set size indicated", "canopen.sdo.s",
1475
14
            FT_BOOLEAN, 8, NULL, 0x02,
1476
14
            "toggle", HFILL }
1477
14
        },
1478
14
        { &hf_canopen_sdo_cmd_block_n,
1479
14
          { "Non-data byte", "canopen.sdo.n",
1480
14
            FT_UINT8, BASE_DEC, NULL, 0x1C,
1481
14
            "toggle", HFILL }
1482
14
        },
1483
14
        { &hf_canopen_sdo_cmd_block_ackseq,
1484
14
          { "Number of segments acknowledged", "canopen.sdo.ackseq",
1485
14
            FT_UINT8, BASE_DEC, NULL, 0x0,
1486
14
            NULL, HFILL }
1487
14
        },
1488
14
        { &hf_canopen_sdo_cmd_block_blksize,
1489
14
          { "Number of segments per block", "canopen.sdo.blksize",
1490
14
            FT_UINT8, BASE_DEC, NULL, 0x0,
1491
14
            NULL, HFILL }
1492
14
        },
1493
14
        { &hf_canopen_sdo_cmd_block_pst,
1494
14
          { "Protocol switch threshold (bytes)", "canopen.sdo.pst",
1495
14
            FT_UINT8, BASE_DEC, NULL, 0x0,
1496
14
            NULL, HFILL }
1497
14
        },
1498
14
        { &hf_canopen_sdo_cmd_toggle,
1499
14
          { "Toggle bit", "canopen.sdo.toggle",
1500
14
            FT_UINT8, BASE_DEC, NULL, 0x10,
1501
14
            NULL, HFILL }},
1502
14
        { &hf_canopen_sdo_cmd_updown_n,
1503
14
          { "Non-data bytes", "canopen.sdo.n",
1504
14
            FT_UINT8, BASE_DEC, NULL, 0x0E,
1505
14
            "toggle", HFILL }},
1506
14
        { &hf_canopen_sdo_cmd_updown_c,
1507
14
          { "No more segments", "canopen.sdo.c",
1508
14
            FT_BOOLEAN, 8, NULL, 0x01,
1509
14
            "toggle", HFILL }},
1510
14
        { &hf_canopen_sdo_cmd_init_n,
1511
14
          { "Non-data bytes", "canopen.sdo.n",
1512
14
            FT_UINT8, BASE_DEC, NULL, 0x0C,
1513
14
            "toggle", HFILL }},
1514
14
        { &hf_canopen_sdo_cmd_init_e,
1515
14
          { "Expedited transfer", "canopen.sdo.e",
1516
14
            FT_BOOLEAN, 8, NULL, 0x02,
1517
14
            "toggle", HFILL }},
1518
14
        { &hf_canopen_sdo_cmd_init_s,
1519
14
          { "Data set size indicated", "canopen.sdo.s",
1520
14
            FT_BOOLEAN, 8, NULL, 0x01,
1521
14
            "toggle", HFILL }},
1522
14
        { &hf_canopen_sdo_main_idx,
1523
14
          { "OD main-index", "canopen.sdo.main_idx",
1524
14
            FT_UINT16, BASE_HEX|BASE_RANGE_STRING, RVALS(obj_dict), 0x0,
1525
14
            NULL, HFILL }
1526
14
        },
1527
14
        { &hf_canopen_sdo_sub_idx,
1528
14
          { "OD sub-index", "canopen.sdo.sub_idx",
1529
14
            FT_UINT8, BASE_HEX, NULL, 0x0,
1530
14
            NULL, HFILL }
1531
14
        },
1532
14
        { &hf_canopen_sdo_data,
1533
14
          { "Data", "canopen.sdo.data.bytes",
1534
14
            FT_BYTES, BASE_NONE, NULL, 0x0,
1535
14
            NULL, HFILL }
1536
14
        },
1537
14
        { &hf_canopen_sdo_abort_code,
1538
14
          { "Abort code", "canopen.sdo.abort_code",
1539
14
            FT_UINT32, BASE_HEX, VALS(sdo_abort_code), 0x0,
1540
14
            NULL, HFILL }
1541
14
        },
1542
14
        { &hf_canopen_reserved,
1543
14
          { "Reserved", "canopen.reserved",
1544
14
            FT_BYTES, BASE_NONE, NULL, 0x00,
1545
14
            NULL, HFILL }
1546
14
        },
1547
14
        { &hf_canopen_em_err_code,
1548
14
          { "Error code", "canopen.em.err_code",
1549
14
            FT_UINT16, BASE_HEX|BASE_RANGE_STRING, RVALS(em_err_code), 0x0,
1550
14
            NULL, HFILL }
1551
14
        },
1552
14
        { &hf_canopen_em_err_reg,
1553
14
          { "Error register", "canopen.em.err_reg",
1554
14
            FT_UINT8, BASE_HEX, NULL, 0x0,
1555
14
            NULL, HFILL }
1556
14
        },
1557
14
        { &hf_canopen_em_err_reg_ge,
1558
14
          { "Generic error", "canopen.em.err_reg_ge",
1559
14
            FT_BOOLEAN, 8, NULL, 0x01,
1560
14
            NULL, HFILL }
1561
14
        },
1562
14
        { &hf_canopen_em_err_reg_cu,
1563
14
          { "Current", "canopen.em.err_reg_cu",
1564
14
            FT_BOOLEAN, 8, NULL, 0x02,
1565
14
            NULL, HFILL }
1566
14
        },
1567
14
        { &hf_canopen_em_err_reg_vo,
1568
14
          { "Voltage", "canopen.em.err_reg_vo",
1569
14
            FT_BOOLEAN, 8, NULL, 0x04,
1570
14
            NULL, HFILL }
1571
14
        },
1572
14
        { &hf_canopen_em_err_reg_te,
1573
14
          { "Temperature", "canopen.em.err_reg_te",
1574
14
            FT_BOOLEAN, 8, NULL, 0x08,
1575
14
            NULL, HFILL }
1576
14
        },
1577
14
        { &hf_canopen_em_err_reg_co,
1578
14
          { "Communication error (overrun, error state)", "canopen.em.err_reg_co",
1579
14
            FT_BOOLEAN, 8, NULL, 0x10,
1580
14
            NULL, HFILL }
1581
14
        },
1582
14
        { &hf_canopen_em_err_reg_de,
1583
14
          { "Device profile specific", "canopen.em.err_reg_de",
1584
14
            FT_BOOLEAN, 8, NULL, 0x20,
1585
14
            NULL, HFILL }
1586
14
        },
1587
14
        { &hf_canopen_em_err_reg_re,
1588
14
          { "Reserved (must be false)", "canopen.em.err_reg_re",
1589
14
            FT_BOOLEAN, 8, NULL, 0x40,
1590
14
            NULL, HFILL }
1591
14
        },
1592
14
        { &hf_canopen_em_err_reg_ma,
1593
14
          { "Manufacturer specific", "canopen.em.err_reg_ma",
1594
14
            FT_BOOLEAN, 8, NULL, 0x80,
1595
14
            NULL, HFILL }
1596
14
        },
1597
14
        { &hf_canopen_em_err_field,
1598
14
          { "Manufacturer specific error field", "canopen.em.err_field",
1599
14
            FT_BYTES, BASE_NONE, NULL, 0x0,
1600
14
            NULL, HFILL }
1601
14
        },
1602
14
        { &hf_canopen_nmt_ctrl_cs,
1603
14
          { "Command specifier", "canopen.nmt_ctrl.cd",
1604
14
            FT_UINT8, BASE_HEX, VALS(nmt_ctrl_cs), 0x0,
1605
14
            NULL, HFILL }
1606
14
        },
1607
14
        { &hf_canopen_nmt_ctrl_node_id,
1608
14
          { "Node-ID", "canopen.nmt_ctrl.node_id",
1609
14
            FT_UINT8, BASE_HEX, NULL, 0x0,
1610
14
            NULL, HFILL }
1611
14
        },
1612
14
        { &hf_canopen_nmt_guard_toggle,
1613
14
          { "Reserved/Toggle", "canopen.nmt_guard.toggle",
1614
14
            FT_UINT8, BASE_DEC, NULL, 0x80,
1615
14
            NULL, HFILL }
1616
14
        },
1617
14
        { &hf_canopen_nmt_guard_state,
1618
14
          { "State", "canopen.nmt_guard.state",
1619
14
            FT_UINT8, BASE_HEX, VALS(nmt_guard_state), 0x7F,
1620
14
            NULL, HFILL }
1621
14
        },
1622
        /* SYNC */
1623
14
        { &hf_canopen_sync_counter,
1624
14
          { "Counter", "canopen.sync.counter",
1625
14
            FT_UINT8, BASE_DEC, NULL, 0x0,
1626
14
            NULL, HFILL }
1627
14
        },
1628
        /* LSS */
1629
14
        { &hf_canopen_lss_cs,
1630
14
          { "Command specifier", "canopen.lss.cs",
1631
14
            FT_UINT8, BASE_HEX, VALS(lss_cs_code), 0x0,
1632
14
            NULL, HFILL }
1633
14
        },
1634
14
        { &hf_canopen_lss_addr_vendor,
1635
14
          { "Vendor-ID", "canopen.lss.addr.vendor",
1636
14
            FT_UINT32, BASE_HEX, NULL, 0x0,
1637
14
            NULL, HFILL }
1638
14
        },
1639
14
        { &hf_canopen_lss_addr_product,
1640
14
          { "Product-code", "canopen.lss.addr.product",
1641
14
            FT_UINT32, BASE_HEX, NULL, 0x0,
1642
14
            NULL, HFILL }
1643
14
        },
1644
14
        { &hf_canopen_lss_addr_revision,
1645
14
          { "Revision-number", "canopen.lss.addr.revision",
1646
14
            FT_UINT32, BASE_HEX, NULL, 0x0,
1647
14
            NULL, HFILL }
1648
14
        },
1649
14
        { &hf_canopen_lss_addr_revision_low,
1650
14
          { "Revision-number (low)", "canopen.lss.addr.revision_low",
1651
14
            FT_UINT32, BASE_HEX, NULL, 0x0,
1652
14
            NULL, HFILL }
1653
14
        },
1654
14
        { &hf_canopen_lss_addr_revision_high,
1655
14
          { "Revision-number (high)", "canopen.lss.addr.revision_high",
1656
14
            FT_UINT32, BASE_HEX, NULL, 0x0,
1657
14
            NULL, HFILL }
1658
14
        },
1659
14
        { &hf_canopen_lss_addr_serial,
1660
14
          { "Serial-number", "canopen.lss.addr.serial",
1661
14
            FT_UINT32, BASE_HEX, NULL, 0x0,
1662
14
            NULL, HFILL }
1663
14
        },
1664
14
        { &hf_canopen_lss_addr_serial_low,
1665
14
          { "Serial-number (low)", "canopen.lss.addr.serial_low",
1666
14
            FT_UINT32, BASE_HEX, NULL, 0x0,
1667
14
            NULL, HFILL }
1668
14
        },
1669
14
        { &hf_canopen_lss_addr_serial_high,
1670
14
          { "Serial-number (high)", "canopen.lss.addr.serial_high",
1671
14
            FT_UINT32, BASE_HEX, NULL, 0x0,
1672
14
            NULL, HFILL }
1673
14
        },
1674
14
        { &hf_canopen_lss_fastscan_id,
1675
14
          { "IDNumber", "canopen.lss.fastscan.id",
1676
14
            FT_UINT32, BASE_HEX, NULL, 0x0,
1677
14
            NULL, HFILL }
1678
14
        },
1679
14
        { &hf_canopen_lss_fastscan_check,
1680
14
          { "Bit Check", "canopen.lss.fastscan.check",
1681
14
            FT_UINT8, BASE_HEX, NULL, 0x0,
1682
14
            NULL, HFILL }
1683
14
        },
1684
14
        { &hf_canopen_lss_fastscan_sub,
1685
14
          { "LSS Sub", "canopen.lss.fastscan.sub",
1686
14
            FT_UINT8, BASE_HEX, VALS(lss_fastscan_subnext), 0x0,
1687
14
            NULL, HFILL }
1688
14
        },
1689
14
        { &hf_canopen_lss_fastscan_next,
1690
14
          { "LSS Next", "canopen.lss.fastscan.next",
1691
14
            FT_UINT8, BASE_HEX, VALS(lss_fastscan_subnext), 0x0,
1692
14
            NULL, HFILL }
1693
14
        },
1694
14
        { &hf_canopen_lss_switch_mode,
1695
14
          { "Mode", "canopen.lss.switch.mode",
1696
14
            FT_UINT8, BASE_HEX, VALS(lss_switch_mode), 0x0,
1697
14
            NULL, HFILL }
1698
14
        },
1699
14
        { &hf_canopen_lss_nid,
1700
14
          { "NID", "canopen.lss.nid",
1701
14
            FT_UINT8, BASE_HEX, NULL, 0x0,
1702
14
            NULL, HFILL }
1703
14
        },
1704
14
        { &hf_canopen_lss_conf_id_err_code,
1705
14
          { "Error code", "canopen.lss.conf_id.err_code",
1706
14
            FT_UINT8, BASE_HEX, VALS(lss_conf_id_err_code), 0x0,
1707
14
            NULL, HFILL }
1708
14
        },
1709
14
        { &hf_canopen_lss_conf_bt_err_code,
1710
14
          { "Error code", "canopen.lss.conf_bt.err_code",
1711
14
            FT_UINT8, BASE_HEX, VALS(lss_conf_bt_err_code), 0x0,
1712
14
            NULL, HFILL }
1713
14
        },
1714
14
        { &hf_canopen_lss_store_conf_err_code,
1715
14
          { "Error code", "canopen.lss.store_conf.err_code",
1716
14
            FT_UINT8, BASE_HEX, VALS(lss_store_conf_err_code), 0x0,
1717
14
            NULL, HFILL }
1718
14
        },
1719
14
        { &hf_canopen_lss_spec_err,
1720
14
          { "Spec-error", "canopen.lss.spec_err",
1721
14
            FT_UINT8, BASE_HEX, NULL, 0x0,
1722
14
            NULL, HFILL }
1723
14
        },
1724
14
        { &hf_canopen_lss_bt_tbl_selector,
1725
14
          { "Table selector", "canopen.lss.bt.tbl_selector",
1726
14
            FT_UINT8, BASE_HEX, NULL, 0x0,
1727
14
            NULL, HFILL }
1728
14
        },
1729
14
        { &hf_canopen_lss_bt_tbl_index,
1730
14
          { "Table index", "canopen.lss.bt.tbl_index",
1731
14
            FT_UINT8, BASE_HEX, VALS(bit_timing_tbl), 0x0,
1732
14
            NULL, HFILL }
1733
14
        },
1734
14
        { &hf_canopen_lss_abt_delay,
1735
14
          { "Switch delay", "canopen.lss.abt_delay",
1736
14
            FT_UINT16, BASE_DEC, NULL, 0x0,
1737
14
            NULL, HFILL }
1738
14
        },
1739
1740
1741
14
        { &hf_canopen_time_stamp,
1742
14
          { "Time stamp",           "canopen.time_stamp",
1743
14
            FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC, NULL, 0x0,
1744
14
            NULL, HFILL }
1745
14
        },
1746
14
        { &hf_canopen_time_stamp_ms,
1747
14
          { "Time, after Midnight in Milliseconds", "canopen.time_stamp_ms",
1748
14
            FT_UINT32, BASE_DEC, NULL, 0x0,
1749
14
            NULL, HFILL }
1750
14
        },
1751
14
        { &hf_canopen_time_stamp_days,
1752
14
          { "Current day since 1 Jan 1984", "canopen.time_stamp_days",
1753
14
            FT_UINT16, BASE_DEC, NULL, 0x0,
1754
14
            NULL, HFILL }
1755
14
        },
1756
14
    };
1757
1758
14
    static int *ett[] = {
1759
14
        &ett_canopen,
1760
14
        &ett_canopen_cob,
1761
14
        &ett_canopen_type,
1762
14
        &ett_canopen_sdo_cmd,
1763
14
        &ett_canopen_em_er
1764
14
    };
1765
1766
14
    proto_canopen = proto_register_protocol("CANopen", "CANOPEN", "canopen");
1767
1768
14
    proto_register_field_array(proto_canopen, hf, array_length(hf));
1769
14
    proto_register_subtree_array(ett, array_length(ett));
1770
1771
14
    canopen_handle = register_dissector("canopen",  dissect_canopen, proto_canopen );
1772
14
}
1773
1774
void
1775
proto_reg_handoff_canopen(void)
1776
14
{
1777
14
   dissector_add_for_decode_as("can.subdissector", canopen_handle );
1778
14
}
1779
1780
/*
1781
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1782
 *
1783
 * Local variables:
1784
 * c-basic-offset: 4
1785
 * tab-width: 8
1786
 * indent-tabs-mode: nil
1787
 * End:
1788
 *
1789
 * vi: set shiftwidth=4 tabstop=8 expandtab:
1790
 * :indentSize=4:tabSize=8:noTabs=true:
1791
 */