Coverage Report

Created: 2026-08-14 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-iec104.c
Line
Count
Source
1
/* packet-iec104.c
2
 * Routines for IEC-60870-5-101 & 104 Protocol disassembly
3
 *
4
 * Copyright (c) 2008 by Joan Ramio <joan@ramio.cat>
5
 * Joan is a masculine catalan name. Search the Internet for Joan Pujol (alias Garbo).
6
 *
7
 * Copyright (c) 2009 by Kjell Hultman <kjell.hultman@gmail.com>
8
 * Added dissection of signal (ASDU) information.
9
 * Kjell is also a masculine name, but a Scandinavian one.
10
 *
11
 * Wireshark - Network traffic analyzer
12
 * By Gerald Combs <gerald@wireshark.org>
13
 * Copyright 1999 Gerald Combs
14
 *
15
 * SPDX-License-Identifier: GPL-2.0-or-later
16
 */
17
18
#include "config.h"
19
20
#include <math.h> /* floor */
21
22
#include <epan/packet.h>
23
#include <epan/prefs.h>
24
#include <epan/expert.h>
25
#include <epan/reassemble.h>
26
#include <epan/tfs.h>
27
#include <wsutil/array.h>
28
#include <wsutil/str_util.h>
29
#include "packet-tcp.h"
30
31
void proto_register_iec60870_104(void);
32
void proto_reg_handoff_iec60870_104(void);
33
34
void proto_register_iec60870_101(void);
35
void proto_reg_handoff_iec60870_101(void);
36
37
void proto_register_iec60870_5_103(void);
38
void proto_reg_handoff_iec60870_5_103(void);
39
40
void proto_register_iec60870_asdu(void);
41
42
static int dissect_iec60870_asdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
43
44
static dissector_handle_t iec60870_asdu_handle;
45
static dissector_handle_t iec60870_104_handle;
46
static dissector_handle_t iec60870_101_handle;
47
static dissector_handle_t iec60870_5_103_handle;
48
49
static reassembly_table iec60870_reassemble_table;
50
51
/* the asdu header structure */
52
struct asduheader {
53
  uint32_t Addr;
54
  uint8_t OA;
55
  uint8_t TypeId;
56
  uint8_t TNCause;
57
  uint32_t IOA;
58
  uint8_t NumIx;
59
  uint8_t SQ;
60
  uint8_t DataLength;
61
};
62
63
struct asdu_parms {
64
  unsigned cot_len;
65
  unsigned asdu_addr_len;
66
  unsigned ioa_len;
67
};
68
69
16
#define IEC104_PORT     2404
70
71
/* Define the iec101/103/104 protos */
72
static int proto_iec60870_101;
73
static int proto_iec60870_5_103;
74
static int proto_iec60870_104;
75
static int proto_iec60870_asdu;
76
77
/* Protocol constants */
78
251k
#define APCI_START  0x68
79
8.86k
#define APCI_LEN  6
80
2.60k
#define APCI_START_LEN  2
81
2.60k
#define APCI_DATA_LEN (APCI_LEN - APCI_START_LEN)
82
3.11k
#define APDU_MIN_LEN  4
83
2.77k
#define APDU_MAX_LEN  253
84
85
/* ASDU_HEAD_LEN: Includes Asdu head and first IOA */
86
#define ASDU_HEAD_LEN 9
87
5.30k
#define F_TEST  0x80
88
5.30k
#define F_NEGA  0x40
89
2.66k
#define F_CAUSE 0x3F
90
5.01k
#define F_SQ    0x80
91
92
/* APCI types */
93
94
/* Type I is only lowest bit set to 0 */
95
8.13k
#define I_TYPE    0
96
62
#define S_TYPE    1
97
91
#define U_TYPE    3
98
#define APCI_TYPE_UNKNOWN 4
99
100
static const value_string apci_types [] = {
101
  { I_TYPE,   "I" },
102
  { S_TYPE,   "S" },
103
  { U_TYPE,   "U" },
104
  { 0, NULL }
105
};
106
107
/* Constants relative to the field, independent of the field position in the byte */
108
/* U (Unnumbered) constants */
109
#define U_STARTDT_ACT     0x01
110
#define U_STARTDT_CON   0x02
111
#define U_STOPDT_ACT    0x04
112
#define U_STOPDT_CON    0x08
113
#define U_TESTFR_ACT    0x10
114
#define U_TESTFR_CON    0x20
115
static const value_string u_types[] = {
116
  { U_STARTDT_ACT,    "STARTDT act" },
117
  { U_STARTDT_CON,    "STARTDT con" },
118
  { U_STOPDT_ACT,     "STOPDT act" },
119
  { U_STOPDT_CON,     "STOPDT con" },
120
  { U_TESTFR_ACT,     "TESTFR act" },
121
  { U_TESTFR_CON,     "TESTFR con" },
122
  { 0, NULL }
123
};
124
125
/* ASDU types (TypeId) */
126
444
#define M_SP_NA_1  1    /* single-point information                 */
127
397
#define M_SP_TA_1  2    /* single-point information with time tag             */
128
472
#define M_DP_NA_1  3    /* double-point information                 */
129
796
#define M_DP_TA_1  4    /* double-point information with time tag             */
130
631
#define M_ST_NA_1  5    /* step position information                */
131
613
#define M_ST_TA_1  6    /* step position information with time tag            */
132
589
#define M_BO_NA_1  7    /* bitstring of 32 bits                 */
133
676
#define M_BO_TA_1  8    /* bitstring of 32 bits with time tag               */
134
882
#define M_ME_NA_1  9    /* measured value, normalized value               */
135
890
#define M_ME_TA_1  10    /* measured value, normalized value with time tag           */
136
836
#define M_ME_NB_1  11    /* measured value, scaled value               */
137
854
#define M_ME_TB_1  12    /* measured value, scaled value with time tag             */
138
903
#define M_ME_NC_1  13    /* measured value, short floating point number          */
139
874
#define M_ME_TC_1  14    /* measured value, short floating point number with time tag        */
140
912
#define M_IT_NA_1  15    /* integrated totals                  */
141
998
#define M_IT_TA_1  16    /* integrated totals with time tag              */
142
1.05k
#define M_EP_TA_1  17    /* event of protection equipment with time tag          */
143
973
#define M_EP_TB_1  18    /* packed start events of protection equipment with time tag        */
144
1.21k
#define M_EP_TC_1  19    /* packed output circuit information of protection equipment with time tag    */
145
1.22k
#define M_PS_NA_1  20    /* packed single-point information with status change detection       */
146
966
#define M_ME_ND_1  21    /* measured value, normalized value without quality descriptor      */
147
704
#define M_SP_TB_1  30    /* single-point information with time tag CP56Time2a          */
148
665
#define M_DP_TB_1  31    /* double-point information with time tag CP56Time2a          */
149
901
#define M_ST_TB_1  32    /* step position information with time tag CP56Time2a           */
150
800
#define M_BO_TB_1  33    /* bitstring of 32 bit with time tag CP56Time2a           */
151
1.05k
#define M_ME_TD_1  34    /* measured value, normalized value with time tag CP56Time2a        */
152
1.10k
#define M_ME_TE_1  35    /* measured value, scaled value with time tag CP56Time2a        */
153
1.13k
#define M_ME_TF_1  36    /* measured value, short floating point number with time tag CP56Time2a     */
154
1.21k
#define M_IT_TB_1  37    /* integrated totals with time tag CP56Time2a             */
155
1.15k
#define M_EP_TD_1  38    /* event of protection equipment with time tag CP56Time2a         */
156
1.11k
#define M_EP_TE_1  39    /* packed start events of protection equipment with time tag CP56Time2a     */
157
1.23k
#define M_EP_TF_1  40    /* packed output circuit information of protection equipment with time tag CP56Time2a   */
158
1.13k
#define S_IT_TC_1  41    /* integrated totals containing time tagged security statistics     */
159
1.29k
#define C_SC_NA_1  45    /* single command                   */
160
1.72k
#define C_DC_NA_1  46    /* double command                   */
161
1.31k
#define C_RC_NA_1  47    /* regulating step command                */
162
1.51k
#define C_SE_NA_1  48    /* set point command, normalized value            */
163
1.63k
#define C_SE_NB_1  49    /* set point command, scaled value              */
164
1.54k
#define C_SE_NC_1  50    /* set point command, short floating point number           */
165
1.46k
#define C_BO_NA_1  51    /* bitstring of 32 bits                 */
166
1.39k
#define C_SC_TA_1  58    /* single command with time tag CP56Time2a            */
167
1.43k
#define C_DC_TA_1  59    /* double command with time tag CP56Time2a            */
168
1.42k
#define C_RC_TA_1  60    /* regulating step command with time tag CP56Time2a           */
169
1.49k
#define C_SE_TA_1  61    /* set point command, normalized value with time tag CP56Time2a       */
170
1.54k
#define C_SE_TB_1  62    /* set point command, scaled value with time tag CP56Time2a         */
171
1.48k
#define C_SE_TC_1  63    /* set point command, short floating-point number with time tag CP56Time2a    */
172
1.62k
#define C_BO_TA_1  64    /* bitstring of 32 bits with time tag CP56Time2a          */
173
1.63k
#define M_EI_NA_1  70    /* end of initialization                */
174
5.30k
#define S_CH_NA_1  81    /* authentication challenge               */
175
175
#define S_RP_NA_1  82    /* authentication reply               */
176
244
#define S_AR_NA_1  83    /* aggressive mode authentication request session key status request      */
177
15
#define S_KR_NA_1  84    /* session key status request               */
178
265
#define S_KS_NA_1  85    /* session key status                 */
179
250
#define S_KC_NA_1  86    /* session key change                 */
180
421
#define S_ER_NA_1  87    /* authentication error               */
181
#define S_US_NA_1  90    /* user status change                  */
182
#define S_UQ_NA_1  91    /* update key change request               */
183
#define S_UR_NA_1  92    /* update key change reply               */
184
#define S_UK_NA_1  93    /* update key change symmetric               */
185
#define S_UA_NA_1  94    /* update key change asymmetric              */
186
968
#define S_UC_NA_1  95    /* update key change confirmation             */
187
1.99k
#define C_IC_NA_1  100    /* interrogation command                */
188
1.98k
#define C_CI_NA_1  101    /* counter interrogation command              */
189
#define C_RD_NA_1  102    /* read command                   */
190
1.69k
#define C_CS_NA_1  103    /* clock synchronization command              */
191
2.26k
#define C_TS_NA_1  104    /* test command                                                                       */
192
1.85k
#define C_RP_NA_1  105    /* reset process command                */
193
2.05k
#define C_CD_NA_1  106    /* delay acquisition command                */
194
1.79k
#define C_TS_TA_1  107    /* test command with time tag CP56Time2a            */
195
1.88k
#define P_ME_NA_1  110    /* parameter of measured value, normalized value          */
196
1.81k
#define P_ME_NB_1  111    /* parameter of measured value, scaled value            */
197
1.83k
#define P_ME_NC_1  112    /* parameter of measured value, short floating-point number         */
198
2.06k
#define P_AC_NA_1  113    /* parameter activation                 */
199
1.81k
#define F_FR_NA_1  120    /* file ready                   */
200
1.87k
#define F_SR_NA_1  121    /* section ready                  */
201
1.87k
#define F_SC_NA_1  122    /* call directory, select file, call file, call section         */
202
1.97k
#define F_LS_NA_1  123    /* last section, last segment               */
203
2.13k
#define F_AF_NA_1  124    /* ack file, ack section                */
204
1.84k
#define F_SG_NA_1  125    /* segment                    */
205
1.87k
#define F_DR_TA_1  126    /* directory                    */
206
1.99k
#define F_SC_NB_1  127    /* Query Log - Request archive file               */
207
static const value_string asdu_types [] = {
208
  {  M_SP_NA_1,   "M_SP_NA_1" },
209
  {  M_SP_TA_1,   "M_SP_TA_1" },
210
  {  M_DP_NA_1,   "M_DP_NA_1" },
211
  {  M_DP_TA_1,   "M_DP_TA_1" },
212
  {  M_ST_NA_1,   "M_ST_NA_1" },
213
  {  M_ST_TA_1,   "M_ST_TA_1" },
214
  {  M_BO_NA_1,   "M_BO_NA_1" },
215
  {  M_BO_TA_1,   "M_BO_TA_1" },
216
  {  M_ME_NA_1,   "M_ME_NA_1" },
217
  {  M_ME_TA_1,   "M_ME_TA_1" },
218
  {  M_ME_NB_1,   "M_ME_NB_1" },
219
  {  M_ME_TB_1,   "M_ME_TB_1" },
220
  {  M_ME_NC_1,   "M_ME_NC_1" },
221
  {  M_ME_TC_1,   "M_ME_TC_1" },
222
  {  M_IT_NA_1,   "M_IT_NA_1" },
223
  {  M_IT_TA_1,   "M_IT_TA_1" },
224
  {  M_EP_TA_1,   "M_EP_TA_1" },
225
  {  M_EP_TB_1,   "M_EP_TB_1" },
226
  {  M_EP_TC_1,   "M_EP_TC_1" },
227
  {  M_PS_NA_1,   "M_PS_NA_1" },
228
  {  M_ME_ND_1,   "M_ME_ND_1" },
229
  {  M_SP_TB_1,   "M_SP_TB_1" },
230
  {  M_DP_TB_1,   "M_DP_TB_1" },
231
  {  M_ST_TB_1,   "M_ST_TB_1" },
232
  {  M_BO_TB_1,   "M_BO_TB_1" },
233
  {  M_ME_TD_1,   "M_ME_TD_1" },
234
  {  M_ME_TE_1,   "M_ME_TE_1" },
235
  {  M_ME_TF_1,   "M_ME_TF_1" },
236
  {  M_IT_TB_1,   "M_IT_TB_1" },
237
  {  M_EP_TD_1,   "M_EP_TD_1" },
238
  {  M_EP_TE_1,   "M_EP_TE_1" },
239
  {  M_EP_TF_1,   "M_EP_TF_1" },
240
  {  S_IT_TC_1,   "S_IT_TC_1" },
241
  {  C_SC_NA_1,   "C_SC_NA_1" },
242
  {  C_DC_NA_1,   "C_DC_NA_1" },
243
  {  C_RC_NA_1,   "C_RC_NA_1" },
244
  {  C_SE_NA_1,   "C_SE_NA_1" },
245
  {  C_SE_NB_1,   "C_SE_NB_1" },
246
  {  C_SE_NC_1,   "C_SE_NC_1" },
247
  {  C_BO_NA_1,   "C_BO_NA_1" },
248
  {  C_SC_TA_1,   "C_SC_TA_1" },
249
  {  C_DC_TA_1,   "C_DC_TA_1" },
250
  {  C_RC_TA_1,   "C_RC_TA_1" },
251
  {  C_SE_TA_1,   "C_SE_TA_1" },
252
  {  C_SE_TB_1,   "C_SE_TB_1" },
253
  {  C_SE_TC_1,   "C_SE_TC_1" },
254
  {  C_BO_TA_1,   "C_BO_TA_1" },
255
  {  M_EI_NA_1,   "M_EI_NA_1" },
256
  {  S_CH_NA_1,   "S_CH_NA_1" },
257
  {  S_RP_NA_1,   "S_RP_NA_1" },
258
  {  S_AR_NA_1,   "S_AR_NA_1" },
259
  {  S_KR_NA_1,   "S_KR_NA_1" },
260
  {  S_KS_NA_1,   "S_KS_NA_1" },
261
  {  S_KC_NA_1,   "S_KC_NA_1" },
262
  {  S_ER_NA_1,   "S_ER_NA_1" },
263
  {  S_US_NA_1,   "S_US_NA_1" },
264
  {  S_UQ_NA_1,   "S_UQ_NA_1" },
265
  {  S_UR_NA_1,   "S_UR_NA_1" },
266
  {  S_UK_NA_1,   "S_UK_NA_1" },
267
  {  S_UA_NA_1,   "S_UA_NA_1" },
268
  {  S_UC_NA_1,   "S_UC_NA_1" },
269
  {  C_IC_NA_1,   "C_IC_NA_1" },
270
  {  C_CI_NA_1,   "C_CI_NA_1" },
271
  {  C_RD_NA_1,   "C_RD_NA_1" },
272
  {  C_CS_NA_1,   "C_CS_NA_1" },
273
  {  C_TS_NA_1,   "C_TS_NA_1" },
274
  {  C_RP_NA_1,   "C_RP_NA_1" },
275
  {  C_CD_NA_1,   "C_CD_NA_1" },
276
  {  C_TS_TA_1,   "C_TS_TA_1" },
277
  {  P_ME_NA_1,   "P_ME_NA_1" },
278
  {  P_ME_NB_1,   "P_ME_NB_1" },
279
  {  P_ME_NC_1,   "P_ME_NC_1" },
280
  {  P_AC_NA_1,   "P_AC_NA_1" },
281
  {  F_FR_NA_1,   "F_FR_NA_1" },
282
  {  F_SR_NA_1,   "F_SR_NA_1" },
283
  {  F_SC_NA_1,   "F_SC_NA_1" },
284
  {  F_LS_NA_1,   "F_LS_NA_1" },
285
  {  F_AF_NA_1,   "F_AF_NA_1" },
286
  {  F_SG_NA_1,   "F_SG_NA_1" },
287
  {  F_DR_TA_1,   "F_DR_TA_1" },
288
  {  F_SC_NB_1,   "F_SC_NB_1" },
289
  { 0, NULL }
290
};
291
292
static const value_string asdu_lngtypes [] = {
293
  {  M_SP_NA_1,   "single-point information" },
294
  {  M_SP_TA_1,   "single-point information with time tag" },
295
  {  M_DP_NA_1,   "double-point information" },
296
  {  M_DP_TA_1,   "double-point information with time tag" },
297
  {  M_ST_NA_1,   "step position information" },
298
  {  M_ST_TA_1,   "step position information with time tag" },
299
  {  M_BO_NA_1,   "bitstring of 32 bits" },
300
  {  M_BO_TA_1,   "bitstring of 32 bits with time tag" },
301
  {  M_ME_NA_1,   "measured value, normalized value" },
302
  {  M_ME_TA_1,   "measured value, normalized value with time tag" },
303
  {  M_ME_NB_1,   "measured value, scaled value" },
304
  {  M_ME_TB_1,   "measured value, scaled value with time tag" },
305
  {  M_ME_NC_1,   "measured value, short floating point number" },
306
  {  M_ME_TC_1,   "measured value, short floating point number with time tag" },
307
  {  M_IT_NA_1,   "integrated totals" },
308
  {  M_IT_TA_1,   "integrated totals with time tag" },
309
  {  M_EP_TA_1,   "event of protection equipment with time tag" },
310
  {  M_EP_TB_1,   "packed start events of protection equipment with time tag" },
311
  {  M_EP_TC_1,   "packed output circuit information of protection equipment with time tag" },
312
  {  M_PS_NA_1,   "packed single-point information with status change detection" },
313
  {  M_ME_ND_1,   "measured value, normalized value without quality descriptor" },
314
  {  M_SP_TB_1,   "single-point information with time tag CP56Time2a" },
315
  {  M_DP_TB_1,   "double-point information with time tag CP56Time2a" },
316
  {  M_ST_TB_1,   "step position information with time tag CP56Time2a" },
317
  {  M_BO_TB_1,   "bitstring of 32 bit with time tag CP56Time2a" },
318
  {  M_ME_TD_1,   "measured value, normalized value with time tag CP56Time2a" },
319
  {  M_ME_TE_1,   "measured value, scaled value with time tag CP56Time2a" },
320
  {  M_ME_TF_1,   "measured value, short floating point number with time tag CP56Time2a" },
321
  {  M_IT_TB_1,   "integrated totals with time tag CP56Time2a" },
322
  {  M_EP_TD_1,   "event of protection equipment with time tag CP56Time2a" },
323
  {  M_EP_TE_1,   "packed start events of protection equipment with time tag CP56Time2a" },
324
  {  M_EP_TF_1,   "packed output circuit information of protection equipment with time tag CP56Time2a" },
325
  {  S_IT_TC_1,   "integrated totals containing time tagged security statistics" },
326
  {  C_SC_NA_1,   "single command" },
327
  {  C_DC_NA_1,   "double command" },
328
  {  C_RC_NA_1,   "regulating step command" },
329
  {  C_SE_NA_1,   "set point command, normalized value" },
330
  {  C_SE_NB_1,   "set point command, scaled value" },
331
  {  C_SE_NC_1,   "set point command, short floating point number" },
332
  {  C_BO_NA_1,   "bitstring of 32 bits" },
333
  {  C_SC_TA_1,   "single command with time tag CP56Time2a" },
334
  {  C_DC_TA_1,   "double command with time tag CP56Time2a" },
335
  {  C_RC_TA_1,   "regulating step command with time tag CP56Time2a" },
336
  {  C_SE_TA_1,   "set point command, normalized value with time tag CP56Time2a" },
337
  {  C_SE_TB_1,   "set point command, scaled value with time tag CP56Time2a" },
338
  {  C_SE_TC_1,   "set point command, short floating-point number with time tag CP56Time2a" },
339
  {  C_BO_TA_1,   "bitstring of 32 bits with time tag CP56Time2a" },
340
  {  M_EI_NA_1,   "end of initialization" },
341
  {  S_CH_NA_1,   "authentication challenge" },
342
  {  S_RP_NA_1,   "authentication reply" },
343
  {  S_AR_NA_1,   "aggressive mode authentication request session key status request" },
344
  {  S_KR_NA_1,   "session key status request" },
345
  {  S_KS_NA_1,   "session key status" },
346
  {  S_KC_NA_1,   "session key change" },
347
  {  S_ER_NA_1,   "authentication error" },
348
  {  S_US_NA_1,   "user status change" },
349
  {  S_UQ_NA_1,   "update key change request" },
350
  {  S_UR_NA_1,   "update key change reply" },
351
  {  S_UK_NA_1,   "update key change symmetric" },
352
  {  S_UA_NA_1,   "update key change asymmetric" },
353
  {  S_UC_NA_1,   "update key change confirmation" },
354
  {  C_IC_NA_1,   "interrogation command" },
355
  {  C_CI_NA_1,   "counter interrogation command" },
356
  {  C_RD_NA_1,   "read command" },
357
  {  C_CS_NA_1,   "clock synchronization command" },
358
  {  C_TS_NA_1,   "test command" },
359
  {  C_RP_NA_1,   "reset process command" },
360
  {  C_CD_NA_1,   "delay acquisition command" },
361
  {  C_TS_TA_1,   "test command with time tag CP56Time2a" },
362
  {  P_ME_NA_1,   "parameter of measured value, normalized value" },
363
  {  P_ME_NB_1,   "parameter of measured value, scaled value" },
364
  {  P_ME_NC_1,   "parameter of measured value, short floating-point number" },
365
  {  P_AC_NA_1,   "parameter activation" },
366
  {  F_FR_NA_1,   "file ready" },
367
  {  F_SR_NA_1,   "section ready" },
368
  {  F_SC_NA_1,   "call directory, select file, call file, call section" },
369
  {  F_LS_NA_1,   "last section, last segment" },
370
  {  F_AF_NA_1,   "ack file, ack section" },
371
  {  F_SG_NA_1,   "segment" },
372
  {  F_DR_TA_1,   "directory" },
373
  {  F_SC_NB_1,   "Query Log - Request archive file" },
374
  { 0, NULL }
375
};
376
377
typedef struct {
378
  uint8_t value;
379
  uint8_t length;
380
} td_asdu_length;
381
382
static const td_asdu_length asdu_length [] = {
383
  {  M_SP_NA_1,  1 },
384
  {  M_SP_TA_1,  4 },
385
  {  M_DP_NA_1,  1 },
386
  {  M_DP_TA_1,  4 },
387
  {  M_ST_NA_1,  2 },
388
  {  M_ST_TA_1,  5 },
389
  {  M_BO_NA_1,  5 },
390
  {  M_BO_TA_1,  8 },
391
  {  M_ME_NA_1,  3 },
392
  {  M_ME_TA_1,  6 },
393
  {  M_ME_NB_1,  3 },
394
  {  M_ME_TB_1,  6 },
395
  {  M_ME_NC_1,  5 },
396
  {  M_ME_TC_1,  8 },
397
  {  M_IT_NA_1,  5 },
398
  {  M_IT_TA_1,  8 },
399
  {  M_EP_TA_1,  6 },
400
  {  M_EP_TB_1,  7 },
401
  {  M_EP_TC_1,  7 },
402
  {  M_PS_NA_1,  5 },
403
  {  M_ME_ND_1,  2 },
404
  {  M_SP_TB_1,  8 },
405
  {  M_DP_TB_1,  8 },
406
  {  M_ST_TB_1,  9 },
407
  {  M_BO_TB_1, 12 },
408
  {  M_ME_TD_1, 10 },
409
  {  M_ME_TE_1, 10 },
410
  {  M_ME_TF_1, 12 },
411
  {  M_IT_TB_1, 12 },
412
  {  M_EP_TD_1, 10 },
413
  {  M_EP_TE_1, 11 },
414
  {  M_EP_TF_1, 11 },
415
  {  S_IT_TC_1,   14 },
416
  {  C_SC_NA_1,  1 },
417
  {  C_DC_NA_1,  1 },
418
  {  C_RC_NA_1,  1 },
419
  {  C_SE_NA_1,  3 },
420
  {  C_SE_NB_1,  3 },
421
  {  C_SE_NC_1,  5 },
422
  {  C_BO_NA_1,  4 },
423
  {  C_SC_TA_1,  8 },
424
  {  C_DC_TA_1,  8 },
425
  {  C_RC_TA_1,  8 },
426
  {  C_SE_TA_1, 10 },
427
  {  C_SE_TB_1, 10 },
428
  {  C_SE_TC_1, 12 },
429
  {  C_BO_TA_1, 11 },
430
  {  M_EI_NA_1,  1 },
431
  {  S_CH_NA_1,    0 },
432
  {  S_RP_NA_1,    0 },
433
  {  S_AR_NA_1,    0 },
434
  {  S_KR_NA_1,    0 },
435
  {  S_KS_NA_1,    0 },
436
  {  S_KC_NA_1,    0 },
437
  {  S_ER_NA_1,    0 },
438
  {  S_US_NA_1,    0 },
439
  {  S_UQ_NA_1,    0 },
440
  {  S_UR_NA_1,    0 },
441
  {  S_UK_NA_1,    0 },
442
  {  S_UA_NA_1,    0 },
443
  {  S_UC_NA_1,    0 },
444
  {  C_IC_NA_1,  1 },
445
  {  C_CI_NA_1,  1 },
446
  {  C_RD_NA_1,  0 },
447
  {  C_CS_NA_1,  7 },
448
  {  C_TS_NA_1,  2 },
449
  {  C_RP_NA_1,  1 },
450
  {  C_CD_NA_1,  2 },
451
  {  C_TS_TA_1,  9 },
452
  {  P_ME_NA_1,  3 },
453
  {  P_ME_NB_1,  3 },
454
  {  P_ME_NC_1,  5 },
455
  {  P_AC_NA_1,  1 },
456
  {  F_FR_NA_1,  6 },
457
  {  F_SR_NA_1,  7 },
458
  {  F_SC_NA_1,  4 },
459
  {  F_LS_NA_1,  5 },
460
  {  F_AF_NA_1,  4 },
461
  {  F_SG_NA_1,  4 },
462
  {  F_DR_TA_1, 13 },
463
  {  F_SC_NB_1, 16 },
464
  { 0, 0 }
465
};
466
467
/* Cause of Transmission (CauseTx) */
468
#define Per_Cyc         1
469
#define Back            2
470
#define Spont           3
471
#define Init            4
472
#define Req             5
473
#define Act             6
474
#define ActCon          7
475
#define Deact           8
476
#define DeactCon        9
477
#define ActTerm         10
478
#define Retrem          11
479
#define Retloc          12
480
#define File            13
481
#define Auth            14
482
#define Seskey          15
483
#define Usrkey          16
484
#define Inrogen         20
485
#define Inro1           21
486
#define Inro2           22
487
#define Inro3           23
488
#define Inro4           24
489
#define Inro5           25
490
#define Inro6           26
491
#define Inro7           27
492
#define Inro8           28
493
#define Inro9           29
494
#define Inro10          30
495
#define Inro11          31
496
#define Inro12          32
497
#define Inro13          33
498
#define Inro14          34
499
#define Inro15          35
500
#define Inro16          36
501
#define Reqcogen        37
502
#define Reqco1          38
503
#define Reqco2          39
504
#define Reqco3          40
505
#define Reqco4          41
506
#define UkTypeId        44
507
#define UkCauseTx       45
508
#define UkComAdrASDU    46
509
#define UkIOA           47
510
511
static const value_string causetx_types [] = {
512
  { Per_Cyc         ,"Per/Cyc" },
513
  { Back            ,"Back" },
514
  { Spont           ,"Spont" },
515
  { Init            ,"Init" },
516
  { Req             ,"Req" },
517
  { Act             ,"Act" },
518
  { ActCon          ,"ActCon" },
519
  { Deact           ,"Deact" },
520
  { DeactCon        ,"DeactCon" },
521
  { ActTerm         ,"ActTerm" },
522
  { Retrem          ,"Retrem" },
523
  { Retloc          ,"Retloc" },
524
  { File            ,"File" },
525
  { Auth            ,"Auth" },
526
  { Seskey          ,"Seskey" },
527
  { Usrkey          ,"Usrkey" },
528
  { Inrogen         ,"Inrogen" },
529
  { Inro1           ,"Inro1" },
530
  { Inro2           ,"Inro2" },
531
  { Inro3           ,"Inro3" },
532
  { Inro4           ,"Inro4" },
533
  { Inro5           ,"Inro5" },
534
  { Inro6           ,"Inro6" },
535
  { Inro7           ,"Inro7" },
536
  { Inro8           ,"Inro8" },
537
  { Inro9           ,"Inro9" },
538
  { Inro10          ,"Inro10" },
539
  { Inro11          ,"Inro11" },
540
  { Inro12          ,"Inro12" },
541
  { Inro13          ,"Inro13" },
542
  { Inro14          ,"Inro14" },
543
  { Inro15          ,"Inro15" },
544
  { Inro16          ,"Inro16" },
545
  { Reqcogen        ,"Reqcogen" },
546
  { Reqco1          ,"Reqco1" },
547
  { Reqco2          ,"Reqco2" },
548
  { Reqco3          ,"Reqco3" },
549
  { Reqco4          ,"Reqco4" },
550
  { UkTypeId        ,"UkTypeId" },
551
  { UkCauseTx       ,"UkCauseTx" },
552
  { UkComAdrASDU    ,"UkComAdrASDU" },
553
  { UkIOA           ,"UkIOA" },
554
  { 0, NULL }
555
};
556
557
static const value_string diq_types[] = {
558
  { 0,    "Indeterminate or Intermediate" },
559
  { 1,    "OFF" },
560
  { 2,    "ON" },
561
  { 3,    "Indeterminate" },
562
  { 0, NULL }
563
};
564
565
static const value_string qos_qu_types[] = {
566
  { 0,    "No pulse defined" },
567
  { 1,    "Short Pulse" },
568
  { 2,    "Long Pulse" },
569
  { 3,    "Persistent Output" },
570
  { 0, NULL }
571
};
572
573
static const value_string dco_on_types[] = {
574
  { 0,    "(None)" },
575
  { 1,    "OFF" },
576
  { 2,    "ON" },
577
  { 3,    "Error: On/Off not defined" },
578
  { 0, NULL }
579
};
580
581
static const value_string rco_up_types[] = {
582
  { 0,    "(None)" },
583
  { 1,    "DOWN" },
584
  { 2,    "UP" },
585
  { 3,    "Error: Up/Down not defined" },
586
  { 0, NULL }
587
};
588
589
static const value_string qpm_kpa_types[] = {
590
  { 0,    "Not used" },
591
  { 1,    "Threshold value" },
592
  { 2,    "Smoothing factor (filter time constant)" },
593
  { 0, NULL }
594
};
595
596
static const value_string qpm_lpc_types[] = {
597
  { 0,    "No change" },
598
  { 1,    "Change" },
599
  { 0, NULL }
600
};
601
602
static const value_string qpm_pop_types[] = {
603
  { 0,    "Operation" },
604
  { 1,    "Not in operation" },
605
  { 0, NULL }
606
};
607
608
static const value_string coi_r_types[] = {
609
  { 0,    "Local power switch on" },
610
  { 1,    "Local manual reset" },
611
  { 2,    "Remote reset" },
612
  { 0, NULL }
613
};
614
615
static const value_string qoi_r_types[] = {
616
  { 0,    "Not specified" },
617
  { 20,   "Station interrogation (global)" },
618
  { 21,   "Group 1 interrogation" },
619
  { 22,   "Group 2 interrogation" },
620
  { 23,   "Group 3 interrogation" },
621
  { 24,   "Group 4 interrogation" },
622
  { 25,   "Group 5 interrogation" },
623
  { 26,   "Group 6 interrogation" },
624
  { 27,   "Group 7 interrogation" },
625
  { 28,   "Group 8 interrogation" },
626
  { 29,   "Group 9 interrogation" },
627
  { 30,   "Group 10 interrogation" },
628
  { 31,   "Group 11 interrogation" },
629
  { 32,   "Group 12 interrogation" },
630
  { 33,   "Group 13 interrogation" },
631
  { 34,   "Group 14 interrogation" },
632
  { 35,   "Group 15 interrogation" },
633
  { 36,   "Group 16 interrogation" },
634
  { 0, NULL }
635
};
636
637
static const value_string rqt_r_types[] = {
638
  { 0,    "Not specified" },
639
  { 1,    "Group 1 counter interrogation" },
640
  { 2,    "Group 2 counter interrogation" },
641
  { 3,    "Group 3 counter interrogation" },
642
  { 4,    "Group 4 counter interrogation" },
643
  { 5,    "General counter interrogation" },
644
  { 0, NULL }
645
};
646
647
static const value_string frz_r_types[] = {
648
  { 0,    "Read only (no freeze or reset)" },
649
  { 1,    "Counter freeze without reset (value frozen represents integrated total)" },
650
  { 2,    "Counter freeze with reset (value frozen represents incremental information)" },
651
  { 3,    "Counter reset" },
652
  { 0, NULL }
653
};
654
655
static const value_string qrp_r_types[] = {
656
  { 0,    "Not used" },
657
  { 1,    "General reset of process" },
658
  { 2,    "Reset of pending information with time tag of the event buffer" },
659
  { 0, NULL }
660
};
661
662
static const value_string frq_qualifier[] = {
663
  { 0,    "Default" },
664
  { 0, NULL }
665
};
666
667
static const value_string srq_qualifier[] = {
668
  { 0,    "Default" },
669
  { 0, NULL }
670
};
671
672
static const value_string scq_select[] = {
673
  { 0,    "Default" },
674
  { 1,    "Select file" },
675
  { 2,    "Request file" },
676
  { 3,    "Deactivate file" },
677
  { 4,    "Delete file" },
678
  { 5,    "Select section" },
679
  { 6,    "Request section" },
680
  { 7,    "deactivate section" },
681
  { 0, NULL }
682
};
683
684
static const value_string scq_qualifier[] = {
685
  { 0,    "Default" },
686
  { 1,    "Requested memory space not available" },
687
  { 2,    "Checksum failed" },
688
  { 3,    "Unexpected communication service" },
689
  { 4,    "Unexpected name of file" },
690
  { 5,    "Unexpected name of section" },
691
  { 0, NULL }
692
};
693
694
static const value_string lsq_qualifier[] = {
695
  { 0,    "Not used" },
696
  { 1,    "File transfer without deactivation" },
697
  { 2,    "File transfer with deactivation" },
698
  { 3,    "Section transfer without deactivation" },
699
  { 4,    "Section transfer with deactivation" },
700
  { 0, NULL }
701
};
702
703
static const value_string afq_ack[] = {
704
  { 0,    "Not used" },
705
  { 1,    "Positive acknowledge of file transfer" },
706
  { 2,    "Negative acknowledge of file transfer" },
707
  { 3,    "Positive acknowledge of section transfer" },
708
  { 4,    "Negative acknowledge of section transfer" },
709
  { 0, NULL }
710
};
711
712
static const value_string afq_qualifier[] = {
713
  { 0,    "Default" },
714
  { 1,    "Requested memory space not available" },
715
  { 2,    "Checksum failed" },
716
  { 3,    "Unexpected communication service" },
717
  { 4,    "Unexpected name of file" },
718
  { 5,    "Unexpected name of section" },
719
  { 0, NULL }
720
};
721
722
static const value_string sof_status[] = {
723
  { 0,    "Default" },
724
  { 0, NULL }
725
};
726
727
static const value_string sep_types[] = {
728
  { 0,    "Indeterminate" },
729
  { 1,    "OFF" },
730
  { 2,    "ON" },
731
  { 3,    "Indeterminate" },
732
  { 0, NULL }
733
};
734
735
static const value_string qpa_types[] = {
736
  { 0,    "Not used" },
737
  { 1,    "Act/deact of the previously loaded parameters (object address = 0)" },
738
  { 2,    "Act/deact of the parameter of the addressed object" },
739
  { 3,    "Act/deact of persistent cyclic or periodic transmission of the addressed object" },
740
  { 0, NULL }
741
};
742
743
static const range_string usr_types[] = {
744
  { 0,  0,  "(Unknown)" },
745
  { 1,  1,  "Default" },
746
  { 2,  65535,  "Chosen by the controlling station" },
747
  { 0, 0, NULL }
748
};
749
750
static const range_string mal_types[] = {
751
  { 0,  0,  "(not used)" },
752
  { 1,  1,  "HMAC SHA-1 truncated to 4 octets (serial)" },
753
  { 2,  2,  "HMAC SHA-1 truncated to 10 octets (networked)" },
754
  { 3,  3,  "HMAC-SHA-256 truncated to 8 octets (serial)" },
755
  { 4,  4,  "HMAC-SHA-256 truncated to 16 octets (networked)" },
756
  { 128,  255,  "(vendor-specific choice)" },
757
  { 0, 0, NULL }
758
};
759
760
static const value_string rsc_types[] = {
761
  { 0,    "(not used)" },
762
  { 1,    "CRITICAL" },
763
  { 0, NULL }
764
};
765
766
static const range_string kwa_types[] = {
767
  { 0,  0,  "(not used)" },
768
  { 1,  1,  "AES-128 Key Wrap Algorithm" },
769
  { 2,  2,  "AES-256 Key Wrap Algorithm" },
770
  { 128,  255,  "(vendor-specific choice)" },
771
  { 0, 0, NULL }
772
};
773
774
static const value_string kst_types[] = {
775
  { 0,    "(not used)" },
776
  { 1,    "OK" },
777
  { 2,    "NOT INIT" },
778
  { 3,    "COMM FAIL" },
779
  { 4,    "AUTH FAIL" },
780
  { 0, NULL }
781
};
782
783
static const range_string hal_types[] = {
784
  { 0,  0,  "No MAC value in this message" },
785
  { 1,  1,  "HMAC SHA-1 truncated to 4 octets (serial)" },
786
  { 2,  2,  "HMAC SHA-1 truncated to 10 octets (networked)" },
787
  { 3,  3,  "HMAC-SHA-256 truncated to 8 octets (serial)" },
788
  { 4,  4,  "HMAC-SHA-256 truncated to 16 octets (networked)" },
789
  { 128,  255,  "(vendor-specific choice)" },
790
  { 0, 0, NULL }
791
};
792
793
static const range_string error_codes[] = {
794
  { 0,  0,  "(not used)" },
795
  { 1,  1,  "Authentication failed" },
796
  { 2,  2,  "Unexpected reply" },
797
  { 3,  3,  "No reply" },
798
  { 4,  4,  "Aggressive Mode not permitted" },
799
  { 5,  5,  "MAC algorithm not permitted" },
800
  { 6,  6,  "Key Wrap algorithm not permitted" },
801
  { 7,  7,  "Authorization failed" },
802
  { 8,  8,  "Update Key Change Method not permitted" },
803
  { 9,  9,  "Invalid Signature" },
804
  { 10, 10, "Invalid Certification Data" },
805
  { 11, 11, "Unknown User" },
806
  { 128, 255, "(vendor-specific choice)"},
807
  { 0, 0, NULL }
808
};
809
810
static const true_false_string tfs_blocked_not_blocked = { "Blocked", "Not blocked" };
811
static const true_false_string tfs_substituted_not_substituted = { "Substituted", "Not Substituted" };
812
static const true_false_string tfs_not_topical_topical = { "Not Topical", "Topical" };
813
static const true_false_string tfs_transient_not_transient = { "Transient", "Not Transient" };
814
static const true_false_string tfs_overflow_no_overflow = { "Overflow", "No overflow" };
815
static const true_false_string tfs_select_execute = { "Select", "Execute" };
816
static const true_false_string tfs_summer_standard_time = { "Summer time", "Standard time" };
817
static const true_false_string tfs_coi_i = { "Initialisation after change of local parameters", "Initialisation with unchanged local parameters" };
818
static const true_false_string tfs_adjusted_not_adjusted = { "Adjusted", "Not Adjusted" };
819
static const true_false_string tfs_negative_positive = { "Negative", "Positive" };
820
static const true_false_string tfs_not_ready_ready = { "Not ready", "Ready" };
821
static const true_false_string tfs_last_file_additional_follows = { "Last file", "Additional file follows" };
822
static const true_false_string tfs_subdir_file = { "Subdirectory", "File" };
823
static const true_false_string tfs_active_waits = { "Transfer active", "Waits for transfer" };
824
static const true_false_string tfs_elapsed_invalid_valid = { "Elapsed time invalid", "Elapsed time valid" };
825
static const true_false_string tfs_general_start_no_general_start = { "General start", "No general start" };
826
static const true_false_string tfs_general_command_no_general_command = { "General command", "No general command" };
827
static const true_false_string tfs_start_no_start = { "Start", "No start" };
828
static const true_false_string tfs_start_reverse_no_start_revers = { "Start in reverse direction", "No start in reverse direction" };
829
static const true_false_string tfs_command_no_command = { "Command", "No command" };
830
831
static int global_iec60870_link_addr_len = 1;
832
static int global_iec60870_cot_len = 1;
833
static int global_iec60870_asdu_addr_len = 1;
834
static int global_iec60870_ioa_len = 2;
835
836
/* Protocol fields to be filtered */
837
static int hf_apdulen;
838
static int hf_apcitype_i;
839
static int hf_apcitype_s_u;
840
static int hf_apciutype;
841
static int hf_apcitx;
842
static int hf_apcirx;
843
static int hf_apcidata;
844
845
static int hf_addr;
846
static int hf_oa;
847
static int hf_typeid;
848
static int hf_causetx;
849
static int hf_nega;
850
static int hf_test;
851
static int hf_ioa;
852
static int hf_numix;
853
static int hf_sq;
854
static int hf_cp16time;
855
static int hf_cp24time;
856
static int hf_cp24time_ms;
857
static int hf_cp24time_min;
858
static int hf_cp24time_iv;
859
static int hf_cp56time;
860
static int hf_cp56time_ms;
861
static int hf_cp56time_min;
862
static int hf_cp56time_gen;
863
static int hf_cp56time_iv;
864
static int hf_cp56time_hour;
865
static int hf_cp56time_su;
866
static int hf_cp56time_day;
867
static int hf_cp56time_dow;
868
static int hf_cp56time_month;
869
static int hf_cp56time_year;
870
static int hf_range_start_cp56time;
871
static int hf_range_stop_cp56time;
872
static int hf_siq;
873
static int hf_siq_spi;
874
static int hf_siq_bl;
875
static int hf_siq_sb;
876
static int hf_siq_nt;
877
static int hf_siq_iv;
878
static int hf_diq;
879
static int hf_diq_dpi;
880
static int hf_diq_bl;
881
static int hf_diq_sb;
882
static int hf_diq_nt;
883
static int hf_diq_iv;
884
static int hf_qds;
885
static int hf_qds_ov;
886
static int hf_qds_bl;
887
static int hf_qds_sb;
888
static int hf_qds_nt;
889
static int hf_qds_iv;
890
static int hf_vti;
891
static int hf_vti_v;
892
static int hf_vti_t;
893
static int hf_qos;
894
static int hf_qos_ql;
895
static int hf_qos_se;
896
static int hf_sco;
897
static int hf_sco_on;
898
static int hf_sco_qu;
899
static int hf_sco_se;
900
static int hf_dco;
901
static int hf_dco_on;
902
static int hf_dco_qu;
903
static int hf_dco_se;
904
static int hf_rco;
905
static int hf_rco_up;
906
static int hf_rco_qu;
907
static int hf_rco_se;
908
static int hf_qpm;
909
static int hf_qpm_kpa;
910
static int hf_qpm_lpc;
911
static int hf_qpm_pop;
912
static int hf_nof;
913
static int hf_lof;
914
static int hf_frq;
915
static int hf_frq_qualifier;
916
static int hf_frq_confirm;
917
static int hf_nos;
918
static int hf_srq;
919
static int hf_srq_qualifier;
920
static int hf_srq_ready;
921
static int hf_scq;
922
static int hf_scq_select;
923
static int hf_scq_qualifier;
924
static int hf_lsq;
925
static int hf_chs;
926
static int hf_afq;
927
static int hf_afq_ack;
928
static int hf_afq_qualifier;
929
static int hf_los;
930
static int hf_segment_data;
931
static int hf_sof;
932
static int hf_sof_status;
933
static int hf_sof_lfd;
934
static int hf_sof_for;
935
static int hf_sof_fa;
936
static int hf_sep;
937
static int hf_sep_es;
938
static int hf_sep_ei;
939
static int hf_sep_bl;
940
static int hf_sep_sb;
941
static int hf_sep_nt;
942
static int hf_sep_iv;
943
static int hf_spe;
944
static int hf_spe_gs;
945
static int hf_spe_sl1;
946
static int hf_spe_sl2;
947
static int hf_spe_sl3;
948
static int hf_spe_sie;
949
static int hf_spe_srd;
950
static int hf_qdp;
951
static int hf_qdp_ei;
952
static int hf_qdp_bl;
953
static int hf_qdp_sb;
954
static int hf_qdp_nt;
955
static int hf_qdp_iv;
956
static int hf_oci;
957
static int hf_oci_gc;
958
static int hf_oci_cl1;
959
static int hf_oci_cl2;
960
static int hf_oci_cl3;
961
static int hf_qpa;
962
static int hf_fbp;
963
static int hf_scd;
964
static int hf_scd_st;
965
static int hf_scd_cd;
966
static int hf_asn;
967
static int hf_usr;
968
static int hf_iec60870_segment_data;
969
static int hf_mal;
970
static int hf_rsc;
971
static int hf_asn_fin;
972
static int hf_asn_fir;
973
static int hf_csq;
974
static int hf_ksq;
975
static int hf_kwa;
976
static int hf_kst;
977
static int hf_hln;
978
static int hf_hal;
979
static int hf_cln;
980
static int hf_wkl;
981
static int hf_prcd_raw_data;
982
static int hf_hmac_raw_data;
983
static int hf_wkd_raw_data;
984
static int hf_aid;
985
static int hf_err;
986
static int hf_etm;
987
static int hf_etm_ms;
988
static int hf_etm_min;
989
static int hf_etm_iv;
990
static int hf_etm_hour;
991
static int hf_etm_su;
992
static int hf_etm_day;
993
static int hf_etm_dow;
994
static int hf_etm_month;
995
static int hf_etm_year;
996
static int hf_eln;
997
static int hf_error_text;
998
static int hf_coi;
999
static int hf_coi_r;
1000
static int hf_coi_i;
1001
static int hf_qoi;
1002
static int hf_qcc;
1003
static int hf_qcc_rqt;
1004
static int hf_qcc_frz;
1005
static int hf_qrp;
1006
static int hf_bcr;
1007
static int hf_bcr_count;
1008
static int hf_bcr_sq;
1009
static int hf_bcr_cy;
1010
static int hf_bcr_ca;
1011
static int hf_bcr_iv;
1012
static int hf_start;
1013
1014
static int hf_asdu_bitstring;
1015
static int hf_asdu_float;
1016
static int hf_asdu_normval;
1017
static int hf_asdu_scalval;
1018
static int hf_asdu_tsc;
1019
static int hf_asdu_raw_data;
1020
1021
static int ett_apci;
1022
static int ett_asdu;
1023
static int ett_asdu_objects;
1024
static int ett_siq;
1025
static int ett_diq;
1026
static int ett_vti;
1027
static int ett_qds;
1028
static int ett_qos;
1029
static int ett_sco;
1030
static int ett_sep;
1031
static int ett_spe;
1032
static int ett_qdp;
1033
static int ett_oci;
1034
static int ett_scd;
1035
static int ett_dco;
1036
static int ett_rco;
1037
static int ett_qpm;
1038
static int ett_frq;
1039
static int ett_srq;
1040
static int ett_scq;
1041
static int ett_afq;
1042
static int ett_sof;
1043
static int ett_coi;
1044
static int ett_qcc;
1045
static int ett_cp24time;
1046
static int ett_cp56time;
1047
static int ett_etm;
1048
1049
static int ett_iec60870_segment;
1050
static int ett_iec60870_segments;
1051
1052
static expert_field ei_iec104_short_asdu;
1053
static expert_field ei_iec104_apdu_min_len;
1054
static expert_field ei_iec104_apdu_invalid_len;
1055
1056
/* IEC 101 stuff */
1057
/* Initialize the protocol and registered fields */
1058
static int hf_iec60870_101_frame;
1059
static int hf_iec60870_101_length;
1060
static int hf_iec60870_101_num_user_octets;
1061
static int hf_iec60870_101_ctrlfield;
1062
static int hf_iec60870_101_ctrl_prm;
1063
static int hf_iec60870_101_ctrl_fcb;
1064
static int hf_iec60870_101_ctrl_fcv;
1065
static int hf_iec60870_101_ctrl_dfc;
1066
static int hf_iec60870_101_ctrl_func_pri_to_sec;
1067
static int hf_iec60870_101_ctrl_func_sec_to_pri;
1068
static int hf_iec60870_101_linkaddr;
1069
static int hf_iec60870_101_checksum;
1070
static int hf_iec60870_101_stopchar;
1071
1072
static int hf_iec60870_segments;
1073
static int hf_iec60870_segment;
1074
static int hf_iec60870_segment_overlap;
1075
static int hf_iec60870_segment_overlap_conflict;
1076
static int hf_iec60870_segment_multiple_tails;
1077
static int hf_iec60870_segment_too_long_segment;
1078
static int hf_iec60870_segment_error;
1079
static int hf_iec60870_segment_count;
1080
static int hf_iec60870_reassembled_in;
1081
static int hf_iec60870_reassembled_length;
1082
1083
static const fragment_items iec60870_frag_items = {
1084
  &ett_iec60870_segment,
1085
  &ett_iec60870_segments,
1086
  &hf_iec60870_segments,
1087
  &hf_iec60870_segment,
1088
  &hf_iec60870_segment_overlap,
1089
  &hf_iec60870_segment_overlap_conflict,
1090
  &hf_iec60870_segment_multiple_tails,
1091
  &hf_iec60870_segment_too_long_segment,
1092
  &hf_iec60870_segment_error,
1093
  &hf_iec60870_segment_count,
1094
  &hf_iec60870_reassembled_in,
1095
  &hf_iec60870_reassembled_length,
1096
  /* Reassembled data field */
1097
  NULL,
1098
  "segments"
1099
};
1100
1101
/* Initialize the subtree pointers */
1102
static int ett_iec60870_101;
1103
static int ett_iec60870_101_ctrlfield;
1104
1105
static expert_field ei_iec101_frame_mismatch;
1106
static expert_field ei_iec101_length_mismatch;
1107
static expert_field ei_iec101_stopchar_invalid;
1108
1109
/* Frame Format */
1110
0
#define IEC101_VAR_LEN        0x68
1111
0
#define IEC101_FIXED_LEN      0x10
1112
0
#define IEC101_SINGLE_CHAR    0xE5
1113
0
#define IEC101_STOP_CHAR      0x16
1114
1115
static const value_string iec60870_101_frame_vals[] = {
1116
  { IEC101_VAR_LEN,         "Variable Length" },
1117
  { IEC101_FIXED_LEN,       "Fixed Length" },
1118
  { IEC101_SINGLE_CHAR,     "Single Character" },
1119
  { 0,                         NULL }
1120
};
1121
1122
static const value_string iec60870_101_ctrl_prm_values[] = {
1123
  { 0,      "Message from Secondary (Responding) Station" },
1124
  { 1,      "Message from Primary (Initiating) Station" },
1125
  { 0,      NULL }
1126
};
1127
1128
static const value_string iec60870_101_ctrl_func_pri_to_sec_values[] = {
1129
  { 0,      "Reset of Remote Link" },
1130
  { 1,      "Reset of User Process" },
1131
  { 2,      "Reserved for Balanced Mode" },
1132
  { 3,      "User Data" },
1133
  { 4,      "User Data" },
1134
  { 5,      "Reserved" },
1135
  { 6,      "Reserved" },
1136
  { 7,      "Reserved" },
1137
  { 8,      "Expected Response Specifies Access Demand" },
1138
  { 9,      "Request Status of Link" },
1139
  { 10,     "Request User Data Class 1" },
1140
  { 11,     "Request User Data Class 2" },
1141
  { 12,     "Reserved" },
1142
  { 13,     "Reserved" },
1143
  { 14,     "Reserved" },
1144
  { 15,     "Reserved" },
1145
  { 0,      NULL }
1146
};
1147
1148
static const value_string iec60870_101_ctrl_func_sec_to_pri_values[] = {
1149
  { 0,      "ACK: Positive Acknowledgement" },
1150
  { 1,      "NACK: Message Not Accepted, Link Busy" },
1151
  { 2,      "Reserved" },
1152
  { 3,      "Reserved" },
1153
  { 4,      "Reserved" },
1154
  { 5,      "Reserved" },
1155
  { 6,      "Reserved" },
1156
  { 7,      "Reserved" },
1157
  { 8,      "User Data" },
1158
  { 9,      "NACK: Requested Data not Available" },
1159
  { 10,     "Reserved" },
1160
  { 11,     "Status of Link" },
1161
  { 12,     "Reserved" },
1162
  { 13,     "Reserved" },
1163
  { 14,     "Link Service not Functioning" },
1164
  { 15,     "Link Service not Implemented" },
1165
  { 0,      NULL }
1166
};
1167
1168
/* IEC 60870-5-103 Variables */
1169
/* Initialize the protocol and registered fields */
1170
static int hf_iec60870_5_103_areva_cmd;
1171
static int hf_iec60870_5_103_asdu_address;
1172
static int hf_iec60870_5_103_asdu_typeid_mon;
1173
static int hf_iec60870_5_103_asdu_typeid_ctrl;
1174
static int hf_iec60870_5_103_asdu205_ms;
1175
static int hf_iec60870_5_103_asdu205_min;
1176
static int hf_iec60870_5_103_asdu205_h;
1177
static int hf_iec60870_5_103_asdu205_value;
1178
static int hf_iec60870_5_103_checksum;
1179
static int hf_iec60870_5_103_col;
1180
static int hf_iec60870_5_103_cot_mon;
1181
static int hf_iec60870_5_103_cot_ctrl;
1182
static int hf_iec60870_5_103_cp32time2a;
1183
static int hf_iec60870_5_103_cp32time2a_ms;
1184
static int hf_iec60870_5_103_cp32time2a_min;
1185
static int hf_iec60870_5_103_cp32time2a_res1;
1186
static int hf_iec60870_5_103_cp32time2a_iv;
1187
static int hf_iec60870_5_103_cp32time2a_hr;
1188
static int hf_iec60870_5_103_cp32time2a_res2;
1189
static int hf_iec60870_5_103_cp32time2a_sum;
1190
static int hf_iec60870_5_103_ctrlfield;
1191
static int hf_iec60870_5_103_ctrl_prm;
1192
static int hf_iec60870_5_103_ctrl_fcb;
1193
static int hf_iec60870_5_103_ctrl_fcv;
1194
static int hf_iec60870_5_103_ctrl_dfc;
1195
static int hf_iec60870_5_103_ctrl_func_pri_to_sec;
1196
static int hf_iec60870_5_103_ctrl_func_sec_to_pri;
1197
static int hf_iec60870_5_103_dco;
1198
static int hf_iec60870_5_103_dpi;
1199
static int hf_iec60870_5_103_frame;
1200
static int hf_iec60870_5_103_func_type;
1201
static int hf_iec60870_5_103_info_num;
1202
static int hf_iec60870_5_103_length;
1203
static int hf_iec60870_5_103_linkaddr;
1204
static int hf_iec60870_5_103_mfg;
1205
static int hf_iec60870_5_103_mfg_sw;
1206
static int hf_iec60870_5_103_num_user_octets;
1207
static int hf_iec60870_5_103_rii;
1208
static int hf_iec60870_5_103_scn;
1209
static int hf_iec60870_5_103_sin;
1210
static int hf_iec60870_5_103_sq;
1211
static int hf_iec60870_5_103_stopchar;
1212
1213
/* Initialize the subtree pointers */
1214
static int ett_iec60870_5_103;
1215
static int ett_iec60870_5_103_ctrlfield;
1216
static int ett_iec60870_5_103_cp32time2a;
1217
1218
/* Frame Format */
1219
0
#define IEC103_VAR_LEN        0x68
1220
0
#define IEC103_FIXED_LEN      0x10
1221
0
#define IEC103_SINGLE_CHAR    0xE5
1222
1223
/* Frame Format */
1224
static const value_string iec60870_5_103_frame_vals[] = {
1225
  { IEC103_VAR_LEN,         "Variable Length" },
1226
  { IEC103_FIXED_LEN,       "Fixed Length" },
1227
  { IEC103_SINGLE_CHAR,     "Single Character" },
1228
  { 0,                         NULL }
1229
};
1230
1231
static const value_string iec60870_5_103_ctrl_prm_values[] = {
1232
  { 0,      "Message from Secondary (Responding) Station" },
1233
  { 1,      "Message from Primary (Initiating) Station" },
1234
  { 0,      NULL }
1235
};
1236
1237
static const value_string iec60870_5_103_ctrl_func_pri_to_sec_values[] = {
1238
  { 0,     "Reset of Communications Unit" },
1239
  { 1,     "Reserved" },
1240
  { 2,     "Reserved" },
1241
  { 3,     "Send / Confirm Expected" },
1242
  { 4,     "Send / No Confirm Expected" },
1243
  { 5,     "Reserved" },
1244
  { 6,     "Reserved" },
1245
  { 7,     "Reset Frame Count Bit" },
1246
  { 8,     "Reserved" },
1247
  { 9,     "Request Status of Link" },
1248
  { 10,    "Request User Data Class 1" },
1249
  { 11,    "Request User Data Class 2" },
1250
  { 12,    "Reserved" },
1251
  { 13,    "Reserved" },
1252
  { 14,    "Reserved" },
1253
  { 15,    "Reserved" },
1254
  { 0,     NULL }
1255
};
1256
1257
static const value_string iec60870_5_103_ctrl_func_sec_to_pri_values[] = {
1258
  { 0,     "ACK: Positive Acknowledgement" },
1259
  { 1,     "NACK: Message Not Accepted, Link Busy" },
1260
  { 2,     "Reserved" },
1261
  { 3,     "Reserved" },
1262
  { 4,     "Reserved" },
1263
  { 5,     "Reserved" },
1264
  { 6,     "Reserved" },
1265
  { 7,     "Reserved" },
1266
  { 8,     "ACK: User Data" },
1267
  { 9,     "NACK: Requested Data not Available" },
1268
  { 10,    "Reserved" },
1269
  { 11,    "Status of Link" },
1270
  { 12,    "Reserved" },
1271
  { 13,    "Reserved" },
1272
  { 14,    "Link Service not Functioning" },
1273
  { 15,    "Link Service not Implemented" },
1274
  { 0,     NULL }
1275
};
1276
1277
/* IEC 60870-5-103 ASDU types (TypeId); monitor direction */
1278
static const value_string iec103_asdu_types_monitor_dir [] = {
1279
  {  1,   "Time tagged message" },    /* dissection implemented */
1280
  {  2,   "Time tagged message with relative time" },
1281
  {  3,   "Measurands I" },
1282
  {  4,   "Time tagged measurands with relative time" },
1283
  {  5,   "Identification" },    /* dissection implemented */
1284
  {  6,   "Time synchronization" },    /* dissection implemented */
1285
  {  8,   "General interrogation termination" },    /* dissection implemented */
1286
  {  9,   "Measurands II" },    /* dissection implemented */
1287
  {  10,    "Generic data" },
1288
  {  11,    "Generic identification" },
1289
  {  12,    "reserved" },
1290
  {  13,    "reserved" },
1291
  {  14,    "reserved" },
1292
  {  15,    "reserved" },
1293
  {  16,    "reserved" },
1294
  {  17,    "reserved" },
1295
  {  18,    "reserved" },
1296
  {  19,    "reserved" },
1297
  {  20,    "reserved" },
1298
  {  21,    "reserved" },
1299
  {  22,    "reserved" },
1300
  {  23,    "List of recorded disturbances" },
1301
  {  24,    "reserved" },
1302
  {  25,    "reserved" },
1303
  {  26,    "Ready for transmission of disturbance data" },
1304
  {  27,    "Ready for transmission of a channel" },
1305
  {  28,    "Ready for transmission of tags" },
1306
  {  29,    "Transmission of tags" },
1307
  {  30,    "Transmission of disturbance values" },
1308
  {  31,    "End of transmission" },
1309
  {  205,     "Private, Siemens energy counters"},    /* dissection implemented */
1310
  {  0,   NULL }
1311
};
1312
1313
/* IEC 60870-5-103 ASDU types (TypeId); control direction */
1314
static const value_string iec103_asdu_types_control_dir [] = {
1315
  {  1,   "reserved" },
1316
  {  2,   "reserved" },
1317
  {  3,   "reserved" },
1318
  {  4,   "reserved" },
1319
  {  5,   "reserved" },
1320
  {  6,   "Time synchronization" },    /* dissection implemented */
1321
  {  7,   "General interrogation" },    /* dissection implemented */
1322
  {  8,   "reserved" },
1323
  {  9,   "reserved" },
1324
  {  10,    "Generic data" },
1325
  {  11,    "reserved" },
1326
  {  12,    "reserved" },
1327
  {  13,    "reserved" },
1328
  {  14,    "reserved" },
1329
  {  15,    "reserved" },
1330
  {  16,    "reserved" },
1331
  {  17,    "reserved" },
1332
  {  18,    "reserved" },
1333
  {  19,    "reserved" },
1334
  {  20,    "General command" },    /* dissection implemented */
1335
  {  21,    "Generic command" },
1336
  {  22,    "reserved" },
1337
  {  23,    "reserved" },
1338
  {  24,    "Order for disturbance data transmission" },
1339
  {  25,    "Acknowledgement for disturbance data transmission" },
1340
  {  26,    "reserved" },
1341
  {  27,    "reserved" },
1342
  {  28,    "reserved" },
1343
  {  29,    "reserved" },
1344
  {  30,    "reserved" },
1345
  {  31,    "reserved" },
1346
  {  45,    "Private, Areva Single Command" },    /* dissection implemented */
1347
  {  46,    "Private, Areva Double Command" },    /* dissection implemented */
1348
  {  0,   NULL }
1349
};
1350
1351
static const value_string iec60870_5_103_cot_monitor_dir [] = {
1352
  { 1,     "Spontaneous" },
1353
  { 2,     "Cyclic" },
1354
  { 3,     "Reset frame count bit (FCB)" },
1355
  { 4,     "Reset communication unit (CU)" },
1356
  { 5,     "Start / restart" },
1357
  { 6,     "Power on" },
1358
  { 7,     "Test mode" },
1359
  { 8,     "Time synchronization" },
1360
  { 9,     "General interrogation" },
1361
  { 10,    "Termination of general interrogation" },
1362
  { 11,    "Local operation" },
1363
  { 12,    "Remote operation" },
1364
  { 20,    "Positive acknowledgement of command" },
1365
  { 21,    "Negative acknowledgement of command" },
1366
  { 31,    "Transmission of disturbance data" },
1367
  { 40,    "Positive acknowledgement of generic write command" },
1368
  { 41,    "Negative acknowledgement of generic write command" },
1369
  { 42,    "Valid data response to generic read command" },
1370
  { 43,    "Invalid data response to generic read command" },
1371
  { 44,    "Generic write confirmation" },
1372
  { 0,     NULL }
1373
};
1374
1375
static const value_string iec60870_5_103_cot_ctrl_dir [] = {
1376
  { 8,     "Time synchronization" },
1377
  { 9,     "Initiation of general interrogation" },
1378
  { 20,    "General command" },
1379
  { 31,    "Transmission of disturbance data" },
1380
  { 40,    "Generic write command" },
1381
  { 42,    "Generic read command" },
1382
  { 0,     NULL }
1383
};
1384
1385
1386
static const value_string iec103_quadstate_types[] = {
1387
  { 0,      "Not used" },
1388
  { 1,      "OFF" },
1389
  { 2,      "ON" },
1390
  { 3,      "Not used" },
1391
  { 0,      NULL }
1392
};
1393
1394
/* Misc. functions for dissection of signal values */
1395
1396
/* ====================================================================
1397
   CP24Time2a: 7.2.6.19 Three octet binary time
1398
   ==================================================================== */
1399
static void get_CP24Time(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
1400
1.83k
{
1401
1.83k
  uint16_t ms;
1402
1.83k
  uint8_t min;
1403
1.83k
  nstime_t nstime;
1404
1.83k
  proto_item* ti;
1405
1.83k
  proto_tree* cp24time_tree;
1406
1407
1.83k
  ms = tvb_get_letohs(tvb, *offset);
1408
1.83k
  nstime.nsecs = (ms % 1000) * 1000000;
1409
1.83k
  nstime.secs = ms / 1000;
1410
1.83k
  (*offset) += 2;
1411
1412
1.83k
  min = tvb_get_uint8(tvb, *offset);
1413
1.83k
  nstime.secs += (min & 0x3F) * 60;
1414
1.83k
  (*offset)++;
1415
1416
1.83k
  (*offset) -= 3;
1417
1418
1.83k
  ti = proto_tree_add_time(iec104_header_tree, hf_cp24time, tvb, *offset, 3, &nstime);
1419
1.83k
  cp24time_tree = proto_item_add_subtree(ti, ett_cp24time);
1420
1421
1.83k
  proto_tree_add_item(cp24time_tree, hf_cp24time_ms, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
1422
1.83k
  (*offset) += 2;
1423
1424
1.83k
  proto_tree_add_item(cp24time_tree, hf_cp24time_min, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1425
1.83k
  proto_tree_add_item(cp24time_tree, hf_cp24time_iv, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1426
1.83k
  (*offset) ++;
1427
1.83k
}
1428
1429
/* ====================================================================
1430
   CP56Time2a: 60870-5-103 7.2.6.28 Four octet binary time
1431
   ==================================================================== */
1432
static void get_CP32TimeA(tvbuff_t *tvb, uint8_t *offset, proto_tree *tree)
1433
0
{
1434
0
  uint16_t ms;
1435
0
  uint8_t value;
1436
0
  nstime_t  datetime;
1437
0
  struct tm tm = {0};
1438
0
  proto_item* ti;
1439
0
  proto_tree* cp32time2a_tree;
1440
1441
0
  ms = tvb_get_letohs(tvb, *offset);
1442
0
  tm.tm_sec = ms / 1000;
1443
0
  datetime.nsecs = (ms % 1000) * 1000000;
1444
1445
0
  value = tvb_get_uint8(tvb, *offset+2);
1446
0
  tm.tm_min = value & 0x3F;
1447
1448
0
  value = tvb_get_uint8(tvb, *offset+3);
1449
0
  tm.tm_hour = value & 0x1F;
1450
1451
  /* The CP32Time2a structure does not contain any mm/dd/yyyy information.  Set these as default to 1/1/2000 */
1452
0
  tm.tm_mday = 1;
1453
0
  tm.tm_mon = 0;
1454
0
  tm.tm_year = 100;
1455
1456
0
  datetime.secs = mktime(&tm);
1457
1458
0
  ti = proto_tree_add_time(tree, hf_iec60870_5_103_cp32time2a, tvb, *offset, 4, &datetime);
1459
0
  cp32time2a_tree = proto_item_add_subtree(ti, ett_iec60870_5_103_cp32time2a);
1460
1461
0
  proto_tree_add_item(cp32time2a_tree, hf_iec60870_5_103_cp32time2a_ms, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
1462
0
  proto_tree_add_item(cp32time2a_tree, hf_iec60870_5_103_cp32time2a_min, tvb, *offset+2, 1, ENC_LITTLE_ENDIAN);
1463
0
  proto_tree_add_item(cp32time2a_tree, hf_iec60870_5_103_cp32time2a_res1, tvb, *offset+2, 1, ENC_LITTLE_ENDIAN);
1464
0
  proto_tree_add_item(cp32time2a_tree, hf_iec60870_5_103_cp32time2a_iv, tvb, *offset+2, 1, ENC_LITTLE_ENDIAN);
1465
0
  proto_tree_add_item(cp32time2a_tree, hf_iec60870_5_103_cp32time2a_hr, tvb, *offset+3, 1, ENC_LITTLE_ENDIAN);
1466
0
  proto_tree_add_item(cp32time2a_tree, hf_iec60870_5_103_cp32time2a_res2, tvb, *offset+3, 1, ENC_LITTLE_ENDIAN);
1467
0
  proto_tree_add_item(cp32time2a_tree, hf_iec60870_5_103_cp32time2a_sum, tvb, *offset+3, 1, ENC_LITTLE_ENDIAN);
1468
1469
0
  (*offset) += 4;
1470
0
}
1471
1472
/* ====================================================================
1473
   CP56Time2a: 7.2.6.18 Seven octet binary time
1474
   ==================================================================== */
1475
static void decode_CP56Time(tvbuff_t *tvb, uint8_t *offset, int hfindex, proto_tree *iec104_header_tree)
1476
2.17k
{
1477
2.17k
  uint16_t ms;
1478
2.17k
  uint8_t value;
1479
2.17k
  uint8_t su;
1480
2.17k
  struct tm tm;
1481
2.17k
  nstime_t  datetime;
1482
2.17k
  proto_item* ti;
1483
2.17k
  proto_tree* cp56time_tree;
1484
1485
2.17k
  ms = tvb_get_letohs(tvb, *offset);
1486
2.17k
  tm.tm_sec = ms / 1000;
1487
2.17k
  datetime.nsecs = (ms % 1000) * 1000000;
1488
2.17k
  (*offset) += 2;
1489
1490
2.17k
  value = tvb_get_uint8(tvb, *offset);
1491
2.17k
  tm.tm_min = value & 0x3F;
1492
2.17k
  (*offset)++;
1493
1494
2.17k
  value = tvb_get_uint8(tvb, *offset);
1495
2.17k
  tm.tm_hour = value & 0x1F;
1496
2.17k
  su = value & 0x80;
1497
2.17k
  (*offset)++;
1498
1499
2.17k
  value = tvb_get_uint8(tvb, *offset);
1500
2.17k
  tm.tm_mday = value & 0x1F;
1501
2.17k
  (*offset)++;
1502
1503
2.17k
  value = tvb_get_uint8(tvb, *offset);
1504
2.17k
  tm.tm_mon = (value & 0x0F) - 1;
1505
2.17k
  (*offset)++;
1506
1507
2.17k
  value = tvb_get_uint8(tvb, *offset);
1508
2.17k
  tm.tm_year = value & 0x7F;
1509
2.17k
  if (tm.tm_year < 70)
1510
1.34k
    tm.tm_year += 100;
1511
1512
2.17k
  (*offset)++;
1513
1514
2.17k
  if (su)
1515
551
    tm.tm_isdst = 1;
1516
1.62k
  else
1517
1.62k
    tm.tm_isdst = -1; /* there's no info on whether DST was in force; assume it's
1518
           * the same as currently */
1519
1520
2.17k
  datetime.secs = mktime(&tm);
1521
1522
2.17k
  (*offset) -= 7;
1523
1524
2.17k
  ti = proto_tree_add_time(iec104_header_tree, hfindex, tvb, *offset, 7, &datetime);
1525
2.17k
  cp56time_tree = proto_item_add_subtree(ti, ett_cp56time);
1526
1527
2.17k
  proto_tree_add_item(cp56time_tree, hf_cp56time_ms, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
1528
2.17k
  (*offset) += 2;
1529
1530
2.17k
  proto_tree_add_item(cp56time_tree, hf_cp56time_min, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1531
2.17k
  proto_tree_add_item(cp56time_tree, hf_cp56time_gen, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1532
2.17k
  proto_tree_add_item(cp56time_tree, hf_cp56time_iv, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1533
2.17k
  (*offset) ++;
1534
1535
2.17k
  proto_tree_add_item(cp56time_tree, hf_cp56time_hour, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1536
2.17k
  proto_tree_add_item(cp56time_tree, hf_cp56time_su, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1537
2.17k
  (*offset) ++;
1538
1539
2.17k
  proto_tree_add_item(cp56time_tree, hf_cp56time_day, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1540
2.17k
  proto_tree_add_item(cp56time_tree, hf_cp56time_dow, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1541
2.17k
  (*offset) ++;
1542
1543
2.17k
  proto_tree_add_item(cp56time_tree, hf_cp56time_month, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1544
2.17k
  (*offset) ++;
1545
1546
2.17k
  proto_tree_add_item(cp56time_tree, hf_cp56time_year, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1547
2.17k
  (*offset) ++;
1548
2.17k
}
1549
1550
static void get_CP56Time(tvbuff_t* tvb, uint8_t* offset, proto_tree* iec104_header_tree)
1551
1.97k
{
1552
1.97k
  decode_CP56Time(tvb, offset, hf_cp56time, iec104_header_tree);
1553
1.97k
}
1554
1555
static void get_RangeStartCP56Time(tvbuff_t* tvb, uint8_t* offset, proto_tree* iec104_header_tree)
1556
103
{
1557
103
  decode_CP56Time(tvb, offset, hf_range_start_cp56time, iec104_header_tree);
1558
103
}
1559
1560
static void get_RangeStopCP56Time(tvbuff_t* tvb, uint8_t* offset, proto_tree* iec104_header_tree)
1561
102
{
1562
102
  decode_CP56Time(tvb, offset, hf_range_stop_cp56time, iec104_header_tree);
1563
102
}
1564
1565
/* ====================================================================
1566
   CP16Time2a: 7.2.6.20 Two octet binary time
1567
   ==================================================================== */
1568
static void get_CP16Time(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
1569
1.12k
{
1570
1.12k
  proto_tree_add_item(iec104_header_tree, hf_cp16time, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
1571
1.12k
  (*offset) += 2;
1572
1.12k
}
1573
1574
/* ====================================================================
1575
   Information object address (Identifier)
1576
   ASDU -> Inform Object #1 -> Information object address
1577
   ==================================================================== */
1578
static proto_item* get_InfoObjectAddress(uint32_t *asdu_info_obj_addr, tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree, unsigned ioa_len)
1579
7.46k
{
1580
7.46k
  proto_item* ti = NULL;
1581
1582
  /* Information object address */
1583
  /* Support both 16 and 24-bit IOA addresses */
1584
7.46k
  ti = proto_tree_add_item_ret_uint(iec104_header_tree, hf_ioa, tvb, *offset, ioa_len, ENC_LITTLE_ENDIAN, asdu_info_obj_addr);
1585
7.46k
  (*offset) += ioa_len;
1586
1587
7.46k
  return ti;
1588
7.46k
}
1589
1590
/* ====================================================================
1591
   TypeId length
1592
   ==================================================================== */
1593
static uint8_t get_TypeIdLength(uint8_t TypeId)
1594
2.67k
{
1595
2.67k
  uint8_t ret = 0;
1596
2.67k
  const td_asdu_length *item;
1597
1598
2.67k
  item = asdu_length;
1599
106k
  while (item->value)
1600
106k
  {
1601
106k
    if (item->value == TypeId)
1602
2.32k
    {
1603
2.32k
      ret = item->length;
1604
2.32k
      break;
1605
2.32k
    }
1606
104k
    item++;
1607
104k
  }
1608
1609
2.67k
  return ret;
1610
2.67k
}
1611
1612
/* ====================================================================
1613
   SIQ: 7.2.6.1 Single-point information (IEV 371-02-07) w quality descriptor
1614
   ==================================================================== */
1615
static void get_SIQ(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
1616
729
{
1617
729
  proto_item* ti;
1618
729
  proto_tree* siq_tree;
1619
1620
729
  ti = proto_tree_add_item(iec104_header_tree, hf_siq, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1621
729
  siq_tree = proto_item_add_subtree(ti, ett_siq);
1622
1623
729
  proto_tree_add_item(siq_tree, hf_siq_spi, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1624
729
  proto_tree_add_item(siq_tree, hf_siq_bl, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1625
729
  proto_tree_add_item(siq_tree, hf_siq_sb, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1626
729
  proto_tree_add_item(siq_tree, hf_siq_nt, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1627
729
  proto_tree_add_item(siq_tree, hf_siq_iv, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1628
1629
729
  (*offset)++;
1630
729
}
1631
1632
/* ====================================================================
1633
   DIQ: 7.2.6.2 Double-point information (IEV 371-02-08) w quality descriptor
1634
   ==================================================================== */
1635
static void get_DIQ(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
1636
687
{
1637
687
  proto_item* ti;
1638
687
  proto_tree* diq_tree;
1639
1640
687
  ti = proto_tree_add_item(iec104_header_tree, hf_diq, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1641
687
  diq_tree = proto_item_add_subtree(ti, ett_diq);
1642
1643
687
  proto_tree_add_item(diq_tree, hf_diq_dpi, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1644
687
  proto_tree_add_item(diq_tree, hf_diq_bl, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1645
687
  proto_tree_add_item(diq_tree, hf_diq_sb, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1646
687
  proto_tree_add_item(diq_tree, hf_diq_nt, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1647
687
  proto_tree_add_item(diq_tree, hf_diq_iv, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1648
1649
687
  (*offset)++;
1650
687
}
1651
1652
/* ====================================================================
1653
   QDS: 7.2.6.3 Quality descriptor (separate octet)
1654
   ==================================================================== */
1655
static void get_QDS(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
1656
2.14k
{
1657
2.14k
  proto_item* ti;
1658
2.14k
  proto_tree* qds_tree;
1659
1660
2.14k
  ti = proto_tree_add_item(iec104_header_tree, hf_qds, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1661
2.14k
  qds_tree = proto_item_add_subtree(ti, ett_qds);
1662
1663
2.14k
  proto_tree_add_item(qds_tree, hf_qds_ov, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1664
2.14k
  proto_tree_add_item(qds_tree, hf_qds_bl, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1665
2.14k
  proto_tree_add_item(qds_tree, hf_qds_sb, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1666
2.14k
  proto_tree_add_item(qds_tree, hf_qds_nt, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1667
2.14k
  proto_tree_add_item(qds_tree, hf_qds_iv, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1668
1669
2.14k
  (*offset)++;
1670
2.14k
}
1671
1672
/* ====================================================================
1673
   QDP: 7.2.6.4 Quality descriptor for events of protection equipment
1674
   (separate octet)
1675
   ==================================================================== */
1676
static void get_QDP(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
1677
510
{
1678
510
  proto_item* ti;
1679
510
  proto_tree* qdp_tree;
1680
1681
510
  ti = proto_tree_add_item(iec104_header_tree, hf_qdp, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1682
510
  qdp_tree = proto_item_add_subtree(ti, ett_qdp);
1683
1684
510
  proto_tree_add_item(qdp_tree, hf_qdp_ei, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1685
510
  proto_tree_add_item(qdp_tree, hf_qdp_bl, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1686
510
  proto_tree_add_item(qdp_tree, hf_qdp_sb, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1687
510
  proto_tree_add_item(qdp_tree, hf_qdp_nt, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1688
510
  proto_tree_add_item(qdp_tree, hf_qdp_iv, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1689
1690
510
  (*offset)++;
1691
510
}
1692
1693
/* ====================================================================
1694
   VTI: 7.2.6.5 Value with transient state indication
1695
   ==================================================================== */
1696
static void get_VTI(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
1697
584
{
1698
584
  proto_item* ti;
1699
584
  proto_tree* vti_tree;
1700
1701
584
  ti = proto_tree_add_item(iec104_header_tree, hf_vti, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1702
584
  vti_tree = proto_item_add_subtree(ti, ett_vti);
1703
1704
584
  proto_tree_add_item(vti_tree, hf_vti_v, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1705
584
  proto_tree_add_item(vti_tree, hf_vti_t, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1706
1707
584
  (*offset)++;
1708
584
}
1709
1710
/* ====================================================================
1711
   NVA: 7.2.6.6 Normalized value
1712
   ==================================================================== */
1713
static void get_NVA(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
1714
582
{
1715
582
  int16_t value;
1716
582
  float fvalue;
1717
1718
582
  value = tvb_get_letohis(tvb, *offset);
1719
582
  fvalue = (float)value / 32768;
1720
1721
  /* Normalized value F16[1..16]<-1..+1-2^-15> */
1722
582
  proto_tree_add_float_format_value(iec104_header_tree, hf_asdu_normval, tvb, *offset, 2, fvalue, "%." G_STRINGIFY(FLT_DIG) "g (%d)", fvalue, value);
1723
1724
582
  (*offset) += 2;
1725
582
}
1726
1727
static void get_NVAspt(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
1728
354
{
1729
354
  int16_t value;
1730
354
  float fvalue;
1731
1732
354
  value = tvb_get_letohis(tvb, *offset);
1733
354
  fvalue = (float)value / 32768;
1734
1735
  /* Normalized value F16[1..16]<-1..+1-2^-15> */
1736
354
  proto_tree_add_float_format_value(iec104_header_tree, hf_asdu_normval, tvb, *offset, 2, fvalue, "%." G_STRINGIFY(FLT_DIG) "g (%d)", fvalue, value);
1737
1738
354
  (*offset) += 2;
1739
354
}
1740
1741
/* ====================================================================
1742
   SVA: 7.2.6.7 Scaled value
1743
   ==================================================================== */
1744
static void get_SVA(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
1745
328
{
1746
  /* Scaled value I16[1..16]<-2^15..+2^15-1> */
1747
328
  proto_tree_add_item(iec104_header_tree, hf_asdu_scalval, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
1748
1749
328
  (*offset) += 2;
1750
328
}
1751
1752
static void get_SVAspt(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
1753
467
{
1754
  /* Scaled value I16[1..16]<-2^15..+2^15-1> */
1755
467
  proto_tree_add_item(iec104_header_tree, hf_asdu_scalval, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
1756
1757
467
  (*offset) += 2;
1758
467
}
1759
1760
/* ====================================================================
1761
   FLT: 7.2.6.8 Short floating point number
1762
   ==================================================================== */
1763
static void get_FLT(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
1764
350
{
1765
  /* --------  IEEE 754 float value */
1766
350
  proto_tree_add_item(iec104_header_tree, hf_asdu_float, tvb, *offset, 4, ENC_LITTLE_ENDIAN);
1767
1768
350
  (*offset) += 4;
1769
350
}
1770
1771
static void get_FLTspt(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
1772
272
{
1773
  /* --------  IEEE 754 float value */
1774
272
  proto_tree_add_item(iec104_header_tree, hf_asdu_float, tvb, *offset, 4, ENC_LITTLE_ENDIAN);
1775
1776
272
  (*offset) += 4;
1777
272
}
1778
1779
/* ====================================================================
1780
   BCR: 7.2.6.9 Binary counter reading
1781
   ==================================================================== */
1782
static void get_BCR(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
1783
414
{
1784
414
  proto_item* ti;
1785
414
  proto_tree* bcr_tree;
1786
1787
414
  ti = proto_tree_add_item(iec104_header_tree, hf_bcr, tvb, *offset, 4, ENC_LITTLE_ENDIAN);
1788
414
  bcr_tree = proto_item_add_subtree(ti, ett_vti);
1789
1790
414
  proto_tree_add_item(bcr_tree, hf_bcr_count, tvb, *offset, 4, ENC_LITTLE_ENDIAN);
1791
414
  (*offset) += 4;
1792
1793
414
  proto_tree_add_item(bcr_tree, hf_bcr_sq, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1794
414
  proto_tree_add_item(bcr_tree, hf_bcr_cy, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1795
414
  proto_tree_add_item(bcr_tree, hf_bcr_ca, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1796
414
  proto_tree_add_item(bcr_tree, hf_bcr_iv, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1797
414
  (*offset)++;
1798
414
}
1799
1800
/* ====================================================================
1801
   SEP: 7.2.6.10 Single event of protection equipment
1802
   ==================================================================== */
1803
static void get_SEP(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
1804
255
{
1805
255
  proto_item* ti;
1806
255
  proto_tree* sep_tree;
1807
1808
255
  ti = proto_tree_add_item(iec104_header_tree, hf_sep, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1809
255
  sep_tree = proto_item_add_subtree(ti, ett_sep);
1810
1811
255
  proto_tree_add_item(sep_tree, hf_sep_es, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1812
255
  proto_tree_add_item(sep_tree, hf_sep_ei, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1813
255
  proto_tree_add_item(sep_tree, hf_sep_bl, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1814
255
  proto_tree_add_item(sep_tree, hf_sep_sb, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1815
255
  proto_tree_add_item(sep_tree, hf_sep_nt, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1816
255
  proto_tree_add_item(sep_tree, hf_sep_iv, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1817
1818
255
  (*offset)++;
1819
255
}
1820
1821
/* ====================================================================
1822
   SPE: 7.2.6.11 Start events of protection equipment
1823
   ==================================================================== */
1824
static void get_SPE(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
1825
108
{
1826
108
  proto_item* ti;
1827
108
  proto_tree* spe_tree;
1828
1829
108
  ti = proto_tree_add_item(iec104_header_tree, hf_spe, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1830
108
  spe_tree = proto_item_add_subtree(ti, ett_spe);
1831
1832
108
  proto_tree_add_item(spe_tree, hf_spe_gs, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1833
108
  proto_tree_add_item(spe_tree, hf_spe_sl1, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1834
108
  proto_tree_add_item(spe_tree, hf_spe_sl2, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1835
108
  proto_tree_add_item(spe_tree, hf_spe_sl3, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1836
108
  proto_tree_add_item(spe_tree, hf_spe_sie, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1837
108
  proto_tree_add_item(spe_tree, hf_spe_srd, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1838
1839
108
  (*offset)++;
1840
108
}
1841
1842
/* ====================================================================
1843
   OCI: 7.2.6.12 Output circuit information of protection equipment
1844
   ==================================================================== */
1845
static void get_OCI(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
1846
402
{
1847
402
  proto_item* ti;
1848
402
  proto_tree* oci_tree;
1849
1850
402
  ti = proto_tree_add_item(iec104_header_tree, hf_oci, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1851
402
  oci_tree = proto_item_add_subtree(ti, ett_oci);
1852
1853
402
  proto_tree_add_item(oci_tree, hf_oci_gc, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1854
402
  proto_tree_add_item(oci_tree, hf_oci_cl1, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1855
402
  proto_tree_add_item(oci_tree, hf_oci_cl2, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1856
402
  proto_tree_add_item(oci_tree, hf_oci_cl3, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1857
1858
402
  (*offset)++;
1859
402
}
1860
1861
/* ====================================================================
1862
   BSI: 7.2.6.13 Binary state information (IEV 371-02-03) 32 bit
1863
   ==================================================================== */
1864
static void get_BSI(tvbuff_t* tvb, uint8_t* offset, proto_tree* iec104_header_tree)
1865
340
{
1866
340
  proto_tree_add_bits_item(iec104_header_tree, hf_asdu_bitstring, tvb, *offset * 8, 32, ENC_LITTLE_ENDIAN);
1867
1868
340
  (*offset) += 4;
1869
340
}
1870
1871
static void get_BSIspt(tvbuff_t* tvb, uint8_t* offset, proto_tree* iec104_header_tree)
1872
276
{
1873
276
  proto_tree_add_bits_item(iec104_header_tree, hf_asdu_bitstring, tvb, *offset * 8, 32, ENC_LITTLE_ENDIAN);
1874
1875
276
  (*offset) += 4;
1876
276
}
1877
1878
/* ====================================================================
1879
   FBP: 7.2.6.14 Fixed test bit pattern, two octets
1880
   ==================================================================== */
1881
static void get_FBP(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
1882
611
{
1883
611
  proto_tree_add_item(iec104_header_tree, hf_fbp, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
1884
1885
611
  (*offset) += 2;
1886
611
}
1887
1888
/* ====================================================================
1889
   SCO: 7.2.6.15 Single Command (IEV 371-03-02)
1890
   ==================================================================== */
1891
static void get_SCO(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
1892
192
{
1893
192
  proto_item* ti;
1894
192
  proto_tree* sco_tree;
1895
1896
192
  ti = proto_tree_add_item(iec104_header_tree, hf_sco, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1897
192
  sco_tree = proto_item_add_subtree(ti, ett_sco);
1898
1899
192
  proto_tree_add_item(sco_tree, hf_sco_on, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1900
192
  proto_tree_add_item(sco_tree, hf_sco_qu, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1901
192
  proto_tree_add_item(sco_tree, hf_sco_se, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1902
1903
192
  (*offset)++;
1904
192
}
1905
1906
/* ====================================================================
1907
   DCO: 7.2.6.16 Double Command (IEV 371-03-03)
1908
   ==================================================================== */
1909
static void get_DCO(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
1910
606
{
1911
606
  proto_item* ti;
1912
606
  proto_tree* dco_tree;
1913
1914
606
  ti = proto_tree_add_item(iec104_header_tree, hf_dco, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1915
606
  dco_tree = proto_item_add_subtree(ti, ett_dco);
1916
1917
606
  proto_tree_add_item(dco_tree, hf_dco_on, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1918
606
  proto_tree_add_item(dco_tree, hf_dco_qu, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1919
606
  proto_tree_add_item(dco_tree, hf_dco_se, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1920
1921
606
  (*offset)++;
1922
606
}
1923
1924
/* ====================================================================
1925
   RCO: 7.2.6.17 Regulating step command (IEV 371-03-13)
1926
   ==================================================================== */
1927
static void get_RCO(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
1928
141
{
1929
141
  proto_item* ti;
1930
141
  proto_tree* rco_tree;
1931
1932
141
  ti = proto_tree_add_item(iec104_header_tree, hf_rco, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1933
141
  rco_tree = proto_item_add_subtree(ti, ett_rco);
1934
1935
141
  proto_tree_add_item(rco_tree, hf_rco_up, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1936
141
  proto_tree_add_item(rco_tree, hf_rco_qu, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1937
141
  proto_tree_add_item(rco_tree, hf_rco_se, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1938
1939
141
  (*offset)++;
1940
141
}
1941
1942
/* ====================================================================
1943
   COI: 7.2.6.21 Cause of initialisation
1944
   ==================================================================== */
1945
static void get_COI(tvbuff_t* tvb, uint8_t* offset, proto_tree* iec104_header_tree)
1946
126
{
1947
126
  proto_item* ti;
1948
126
  proto_tree* coi_tree;
1949
1950
126
  ti = proto_tree_add_item(iec104_header_tree, hf_coi, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1951
126
  coi_tree = proto_item_add_subtree(ti, ett_coi);
1952
1953
126
  proto_tree_add_item(coi_tree, hf_coi_r, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1954
126
  proto_tree_add_item(coi_tree, hf_coi_i, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1955
1956
126
  (*offset)++;
1957
126
}
1958
1959
/* ====================================================================
1960
   QOI: 7.2.6.22 Qualifier of interrogation
1961
   ==================================================================== */
1962
static void get_QOI(tvbuff_t* tvb, uint8_t* offset, proto_tree* iec104_header_tree)
1963
433
{
1964
433
  proto_tree_add_item(iec104_header_tree, hf_qoi, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1965
1966
433
  (*offset)++;
1967
433
}
1968
1969
/* ====================================================================
1970
   QCC: 7.2.6.23 Qualifier of counter interrogation
1971
   ==================================================================== */
1972
static void get_QCC(tvbuff_t* tvb, uint8_t* offset, proto_tree* iec104_header_tree)
1973
402
{
1974
402
  proto_item* ti;
1975
402
  proto_tree* qcc_tree;
1976
1977
402
  ti = proto_tree_add_item(iec104_header_tree, hf_qcc, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1978
402
  qcc_tree = proto_item_add_subtree(ti, ett_qcc);
1979
1980
402
  proto_tree_add_item(qcc_tree, hf_qcc_rqt, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1981
402
  proto_tree_add_item(qcc_tree, hf_qcc_frz, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1982
1983
402
  (*offset)++;
1984
402
}
1985
1986
/* ====================================================================
1987
   QPM: 7.2.6.24 Qualifier of parameter of measured value
1988
   ==================================================================== */
1989
static void get_QPM(tvbuff_t* tvb, uint8_t* offset, proto_tree* iec104_header_tree)
1990
284
{
1991
284
  proto_item* ti;
1992
284
  proto_tree* qpm_tree;
1993
1994
284
  ti = proto_tree_add_item(iec104_header_tree, hf_qpm, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1995
284
  qpm_tree = proto_item_add_subtree(ti, ett_qpm);
1996
1997
284
  proto_tree_add_item(qpm_tree, hf_qpm_kpa, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1998
284
  proto_tree_add_item(qpm_tree, hf_qpm_lpc, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1999
284
  proto_tree_add_item(qpm_tree, hf_qpm_pop, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2000
2001
284
  (*offset)++;
2002
284
}
2003
2004
/* ====================================================================
2005
   QPA: 7.2.6.25 Qualifier of parameter activation
2006
   ==================================================================== */
2007
static void get_QPA(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
2008
291
{
2009
291
  proto_tree_add_item(iec104_header_tree, hf_qpa, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2010
2011
291
  (*offset)++;
2012
291
}
2013
2014
/* ====================================================================
2015
   QRP: 7.2.6.27 Qualifier of reset process command
2016
   ==================================================================== */
2017
static void get_QRP(tvbuff_t* tvb, uint8_t* offset, proto_tree* iec104_header_tree)
2018
183
{
2019
183
  proto_tree_add_item(iec104_header_tree, hf_qrp, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2020
2021
183
  (*offset)++;
2022
183
}
2023
2024
/* ====================================================================
2025
   FRQ: 7.2.6.28 File request qualifier
2026
   ==================================================================== */
2027
static void get_FRQ(tvbuff_t* tvb, uint8_t* offset, proto_tree* iec104_header_tree)
2028
27
{
2029
27
  proto_item* ti;
2030
27
  proto_tree* frq_tree;
2031
2032
27
  ti = proto_tree_add_item(iec104_header_tree, hf_frq, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2033
27
  frq_tree = proto_item_add_subtree(ti, ett_frq);
2034
2035
27
  proto_tree_add_item(frq_tree, hf_frq_confirm, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2036
27
  proto_tree_add_item(frq_tree, hf_frq_qualifier, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2037
2038
27
  (*offset)++;
2039
27
}
2040
2041
/* ====================================================================
2042
   SRQ: 7.2.6.29 Section ready qualifier
2043
   ==================================================================== */
2044
static void get_SRQ(tvbuff_t* tvb, uint8_t* offset, proto_tree* iec104_header_tree)
2045
87
{
2046
87
  proto_item* ti;
2047
87
  proto_tree* srq_tree;
2048
2049
87
  ti = proto_tree_add_item(iec104_header_tree, hf_srq, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2050
87
  srq_tree = proto_item_add_subtree(ti, ett_srq);
2051
2052
87
  proto_tree_add_item(srq_tree, hf_srq_ready, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2053
87
  proto_tree_add_item(srq_tree, hf_srq_qualifier, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2054
2055
87
  (*offset)++;
2056
87
}
2057
2058
/* ====================================================================
2059
   SCQ: 7.2.6.30 Select and call qualifier
2060
   ==================================================================== */
2061
static void get_SCQ(tvbuff_t* tvb, uint8_t* offset, proto_tree* iec104_header_tree)
2062
77
{
2063
77
  proto_item* ti;
2064
77
  proto_tree* scq_tree;
2065
2066
77
  ti = proto_tree_add_item(iec104_header_tree, hf_scq, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2067
77
  scq_tree = proto_item_add_subtree(ti, ett_scq);
2068
2069
77
  proto_tree_add_item(scq_tree, hf_scq_select, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2070
77
  proto_tree_add_item(scq_tree, hf_scq_qualifier, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2071
2072
77
  (*offset)++;
2073
77
}
2074
2075
/* ====================================================================
2076
   LSQ: 7.2.6.31 Last section or segment qualifier
2077
   ==================================================================== */
2078
static void get_LSQ(tvbuff_t* tvb, uint8_t* offset, proto_tree* iec104_header_tree)
2079
147
{
2080
147
  proto_tree_add_item(iec104_header_tree, hf_lsq, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2081
147
  (*offset)++;
2082
147
}
2083
2084
/* ====================================================================
2085
   AFQ: 7.2.6.32 Acknowledge file or section qualifier
2086
   ==================================================================== */
2087
static void get_AFQ(tvbuff_t* tvb, uint8_t* offset, proto_tree* iec104_header_tree)
2088
290
{
2089
290
  proto_item* ti;
2090
290
  proto_tree* afq_tree;
2091
2092
290
  ti = proto_tree_add_item(iec104_header_tree, hf_afq, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2093
290
  afq_tree = proto_item_add_subtree(ti, ett_afq);
2094
2095
290
  proto_tree_add_item(afq_tree, hf_afq_ack, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2096
290
  proto_tree_add_item(afq_tree, hf_afq_qualifier, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2097
2098
290
  (*offset)++;
2099
290
}
2100
2101
/* ====================================================================
2102
   NOF: 7.2.6.33 Name of file
2103
   ==================================================================== */
2104
static void get_NOF(tvbuff_t* tvb, uint8_t* offset, proto_tree* iec104_header_tree)
2105
754
{
2106
754
  proto_tree_add_item(iec104_header_tree, hf_nof, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
2107
754
  (*offset) += 2;
2108
754
}
2109
2110
/* ====================================================================
2111
   NOS: 7.2.6.34 Name of section
2112
   ==================================================================== */
2113
static void get_NOS(tvbuff_t* tvb, uint8_t* offset, proto_tree* iec104_header_tree)
2114
604
{
2115
604
  proto_tree_add_item(iec104_header_tree, hf_nos, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2116
604
  (*offset) ++;
2117
604
}
2118
2119
/* ====================================================================
2120
   LOF: 7.2.6.35 Length of file
2121
   ==================================================================== */
2122
static void get_LOF(tvbuff_t* tvb, uint8_t* offset, proto_tree* iec104_header_tree)
2123
132
{
2124
132
  proto_tree_add_item(iec104_header_tree, hf_lof, tvb, *offset, 3, ENC_LITTLE_ENDIAN);
2125
132
  (*offset) += 3;
2126
132
}
2127
2128
/* ====================================================================
2129
   LOS: 7.2.6.36 Length of segment
2130
   ==================================================================== */
2131
static uint8_t get_LOS(tvbuff_t* tvb, uint8_t* offset, proto_tree* iec104_header_tree)
2132
1
{
2133
1
  uint8_t value = tvb_get_uint8(tvb, *offset);
2134
2135
1
  proto_tree_add_item(iec104_header_tree, hf_los, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2136
2137
1
  (*offset)++;
2138
1
  return value;
2139
1
}
2140
2141
/* ====================================================================
2142
   CHS: 7.2.6.37 Checksum
2143
   ==================================================================== */
2144
static void get_CHS(tvbuff_t* tvb, uint8_t* offset, proto_tree* iec104_header_tree)
2145
145
{
2146
145
  proto_tree_add_item(iec104_header_tree, hf_chs, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2147
145
  (*offset)++;
2148
145
}
2149
2150
/* ====================================================================
2151
   SOF: 7.2.6.38 Status of file
2152
   ==================================================================== */
2153
static void get_SOF(tvbuff_t* tvb, uint8_t* offset, proto_tree* iec104_header_tree)
2154
18
{
2155
18
  proto_item* ti;
2156
18
  proto_tree* sof_tree;
2157
2158
18
  ti = proto_tree_add_item(iec104_header_tree, hf_sof, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2159
18
  sof_tree = proto_item_add_subtree(ti, ett_sof);
2160
2161
18
  proto_tree_add_item(sof_tree, hf_sof_status, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2162
18
  proto_tree_add_item(sof_tree, hf_sof_lfd, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2163
18
  proto_tree_add_item(sof_tree, hf_sof_for, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2164
18
  proto_tree_add_item(sof_tree, hf_sof_fa, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2165
2166
18
  (*offset)++;
2167
18
}
2168
2169
/* ====================================================================
2170
   QOS: 7.2.6.39 Qualifier Of Set-point command
2171
   ==================================================================== */
2172
static void get_QOS(tvbuff_t* tvb, uint8_t* offset, proto_tree* iec104_header_tree)
2173
1.08k
{
2174
1.08k
  proto_item* ti;
2175
1.08k
  proto_tree* qos_tree;
2176
2177
1.08k
  ti = proto_tree_add_item(iec104_header_tree, hf_qos, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2178
1.08k
  qos_tree = proto_item_add_subtree(ti, ett_qos);
2179
2180
1.08k
  proto_tree_add_item(qos_tree, hf_qos_ql, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2181
1.08k
  proto_tree_add_item(qos_tree, hf_qos_se, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2182
2183
1.08k
  (*offset)++;
2184
1.08k
}
2185
2186
/* ====================================================================
2187
   SCD: 7.2.6.40 Status and status change detection
2188
   ==================================================================== */
2189
static void get_SCD(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
2190
275
{
2191
275
  proto_item* ti;
2192
275
  proto_tree* scd_tree;
2193
2194
275
  ti = proto_tree_add_item(iec104_header_tree, hf_scd, tvb, *offset, 4, ENC_LITTLE_ENDIAN);
2195
275
  scd_tree = proto_item_add_subtree(ti, ett_scd);
2196
2197
275
  proto_tree_add_bits_item(scd_tree, hf_scd_st, tvb, *offset * 8, 16, ENC_LITTLE_ENDIAN);
2198
275
  (*offset) += 2;
2199
2200
275
  proto_tree_add_bits_item(scd_tree, hf_scd_cd, tvb, *offset * 8, 16, ENC_LITTLE_ENDIAN);
2201
275
  (*offset) += 2;
2202
275
}
2203
2204
/* ====================================================================
2205
   TSC: Test sequence counter
2206
   ==================================================================== */
2207
static void get_TSC(tvbuff_t* tvb, uint8_t* offset, proto_tree* iec104_header_tree)
2208
75
{
2209
75
  proto_tree_add_item(iec104_header_tree, hf_asdu_tsc, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
2210
2211
75
  (*offset) += 2;
2212
75
}
2213
2214
/* ====================================================================
2215
   SEG: Segment data
2216
   ==================================================================== */
2217
static void get_SEG(tvbuff_t* tvb, uint8_t* offset, proto_tree* iec104_header_tree, int length)
2218
1
{
2219
1
  proto_tree_add_item(iec104_header_tree, hf_segment_data, tvb, *offset, length, ENC_NA);
2220
1
  (*offset) += length;
2221
1
}
2222
2223
/* ====================================================================
2224
   USR: User Number
2225
   ==================================================================== */
2226
static void get_USR(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
2227
149
{
2228
149
  proto_tree_add_item(iec104_header_tree, hf_usr, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
2229
2230
149
  (*offset) += 2;
2231
149
}
2232
2233
/* ====================================================================
2234
   MAL: MAC algorithm
2235
   ==================================================================== */
2236
static void get_MAL(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
2237
8
{
2238
8
  proto_tree_add_item(iec104_header_tree, hf_mal, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2239
2240
8
  (*offset)++;
2241
8
}
2242
2243
/* ====================================================================
2244
   RSC: Reason for challenge
2245
   ==================================================================== */
2246
static void get_RSC(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
2247
8
{
2248
8
  proto_tree_add_item(iec104_header_tree, hf_rsc, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2249
2250
8
  (*offset)++;
2251
8
}
2252
2253
/* ====================================================================
2254
   CSQ: Challenge sequence number
2255
   ==================================================================== */
2256
static void get_CSQ(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
2257
119
{
2258
119
  proto_tree_add_item(iec104_header_tree, hf_csq, tvb, *offset, 4, ENC_LITTLE_ENDIAN);
2259
2260
119
  (*offset) += 4;
2261
119
}
2262
2263
/* ====================================================================
2264
   KSQ: Key change sequence number
2265
   ==================================================================== */
2266
static void get_KSQ(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
2267
31
{
2268
31
  proto_tree_add_item(iec104_header_tree, hf_ksq, tvb, *offset, 4, ENC_LITTLE_ENDIAN);
2269
2270
31
  (*offset) += 4;
2271
31
}
2272
2273
/* ====================================================================
2274
   KWA: Key wrap algorithm
2275
   ==================================================================== */
2276
static void get_KWA(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
2277
29
{
2278
29
  proto_tree_add_item(iec104_header_tree, hf_kwa, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2279
2280
29
  (*offset)++;
2281
29
}
2282
2283
/* ====================================================================
2284
   KST: Key status
2285
   ==================================================================== */
2286
static void get_KST(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
2287
29
{
2288
29
  proto_tree_add_item(iec104_header_tree, hf_kst, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2289
2290
29
  (*offset)++;
2291
29
}
2292
2293
/* ====================================================================
2294
   HLN: MAC length
2295
   ==================================================================== */
2296
static uint16_t get_HLN(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
2297
19
{
2298
19
  uint16_t value = tvb_get_letohs(tvb, *offset);
2299
2300
19
  proto_tree_add_item(iec104_header_tree, hf_hln, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
2301
2302
19
  (*offset) += 2;
2303
19
  return value;
2304
19
}
2305
2306
/* ====================================================================
2307
   HAL: MAC algorithm
2308
   ==================================================================== */
2309
static uint8_t get_HAL(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
2310
29
{
2311
29
  uint8_t hal = tvb_get_uint8(tvb, *offset);
2312
29
  proto_tree_add_item(iec104_header_tree, hf_hal, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2313
2314
29
  (*offset)++;
2315
29
  switch (hal)
2316
29
  {
2317
0
    case 3: /* HMAC-SHA-256 truncated to 8 octets (serial) */
2318
0
      return 8;
2319
0
    case 4: /* HMAC-SHA-256 truncated to 16 octets (networked) */
2320
0
      return 16;
2321
0
    case 6: /* AES-GMAC (output is 12 octets) */
2322
0
      return 12;
2323
29
  }
2324
29
  return 0;
2325
29
}
2326
2327
/* ====================================================================
2328
   CLN: Challenge data length
2329
   ==================================================================== */
2330
static uint16_t get_CLN(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
2331
37
{
2332
37
  uint16_t value = tvb_get_letohs(tvb, *offset);
2333
2334
37
  proto_tree_add_item(iec104_header_tree, hf_cln, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
2335
2336
37
  (*offset) += 2;
2337
37
  return value;
2338
37
}
2339
2340
/* ====================================================================
2341
   WKL: Wrapped key data length
2342
   ==================================================================== */
2343
static uint16_t get_WKL(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
2344
2
{
2345
2
  uint16_t value = tvb_get_letohs(tvb, *offset);
2346
2347
2
  proto_tree_add_item(iec104_header_tree, hf_wkl, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
2348
2349
2
  (*offset) += 2;
2350
2
  return value;
2351
2
}
2352
2353
/* ====================================================================
2354
   Pseudo-random challenge data
2355
   ==================================================================== */
2356
static void get_PRCD(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree, int length)
2357
37
{
2358
37
  proto_tree_add_item(iec104_header_tree, hf_prcd_raw_data, tvb, *offset, length, ENC_NA);
2359
37
  (*offset) += length;
2360
37
}
2361
2362
/* ====================================================================
2363
   MAC value
2364
   ==================================================================== */
2365
static void get_HMAC(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree, int length)
2366
55
{
2367
55
  if (length)
2368
38
  {
2369
38
    proto_tree_add_item(iec104_header_tree, hf_hmac_raw_data, tvb, *offset, length, ENC_NA);
2370
38
    (*offset) += length;
2371
38
  }
2372
55
}
2373
2374
/* ====================================================================
2375
   Wrapped key data
2376
   ==================================================================== */
2377
static void get_WKD(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree, int length)
2378
2
{
2379
2
  proto_tree_add_item(iec104_header_tree, hf_wkd_raw_data, tvb, *offset, length, ENC_NA);
2380
2
  (*offset) += length;
2381
2
}
2382
2383
/* ====================================================================
2384
   AID: Association ID
2385
   ==================================================================== */
2386
static void get_AID(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
2387
82
{
2388
82
  proto_tree_add_item(iec104_header_tree, hf_aid, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
2389
2390
82
  (*offset) += 2;
2391
82
}
2392
2393
/* ====================================================================
2394
   ERR: Error code
2395
   ==================================================================== */
2396
static void get_ERR(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
2397
64
{
2398
64
  proto_tree_add_item(iec104_header_tree, hf_err, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2399
2400
64
  (*offset)++;
2401
64
}
2402
2403
/* ====================================================================
2404
   ETM: Error time stamp (7-octet binary time)
2405
   ==================================================================== */
2406
static void get_ETM(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
2407
64
{
2408
64
  uint16_t ms;
2409
64
  uint8_t value;
2410
64
  uint8_t su;
2411
64
  struct tm tm;
2412
64
  nstime_t  datetime;
2413
64
  proto_item* ti;
2414
64
  proto_tree* etm_tree;
2415
2416
64
  ms = tvb_get_letohs(tvb, *offset);
2417
64
  tm.tm_sec = ms / 1000;
2418
64
  datetime.nsecs = (ms % 1000) * 1000000;
2419
64
  (*offset) += 2;
2420
2421
64
  value = tvb_get_uint8(tvb, *offset);
2422
64
  tm.tm_min = value & 0x3F;
2423
64
  (*offset)++;
2424
2425
64
  value = tvb_get_uint8(tvb, *offset);
2426
64
  tm.tm_hour = value & 0x1F;
2427
64
  su = value & 0x80;
2428
64
  (*offset)++;
2429
2430
64
  value = tvb_get_uint8(tvb, *offset);
2431
64
  tm.tm_mday = value & 0x1F;
2432
64
  (*offset)++;
2433
2434
64
  value = tvb_get_uint8(tvb, *offset);
2435
64
  tm.tm_mon = (value & 0x0F) - 1;
2436
64
  (*offset)++;
2437
2438
64
  value = tvb_get_uint8(tvb, *offset);
2439
64
  tm.tm_year = value & 0x7F;
2440
64
  if (tm.tm_year < 70)
2441
39
    tm.tm_year += 100;
2442
2443
64
  (*offset)++;
2444
2445
64
  if (su)
2446
30
    tm.tm_isdst = 1;
2447
34
  else
2448
34
    tm.tm_isdst = -1; /* there's no info on whether DST was in force; assume it's
2449
           * the same as currently */
2450
2451
64
  datetime.secs = mktime(&tm);
2452
2453
64
  (*offset) -= 7;
2454
2455
64
  ti = proto_tree_add_time(iec104_header_tree, hf_etm, tvb, *offset, 7, &datetime);
2456
64
  etm_tree = proto_item_add_subtree(ti, ett_etm);
2457
2458
64
  proto_tree_add_item(etm_tree, hf_etm_ms, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
2459
64
  (*offset) += 2;
2460
2461
64
  proto_tree_add_item(etm_tree, hf_etm_min, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2462
64
  proto_tree_add_item(etm_tree, hf_etm_iv, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2463
64
  (*offset)++;
2464
2465
64
  proto_tree_add_item(etm_tree, hf_etm_hour, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2466
64
  proto_tree_add_item(etm_tree, hf_etm_su, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2467
64
  (*offset)++;
2468
2469
64
  proto_tree_add_item(etm_tree, hf_etm_day, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2470
64
  proto_tree_add_item(etm_tree, hf_etm_dow, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2471
64
  (*offset)++;
2472
2473
64
  proto_tree_add_item(etm_tree, hf_etm_month, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2474
64
  (*offset)++;
2475
2476
64
  proto_tree_add_item(etm_tree, hf_etm_year, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2477
64
  (*offset)++;
2478
64
}
2479
2480
/* ====================================================================
2481
   ELN: Error length
2482
   ==================================================================== */
2483
static uint16_t get_ELN(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
2484
64
{
2485
64
  uint16_t value = tvb_get_letohs(tvb, *offset);
2486
64
  proto_tree_add_item(iec104_header_tree, hf_eln, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
2487
2488
64
  (*offset) += 2;
2489
64
  return value;
2490
64
}
2491
2492
/* ====================================================================
2493
   Error text
2494
   ==================================================================== */
2495
static void get_ErrorText(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree, int length)
2496
64
{
2497
64
  if (length)
2498
44
  {
2499
44
    proto_tree_add_item(iec104_header_tree, hf_error_text, tvb, *offset, length, ENC_UTF_8);
2500
44
    (*offset) += length;
2501
44
  }
2502
64
}
2503
2504
/* .... end Misc. functions for dissection of signal values */
2505
2506
2507
/* Find the IEC60870-5-104 APDU (APDU=APCI+ASDU) length.
2508
Includes possible tvb_length-1 bytes that don't form an APDU */
2509
static unsigned get_iec104apdu_len(packet_info *pinfo _U_, tvbuff_t *tvb,
2510
                                int offset, void *data _U_)
2511
3.23k
{
2512
3.23k
  uint8_t Val;
2513
3.23k
  uint32_t Off;
2514
2515
131k
  for (Off = 0; Off <= tvb_reported_length(tvb) - 2; Off++) {
2516
131k
    Val = tvb_get_uint8(tvb, offset + Off);
2517
131k
    if (Val == APCI_START) {
2518
2.95k
      return (unsigned)(Off + tvb_get_uint8(tvb, offset + Off + 1) + 2);
2519
2.95k
    }
2520
131k
  }
2521
2522
286
  return (unsigned)(tvb_reported_length(tvb));
2523
3.23k
}
2524
2525
/* Dissect reassembled extended IEC60870-5-7 secure authentication ASDUs */
2526
// NOLINTNEXTLINE(misc-no-recursion)
2527
static int dissect_iec60870_asdu_segment(tvbuff_t *tvb, packet_info *pinfo, proto_tree *it_segment_tree, uint8_t type_id, struct asdu_parms* parms)
2528
164
{
2529
164
  unsigned Len = tvb_reported_length(tvb);
2530
164
  uint8_t offset = 0;
2531
164
  uint8_t i, encapsulated_type, encapsulated_length;
2532
164
  uint16_t j;
2533
164
  tvbuff_t *encapsulated_tvb = NULL;
2534
2535
164
  switch (type_id) {
2536
8
    case S_CH_NA_1: /* 81    authentication challenge */
2537
8
      get_CSQ(tvb, &offset, it_segment_tree);
2538
8
      get_USR(tvb, &offset, it_segment_tree);
2539
8
      get_MAL(tvb, &offset, it_segment_tree);
2540
8
      get_RSC(tvb, &offset, it_segment_tree);
2541
8
      j = get_CLN(tvb, &offset, it_segment_tree);
2542
8
      get_PRCD(tvb, &offset, it_segment_tree, j);
2543
8
      break;
2544
20
    case S_RP_NA_1: /* 82    authentication reply */
2545
20
      get_CSQ(tvb, &offset, it_segment_tree);
2546
20
      get_USR(tvb, &offset, it_segment_tree);
2547
20
      j = get_HLN(tvb, &offset, it_segment_tree);
2548
20
      get_HMAC(tvb, &offset, it_segment_tree, j);
2549
20
      break;
2550
41
    case S_AR_NA_1: /* 83    Aggressive mode authentication request */
2551
41
      encapsulated_type = tvb_get_uint8(tvb, offset);
2552
41
      encapsulated_length = 1 + 1 + parms->cot_len + parms->asdu_addr_len + parms->ioa_len + get_TypeIdLength(encapsulated_type);
2553
41
      encapsulated_tvb = tvb_new_subset_length(tvb, offset, encapsulated_length);
2554
41
      dissect_iec60870_asdu(encapsulated_tvb, pinfo, it_segment_tree, parms);
2555
41
      offset = tvb_reported_length(encapsulated_tvb);
2556
41
      get_CSQ(tvb, &offset, it_segment_tree);
2557
41
      get_USR(tvb, &offset, it_segment_tree);
2558
41
      get_HMAC(tvb, &offset, it_segment_tree, tvb_reported_length_remaining(tvb, offset));
2559
41
      break;
2560
29
    case S_KS_NA_1: /* 85    session key status */
2561
29
      get_KSQ(tvb, &offset, it_segment_tree);
2562
29
      get_USR(tvb, &offset, it_segment_tree);
2563
29
      get_KWA(tvb, &offset, it_segment_tree);
2564
29
      get_KST(tvb, &offset, it_segment_tree);
2565
29
      i = get_HAL(tvb, &offset, it_segment_tree);
2566
29
      j = get_CLN(tvb, &offset, it_segment_tree);
2567
29
      get_PRCD(tvb, &offset, it_segment_tree, j);
2568
29
      get_HMAC(tvb, &offset, it_segment_tree, i);
2569
29
      break;
2570
2
    case S_KC_NA_1: /* 86    session key change */
2571
2
      get_KSQ(tvb, &offset, it_segment_tree);
2572
2
      get_USR(tvb, &offset, it_segment_tree);
2573
2
      j = get_WKL(tvb, &offset, it_segment_tree);
2574
2
      get_WKD(tvb, &offset, it_segment_tree, j);
2575
2
      break;
2576
64
    case S_ER_NA_1: /* 87    Authentication error */
2577
64
      get_CSQ(tvb, &offset, it_segment_tree);
2578
64
      get_USR(tvb, &offset, it_segment_tree);
2579
64
      get_AID(tvb, &offset, it_segment_tree);
2580
64
      get_ERR(tvb, &offset, it_segment_tree);
2581
64
      get_ETM(tvb, &offset, it_segment_tree);
2582
64
      j = get_ELN(tvb, &offset, it_segment_tree);
2583
64
      get_ErrorText(tvb, &offset, it_segment_tree, j);
2584
64
      break;
2585
0
    default:
2586
0
      proto_tree_add_item(it_segment_tree, hf_ioa, tvb, offset, 3, ENC_LITTLE_ENDIAN);
2587
0
      offset += 3;
2588
2589
0
      if (Len - offset > 0)
2590
0
        proto_tree_add_item(it_segment_tree, hf_asdu_raw_data, tvb, offset, Len - offset, ENC_NA);
2591
0
      offset = Len;
2592
2593
0
      break;
2594
164
  }
2595
  /* check correct apdu length */
2596
67
  if (Len != offset) {
2597
41
    expert_add_info(pinfo, it_segment_tree, &ei_iec104_apdu_invalid_len);
2598
41
    return offset;
2599
41
  }
2600
2601
26
  return Len;
2602
67
}
2603
2604
/* Handle segmentation of IEC60870-5-7 secure authentication APDUs */
2605
// NOLINTNEXTLINE(misc-no-recursion)
2606
static void dissect_iec60870_segment(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, uint8_t *offset, uint8_t typeId, struct asdu_parms* parms)
2607
357
{
2608
357
  uint32_t msg_seqid = 0;
2609
2610
357
  bool final_segment = tvb_get_bits8(tvb, (*offset << 3) + 0, 1) == 1;
2611
2612
357
  proto_tree_add_item(tree, hf_asn_fin, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2613
357
  proto_tree_add_item(tree, hf_asn_fir, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2614
357
  proto_tree_add_item(tree, hf_asn, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2615
2616
357
  (*offset)++;
2617
2618
357
  tvbuff_t *next_tvb = tvb_new_subset_remaining(tvb, *offset);
2619
357
  uint32_t fragment_length = tvb_captured_length(next_tvb);
2620
357
  if (!final_segment) {
2621
193
    col_append_fstr(pinfo->cinfo, COL_INFO, " [ASDU fragment, %u byte%s]",
2622
193
        fragment_length, plurality(fragment_length, "", "s"));
2623
193
  } else {
2624
164
    col_append_str(pinfo->cinfo, COL_INFO, " EOA");
2625
164
  }
2626
2627
357
  fragment_head *fd_head = fragment_add_seq_next(&iec60870_reassemble_table, next_tvb, 0, pinfo,msg_seqid, NULL,
2628
357
                   fragment_length, !final_segment);
2629
2630
357
  if (fd_head && fd_head->next) {
2631
    /* don't use -1 if fragment length is zero (throws Exception) */
2632
49
    proto_tree_add_bytes_format(tree, hf_iec60870_segment_data, tvb, *offset, (fragment_length) ? -1 : 0,
2633
49
              NULL, "ASDU segment data (%u byte%s)", fragment_length,
2634
49
              plurality(fragment_length, "", "s"));
2635
2636
49
    if (final_segment) {
2637
49
      next_tvb = process_reassembled_data(next_tvb, *offset, pinfo,
2638
49
                  "Reassembled ASDU", fd_head,
2639
49
                  &iec60870_frag_items, NULL, tree);
2640
49
    } else if (pinfo->num != fd_head->reassembled_in) {
2641
      /* Add a "Reassembled in" link if not reassembled in this frame */
2642
0
      proto_tree_add_uint(tree, *(iec60870_frag_items.hf_reassembled_in),
2643
0
              next_tvb, 0, 0, fd_head->reassembled_in);
2644
0
    }
2645
49
    pinfo->fragmented = !final_segment;
2646
49
  }
2647
2648
357
  if (final_segment) {
2649
164
    dissect_iec60870_asdu_segment(next_tvb, pinfo, tree, typeId, parms);
2650
164
  }
2651
2652
357
  *offset += tvb_captured_length_remaining(tvb, *offset);
2653
357
}
2654
2655
/* Is is called twice: For 'Packet List' and for 'Packet Details' */
2656
/* This dissection is shared by the IEC '101 and '104 dissectors */
2657
// NOLINTNEXTLINE(misc-no-recursion)
2658
static int dissect_iec60870_asdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2659
2.64k
{
2660
2.64k
  unsigned Len = tvb_reported_length(tvb);
2661
2.64k
  uint8_t Bytex;
2662
2.64k
  const char *cause_str;
2663
2.64k
  size_t Ind;
2664
2.64k
  struct asduheader asduh = { .OA = 0, .Addr = 0, .IOA = 0};
2665
2.64k
  struct asdu_parms* parms = (struct asdu_parms*)data;
2666
2.64k
  proto_item *it104;
2667
2.64k
  proto_tree *it104tree;
2668
2.64k
  wmem_strbuf_t * res;
2669
2670
2.64k
  uint8_t offset = 0;  /* byte offset, signal dissection */
2671
2.64k
  uint8_t i;
2672
2.64k
  uint8_t seg_len;
2673
2.64k
  uint32_t asdu_info_obj_addr = 0;
2674
2.64k
  proto_item * itSignal = NULL;
2675
2.64k
  proto_tree * trSignal;
2676
2677
2.64k
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "IEC 60870-5 ASDU");
2678
2679
2.64k
  it104 = proto_tree_add_item(tree, proto_iec60870_asdu, tvb, offset, -1, ENC_NA);
2680
2.64k
  it104tree = proto_item_add_subtree(it104, ett_asdu);
2681
2682
2.64k
  res = wmem_strbuf_create(pinfo->pool);
2683
2684
  /* Type identification */
2685
2.64k
  asduh.TypeId = tvb_get_uint8(tvb, offset);
2686
2.64k
  proto_tree_add_item(it104tree, hf_typeid, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2687
2.64k
  asduh.DataLength = get_TypeIdLength(asduh.TypeId);
2688
2.64k
  offset += 1;
2689
2690
  /* Variable structure qualifier */
2691
2.64k
  Bytex = tvb_get_uint8(tvb, 1);
2692
2.64k
  asduh.SQ = Bytex & F_SQ;
2693
2.64k
  asduh.NumIx = Bytex & 0x7F;
2694
2.64k
  proto_tree_add_item(it104tree, hf_sq, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2695
2.64k
  proto_tree_add_item(it104tree, hf_numix, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2696
2.64k
  offset += 1;
2697
2698
  /* Cause of transmission */
2699
2.64k
  asduh.TNCause = tvb_get_uint8(tvb, offset);
2700
2.64k
  proto_tree_add_item(it104tree, hf_causetx, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2701
2.64k
  proto_tree_add_item(it104tree, hf_nega, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2702
2.64k
  proto_tree_add_item(it104tree, hf_test, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2703
2.64k
  offset += 1;
2704
2705
  /* Originator address */
2706
  /* This is only present if the Cause of Tx field is 2 octets */
2707
2.64k
  if (parms->cot_len == 2) {
2708
2.62k
    asduh.OA = tvb_get_uint8(tvb, offset);
2709
2.62k
    proto_tree_add_item(it104tree, hf_oa, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2710
2.62k
    offset += 1;
2711
2.62k
  }
2712
2713
  /* Common address of ASDU */
2714
2.64k
  proto_tree_add_item_ret_uint(it104tree, hf_addr, tvb, offset, parms->asdu_addr_len, ENC_LITTLE_ENDIAN, &asduh.Addr);
2715
2.64k
  offset += parms->asdu_addr_len;
2716
2717
  /* Information object address */
2718
  /* Support both 16 and 24-bit IOA addresses */
2719
  /* Don't increment offset, as we'll want to be at this position later */
2720
2.64k
  if (asduh.TypeId < S_CH_NA_1 || asduh.TypeId > S_UC_NA_1) {
2721
2.21k
    if (parms->ioa_len == 3) {
2722
2.21k
      asduh.IOA = tvb_get_letoh24(tvb, offset);
2723
2.21k
    }
2724
0
    else if (parms->ioa_len == 2) {
2725
0
      asduh.IOA = tvb_get_letohs(tvb, offset);
2726
0
    }
2727
2.21k
  }
2728
2729
2.64k
  cause_str = val_to_str(pinfo->pool, asduh.TNCause & F_CAUSE, causetx_types, " <CauseTx=%u>");
2730
2731
2.64k
  wmem_strbuf_append_printf(res, "ASDU=%u %s %s", asduh.Addr, val_to_str(pinfo->pool, asduh.TypeId, asdu_types, "<TypeId=%u>"), cause_str);
2732
2733
2.64k
  if (asduh.TNCause & F_NEGA)
2734
1.09k
    wmem_strbuf_append(res, "_NEGA");
2735
2.64k
  if (asduh.TNCause & F_TEST)
2736
437
    wmem_strbuf_append(res, "_TEST");
2737
2738
2.64k
  if ((asduh.TNCause & (F_TEST | F_NEGA)) == 0) {
2739
2.49k
    for (Ind=strlen(cause_str); Ind< 7; Ind++)
2740
1.16k
      wmem_strbuf_append(res, " ");
2741
1.32k
  }
2742
2743
2.64k
  if (asduh.NumIx > 1) {
2744
2.35k
    wmem_strbuf_append_printf(res, " IOA[%d]=%d", asduh.NumIx, asduh.IOA);
2745
2.35k
    if (asduh.SQ == F_SQ)
2746
672
      wmem_strbuf_append_printf(res, "-%d", asduh.IOA + asduh.NumIx - 1);
2747
1.68k
    else
2748
1.68k
      wmem_strbuf_append(res, ",...");
2749
2.35k
  } else {
2750
287
    wmem_strbuf_append_printf(res, " IOA=%d", asduh.IOA);
2751
287
  }
2752
2753
2.64k
  col_append_str(pinfo->cinfo, COL_INFO, wmem_strbuf_get_str(res));
2754
2.64k
  col_set_fence(pinfo->cinfo, COL_INFO);
2755
2756
  /* 'ASDU Details': ROOT ITEM */
2757
2.64k
  proto_item_append_text(it104, ": %s '%s'", wmem_strbuf_get_str(res),
2758
2.64k
    Len >= offset + parms->ioa_len ? val_to_str_const(asduh.TypeId, asdu_lngtypes, "<Unknown TypeId>") : "");
2759
2760
  /* 'Signal Details': TREE */
2761
  /* -------- get signal value and status based on ASDU type id */
2762
2763
2.64k
  switch (asduh.TypeId) {
2764
36
    case M_SP_NA_1:
2765
212
    case M_SP_TA_1:
2766
239
    case M_DP_NA_1:
2767
417
    case M_DP_TA_1:
2768
438
    case M_ST_NA_1:
2769
478
    case M_ST_TA_1:
2770
496
    case M_BO_NA_1:
2771
549
    case M_BO_TA_1:
2772
568
    case M_SP_TB_1:
2773
590
    case M_DP_TB_1:
2774
645
    case M_ST_TB_1:
2775
680
    case M_BO_TB_1:
2776
697
    case M_ME_NA_1:
2777
727
    case M_ME_TA_1:
2778
749
    case M_ME_NB_1:
2779
776
    case M_ME_TB_1:
2780
788
    case M_ME_NC_1:
2781
810
    case M_ME_TC_1:
2782
818
    case M_IT_NA_1:
2783
840
    case M_IT_TA_1:
2784
866
    case M_EP_TA_1:
2785
886
    case M_EP_TB_1:
2786
935
    case M_EP_TC_1:
2787
954
    case M_PS_NA_1:
2788
957
    case M_ME_ND_1:
2789
979
    case M_ME_TD_1:
2790
1.00k
    case M_ME_TE_1:
2791
1.04k
    case M_ME_TF_1:
2792
1.07k
    case M_IT_TB_1:
2793
1.08k
    case M_EP_TD_1:
2794
1.09k
    case M_EP_TE_1:
2795
1.11k
    case M_EP_TF_1:
2796
1.12k
    case S_IT_TC_1:
2797
1.14k
    case C_SC_NA_1:
2798
1.19k
    case C_DC_NA_1:
2799
1.22k
    case C_RC_NA_1:
2800
1.25k
    case C_SE_NA_1:
2801
1.29k
    case C_SE_NB_1:
2802
1.31k
    case C_SE_NC_1:
2803
1.33k
    case C_BO_NA_1:
2804
1.35k
    case C_SC_TA_1:
2805
1.36k
    case C_DC_TA_1:
2806
1.37k
    case C_RC_TA_1:
2807
1.39k
    case C_SE_TA_1:
2808
1.42k
    case C_SE_TB_1:
2809
1.43k
    case C_SE_TC_1:
2810
1.47k
    case C_BO_TA_1:
2811
1.50k
    case M_EI_NA_1:
2812
1.56k
    case C_IC_NA_1:
2813
1.58k
    case C_CI_NA_1:
2814
1.60k
    case C_CS_NA_1:
2815
1.64k
    case C_TS_NA_1:
2816
1.66k
    case C_RP_NA_1:
2817
1.69k
    case C_CD_NA_1:
2818
1.71k
    case C_TS_TA_1:
2819
1.73k
    case P_ME_NA_1:
2820
1.74k
    case P_ME_NB_1:
2821
1.76k
    case P_ME_NC_1:
2822
1.77k
    case P_AC_NA_1:
2823
1.78k
    case F_FR_NA_1:
2824
1.79k
    case F_SR_NA_1:
2825
1.80k
    case F_SC_NA_1:
2826
1.82k
    case F_LS_NA_1:
2827
1.84k
    case F_AF_NA_1:
2828
1.84k
    case F_SG_NA_1:
2829
1.85k
    case F_DR_TA_1:
2830
1.88k
    case F_SC_NB_1:
2831
2832
      /* -- object values */
2833
12.4k
      for(i = 0; i < asduh.NumIx; i++)
2834
12.1k
      {
2835
        /* create subtree for the signal values ... */
2836
12.1k
        if (i == 0 || !asduh.SQ)
2837
7.76k
          trSignal = proto_tree_add_subtree(it104tree, tvb, offset, asduh.DataLength + parms->ioa_len,
2838
7.76k
                            ett_asdu_objects, &itSignal, "IOA:s");
2839
4.35k
        else
2840
4.35k
          trSignal = proto_tree_add_subtree(it104tree, tvb, offset, asduh.DataLength,
2841
4.35k
                            ett_asdu_objects, &itSignal, "IOA:s");
2842
2843
        /* --------  First Information object address */
2844
12.1k
        if (i == 0)
2845
1.79k
        {
2846
          /* --------  Information object address */
2847
          /* check length */
2848
1.79k
          if(Len < (unsigned)(offset + 3)) {
2849
0
            expert_add_info(pinfo, itSignal, &ei_iec104_short_asdu);
2850
0
            return offset;
2851
0
          }
2852
1.79k
          get_InfoObjectAddress(&asdu_info_obj_addr, tvb, &offset, trSignal, parms->ioa_len);
2853
10.3k
        } else {
2854
          /* -------- following Information object address depending on SQ */
2855
10.3k
          if (asduh.SQ) /* <=> SQ=1, info obj addr = startaddr++ */
2856
4.21k
          {
2857
4.21k
            proto_item *ti;
2858
4.21k
            asdu_info_obj_addr++;
2859
4.21k
            ti = proto_tree_add_uint(trSignal, hf_ioa, tvb, 0, 0, asdu_info_obj_addr);
2860
4.21k
            proto_item_set_generated(ti);
2861
6.11k
          } else { /* SQ=0, info obj addr given */
2862
            /* --------  Information object address */
2863
            /* check length */
2864
6.11k
            if(Len < (unsigned)(offset + 3)) {
2865
231
              expert_add_info(pinfo, itSignal, &ei_iec104_short_asdu);
2866
231
              return offset;
2867
231
            }
2868
5.88k
            get_InfoObjectAddress(&asdu_info_obj_addr, tvb, &offset, trSignal, parms->ioa_len);
2869
5.88k
          }
2870
10.3k
        }
2871
2872
11.8k
        proto_item_set_text(itSignal, "IOA: %d", asdu_info_obj_addr);
2873
2874
        /* check length */
2875
11.8k
        if(Len < (unsigned)(offset + asduh.DataLength)) {
2876
931
          expert_add_info(pinfo, itSignal, &ei_iec104_short_asdu);
2877
931
          return offset;
2878
931
        }
2879
2880
10.9k
        switch (asduh.TypeId) {
2881
408
        case M_SP_NA_1: /* 1  Single-point information */
2882
408
          get_SIQ(tvb, &offset, trSignal);
2883
408
          break;
2884
185
        case M_SP_TA_1: /* 2  Single-point information with time tag */
2885
185
          get_SIQ(tvb, &offset, trSignal);
2886
185
          get_CP24Time(tvb, &offset, trSignal);
2887
185
          break;
2888
233
        case M_DP_NA_1: /* 3  Double-point information */
2889
233
          get_DIQ(tvb, &offset, trSignal);
2890
233
          break;
2891
379
        case M_DP_TA_1: /* 4  Double-point information with time tag */
2892
379
          get_DIQ(tvb, &offset, trSignal);
2893
379
          get_CP24Time(tvb, &offset, trSignal);
2894
379
          break;
2895
193
        case M_ST_NA_1: /* 5  Step position information */
2896
193
          get_VTI(tvb, &offset, trSignal);
2897
193
          get_QDS(tvb, &offset, trSignal);
2898
193
          break;
2899
135
        case M_ST_TA_1: /* 6  Step position information with time tag */
2900
135
          get_VTI(tvb, &offset, trSignal);
2901
135
          get_QDS(tvb, &offset, trSignal);
2902
135
          get_CP24Time(tvb, &offset, trSignal);
2903
135
          break;
2904
93
        case M_BO_NA_1: /* 7  Bitstring of 32 bits */
2905
93
          get_BSI(tvb, &offset, trSignal);
2906
93
          get_QDS(tvb, &offset, trSignal);
2907
93
          break;
2908
127
        case M_BO_TA_1: /* 8  Bitstring of 32 bits with time tag */
2909
127
          get_BSI(tvb, &offset, trSignal);
2910
127
          get_QDS(tvb, &offset, trSignal);
2911
127
          get_CP24Time(tvb, &offset, trSignal);
2912
127
          break;
2913
185
        case M_ME_NA_1: /* 9  Measured value, normalized value */
2914
185
          get_NVA(tvb, &offset, trSignal);
2915
185
          get_QDS(tvb, &offset, trSignal);
2916
185
          break;
2917
163
        case M_ME_TA_1: /* 10 Measured value, normalized value with time tag */
2918
163
          get_NVA(tvb, &offset, trSignal);
2919
163
          get_QDS(tvb, &offset, trSignal);
2920
163
          get_CP24Time(tvb, &offset, trSignal);
2921
163
          break;
2922
87
        case M_ME_NB_1: /* 11     Measured value, scaled value */
2923
87
          get_SVA(tvb, &offset, trSignal);
2924
87
          get_QDS(tvb, &offset, trSignal);
2925
87
          break;
2926
78
        case M_ME_TB_1: /* 12     Measured value, scaled value with time tag */
2927
78
          get_SVA(tvb, &offset, trSignal);
2928
78
          get_QDS(tvb, &offset, trSignal);
2929
78
          get_CP24Time(tvb, &offset, trSignal);
2930
78
          break;
2931
115
        case M_ME_NC_1: /* 13 Measured value, short floating point value */
2932
115
          get_FLT(tvb, &offset, trSignal);
2933
115
          get_QDS(tvb, &offset, trSignal);
2934
115
          break;
2935
64
        case M_ME_TC_1: /* 14 Measured value, short floating point value with time tag */
2936
64
          get_FLT(tvb, &offset, trSignal);
2937
64
          get_QDS(tvb, &offset, trSignal);
2938
64
          get_CP24Time(tvb, &offset, trSignal);
2939
64
          break;
2940
94
        case M_IT_NA_1: /* 15 Integrated totals */
2941
94
          get_BCR(tvb, &offset, trSignal);
2942
94
          break;
2943
158
        case M_IT_TA_1: /* 16 Integrated totals with time tag */
2944
158
          get_BCR(tvb, &offset, trSignal);
2945
158
          get_CP24Time(tvb, &offset, trSignal);
2946
158
          break;
2947
193
        case M_EP_TA_1: /* 17   Event of protection equipment with time tag */
2948
193
          get_SEP(tvb, &offset, trSignal);
2949
193
          get_CP16Time(tvb, &offset, trSignal);
2950
193
          get_CP24Time(tvb, &offset, trSignal);
2951
193
          break;
2952
87
        case M_EP_TB_1: /* 18   Packed start events of protection equipment with time tag */
2953
87
          get_SPE(tvb, &offset, trSignal);
2954
87
          get_QDP(tvb, &offset, trSignal);
2955
87
          get_CP16Time(tvb, &offset, trSignal);
2956
87
          get_CP24Time(tvb, &offset, trSignal);
2957
87
          break;
2958
281
        case M_EP_TC_1: /* 19   Packed output circuit information of protection equipment with time tag */
2959
281
          get_OCI(tvb, &offset, trSignal);
2960
281
          get_QDP(tvb, &offset, trSignal);
2961
281
          get_CP16Time(tvb, &offset, trSignal);
2962
281
          get_CP24Time(tvb, &offset, trSignal);
2963
281
          break;
2964
275
        case M_PS_NA_1: /* 20   Packed single-point information */
2965
275
          get_SCD(tvb, &offset, trSignal);
2966
275
          get_QDS(tvb, &offset, trSignal);
2967
275
          break;
2968
9
        case M_ME_ND_1: /* 21   Measured value, normalized value without quality descriptor */
2969
9
          get_NVA(tvb, &offset, trSignal);
2970
9
          break;
2971
136
        case M_SP_TB_1: /* 30 Single-point information with time tag CP56Time2a */
2972
136
          get_SIQ(tvb, &offset, trSignal);
2973
136
          get_CP56Time(tvb, &offset, trSignal);
2974
136
          break;
2975
75
        case M_DP_TB_1: /* 31 Double-point information with time tag CP56Time2a */
2976
75
          get_DIQ(tvb, &offset, trSignal);
2977
75
          get_CP56Time(tvb, &offset, trSignal);
2978
75
          break;
2979
256
        case M_ST_TB_1: /* 32 Step position information with time tag CP56Time2a */
2980
256
          get_VTI(tvb, &offset, trSignal);
2981
256
          get_QDS(tvb, &offset, trSignal);
2982
256
          get_CP56Time(tvb, &offset, trSignal);
2983
256
          break;
2984
120
        case M_BO_TB_1: /* 33 Bitstring of 32 bit with time tag CP56Time2a */
2985
120
          get_BSI(tvb, &offset, trSignal);
2986
120
          get_QDS(tvb, &offset, trSignal);
2987
120
          get_CP56Time(tvb, &offset, trSignal);
2988
120
          break;
2989
78
        case M_ME_TD_1: /* 34    Measured value, normalized value with time tag CP56Time2a */
2990
78
          get_NVA(tvb, &offset, trSignal);
2991
78
          get_QDS(tvb, &offset, trSignal);
2992
78
          get_CP56Time(tvb, &offset, trSignal);
2993
78
          break;
2994
97
        case M_ME_TE_1: /* 35    Measured value, scaled value with time tag CP56Time2a */
2995
97
          get_SVA(tvb, &offset, trSignal);
2996
97
          get_QDS(tvb, &offset, trSignal);
2997
97
          get_CP56Time(tvb, &offset, trSignal);
2998
97
          break;
2999
95
        case M_ME_TF_1: /* 36    Measured value, short floating point value with time tag CP56Time2a */
3000
95
          get_FLT(tvb, &offset, trSignal);
3001
95
          get_QDS(tvb, &offset, trSignal);
3002
95
          get_CP56Time(tvb, &offset, trSignal);
3003
95
          break;
3004
144
        case M_IT_TB_1: /* 37 Integrated totals with time tag CP56Time2a */
3005
144
          get_BCR(tvb, &offset, trSignal);
3006
144
          get_CP56Time(tvb, &offset, trSignal);
3007
144
          break;
3008
62
        case M_EP_TD_1: /* 38   Event of protection equipment with time tag CP56Time2a */
3009
62
          get_SEP(tvb, &offset, trSignal);
3010
62
          get_CP16Time(tvb, &offset, trSignal);
3011
62
          get_CP56Time(tvb, &offset, trSignal);
3012
62
          break;
3013
21
        case M_EP_TE_1: /* 39   Packed start events of protection equipment with time tag CP56Time2a */
3014
21
          get_SPE(tvb, &offset, trSignal);
3015
21
          get_QDP(tvb, &offset, trSignal);
3016
21
          get_CP16Time(tvb, &offset, trSignal);
3017
21
          get_CP56Time(tvb, &offset, trSignal);
3018
21
          break;
3019
121
        case M_EP_TF_1: /* 40   Packed output circuit information of protection equipment with time tag CP56Time2a */
3020
121
          get_OCI(tvb, &offset, trSignal);
3021
121
          get_QDP(tvb, &offset, trSignal);
3022
121
          get_CP16Time(tvb, &offset, trSignal);
3023
121
          get_CP56Time(tvb, &offset, trSignal);
3024
121
          break;
3025
18
        case S_IT_TC_1: /* 41   Integrated totals containing time tagged security statistics */
3026
18
          get_AID(tvb, &offset, trSignal);
3027
18
          get_BCR(tvb, &offset, trSignal);
3028
18
          get_CP56Time(tvb, &offset, trSignal);
3029
18
          break;
3030
149
        case C_SC_NA_1: /* 45 Single command */
3031
149
          get_SCO(tvb, &offset, trSignal);
3032
149
          break;
3033
537
        case C_DC_NA_1: /* 46 Double command */
3034
537
          get_DCO(tvb, &offset, trSignal);
3035
537
          break;
3036
92
        case C_RC_NA_1: /* 47 Regulating step command */
3037
92
          get_RCO(tvb, &offset, trSignal);
3038
92
          break;
3039
255
        case C_SE_NA_1: /* 48    Set point command, normalized value */
3040
255
          get_NVAspt(tvb, &offset, trSignal);
3041
255
          get_QOS(tvb, &offset, trSignal);
3042
255
          break;
3043
342
        case C_SE_NB_1: /* 49    Set point command, scaled value */
3044
342
          get_SVAspt(tvb, &offset, trSignal);
3045
342
          get_QOS(tvb, &offset, trSignal);
3046
342
          break;
3047
226
        case C_SE_NC_1: /* 50    Set point command, short floating point value */
3048
226
          get_FLTspt(tvb, &offset, trSignal);
3049
226
          get_QOS(tvb, &offset, trSignal);
3050
226
          break;
3051
127
        case C_BO_NA_1: /* 51    Bitstring of 32 bits */
3052
127
          get_BSIspt(tvb, &offset, trSignal);
3053
127
          break;
3054
43
        case C_SC_TA_1: /* 58    Single command with time tag CP56Time2a */
3055
43
          get_SCO(tvb, &offset, trSignal);
3056
43
          get_CP56Time(tvb, &offset, trSignal);
3057
43
          break;
3058
69
        case C_DC_TA_1: /* 59    Double command with time tag CP56Time2a */
3059
69
          get_DCO(tvb, &offset, trSignal);
3060
69
          get_CP56Time(tvb, &offset, trSignal);
3061
69
          break;
3062
49
        case C_RC_TA_1: /* 60    Regulating step command with time tag CP56Time2a */
3063
49
          get_RCO(tvb, &offset, trSignal);
3064
49
          get_CP56Time(tvb, &offset, trSignal);
3065
49
          break;
3066
99
        case C_SE_TA_1: /* 61    Set point command, normalized value with time tag CP56Time2a */
3067
99
          get_NVAspt(tvb, &offset, trSignal);
3068
99
          get_QOS(tvb, &offset, trSignal);
3069
99
          get_CP56Time(tvb, &offset, trSignal);
3070
99
          break;
3071
125
        case C_SE_TB_1: /* 62    Set point command, scaled value with time tag CP56Time2a */
3072
125
          get_SVAspt(tvb, &offset, trSignal);
3073
125
          get_QOS(tvb, &offset, trSignal);
3074
125
          get_CP56Time(tvb, &offset, trSignal);
3075
125
          break;
3076
46
        case C_SE_TC_1: /* 63    Set point command, short floating point value with time tag CP56Time2a */
3077
46
          get_FLTspt(tvb, &offset, trSignal);
3078
46
          get_QOS(tvb, &offset, trSignal);
3079
46
          get_CP56Time(tvb, &offset, trSignal);
3080
46
          break;
3081
149
        case C_BO_TA_1: /* 64    Bitstring of 32 bits with time tag CP56Time2a */
3082
149
          get_BSIspt(tvb, &offset, trSignal);
3083
149
          get_CP56Time(tvb, &offset, trSignal);
3084
149
          break;
3085
126
        case M_EI_NA_1: /* 70    End of initialization  */
3086
126
          get_COI(tvb, &offset, trSignal);
3087
126
          break;
3088
433
        case C_IC_NA_1: /* 100   Interrogation command  */
3089
433
          get_QOI(tvb, &offset, trSignal);
3090
433
          break;
3091
402
        case C_CI_NA_1: /* 101   Counter interrogation command  */
3092
402
          get_QCC(tvb, &offset, trSignal);
3093
402
          break;
3094
96
        case C_CS_NA_1: /* 103   Clock synchronization command  */
3095
96
          get_CP56Time(tvb, &offset, trSignal);
3096
96
          break;
3097
611
        case C_TS_NA_1: /* 104   Test command */
3098
611
          get_FBP(tvb, &offset, trSignal);
3099
611
          break;
3100
183
        case C_RP_NA_1: /* 105   reset process command  */
3101
183
          get_QRP(tvb, &offset, trSignal);
3102
183
          break;
3103
362
        case C_CD_NA_1: /* 106   Delay acquisition command */
3104
362
          get_CP16Time(tvb, &offset, trSignal);
3105
362
          break;
3106
75
        case C_TS_TA_1: /* 107   test command with time tag CP56Time2a */
3107
75
          get_TSC(tvb, &offset, trSignal);
3108
75
          get_CP56Time(tvb, &offset, trSignal);
3109
75
          break;
3110
147
        case P_ME_NA_1: /* 110   Parameter of measured value, normalized value */
3111
147
          get_NVA(tvb, &offset, trSignal);
3112
147
          get_QPM(tvb, &offset, trSignal);
3113
147
          break;
3114
66
        case P_ME_NB_1: /* 111   Parameter of measured value, scaled value */
3115
66
          get_SVA(tvb, &offset, trSignal);
3116
66
          get_QPM(tvb, &offset, trSignal);
3117
66
          break;
3118
76
        case P_ME_NC_1: /* 112   Parameter of measured value, short floating-point number */
3119
76
          get_FLT(tvb, &offset, trSignal);
3120
76
          get_QPM(tvb, &offset, trSignal);
3121
76
          break;
3122
291
        case P_AC_NA_1: /* 113   Parameter activation */
3123
291
          get_QPA(tvb, &offset, trSignal);
3124
291
          break;
3125
27
        case F_FR_NA_1: /* 120   File ready */
3126
27
          get_NOF(tvb, &offset, trSignal);
3127
27
          get_LOF(tvb, &offset, trSignal);
3128
27
          get_FRQ(tvb, &offset, trSignal);
3129
27
          break;
3130
87
        case F_SR_NA_1: /* 121   Section ready */
3131
87
          get_NOF(tvb, &offset, trSignal);
3132
87
          get_NOS(tvb, &offset, trSignal);
3133
87
          get_LOF(tvb, &offset, trSignal);
3134
87
          get_SRQ(tvb, &offset, trSignal);
3135
87
          break;
3136
77
        case F_SC_NA_1: /* 122   Call directory, select file, call file, call section */
3137
77
          get_NOF(tvb, &offset, trSignal);
3138
77
          get_NOS(tvb, &offset, trSignal);
3139
77
          get_SCQ(tvb, &offset, trSignal);
3140
77
          break;
3141
147
        case F_LS_NA_1: /* 123   Last section, last segment */
3142
147
          get_NOF(tvb, &offset, trSignal);
3143
147
          get_NOS(tvb, &offset, trSignal);
3144
147
          get_LSQ(tvb, &offset, trSignal);
3145
147
          get_CHS(tvb, &offset, trSignal);
3146
147
          break;
3147
294
        case F_AF_NA_1: /* 124   Ack file, ack section */
3148
294
          get_NOF(tvb, &offset, trSignal);
3149
294
          get_NOS(tvb, &offset, trSignal);
3150
294
          get_AFQ(tvb, &offset, trSignal);
3151
294
          break;
3152
1
        case F_SG_NA_1: /* 125   Segment */
3153
1
          get_NOF(tvb, &offset, trSignal);
3154
1
          get_NOS(tvb, &offset, trSignal);
3155
1
          seg_len = get_LOS(tvb, &offset, trSignal);
3156
1
          get_SEG(tvb, &offset, trSignal, seg_len);
3157
1
          break;
3158
18
        case F_DR_TA_1: /* 126   Directory */
3159
18
          get_NOF(tvb, &offset, trSignal);
3160
18
          get_LOF(tvb, &offset, trSignal);
3161
18
          get_SOF(tvb, &offset, trSignal);
3162
18
          get_CP56Time(tvb, &offset, trSignal);
3163
18
          break;
3164
103
        case F_SC_NB_1: /* 127   Query Log - Request archive file */
3165
103
          get_NOF(tvb, &offset, trSignal);
3166
103
          get_RangeStartCP56Time(tvb, &offset, trSignal);
3167
103
          get_RangeStopCP56Time(tvb, &offset, trSignal);
3168
103
          break;
3169
0
        default:
3170
0
          break;
3171
10.9k
        } /* end 'switch (asduh.TypeId)' */
3172
10.9k
      } /* end 'for(i = 0; i < dui.asdu_vsq_no_of_obj; i++)' */
3173
280
      break;
3174
280
    case S_CH_NA_1: /* 81    authentication challenge */
3175
155
    case S_RP_NA_1: /* 82    authentication reply */
3176
203
    case S_AR_NA_1: /* 83    Aggressive mode authentication request */
3177
236
    case S_KS_NA_1: /* 85    session key status */
3178
248
    case S_KC_NA_1: /* 86    session key change */
3179
357
    case S_ER_NA_1: /* 87    Authentication error */
3180
357
      dissect_iec60870_segment(tvb, pinfo, it104tree, &offset, asduh.TypeId, parms);
3181
357
      break;
3182
15
    case S_KR_NA_1: /* 84    Session key status request */
3183
15
      proto_tree_add_item(it104tree, hf_usr, tvb, offset, 2, ENC_LITTLE_ENDIAN);
3184
15
      offset += 2;
3185
15
      break;
3186
351
    default:
3187
351
      proto_tree_add_item(it104tree, hf_ioa, tvb, offset, 3, ENC_LITTLE_ENDIAN);
3188
351
      offset += 3;
3189
3190
351
      if (Len - offset > 0)
3191
299
        proto_tree_add_item(it104tree, hf_asdu_raw_data, tvb, offset, Len - offset, ENC_NA);
3192
351
      offset = Len;
3193
3194
351
      break;
3195
2.64k
  } /* end 'switch (asdu_typeid)' */
3196
3197
  /* check correct apdu length */
3198
872
  if (Len != offset) {
3199
307
    expert_add_info_format(pinfo, it104tree, &ei_iec104_apdu_invalid_len, "Invalid Apdulen (%d != %d)", Len, offset);
3200
307
    return offset;
3201
307
  }
3202
3203
565
  return tvb_captured_length(tvb);
3204
872
}
3205
3206
3207
3208
/* Is is called twice: For 'Packet List' and for 'Packet Details' */
3209
static int dissect_iec60870_104(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
3210
2.95k
{
3211
2.95k
  unsigned TcpLen = tvb_reported_length(tvb);
3212
2.95k
  uint8_t Start, len, type, temp8;
3213
2.95k
  uint32_t apci_txid, apci_rxid, apci_u_type;
3214
2.95k
  unsigned Off;
3215
2.95k
  proto_item *it104, *ti;
3216
2.95k
  proto_tree *it104tree;
3217
2.95k
  wmem_strbuf_t * res;
3218
2.95k
  struct asdu_parms parms;
3219
3220
2.95k
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "IEC 60870-5-104");
3221
3222
2.95k
  it104 = proto_tree_add_item(tree, proto_iec60870_104, tvb, 0, -1, ENC_NA);
3223
2.95k
  it104tree = proto_item_add_subtree(it104, ett_apci);
3224
3225
2.95k
  res = wmem_strbuf_create(pinfo->pool);
3226
3227
2.95k
  Start = 0;
3228
117k
  for (Off = 0; Off <= TcpLen - 2; Off++) {
3229
117k
    Start = tvb_get_uint8(tvb, Off);
3230
3231
117k
    if (Start == APCI_START) {
3232
2.94k
      if (Off > 0)
3233
2.82k
      {
3234
2.82k
        proto_tree_add_item(it104tree, hf_apcidata, tvb, 0, Off, ENC_NA);
3235
2.82k
        wmem_strbuf_append_printf(res, "<ERR prefix %u bytes> ", Off);
3236
2.82k
      }
3237
3238
2.94k
      proto_item_set_len(it104, Off + APCI_LEN);
3239
3240
2.94k
      proto_tree_add_uint_format(it104tree, hf_start, tvb, Off, 1, Start, "START");
3241
2.94k
      ti = proto_tree_add_item_ret_uint8(it104tree, hf_apdulen, tvb, Off + 1, 1, ENC_LITTLE_ENDIAN, &len);
3242
3243
2.94k
      if (len < APDU_MIN_LEN) {
3244
171
        expert_add_info_format(pinfo, ti, &ei_iec104_apdu_min_len, "APDU less than %d bytes", APDU_MIN_LEN);
3245
171
        wmem_strbuf_append_printf(res, "<ERR ApduLen=%u bytes> ", len);
3246
171
        return tvb_captured_length(tvb);
3247
171
      }
3248
3249
2.77k
      temp8 = tvb_get_uint8(tvb, Off + 2);
3250
2.77k
      if ((temp8 & 0x01) == 0)
3251
2.62k
        type = 0;
3252
157
      else
3253
157
        type = temp8 & 0x03;
3254
3255
2.77k
      if (type == I_TYPE)
3256
2.62k
        proto_tree_add_item(it104tree, hf_apcitype_i, tvb, Off + 2, 4, ENC_LITTLE_ENDIAN);
3257
157
      else
3258
157
        proto_tree_add_item(it104tree, hf_apcitype_s_u, tvb, Off + 2, 4, ENC_LITTLE_ENDIAN);
3259
3260
2.77k
      if (len <= APDU_MAX_LEN) {
3261
2.72k
        wmem_strbuf_append_printf(res, "%s %s ",
3262
2.72k
          (pinfo->srcport == pinfo->match_uint ? "->" : "<-"),
3263
2.72k
          val_to_str_const(type, apci_types, "<ERR>"));
3264
2.72k
      }
3265
51
      else {
3266
51
        wmem_strbuf_append_printf(res, "<ERR ApduLen=%u bytes> ", len);
3267
51
      }
3268
3269
2.77k
      switch(type) {
3270
2.60k
      case I_TYPE:
3271
2.60k
        proto_tree_add_item_ret_uint(it104tree, hf_apcitx, tvb, Off + 2, 4, ENC_LITTLE_ENDIAN, &apci_txid);
3272
2.60k
        proto_tree_add_item_ret_uint(it104tree, hf_apcirx, tvb, Off + 2, 4, ENC_LITTLE_ENDIAN, &apci_rxid);
3273
2.60k
        wmem_strbuf_append_printf(res, "(%d,%d) ", apci_txid, apci_rxid);
3274
2.60k
        break;
3275
62
      case S_TYPE:
3276
62
        proto_tree_add_item_ret_uint(it104tree, hf_apcirx, tvb, Off + 2, 4, ENC_LITTLE_ENDIAN, &apci_rxid);
3277
62
        wmem_strbuf_append_printf(res, "(%d) ", apci_rxid);
3278
62
        break;
3279
91
      case U_TYPE:
3280
91
        proto_tree_add_item_ret_uint(it104tree, hf_apciutype, tvb, Off + 2, 4, ENC_LITTLE_ENDIAN, &apci_u_type);
3281
91
        wmem_strbuf_append_printf(res, "(%s) ", val_to_str_const(apci_u_type, u_types, "<ERR>"));
3282
91
        break;
3283
2.77k
      }
3284
3285
2.75k
      col_clear(pinfo->cinfo, COL_INFO);
3286
2.75k
      col_append_sep_str(pinfo->cinfo, COL_INFO, " | ", wmem_strbuf_get_str(res));
3287
2.75k
      col_set_fence(pinfo->cinfo, COL_INFO);
3288
3289
2.75k
      proto_item_append_text(it104, ": %s", wmem_strbuf_get_str(res));
3290
3291
2.75k
      if (type == I_TYPE) {
3292
        /* Set the field lengths to the '104 fixed values before calling the ASDU dissection */
3293
2.60k
        parms.cot_len = 2;
3294
2.60k
        parms.asdu_addr_len = 2;
3295
2.60k
        parms.ioa_len = 3;
3296
3297
2.60k
        call_dissector_with_data(iec60870_asdu_handle, tvb_new_subset_length(tvb, Off + APCI_LEN, len - APCI_DATA_LEN), pinfo, tree, &parms);
3298
2.60k
      }
3299
      /* Don't search more the APCI_START */
3300
2.75k
      break;
3301
2.77k
    }
3302
117k
  }
3303
3304
2.76k
  if (Start != APCI_START) {
3305
    /* Everything is bad (no APCI found) */
3306
6
    proto_tree_add_item(it104tree, hf_apcidata, tvb, 0, Off, ENC_NA);
3307
6
  }
3308
3309
2.76k
  return tvb_captured_length(tvb);
3310
2.95k
}
3311
3312
/******************************************************************************************************/
3313
/* Code to dissect IEC 101 Protocol packets */
3314
/******************************************************************************************************/
3315
static int
3316
dissect_iec60870_101(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
3317
0
{
3318
/* Set up structures needed to add the protocol subtree and manage it */
3319
0
  proto_item  *iec101_item, *ctrlfield_item, *expert_item;
3320
0
  proto_tree  *iec101_tree, *ctrlfield_tree;
3321
0
  uint8_t   ctrlfield_prm;
3322
0
  uint32_t  frametype, linkaddr, data_len = 0, stopchar;
3323
0
  int   offset = 0;
3324
0
  struct      asdu_parms parms;
3325
3326
  /* Make entries in Protocol column on summary display */
3327
0
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "IEC 60870-5-101");
3328
0
  col_clear(pinfo->cinfo, COL_INFO);
3329
3330
0
  iec101_item = proto_tree_add_item(tree, proto_iec60870_101, tvb, 0, -1, ENC_NA);
3331
0
  iec101_tree = proto_item_add_subtree(iec101_item, ett_iec60870_101);
3332
3333
  /* Add Frame Format to Protocol Tree */
3334
0
  proto_tree_add_item_ret_uint(iec101_tree, hf_iec60870_101_frame, tvb, offset, 1, ENC_LITTLE_ENDIAN, &frametype);
3335
0
  offset += 1;
3336
3337
  /* If this is a single character frame, there is nothing left to do... */
3338
0
  if (frametype == IEC101_SINGLE_CHAR) {
3339
0
    return offset;
3340
0
  }
3341
3342
0
  if (frametype == IEC101_VAR_LEN) {
3343
0
    proto_tree_add_item(iec101_tree, hf_iec60870_101_length, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3344
0
    expert_item = proto_tree_add_item_ret_uint(iec101_tree, hf_iec60870_101_num_user_octets, tvb, offset+1, 1, ENC_LITTLE_ENDIAN, &data_len);
3345
0
    if (data_len != tvb_get_uint8(tvb, offset)) {
3346
0
      expert_add_info(pinfo, expert_item, &ei_iec101_length_mismatch);
3347
0
      col_set_str(pinfo->cinfo, COL_INFO, "Continuation");
3348
0
      return tvb_captured_length(tvb);
3349
0
    }
3350
    /* do not include the ctrl field and link address bytes in the length passed to the asdu dissector */
3351
0
    data_len -= 1 + global_iec60870_link_addr_len;
3352
0
    expert_item = proto_tree_add_item_ret_uint(iec101_tree, hf_iec60870_101_frame, tvb, offset+2, 1, ENC_LITTLE_ENDIAN, &frametype);
3353
0
    if (frametype != IEC101_VAR_LEN) {
3354
0
      expert_add_info(pinfo, expert_item, &ei_iec101_frame_mismatch);
3355
0
      col_set_str(pinfo->cinfo, COL_INFO, "Continuation");
3356
0
      return tvb_captured_length(tvb);
3357
0
    }
3358
0
    offset += 3;
3359
0
  }
3360
3361
  /* Fields common to both variable and fixed length frames */
3362
0
  ctrlfield_item = proto_tree_add_item(iec101_tree, hf_iec60870_101_ctrlfield, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3363
0
  ctrlfield_tree = proto_item_add_subtree(ctrlfield_item, ett_iec60870_101_ctrlfield);
3364
3365
0
  ctrlfield_prm = tvb_get_uint8(tvb, offset) & 0x40;
3366
0
  if (ctrlfield_prm) {
3367
0
    col_append_sep_str(pinfo->cinfo, COL_INFO, ", ", "Pri->Sec");
3368
0
    proto_tree_add_item(ctrlfield_tree, hf_iec60870_101_ctrl_prm, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3369
0
    proto_tree_add_item(ctrlfield_tree, hf_iec60870_101_ctrl_fcb, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3370
0
    proto_tree_add_item(ctrlfield_tree, hf_iec60870_101_ctrl_fcv, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3371
0
    proto_tree_add_item(ctrlfield_tree, hf_iec60870_101_ctrl_func_pri_to_sec, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3372
0
  }
3373
0
  else {
3374
0
    col_append_sep_str(pinfo->cinfo, COL_INFO, ", ", "Sec->Pri");
3375
0
    proto_tree_add_item(ctrlfield_tree, hf_iec60870_101_ctrl_prm, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3376
0
    proto_tree_add_item(ctrlfield_tree, hf_iec60870_101_ctrl_dfc, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3377
0
    proto_tree_add_item(ctrlfield_tree, hf_iec60870_101_ctrl_func_sec_to_pri, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3378
0
  }
3379
0
  offset += 1;
3380
3381
0
  if (global_iec60870_link_addr_len) {
3382
0
    proto_tree_add_item_ret_uint(iec101_tree, hf_iec60870_101_linkaddr, tvb, offset, global_iec60870_link_addr_len, ENC_LITTLE_ENDIAN, &linkaddr);
3383
0
    col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Link Address: %d ", linkaddr);
3384
0
    offset += global_iec60870_link_addr_len;
3385
0
  }
3386
3387
  /* If this is a variable length frame, we need to call the ASDU dissector */
3388
0
  if (frametype == IEC101_VAR_LEN) {
3389
3390
    /* Retrieve the user preferences */
3391
0
    parms.cot_len = global_iec60870_cot_len;
3392
0
    parms.asdu_addr_len = global_iec60870_asdu_addr_len;
3393
0
    parms.ioa_len = global_iec60870_ioa_len;
3394
3395
0
    call_dissector_with_data(iec60870_asdu_handle, tvb_new_subset_length(tvb, offset, data_len), pinfo, tree, &parms);
3396
0
    offset += data_len;
3397
0
  }
3398
3399
0
  proto_tree_add_item(iec101_tree, hf_iec60870_101_checksum, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3400
0
  expert_item = proto_tree_add_item_ret_uint(iec101_tree, hf_iec60870_101_stopchar, tvb, offset+1, 1, ENC_LITTLE_ENDIAN, &stopchar);
3401
0
  if (stopchar != IEC101_STOP_CHAR) {
3402
0
    expert_add_info(pinfo, expert_item, &ei_iec101_stopchar_invalid);
3403
0
  }
3404
0
  offset += 2;
3405
3406
0
  return offset;
3407
3408
0
}
3409
3410
static int dissect_iec60870_104_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
3411
708
{
3412
  /* 5th parameter = 6 = minimum bytes received to calculate the length.
3413
   * (Not 2 in order to find more APCIs in case of 'noisy' bytes between the APCIs)
3414
   */
3415
708
  tcp_dissect_pdus(tvb, pinfo, tree, true, APCI_LEN,
3416
708
      get_iec104apdu_len, dissect_iec60870_104, data);
3417
708
  return tvb_captured_length(tvb);
3418
708
}
3419
3420
/* The protocol has two subprotocols: Register APCI */
3421
void
3422
proto_register_iec60870_104(void)
3423
16
{
3424
16
  static hf_register_info hf_ap[] = {
3425
3426
16
    { &hf_apdulen,
3427
16
      { "ApduLen", "iec60870_104.apdulen", FT_UINT8, BASE_DEC, NULL, 0x0,
3428
16
        "APDU Len", HFILL }},
3429
3430
16
    { &hf_apcitype_i,
3431
16
      { "Type", "iec60870_104.type", FT_UINT32, BASE_HEX, VALS(apci_types), 0x00000001,
3432
16
        "APCI type", HFILL }},
3433
3434
16
    { &hf_apcitype_s_u,
3435
16
      { "Type", "iec60870_104.type", FT_UINT32, BASE_HEX, VALS(apci_types), 0x00000003,
3436
16
        "APCI type", HFILL }},
3437
3438
16
    { &hf_apciutype,
3439
16
      { "UType", "iec60870_104.utype", FT_UINT32, BASE_HEX, VALS(u_types), 0x000000FC,
3440
16
        "Apci U type", HFILL }},
3441
3442
16
    { &hf_apcitx,
3443
16
      { "Tx", "iec60870_104.tx", FT_UINT32, BASE_DEC, NULL, 0x0000FFFE,
3444
16
        NULL, HFILL }},
3445
3446
16
    { &hf_apcirx,
3447
16
      { "Rx", "iec60870_104.rx", FT_UINT32, BASE_DEC, NULL, 0xFFFE0000,
3448
16
        NULL, HFILL }},
3449
3450
16
    { &hf_apcidata,
3451
16
      { "Data", "iec60870_104.data", FT_BYTES, BASE_NONE, NULL, 0,
3452
16
        NULL, HFILL }},
3453
16
  };
3454
3455
16
  static int *ett_ap[] = {
3456
16
    &ett_apci,
3457
16
  };
3458
3459
16
  proto_iec60870_104 = proto_register_protocol("IEC 60870-5-104", "IEC 60870-5-104", "iec60870_104");
3460
3461
  /* Provide an alias to the previous name of this dissector */
3462
16
  proto_register_alias(proto_iec60870_104, "104apci");
3463
3464
16
  proto_register_field_array(proto_iec60870_104, hf_ap, array_length(hf_ap));
3465
16
  proto_register_subtree_array(ett_ap, array_length(ett_ap));
3466
3467
16
  prefs_register_protocol(proto_iec60870_104, NULL);
3468
3469
16
  iec60870_104_handle = register_dissector("iec60870_104", dissect_iec60870_104_tcp, proto_iec60870_104);
3470
3471
16
}
3472
3473
/* Register ASDU dissection, shared by the '101 and '104 dissectors */
3474
void
3475
proto_register_iec60870_asdu(void)
3476
16
{
3477
16
  static hf_register_info hf_as[] = {
3478
3479
16
    { &hf_addr,
3480
16
      { "Addr", "iec60870_asdu.addr", FT_UINT16, BASE_DEC, NULL, 0x0,
3481
16
        "Common Address of Asdu", HFILL }},
3482
3483
16
    { &hf_oa,
3484
16
      { "OA", "iec60870_asdu.oa", FT_UINT8, BASE_DEC, NULL, 0x0,
3485
16
        "Originator Address", HFILL }},
3486
3487
16
    { &hf_typeid,
3488
16
      { "TypeId", "iec60870_asdu.typeid", FT_UINT8, BASE_DEC, VALS(asdu_types), 0x0,
3489
16
        "Asdu Type Id", HFILL }},
3490
3491
16
    { &hf_causetx,
3492
16
      { "CauseTx", "iec60870_asdu.causetx", FT_UINT8, BASE_DEC, VALS(causetx_types), F_CAUSE,
3493
16
        "Cause of Transmission", HFILL }},
3494
3495
16
    { &hf_nega,
3496
16
      { "Negative", "iec60870_asdu.nega", FT_BOOLEAN, 8, NULL, F_NEGA,
3497
16
        NULL, HFILL }},
3498
3499
16
    { &hf_test,
3500
16
      { "Test", "iec60870_asdu.test", FT_BOOLEAN, 8, NULL, F_TEST,
3501
16
        NULL, HFILL }},
3502
3503
16
    { &hf_ioa,
3504
16
      { "IOA", "iec60870_asdu.ioa", FT_UINT24, BASE_DEC, NULL, 0x0,
3505
16
        "Information Object Address", HFILL }},
3506
3507
16
    { &hf_numix,
3508
16
      { "NumIx", "iec60870_asdu.numix", FT_UINT8, BASE_DEC, NULL, 0x7F,
3509
16
        "Number of Information Objects/Elements", HFILL }},
3510
3511
16
    { &hf_sq,
3512
16
      { "SQ", "iec60870_asdu.sq", FT_BOOLEAN, 8, NULL, F_SQ,
3513
16
        "Sequence", HFILL }},
3514
3515
16
    { &hf_cp16time,
3516
16
      { "CP16Time (ms)", "iec60870_asdu.cp16time", FT_UINT16, BASE_DEC, NULL, 0,
3517
16
        NULL, HFILL }},
3518
3519
16
    { &hf_cp24time,
3520
16
      { "CP24Time", "iec60870_asdu.cp24time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0,
3521
16
        NULL, HFILL }},
3522
3523
16
    { &hf_cp24time_ms,
3524
16
      { "MS", "iec60870_asdu.cp24time.ms", FT_UINT16, BASE_DEC, NULL, 0,
3525
16
        "CP24Time milliseconds", HFILL }},
3526
3527
16
    { &hf_cp24time_min,
3528
16
      { "Min", "iec60870_asdu.cp24time.min", FT_UINT8, BASE_DEC, NULL, 0x3F,
3529
16
        "CP24Time minutes", HFILL }},
3530
3531
16
    { &hf_cp24time_iv,
3532
16
      { "IV", "iec60870_asdu.cp24time.iv", FT_BOOLEAN, 8, TFS(&tfs_invalid_valid), 0x80,
3533
16
        "CP24Time invalid", HFILL }},
3534
3535
16
    { &hf_cp56time,
3536
16
      { "CP56Time", "iec60870_asdu.cp56time", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0,
3537
16
        NULL, HFILL }},
3538
3539
16
    { &hf_cp56time_ms,
3540
16
      { "MS", "iec60870_asdu.cp56time.ms", FT_UINT16, BASE_DEC, NULL, 0,
3541
16
        "CP56Time milliseconds", HFILL }},
3542
3543
16
    { &hf_cp56time_min,
3544
16
      { "Min", "iec60870_asdu.cp56time.min", FT_UINT8, BASE_DEC, NULL, 0x3F,
3545
16
        "CP56Time minutes", HFILL }},
3546
3547
16
    { &hf_cp56time_gen,
3548
16
      { "GEN", "iec60870_asdu.cp56time.gen", FT_BOOLEAN, 8, TFS(&tfs_substituted_not_substituted), 0x40,
3549
16
        "CP56Time substituted", HFILL }},
3550
3551
16
    { &hf_cp56time_iv,
3552
16
      { "IV", "iec60870_asdu.cp56time.iv", FT_BOOLEAN, 8, TFS(&tfs_invalid_valid), 0x80,
3553
16
        "CP56Time invalid", HFILL }},
3554
3555
16
    { &hf_cp56time_hour,
3556
16
      { "Hour", "iec60870_asdu.cp56time.hour", FT_UINT8, BASE_DEC, NULL, 0x1F,
3557
16
        "CP56Time hours", HFILL }},
3558
3559
16
    { &hf_cp56time_su,
3560
16
      { "SU", "iec60870_asdu.cp56time.su", FT_BOOLEAN, 8, TFS(&tfs_summer_standard_time), 0x80,
3561
16
        "CP56Time summer time", HFILL }},
3562
3563
16
    { &hf_cp56time_day,
3564
16
      { "Day", "iec60870_asdu.cp56time.day", FT_UINT8, BASE_DEC, NULL, 0x1F,
3565
16
        "CP56Time day", HFILL }},
3566
3567
16
    { &hf_cp56time_dow,
3568
16
      { "DOW", "iec60870_asdu.cp56time.dow", FT_UINT8, BASE_DEC, NULL, 0xE0,
3569
16
        "CP56Time day of week", HFILL }},
3570
3571
16
    { &hf_cp56time_month,
3572
16
      { "Month", "iec60870_asdu.cp56time.month", FT_UINT8, BASE_DEC, NULL, 0x0F,
3573
16
        "CP56Time month", HFILL }},
3574
3575
16
    { &hf_cp56time_year,
3576
16
      { "Year", "iec60870_asdu.cp56time.year", FT_UINT8, BASE_DEC, NULL, 0x7F,
3577
16
        "CP56Time year", HFILL }},
3578
3579
16
    { &hf_range_start_cp56time,
3580
16
      { "Range start CP56Time", "iec60870_asdu.range_start_cp56time", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0,
3581
16
        NULL, HFILL }},
3582
3583
16
    { &hf_range_stop_cp56time,
3584
16
      { "Range stop CP56Time", "iec60870_asdu.range_stop_cp56time", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0,
3585
16
        NULL, HFILL } },
3586
3587
16
    { &hf_siq,
3588
16
      { "SIQ", "iec60870_asdu.siq", FT_UINT8, BASE_HEX, NULL, 0,
3589
16
        NULL, HFILL }},
3590
3591
16
    { &hf_siq_spi,
3592
16
      { "SPI", "iec60870_asdu.siq.spi", FT_BOOLEAN, 8, TFS(&tfs_on_off), 0x01,
3593
16
        "SIQ SPI", HFILL }},
3594
3595
16
    { &hf_siq_bl,
3596
16
      { "BL", "iec60870_asdu.siq.bl", FT_BOOLEAN, 8, TFS(&tfs_blocked_not_blocked), 0x10,
3597
16
        "SIQ BL", HFILL }},
3598
3599
16
    { &hf_siq_sb,
3600
16
      { "SB", "iec60870_asdu.siq.sb", FT_BOOLEAN, 8, TFS(&tfs_substituted_not_substituted), 0x20,
3601
16
        "SIQ SB", HFILL }},
3602
3603
16
    { &hf_siq_nt,
3604
16
      { "NT", "iec60870_asdu.siq.nt", FT_BOOLEAN, 8, TFS(&tfs_not_topical_topical), 0x40,
3605
16
        "SIQ NT", HFILL }},
3606
3607
16
    { &hf_siq_iv,
3608
16
      { "IV", "iec60870_asdu.siq.iv", FT_BOOLEAN, 8, TFS(&tfs_invalid_valid), 0x80,
3609
16
        "SIQ IV", HFILL }},
3610
3611
16
    { &hf_diq,
3612
16
      { "DIQ", "iec60870_asdu.diq", FT_UINT8, BASE_HEX, NULL, 0,
3613
16
        NULL, HFILL }},
3614
3615
16
    { &hf_diq_dpi,
3616
16
      { "DPI", "iec60870_asdu.diq.dpi", FT_UINT8, BASE_DEC, VALS(diq_types), 0x03,
3617
16
        "DIQ DPI", HFILL }},
3618
3619
16
    { &hf_diq_bl,
3620
16
      { "BL", "iec60870_asdu.diq.bl", FT_BOOLEAN, 8, TFS(&tfs_blocked_not_blocked), 0x10,
3621
16
        "DIQ BL", HFILL }},
3622
3623
16
    { &hf_diq_sb,
3624
16
      { "SB", "iec60870_asdu.diq.sb", FT_BOOLEAN, 8, TFS(&tfs_substituted_not_substituted), 0x20,
3625
16
        "DIQ SB", HFILL }},
3626
3627
16
    { &hf_diq_nt,
3628
16
      { "NT", "iec60870_asdu.diq.nt", FT_BOOLEAN, 8, TFS(&tfs_not_topical_topical), 0x40,
3629
16
        "DIQ NT", HFILL }},
3630
3631
16
    { &hf_diq_iv,
3632
16
      { "IV", "iec60870_asdu.diq.iv", FT_BOOLEAN, 8, TFS(&tfs_invalid_valid), 0x80,
3633
16
        "DIQ IV", HFILL }},
3634
3635
16
    { &hf_qds,
3636
16
      { "QDS", "iec60870_asdu.qds", FT_UINT8, BASE_HEX, NULL, 0,
3637
16
        NULL, HFILL }},
3638
3639
16
    { &hf_qds_ov,
3640
16
      { "OV", "iec60870_asdu.qds.ov", FT_BOOLEAN, 8, TFS(&tfs_overflow_no_overflow), 0x01,
3641
16
        "QDS OV", HFILL }},
3642
3643
16
    { &hf_qds_bl,
3644
16
      { "BL", "iec60870_asdu.qds.bl", FT_BOOLEAN, 8, TFS(&tfs_blocked_not_blocked), 0x10,
3645
16
        "QDS BL", HFILL }},
3646
3647
16
    { &hf_qds_sb,
3648
16
      { "SB", "iec60870_asdu.qds.sb", FT_BOOLEAN, 8, TFS(&tfs_substituted_not_substituted), 0x20,
3649
16
        "QDS SB", HFILL }},
3650
3651
16
    { &hf_qds_nt,
3652
16
      { "NT", "iec60870_asdu.qds.nt", FT_BOOLEAN, 8, TFS(&tfs_not_topical_topical), 0x40,
3653
16
        "QDS NT", HFILL }},
3654
3655
16
    { &hf_qds_iv,
3656
16
      { "IV", "iec60870_asdu.qds.iv", FT_BOOLEAN, 8, TFS(&tfs_invalid_valid), 0x80,
3657
16
        "QDS IV", HFILL }},
3658
3659
16
    { &hf_vti,
3660
16
      { "VTI", "iec60870_asdu.vti", FT_UINT8, BASE_HEX, NULL, 0,
3661
16
        NULL, HFILL }},
3662
3663
16
    { &hf_vti_v,
3664
16
      { "Value", "iec60870_asdu.vti.v", FT_INT8, BASE_DEC, NULL, 0x7F,
3665
16
        "VTI Value", HFILL }},
3666
3667
16
    { &hf_vti_t,
3668
16
      { "T", "iec60870_asdu.vti.t", FT_BOOLEAN, 8, TFS(&tfs_transient_not_transient), 0x80,
3669
16
        "VTI T", HFILL }},
3670
3671
16
    { &hf_qos,
3672
16
      { "QOS", "iec60870_asdu.qos", FT_UINT8, BASE_HEX, NULL, 0,
3673
16
        NULL, HFILL }},
3674
3675
16
    { &hf_qos_ql,
3676
16
      { "QL", "iec60870_asdu.qos.ql", FT_UINT8, BASE_DEC, NULL, 0x7F,
3677
16
        "QOS QL", HFILL }},
3678
3679
16
    { &hf_qos_se,
3680
16
      { "S/E", "iec60870_asdu.qos.se", FT_BOOLEAN, 8, TFS(&tfs_select_execute), 0x80,
3681
16
        "QOS S/E", HFILL }},
3682
3683
16
    { &hf_sco,
3684
16
      { "SCO", "iec60870_asdu.sco", FT_UINT8, BASE_HEX, NULL, 0,
3685
16
        NULL, HFILL }},
3686
3687
16
    { &hf_sco_on,
3688
16
      { "ON/OFF", "iec60870_asdu.sco.on", FT_BOOLEAN, 8, TFS(&tfs_on_off), 0x01,
3689
16
        "SCO SCS", HFILL }},
3690
3691
16
    { &hf_sco_qu,
3692
16
      { "QU", "iec60870_asdu.sco.qu", FT_UINT8, BASE_DEC, VALS(qos_qu_types), 0x7C,
3693
16
        "SCO QU", HFILL }},
3694
3695
16
    { &hf_sco_se,
3696
16
      { "S/E", "iec60870_asdu.sco.se", FT_BOOLEAN, 8, TFS(&tfs_select_execute), 0x80,
3697
16
        "SCO S/E", HFILL }},
3698
3699
16
    { &hf_dco,
3700
16
      { "DCO", "iec60870_asdu.dco", FT_UINT8, BASE_HEX, NULL, 0,
3701
16
        NULL, HFILL }},
3702
3703
16
    { &hf_dco_on,
3704
16
      { "ON/OFF", "iec60870_asdu.dco.on", FT_UINT8, BASE_DEC, VALS(dco_on_types), 0x03,
3705
16
        "DCO DCS", HFILL }},
3706
3707
16
    { &hf_dco_qu,
3708
16
      { "QU", "iec60870_asdu.dco.qu", FT_UINT8, BASE_DEC, VALS(qos_qu_types), 0x7C,
3709
16
        "DCO QU", HFILL }},
3710
3711
16
    { &hf_dco_se,
3712
16
      { "S/E", "iec60870_asdu.dco.se", FT_BOOLEAN, 8, TFS(&tfs_select_execute), 0x80,
3713
16
        "DCO S/E", HFILL }},
3714
3715
16
    { &hf_rco,
3716
16
      { "RCO", "iec60870_asdu.rco", FT_UINT8, BASE_HEX, NULL, 0,
3717
16
        NULL, HFILL }},
3718
3719
16
    { &hf_rco_up,
3720
16
      { "UP/DOWN", "iec60870_asdu.rco.up", FT_UINT8, BASE_DEC, VALS(rco_up_types), 0x03,
3721
16
        "RCO RCS", HFILL }},
3722
3723
16
    { &hf_rco_qu,
3724
16
      { "QU", "iec60870_asdu.rco.qu", FT_UINT8, BASE_DEC, VALS(qos_qu_types), 0x7C,
3725
16
        "RCO QU", HFILL }},
3726
3727
16
    { &hf_rco_se,
3728
16
      { "S/E", "iec60870_asdu.rco.se", FT_BOOLEAN, 8, TFS(&tfs_select_execute), 0x80,
3729
16
        "RCO S/E", HFILL }},
3730
3731
16
    { &hf_qpm,
3732
16
      { "QPM", "iec60870_asdu.qpm", FT_UINT8, BASE_HEX, NULL, 0,
3733
16
        NULL, HFILL } },
3734
3735
16
    { &hf_qpm_kpa,
3736
16
      { "KPA", "iec60870_asdu.qpm.kpa", FT_UINT8, BASE_DEC, VALS(qpm_kpa_types), 0x3F,
3737
16
        "QPM KPA", HFILL } },
3738
3739
16
    { &hf_qpm_lpc,
3740
16
      { "LPC", "iec60870_asdu.qpm.lpc", FT_UINT8, BASE_DEC, VALS(qpm_lpc_types), 0x40,
3741
16
        "QPM LPC", HFILL } },
3742
3743
16
    { &hf_qpm_pop,
3744
16
      { "POP", "iec60870_asdu.qpm.pop", FT_UINT8, BASE_DEC, VALS(qpm_pop_types), 0x80,
3745
16
        "QPM POP", HFILL } },
3746
3747
16
    { &hf_nof,
3748
16
      { "NOF", "iec60870_asdu.nof", FT_UINT16, BASE_DEC, NULL, 0,
3749
16
        "Name of file", HFILL} },
3750
3751
16
    { &hf_lof,
3752
16
      { "LOF", "iec60870_asdu.lof", FT_UINT32, BASE_DEC, NULL, 0,
3753
16
        "Length of file or section", HFILL} },
3754
3755
16
    { &hf_frq,
3756
16
      { "FRQ", "iec60870_asdu.frq", FT_UINT8, BASE_HEX, NULL, 0,
3757
16
        "File ready qualifier", HFILL} },
3758
3759
16
    { &hf_frq_confirm,
3760
16
      { "Confirmation", "iec60870_asdu.frq.confirm", FT_BOOLEAN, 8, TFS(&tfs_negative_positive), 0x80,
3761
16
        NULL, HFILL } },
3762
3763
16
    { &hf_frq_qualifier,
3764
16
      { "Qualifier", "iec60870_asdu.frq.qualifier", FT_UINT8, BASE_DEC, VALS(frq_qualifier), 0x7F,
3765
16
        NULL, HFILL } },
3766
3767
16
    { &hf_nos,
3768
16
      { "NOS", "iec60870_asdu.nos", FT_UINT16, BASE_DEC, NULL, 0,
3769
16
        "Name of section", HFILL} },
3770
3771
16
    { &hf_srq,
3772
16
      { "SRQ", "iec60870_asdu.srq", FT_UINT8, BASE_HEX, NULL, 0,
3773
16
        "Section ready qualifier", HFILL} },
3774
3775
16
    { &hf_srq_ready,
3776
16
      { "Ready", "iec60870_asdu.srq.ready", FT_BOOLEAN, 8, TFS(&tfs_not_ready_ready), 0x80,
3777
16
        NULL, HFILL } },
3778
3779
16
    { &hf_srq_qualifier,
3780
16
      { "Qualifier", "iec60870_asdu.srq.qualifier", FT_UINT8, BASE_DEC, VALS(srq_qualifier), 0x7F,
3781
16
        NULL, HFILL } },
3782
3783
16
    { &hf_scq,
3784
16
      { "SCQ", "iec60870_asdu.scq", FT_UINT8, BASE_HEX, NULL, 0,
3785
16
        "Select and call qualifier", HFILL}},
3786
3787
16
    { &hf_scq_select,
3788
16
      { "Select", "iec60870_asdu.scq.select", FT_UINT8, BASE_DEC, VALS(scq_select), 0x0F,
3789
16
        NULL, HFILL } },
3790
3791
16
    { &hf_scq_qualifier,
3792
16
      { "Qualifier", "iec60870_asdu.scq.qualifier", FT_UINT8, BASE_DEC, VALS(scq_qualifier), 0xF0,
3793
16
        NULL, HFILL } },
3794
3795
16
    { &hf_lsq,
3796
16
      { "LSQ", "iec60870_asdu.lsq", FT_UINT8, BASE_DEC, VALS(lsq_qualifier), 0,
3797
16
        "Last section or segment qualifier", HFILL} },
3798
3799
16
    { &hf_chs,
3800
16
      { "CHS", "iec60870_asdu.chs", FT_UINT8, BASE_HEX, NULL, 0,
3801
16
        "Checksum", HFILL} },
3802
3803
16
    { &hf_afq,
3804
16
      { "AFQ", "iec60870_asdu.afq", FT_UINT8, BASE_HEX, NULL, 0,
3805
16
        "Acknowledge file or section qualifier", HFILL} },
3806
3807
16
    { &hf_afq_ack,
3808
16
      { "Acknowledge", "iec60870_asdu.afq.ack", FT_UINT8, BASE_DEC, VALS(afq_ack), 0x0F,
3809
16
        NULL, HFILL } },
3810
3811
16
    { &hf_afq_qualifier,
3812
16
      { "Qualifier", "iec60870_asdu.afq.qualifier", FT_UINT8, BASE_DEC, VALS(afq_qualifier), 0xF0,
3813
16
        NULL, HFILL } },
3814
3815
16
    { &hf_los,
3816
16
      { "LOS", "iec60870_asdu.los", FT_UINT8, BASE_DEC, NULL, 0,
3817
16
        "Length of segment", HFILL} },
3818
3819
16
    { &hf_segment_data,
3820
16
      { "Data", "iec60870_asdu.segmentdata", FT_BYTES, BASE_NONE, NULL, 0x0,
3821
16
        "Segment data", HFILL } },
3822
3823
16
    { &hf_sof,
3824
16
      { "SOF", "iec60870_asdu.sof", FT_UINT8, BASE_HEX, NULL, 0,
3825
16
        "Status of file", HFILL} },
3826
3827
16
    { &hf_sof_status,
3828
16
      { "Status", "iec60870_asdu.sof.status", FT_UINT8, BASE_DEC, VALS(sof_status), 0x1F,
3829
16
        NULL, HFILL } },
3830
3831
16
    { &hf_sof_lfd,
3832
16
      { "LFD", "iec60870_asdu.sof.lfd", FT_BOOLEAN, 8, TFS(&tfs_last_file_additional_follows), 0x20,
3833
16
        NULL, HFILL } },
3834
3835
16
    { &hf_sof_for,
3836
16
      { "FOR", "iec60870_asdu.sof.for", FT_BOOLEAN, 8, TFS(&tfs_subdir_file), 0x40,
3837
16
        NULL, HFILL } },
3838
3839
16
    { &hf_sof_fa,
3840
16
      { "FA", "iec60870_asdu.sof.fa", FT_BOOLEAN, 8, TFS(&tfs_active_waits), 0x80,
3841
16
        NULL, HFILL } },
3842
3843
16
    { &hf_sep,
3844
16
      { "SEP", "iec60870_asdu.sep", FT_UINT8, BASE_HEX, NULL, 0,
3845
16
        NULL, HFILL } },
3846
3847
16
    { &hf_sep_es,
3848
16
      { "ES", "iec60870_asdu.sep.es", FT_UINT8, BASE_DEC, VALS(sep_types), 0x03,
3849
16
        "SEP ES", HFILL}},
3850
3851
16
    { &hf_sep_ei,
3852
16
      { "EI", "iec60870_asdu.sep.ei", FT_BOOLEAN, 8, TFS(&tfs_elapsed_invalid_valid), 0x08,
3853
16
        "SEP EI", HFILL} },
3854
3855
16
    { &hf_sep_bl ,
3856
16
      { "BL", "iec60870_asdu.sep.bl", FT_BOOLEAN, 8, TFS(&tfs_blocked_not_blocked), 0x10,
3857
16
        "SEP BL", HFILL} },
3858
3859
16
    { &hf_sep_sb ,
3860
16
      { "SB", "iec60870_asdu.sep.sb", FT_BOOLEAN, 8, TFS(&tfs_substituted_not_substituted), 0x20,
3861
16
        "SEP SB", HFILL} },
3862
3863
16
    { &hf_sep_nt ,
3864
16
      { "NT", "iec60870_asdu.sep.nt", FT_BOOLEAN, 8, TFS(&tfs_not_topical_topical), 0x40,
3865
16
        "SEP NT", HFILL} },
3866
3867
16
    { &hf_sep_iv ,
3868
16
      { "IV", "iec60870_asdu.sep.iv", FT_BOOLEAN, 8, TFS(&tfs_invalid_valid), 0x80,
3869
16
        "SEP IV", HFILL} },
3870
3871
16
    { &hf_spe,
3872
16
      { "SPE", "iec60870_asdu.spe", FT_UINT8, BASE_HEX, NULL, 0,
3873
16
        NULL, HFILL } },
3874
3875
16
    { &hf_spe_gs,
3876
16
      { "GS", "iec60870_asdu.spe.gs", FT_BOOLEAN, 8, TFS(&tfs_general_start_no_general_start), 0x01,
3877
16
        "SPE GS", HFILL} },
3878
3879
16
    { &hf_spe_sl1,
3880
16
      { "SL1", "iec60870_asdu.spe.sl1", FT_BOOLEAN, 8, TFS(&tfs_start_no_start), 0x02,
3881
16
        "SPE SL1", HFILL} },
3882
3883
16
    { &hf_spe_sl2,
3884
16
      { "SL2", "iec60870_asdu.spe.sl2", FT_BOOLEAN, 8, TFS(&tfs_start_no_start), 0x04,
3885
16
        "SPE SL2", HFILL} },
3886
3887
16
    { &hf_spe_sl3,
3888
16
      { "SL3", "iec60870_asdu.spe.sl3", FT_BOOLEAN, 8, TFS(&tfs_start_no_start), 0x08,
3889
16
        "SPE SL3", HFILL} },
3890
3891
16
    { &hf_spe_sie,
3892
16
      { "SIE", "iec60870_asdu.spe.sie", FT_BOOLEAN, 8, TFS(&tfs_start_no_start), 0x10,
3893
16
        "SPE SIE", HFILL} },
3894
3895
16
    { &hf_spe_srd,
3896
16
      { "SRD", "iec60870_asdu.spe.srd", FT_BOOLEAN, 8, TFS(&tfs_start_reverse_no_start_revers), 0x20,
3897
16
        "SPE SRD", HFILL} },
3898
3899
16
    { &hf_qdp,
3900
16
      { "QDP", "iec60870_asdu.qdp", FT_UINT8, BASE_HEX, NULL, 0,
3901
16
        NULL, HFILL } },
3902
3903
16
    { &hf_qdp_ei,
3904
16
      { "EI", "iec60870_asdu.qdp.ei", FT_BOOLEAN, 8, TFS(&tfs_elapsed_invalid_valid), 0x08,
3905
16
        "QDP EI", HFILL} },
3906
3907
16
    { &hf_qdp_bl ,
3908
16
      { "BL", "iec60870_asdu.qdp.bl", FT_BOOLEAN, 8, TFS(&tfs_blocked_not_blocked), 0x10,
3909
16
        "QDP BL", HFILL} },
3910
3911
16
    { &hf_qdp_sb ,
3912
16
      { "SB", "iec60870_asdu.qdp.sb", FT_BOOLEAN, 8, TFS(&tfs_substituted_not_substituted), 0x20,
3913
16
        "QDP SB", HFILL} },
3914
3915
16
    { &hf_qdp_nt ,
3916
16
      { "NT", "iec60870_asdu.qdp.nt", FT_BOOLEAN, 8, TFS(&tfs_not_topical_topical), 0x40,
3917
16
        "QDP NT", HFILL} },
3918
3919
16
    { &hf_qdp_iv ,
3920
16
      { "IV", "iec60870_asdu.qdp.iv", FT_BOOLEAN, 8, TFS(&tfs_invalid_valid), 0x80,
3921
16
        "QDP IV", HFILL} },
3922
3923
16
    { &hf_oci,
3924
16
      { "OCI", "iec60870_asdu.oci", FT_UINT8, BASE_HEX, NULL, 0,
3925
16
        NULL, HFILL } },
3926
3927
16
    { &hf_oci_gc,
3928
16
      { "GC", "iec60870_asdu.oci.gc", FT_BOOLEAN, 8, TFS(&tfs_general_command_no_general_command), 0x01,
3929
16
        "OCI GC", HFILL} },
3930
3931
16
    { &hf_oci_cl1,
3932
16
      { "CL1", "iec60870_asdu.oci.cl1", FT_BOOLEAN, 8, TFS(&tfs_command_no_command), 0x02,
3933
16
        "OCI CL1", HFILL} },
3934
3935
16
    { &hf_oci_cl2,
3936
16
      { "CL2", "iec60870_asdu.oci.cl2", FT_BOOLEAN, 8, TFS(&tfs_command_no_command), 0x04,
3937
16
        "OCI CL2", HFILL} },
3938
3939
16
    { &hf_oci_cl3,
3940
16
      { "CL3", "iec60870_asdu.oci.cl3", FT_BOOLEAN, 8, TFS(&tfs_command_no_command), 0x08,
3941
16
        "OCI CL3", HFILL} },
3942
3943
16
    { &hf_qpa,
3944
16
      { "QPA", "iec60870_asdu.qpa", FT_UINT8, BASE_DEC, VALS(qpa_types), 0x0,
3945
16
        NULL, HFILL} },
3946
3947
16
    { &hf_fbp,
3948
16
      { "FBP", "iec60870_asdu.fbp", FT_UINT16, BASE_HEX, NULL, 0x0,
3949
16
        NULL, HFILL} },
3950
3951
16
    { &hf_scd,
3952
16
      { "SCD", "iec60870_asdu.scd", FT_UINT32, BASE_HEX, NULL, 0,
3953
16
        NULL, HFILL } },
3954
3955
16
    { &hf_scd_st,
3956
16
      { "ST", "iec60870_asdu.scd.st", FT_UINT16, BASE_HEX, NULL, 0x0,
3957
16
        "SCD ST", HFILL} },
3958
3959
16
    { &hf_scd_cd,
3960
16
      { "CD", "iec60870_asdu.scd.cd", FT_UINT16, BASE_HEX, NULL, 0x0,
3961
16
        "SCD CD", HFILL} },
3962
3963
16
    { &hf_asn,
3964
16
      { "ASDU Segment Sequence Number (ASN)", "iec60870_asdu.asn", FT_UINT8, BASE_DEC, NULL, 0x3F,
3965
16
        NULL, HFILL }},
3966
3967
16
    { &hf_asn_fin,
3968
16
      { "Final segment (FIN)", "iec60870_asdu.asn.fin", FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x80,
3969
16
        NULL, HFILL }},
3970
3971
16
    { &hf_asn_fir,
3972
16
      { "First segment (FIR)", "iec60870_asdu.asn.fir", FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x40,
3973
16
        NULL, HFILL }},
3974
3975
16
    { &hf_iec60870_segment_data,
3976
16
       { "ASDU segment data", "iec60870_asdu.segment_data", FT_BYTES, BASE_NONE, NULL, 0x0,
3977
16
         NULL, HFILL }},
3978
3979
16
    { &hf_usr,
3980
16
      { "User number (USR)", "iec60870_asdu.usr", FT_UINT16, BASE_DEC | BASE_RANGE_STRING, RVALS(usr_types), 0,
3981
16
        NULL, HFILL }},
3982
3983
16
    { &hf_mal,
3984
16
      { "MAC algorithm (MAL)", "iec60870_asdu.mal", FT_UINT8, BASE_DEC | BASE_RANGE_STRING, RVALS(mal_types), 0,
3985
16
        NULL, HFILL }},
3986
3987
16
    { &hf_rsc,
3988
16
      { "Reason for challenge (RSC)", "iec60870_asdu.rsc", FT_UINT8, BASE_DEC, VALS(rsc_types), 0,
3989
16
        NULL, HFILL }},
3990
3991
16
    { &hf_csq,
3992
16
      { "Challenge sequence number (CSQ)", "iec60870_asdu.csq", FT_UINT32, BASE_DEC, NULL, 0,
3993
16
        NULL, HFILL }},
3994
3995
16
    { &hf_ksq,
3996
16
      { "Key change sequence number (KSQ)", "iec60870_asdu.ksq", FT_UINT32, BASE_DEC, NULL, 0,
3997
16
        NULL, HFILL }},
3998
3999
16
    { &hf_kwa,
4000
16
      { "Key wrap algorithm (KWA)", "iec60870_asdu.kwa", FT_UINT8, BASE_DEC | BASE_RANGE_STRING, RVALS(kwa_types), 0,
4001
16
        NULL, HFILL }},
4002
4003
16
    { &hf_kst,
4004
16
      { "Key status (KST)", "iec60870_asdu.kst", FT_UINT8, BASE_DEC, VALS(kst_types), 0,
4005
16
        NULL, HFILL }},
4006
4007
16
    { &hf_hln,
4008
16
      { "MAC length (HLN)", "iec60870_asdu.hln", FT_UINT16, BASE_DEC, NULL, 0,
4009
16
        NULL, HFILL }},
4010
4011
16
    { &hf_hal,
4012
16
      { "MAC algorithm (HAL)", "iec60870_asdu.hal", FT_UINT8, BASE_DEC | BASE_RANGE_STRING, RVALS(hal_types), 0,
4013
16
        NULL, HFILL }},
4014
4015
16
    { &hf_cln,
4016
16
      { "Challenge data length (CLN)", "iec60870_asdu.cln", FT_UINT16, BASE_DEC, NULL, 0,
4017
16
        NULL, HFILL }},
4018
4019
16
    { &hf_wkl,
4020
16
      { "Wrapped key data length (CLN)", "iec60870_asdu.wkl", FT_UINT16, BASE_DEC, NULL, 0,
4021
16
        NULL, HFILL }},
4022
4023
16
    { &hf_prcd_raw_data,
4024
16
      { "Pseudo-random challenge data", "iec60870_asdu.challenge_data", FT_BYTES, BASE_NONE, NULL, 0x0,
4025
16
        NULL, HFILL }},
4026
4027
16
    { &hf_hmac_raw_data,
4028
16
      { "HMAC value", "iec60870_asdu.hmac", FT_BYTES, BASE_NONE, NULL, 0x0,
4029
16
        NULL, HFILL }},
4030
4031
16
    { &hf_wkd_raw_data,
4032
16
      { "Wrapped key data", "iec60870_asdu.wkd", FT_BYTES, BASE_NONE, NULL, 0x0,
4033
16
        NULL, HFILL }},
4034
4035
16
    { &hf_aid,
4036
16
      { "Association ID (AID)", "iec60870_asdu.aid", FT_UINT16, BASE_DEC, NULL, 0,
4037
16
        NULL, HFILL }},
4038
4039
16
    { &hf_err,
4040
16
      { "Error code (ERR)", "iec60870_asdu.err", FT_UINT8, BASE_DEC | BASE_RANGE_STRING, RVALS(error_codes), 0,
4041
16
        NULL, HFILL }},
4042
4043
16
    { &hf_etm,
4044
16
      { "Error time stamp (ETM)", "iec60870_asdu.etm", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0,
4045
16
        NULL, HFILL }},
4046
4047
16
    { &hf_etm_ms,
4048
16
      { "MS", "iec60870_asdu.etm.ms", FT_UINT16, BASE_DEC, NULL, 0,
4049
16
        "Error time stamp milliseconds", HFILL }},
4050
4051
16
    { &hf_etm_min,
4052
16
      { "Min", "iec60870_asdu.etm.min", FT_UINT8, BASE_DEC, NULL, 0x3F,
4053
16
        "Error time stamp minutes", HFILL }},
4054
4055
16
    { &hf_etm_iv,
4056
16
      { "IV", "iec60870_asdu.etm.iv", FT_BOOLEAN, 8, TFS(&tfs_invalid_valid), 0x80,
4057
16
        "Error time stamp invalid", HFILL }},
4058
4059
16
    { &hf_etm_hour,
4060
16
      { "Hour", "iec60870_asdu.etm.hour", FT_UINT8, BASE_DEC, NULL, 0x1F,
4061
16
        "Error time stamp hours", HFILL }},
4062
4063
16
    { &hf_etm_su,
4064
16
      { "SU", "iec60870_asdu.etm.su", FT_BOOLEAN, 8, TFS(&tfs_summer_standard_time), 0x80,
4065
16
        "Error time stamp summer time", HFILL }},
4066
4067
16
    { &hf_etm_day,
4068
16
      { "Day", "iec60870_asdu.etm.day", FT_UINT8, BASE_DEC, NULL, 0x1F,
4069
16
        "Error time stamp day", HFILL }},
4070
4071
16
    { &hf_etm_dow,
4072
16
      { "DOW", "iec60870_asdu.etm.dow", FT_UINT8, BASE_DEC, NULL, 0xE0,
4073
16
        "Error time stamp day of week", HFILL }},
4074
4075
16
    { &hf_etm_month,
4076
16
      { "Month", "iec60870_asdu.etm.month", FT_UINT8, BASE_DEC, NULL, 0x0F,
4077
16
        "Error time stamp month", HFILL }},
4078
4079
16
    { &hf_etm_year,
4080
16
      { "Year", "iec60870_asdu.etm.year", FT_UINT8, BASE_DEC, NULL, 0x7F,
4081
16
        "Error time stamp year", HFILL }},
4082
4083
16
    { &hf_eln,
4084
16
      { "Error length (ELN)", "iec60870_asdu.eln", FT_UINT16, BASE_DEC, NULL, 0,
4085
16
        NULL, HFILL }},
4086
4087
16
    { &hf_error_text,
4088
16
      { "Error text", "iec60870_asdu.error_text", FT_STRING, BASE_NONE, NULL, 0x0,
4089
16
        NULL, HFILL }},
4090
4091
16
    { &hf_coi,
4092
16
      { "COI", "iec60870_asdu.coi", FT_UINT8, BASE_HEX, NULL, 0,
4093
16
        NULL, HFILL }},
4094
4095
16
    { &hf_coi_r,
4096
16
      { "R", "iec60870_asdu.coi.r", FT_UINT8, BASE_DEC, VALS(coi_r_types), 0x7F,
4097
16
        "COI R", HFILL }},
4098
4099
16
    { &hf_coi_i,
4100
16
      { "I", "iec60870_asdu.coi.i", FT_BOOLEAN, 8, TFS(&tfs_coi_i), 0x80,
4101
16
        "COI I", HFILL }},
4102
4103
16
    { &hf_qoi,
4104
16
      { "QOI", "iec60870_asdu.qoi", FT_UINT8, BASE_DEC, VALS(qoi_r_types), 0,
4105
16
        NULL, HFILL }},
4106
4107
16
    { &hf_qcc,
4108
16
      { "QCC", "iec60870_asdu.qcc", FT_UINT8, BASE_HEX, NULL, 0,
4109
16
        NULL, HFILL } },
4110
4111
16
    { &hf_qcc_rqt,
4112
16
      { "RQT", "iec60870_asdu.qcc.rqt", FT_UINT8, BASE_DEC, VALS(rqt_r_types), 0x3F,
4113
16
        NULL, HFILL } },
4114
4115
16
    { &hf_qcc_frz,
4116
16
      { "FRZ", "iec60870_asdu.qcc.frz", FT_UINT8, BASE_DEC, VALS(frz_r_types), 0xC0,
4117
16
        NULL, HFILL } },
4118
4119
16
    { &hf_qrp,
4120
16
      { "QRP", "iec60870_asdu.qrp", FT_UINT8, BASE_DEC, VALS(qrp_r_types), 0,
4121
16
        NULL, HFILL }},
4122
4123
16
    { &hf_bcr,
4124
16
      { "BCR", "iec60870_asdu.bcr", FT_INT32, BASE_DEC, NULL, 0x0,
4125
16
        "Binary Counter", HFILL }},
4126
4127
16
    { &hf_bcr_count,
4128
16
      { "Value", "iec60870_asdu.bcr.count", FT_INT32, BASE_DEC, NULL, 0x0,
4129
16
        NULL, HFILL }},
4130
4131
16
    { &hf_bcr_sq,
4132
16
      { "SQ", "iec60870_asdu.bcr.sq", FT_UINT8, BASE_DEC, NULL, 0x1F,
4133
16
        "Sequence Number", HFILL }},
4134
4135
16
    { &hf_bcr_cy,
4136
16
      { "CY", "iec60870_asdu.bcr.cy", FT_BOOLEAN, 8, TFS(&tfs_overflow_no_overflow), 0x20,
4137
16
        "Counter Overflow", HFILL }},
4138
4139
16
    { &hf_bcr_ca,
4140
16
      { "CA", "iec60870_asdu.bcr.ca", FT_BOOLEAN, 8, TFS(&tfs_adjusted_not_adjusted), 0x40,
4141
16
        "Counter Adjusted", HFILL }},
4142
4143
16
    { &hf_bcr_iv,
4144
16
      { "IV", "iec60870_asdu.bcr.iv", FT_BOOLEAN, 8, TFS(&tfs_invalid_valid), 0x80,
4145
16
        "Counter Validity", HFILL }},
4146
4147
16
    { &hf_start,
4148
16
      { "START", "iec60870_asdu.start", FT_UINT8, BASE_HEX, NULL, 0x0,
4149
16
        NULL, HFILL }},
4150
4151
16
    { &hf_asdu_bitstring,
4152
16
      { "Value", "iec60870_asdu.bitstring", FT_UINT32, BASE_HEX, NULL, 0x0,
4153
16
        "BSI value", HFILL }},
4154
4155
16
    { &hf_asdu_float,
4156
16
      { "Value", "iec60870_asdu.float", FT_FLOAT, BASE_NONE, NULL, 0x0,
4157
16
        "Float value", HFILL }},
4158
4159
16
    { &hf_asdu_normval,
4160
16
      { "Value", "iec60870_asdu.normval", FT_FLOAT, BASE_NONE, NULL, 0x0,
4161
16
        "Normalised value", HFILL }},
4162
4163
16
    { &hf_asdu_scalval,
4164
16
      { "Value", "iec60870_asdu.scalval", FT_INT16, BASE_DEC, NULL, 0x0,
4165
16
        "Scaled value", HFILL }},
4166
4167
16
    { &hf_asdu_tsc,
4168
16
      { "TSC", "iec60870_asdu.tsc", FT_UINT16, BASE_DEC, NULL, 0x0,
4169
16
              "Test sequence counter", HFILL }},
4170
4171
16
    { &hf_asdu_raw_data,
4172
16
      { "Raw Data", "iec60870_asdu.rawdata", FT_BYTES, BASE_NONE, NULL, 0x0,
4173
16
        "Information object raw data", HFILL }},
4174
4175
16
    { &hf_iec60870_segments,
4176
16
      { "ASDU Segments", "iec60870_asdu.segments", FT_NONE, BASE_NONE, NULL, 0x0,
4177
16
        NULL, HFILL }},
4178
4179
16
    { &hf_iec60870_segment,
4180
16
      { "ASDU Segment", "iec60870_asdu.segment", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
4181
16
        NULL, HFILL }},
4182
4183
16
    { &hf_iec60870_segment_overlap,
4184
16
      { "Segment overlap", "iec60870_asdu.segment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
4185
16
        "Segment overlaps with other segments", HFILL }},
4186
4187
16
    { &hf_iec60870_segment_overlap_conflict,
4188
16
      { "Conflicting data in segment overlap", "iec60870_asdu.segment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
4189
16
        "Overlapping segments contained conflicting data", HFILL }},
4190
4191
16
    { &hf_iec60870_segment_multiple_tails,
4192
16
      { "Multiple tail segments found", "iec60870_asdu.segment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
4193
16
        "Several tails were found when reassembling the packet", HFILL }},
4194
4195
16
    { &hf_iec60870_segment_too_long_segment,
4196
16
      { "Segment too long", "iec60870_asdu.segment.toolongsegment", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
4197
16
        "Segment contained data past end of packet", HFILL }},
4198
4199
16
    { &hf_iec60870_segment_error,
4200
16
      { "Reassembly error", "iec60870_asdu.segment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
4201
16
        "Reassembly error due to illegal segments", HFILL }},
4202
4203
16
    { &hf_iec60870_segment_count,
4204
16
      { "Segment count", "iec60870_asdu.segment.count", FT_UINT32, BASE_DEC, NULL, 0x0,
4205
16
        NULL, HFILL }},
4206
4207
16
    { &hf_iec60870_reassembled_in,
4208
16
       { "Reassembled ASDU in frame", "iec60870_asdu.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
4209
16
         "This ASDU packet is reassembled in this frame", HFILL }},
4210
4211
16
    { &hf_iec60870_reassembled_length,
4212
16
      { "Reassembled ASDU length", "iec60870_asdu.reassembled.length", FT_UINT32, BASE_DEC, NULL, 0x0,
4213
16
        "The total length of the reassembled payload", HFILL }},
4214
4215
16
  };
4216
4217
16
  static int *ett_as[] = {
4218
16
    &ett_asdu,
4219
16
    &ett_asdu_objects,
4220
16
    &ett_siq,
4221
16
    &ett_diq,
4222
16
    &ett_qds,
4223
16
    &ett_qos,
4224
16
    &ett_vti,
4225
16
    &ett_sco,
4226
16
    &ett_sep,
4227
16
    &ett_spe,
4228
16
    &ett_qdp,
4229
16
    &ett_oci,
4230
16
    &ett_scd,
4231
16
    &ett_dco,
4232
16
    &ett_rco,
4233
16
    &ett_qpm,
4234
16
    &ett_frq,
4235
16
    &ett_srq,
4236
16
    &ett_scq,
4237
16
    &ett_afq,
4238
16
    &ett_sof,
4239
16
    &ett_coi,
4240
16
    &ett_qcc,
4241
16
    &ett_cp24time,
4242
16
    &ett_cp56time,
4243
16
    &ett_etm,
4244
16
    &ett_iec60870_segment,
4245
16
    &ett_iec60870_segments
4246
16
  };
4247
4248
16
  static ei_register_info ei[] = {
4249
16
    { &ei_iec104_short_asdu, { "iec104.short_asdu", PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>", EXPFILL }},
4250
16
    { &ei_iec104_apdu_min_len, { "iec104.apdu_min_len", PI_MALFORMED, PI_ERROR, "APDU less than bytes", EXPFILL }},
4251
16
    { &ei_iec104_apdu_invalid_len, { "iec104.apdu_invalid_len", PI_MALFORMED, PI_ERROR, "Invalid ApduLen", EXPFILL }},
4252
16
  };
4253
4254
16
  expert_module_t* expert_iec60870;
4255
4256
16
  proto_iec60870_asdu = proto_register_protocol("IEC 60870-5-101/104 ASDU", "IEC 60870-5-101/104 ASDU", "iec60870_asdu");
4257
16
  iec60870_asdu_handle = register_dissector("iec60870_asdu", dissect_iec60870_asdu, proto_iec60870_asdu);
4258
4259
  /* Provide an alias to the previous name of this dissector */
4260
16
  proto_register_alias(proto_iec60870_asdu, "104asdu");
4261
4262
16
  proto_register_field_array(proto_iec60870_asdu, hf_as, array_length(hf_as));
4263
16
  proto_register_subtree_array(ett_as, array_length(ett_as));
4264
16
  expert_iec60870 = expert_register_protocol(proto_iec60870_asdu);
4265
16
  expert_register_field_array(expert_iec60870, ei, array_length(ei));
4266
4267
16
  reassembly_table_register(&iec60870_reassemble_table, &addresses_ports_reassembly_table_functions);
4268
16
}
4269
4270
/* The registration hand-off routine */
4271
void
4272
proto_reg_handoff_iec60870_104(void)
4273
16
{
4274
16
  dissector_add_uint_with_preference("tcp.port", IEC104_PORT, iec60870_104_handle);
4275
16
}
4276
4277
/******************************************************************************************************/
4278
/* Return length of IEC 101 Protocol over TCP message (used for re-assembly)             */
4279
/******************************************************************************************************/
4280
static unsigned
4281
get_iec101_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset _U_, void *data _U_)
4282
0
{
4283
4284
0
  unsigned len=0, type;
4285
0
  type = tvb_get_uint8(tvb, offset);
4286
4287
0
  switch (type) {
4288
0
    case IEC101_SINGLE_CHAR:
4289
0
      len = 1;
4290
0
      break;
4291
0
    case IEC101_FIXED_LEN:
4292
0
      len = global_iec60870_link_addr_len + 4;
4293
0
      break;
4294
0
    case IEC101_VAR_LEN:
4295
0
      if (tvb_captured_length_remaining(tvb, offset) < 3) {
4296
        /* We need another segment. */
4297
0
        return 0;
4298
0
      }
4299
0
      len = tvb_get_uint8(tvb, offset + 1) + 6;
4300
      /* If the copy of the length or start byte is wrong,
4301
       * we have errors. Take the entire remaining length
4302
       * and the dissector will show the error. We'll try
4303
       * to start a new PDU in a later packet. We can't
4304
       * really reject the packet at this point.
4305
       */
4306
0
      if (len != (unsigned)tvb_get_uint8(tvb, offset + 2) + 6) {
4307
0
        len = tvb_reported_length_remaining(tvb, offset);
4308
0
      }
4309
0
      if (tvb_get_uint8(tvb, offset+3) != IEC101_VAR_LEN) {
4310
0
        len = tvb_reported_length_remaining(tvb, offset);
4311
0
      }
4312
0
      break;
4313
0
  }
4314
4315
0
  return len;
4316
0
}
4317
4318
/******************************************************************************************************/
4319
/* Dissect (and possibly Re-assemble) IEC 101 protocol payload data */
4320
/******************************************************************************************************/
4321
static int
4322
dissect_iec60870_101_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
4323
0
{
4324
4325
0
  unsigned type = tvb_get_uint8(tvb, 0);
4326
4327
  /* Check that this is actually a IEC 60870-5-101 packet. */
4328
  /* Note we are guaranteed to get one byte here, not necessarily more. */
4329
0
  switch (type) {
4330
0
    case IEC101_SINGLE_CHAR:
4331
0
    case IEC101_FIXED_LEN:
4332
0
    case IEC101_VAR_LEN:
4333
0
      tcp_dissect_pdus(tvb, pinfo, tree, true, 1, get_iec101_len, dissect_iec60870_101, data);
4334
0
      break;
4335
0
    default:
4336
0
      return 0;
4337
0
  }
4338
4339
0
  return tvb_captured_length(tvb);
4340
0
}
4341
4342
/* The registration hand-off routine */
4343
void
4344
proto_register_iec60870_101(void)
4345
16
{
4346
  /* IEC 101 Protocol header fields */
4347
16
  static hf_register_info iec60870_101_hf[] = {
4348
16
    { &hf_iec60870_101_frame,
4349
16
    { "Frame Format", "iec60870_101.header", FT_UINT8, BASE_HEX, VALS(iec60870_101_frame_vals), 0x0, NULL, HFILL }},
4350
16
    { &hf_iec60870_101_length,
4351
16
    { "Length", "iec60870_101.length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4352
16
    { &hf_iec60870_101_num_user_octets,
4353
16
    { "Number of User Octets", "iec60870_101.num_user_octets", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4354
16
    { &hf_iec60870_101_ctrlfield,
4355
16
    { "Control Field", "iec60870_101.ctrlfield", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
4356
16
    { &hf_iec60870_101_ctrl_prm,
4357
16
    { "PRM", "iec60870_101.ctrl_prm", FT_UINT8, BASE_DEC, VALS(iec60870_101_ctrl_prm_values), 0x40, "Primary Message", HFILL }},
4358
16
    { &hf_iec60870_101_ctrl_fcb,
4359
16
    { "FCB", "iec60870_101.ctrl_fcb", FT_UINT8, BASE_DEC, NULL, 0x20, "Frame Count Bit", HFILL }},
4360
16
    { &hf_iec60870_101_ctrl_fcv,
4361
16
    { "FCV", "iec60870_101.ctrl_fcv", FT_UINT8, BASE_DEC, NULL, 0x10, "Frame Count Bit Valid", HFILL }},
4362
16
    { &hf_iec60870_101_ctrl_dfc,
4363
16
    { "DFC", "iec60870_101.ctrl_dfc", FT_UINT8, BASE_DEC, NULL, 0x10, "Data Flow Control", HFILL }},
4364
16
    { &hf_iec60870_101_ctrl_func_pri_to_sec,
4365
16
    { "CF Func Code", "iec60870_101.ctrl_func_pri_to_sec", FT_UINT8, BASE_DEC, VALS(iec60870_101_ctrl_func_pri_to_sec_values), 0x0F, "Control Field Function Code, Pri to Sec", HFILL }},
4366
16
    { &hf_iec60870_101_ctrl_func_sec_to_pri,
4367
16
    { "CF Func Code", "iec60870_101.ctrl_func_sec_to_pri", FT_UINT8, BASE_DEC, VALS(iec60870_101_ctrl_func_sec_to_pri_values), 0x0F, "Control Field Function Code, Sec to Pri", HFILL }},
4368
16
    { &hf_iec60870_101_linkaddr,
4369
16
    { "Data Link Address", "iec60870_101.linkaddr", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4370
16
    { &hf_iec60870_101_checksum,
4371
16
    { "Checksum", "iec60870_101.checksum", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
4372
16
    { &hf_iec60870_101_stopchar,
4373
16
    { "Stop Character", "iec60870_101.stopchar", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
4374
4375
16
  };
4376
4377
  /* Setup protocol subtree array */
4378
16
  static int *ett_serial[] = {
4379
16
    &ett_iec60870_101,
4380
16
    &ett_iec60870_101_ctrlfield,
4381
16
  };
4382
4383
16
  static ei_register_info ei_101[] = {
4384
16
    { &ei_iec101_frame_mismatch, { "iec60870_101.header.mismatch", PI_MALFORMED, PI_ERROR, "Variable Length frames must have two matching start bytes (0x68)", EXPFILL }},
4385
16
    { &ei_iec101_length_mismatch, { "iec60870_101.length.mismatch", PI_MALFORMED, PI_ERROR, "Variable Length frames must have two matching length bytes", EXPFILL }},
4386
16
    { &ei_iec101_stopchar_invalid, { "iec60870_101.stopchar.invalid", PI_PROTOCOL, PI_WARN, "Stop character must be 0x16", EXPFILL }},
4387
16
  };
4388
4389
16
  module_t *iec60870_101_module;
4390
16
  expert_module_t* expert_iec60870_101;
4391
4392
  /* Register the protocol name and description */
4393
16
  proto_iec60870_101 = proto_register_protocol("IEC 60870-5-101", "IEC 60870-5-101", "iec60870_101");
4394
4395
  /* Required function calls to register the header fields and subtrees used */
4396
16
  proto_register_field_array(proto_iec60870_101, iec60870_101_hf, array_length(iec60870_101_hf));
4397
16
  proto_register_subtree_array(ett_serial, array_length(ett_serial));
4398
4399
16
  expert_iec60870_101 = expert_register_protocol(proto_iec60870_101);
4400
16
  expert_register_field_array(expert_iec60870_101, ei_101, array_length(ei_101));
4401
4402
16
  iec60870_101_handle = register_dissector("iec60870_101", dissect_iec60870_101_tcp, proto_iec60870_101);
4403
4404
  /* Register required preferences for IEC 101 configurable field lengths */
4405
16
  iec60870_101_module = prefs_register_protocol(proto_iec60870_101, NULL);
4406
4407
16
  static const enum_val_t link_addr_len[] = {
4408
16
    {"0", "0 octet", 0},
4409
16
    {"1", "1 octet", 1},
4410
16
    {"2", "2 octet", 2},
4411
16
    {NULL, NULL, -1}
4412
16
  };
4413
4414
16
  static const enum_val_t cot_len[] = {
4415
16
    {"1", "1 octet", 1},
4416
16
    {"2", "2 octet", 2},
4417
16
    {NULL, NULL, -1}
4418
16
  };
4419
4420
16
  static const enum_val_t asdu_addr_len[] = {
4421
16
    {"1", "1 octet", 1},
4422
16
    {"2", "2 octet", 2},
4423
16
    {NULL, NULL, -1}
4424
16
  };
4425
4426
16
  static const enum_val_t asdu_ioa_len[] = {
4427
16
    {"1", "1 octet", 1},
4428
16
    {"2", "2 octet", 2},
4429
16
    {"3", "3 octet", 3},
4430
16
    {NULL, NULL, -1}
4431
16
  };
4432
4433
16
  prefs_register_enum_preference(iec60870_101_module, "linkaddr_len",
4434
16
    "Length of the Link Address Field",
4435
16
    "Length of the Link Address Field, configurable in '101 and absent in '104",
4436
16
    &global_iec60870_link_addr_len, link_addr_len, false);
4437
4438
16
  prefs_register_enum_preference(iec60870_101_module, "cot_len",
4439
16
    "Length of the Cause of Transmission Field",
4440
16
    "Length of the Cause of Transmission Field, configurable in '101 and fixed at 2 octets with '104",
4441
16
    &global_iec60870_cot_len, cot_len, false);
4442
4443
16
  prefs_register_enum_preference(iec60870_101_module, "asdu_addr_len",
4444
16
    "Length of the Common ASDU Address Field",
4445
16
    "Length of the Common ASDU Address Field, configurable in '101 and fixed at 2 octets with '104",
4446
16
    &global_iec60870_asdu_addr_len, asdu_addr_len, false);
4447
4448
16
  prefs_register_enum_preference(iec60870_101_module, "asdu_ioa_len",
4449
16
    "Length of the Information Object Address Field",
4450
16
    "Length of the Information Object Address Field, configurable in '101 and fixed at 3 octets with '104",
4451
16
    &global_iec60870_ioa_len, asdu_ioa_len, false);
4452
4453
16
}
4454
4455
void
4456
proto_reg_handoff_iec60870_101(void)
4457
16
{
4458
  /* Add decode-as connection to determine user-customized TCP port */
4459
16
  dissector_add_for_decode_as_with_preference("tcp.port", iec60870_101_handle);
4460
  /* Add dissection for serial pcap files generated by the RTAC */
4461
16
  dissector_add_for_decode_as("rtacser.data", iec60870_101_handle);
4462
16
}
4463
4464
/******************************************************************************************************/
4465
/* Code to dissect IEC 60870-5-103 Protocol packets */
4466
/******************************************************************************************************/
4467
static int
4468
dissect_iec60870_5_103(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
4469
0
{
4470
/* Set up structures needed to add the protocol subtree and manage it */
4471
0
  proto_item  *iec103_item, *ctrlfield_item;
4472
0
  proto_tree  *iec103_tree, *ctrlfield_tree;
4473
0
  uint8_t   frametype, ctrlfield_prm, linkaddr, asdu_type, sq_num_obj;
4474
0
  uint8_t   offset = 0;
4475
0
  int         i;
4476
4477
  /* Make entries in Protocol column on summary display */
4478
0
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "IEC 60870-5-103");
4479
0
  col_clear(pinfo->cinfo, COL_INFO);
4480
4481
0
  iec103_item = proto_tree_add_item(tree, proto_iec60870_5_103, tvb, 0, -1, ENC_NA);
4482
0
  iec103_tree = proto_item_add_subtree(iec103_item, ett_iec60870_5_103);
4483
4484
  /* Add Frame Format to Protocol Tree */
4485
0
  proto_tree_add_item(iec103_tree, hf_iec60870_5_103_frame, tvb, offset, 1, ENC_LITTLE_ENDIAN);
4486
0
  frametype = tvb_get_uint8(tvb, 0);
4487
0
  offset += 1;
4488
4489
  /* If this is a single character frame, there is nothing left to do... */
4490
0
  if (frametype == IEC103_SINGLE_CHAR) {
4491
0
    return offset;
4492
0
  }
4493
4494
0
  if (frametype == IEC103_VAR_LEN) {
4495
0
    proto_tree_add_item(iec103_tree, hf_iec60870_5_103_length, tvb, offset, 1, ENC_LITTLE_ENDIAN);
4496
0
    proto_tree_add_item(iec103_tree, hf_iec60870_5_103_num_user_octets, tvb, offset+1, 1, ENC_LITTLE_ENDIAN);
4497
0
    proto_tree_add_item(iec103_tree, hf_iec60870_5_103_frame, tvb, offset+2, 1, ENC_LITTLE_ENDIAN);
4498
0
    offset += 3;
4499
0
  }
4500
4501
  /* Fields common to both variable and fixed length frames */
4502
0
  ctrlfield_item = proto_tree_add_item(iec103_tree, hf_iec60870_5_103_ctrlfield, tvb, offset, 1, ENC_LITTLE_ENDIAN);
4503
0
  ctrlfield_tree = proto_item_add_subtree(ctrlfield_item, ett_iec60870_5_103_ctrlfield);
4504
4505
0
  ctrlfield_prm = tvb_get_uint8(tvb, offset) & 0x40;
4506
0
  if (ctrlfield_prm) {
4507
0
    col_append_sep_str(pinfo->cinfo, COL_INFO, ", ", "Pri->Sec");
4508
0
    proto_tree_add_item(ctrlfield_tree, hf_iec60870_5_103_ctrl_prm, tvb, offset, 1, ENC_LITTLE_ENDIAN);
4509
0
    proto_tree_add_item(ctrlfield_tree, hf_iec60870_5_103_ctrl_fcb, tvb, offset, 1, ENC_LITTLE_ENDIAN);
4510
0
    proto_tree_add_item(ctrlfield_tree, hf_iec60870_5_103_ctrl_fcv, tvb, offset, 1, ENC_LITTLE_ENDIAN);
4511
0
    proto_tree_add_item(ctrlfield_tree, hf_iec60870_5_103_ctrl_func_pri_to_sec, tvb, offset, 1, ENC_LITTLE_ENDIAN);
4512
0
  }
4513
0
  else {
4514
0
    col_append_sep_str(pinfo->cinfo, COL_INFO, ", ", "Sec->Pri");
4515
0
    proto_tree_add_item(ctrlfield_tree, hf_iec60870_5_103_ctrl_prm, tvb, offset, 1, ENC_LITTLE_ENDIAN);
4516
0
    proto_tree_add_item(ctrlfield_tree, hf_iec60870_5_103_ctrl_dfc, tvb, offset, 1, ENC_LITTLE_ENDIAN);
4517
0
    proto_tree_add_item(ctrlfield_tree, hf_iec60870_5_103_ctrl_func_sec_to_pri, tvb, offset, 1, ENC_LITTLE_ENDIAN);
4518
0
  }
4519
0
  offset += 1;
4520
4521
0
  proto_tree_add_item_ret_uint8(iec103_tree, hf_iec60870_5_103_linkaddr, tvb, offset, 1, ENC_LITTLE_ENDIAN, &linkaddr);
4522
0
  col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Link Address: %d ", linkaddr);
4523
0
  offset += 1;
4524
4525
  /* If this is a variable length frame, we need to perform additional dissection */
4526
0
  if (frametype == IEC103_VAR_LEN) {
4527
4528
0
    if (ctrlfield_prm) {
4529
0
      proto_tree_add_item(iec103_tree, hf_iec60870_5_103_asdu_typeid_ctrl, tvb, offset, 1, ENC_LITTLE_ENDIAN);
4530
0
      asdu_type = tvb_get_uint8(tvb, offset);
4531
0
    }
4532
0
    else {
4533
0
      proto_tree_add_item(iec103_tree, hf_iec60870_5_103_asdu_typeid_mon, tvb, offset, 1, ENC_LITTLE_ENDIAN);
4534
0
      asdu_type = tvb_get_uint8(tvb, offset);
4535
0
    }
4536
0
    proto_tree_add_item(iec103_tree, hf_iec60870_5_103_sq, tvb, offset+1, 1, ENC_LITTLE_ENDIAN);
4537
0
    sq_num_obj = tvb_get_uint8(tvb, offset+1) & 0x1F;
4538
4539
0
    if (ctrlfield_prm) {
4540
0
      proto_tree_add_item(iec103_tree, hf_iec60870_5_103_cot_ctrl, tvb, offset+2, 1, ENC_LITTLE_ENDIAN);
4541
0
    }
4542
0
    else {
4543
0
      proto_tree_add_item(iec103_tree, hf_iec60870_5_103_cot_mon, tvb, offset+2, 1, ENC_LITTLE_ENDIAN);
4544
0
    }
4545
4546
0
    proto_tree_add_item(iec103_tree, hf_iec60870_5_103_asdu_address, tvb, offset+3, 1, ENC_LITTLE_ENDIAN);
4547
0
    proto_tree_add_item(iec103_tree, hf_iec60870_5_103_func_type, tvb, offset+4, 1, ENC_LITTLE_ENDIAN);
4548
0
    proto_tree_add_item(iec103_tree, hf_iec60870_5_103_info_num, tvb, offset+5, 1, ENC_LITTLE_ENDIAN);
4549
0
    offset += 6;
4550
4551
0
    for(i = 0; i < sq_num_obj; i++) {
4552
      /* Control Direction */
4553
0
      if (ctrlfield_prm) {
4554
0
        switch (asdu_type) {
4555
0
          case 0x06:   /* ASDU 6 - Time synchronization */
4556
0
            get_CP56Time(tvb, &offset, iec103_tree);
4557
0
            break;
4558
0
          case 0x07:   /* ASDU 7 - General interrogation */
4559
0
            proto_tree_add_item(iec103_tree, hf_iec60870_5_103_scn, tvb, offset, 1, ENC_LITTLE_ENDIAN);
4560
0
            offset += 1;
4561
0
            break;
4562
0
          case 0x14:   /* ASDU 20 - general command */
4563
0
            proto_tree_add_item(iec103_tree, hf_iec60870_5_103_dco, tvb, offset, 1, ENC_LITTLE_ENDIAN);
4564
0
            proto_tree_add_item(iec103_tree, hf_iec60870_5_103_rii, tvb, offset+1, 1, ENC_LITTLE_ENDIAN);
4565
0
            offset += 2;
4566
0
            break;
4567
0
          case 0x2d:   /* ASDU 45 - Private, Areva Single command */
4568
0
          case 0x2e:   /* ASDU 46 - Private, Areva Double command */
4569
0
            proto_tree_add_item(iec103_tree, hf_iec60870_5_103_areva_cmd, tvb, offset, 1, ENC_LITTLE_ENDIAN);
4570
0
            offset += 1;
4571
0
            break;
4572
0
        }
4573
0
      }
4574
      /* Monitor Direction */
4575
0
      else {
4576
0
        switch (asdu_type) {
4577
0
          case 0x01:     /* ASDU 1 - Time Tagged Message */
4578
0
            proto_tree_add_item(iec103_tree, hf_iec60870_5_103_dpi, tvb, offset, 1, ENC_LITTLE_ENDIAN);
4579
0
            offset += 1;
4580
0
            get_CP32TimeA(tvb, &offset, iec103_tree);
4581
0
            proto_tree_add_item(iec103_tree, hf_iec60870_5_103_sin, tvb, offset, 1, ENC_LITTLE_ENDIAN);
4582
0
            offset += 1;
4583
0
            break;
4584
0
          case 0x05:    /* ASDU 5 - Identification */
4585
0
            proto_tree_add_item(iec103_tree, hf_iec60870_5_103_col, tvb, offset, 1, ENC_LITTLE_ENDIAN);
4586
0
            offset += 1;
4587
0
            proto_tree_add_item(iec103_tree, hf_iec60870_5_103_mfg, tvb, offset, 8, ENC_ASCII);
4588
0
            offset += 8;
4589
0
            proto_tree_add_item(iec103_tree, hf_iec60870_5_103_mfg_sw, tvb, offset, 4, ENC_LITTLE_ENDIAN);
4590
0
            offset += 4;
4591
0
            break;
4592
0
          case 0x06:    /* ASDU 6 - Time synchronization */
4593
0
            get_CP56Time(tvb, &offset, iec103_tree);
4594
0
            break;
4595
0
          case 0x08:    /* ASDU 8 - Termination of general interrogation */
4596
0
            proto_tree_add_item(iec103_tree, hf_iec60870_5_103_scn, tvb, offset, 1, ENC_LITTLE_ENDIAN);
4597
0
            offset += 1;
4598
0
            break;
4599
0
          case 0x09:    /* ASDU 9 - Measurements II */
4600
0
            get_NVA(tvb, &offset, iec103_tree);
4601
0
            break;
4602
0
          case 0xcd:    /* ASDU 205 - private, siemens energy counters */
4603
0
            proto_tree_add_item(iec103_tree, hf_iec60870_5_103_asdu205_value, tvb, offset, 4, ENC_LITTLE_ENDIAN);
4604
0
            proto_tree_add_item(iec103_tree, hf_iec60870_5_103_asdu205_ms, tvb, offset+4, 2, ENC_LITTLE_ENDIAN);
4605
0
            proto_tree_add_item(iec103_tree, hf_iec60870_5_103_asdu205_min, tvb, offset+6, 1, ENC_LITTLE_ENDIAN);
4606
0
            proto_tree_add_item(iec103_tree, hf_iec60870_5_103_asdu205_h, tvb, offset+7, 1, ENC_LITTLE_ENDIAN);
4607
0
            offset += 8;
4608
0
            break;
4609
0
        }
4610
4611
0
      }
4612
0
    }
4613
0
  }
4614
4615
0
  proto_tree_add_item(iec103_tree, hf_iec60870_5_103_checksum, tvb, offset, 1, ENC_LITTLE_ENDIAN);
4616
0
  proto_tree_add_item(iec103_tree, hf_iec60870_5_103_stopchar, tvb, offset+1, 1, ENC_LITTLE_ENDIAN);
4617
0
  offset += 2;
4618
4619
0
  return offset;
4620
4621
0
}
4622
4623
/******************************************************************************************************/
4624
/* Return length of IEC 103 Protocol over TCP message (used for re-assembly)             */
4625
/******************************************************************************************************/
4626
static unsigned
4627
get_iec103_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset _U_, void *data _U_)
4628
0
{
4629
4630
0
  unsigned len=0, type;
4631
0
  type = tvb_get_uint8(tvb, offset);
4632
4633
0
  switch (type) {
4634
0
    case IEC103_SINGLE_CHAR:
4635
0
      len = 1;
4636
0
      break;
4637
0
    case IEC103_FIXED_LEN:
4638
0
      len = 5;
4639
0
      break;
4640
0
    case IEC103_VAR_LEN:
4641
0
      len = tvb_get_uint8(tvb, offset+1) + 6;
4642
0
      break;
4643
0
  }
4644
4645
0
  return len;
4646
0
}
4647
4648
/******************************************************************************************************/
4649
/* Dissect (and possibly Re-assemble) IEC 103 protocol payload data */
4650
/******************************************************************************************************/
4651
static int
4652
dissect_iec60870_5_103_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
4653
0
{
4654
4655
0
  unsigned type = tvb_get_uint8(tvb, 0);
4656
4657
  /* Check that this is actually a IEC 60870-5-103 packet. */
4658
0
  switch (type) {
4659
0
    case IEC103_SINGLE_CHAR:
4660
0
    case IEC103_FIXED_LEN:
4661
0
    case IEC103_VAR_LEN:
4662
0
      tcp_dissect_pdus(tvb, pinfo, tree, true, 1, get_iec103_len, dissect_iec60870_5_103, data);
4663
0
      break;
4664
0
    default:
4665
0
      return 0;
4666
0
  }
4667
4668
0
  return tvb_captured_length(tvb);
4669
0
}
4670
4671
/* IEC 60870-5-103 Protocol registration hand-off routine */
4672
void
4673
proto_register_iec60870_5_103(void)
4674
16
{
4675
  /* IEC 103 Protocol header fields */
4676
16
  static hf_register_info iec60870_5_103_hf[] = {
4677
16
    { &hf_iec60870_5_103_areva_cmd,
4678
16
    { "Areva Command Code", "iec60870_5_103.areva_cmd", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
4679
16
    { &hf_iec60870_5_103_asdu_address,
4680
16
    { "ASDU Common Address", "iec60870_5_103.asdu_address", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4681
16
    { &hf_iec60870_5_103_asdu_typeid_ctrl,
4682
16
    { "ASDU Type ID (Ctrl Direction)", "iec60870_5_103.asdu_typeid_ctrl", FT_UINT8, BASE_HEX, VALS(iec103_asdu_types_control_dir), 0x0, NULL, HFILL }},
4683
16
    { &hf_iec60870_5_103_asdu_typeid_mon,
4684
16
    { "ASDU Type ID (Monitor Direction)", "iec60870_5_103.asdu_typeid_mon", FT_UINT8, BASE_HEX, VALS(iec103_asdu_types_monitor_dir), 0x0, NULL, HFILL }},
4685
16
    { &hf_iec60870_5_103_asdu205_ms,
4686
16
    { "Timestamp: Milliseconds", "iec60870_5_103.asdu205_ms", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4687
16
    { &hf_iec60870_5_103_asdu205_min,
4688
16
    { "Timestamp: Minutes", "iec60870_5_103.asdu205_min", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4689
16
    { &hf_iec60870_5_103_asdu205_h,
4690
16
    { "Timestamp: Hours", "iec60870_5_103.asdu205_h", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4691
16
    { &hf_iec60870_5_103_asdu205_value,
4692
16
    { "Counter Value", "iec60870_5_103.asdu205_value", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4693
16
    { &hf_iec60870_5_103_checksum,
4694
16
    { "Checksum", "iec60870_5_103.checksum", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
4695
16
    { &hf_iec60870_5_103_col,
4696
16
    { "Compatibility Level", "iec60870_5_103.col", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4697
16
    { &hf_iec60870_5_103_cot_ctrl,
4698
16
    { "Cause of Transmission (Ctrl Direction)", "iec60870_5_103.cot_ctrl", FT_UINT8, BASE_HEX, VALS(iec60870_5_103_cot_ctrl_dir), 0x0, NULL, HFILL }},
4699
16
    { &hf_iec60870_5_103_cot_mon,
4700
16
    { "Cause of Transmission (Monitored Direction)", "iec60870_5_103.cot_mon", FT_UINT8, BASE_HEX, VALS(iec60870_5_103_cot_monitor_dir), 0x0, NULL, HFILL }},
4701
16
    { &hf_iec60870_5_103_cp32time2a,
4702
16
    { "CP32Time2a", "iec60870_5_103.cp32time2a", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0, NULL, HFILL }},
4703
16
    { &hf_iec60870_5_103_cp32time2a_ms,
4704
16
    { "Milliseconds", "iec60870_5_103.cp32time2a_ms", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4705
16
    { &hf_iec60870_5_103_cp32time2a_min,
4706
16
    { "Minutes", "iec60870_5_103.cp32time2a_min", FT_UINT8, BASE_DEC, NULL, 0x3f, NULL, HFILL }},
4707
16
    { &hf_iec60870_5_103_cp32time2a_res1,
4708
16
    { "Res1", "iec60870_5_103.cp32time2a_res1", FT_UINT8, BASE_DEC, NULL, 0x40, NULL, HFILL }},
4709
16
    { &hf_iec60870_5_103_cp32time2a_iv,
4710
16
    { "Invalid", "iec60870_5_103.cp32time2a_iv", FT_UINT8, BASE_DEC, NULL, 0x80, NULL, HFILL }},
4711
16
    { &hf_iec60870_5_103_cp32time2a_hr,
4712
16
    { "Hours", "iec60870_5_103.cp32time2a_hr", FT_UINT8, BASE_DEC, NULL, 0x1f, NULL, HFILL }},
4713
16
    { &hf_iec60870_5_103_cp32time2a_res2,
4714
16
    { "Res2", "iec60870_5_103.cp32time2a_res2", FT_UINT8, BASE_DEC, NULL, 0x60, NULL, HFILL }},
4715
16
    { &hf_iec60870_5_103_cp32time2a_sum,
4716
16
    { "Summer Time", "iec60870_5_103.cp32time2a_sum", FT_UINT8, BASE_DEC, NULL, 0x80, NULL, HFILL }},
4717
16
    { &hf_iec60870_5_103_ctrlfield,
4718
16
    { "Control Field", "iec60870_5_103.ctrlfield", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
4719
16
    { &hf_iec60870_5_103_ctrl_prm,
4720
16
    { "PRM", "iec60870_5_103.ctrl_prm", FT_UINT8, BASE_DEC, VALS(iec60870_5_103_ctrl_prm_values), 0x40, "Primary Message", HFILL }},
4721
16
    { &hf_iec60870_5_103_ctrl_fcb,
4722
16
    { "FCB", "iec60870_5_103.ctrl_fcb", FT_UINT8, BASE_DEC, NULL, 0x20, "Frame Count Bit", HFILL }},
4723
16
    { &hf_iec60870_5_103_ctrl_fcv,
4724
16
    { "FCV", "iec60870_5_103.ctrl_fcv", FT_UINT8, BASE_DEC, NULL, 0x10, "Frame Count Bit Valid", HFILL }},
4725
16
    { &hf_iec60870_5_103_ctrl_dfc,
4726
16
    { "DFC", "iec60870_5_103.ctrl_dfc", FT_UINT8, BASE_DEC, NULL, 0x10, "Data Flow Control", HFILL }},
4727
16
    { &hf_iec60870_5_103_ctrl_func_pri_to_sec,
4728
16
    { "CF Func Code", "iec60870_5_103.ctrl_func_pri_to_sec", FT_UINT8, BASE_DEC, VALS(iec60870_5_103_ctrl_func_pri_to_sec_values), 0x0F, "Control Field Function Code, Pri to Sec", HFILL }},
4729
16
    { &hf_iec60870_5_103_ctrl_func_sec_to_pri,
4730
16
    { "CF Func Code", "iec60870_5_103.ctrl_func_sec_to_pri", FT_UINT8, BASE_DEC, VALS(iec60870_5_103_ctrl_func_sec_to_pri_values), 0x0F, "Control Field Function Code, Sec to Pri", HFILL }},
4731
16
    { &hf_iec60870_5_103_dco,
4732
16
    { "Double Command Type", "iec60870_5_103.dco", FT_UINT8, BASE_DEC, VALS(iec103_quadstate_types), 0x0, NULL, HFILL }},
4733
16
    { &hf_iec60870_5_103_dpi,
4734
16
    { "Double Point Information", "iec60870_5_103.dpi", FT_UINT8, BASE_DEC, VALS(iec103_quadstate_types), 0x0, NULL, HFILL }},
4735
16
    { &hf_iec60870_5_103_frame,
4736
16
    { "Frame Format", "iec60870_5_103.header", FT_UINT8, BASE_HEX, VALS(iec60870_5_103_frame_vals), 0x0, NULL, HFILL }},
4737
16
    { &hf_iec60870_5_103_func_type,
4738
16
    { "Function Type", "iec60870_5_103.func_type", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4739
16
    { &hf_iec60870_5_103_info_num,
4740
16
    { "Information Number", "iec60870_5_103.info_num", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4741
16
    { &hf_iec60870_5_103_length,
4742
16
    { "Length", "iec60870_5_103.length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4743
16
    { &hf_iec60870_5_103_linkaddr,
4744
16
    { "Data Link Address", "iec60870_5_103.linkaddr", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4745
16
    { &hf_iec60870_5_103_mfg,
4746
16
    { "Manufacturer Identity", "iec60870_5_103.mfg", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
4747
16
    { &hf_iec60870_5_103_mfg_sw,
4748
16
    { "Manufacturer's Software Identification", "iec60870_5_103.mfg_sw", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4749
16
    { &hf_iec60870_5_103_num_user_octets,
4750
16
    { "Number of User Octets", "iec60870_5_103.num_user_octets", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4751
16
    { &hf_iec60870_5_103_rii,
4752
16
    { "Return Information Identifier", "iec60870_5_103.rii", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4753
16
    { &hf_iec60870_5_103_scn,
4754
16
    { "Scan Number", "iec60870_5_103.scn", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4755
16
    { &hf_iec60870_5_103_sin,
4756
16
    { "Supplementary Information", "iec60870_5_103.sin", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4757
16
    { &hf_iec60870_5_103_sq,
4758
16
    { "Structured Qualifier", "iec60870_5_103.sq", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
4759
16
    { &hf_iec60870_5_103_stopchar,
4760
16
    { "Stop Character", "iec60870_5_103.stopchar", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
4761
16
  };
4762
4763
  /* Setup protocol subtree array */
4764
16
  static int *ett_serial[] = {
4765
16
    &ett_iec60870_5_103,
4766
16
    &ett_iec60870_5_103_ctrlfield,
4767
16
    &ett_iec60870_5_103_cp32time2a,
4768
16
  };
4769
4770
  /* Register the protocol name and description */
4771
16
  proto_iec60870_5_103 = proto_register_protocol("IEC 60870-5-103", "IEC 60870-5-103", "iec60870_5_103");
4772
4773
  /* Required function calls to register the header fields and subtrees used */
4774
16
  proto_register_field_array(proto_iec60870_5_103, iec60870_5_103_hf, array_length(iec60870_5_103_hf));
4775
16
  proto_register_subtree_array(ett_serial, array_length(ett_serial));
4776
4777
16
  iec60870_5_103_handle = register_dissector("iec60870_5_103", dissect_iec60870_5_103_tcp, proto_iec60870_5_103);
4778
16
}
4779
4780
void
4781
proto_reg_handoff_iec60870_5_103(void)
4782
16
{
4783
  /* Add decode-as connection to determine user-customized TCP port */
4784
16
  dissector_add_for_decode_as_with_preference("tcp.port", iec60870_5_103_handle);
4785
  /* Add dissection for serial pcap files generated by the RTAC */
4786
16
  dissector_add_for_decode_as("rtacser.data", iec60870_5_103_handle);
4787
16
}
4788
4789
4790
/*
4791
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
4792
 *
4793
 * Local variables:
4794
 * c-basic-offset: 8
4795
 * tab-width: 8
4796
 * indent-tabs-mode: t
4797
 * End:
4798
 *
4799
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
4800
 * :indentSize=8:tabSize=8:noTabs=false:
4801
 */