Coverage Report

Created: 2026-05-14 06:28

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
15
#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
88.9k
#define APCI_START  0x68
79
3.15k
#define APCI_LEN  6
80
925
#define APCI_START_LEN  2
81
925
#define APCI_DATA_LEN (APCI_LEN - APCI_START_LEN)
82
1.07k
#define APDU_MIN_LEN  4
83
976
#define APDU_MAX_LEN  253
84
85
/* ASDU_HEAD_LEN: Includes Asdu head and first IOA */
86
#define ASDU_HEAD_LEN 9
87
1.91k
#define F_TEST  0x80
88
1.91k
#define F_NEGA  0x40
89
966
#define F_CAUSE 0x3F
90
1.76k
#define F_SQ    0x80
91
92
/* APCI types */
93
94
/* Type I is only lowest bit set to 0 */
95
2.86k
#define I_TYPE    0
96
15
#define S_TYPE    1
97
25
#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
242
#define M_SP_NA_1  1    /* single-point information                 */
127
131
#define M_SP_TA_1  2    /* single-point information with time tag             */
128
274
#define M_DP_NA_1  3    /* double-point information                 */
129
210
#define M_DP_TA_1  4    /* double-point information with time tag             */
130
234
#define M_ST_NA_1  5    /* step position information                */
131
204
#define M_ST_TA_1  6    /* step position information with time tag            */
132
168
#define M_BO_NA_1  7    /* bitstring of 32 bits                 */
133
180
#define M_BO_TA_1  8    /* bitstring of 32 bits with time tag               */
134
283
#define M_ME_NA_1  9    /* measured value, normalized value               */
135
300
#define M_ME_TA_1  10    /* measured value, normalized value with time tag           */
136
264
#define M_ME_NB_1  11    /* measured value, scaled value               */
137
323
#define M_ME_TB_1  12    /* measured value, scaled value with time tag             */
138
243
#define M_ME_NC_1  13    /* measured value, short floating point number          */
139
274
#define M_ME_TC_1  14    /* measured value, short floating point number with time tag        */
140
353
#define M_IT_NA_1  15    /* integrated totals                  */
141
483
#define M_IT_TA_1  16    /* integrated totals with time tag              */
142
354
#define M_EP_TA_1  17    /* event of protection equipment with time tag          */
143
373
#define M_EP_TB_1  18    /* packed start events of protection equipment with time tag        */
144
367
#define M_EP_TC_1  19    /* packed output circuit information of protection equipment with time tag    */
145
300
#define M_PS_NA_1  20    /* packed single-point information with status change detection       */
146
319
#define M_ME_ND_1  21    /* measured value, normalized value without quality descriptor      */
147
178
#define M_SP_TB_1  30    /* single-point information with time tag CP56Time2a          */
148
163
#define M_DP_TB_1  31    /* double-point information with time tag CP56Time2a          */
149
242
#define M_ST_TB_1  32    /* step position information with time tag CP56Time2a           */
150
215
#define M_BO_TB_1  33    /* bitstring of 32 bit with time tag CP56Time2a           */
151
357
#define M_ME_TD_1  34    /* measured value, normalized value with time tag CP56Time2a        */
152
377
#define M_ME_TE_1  35    /* measured value, scaled value with time tag CP56Time2a        */
153
426
#define M_ME_TF_1  36    /* measured value, short floating point number with time tag CP56Time2a     */
154
380
#define M_IT_TB_1  37    /* integrated totals with time tag CP56Time2a             */
155
420
#define M_EP_TD_1  38    /* event of protection equipment with time tag CP56Time2a         */
156
370
#define M_EP_TE_1  39    /* packed start events of protection equipment with time tag CP56Time2a     */
157
380
#define M_EP_TF_1  40    /* packed output circuit information of protection equipment with time tag CP56Time2a   */
158
391
#define S_IT_TC_1  41    /* integrated totals containing time tagged security statistics     */
159
430
#define C_SC_NA_1  45    /* single command                   */
160
661
#define C_DC_NA_1  46    /* double command                   */
161
712
#define C_RC_NA_1  47    /* regulating step command                */
162
527
#define C_SE_NA_1  48    /* set point command, normalized value            */
163
717
#define C_SE_NB_1  49    /* set point command, scaled value              */
164
519
#define C_SE_NC_1  50    /* set point command, short floating point number           */
165
545
#define C_BO_NA_1  51    /* bitstring of 32 bits                 */
166
480
#define C_SC_TA_1  58    /* single command with time tag CP56Time2a            */
167
568
#define C_DC_TA_1  59    /* double command with time tag CP56Time2a            */
168
519
#define C_RC_TA_1  60    /* regulating step command with time tag CP56Time2a           */
169
512
#define C_SE_TA_1  61    /* set point command, normalized value with time tag CP56Time2a       */
170
497
#define C_SE_TB_1  62    /* set point command, scaled value with time tag CP56Time2a         */
171
504
#define C_SE_TC_1  63    /* set point command, short floating-point number with time tag CP56Time2a    */
172
568
#define C_BO_TA_1  64    /* bitstring of 32 bits with time tag CP56Time2a          */
173
530
#define M_EI_NA_1  70    /* end of initialization                */
174
1.90k
#define S_CH_NA_1  81    /* authentication challenge               */
175
24
#define S_RP_NA_1  82    /* authentication reply               */
176
77
#define S_AR_NA_1  83    /* aggressive mode authentication request session key status request      */
177
8
#define S_KR_NA_1  84    /* session key status request               */
178
71
#define S_KS_NA_1  85    /* session key status                 */
179
65
#define S_KC_NA_1  86    /* session key change                 */
180
137
#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
349
#define S_UC_NA_1  95    /* update key change confirmation             */
187
648
#define C_IC_NA_1  100    /* interrogation command                */
188
691
#define C_CI_NA_1  101    /* counter interrogation command              */
189
#define C_RD_NA_1  102    /* read command                   */
190
565
#define C_CS_NA_1  103    /* clock synchronization command              */
191
1.05k
#define C_TS_NA_1  104    /* test command                                                                       */
192
712
#define C_RP_NA_1  105    /* reset process command                */
193
931
#define C_CD_NA_1  106    /* delay acquisition command                */
194
665
#define C_TS_TA_1  107    /* test command with time tag CP56Time2a            */
195
636
#define P_ME_NA_1  110    /* parameter of measured value, normalized value          */
196
636
#define P_ME_NB_1  111    /* parameter of measured value, scaled value            */
197
757
#define P_ME_NC_1  112    /* parameter of measured value, short floating-point number         */
198
658
#define P_AC_NA_1  113    /* parameter activation                 */
199
648
#define F_FR_NA_1  120    /* file ready                   */
200
685
#define F_SR_NA_1  121    /* section ready                  */
201
670
#define F_SC_NA_1  122    /* call directory, select file, call file, call section         */
202
689
#define F_LS_NA_1  123    /* last section, last segment               */
203
717
#define F_AF_NA_1  124    /* ack file, ack section                */
204
661
#define F_SG_NA_1  125    /* segment                    */
205
668
#define F_DR_TA_1  126    /* directory                    */
206
711
#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
939
{
1401
939
  uint16_t ms;
1402
939
  uint8_t min;
1403
939
  nstime_t nstime;
1404
939
  proto_item* ti;
1405
939
  proto_tree* cp24time_tree;
1406
1407
939
  ms = tvb_get_letohs(tvb, *offset);
1408
939
  nstime.nsecs = (ms % 1000) * 1000000;
1409
939
  nstime.secs = ms / 1000;
1410
939
  (*offset) += 2;
1411
1412
939
  min = tvb_get_uint8(tvb, *offset);
1413
939
  nstime.secs += (min & 0x3F) * 60;
1414
939
  (*offset)++;
1415
1416
939
  (*offset) -= 3;
1417
1418
939
  ti = proto_tree_add_time(iec104_header_tree, hf_cp24time, tvb, *offset, 3, &nstime);
1419
939
  cp24time_tree = proto_item_add_subtree(ti, ett_cp24time);
1420
1421
939
  proto_tree_add_item(cp24time_tree, hf_cp24time_ms, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
1422
939
  (*offset) += 2;
1423
1424
939
  proto_tree_add_item(cp24time_tree, hf_cp24time_min, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1425
939
  proto_tree_add_item(cp24time_tree, hf_cp24time_iv, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1426
939
  (*offset) ++;
1427
939
}
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
730
{
1477
730
  uint16_t ms;
1478
730
  uint8_t value;
1479
730
  uint8_t su;
1480
730
  struct tm tm;
1481
730
  nstime_t  datetime;
1482
730
  proto_item* ti;
1483
730
  proto_tree* cp56time_tree;
1484
1485
730
  ms = tvb_get_letohs(tvb, *offset);
1486
730
  tm.tm_sec = ms / 1000;
1487
730
  datetime.nsecs = (ms % 1000) * 1000000;
1488
730
  (*offset) += 2;
1489
1490
730
  value = tvb_get_uint8(tvb, *offset);
1491
730
  tm.tm_min = value & 0x3F;
1492
730
  (*offset)++;
1493
1494
730
  value = tvb_get_uint8(tvb, *offset);
1495
730
  tm.tm_hour = value & 0x1F;
1496
730
  su = value & 0x80;
1497
730
  (*offset)++;
1498
1499
730
  value = tvb_get_uint8(tvb, *offset);
1500
730
  tm.tm_mday = value & 0x1F;
1501
730
  (*offset)++;
1502
1503
730
  value = tvb_get_uint8(tvb, *offset);
1504
730
  tm.tm_mon = (value & 0x0F) - 1;
1505
730
  (*offset)++;
1506
1507
730
  value = tvb_get_uint8(tvb, *offset);
1508
730
  tm.tm_year = value & 0x7F;
1509
730
  if (tm.tm_year < 70)
1510
450
    tm.tm_year += 100;
1511
1512
730
  (*offset)++;
1513
1514
730
  if (su)
1515
241
    tm.tm_isdst = 1;
1516
489
  else
1517
489
    tm.tm_isdst = -1; /* there's no info on whether DST was in force; assume it's
1518
           * the same as currently */
1519
1520
730
  datetime.secs = mktime(&tm);
1521
1522
730
  (*offset) -= 7;
1523
1524
730
  ti = proto_tree_add_time(iec104_header_tree, hfindex, tvb, *offset, 7, &datetime);
1525
730
  cp56time_tree = proto_item_add_subtree(ti, ett_cp56time);
1526
1527
730
  proto_tree_add_item(cp56time_tree, hf_cp56time_ms, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
1528
730
  (*offset) += 2;
1529
1530
730
  proto_tree_add_item(cp56time_tree, hf_cp56time_min, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1531
730
  proto_tree_add_item(cp56time_tree, hf_cp56time_gen, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1532
730
  proto_tree_add_item(cp56time_tree, hf_cp56time_iv, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1533
730
  (*offset) ++;
1534
1535
730
  proto_tree_add_item(cp56time_tree, hf_cp56time_hour, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1536
730
  proto_tree_add_item(cp56time_tree, hf_cp56time_su, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1537
730
  (*offset) ++;
1538
1539
730
  proto_tree_add_item(cp56time_tree, hf_cp56time_day, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1540
730
  proto_tree_add_item(cp56time_tree, hf_cp56time_dow, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1541
730
  (*offset) ++;
1542
1543
730
  proto_tree_add_item(cp56time_tree, hf_cp56time_month, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1544
730
  (*offset) ++;
1545
1546
730
  proto_tree_add_item(cp56time_tree, hf_cp56time_year, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1547
730
  (*offset) ++;
1548
730
}
1549
1550
static void get_CP56Time(tvbuff_t* tvb, uint8_t* offset, proto_tree* iec104_header_tree)
1551
662
{
1552
662
  decode_CP56Time(tvb, offset, hf_cp56time, iec104_header_tree);
1553
662
}
1554
1555
static void get_RangeStartCP56Time(tvbuff_t* tvb, uint8_t* offset, proto_tree* iec104_header_tree)
1556
34
{
1557
34
  decode_CP56Time(tvb, offset, hf_range_start_cp56time, iec104_header_tree);
1558
34
}
1559
1560
static void get_RangeStopCP56Time(tvbuff_t* tvb, uint8_t* offset, proto_tree* iec104_header_tree)
1561
34
{
1562
34
  decode_CP56Time(tvb, offset, hf_range_stop_cp56time, iec104_header_tree);
1563
34
}
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
588
{
1570
588
  proto_tree_add_item(iec104_header_tree, hf_cp16time, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
1571
588
  (*offset) += 2;
1572
588
}
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
3.04k
{
1580
3.04k
  proto_item* ti = NULL;
1581
1582
  /* Information object address */
1583
  /* Support both 16 and 24-bit IOA addresses */
1584
3.04k
  ti = proto_tree_add_item_ret_uint(iec104_header_tree, hf_ioa, tvb, *offset, ioa_len, ENC_LITTLE_ENDIAN, asdu_info_obj_addr);
1585
3.04k
  (*offset) += ioa_len;
1586
1587
3.04k
  return ti;
1588
3.04k
}
1589
1590
/* ====================================================================
1591
   TypeId length
1592
   ==================================================================== */
1593
static uint8_t get_TypeIdLength(uint8_t TypeId)
1594
975
{
1595
975
  uint8_t ret = 0;
1596
975
  const td_asdu_length *item;
1597
1598
975
  item = asdu_length;
1599
41.1k
  while (item->value)
1600
40.9k
  {
1601
40.9k
    if (item->value == TypeId)
1602
826
    {
1603
826
      ret = item->length;
1604
826
      break;
1605
826
    }
1606
40.1k
    item++;
1607
40.1k
  }
1608
1609
975
  return ret;
1610
975
}
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
333
{
1617
333
  proto_item* ti;
1618
333
  proto_tree* siq_tree;
1619
1620
333
  ti = proto_tree_add_item(iec104_header_tree, hf_siq, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1621
333
  siq_tree = proto_item_add_subtree(ti, ett_siq);
1622
1623
333
  proto_tree_add_item(siq_tree, hf_siq_spi, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1624
333
  proto_tree_add_item(siq_tree, hf_siq_bl, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1625
333
  proto_tree_add_item(siq_tree, hf_siq_sb, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1626
333
  proto_tree_add_item(siq_tree, hf_siq_nt, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1627
333
  proto_tree_add_item(siq_tree, hf_siq_iv, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1628
1629
333
  (*offset)++;
1630
333
}
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
356
{
1637
356
  proto_item* ti;
1638
356
  proto_tree* diq_tree;
1639
1640
356
  ti = proto_tree_add_item(iec104_header_tree, hf_diq, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1641
356
  diq_tree = proto_item_add_subtree(ti, ett_diq);
1642
1643
356
  proto_tree_add_item(diq_tree, hf_diq_dpi, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1644
356
  proto_tree_add_item(diq_tree, hf_diq_bl, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1645
356
  proto_tree_add_item(diq_tree, hf_diq_sb, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1646
356
  proto_tree_add_item(diq_tree, hf_diq_nt, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1647
356
  proto_tree_add_item(diq_tree, hf_diq_iv, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1648
1649
356
  (*offset)++;
1650
356
}
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
887
{
1657
887
  proto_item* ti;
1658
887
  proto_tree* qds_tree;
1659
1660
887
  ti = proto_tree_add_item(iec104_header_tree, hf_qds, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1661
887
  qds_tree = proto_item_add_subtree(ti, ett_qds);
1662
1663
887
  proto_tree_add_item(qds_tree, hf_qds_ov, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1664
887
  proto_tree_add_item(qds_tree, hf_qds_bl, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1665
887
  proto_tree_add_item(qds_tree, hf_qds_sb, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1666
887
  proto_tree_add_item(qds_tree, hf_qds_nt, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1667
887
  proto_tree_add_item(qds_tree, hf_qds_iv, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1668
1669
887
  (*offset)++;
1670
887
}
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
153
{
1678
153
  proto_item* ti;
1679
153
  proto_tree* qdp_tree;
1680
1681
153
  ti = proto_tree_add_item(iec104_header_tree, hf_qdp, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1682
153
  qdp_tree = proto_item_add_subtree(ti, ett_qdp);
1683
1684
153
  proto_tree_add_item(qdp_tree, hf_qdp_ei, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1685
153
  proto_tree_add_item(qdp_tree, hf_qdp_bl, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1686
153
  proto_tree_add_item(qdp_tree, hf_qdp_sb, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1687
153
  proto_tree_add_item(qdp_tree, hf_qdp_nt, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1688
153
  proto_tree_add_item(qdp_tree, hf_qdp_iv, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1689
1690
153
  (*offset)++;
1691
153
}
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
290
{
1698
290
  proto_item* ti;
1699
290
  proto_tree* vti_tree;
1700
1701
290
  ti = proto_tree_add_item(iec104_header_tree, hf_vti, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1702
290
  vti_tree = proto_item_add_subtree(ti, ett_vti);
1703
1704
290
  proto_tree_add_item(vti_tree, hf_vti_v, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1705
290
  proto_tree_add_item(vti_tree, hf_vti_t, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1706
1707
290
  (*offset)++;
1708
290
}
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
243
{
1715
243
  int16_t value;
1716
243
  float fvalue;
1717
1718
243
  value = tvb_get_letohis(tvb, *offset);
1719
243
  fvalue = (float)value / 32768;
1720
1721
  /* Normalized value F16[1..16]<-1..+1-2^-15> */
1722
243
  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
243
  (*offset) += 2;
1725
243
}
1726
1727
static void get_NVAspt(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
1728
120
{
1729
120
  int16_t value;
1730
120
  float fvalue;
1731
1732
120
  value = tvb_get_letohis(tvb, *offset);
1733
120
  fvalue = (float)value / 32768;
1734
1735
  /* Normalized value F16[1..16]<-1..+1-2^-15> */
1736
120
  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
120
  (*offset) += 2;
1739
120
}
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
177
{
1746
  /* Scaled value I16[1..16]<-2^15..+2^15-1> */
1747
177
  proto_tree_add_item(iec104_header_tree, hf_asdu_scalval, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
1748
1749
177
  (*offset) += 2;
1750
177
}
1751
1752
static void get_SVAspt(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
1753
274
{
1754
  /* Scaled value I16[1..16]<-2^15..+2^15-1> */
1755
274
  proto_tree_add_item(iec104_header_tree, hf_asdu_scalval, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
1756
1757
274
  (*offset) += 2;
1758
274
}
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
219
{
1765
  /* --------  IEEE 754 float value */
1766
219
  proto_tree_add_item(iec104_header_tree, hf_asdu_float, tvb, *offset, 4, ENC_LITTLE_ENDIAN);
1767
1768
219
  (*offset) += 4;
1769
219
}
1770
1771
static void get_FLTspt(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
1772
72
{
1773
  /* --------  IEEE 754 float value */
1774
72
  proto_tree_add_item(iec104_header_tree, hf_asdu_float, tvb, *offset, 4, ENC_LITTLE_ENDIAN);
1775
1776
72
  (*offset) += 4;
1777
72
}
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
344
{
1784
344
  proto_item* ti;
1785
344
  proto_tree* bcr_tree;
1786
1787
344
  ti = proto_tree_add_item(iec104_header_tree, hf_bcr, tvb, *offset, 4, ENC_LITTLE_ENDIAN);
1788
344
  bcr_tree = proto_item_add_subtree(ti, ett_vti);
1789
1790
344
  proto_tree_add_item(bcr_tree, hf_bcr_count, tvb, *offset, 4, ENC_LITTLE_ENDIAN);
1791
344
  (*offset) += 4;
1792
1793
344
  proto_tree_add_item(bcr_tree, hf_bcr_sq, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1794
344
  proto_tree_add_item(bcr_tree, hf_bcr_cy, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1795
344
  proto_tree_add_item(bcr_tree, hf_bcr_ca, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1796
344
  proto_tree_add_item(bcr_tree, hf_bcr_iv, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1797
344
  (*offset)++;
1798
344
}
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
122
{
1805
122
  proto_item* ti;
1806
122
  proto_tree* sep_tree;
1807
1808
122
  ti = proto_tree_add_item(iec104_header_tree, hf_sep, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1809
122
  sep_tree = proto_item_add_subtree(ti, ett_sep);
1810
1811
122
  proto_tree_add_item(sep_tree, hf_sep_es, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1812
122
  proto_tree_add_item(sep_tree, hf_sep_ei, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1813
122
  proto_tree_add_item(sep_tree, hf_sep_bl, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1814
122
  proto_tree_add_item(sep_tree, hf_sep_sb, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1815
122
  proto_tree_add_item(sep_tree, hf_sep_nt, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1816
122
  proto_tree_add_item(sep_tree, hf_sep_iv, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1817
1818
122
  (*offset)++;
1819
122
}
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
78
{
1826
78
  proto_item* ti;
1827
78
  proto_tree* spe_tree;
1828
1829
78
  ti = proto_tree_add_item(iec104_header_tree, hf_spe, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1830
78
  spe_tree = proto_item_add_subtree(ti, ett_spe);
1831
1832
78
  proto_tree_add_item(spe_tree, hf_spe_gs, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1833
78
  proto_tree_add_item(spe_tree, hf_spe_sl1, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1834
78
  proto_tree_add_item(spe_tree, hf_spe_sl2, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1835
78
  proto_tree_add_item(spe_tree, hf_spe_sl3, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1836
78
  proto_tree_add_item(spe_tree, hf_spe_sie, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1837
78
  proto_tree_add_item(spe_tree, hf_spe_srd, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1838
1839
78
  (*offset)++;
1840
78
}
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
75
{
1847
75
  proto_item* ti;
1848
75
  proto_tree* oci_tree;
1849
1850
75
  ti = proto_tree_add_item(iec104_header_tree, hf_oci, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1851
75
  oci_tree = proto_item_add_subtree(ti, ett_oci);
1852
1853
75
  proto_tree_add_item(oci_tree, hf_oci_gc, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1854
75
  proto_tree_add_item(oci_tree, hf_oci_cl1, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1855
75
  proto_tree_add_item(oci_tree, hf_oci_cl2, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1856
75
  proto_tree_add_item(oci_tree, hf_oci_cl3, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1857
1858
75
  (*offset)++;
1859
75
}
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
103
{
1866
103
  proto_tree_add_bits_item(iec104_header_tree, hf_asdu_bitstring, tvb, *offset * 8, 32, ENC_LITTLE_ENDIAN);
1867
1868
103
  (*offset) += 4;
1869
103
}
1870
1871
static void get_BSIspt(tvbuff_t* tvb, uint8_t* offset, proto_tree* iec104_header_tree)
1872
131
{
1873
131
  proto_tree_add_bits_item(iec104_header_tree, hf_asdu_bitstring, tvb, *offset * 8, 32, ENC_LITTLE_ENDIAN);
1874
1875
131
  (*offset) += 4;
1876
131
}
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
476
{
1883
476
  proto_tree_add_item(iec104_header_tree, hf_fbp, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
1884
1885
476
  (*offset) += 2;
1886
476
}
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
53
{
1893
53
  proto_item* ti;
1894
53
  proto_tree* sco_tree;
1895
1896
53
  ti = proto_tree_add_item(iec104_header_tree, hf_sco, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1897
53
  sco_tree = proto_item_add_subtree(ti, ett_sco);
1898
1899
53
  proto_tree_add_item(sco_tree, hf_sco_on, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1900
53
  proto_tree_add_item(sco_tree, hf_sco_qu, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1901
53
  proto_tree_add_item(sco_tree, hf_sco_se, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1902
1903
53
  (*offset)++;
1904
53
}
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
347
{
1911
347
  proto_item* ti;
1912
347
  proto_tree* dco_tree;
1913
1914
347
  ti = proto_tree_add_item(iec104_header_tree, hf_dco, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1915
347
  dco_tree = proto_item_add_subtree(ti, ett_dco);
1916
1917
347
  proto_tree_add_item(dco_tree, hf_dco_on, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1918
347
  proto_tree_add_item(dco_tree, hf_dco_qu, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1919
347
  proto_tree_add_item(dco_tree, hf_dco_se, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1920
1921
347
  (*offset)++;
1922
347
}
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
333
{
1929
333
  proto_item* ti;
1930
333
  proto_tree* rco_tree;
1931
1932
333
  ti = proto_tree_add_item(iec104_header_tree, hf_rco, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1933
333
  rco_tree = proto_item_add_subtree(ti, ett_rco);
1934
1935
333
  proto_tree_add_item(rco_tree, hf_rco_up, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1936
333
  proto_tree_add_item(rco_tree, hf_rco_qu, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1937
333
  proto_tree_add_item(rco_tree, hf_rco_se, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1938
1939
333
  (*offset)++;
1940
333
}
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
11
{
1947
11
  proto_item* ti;
1948
11
  proto_tree* coi_tree;
1949
1950
11
  ti = proto_tree_add_item(iec104_header_tree, hf_coi, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1951
11
  coi_tree = proto_item_add_subtree(ti, ett_coi);
1952
1953
11
  proto_tree_add_item(coi_tree, hf_coi_r, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1954
11
  proto_tree_add_item(coi_tree, hf_coi_i, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1955
1956
11
  (*offset)++;
1957
11
}
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
113
{
1964
113
  proto_tree_add_item(iec104_header_tree, hf_qoi, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1965
1966
113
  (*offset)++;
1967
113
}
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
144
{
1974
144
  proto_item* ti;
1975
144
  proto_tree* qcc_tree;
1976
1977
144
  ti = proto_tree_add_item(iec104_header_tree, hf_qcc, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1978
144
  qcc_tree = proto_item_add_subtree(ti, ett_qcc);
1979
1980
144
  proto_tree_add_item(qcc_tree, hf_qcc_rqt, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1981
144
  proto_tree_add_item(qcc_tree, hf_qcc_frz, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1982
1983
144
  (*offset)++;
1984
144
}
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
120
{
1991
120
  proto_item* ti;
1992
120
  proto_tree* qpm_tree;
1993
1994
120
  ti = proto_tree_add_item(iec104_header_tree, hf_qpm, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1995
120
  qpm_tree = proto_item_add_subtree(ti, ett_qpm);
1996
1997
120
  proto_tree_add_item(qpm_tree, hf_qpm_kpa, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1998
120
  proto_tree_add_item(qpm_tree, hf_qpm_lpc, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
1999
120
  proto_tree_add_item(qpm_tree, hf_qpm_pop, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2000
2001
120
  (*offset)++;
2002
120
}
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
13
{
2009
13
  proto_tree_add_item(iec104_header_tree, hf_qpa, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2010
2011
13
  (*offset)++;
2012
13
}
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
118
{
2019
118
  proto_tree_add_item(iec104_header_tree, hf_qrp, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2020
2021
118
  (*offset)++;
2022
118
}
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
1
{
2029
1
  proto_item* ti;
2030
1
  proto_tree* frq_tree;
2031
2032
1
  ti = proto_tree_add_item(iec104_header_tree, hf_frq, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2033
1
  frq_tree = proto_item_add_subtree(ti, ett_frq);
2034
2035
1
  proto_tree_add_item(frq_tree, hf_frq_confirm, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2036
1
  proto_tree_add_item(frq_tree, hf_frq_qualifier, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2037
2038
1
  (*offset)++;
2039
1
}
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
36
{
2046
36
  proto_item* ti;
2047
36
  proto_tree* srq_tree;
2048
2049
36
  ti = proto_tree_add_item(iec104_header_tree, hf_srq, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2050
36
  srq_tree = proto_item_add_subtree(ti, ett_srq);
2051
2052
36
  proto_tree_add_item(srq_tree, hf_srq_ready, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2053
36
  proto_tree_add_item(srq_tree, hf_srq_qualifier, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2054
2055
36
  (*offset)++;
2056
36
}
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
19
{
2063
19
  proto_item* ti;
2064
19
  proto_tree* scq_tree;
2065
2066
19
  ti = proto_tree_add_item(iec104_header_tree, hf_scq, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2067
19
  scq_tree = proto_item_add_subtree(ti, ett_scq);
2068
2069
19
  proto_tree_add_item(scq_tree, hf_scq_select, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2070
19
  proto_tree_add_item(scq_tree, hf_scq_qualifier, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2071
2072
19
  (*offset)++;
2073
19
}
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
33
{
2080
33
  proto_tree_add_item(iec104_header_tree, hf_lsq, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2081
33
  (*offset)++;
2082
33
}
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
58
{
2089
58
  proto_item* ti;
2090
58
  proto_tree* afq_tree;
2091
2092
58
  ti = proto_tree_add_item(iec104_header_tree, hf_afq, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2093
58
  afq_tree = proto_item_add_subtree(ti, ett_afq);
2094
2095
58
  proto_tree_add_item(afq_tree, hf_afq_ack, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2096
58
  proto_tree_add_item(afq_tree, hf_afq_qualifier, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2097
2098
58
  (*offset)++;
2099
58
}
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
191
{
2106
191
  proto_tree_add_item(iec104_header_tree, hf_nof, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
2107
191
  (*offset) += 2;
2108
191
}
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
147
{
2115
147
  proto_tree_add_item(iec104_header_tree, hf_nos, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2116
147
  (*offset) ++;
2117
147
}
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
45
{
2124
45
  proto_tree_add_item(iec104_header_tree, hf_lof, tvb, *offset, 3, ENC_LITTLE_ENDIAN);
2125
45
  (*offset) += 3;
2126
45
}
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
32
{
2146
32
  proto_tree_add_item(iec104_header_tree, hf_chs, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2147
32
  (*offset)++;
2148
32
}
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
7
{
2155
7
  proto_item* ti;
2156
7
  proto_tree* sof_tree;
2157
2158
7
  ti = proto_tree_add_item(iec104_header_tree, hf_sof, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2159
7
  sof_tree = proto_item_add_subtree(ti, ett_sof);
2160
2161
7
  proto_tree_add_item(sof_tree, hf_sof_status, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2162
7
  proto_tree_add_item(sof_tree, hf_sof_lfd, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2163
7
  proto_tree_add_item(sof_tree, hf_sof_for, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2164
7
  proto_tree_add_item(sof_tree, hf_sof_fa, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2165
2166
7
  (*offset)++;
2167
7
}
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
458
{
2174
458
  proto_item* ti;
2175
458
  proto_tree* qos_tree;
2176
2177
458
  ti = proto_tree_add_item(iec104_header_tree, hf_qos, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2178
458
  qos_tree = proto_item_add_subtree(ti, ett_qos);
2179
2180
458
  proto_tree_add_item(qos_tree, hf_qos_ql, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2181
458
  proto_tree_add_item(qos_tree, hf_qos_se, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2182
2183
458
  (*offset)++;
2184
458
}
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
0
{
2191
0
  proto_item* ti;
2192
0
  proto_tree* scd_tree;
2193
2194
0
  ti = proto_tree_add_item(iec104_header_tree, hf_scd, tvb, *offset, 4, ENC_LITTLE_ENDIAN);
2195
0
  scd_tree = proto_item_add_subtree(ti, ett_scd);
2196
2197
0
  proto_tree_add_bits_item(scd_tree, hf_scd_st, tvb, *offset * 8, 16, ENC_LITTLE_ENDIAN);
2198
0
  (*offset) += 2;
2199
2200
0
  proto_tree_add_bits_item(scd_tree, hf_scd_cd, tvb, *offset * 8, 16, ENC_LITTLE_ENDIAN);
2201
0
  (*offset) += 2;
2202
0
}
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
36
{
2209
36
  proto_tree_add_item(iec104_header_tree, hf_asdu_tsc, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
2210
2211
36
  (*offset) += 2;
2212
36
}
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
65
{
2228
65
  proto_tree_add_item(iec104_header_tree, hf_usr, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
2229
2230
65
  (*offset) += 2;
2231
65
}
2232
2233
/* ====================================================================
2234
   MAL: MAC algorithm
2235
   ==================================================================== */
2236
static void get_MAL(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
2237
0
{
2238
0
  proto_tree_add_item(iec104_header_tree, hf_mal, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2239
2240
0
  (*offset)++;
2241
0
}
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
0
{
2248
0
  proto_tree_add_item(iec104_header_tree, hf_rsc, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2249
2250
0
  (*offset)++;
2251
0
}
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
57
{
2258
57
  proto_tree_add_item(iec104_header_tree, hf_csq, tvb, *offset, 4, ENC_LITTLE_ENDIAN);
2259
2260
57
  (*offset) += 4;
2261
57
}
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
9
{
2268
9
  proto_tree_add_item(iec104_header_tree, hf_ksq, tvb, *offset, 4, ENC_LITTLE_ENDIAN);
2269
2270
9
  (*offset) += 4;
2271
9
}
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
8
{
2278
8
  proto_tree_add_item(iec104_header_tree, hf_kwa, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2279
2280
8
  (*offset)++;
2281
8
}
2282
2283
/* ====================================================================
2284
   KST: Key status
2285
   ==================================================================== */
2286
static void get_KST(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
2287
8
{
2288
8
  proto_tree_add_item(iec104_header_tree, hf_kst, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2289
2290
8
  (*offset)++;
2291
8
}
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
2
{
2298
2
  uint16_t value = tvb_get_letohs(tvb, *offset);
2299
2300
2
  proto_tree_add_item(iec104_header_tree, hf_hln, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
2301
2302
2
  (*offset) += 2;
2303
2
  return value;
2304
2
}
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
8
{
2311
8
  uint8_t hal = tvb_get_uint8(tvb, *offset);
2312
8
  proto_tree_add_item(iec104_header_tree, hf_hal, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2313
2314
8
  (*offset)++;
2315
8
  switch (hal)
2316
8
  {
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
8
  }
2324
8
  return 0;
2325
8
}
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
8
{
2332
8
  uint16_t value = tvb_get_letohs(tvb, *offset);
2333
2334
8
  proto_tree_add_item(iec104_header_tree, hf_cln, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
2335
2336
8
  (*offset) += 2;
2337
8
  return value;
2338
8
}
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
1
{
2345
1
  uint16_t value = tvb_get_letohs(tvb, *offset);
2346
2347
1
  proto_tree_add_item(iec104_header_tree, hf_wkl, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
2348
2349
1
  (*offset) += 2;
2350
1
  return value;
2351
1
}
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
8
{
2358
8
  proto_tree_add_item(iec104_header_tree, hf_prcd_raw_data, tvb, *offset, length, ENC_NA);
2359
8
  (*offset) += length;
2360
8
}
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
27
{
2367
27
  if (length)
2368
26
  {
2369
26
    proto_tree_add_item(iec104_header_tree, hf_hmac_raw_data, tvb, *offset, length, ENC_NA);
2370
26
    (*offset) += length;
2371
26
  }
2372
27
}
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
1
{
2379
1
  proto_tree_add_item(iec104_header_tree, hf_wkd_raw_data, tvb, *offset, length, ENC_NA);
2380
1
  (*offset) += length;
2381
1
}
2382
2383
/* ====================================================================
2384
   AID: Association ID
2385
   ==================================================================== */
2386
static void get_AID(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
2387
44
{
2388
44
  proto_tree_add_item(iec104_header_tree, hf_aid, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
2389
2390
44
  (*offset) += 2;
2391
44
}
2392
2393
/* ====================================================================
2394
   ERR: Error code
2395
   ==================================================================== */
2396
static void get_ERR(tvbuff_t *tvb, uint8_t *offset, proto_tree *iec104_header_tree)
2397
29
{
2398
29
  proto_tree_add_item(iec104_header_tree, hf_err, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2399
2400
29
  (*offset)++;
2401
29
}
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
29
{
2408
29
  uint16_t ms;
2409
29
  uint8_t value;
2410
29
  uint8_t su;
2411
29
  struct tm tm;
2412
29
  nstime_t  datetime;
2413
29
  proto_item* ti;
2414
29
  proto_tree* etm_tree;
2415
2416
29
  ms = tvb_get_letohs(tvb, *offset);
2417
29
  tm.tm_sec = ms / 1000;
2418
29
  datetime.nsecs = (ms % 1000) * 1000000;
2419
29
  (*offset) += 2;
2420
2421
29
  value = tvb_get_uint8(tvb, *offset);
2422
29
  tm.tm_min = value & 0x3F;
2423
29
  (*offset)++;
2424
2425
29
  value = tvb_get_uint8(tvb, *offset);
2426
29
  tm.tm_hour = value & 0x1F;
2427
29
  su = value & 0x80;
2428
29
  (*offset)++;
2429
2430
29
  value = tvb_get_uint8(tvb, *offset);
2431
29
  tm.tm_mday = value & 0x1F;
2432
29
  (*offset)++;
2433
2434
29
  value = tvb_get_uint8(tvb, *offset);
2435
29
  tm.tm_mon = (value & 0x0F) - 1;
2436
29
  (*offset)++;
2437
2438
29
  value = tvb_get_uint8(tvb, *offset);
2439
29
  tm.tm_year = value & 0x7F;
2440
29
  if (tm.tm_year < 70)
2441
13
    tm.tm_year += 100;
2442
2443
29
  (*offset)++;
2444
2445
29
  if (su)
2446
7
    tm.tm_isdst = 1;
2447
22
  else
2448
22
    tm.tm_isdst = -1; /* there's no info on whether DST was in force; assume it's
2449
           * the same as currently */
2450
2451
29
  datetime.secs = mktime(&tm);
2452
2453
29
  (*offset) -= 7;
2454
2455
29
  ti = proto_tree_add_time(iec104_header_tree, hf_etm, tvb, *offset, 7, &datetime);
2456
29
  etm_tree = proto_item_add_subtree(ti, ett_etm);
2457
2458
29
  proto_tree_add_item(etm_tree, hf_etm_ms, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
2459
29
  (*offset) += 2;
2460
2461
29
  proto_tree_add_item(etm_tree, hf_etm_min, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2462
29
  proto_tree_add_item(etm_tree, hf_etm_iv, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2463
29
  (*offset)++;
2464
2465
29
  proto_tree_add_item(etm_tree, hf_etm_hour, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2466
29
  proto_tree_add_item(etm_tree, hf_etm_su, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2467
29
  (*offset)++;
2468
2469
29
  proto_tree_add_item(etm_tree, hf_etm_day, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2470
29
  proto_tree_add_item(etm_tree, hf_etm_dow, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2471
29
  (*offset)++;
2472
2473
29
  proto_tree_add_item(etm_tree, hf_etm_month, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2474
29
  (*offset)++;
2475
2476
29
  proto_tree_add_item(etm_tree, hf_etm_year, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2477
29
  (*offset)++;
2478
29
}
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
29
{
2485
29
  uint16_t value = tvb_get_letohs(tvb, *offset);
2486
29
  proto_tree_add_item(iec104_header_tree, hf_eln, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
2487
2488
29
  (*offset) += 2;
2489
29
  return value;
2490
29
}
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
29
{
2497
29
  if (length)
2498
22
  {
2499
22
    proto_tree_add_item(iec104_header_tree, hf_error_text, tvb, *offset, length, ENC_UTF_8);
2500
22
    (*offset) += length;
2501
22
  }
2502
29
}
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
1.11k
{
2512
1.11k
  uint8_t Val;
2513
1.11k
  uint32_t Off;
2514
2515
46.2k
  for (Off = 0; Off <= tvb_reported_length(tvb) - 2; Off++) {
2516
46.1k
    Val = tvb_get_uint8(tvb, offset + Off);
2517
46.1k
    if (Val == APCI_START) {
2518
1.02k
      return (unsigned)(Off + tvb_get_uint8(tvb, offset + Off + 1) + 2);
2519
1.02k
    }
2520
46.1k
  }
2521
2522
90
  return (unsigned)(tvb_reported_length(tvb));
2523
1.11k
}
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
67
{
2529
67
  unsigned Len = tvb_reported_length(tvb);
2530
67
  uint8_t offset = 0;
2531
67
  uint8_t i, encapsulated_type, encapsulated_length;
2532
67
  uint16_t j;
2533
67
  tvbuff_t *encapsulated_tvb = NULL;
2534
2535
67
  switch (type_id) {
2536
0
    case S_CH_NA_1: /* 81    authentication challenge */
2537
0
      get_CSQ(tvb, &offset, it_segment_tree);
2538
0
      get_USR(tvb, &offset, it_segment_tree);
2539
0
      get_MAL(tvb, &offset, it_segment_tree);
2540
0
      get_RSC(tvb, &offset, it_segment_tree);
2541
0
      j = get_CLN(tvb, &offset, it_segment_tree);
2542
0
      get_PRCD(tvb, &offset, it_segment_tree, j);
2543
0
      break;
2544
3
    case S_RP_NA_1: /* 82    authentication reply */
2545
3
      get_CSQ(tvb, &offset, it_segment_tree);
2546
3
      get_USR(tvb, &offset, it_segment_tree);
2547
3
      j = get_HLN(tvb, &offset, it_segment_tree);
2548
3
      get_HMAC(tvb, &offset, it_segment_tree, j);
2549
3
      break;
2550
26
    case S_AR_NA_1: /* 83    Aggressive mode authentication request */
2551
26
      encapsulated_type = tvb_get_uint8(tvb, offset);
2552
26
      encapsulated_length = 1 + 1 + parms->cot_len + parms->asdu_addr_len + parms->ioa_len + get_TypeIdLength(encapsulated_type);
2553
26
      encapsulated_tvb = tvb_new_subset_length(tvb, offset, encapsulated_length);
2554
26
      dissect_iec60870_asdu(encapsulated_tvb, pinfo, it_segment_tree, parms);
2555
26
      offset = tvb_reported_length(encapsulated_tvb);
2556
26
      get_CSQ(tvb, &offset, it_segment_tree);
2557
26
      get_USR(tvb, &offset, it_segment_tree);
2558
26
      get_HMAC(tvb, &offset, it_segment_tree, tvb_reported_length_remaining(tvb, offset));
2559
26
      break;
2560
8
    case S_KS_NA_1: /* 85    session key status */
2561
8
      get_KSQ(tvb, &offset, it_segment_tree);
2562
8
      get_USR(tvb, &offset, it_segment_tree);
2563
8
      get_KWA(tvb, &offset, it_segment_tree);
2564
8
      get_KST(tvb, &offset, it_segment_tree);
2565
8
      i = get_HAL(tvb, &offset, it_segment_tree);
2566
8
      j = get_CLN(tvb, &offset, it_segment_tree);
2567
8
      get_PRCD(tvb, &offset, it_segment_tree, j);
2568
8
      get_HMAC(tvb, &offset, it_segment_tree, i);
2569
8
      break;
2570
1
    case S_KC_NA_1: /* 86    session key change */
2571
1
      get_KSQ(tvb, &offset, it_segment_tree);
2572
1
      get_USR(tvb, &offset, it_segment_tree);
2573
1
      j = get_WKL(tvb, &offset, it_segment_tree);
2574
1
      get_WKD(tvb, &offset, it_segment_tree, j);
2575
1
      break;
2576
29
    case S_ER_NA_1: /* 87    Authentication error */
2577
29
      get_CSQ(tvb, &offset, it_segment_tree);
2578
29
      get_USR(tvb, &offset, it_segment_tree);
2579
29
      get_AID(tvb, &offset, it_segment_tree);
2580
29
      get_ERR(tvb, &offset, it_segment_tree);
2581
29
      get_ETM(tvb, &offset, it_segment_tree);
2582
29
      j = get_ELN(tvb, &offset, it_segment_tree);
2583
29
      get_ErrorText(tvb, &offset, it_segment_tree, j);
2584
29
      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
67
  }
2595
  /* check correct apdu length */
2596
33
  if (Len != offset) {
2597
12
    expert_add_info(pinfo, it_segment_tree, &ei_iec104_apdu_invalid_len);
2598
12
    return offset;
2599
12
  }
2600
2601
21
  return Len;
2602
33
}
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
108
{
2608
108
  uint32_t msg_seqid = 0;
2609
2610
108
  bool final_segment = tvb_get_bits8(tvb, (*offset << 3) + 0, 1) == 1;
2611
2612
108
  proto_tree_add_item(tree, hf_asn_fin, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2613
108
  proto_tree_add_item(tree, hf_asn_fir, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2614
108
  proto_tree_add_item(tree, hf_asn, tvb, *offset, 1, ENC_LITTLE_ENDIAN);
2615
2616
108
  (*offset)++;
2617
2618
108
  tvbuff_t *next_tvb = tvb_new_subset_remaining(tvb, *offset);
2619
108
  uint32_t fragment_length = tvb_captured_length(next_tvb);
2620
108
  if (!final_segment) {
2621
41
    col_append_fstr(pinfo->cinfo, COL_INFO, " [ASDU fragment, %u byte%s]",
2622
41
        fragment_length, plurality(fragment_length, "", "s"));
2623
67
  } else {
2624
67
    col_append_str(pinfo->cinfo, COL_INFO, " EOA");
2625
67
  }
2626
2627
108
  fragment_head *fd_head = fragment_add_seq_next(&iec60870_reassemble_table, next_tvb, 0, pinfo,msg_seqid, NULL,
2628
108
                   fragment_length, !final_segment);
2629
2630
108
  if (fd_head && fd_head->next) {
2631
    /* don't use -1 if fragment length is zero (throws Exception) */
2632
22
    proto_tree_add_bytes_format(tree, hf_iec60870_segment_data, tvb, *offset, (fragment_length) ? -1 : 0,
2633
22
              NULL, "ASDU segment data (%u byte%s)", fragment_length,
2634
22
              plurality(fragment_length, "", "s"));
2635
2636
22
    if (final_segment) {
2637
22
      next_tvb = process_reassembled_data(next_tvb, *offset, pinfo,
2638
22
                  "Reassembled ASDU", fd_head,
2639
22
                  &iec60870_frag_items, NULL, tree);
2640
22
    } 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
22
    pinfo->fragmented = !final_segment;
2646
22
  }
2647
2648
108
  if (final_segment) {
2649
67
    dissect_iec60870_asdu_segment(next_tvb, pinfo, tree, typeId, parms);
2650
67
  }
2651
2652
108
  *offset += tvb_captured_length_remaining(tvb, *offset);
2653
108
}
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
951
{
2660
951
  unsigned Len = tvb_reported_length(tvb);
2661
951
  uint8_t Bytex;
2662
951
  const char *cause_str;
2663
951
  size_t Ind;
2664
951
  struct asduheader asduh = { .OA = 0, .Addr = 0, .IOA = 0};
2665
951
  struct asdu_parms* parms = (struct asdu_parms*)data;
2666
951
  proto_item *it104;
2667
951
  proto_tree *it104tree;
2668
951
  wmem_strbuf_t * res;
2669
2670
951
  uint8_t offset = 0;  /* byte offset, signal dissection */
2671
951
  uint8_t i;
2672
951
  uint8_t seg_len;
2673
951
  uint32_t asdu_info_obj_addr = 0;
2674
951
  proto_item * itSignal = NULL;
2675
951
  proto_tree * trSignal;
2676
2677
951
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "IEC 60870-5 ASDU");
2678
2679
951
  it104 = proto_tree_add_item(tree, proto_iec60870_asdu, tvb, offset, -1, ENC_NA);
2680
951
  it104tree = proto_item_add_subtree(it104, ett_asdu);
2681
2682
951
  res = wmem_strbuf_create(pinfo->pool);
2683
2684
  /* Type identification */
2685
951
  asduh.TypeId = tvb_get_uint8(tvb, offset);
2686
951
  proto_tree_add_item(it104tree, hf_typeid, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2687
951
  asduh.DataLength = get_TypeIdLength(asduh.TypeId);
2688
951
  offset += 1;
2689
2690
  /* Variable structure qualifier */
2691
951
  Bytex = tvb_get_uint8(tvb, 1);
2692
951
  asduh.SQ = Bytex & F_SQ;
2693
951
  asduh.NumIx = Bytex & 0x7F;
2694
951
  proto_tree_add_item(it104tree, hf_sq, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2695
951
  proto_tree_add_item(it104tree, hf_numix, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2696
951
  offset += 1;
2697
2698
  /* Cause of transmission */
2699
951
  asduh.TNCause = tvb_get_uint8(tvb, offset);
2700
951
  proto_tree_add_item(it104tree, hf_causetx, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2701
951
  proto_tree_add_item(it104tree, hf_nega, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2702
951
  proto_tree_add_item(it104tree, hf_test, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2703
951
  offset += 1;
2704
2705
  /* Originator address */
2706
  /* This is only present if the Cause of Tx field is 2 octets */
2707
951
  if (parms->cot_len == 2) {
2708
939
    asduh.OA = tvb_get_uint8(tvb, offset);
2709
939
    proto_tree_add_item(it104tree, hf_oa, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2710
939
    offset += 1;
2711
939
  }
2712
2713
  /* Common address of ASDU */
2714
951
  proto_tree_add_item_ret_uint(it104tree, hf_addr, tvb, offset, parms->asdu_addr_len, ENC_LITTLE_ENDIAN, &asduh.Addr);
2715
951
  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
951
  if (asduh.TypeId < S_CH_NA_1 || asduh.TypeId > S_UC_NA_1) {
2721
801
    if (parms->ioa_len == 3) {
2722
801
      asduh.IOA = tvb_get_letoh24(tvb, offset);
2723
801
    }
2724
0
    else if (parms->ioa_len == 2) {
2725
0
      asduh.IOA = tvb_get_letohs(tvb, offset);
2726
0
    }
2727
801
  }
2728
2729
951
  cause_str = val_to_str(pinfo->pool, asduh.TNCause & F_CAUSE, causetx_types, " <CauseTx=%u>");
2730
2731
951
  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
951
  if (asduh.TNCause & F_NEGA)
2734
422
    wmem_strbuf_append(res, "_NEGA");
2735
951
  if (asduh.TNCause & F_TEST)
2736
230
    wmem_strbuf_append(res, "_TEST");
2737
2738
951
  if ((asduh.TNCause & (F_TEST | F_NEGA)) == 0) {
2739
720
    for (Ind=strlen(cause_str); Ind< 7; Ind++)
2740
305
      wmem_strbuf_append(res, " ");
2741
415
  }
2742
2743
951
  if (asduh.NumIx > 1) {
2744
803
    wmem_strbuf_append_printf(res, " IOA[%d]=%d", asduh.NumIx, asduh.IOA);
2745
803
    if (asduh.SQ == F_SQ)
2746
226
      wmem_strbuf_append_printf(res, "-%d", asduh.IOA + asduh.NumIx - 1);
2747
577
    else
2748
577
      wmem_strbuf_append(res, ",...");
2749
803
  } else {
2750
148
    wmem_strbuf_append_printf(res, " IOA=%d", asduh.IOA);
2751
148
  }
2752
2753
951
  col_append_str(pinfo->cinfo, COL_INFO, wmem_strbuf_get_str(res));
2754
951
  col_set_fence(pinfo->cinfo, COL_INFO);
2755
2756
  /* 'ASDU Details': ROOT ITEM */
2757
951
  proto_item_append_text(it104, ": %s '%s'", wmem_strbuf_get_str(res),
2758
951
    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
951
  switch (asduh.TypeId) {
2764
16
    case M_SP_NA_1:
2765
48
    case M_SP_TA_1:
2766
55
    case M_DP_NA_1:
2767
81
    case M_DP_TA_1:
2768
97
    case M_ST_NA_1:
2769
118
    case M_ST_TA_1:
2770
123
    case M_BO_NA_1:
2771
151
    case M_BO_TA_1:
2772
154
    case M_SP_TB_1:
2773
155
    case M_DP_TB_1:
2774
175
    case M_ST_TB_1:
2775
186
    case M_BO_TB_1:
2776
195
    case M_ME_NA_1:
2777
207
    case M_ME_TA_1:
2778
217
    case M_ME_NB_1:
2779
243
    case M_ME_TB_1:
2780
243
    case M_ME_NC_1:
2781
248
    case M_ME_TC_1:
2782
253
    case M_IT_NA_1:
2783
273
    case M_IT_TA_1:
2784
282
    case M_EP_TA_1:
2785
295
    case M_EP_TB_1:
2786
300
    case M_EP_TC_1:
2787
300
    case M_PS_NA_1:
2788
305
    case M_ME_ND_1:
2789
314
    case M_ME_TD_1:
2790
331
    case M_ME_TE_1:
2791
347
    case M_ME_TF_1:
2792
360
    case M_IT_TB_1:
2793
370
    case M_EP_TD_1:
2794
370
    case M_EP_TE_1:
2795
372
    case M_EP_TF_1:
2796
376
    case S_IT_TC_1:
2797
382
    case C_SC_NA_1:
2798
404
    case C_DC_NA_1:
2799
414
    case C_RC_NA_1:
2800
430
    case C_SE_NA_1:
2801
450
    case C_SE_NB_1:
2802
456
    case C_SE_NC_1:
2803
467
    case C_BO_NA_1:
2804
475
    case C_SC_TA_1:
2805
478
    case C_DC_TA_1:
2806
484
    case C_RC_TA_1:
2807
489
    case C_SE_TA_1:
2808
490
    case C_SE_TB_1:
2809
495
    case C_SE_TC_1:
2810
515
    case C_BO_TA_1:
2811
519
    case M_EI_NA_1:
2812
535
    case C_IC_NA_1:
2813
547
    case C_CI_NA_1:
2814
548
    case C_CS_NA_1:
2815
583
    case C_TS_NA_1:
2816
594
    case C_RP_NA_1:
2817
617
    case C_CD_NA_1:
2818
629
    case C_TS_TA_1:
2819
631
    case P_ME_NA_1:
2820
632
    case P_ME_NB_1:
2821
643
    case P_ME_NC_1:
2822
645
    case P_AC_NA_1:
2823
646
    case F_FR_NA_1:
2824
649
    case F_SR_NA_1:
2825
651
    case F_SC_NA_1:
2826
656
    case F_LS_NA_1:
2827
659
    case F_AF_NA_1:
2828
660
    case F_SG_NA_1:
2829
661
    case F_DR_TA_1:
2830
676
    case F_SC_NB_1:
2831
2832
      /* -- object values */
2833
5.69k
      for(i = 0; i < asduh.NumIx; i++)
2834
5.57k
      {
2835
        /* create subtree for the signal values ... */
2836
5.57k
        if (i == 0 || !asduh.SQ)
2837
3.15k
          trSignal = proto_tree_add_subtree(it104tree, tvb, offset, asduh.DataLength + parms->ioa_len,
2838
3.15k
                            ett_asdu_objects, &itSignal, "IOA:s");
2839
2.41k
        else
2840
2.41k
          trSignal = proto_tree_add_subtree(it104tree, tvb, offset, asduh.DataLength,
2841
2.41k
                            ett_asdu_objects, &itSignal, "IOA:s");
2842
2843
        /* --------  First Information object address */
2844
5.57k
        if (i == 0)
2845
634
        {
2846
          /* --------  Information object address */
2847
          /* check length */
2848
634
          if(Len < (unsigned)(offset + 3)) {
2849
0
            expert_add_info(pinfo, itSignal, &ei_iec104_short_asdu);
2850
0
            return offset;
2851
0
          }
2852
634
          get_InfoObjectAddress(&asdu_info_obj_addr, tvb, &offset, trSignal, parms->ioa_len);
2853
4.93k
        } else {
2854
          /* -------- following Information object address depending on SQ */
2855
4.93k
          if (asduh.SQ) /* <=> SQ=1, info obj addr = startaddr++ */
2856
2.41k
          {
2857
2.41k
            proto_item *ti;
2858
2.41k
            asdu_info_obj_addr++;
2859
2.41k
            ti = proto_tree_add_uint(trSignal, hf_ioa, tvb, 0, 0, asdu_info_obj_addr);
2860
2.41k
            proto_item_set_generated(ti);
2861
2.51k
          } else { /* SQ=0, info obj addr given */
2862
            /* --------  Information object address */
2863
            /* check length */
2864
2.51k
            if(Len < (unsigned)(offset + 3)) {
2865
105
              expert_add_info(pinfo, itSignal, &ei_iec104_short_asdu);
2866
105
              return offset;
2867
105
            }
2868
2.41k
            get_InfoObjectAddress(&asdu_info_obj_addr, tvb, &offset, trSignal, parms->ioa_len);
2869
2.41k
          }
2870
4.93k
        }
2871
2872
5.46k
        proto_item_set_text(itSignal, "IOA: %d", asdu_info_obj_addr);
2873
2874
        /* check length */
2875
5.46k
        if(Len < (unsigned)(offset + asduh.DataLength)) {
2876
342
          expert_add_info(pinfo, itSignal, &ei_iec104_short_asdu);
2877
342
          return offset;
2878
342
        }
2879
2880
5.12k
        switch (asduh.TypeId) {
2881
226
        case M_SP_NA_1: /* 1  Single-point information */
2882
226
          get_SIQ(tvb, &offset, trSignal);
2883
226
          break;
2884
83
        case M_SP_TA_1: /* 2  Single-point information with time tag */
2885
83
          get_SIQ(tvb, &offset, trSignal);
2886
83
          get_CP24Time(tvb, &offset, trSignal);
2887
83
          break;
2888
219
        case M_DP_NA_1: /* 3  Double-point information */
2889
219
          get_DIQ(tvb, &offset, trSignal);
2890
219
          break;
2891
129
        case M_DP_TA_1: /* 4  Double-point information with time tag */
2892
129
          get_DIQ(tvb, &offset, trSignal);
2893
129
          get_CP24Time(tvb, &offset, trSignal);
2894
129
          break;
2895
137
        case M_ST_NA_1: /* 5  Step position information */
2896
137
          get_VTI(tvb, &offset, trSignal);
2897
137
          get_QDS(tvb, &offset, trSignal);
2898
137
          break;
2899
86
        case M_ST_TA_1: /* 6  Step position information with time tag */
2900
86
          get_VTI(tvb, &offset, trSignal);
2901
86
          get_QDS(tvb, &offset, trSignal);
2902
86
          get_CP24Time(tvb, &offset, trSignal);
2903
86
          break;
2904
45
        case M_BO_NA_1: /* 7  Bitstring of 32 bits */
2905
45
          get_BSI(tvb, &offset, trSignal);
2906
45
          get_QDS(tvb, &offset, trSignal);
2907
45
          break;
2908
29
        case M_BO_TA_1: /* 8  Bitstring of 32 bits with time tag */
2909
29
          get_BSI(tvb, &offset, trSignal);
2910
29
          get_QDS(tvb, &offset, trSignal);
2911
29
          get_CP24Time(tvb, &offset, trSignal);
2912
29
          break;
2913
88
        case M_ME_NA_1: /* 9  Measured value, normalized value */
2914
88
          get_NVA(tvb, &offset, trSignal);
2915
88
          get_QDS(tvb, &offset, trSignal);
2916
88
          break;
2917
93
        case M_ME_TA_1: /* 10 Measured value, normalized value with time tag */
2918
93
          get_NVA(tvb, &offset, trSignal);
2919
93
          get_QDS(tvb, &offset, trSignal);
2920
93
          get_CP24Time(tvb, &offset, trSignal);
2921
93
          break;
2922
47
        case M_ME_NB_1: /* 11     Measured value, scaled value */
2923
47
          get_SVA(tvb, &offset, trSignal);
2924
47
          get_QDS(tvb, &offset, trSignal);
2925
47
          break;
2926
80
        case M_ME_TB_1: /* 12     Measured value, scaled value with time tag */
2927
80
          get_SVA(tvb, &offset, trSignal);
2928
80
          get_QDS(tvb, &offset, trSignal);
2929
80
          get_CP24Time(tvb, &offset, trSignal);
2930
80
          break;
2931
0
        case M_ME_NC_1: /* 13 Measured value, short floating point value */
2932
0
          get_FLT(tvb, &offset, trSignal);
2933
0
          get_QDS(tvb, &offset, trSignal);
2934
0
          break;
2935
26
        case M_ME_TC_1: /* 14 Measured value, short floating point value with time tag */
2936
26
          get_FLT(tvb, &offset, trSignal);
2937
26
          get_QDS(tvb, &offset, trSignal);
2938
26
          get_CP24Time(tvb, &offset, trSignal);
2939
26
          break;
2940
100
        case M_IT_NA_1: /* 15 Integrated totals */
2941
100
          get_BCR(tvb, &offset, trSignal);
2942
100
          break;
2943
210
        case M_IT_TA_1: /* 16 Integrated totals with time tag */
2944
210
          get_BCR(tvb, &offset, trSignal);
2945
210
          get_CP24Time(tvb, &offset, trSignal);
2946
210
          break;
2947
72
        case M_EP_TA_1: /* 17   Event of protection equipment with time tag */
2948
72
          get_SEP(tvb, &offset, trSignal);
2949
72
          get_CP16Time(tvb, &offset, trSignal);
2950
72
          get_CP24Time(tvb, &offset, trSignal);
2951
72
          break;
2952
78
        case M_EP_TB_1: /* 18   Packed start events of protection equipment with time tag */
2953
78
          get_SPE(tvb, &offset, trSignal);
2954
78
          get_QDP(tvb, &offset, trSignal);
2955
78
          get_CP16Time(tvb, &offset, trSignal);
2956
78
          get_CP24Time(tvb, &offset, trSignal);
2957
78
          break;
2958
67
        case M_EP_TC_1: /* 19   Packed output circuit information of protection equipment with time tag */
2959
67
          get_OCI(tvb, &offset, trSignal);
2960
67
          get_QDP(tvb, &offset, trSignal);
2961
67
          get_CP16Time(tvb, &offset, trSignal);
2962
67
          get_CP24Time(tvb, &offset, trSignal);
2963
67
          break;
2964
0
        case M_PS_NA_1: /* 20   Packed single-point information */
2965
0
          get_SCD(tvb, &offset, trSignal);
2966
0
          get_QDS(tvb, &offset, trSignal);
2967
0
          break;
2968
14
        case M_ME_ND_1: /* 21   Measured value, normalized value without quality descriptor */
2969
14
          get_NVA(tvb, &offset, trSignal);
2970
14
          break;
2971
24
        case M_SP_TB_1: /* 30 Single-point information with time tag CP56Time2a */
2972
24
          get_SIQ(tvb, &offset, trSignal);
2973
24
          get_CP56Time(tvb, &offset, trSignal);
2974
24
          break;
2975
8
        case M_DP_TB_1: /* 31 Double-point information with time tag CP56Time2a */
2976
8
          get_DIQ(tvb, &offset, trSignal);
2977
8
          get_CP56Time(tvb, &offset, trSignal);
2978
8
          break;
2979
67
        case M_ST_TB_1: /* 32 Step position information with time tag CP56Time2a */
2980
67
          get_VTI(tvb, &offset, trSignal);
2981
67
          get_QDS(tvb, &offset, trSignal);
2982
67
          get_CP56Time(tvb, &offset, trSignal);
2983
67
          break;
2984
29
        case M_BO_TB_1: /* 33 Bitstring of 32 bit with time tag CP56Time2a */
2985
29
          get_BSI(tvb, &offset, trSignal);
2986
29
          get_QDS(tvb, &offset, trSignal);
2987
29
          get_CP56Time(tvb, &offset, trSignal);
2988
29
          break;
2989
43
        case M_ME_TD_1: /* 34    Measured value, normalized value with time tag CP56Time2a */
2990
43
          get_NVA(tvb, &offset, trSignal);
2991
43
          get_QDS(tvb, &offset, trSignal);
2992
43
          get_CP56Time(tvb, &offset, trSignal);
2993
43
          break;
2994
46
        case M_ME_TE_1: /* 35    Measured value, scaled value with time tag CP56Time2a */
2995
46
          get_SVA(tvb, &offset, trSignal);
2996
46
          get_QDS(tvb, &offset, trSignal);
2997
46
          get_CP56Time(tvb, &offset, trSignal);
2998
46
          break;
2999
79
        case M_ME_TF_1: /* 36    Measured value, short floating point value with time tag CP56Time2a */
3000
79
          get_FLT(tvb, &offset, trSignal);
3001
79
          get_QDS(tvb, &offset, trSignal);
3002
79
          get_CP56Time(tvb, &offset, trSignal);
3003
79
          break;
3004
20
        case M_IT_TB_1: /* 37 Integrated totals with time tag CP56Time2a */
3005
20
          get_BCR(tvb, &offset, trSignal);
3006
20
          get_CP56Time(tvb, &offset, trSignal);
3007
20
          break;
3008
50
        case M_EP_TD_1: /* 38   Event of protection equipment with time tag CP56Time2a */
3009
50
          get_SEP(tvb, &offset, trSignal);
3010
50
          get_CP16Time(tvb, &offset, trSignal);
3011
50
          get_CP56Time(tvb, &offset, trSignal);
3012
50
          break;
3013
0
        case M_EP_TE_1: /* 39   Packed start events of protection equipment with time tag CP56Time2a */
3014
0
          get_SPE(tvb, &offset, trSignal);
3015
0
          get_QDP(tvb, &offset, trSignal);
3016
0
          get_CP16Time(tvb, &offset, trSignal);
3017
0
          get_CP56Time(tvb, &offset, trSignal);
3018
0
          break;
3019
8
        case M_EP_TF_1: /* 40   Packed output circuit information of protection equipment with time tag CP56Time2a */
3020
8
          get_OCI(tvb, &offset, trSignal);
3021
8
          get_QDP(tvb, &offset, trSignal);
3022
8
          get_CP16Time(tvb, &offset, trSignal);
3023
8
          get_CP56Time(tvb, &offset, trSignal);
3024
8
          break;
3025
15
        case S_IT_TC_1: /* 41   Integrated totals containing time tagged security statistics */
3026
15
          get_AID(tvb, &offset, trSignal);
3027
15
          get_BCR(tvb, &offset, trSignal);
3028
15
          get_CP56Time(tvb, &offset, trSignal);
3029
15
          break;
3030
48
        case C_SC_NA_1: /* 45 Single command */
3031
48
          get_SCO(tvb, &offset, trSignal);
3032
48
          break;
3033
257
        case C_DC_NA_1: /* 46 Double command */
3034
257
          get_DCO(tvb, &offset, trSignal);
3035
257
          break;
3036
298
        case C_RC_NA_1: /* 47 Regulating step command */
3037
298
          get_RCO(tvb, &offset, trSignal);
3038
298
          break;
3039
97
        case C_SE_NA_1: /* 48    Set point command, normalized value */
3040
97
          get_NVAspt(tvb, &offset, trSignal);
3041
97
          get_QOS(tvb, &offset, trSignal);
3042
97
          break;
3043
267
        case C_SE_NB_1: /* 49    Set point command, scaled value */
3044
267
          get_SVAspt(tvb, &offset, trSignal);
3045
267
          get_QOS(tvb, &offset, trSignal);
3046
267
          break;
3047
63
        case C_SE_NC_1: /* 50    Set point command, short floating point value */
3048
63
          get_FLTspt(tvb, &offset, trSignal);
3049
63
          get_QOS(tvb, &offset, trSignal);
3050
63
          break;
3051
78
        case C_BO_NA_1: /* 51    Bitstring of 32 bits */
3052
78
          get_BSIspt(tvb, &offset, trSignal);
3053
78
          break;
3054
5
        case C_SC_TA_1: /* 58    Single command with time tag CP56Time2a */
3055
5
          get_SCO(tvb, &offset, trSignal);
3056
5
          get_CP56Time(tvb, &offset, trSignal);
3057
5
          break;
3058
90
        case C_DC_TA_1: /* 59    Double command with time tag CP56Time2a */
3059
90
          get_DCO(tvb, &offset, trSignal);
3060
90
          get_CP56Time(tvb, &offset, trSignal);
3061
90
          break;
3062
35
        case C_RC_TA_1: /* 60    Regulating step command with time tag CP56Time2a */
3063
35
          get_RCO(tvb, &offset, trSignal);
3064
35
          get_CP56Time(tvb, &offset, trSignal);
3065
35
          break;
3066
23
        case C_SE_TA_1: /* 61    Set point command, normalized value with time tag CP56Time2a */
3067
23
          get_NVAspt(tvb, &offset, trSignal);
3068
23
          get_QOS(tvb, &offset, trSignal);
3069
23
          get_CP56Time(tvb, &offset, trSignal);
3070
23
          break;
3071
7
        case C_SE_TB_1: /* 62    Set point command, scaled value with time tag CP56Time2a */
3072
7
          get_SVAspt(tvb, &offset, trSignal);
3073
7
          get_QOS(tvb, &offset, trSignal);
3074
7
          get_CP56Time(tvb, &offset, trSignal);
3075
7
          break;
3076
9
        case C_SE_TC_1: /* 63    Set point command, short floating point value with time tag CP56Time2a */
3077
9
          get_FLTspt(tvb, &offset, trSignal);
3078
9
          get_QOS(tvb, &offset, trSignal);
3079
9
          get_CP56Time(tvb, &offset, trSignal);
3080
9
          break;
3081
53
        case C_BO_TA_1: /* 64    Bitstring of 32 bits with time tag CP56Time2a */
3082
53
          get_BSIspt(tvb, &offset, trSignal);
3083
53
          get_CP56Time(tvb, &offset, trSignal);
3084
53
          break;
3085
11
        case M_EI_NA_1: /* 70    End of initialization  */
3086
11
          get_COI(tvb, &offset, trSignal);
3087
11
          break;
3088
113
        case C_IC_NA_1: /* 100   Interrogation command  */
3089
113
          get_QOI(tvb, &offset, trSignal);
3090
113
          break;
3091
144
        case C_CI_NA_1: /* 101   Counter interrogation command  */
3092
144
          get_QCC(tvb, &offset, trSignal);
3093
144
          break;
3094
17
        case C_CS_NA_1: /* 103   Clock synchronization command  */
3095
17
          get_CP56Time(tvb, &offset, trSignal);
3096
17
          break;
3097
476
        case C_TS_NA_1: /* 104   Test command */
3098
476
          get_FBP(tvb, &offset, trSignal);
3099
476
          break;
3100
118
        case C_RP_NA_1: /* 105   reset process command  */
3101
118
          get_QRP(tvb, &offset, trSignal);
3102
118
          break;
3103
314
        case C_CD_NA_1: /* 106   Delay acquisition command */
3104
314
          get_CP16Time(tvb, &offset, trSignal);
3105
314
          break;
3106
36
        case C_TS_TA_1: /* 107   test command with time tag CP56Time2a */
3107
36
          get_TSC(tvb, &offset, trSignal);
3108
36
          get_CP56Time(tvb, &offset, trSignal);
3109
36
          break;
3110
5
        case P_ME_NA_1: /* 110   Parameter of measured value, normalized value */
3111
5
          get_NVA(tvb, &offset, trSignal);
3112
5
          get_QPM(tvb, &offset, trSignal);
3113
5
          break;
3114
4
        case P_ME_NB_1: /* 111   Parameter of measured value, scaled value */
3115
4
          get_SVA(tvb, &offset, trSignal);
3116
4
          get_QPM(tvb, &offset, trSignal);
3117
4
          break;
3118
114
        case P_ME_NC_1: /* 112   Parameter of measured value, short floating-point number */
3119
114
          get_FLT(tvb, &offset, trSignal);
3120
114
          get_QPM(tvb, &offset, trSignal);
3121
114
          break;
3122
13
        case P_AC_NA_1: /* 113   Parameter activation */
3123
13
          get_QPA(tvb, &offset, trSignal);
3124
13
          break;
3125
2
        case F_FR_NA_1: /* 120   File ready */
3126
2
          get_NOF(tvb, &offset, trSignal);
3127
2
          get_LOF(tvb, &offset, trSignal);
3128
2
          get_FRQ(tvb, &offset, trSignal);
3129
2
          break;
3130
36
        case F_SR_NA_1: /* 121   Section ready */
3131
36
          get_NOF(tvb, &offset, trSignal);
3132
36
          get_NOS(tvb, &offset, trSignal);
3133
36
          get_LOF(tvb, &offset, trSignal);
3134
36
          get_SRQ(tvb, &offset, trSignal);
3135
36
          break;
3136
19
        case F_SC_NA_1: /* 122   Call directory, select file, call file, call section */
3137
19
          get_NOF(tvb, &offset, trSignal);
3138
19
          get_NOS(tvb, &offset, trSignal);
3139
19
          get_SCQ(tvb, &offset, trSignal);
3140
19
          break;
3141
33
        case F_LS_NA_1: /* 123   Last section, last segment */
3142
33
          get_NOF(tvb, &offset, trSignal);
3143
33
          get_NOS(tvb, &offset, trSignal);
3144
33
          get_LSQ(tvb, &offset, trSignal);
3145
33
          get_CHS(tvb, &offset, trSignal);
3146
33
          break;
3147
58
        case F_AF_NA_1: /* 124   Ack file, ack section */
3148
58
          get_NOF(tvb, &offset, trSignal);
3149
58
          get_NOS(tvb, &offset, trSignal);
3150
58
          get_AFQ(tvb, &offset, trSignal);
3151
58
          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
7
        case F_DR_TA_1: /* 126   Directory */
3159
7
          get_NOF(tvb, &offset, trSignal);
3160
7
          get_LOF(tvb, &offset, trSignal);
3161
7
          get_SOF(tvb, &offset, trSignal);
3162
7
          get_CP56Time(tvb, &offset, trSignal);
3163
7
          break;
3164
35
        case F_SC_NB_1: /* 127   Query Log - Request archive file */
3165
35
          get_NOF(tvb, &offset, trSignal);
3166
35
          get_RangeStartCP56Time(tvb, &offset, trSignal);
3167
35
          get_RangeStopCP56Time(tvb, &offset, trSignal);
3168
35
          break;
3169
0
        default:
3170
0
          break;
3171
5.12k
        } /* end 'switch (asduh.TypeId)' */
3172
5.12k
      } /* end 'for(i = 0; i < dui.asdu_vsq_no_of_obj; i++)' */
3173
125
      break;
3174
125
    case S_CH_NA_1: /* 81    authentication challenge */
3175
21
    case S_RP_NA_1: /* 82    authentication reply */
3176
51
    case S_AR_NA_1: /* 83    Aggressive mode authentication request */
3177
63
    case S_KS_NA_1: /* 85    session key status */
3178
64
    case S_KC_NA_1: /* 86    session key change */
3179
108
    case S_ER_NA_1: /* 87    Authentication error */
3180
108
      dissect_iec60870_segment(tvb, pinfo, it104tree, &offset, asduh.TypeId, parms);
3181
108
      break;
3182
8
    case S_KR_NA_1: /* 84    Session key status request */
3183
8
      proto_tree_add_item(it104tree, hf_usr, tvb, offset, 2, ENC_LITTLE_ENDIAN);
3184
8
      offset += 2;
3185
8
      break;
3186
140
    default:
3187
140
      proto_tree_add_item(it104tree, hf_ioa, tvb, offset, 3, ENC_LITTLE_ENDIAN);
3188
140
      offset += 3;
3189
3190
140
      if (Len - offset > 0)
3191
128
        proto_tree_add_item(it104tree, hf_asdu_raw_data, tvb, offset, Len - offset, ENC_NA);
3192
140
      offset = Len;
3193
3194
140
      break;
3195
951
  } /* end 'switch (asdu_typeid)' */
3196
3197
  /* check correct apdu length */
3198
333
  if (Len != offset) {
3199
137
    expert_add_info_format(pinfo, it104tree, &ei_iec104_apdu_invalid_len, "Invalid Apdulen (%d != %d)", Len, offset);
3200
137
    return offset;
3201
137
  }
3202
3203
196
  return tvb_captured_length(tvb);
3204
333
}
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
1.02k
{
3211
1.02k
  unsigned TcpLen = tvb_reported_length(tvb);
3212
1.02k
  uint8_t Start, len, type, temp8;
3213
1.02k
  uint32_t apci_txid, apci_rxid, apci_u_type;
3214
1.02k
  unsigned Off;
3215
1.02k
  proto_item *it104, *ti;
3216
1.02k
  proto_tree *it104tree;
3217
1.02k
  wmem_strbuf_t * res;
3218
1.02k
  struct asdu_parms parms;
3219
3220
1.02k
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "IEC 60870-5-104");
3221
3222
1.02k
  it104 = proto_tree_add_item(tree, proto_iec60870_104, tvb, 0, -1, ENC_NA);
3223
1.02k
  it104tree = proto_item_add_subtree(it104, ett_apci);
3224
3225
1.02k
  res = wmem_strbuf_create(pinfo->pool);
3226
3227
1.02k
  Start = 0;
3228
41.7k
  for (Off = 0; Off <= TcpLen - 2; Off++) {
3229
41.7k
    Start = tvb_get_uint8(tvb, Off);
3230
3231
41.7k
    if (Start == APCI_START) {
3232
1.02k
      if (Off > 0)
3233
972
      {
3234
972
        proto_tree_add_item(it104tree, hf_apcidata, tvb, 0, Off, ENC_NA);
3235
972
        wmem_strbuf_append_printf(res, "<ERR prefix %u bytes> ", Off);
3236
972
      }
3237
3238
1.02k
      proto_item_set_len(it104, Off + APCI_LEN);
3239
3240
1.02k
      proto_tree_add_uint_format(it104tree, hf_start, tvb, Off, 1, Start, "START");
3241
1.02k
      ti = proto_tree_add_item_ret_uint8(it104tree, hf_apdulen, tvb, Off + 1, 1, ENC_LITTLE_ENDIAN, &len);
3242
3243
1.02k
      if (len < APDU_MIN_LEN) {
3244
49
        expert_add_info_format(pinfo, ti, &ei_iec104_apdu_min_len, "APDU less than %d bytes", APDU_MIN_LEN);
3245
49
        wmem_strbuf_append_printf(res, "<ERR ApduLen=%u bytes> ", len);
3246
49
        return tvb_captured_length(tvb);
3247
49
      }
3248
3249
976
      temp8 = tvb_get_uint8(tvb, Off + 2);
3250
976
      if ((temp8 & 0x01) == 0)
3251
935
        type = 0;
3252
41
      else
3253
41
        type = temp8 & 0x03;
3254
3255
976
      if (type == I_TYPE)
3256
935
        proto_tree_add_item(it104tree, hf_apcitype_i, tvb, Off + 2, 4, ENC_LITTLE_ENDIAN);
3257
41
      else
3258
41
        proto_tree_add_item(it104tree, hf_apcitype_s_u, tvb, Off + 2, 4, ENC_LITTLE_ENDIAN);
3259
3260
976
      if (len <= APDU_MAX_LEN) {
3261
950
        wmem_strbuf_append_printf(res, "%s %s ",
3262
950
          (pinfo->srcport == pinfo->match_uint ? "->" : "<-"),
3263
950
          val_to_str_const(type, apci_types, "<ERR>"));
3264
950
      }
3265
26
      else {
3266
26
        wmem_strbuf_append_printf(res, "<ERR ApduLen=%u bytes> ", len);
3267
26
      }
3268
3269
976
      switch(type) {
3270
925
      case I_TYPE:
3271
925
        proto_tree_add_item_ret_uint(it104tree, hf_apcitx, tvb, Off + 2, 4, ENC_LITTLE_ENDIAN, &apci_txid);
3272
925
        proto_tree_add_item_ret_uint(it104tree, hf_apcirx, tvb, Off + 2, 4, ENC_LITTLE_ENDIAN, &apci_rxid);
3273
925
        wmem_strbuf_append_printf(res, "(%d,%d) ", apci_txid, apci_rxid);
3274
925
        break;
3275
15
      case S_TYPE:
3276
15
        proto_tree_add_item_ret_uint(it104tree, hf_apcirx, tvb, Off + 2, 4, ENC_LITTLE_ENDIAN, &apci_rxid);
3277
15
        wmem_strbuf_append_printf(res, "(%d) ", apci_rxid);
3278
15
        break;
3279
25
      case U_TYPE:
3280
25
        proto_tree_add_item_ret_uint(it104tree, hf_apciutype, tvb, Off + 2, 4, ENC_LITTLE_ENDIAN, &apci_u_type);
3281
25
        wmem_strbuf_append_printf(res, "(%s) ", val_to_str_const(apci_u_type, u_types, "<ERR>"));
3282
25
        break;
3283
976
      }
3284
3285
965
      col_clear(pinfo->cinfo, COL_INFO);
3286
965
      col_append_sep_str(pinfo->cinfo, COL_INFO, " | ", wmem_strbuf_get_str(res));
3287
965
      col_set_fence(pinfo->cinfo, COL_INFO);
3288
3289
965
      proto_item_append_text(it104, ": %s", wmem_strbuf_get_str(res));
3290
3291
965
      if (type == I_TYPE) {
3292
        /* Set the field lengths to the '104 fixed values before calling the ASDU dissection */
3293
925
        parms.cot_len = 2;
3294
925
        parms.asdu_addr_len = 2;
3295
925
        parms.ioa_len = 3;
3296
3297
925
        call_dissector_with_data(iec60870_asdu_handle, tvb_new_subset_length(tvb, Off + APCI_LEN, len - APCI_DATA_LEN), pinfo, tree, &parms);
3298
925
      }
3299
      /* Don't search more the APCI_START */
3300
965
      break;
3301
976
    }
3302
41.7k
  }
3303
3304
967
  if (Start != APCI_START) {
3305
    /* Everything is bad (no APCI found) */
3306
2
    proto_tree_add_item(it104tree, hf_apcidata, tvb, 0, Off, ENC_NA);
3307
2
  }
3308
3309
967
  return tvb_captured_length(tvb);
3310
1.02k
}
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
277
{
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
277
  tcp_dissect_pdus(tvb, pinfo, tree, true, APCI_LEN,
3416
277
      get_iec104apdu_len, dissect_iec60870_104, data);
3417
277
  return tvb_captured_length(tvb);
3418
277
}
3419
3420
/* The protocol has two subprotocols: Register APCI */
3421
void
3422
proto_register_iec60870_104(void)
3423
15
{
3424
15
  static hf_register_info hf_ap[] = {
3425
3426
15
    { &hf_apdulen,
3427
15
      { "ApduLen", "iec60870_104.apdulen", FT_UINT8, BASE_DEC, NULL, 0x0,
3428
15
        "APDU Len", HFILL }},
3429
3430
15
    { &hf_apcitype_i,
3431
15
      { "Type", "iec60870_104.type", FT_UINT32, BASE_HEX, VALS(apci_types), 0x00000001,
3432
15
        "APCI type", HFILL }},
3433
3434
15
    { &hf_apcitype_s_u,
3435
15
      { "Type", "iec60870_104.type", FT_UINT32, BASE_HEX, VALS(apci_types), 0x00000003,
3436
15
        "APCI type", HFILL }},
3437
3438
15
    { &hf_apciutype,
3439
15
      { "UType", "iec60870_104.utype", FT_UINT32, BASE_HEX, VALS(u_types), 0x000000FC,
3440
15
        "Apci U type", HFILL }},
3441
3442
15
    { &hf_apcitx,
3443
15
      { "Tx", "iec60870_104.tx", FT_UINT32, BASE_DEC, NULL, 0x0000FFFE,
3444
15
        NULL, HFILL }},
3445
3446
15
    { &hf_apcirx,
3447
15
      { "Rx", "iec60870_104.rx", FT_UINT32, BASE_DEC, NULL, 0xFFFE0000,
3448
15
        NULL, HFILL }},
3449
3450
15
    { &hf_apcidata,
3451
15
      { "Data", "iec60870_104.data", FT_BYTES, BASE_NONE, NULL, 0,
3452
15
        NULL, HFILL }},
3453
15
  };
3454
3455
15
  static int *ett_ap[] = {
3456
15
    &ett_apci,
3457
15
  };
3458
3459
15
  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
15
  proto_register_alias(proto_iec60870_104, "104apci");
3463
3464
15
  proto_register_field_array(proto_iec60870_104, hf_ap, array_length(hf_ap));
3465
15
  proto_register_subtree_array(ett_ap, array_length(ett_ap));
3466
3467
15
  prefs_register_protocol(proto_iec60870_104, NULL);
3468
3469
15
  iec60870_104_handle = register_dissector("iec60870_104", dissect_iec60870_104_tcp, proto_iec60870_104);
3470
3471
15
}
3472
3473
/* Register ASDU dissection, shared by the '101 and '104 dissectors */
3474
void
3475
proto_register_iec60870_asdu(void)
3476
15
{
3477
15
  static hf_register_info hf_as[] = {
3478
3479
15
    { &hf_addr,
3480
15
      { "Addr", "iec60870_asdu.addr", FT_UINT16, BASE_DEC, NULL, 0x0,
3481
15
        "Common Address of Asdu", HFILL }},
3482
3483
15
    { &hf_oa,
3484
15
      { "OA", "iec60870_asdu.oa", FT_UINT8, BASE_DEC, NULL, 0x0,
3485
15
        "Originator Address", HFILL }},
3486
3487
15
    { &hf_typeid,
3488
15
      { "TypeId", "iec60870_asdu.typeid", FT_UINT8, BASE_DEC, VALS(asdu_types), 0x0,
3489
15
        "Asdu Type Id", HFILL }},
3490
3491
15
    { &hf_causetx,
3492
15
      { "CauseTx", "iec60870_asdu.causetx", FT_UINT8, BASE_DEC, VALS(causetx_types), F_CAUSE,
3493
15
        "Cause of Transmission", HFILL }},
3494
3495
15
    { &hf_nega,
3496
15
      { "Negative", "iec60870_asdu.nega", FT_BOOLEAN, 8, NULL, F_NEGA,
3497
15
        NULL, HFILL }},
3498
3499
15
    { &hf_test,
3500
15
      { "Test", "iec60870_asdu.test", FT_BOOLEAN, 8, NULL, F_TEST,
3501
15
        NULL, HFILL }},
3502
3503
15
    { &hf_ioa,
3504
15
      { "IOA", "iec60870_asdu.ioa", FT_UINT24, BASE_DEC, NULL, 0x0,
3505
15
        "Information Object Address", HFILL }},
3506
3507
15
    { &hf_numix,
3508
15
      { "NumIx", "iec60870_asdu.numix", FT_UINT8, BASE_DEC, NULL, 0x7F,
3509
15
        "Number of Information Objects/Elements", HFILL }},
3510
3511
15
    { &hf_sq,
3512
15
      { "SQ", "iec60870_asdu.sq", FT_BOOLEAN, 8, NULL, F_SQ,
3513
15
        "Sequence", HFILL }},
3514
3515
15
    { &hf_cp16time,
3516
15
      { "CP16Time (ms)", "iec60870_asdu.cp16time", FT_UINT16, BASE_DEC, NULL, 0,
3517
15
        NULL, HFILL }},
3518
3519
15
    { &hf_cp24time,
3520
15
      { "CP24Time", "iec60870_asdu.cp24time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0,
3521
15
        NULL, HFILL }},
3522
3523
15
    { &hf_cp24time_ms,
3524
15
      { "MS", "iec60870_asdu.cp24time.ms", FT_UINT16, BASE_DEC, NULL, 0,
3525
15
        "CP24Time milliseconds", HFILL }},
3526
3527
15
    { &hf_cp24time_min,
3528
15
      { "Min", "iec60870_asdu.cp24time.min", FT_UINT8, BASE_DEC, NULL, 0x3F,
3529
15
        "CP24Time minutes", HFILL }},
3530
3531
15
    { &hf_cp24time_iv,
3532
15
      { "IV", "iec60870_asdu.cp24time.iv", FT_BOOLEAN, 8, TFS(&tfs_invalid_valid), 0x80,
3533
15
        "CP24Time invalid", HFILL }},
3534
3535
15
    { &hf_cp56time,
3536
15
      { "CP56Time", "iec60870_asdu.cp56time", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0,
3537
15
        NULL, HFILL }},
3538
3539
15
    { &hf_cp56time_ms,
3540
15
      { "MS", "iec60870_asdu.cp56time.ms", FT_UINT16, BASE_DEC, NULL, 0,
3541
15
        "CP56Time milliseconds", HFILL }},
3542
3543
15
    { &hf_cp56time_min,
3544
15
      { "Min", "iec60870_asdu.cp56time.min", FT_UINT8, BASE_DEC, NULL, 0x3F,
3545
15
        "CP56Time minutes", HFILL }},
3546
3547
15
    { &hf_cp56time_gen,
3548
15
      { "GEN", "iec60870_asdu.cp56time.gen", FT_BOOLEAN, 8, TFS(&tfs_substituted_not_substituted), 0x40,
3549
15
        "CP56Time substituted", HFILL }},
3550
3551
15
    { &hf_cp56time_iv,
3552
15
      { "IV", "iec60870_asdu.cp56time.iv", FT_BOOLEAN, 8, TFS(&tfs_invalid_valid), 0x80,
3553
15
        "CP56Time invalid", HFILL }},
3554
3555
15
    { &hf_cp56time_hour,
3556
15
      { "Hour", "iec60870_asdu.cp56time.hour", FT_UINT8, BASE_DEC, NULL, 0x1F,
3557
15
        "CP56Time hours", HFILL }},
3558
3559
15
    { &hf_cp56time_su,
3560
15
      { "SU", "iec60870_asdu.cp56time.su", FT_BOOLEAN, 8, TFS(&tfs_summer_standard_time), 0x80,
3561
15
        "CP56Time summer time", HFILL }},
3562
3563
15
    { &hf_cp56time_day,
3564
15
      { "Day", "iec60870_asdu.cp56time.day", FT_UINT8, BASE_DEC, NULL, 0x1F,
3565
15
        "CP56Time day", HFILL }},
3566
3567
15
    { &hf_cp56time_dow,
3568
15
      { "DOW", "iec60870_asdu.cp56time.dow", FT_UINT8, BASE_DEC, NULL, 0xE0,
3569
15
        "CP56Time day of week", HFILL }},
3570
3571
15
    { &hf_cp56time_month,
3572
15
      { "Month", "iec60870_asdu.cp56time.month", FT_UINT8, BASE_DEC, NULL, 0x0F,
3573
15
        "CP56Time month", HFILL }},
3574
3575
15
    { &hf_cp56time_year,
3576
15
      { "Year", "iec60870_asdu.cp56time.year", FT_UINT8, BASE_DEC, NULL, 0x7F,
3577
15
        "CP56Time year", HFILL }},
3578
3579
15
    { &hf_range_start_cp56time,
3580
15
      { "Range start CP56Time", "iec60870_asdu.range_start_cp56time", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0,
3581
15
        NULL, HFILL }},
3582
3583
15
    { &hf_range_stop_cp56time,
3584
15
      { "Range stop CP56Time", "iec60870_asdu.range_stop_cp56time", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0,
3585
15
        NULL, HFILL } },
3586
3587
15
    { &hf_siq,
3588
15
      { "SIQ", "iec60870_asdu.siq", FT_UINT8, BASE_HEX, NULL, 0,
3589
15
        NULL, HFILL }},
3590
3591
15
    { &hf_siq_spi,
3592
15
      { "SPI", "iec60870_asdu.siq.spi", FT_BOOLEAN, 8, TFS(&tfs_on_off), 0x01,
3593
15
        "SIQ SPI", HFILL }},
3594
3595
15
    { &hf_siq_bl,
3596
15
      { "BL", "iec60870_asdu.siq.bl", FT_BOOLEAN, 8, TFS(&tfs_blocked_not_blocked), 0x10,
3597
15
        "SIQ BL", HFILL }},
3598
3599
15
    { &hf_siq_sb,
3600
15
      { "SB", "iec60870_asdu.siq.sb", FT_BOOLEAN, 8, TFS(&tfs_substituted_not_substituted), 0x20,
3601
15
        "SIQ SB", HFILL }},
3602
3603
15
    { &hf_siq_nt,
3604
15
      { "NT", "iec60870_asdu.siq.nt", FT_BOOLEAN, 8, TFS(&tfs_not_topical_topical), 0x40,
3605
15
        "SIQ NT", HFILL }},
3606
3607
15
    { &hf_siq_iv,
3608
15
      { "IV", "iec60870_asdu.siq.iv", FT_BOOLEAN, 8, TFS(&tfs_invalid_valid), 0x80,
3609
15
        "SIQ IV", HFILL }},
3610
3611
15
    { &hf_diq,
3612
15
      { "DIQ", "iec60870_asdu.diq", FT_UINT8, BASE_HEX, NULL, 0,
3613
15
        NULL, HFILL }},
3614
3615
15
    { &hf_diq_dpi,
3616
15
      { "DPI", "iec60870_asdu.diq.dpi", FT_UINT8, BASE_DEC, VALS(diq_types), 0x03,
3617
15
        "DIQ DPI", HFILL }},
3618
3619
15
    { &hf_diq_bl,
3620
15
      { "BL", "iec60870_asdu.diq.bl", FT_BOOLEAN, 8, TFS(&tfs_blocked_not_blocked), 0x10,
3621
15
        "DIQ BL", HFILL }},
3622
3623
15
    { &hf_diq_sb,
3624
15
      { "SB", "iec60870_asdu.diq.sb", FT_BOOLEAN, 8, TFS(&tfs_substituted_not_substituted), 0x20,
3625
15
        "DIQ SB", HFILL }},
3626
3627
15
    { &hf_diq_nt,
3628
15
      { "NT", "iec60870_asdu.diq.nt", FT_BOOLEAN, 8, TFS(&tfs_not_topical_topical), 0x40,
3629
15
        "DIQ NT", HFILL }},
3630
3631
15
    { &hf_diq_iv,
3632
15
      { "IV", "iec60870_asdu.diq.iv", FT_BOOLEAN, 8, TFS(&tfs_invalid_valid), 0x80,
3633
15
        "DIQ IV", HFILL }},
3634
3635
15
    { &hf_qds,
3636
15
      { "QDS", "iec60870_asdu.qds", FT_UINT8, BASE_HEX, NULL, 0,
3637
15
        NULL, HFILL }},
3638
3639
15
    { &hf_qds_ov,
3640
15
      { "OV", "iec60870_asdu.qds.ov", FT_BOOLEAN, 8, TFS(&tfs_overflow_no_overflow), 0x01,
3641
15
        "QDS OV", HFILL }},
3642
3643
15
    { &hf_qds_bl,
3644
15
      { "BL", "iec60870_asdu.qds.bl", FT_BOOLEAN, 8, TFS(&tfs_blocked_not_blocked), 0x10,
3645
15
        "QDS BL", HFILL }},
3646
3647
15
    { &hf_qds_sb,
3648
15
      { "SB", "iec60870_asdu.qds.sb", FT_BOOLEAN, 8, TFS(&tfs_substituted_not_substituted), 0x20,
3649
15
        "QDS SB", HFILL }},
3650
3651
15
    { &hf_qds_nt,
3652
15
      { "NT", "iec60870_asdu.qds.nt", FT_BOOLEAN, 8, TFS(&tfs_not_topical_topical), 0x40,
3653
15
        "QDS NT", HFILL }},
3654
3655
15
    { &hf_qds_iv,
3656
15
      { "IV", "iec60870_asdu.qds.iv", FT_BOOLEAN, 8, TFS(&tfs_invalid_valid), 0x80,
3657
15
        "QDS IV", HFILL }},
3658
3659
15
    { &hf_vti,
3660
15
      { "VTI", "iec60870_asdu.vti", FT_UINT8, BASE_HEX, NULL, 0,
3661
15
        NULL, HFILL }},
3662
3663
15
    { &hf_vti_v,
3664
15
      { "Value", "iec60870_asdu.vti.v", FT_INT8, BASE_DEC, NULL, 0x7F,
3665
15
        "VTI Value", HFILL }},
3666
3667
15
    { &hf_vti_t,
3668
15
      { "T", "iec60870_asdu.vti.t", FT_BOOLEAN, 8, TFS(&tfs_transient_not_transient), 0x80,
3669
15
        "VTI T", HFILL }},
3670
3671
15
    { &hf_qos,
3672
15
      { "QOS", "iec60870_asdu.qos", FT_UINT8, BASE_HEX, NULL, 0,
3673
15
        NULL, HFILL }},
3674
3675
15
    { &hf_qos_ql,
3676
15
      { "QL", "iec60870_asdu.qos.ql", FT_UINT8, BASE_DEC, NULL, 0x7F,
3677
15
        "QOS QL", HFILL }},
3678
3679
15
    { &hf_qos_se,
3680
15
      { "S/E", "iec60870_asdu.qos.se", FT_BOOLEAN, 8, TFS(&tfs_select_execute), 0x80,
3681
15
        "QOS S/E", HFILL }},
3682
3683
15
    { &hf_sco,
3684
15
      { "SCO", "iec60870_asdu.sco", FT_UINT8, BASE_HEX, NULL, 0,
3685
15
        NULL, HFILL }},
3686
3687
15
    { &hf_sco_on,
3688
15
      { "ON/OFF", "iec60870_asdu.sco.on", FT_BOOLEAN, 8, TFS(&tfs_on_off), 0x01,
3689
15
        "SCO SCS", HFILL }},
3690
3691
15
    { &hf_sco_qu,
3692
15
      { "QU", "iec60870_asdu.sco.qu", FT_UINT8, BASE_DEC, VALS(qos_qu_types), 0x7C,
3693
15
        "SCO QU", HFILL }},
3694
3695
15
    { &hf_sco_se,
3696
15
      { "S/E", "iec60870_asdu.sco.se", FT_BOOLEAN, 8, TFS(&tfs_select_execute), 0x80,
3697
15
        "SCO S/E", HFILL }},
3698
3699
15
    { &hf_dco,
3700
15
      { "DCO", "iec60870_asdu.dco", FT_UINT8, BASE_HEX, NULL, 0,
3701
15
        NULL, HFILL }},
3702
3703
15
    { &hf_dco_on,
3704
15
      { "ON/OFF", "iec60870_asdu.dco.on", FT_UINT8, BASE_DEC, VALS(dco_on_types), 0x03,
3705
15
        "DCO DCS", HFILL }},
3706
3707
15
    { &hf_dco_qu,
3708
15
      { "QU", "iec60870_asdu.dco.qu", FT_UINT8, BASE_DEC, VALS(qos_qu_types), 0x7C,
3709
15
        "DCO QU", HFILL }},
3710
3711
15
    { &hf_dco_se,
3712
15
      { "S/E", "iec60870_asdu.dco.se", FT_BOOLEAN, 8, TFS(&tfs_select_execute), 0x80,
3713
15
        "DCO S/E", HFILL }},
3714
3715
15
    { &hf_rco,
3716
15
      { "RCO", "iec60870_asdu.rco", FT_UINT8, BASE_HEX, NULL, 0,
3717
15
        NULL, HFILL }},
3718
3719
15
    { &hf_rco_up,
3720
15
      { "UP/DOWN", "iec60870_asdu.rco.up", FT_UINT8, BASE_DEC, VALS(rco_up_types), 0x03,
3721
15
        "RCO RCS", HFILL }},
3722
3723
15
    { &hf_rco_qu,
3724
15
      { "QU", "iec60870_asdu.rco.qu", FT_UINT8, BASE_DEC, VALS(qos_qu_types), 0x7C,
3725
15
        "RCO QU", HFILL }},
3726
3727
15
    { &hf_rco_se,
3728
15
      { "S/E", "iec60870_asdu.rco.se", FT_BOOLEAN, 8, TFS(&tfs_select_execute), 0x80,
3729
15
        "RCO S/E", HFILL }},
3730
3731
15
    { &hf_qpm,
3732
15
      { "QPM", "iec60870_asdu.qpm", FT_UINT8, BASE_HEX, NULL, 0,
3733
15
        NULL, HFILL } },
3734
3735
15
    { &hf_qpm_kpa,
3736
15
      { "KPA", "iec60870_asdu.qpm.kpa", FT_UINT8, BASE_DEC, VALS(qpm_kpa_types), 0x3F,
3737
15
        "QPM KPA", HFILL } },
3738
3739
15
    { &hf_qpm_lpc,
3740
15
      { "LPC", "iec60870_asdu.qpm.lpc", FT_UINT8, BASE_DEC, VALS(qpm_lpc_types), 0x40,
3741
15
        "QPM LPC", HFILL } },
3742
3743
15
    { &hf_qpm_pop,
3744
15
      { "POP", "iec60870_asdu.qpm.pop", FT_UINT8, BASE_DEC, VALS(qpm_pop_types), 0x80,
3745
15
        "QPM POP", HFILL } },
3746
3747
15
    { &hf_nof,
3748
15
      { "NOF", "iec60870_asdu.nof", FT_UINT16, BASE_DEC, NULL, 0,
3749
15
        "Name of file", HFILL} },
3750
3751
15
    { &hf_lof,
3752
15
      { "LOF", "iec60870_asdu.lof", FT_UINT32, BASE_DEC, NULL, 0,
3753
15
        "Length of file or section", HFILL} },
3754
3755
15
    { &hf_frq,
3756
15
      { "FRQ", "iec60870_asdu.frq", FT_UINT8, BASE_HEX, NULL, 0,
3757
15
        "File ready qualifier", HFILL} },
3758
3759
15
    { &hf_frq_confirm,
3760
15
      { "Confirmation", "iec60870_asdu.frq.confirm", FT_BOOLEAN, 8, TFS(&tfs_negative_positive), 0x80,
3761
15
        NULL, HFILL } },
3762
3763
15
    { &hf_frq_qualifier,
3764
15
      { "Qualifier", "iec60870_asdu.frq.qualifier", FT_UINT8, BASE_DEC, VALS(frq_qualifier), 0x7F,
3765
15
        NULL, HFILL } },
3766
3767
15
    { &hf_nos,
3768
15
      { "NOS", "iec60870_asdu.nos", FT_UINT16, BASE_DEC, NULL, 0,
3769
15
        "Name of section", HFILL} },
3770
3771
15
    { &hf_srq,
3772
15
      { "SRQ", "iec60870_asdu.srq", FT_UINT8, BASE_HEX, NULL, 0,
3773
15
        "Section ready qualifier", HFILL} },
3774
3775
15
    { &hf_srq_ready,
3776
15
      { "Ready", "iec60870_asdu.srq.ready", FT_BOOLEAN, 8, TFS(&tfs_not_ready_ready), 0x80,
3777
15
        NULL, HFILL } },
3778
3779
15
    { &hf_srq_qualifier,
3780
15
      { "Qualifier", "iec60870_asdu.srq.qualifier", FT_UINT8, BASE_DEC, VALS(srq_qualifier), 0x7F,
3781
15
        NULL, HFILL } },
3782
3783
15
    { &hf_scq,
3784
15
      { "SCQ", "iec60870_asdu.scq", FT_UINT8, BASE_HEX, NULL, 0,
3785
15
        "Select and call qualifier", HFILL}},
3786
3787
15
    { &hf_scq_select,
3788
15
      { "Select", "iec60870_asdu.scq.select", FT_UINT8, BASE_DEC, VALS(scq_select), 0x0F,
3789
15
        NULL, HFILL } },
3790
3791
15
    { &hf_scq_qualifier,
3792
15
      { "Qualifier", "iec60870_asdu.scq.qualifier", FT_UINT8, BASE_DEC, VALS(scq_qualifier), 0xF0,
3793
15
        NULL, HFILL } },
3794
3795
15
    { &hf_lsq,
3796
15
      { "LSQ", "iec60870_asdu.lsq", FT_UINT8, BASE_DEC, VALS(lsq_qualifier), 0,
3797
15
        "Last section or segment qualifier", HFILL} },
3798
3799
15
    { &hf_chs,
3800
15
      { "CHS", "iec60870_asdu.chs", FT_UINT8, BASE_HEX, NULL, 0,
3801
15
        "Checksum", HFILL} },
3802
3803
15
    { &hf_afq,
3804
15
      { "AFQ", "iec60870_asdu.afq", FT_UINT8, BASE_HEX, NULL, 0,
3805
15
        "Acknowledge file or section qualifier", HFILL} },
3806
3807
15
    { &hf_afq_ack,
3808
15
      { "Acknowledge", "iec60870_asdu.afq.ack", FT_UINT8, BASE_DEC, VALS(afq_ack), 0x0F,
3809
15
        NULL, HFILL } },
3810
3811
15
    { &hf_afq_qualifier,
3812
15
      { "Qualifier", "iec60870_asdu.afq.qualifier", FT_UINT8, BASE_DEC, VALS(afq_qualifier), 0xF0,
3813
15
        NULL, HFILL } },
3814
3815
15
    { &hf_los,
3816
15
      { "LOS", "iec60870_asdu.los", FT_UINT8, BASE_DEC, NULL, 0,
3817
15
        "Length of segment", HFILL} },
3818
3819
15
    { &hf_segment_data,
3820
15
      { "Data", "iec60870_asdu.segmentdata", FT_BYTES, BASE_NONE, NULL, 0x0,
3821
15
        "Segment data", HFILL } },
3822
3823
15
    { &hf_sof,
3824
15
      { "SOF", "iec60870_asdu.sof", FT_UINT8, BASE_HEX, NULL, 0,
3825
15
        "Status of file", HFILL} },
3826
3827
15
    { &hf_sof_status,
3828
15
      { "Status", "iec60870_asdu.sof.status", FT_UINT8, BASE_DEC, VALS(sof_status), 0x1F,
3829
15
        NULL, HFILL } },
3830
3831
15
    { &hf_sof_lfd,
3832
15
      { "LFD", "iec60870_asdu.sof.lfd", FT_BOOLEAN, 8, TFS(&tfs_last_file_additional_follows), 0x20,
3833
15
        NULL, HFILL } },
3834
3835
15
    { &hf_sof_for,
3836
15
      { "FOR", "iec60870_asdu.sof.for", FT_BOOLEAN, 8, TFS(&tfs_subdir_file), 0x40,
3837
15
        NULL, HFILL } },
3838
3839
15
    { &hf_sof_fa,
3840
15
      { "FA", "iec60870_asdu.sof.fa", FT_BOOLEAN, 8, TFS(&tfs_active_waits), 0x80,
3841
15
        NULL, HFILL } },
3842
3843
15
    { &hf_sep,
3844
15
      { "SEP", "iec60870_asdu.sep", FT_UINT8, BASE_HEX, NULL, 0,
3845
15
        NULL, HFILL } },
3846
3847
15
    { &hf_sep_es,
3848
15
      { "ES", "iec60870_asdu.sep.es", FT_UINT8, BASE_DEC, VALS(sep_types), 0x03,
3849
15
        "SEP ES", HFILL}},
3850
3851
15
    { &hf_sep_ei,
3852
15
      { "EI", "iec60870_asdu.sep.ei", FT_BOOLEAN, 8, TFS(&tfs_elapsed_invalid_valid), 0x08,
3853
15
        "SEP EI", HFILL} },
3854
3855
15
    { &hf_sep_bl ,
3856
15
      { "BL", "iec60870_asdu.sep.bl", FT_BOOLEAN, 8, TFS(&tfs_blocked_not_blocked), 0x10,
3857
15
        "SEP BL", HFILL} },
3858
3859
15
    { &hf_sep_sb ,
3860
15
      { "SB", "iec60870_asdu.sep.sb", FT_BOOLEAN, 8, TFS(&tfs_substituted_not_substituted), 0x20,
3861
15
        "SEP SB", HFILL} },
3862
3863
15
    { &hf_sep_nt ,
3864
15
      { "NT", "iec60870_asdu.sep.nt", FT_BOOLEAN, 8, TFS(&tfs_not_topical_topical), 0x40,
3865
15
        "SEP NT", HFILL} },
3866
3867
15
    { &hf_sep_iv ,
3868
15
      { "IV", "iec60870_asdu.sep.iv", FT_BOOLEAN, 8, TFS(&tfs_invalid_valid), 0x80,
3869
15
        "SEP IV", HFILL} },
3870
3871
15
    { &hf_spe,
3872
15
      { "SPE", "iec60870_asdu.spe", FT_UINT8, BASE_HEX, NULL, 0,
3873
15
        NULL, HFILL } },
3874
3875
15
    { &hf_spe_gs,
3876
15
      { "GS", "iec60870_asdu.spe.gs", FT_BOOLEAN, 8, TFS(&tfs_general_start_no_general_start), 0x01,
3877
15
        "SPE GS", HFILL} },
3878
3879
15
    { &hf_spe_sl1,
3880
15
      { "SL1", "iec60870_asdu.spe.sl1", FT_BOOLEAN, 8, TFS(&tfs_start_no_start), 0x02,
3881
15
        "SPE SL1", HFILL} },
3882
3883
15
    { &hf_spe_sl2,
3884
15
      { "SL2", "iec60870_asdu.spe.sl2", FT_BOOLEAN, 8, TFS(&tfs_start_no_start), 0x04,
3885
15
        "SPE SL2", HFILL} },
3886
3887
15
    { &hf_spe_sl3,
3888
15
      { "SL3", "iec60870_asdu.spe.sl3", FT_BOOLEAN, 8, TFS(&tfs_start_no_start), 0x08,
3889
15
        "SPE SL3", HFILL} },
3890
3891
15
    { &hf_spe_sie,
3892
15
      { "SIE", "iec60870_asdu.spe.sie", FT_BOOLEAN, 8, TFS(&tfs_start_no_start), 0x10,
3893
15
        "SPE SIE", HFILL} },
3894
3895
15
    { &hf_spe_srd,
3896
15
      { "SRD", "iec60870_asdu.spe.srd", FT_BOOLEAN, 8, TFS(&tfs_start_reverse_no_start_revers), 0x20,
3897
15
        "SPE SRD", HFILL} },
3898
3899
15
    { &hf_qdp,
3900
15
      { "QDP", "iec60870_asdu.qdp", FT_UINT8, BASE_HEX, NULL, 0,
3901
15
        NULL, HFILL } },
3902
3903
15
    { &hf_qdp_ei,
3904
15
      { "EI", "iec60870_asdu.qdp.ei", FT_BOOLEAN, 8, TFS(&tfs_elapsed_invalid_valid), 0x08,
3905
15
        "QDP EI", HFILL} },
3906
3907
15
    { &hf_qdp_bl ,
3908
15
      { "BL", "iec60870_asdu.qdp.bl", FT_BOOLEAN, 8, TFS(&tfs_blocked_not_blocked), 0x10,
3909
15
        "QDP BL", HFILL} },
3910
3911
15
    { &hf_qdp_sb ,
3912
15
      { "SB", "iec60870_asdu.qdp.sb", FT_BOOLEAN, 8, TFS(&tfs_substituted_not_substituted), 0x20,
3913
15
        "QDP SB", HFILL} },
3914
3915
15
    { &hf_qdp_nt ,
3916
15
      { "NT", "iec60870_asdu.qdp.nt", FT_BOOLEAN, 8, TFS(&tfs_not_topical_topical), 0x40,
3917
15
        "QDP NT", HFILL} },
3918
3919
15
    { &hf_qdp_iv ,
3920
15
      { "IV", "iec60870_asdu.qdp.iv", FT_BOOLEAN, 8, TFS(&tfs_invalid_valid), 0x80,
3921
15
        "QDP IV", HFILL} },
3922
3923
15
    { &hf_oci,
3924
15
      { "OCI", "iec60870_asdu.oci", FT_UINT8, BASE_HEX, NULL, 0,
3925
15
        NULL, HFILL } },
3926
3927
15
    { &hf_oci_gc,
3928
15
      { "GC", "iec60870_asdu.oci.gc", FT_BOOLEAN, 8, TFS(&tfs_general_command_no_general_command), 0x01,
3929
15
        "OCI GC", HFILL} },
3930
3931
15
    { &hf_oci_cl1,
3932
15
      { "CL1", "iec60870_asdu.oci.cl1", FT_BOOLEAN, 8, TFS(&tfs_command_no_command), 0x02,
3933
15
        "OCI CL1", HFILL} },
3934
3935
15
    { &hf_oci_cl2,
3936
15
      { "CL2", "iec60870_asdu.oci.cl2", FT_BOOLEAN, 8, TFS(&tfs_command_no_command), 0x04,
3937
15
        "OCI CL2", HFILL} },
3938
3939
15
    { &hf_oci_cl3,
3940
15
      { "CL3", "iec60870_asdu.oci.cl3", FT_BOOLEAN, 8, TFS(&tfs_command_no_command), 0x08,
3941
15
        "OCI CL3", HFILL} },
3942
3943
15
    { &hf_qpa,
3944
15
      { "QPA", "iec60870_asdu.qpa", FT_UINT8, BASE_DEC, VALS(qpa_types), 0x0,
3945
15
        NULL, HFILL} },
3946
3947
15
    { &hf_fbp,
3948
15
      { "FBP", "iec60870_asdu.fbp", FT_UINT16, BASE_HEX, NULL, 0x0,
3949
15
        NULL, HFILL} },
3950
3951
15
    { &hf_scd,
3952
15
      { "SCD", "iec60870_asdu.scd", FT_UINT32, BASE_HEX, NULL, 0,
3953
15
        NULL, HFILL } },
3954
3955
15
    { &hf_scd_st,
3956
15
      { "ST", "iec60870_asdu.scd.st", FT_UINT16, BASE_HEX, NULL, 0x0,
3957
15
        "SCD ST", HFILL} },
3958
3959
15
    { &hf_scd_cd,
3960
15
      { "CD", "iec60870_asdu.scd.cd", FT_UINT16, BASE_HEX, NULL, 0x0,
3961
15
        "SCD CD", HFILL} },
3962
3963
15
    { &hf_asn,
3964
15
      { "ASDU Segment Sequence Number (ASN)", "iec60870_asdu.asn", FT_UINT8, BASE_DEC, NULL, 0x3F,
3965
15
        NULL, HFILL }},
3966
3967
15
    { &hf_asn_fin,
3968
15
      { "Final segment (FIN)", "iec60870_asdu.asn.fin", FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x80,
3969
15
        NULL, HFILL }},
3970
3971
15
    { &hf_asn_fir,
3972
15
      { "First segment (FIR)", "iec60870_asdu.asn.fir", FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x40,
3973
15
        NULL, HFILL }},
3974
3975
15
    { &hf_iec60870_segment_data,
3976
15
       { "ASDU segment data", "iec60870_asdu.segment_data", FT_BYTES, BASE_NONE, NULL, 0x0,
3977
15
         NULL, HFILL }},
3978
3979
15
    { &hf_usr,
3980
15
      { "User number (USR)", "iec60870_asdu.usr", FT_UINT16, BASE_DEC | BASE_RANGE_STRING, RVALS(usr_types), 0,
3981
15
        NULL, HFILL }},
3982
3983
15
    { &hf_mal,
3984
15
      { "MAC algorithm (MAL)", "iec60870_asdu.mal", FT_UINT8, BASE_DEC | BASE_RANGE_STRING, RVALS(mal_types), 0,
3985
15
        NULL, HFILL }},
3986
3987
15
    { &hf_rsc,
3988
15
      { "Reason for challenge (RSC)", "iec60870_asdu.rsc", FT_UINT8, BASE_DEC, VALS(rsc_types), 0,
3989
15
        NULL, HFILL }},
3990
3991
15
    { &hf_csq,
3992
15
      { "Challenge sequence number (CSQ)", "iec60870_asdu.csq", FT_UINT32, BASE_DEC, NULL, 0,
3993
15
        NULL, HFILL }},
3994
3995
15
    { &hf_ksq,
3996
15
      { "Key change sequence number (KSQ)", "iec60870_asdu.ksq", FT_UINT32, BASE_DEC, NULL, 0,
3997
15
        NULL, HFILL }},
3998
3999
15
    { &hf_kwa,
4000
15
      { "Key wrap algorithm (KWA)", "iec60870_asdu.kwa", FT_UINT8, BASE_DEC | BASE_RANGE_STRING, RVALS(kwa_types), 0,
4001
15
        NULL, HFILL }},
4002
4003
15
    { &hf_kst,
4004
15
      { "Key status (KST)", "iec60870_asdu.kst", FT_UINT8, BASE_DEC, VALS(kst_types), 0,
4005
15
        NULL, HFILL }},
4006
4007
15
    { &hf_hln,
4008
15
      { "MAC length (HLN)", "iec60870_asdu.hln", FT_UINT16, BASE_DEC, NULL, 0,
4009
15
        NULL, HFILL }},
4010
4011
15
    { &hf_hal,
4012
15
      { "MAC algorithm (HAL)", "iec60870_asdu.hal", FT_UINT8, BASE_DEC | BASE_RANGE_STRING, RVALS(hal_types), 0,
4013
15
        NULL, HFILL }},
4014
4015
15
    { &hf_cln,
4016
15
      { "Challenge data length (CLN)", "iec60870_asdu.cln", FT_UINT16, BASE_DEC, NULL, 0,
4017
15
        NULL, HFILL }},
4018
4019
15
    { &hf_wkl,
4020
15
      { "Wrapped key data length (CLN)", "iec60870_asdu.wkl", FT_UINT16, BASE_DEC, NULL, 0,
4021
15
        NULL, HFILL }},
4022
4023
15
    { &hf_prcd_raw_data,
4024
15
      { "Pseudo-random challenge data", "iec60870_asdu.challenge_data", FT_BYTES, BASE_NONE, NULL, 0x0,
4025
15
        NULL, HFILL }},
4026
4027
15
    { &hf_hmac_raw_data,
4028
15
      { "HMAC value", "iec60870_asdu.hmac", FT_BYTES, BASE_NONE, NULL, 0x0,
4029
15
        NULL, HFILL }},
4030
4031
15
    { &hf_wkd_raw_data,
4032
15
      { "Wrapped key data", "iec60870_asdu.wkd", FT_BYTES, BASE_NONE, NULL, 0x0,
4033
15
        NULL, HFILL }},
4034
4035
15
    { &hf_aid,
4036
15
      { "Association ID (AID)", "iec60870_asdu.aid", FT_UINT16, BASE_DEC, NULL, 0,
4037
15
        NULL, HFILL }},
4038
4039
15
    { &hf_err,
4040
15
      { "Error code (ERR)", "iec60870_asdu.err", FT_UINT8, BASE_DEC | BASE_RANGE_STRING, RVALS(error_codes), 0,
4041
15
        NULL, HFILL }},
4042
4043
15
    { &hf_etm,
4044
15
      { "Error time stamp (ETM)", "iec60870_asdu.etm", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0,
4045
15
        NULL, HFILL }},
4046
4047
15
    { &hf_etm_ms,
4048
15
      { "MS", "iec60870_asdu.etm.ms", FT_UINT16, BASE_DEC, NULL, 0,
4049
15
        "Error time stamp milliseconds", HFILL }},
4050
4051
15
    { &hf_etm_min,
4052
15
      { "Min", "iec60870_asdu.etm.min", FT_UINT8, BASE_DEC, NULL, 0x3F,
4053
15
        "Error time stamp minutes", HFILL }},
4054
4055
15
    { &hf_etm_iv,
4056
15
      { "IV", "iec60870_asdu.etm.iv", FT_BOOLEAN, 8, TFS(&tfs_invalid_valid), 0x80,
4057
15
        "Error time stamp invalid", HFILL }},
4058
4059
15
    { &hf_etm_hour,
4060
15
      { "Hour", "iec60870_asdu.etm.hour", FT_UINT8, BASE_DEC, NULL, 0x1F,
4061
15
        "Error time stamp hours", HFILL }},
4062
4063
15
    { &hf_etm_su,
4064
15
      { "SU", "iec60870_asdu.etm.su", FT_BOOLEAN, 8, TFS(&tfs_summer_standard_time), 0x80,
4065
15
        "Error time stamp summer time", HFILL }},
4066
4067
15
    { &hf_etm_day,
4068
15
      { "Day", "iec60870_asdu.etm.day", FT_UINT8, BASE_DEC, NULL, 0x1F,
4069
15
        "Error time stamp day", HFILL }},
4070
4071
15
    { &hf_etm_dow,
4072
15
      { "DOW", "iec60870_asdu.etm.dow", FT_UINT8, BASE_DEC, NULL, 0xE0,
4073
15
        "Error time stamp day of week", HFILL }},
4074
4075
15
    { &hf_etm_month,
4076
15
      { "Month", "iec60870_asdu.etm.month", FT_UINT8, BASE_DEC, NULL, 0x0F,
4077
15
        "Error time stamp month", HFILL }},
4078
4079
15
    { &hf_etm_year,
4080
15
      { "Year", "iec60870_asdu.etm.year", FT_UINT8, BASE_DEC, NULL, 0x7F,
4081
15
        "Error time stamp year", HFILL }},
4082
4083
15
    { &hf_eln,
4084
15
      { "Error length (ELN)", "iec60870_asdu.eln", FT_UINT16, BASE_DEC, NULL, 0,
4085
15
        NULL, HFILL }},
4086
4087
15
    { &hf_error_text,
4088
15
      { "Error text", "iec60870_asdu.error_text", FT_STRING, BASE_NONE, NULL, 0x0,
4089
15
        NULL, HFILL }},
4090
4091
15
    { &hf_coi,
4092
15
      { "COI", "iec60870_asdu.coi", FT_UINT8, BASE_HEX, NULL, 0,
4093
15
        NULL, HFILL }},
4094
4095
15
    { &hf_coi_r,
4096
15
      { "R", "iec60870_asdu.coi.r", FT_UINT8, BASE_DEC, VALS(coi_r_types), 0x7F,
4097
15
        "COI R", HFILL }},
4098
4099
15
    { &hf_coi_i,
4100
15
      { "I", "iec60870_asdu.coi.i", FT_BOOLEAN, 8, TFS(&tfs_coi_i), 0x80,
4101
15
        "COI I", HFILL }},
4102
4103
15
    { &hf_qoi,
4104
15
      { "QOI", "iec60870_asdu.qoi", FT_UINT8, BASE_DEC, VALS(qoi_r_types), 0,
4105
15
        NULL, HFILL }},
4106
4107
15
    { &hf_qcc,
4108
15
      { "QCC", "iec60870_asdu.qcc", FT_UINT8, BASE_HEX, NULL, 0,
4109
15
        NULL, HFILL } },
4110
4111
15
    { &hf_qcc_rqt,
4112
15
      { "RQT", "iec60870_asdu.qcc.rqt", FT_UINT8, BASE_DEC, VALS(rqt_r_types), 0x3F,
4113
15
        NULL, HFILL } },
4114
4115
15
    { &hf_qcc_frz,
4116
15
      { "FRZ", "iec60870_asdu.qcc.frz", FT_UINT8, BASE_DEC, VALS(frz_r_types), 0xC0,
4117
15
        NULL, HFILL } },
4118
4119
15
    { &hf_qrp,
4120
15
      { "QRP", "iec60870_asdu.qrp", FT_UINT8, BASE_DEC, VALS(qrp_r_types), 0,
4121
15
        NULL, HFILL }},
4122
4123
15
    { &hf_bcr,
4124
15
      { "BCR", "iec60870_asdu.bcr", FT_INT32, BASE_DEC, NULL, 0x0,
4125
15
        "Binary Counter", HFILL }},
4126
4127
15
    { &hf_bcr_count,
4128
15
      { "Value", "iec60870_asdu.bcr.count", FT_INT32, BASE_DEC, NULL, 0x0,
4129
15
        NULL, HFILL }},
4130
4131
15
    { &hf_bcr_sq,
4132
15
      { "SQ", "iec60870_asdu.bcr.sq", FT_UINT8, BASE_DEC, NULL, 0x1F,
4133
15
        "Sequence Number", HFILL }},
4134
4135
15
    { &hf_bcr_cy,
4136
15
      { "CY", "iec60870_asdu.bcr.cy", FT_BOOLEAN, 8, TFS(&tfs_overflow_no_overflow), 0x20,
4137
15
        "Counter Overflow", HFILL }},
4138
4139
15
    { &hf_bcr_ca,
4140
15
      { "CA", "iec60870_asdu.bcr.ca", FT_BOOLEAN, 8, TFS(&tfs_adjusted_not_adjusted), 0x40,
4141
15
        "Counter Adjusted", HFILL }},
4142
4143
15
    { &hf_bcr_iv,
4144
15
      { "IV", "iec60870_asdu.bcr.iv", FT_BOOLEAN, 8, TFS(&tfs_invalid_valid), 0x80,
4145
15
        "Counter Validity", HFILL }},
4146
4147
15
    { &hf_start,
4148
15
      { "START", "iec60870_asdu.start", FT_UINT8, BASE_HEX, NULL, 0x0,
4149
15
        NULL, HFILL }},
4150
4151
15
    { &hf_asdu_bitstring,
4152
15
      { "Value", "iec60870_asdu.bitstring", FT_UINT32, BASE_HEX, NULL, 0x0,
4153
15
        "BSI value", HFILL }},
4154
4155
15
    { &hf_asdu_float,
4156
15
      { "Value", "iec60870_asdu.float", FT_FLOAT, BASE_NONE, NULL, 0x0,
4157
15
        "Float value", HFILL }},
4158
4159
15
    { &hf_asdu_normval,
4160
15
      { "Value", "iec60870_asdu.normval", FT_FLOAT, BASE_NONE, NULL, 0x0,
4161
15
        "Normalised value", HFILL }},
4162
4163
15
    { &hf_asdu_scalval,
4164
15
      { "Value", "iec60870_asdu.scalval", FT_INT16, BASE_DEC, NULL, 0x0,
4165
15
        "Scaled value", HFILL }},
4166
4167
15
    { &hf_asdu_tsc,
4168
15
      { "TSC", "iec60870_asdu.tsc", FT_UINT16, BASE_DEC, NULL, 0x0,
4169
15
              "Test sequence counter", HFILL }},
4170
4171
15
    { &hf_asdu_raw_data,
4172
15
      { "Raw Data", "iec60870_asdu.rawdata", FT_BYTES, BASE_NONE, NULL, 0x0,
4173
15
        "Information object raw data", HFILL }},
4174
4175
15
    { &hf_iec60870_segments,
4176
15
      { "ASDU Segments", "iec60870_asdu.segments", FT_NONE, BASE_NONE, NULL, 0x0,
4177
15
        NULL, HFILL }},
4178
4179
15
    { &hf_iec60870_segment,
4180
15
      { "ASDU Segment", "iec60870_asdu.segment", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
4181
15
        NULL, HFILL }},
4182
4183
15
    { &hf_iec60870_segment_overlap,
4184
15
      { "Segment overlap", "iec60870_asdu.segment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
4185
15
        "Segment overlaps with other segments", HFILL }},
4186
4187
15
    { &hf_iec60870_segment_overlap_conflict,
4188
15
      { "Conflicting data in segment overlap", "iec60870_asdu.segment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
4189
15
        "Overlapping segments contained conflicting data", HFILL }},
4190
4191
15
    { &hf_iec60870_segment_multiple_tails,
4192
15
      { "Multiple tail segments found", "iec60870_asdu.segment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
4193
15
        "Several tails were found when reassembling the packet", HFILL }},
4194
4195
15
    { &hf_iec60870_segment_too_long_segment,
4196
15
      { "Segment too long", "iec60870_asdu.segment.toolongsegment", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
4197
15
        "Segment contained data past end of packet", HFILL }},
4198
4199
15
    { &hf_iec60870_segment_error,
4200
15
      { "Reassembly error", "iec60870_asdu.segment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
4201
15
        "Reassembly error due to illegal segments", HFILL }},
4202
4203
15
    { &hf_iec60870_segment_count,
4204
15
      { "Segment count", "iec60870_asdu.segment.count", FT_UINT32, BASE_DEC, NULL, 0x0,
4205
15
        NULL, HFILL }},
4206
4207
15
    { &hf_iec60870_reassembled_in,
4208
15
       { "Reassembled ASDU in frame", "iec60870_asdu.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
4209
15
         "This ASDU packet is reassembled in this frame", HFILL }},
4210
4211
15
    { &hf_iec60870_reassembled_length,
4212
15
      { "Reassembled ASDU length", "iec60870_asdu.reassembled.length", FT_UINT32, BASE_DEC, NULL, 0x0,
4213
15
        "The total length of the reassembled payload", HFILL }},
4214
4215
15
  };
4216
4217
15
  static int *ett_as[] = {
4218
15
    &ett_asdu,
4219
15
    &ett_asdu_objects,
4220
15
    &ett_siq,
4221
15
    &ett_diq,
4222
15
    &ett_qds,
4223
15
    &ett_qos,
4224
15
    &ett_vti,
4225
15
    &ett_sco,
4226
15
    &ett_sep,
4227
15
    &ett_spe,
4228
15
    &ett_qdp,
4229
15
    &ett_oci,
4230
15
    &ett_scd,
4231
15
    &ett_dco,
4232
15
    &ett_rco,
4233
15
    &ett_qpm,
4234
15
    &ett_frq,
4235
15
    &ett_srq,
4236
15
    &ett_scq,
4237
15
    &ett_afq,
4238
15
    &ett_sof,
4239
15
    &ett_coi,
4240
15
    &ett_qcc,
4241
15
    &ett_cp24time,
4242
15
    &ett_cp56time,
4243
15
    &ett_etm,
4244
15
    &ett_iec60870_segment,
4245
15
    &ett_iec60870_segments
4246
15
  };
4247
4248
15
  static ei_register_info ei[] = {
4249
15
    { &ei_iec104_short_asdu, { "iec104.short_asdu", PI_MALFORMED, PI_ERROR, "<ERR Short Asdu>", EXPFILL }},
4250
15
    { &ei_iec104_apdu_min_len, { "iec104.apdu_min_len", PI_MALFORMED, PI_ERROR, "APDU less than bytes", EXPFILL }},
4251
15
    { &ei_iec104_apdu_invalid_len, { "iec104.apdu_invalid_len", PI_MALFORMED, PI_ERROR, "Invalid ApduLen", EXPFILL }},
4252
15
  };
4253
4254
15
  expert_module_t* expert_iec60870;
4255
4256
15
  proto_iec60870_asdu = proto_register_protocol("IEC 60870-5-101/104 ASDU", "IEC 60870-5-101/104 ASDU", "iec60870_asdu");
4257
15
  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
15
  proto_register_alias(proto_iec60870_asdu, "104asdu");
4261
4262
15
  proto_register_field_array(proto_iec60870_asdu, hf_as, array_length(hf_as));
4263
15
  proto_register_subtree_array(ett_as, array_length(ett_as));
4264
15
  expert_iec60870 = expert_register_protocol(proto_iec60870_asdu);
4265
15
  expert_register_field_array(expert_iec60870, ei, array_length(ei));
4266
4267
15
  reassembly_table_register(&iec60870_reassemble_table, &addresses_ports_reassembly_table_functions);
4268
15
}
4269
4270
/* The registration hand-off routine */
4271
void
4272
proto_reg_handoff_iec60870_104(void)
4273
15
{
4274
15
  dissector_add_uint_with_preference("tcp.port", IEC104_PORT, iec60870_104_handle);
4275
15
}
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
15
{
4346
  /* IEC 101 Protocol header fields */
4347
15
  static hf_register_info iec60870_101_hf[] = {
4348
15
    { &hf_iec60870_101_frame,
4349
15
    { "Frame Format", "iec60870_101.header", FT_UINT8, BASE_HEX, VALS(iec60870_101_frame_vals), 0x0, NULL, HFILL }},
4350
15
    { &hf_iec60870_101_length,
4351
15
    { "Length", "iec60870_101.length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4352
15
    { &hf_iec60870_101_num_user_octets,
4353
15
    { "Number of User Octets", "iec60870_101.num_user_octets", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4354
15
    { &hf_iec60870_101_ctrlfield,
4355
15
    { "Control Field", "iec60870_101.ctrlfield", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
4356
15
    { &hf_iec60870_101_ctrl_prm,
4357
15
    { "PRM", "iec60870_101.ctrl_prm", FT_UINT8, BASE_DEC, VALS(iec60870_101_ctrl_prm_values), 0x40, "Primary Message", HFILL }},
4358
15
    { &hf_iec60870_101_ctrl_fcb,
4359
15
    { "FCB", "iec60870_101.ctrl_fcb", FT_UINT8, BASE_DEC, NULL, 0x20, "Frame Count Bit", HFILL }},
4360
15
    { &hf_iec60870_101_ctrl_fcv,
4361
15
    { "FCV", "iec60870_101.ctrl_fcv", FT_UINT8, BASE_DEC, NULL, 0x10, "Frame Count Bit Valid", HFILL }},
4362
15
    { &hf_iec60870_101_ctrl_dfc,
4363
15
    { "DFC", "iec60870_101.ctrl_dfc", FT_UINT8, BASE_DEC, NULL, 0x10, "Data Flow Control", HFILL }},
4364
15
    { &hf_iec60870_101_ctrl_func_pri_to_sec,
4365
15
    { "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
15
    { &hf_iec60870_101_ctrl_func_sec_to_pri,
4367
15
    { "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
15
    { &hf_iec60870_101_linkaddr,
4369
15
    { "Data Link Address", "iec60870_101.linkaddr", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4370
15
    { &hf_iec60870_101_checksum,
4371
15
    { "Checksum", "iec60870_101.checksum", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
4372
15
    { &hf_iec60870_101_stopchar,
4373
15
    { "Stop Character", "iec60870_101.stopchar", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
4374
4375
15
  };
4376
4377
  /* Setup protocol subtree array */
4378
15
  static int *ett_serial[] = {
4379
15
    &ett_iec60870_101,
4380
15
    &ett_iec60870_101_ctrlfield,
4381
15
  };
4382
4383
15
  static ei_register_info ei_101[] = {
4384
15
    { &ei_iec101_frame_mismatch, { "iec60870_101.header.mismatch", PI_MALFORMED, PI_ERROR, "Variable Length frames must have two matching start bytes (0x68)", EXPFILL }},
4385
15
    { &ei_iec101_length_mismatch, { "iec60870_101.length.mismatch", PI_MALFORMED, PI_ERROR, "Variable Length frames must have two matching length bytes", EXPFILL }},
4386
15
    { &ei_iec101_stopchar_invalid, { "iec60870_101.stopchar.invalid", PI_PROTOCOL, PI_WARN, "Stop character must be 0x16", EXPFILL }},
4387
15
  };
4388
4389
15
  module_t *iec60870_101_module;
4390
15
  expert_module_t* expert_iec60870_101;
4391
4392
  /* Register the protocol name and description */
4393
15
  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
15
  proto_register_field_array(proto_iec60870_101, iec60870_101_hf, array_length(iec60870_101_hf));
4397
15
  proto_register_subtree_array(ett_serial, array_length(ett_serial));
4398
4399
15
  expert_iec60870_101 = expert_register_protocol(proto_iec60870_101);
4400
15
  expert_register_field_array(expert_iec60870_101, ei_101, array_length(ei_101));
4401
4402
15
  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
15
  iec60870_101_module = prefs_register_protocol(proto_iec60870_101, NULL);
4406
4407
15
  static const enum_val_t link_addr_len[] = {
4408
15
    {"0", "0 octet", 0},
4409
15
    {"1", "1 octet", 1},
4410
15
    {"2", "2 octet", 2},
4411
15
    {NULL, NULL, -1}
4412
15
  };
4413
4414
15
  static const enum_val_t cot_len[] = {
4415
15
    {"1", "1 octet", 1},
4416
15
    {"2", "2 octet", 2},
4417
15
    {NULL, NULL, -1}
4418
15
  };
4419
4420
15
  static const enum_val_t asdu_addr_len[] = {
4421
15
    {"1", "1 octet", 1},
4422
15
    {"2", "2 octet", 2},
4423
15
    {NULL, NULL, -1}
4424
15
  };
4425
4426
15
  static const enum_val_t asdu_ioa_len[] = {
4427
15
    {"1", "1 octet", 1},
4428
15
    {"2", "2 octet", 2},
4429
15
    {"3", "3 octet", 3},
4430
15
    {NULL, NULL, -1}
4431
15
  };
4432
4433
15
  prefs_register_enum_preference(iec60870_101_module, "linkaddr_len",
4434
15
    "Length of the Link Address Field",
4435
15
    "Length of the Link Address Field, configurable in '101 and absent in '104",
4436
15
    &global_iec60870_link_addr_len, link_addr_len, false);
4437
4438
15
  prefs_register_enum_preference(iec60870_101_module, "cot_len",
4439
15
    "Length of the Cause of Transmission Field",
4440
15
    "Length of the Cause of Transmission Field, configurable in '101 and fixed at 2 octets with '104",
4441
15
    &global_iec60870_cot_len, cot_len, false);
4442
4443
15
  prefs_register_enum_preference(iec60870_101_module, "asdu_addr_len",
4444
15
    "Length of the Common ASDU Address Field",
4445
15
    "Length of the Common ASDU Address Field, configurable in '101 and fixed at 2 octets with '104",
4446
15
    &global_iec60870_asdu_addr_len, asdu_addr_len, false);
4447
4448
15
  prefs_register_enum_preference(iec60870_101_module, "asdu_ioa_len",
4449
15
    "Length of the Information Object Address Field",
4450
15
    "Length of the Information Object Address Field, configurable in '101 and fixed at 3 octets with '104",
4451
15
    &global_iec60870_ioa_len, asdu_ioa_len, false);
4452
4453
15
}
4454
4455
void
4456
proto_reg_handoff_iec60870_101(void)
4457
15
{
4458
  /* Add decode-as connection to determine user-customized TCP port */
4459
15
  dissector_add_for_decode_as_with_preference("tcp.port", iec60870_101_handle);
4460
  /* Add dissection for serial pcap files generated by the RTAC */
4461
15
  dissector_add_for_decode_as("rtacser.data", iec60870_101_handle);
4462
15
}
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
15
{
4675
  /* IEC 103 Protocol header fields */
4676
15
  static hf_register_info iec60870_5_103_hf[] = {
4677
15
    { &hf_iec60870_5_103_areva_cmd,
4678
15
    { "Areva Command Code", "iec60870_5_103.areva_cmd", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
4679
15
    { &hf_iec60870_5_103_asdu_address,
4680
15
    { "ASDU Common Address", "iec60870_5_103.asdu_address", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4681
15
    { &hf_iec60870_5_103_asdu_typeid_ctrl,
4682
15
    { "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
15
    { &hf_iec60870_5_103_asdu_typeid_mon,
4684
15
    { "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
15
    { &hf_iec60870_5_103_asdu205_ms,
4686
15
    { "Timestamp: Milliseconds", "iec60870_5_103.asdu205_ms", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4687
15
    { &hf_iec60870_5_103_asdu205_min,
4688
15
    { "Timestamp: Minutes", "iec60870_5_103.asdu205_min", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4689
15
    { &hf_iec60870_5_103_asdu205_h,
4690
15
    { "Timestamp: Hours", "iec60870_5_103.asdu205_h", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4691
15
    { &hf_iec60870_5_103_asdu205_value,
4692
15
    { "Counter Value", "iec60870_5_103.asdu205_value", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4693
15
    { &hf_iec60870_5_103_checksum,
4694
15
    { "Checksum", "iec60870_5_103.checksum", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
4695
15
    { &hf_iec60870_5_103_col,
4696
15
    { "Compatibility Level", "iec60870_5_103.col", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4697
15
    { &hf_iec60870_5_103_cot_ctrl,
4698
15
    { "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
15
    { &hf_iec60870_5_103_cot_mon,
4700
15
    { "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
15
    { &hf_iec60870_5_103_cp32time2a,
4702
15
    { "CP32Time2a", "iec60870_5_103.cp32time2a", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0, NULL, HFILL }},
4703
15
    { &hf_iec60870_5_103_cp32time2a_ms,
4704
15
    { "Milliseconds", "iec60870_5_103.cp32time2a_ms", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4705
15
    { &hf_iec60870_5_103_cp32time2a_min,
4706
15
    { "Minutes", "iec60870_5_103.cp32time2a_min", FT_UINT8, BASE_DEC, NULL, 0x3f, NULL, HFILL }},
4707
15
    { &hf_iec60870_5_103_cp32time2a_res1,
4708
15
    { "Res1", "iec60870_5_103.cp32time2a_res1", FT_UINT8, BASE_DEC, NULL, 0x40, NULL, HFILL }},
4709
15
    { &hf_iec60870_5_103_cp32time2a_iv,
4710
15
    { "Invalid", "iec60870_5_103.cp32time2a_iv", FT_UINT8, BASE_DEC, NULL, 0x80, NULL, HFILL }},
4711
15
    { &hf_iec60870_5_103_cp32time2a_hr,
4712
15
    { "Hours", "iec60870_5_103.cp32time2a_hr", FT_UINT8, BASE_DEC, NULL, 0x1f, NULL, HFILL }},
4713
15
    { &hf_iec60870_5_103_cp32time2a_res2,
4714
15
    { "Res2", "iec60870_5_103.cp32time2a_res2", FT_UINT8, BASE_DEC, NULL, 0x60, NULL, HFILL }},
4715
15
    { &hf_iec60870_5_103_cp32time2a_sum,
4716
15
    { "Summer Time", "iec60870_5_103.cp32time2a_sum", FT_UINT8, BASE_DEC, NULL, 0x80, NULL, HFILL }},
4717
15
    { &hf_iec60870_5_103_ctrlfield,
4718
15
    { "Control Field", "iec60870_5_103.ctrlfield", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
4719
15
    { &hf_iec60870_5_103_ctrl_prm,
4720
15
    { "PRM", "iec60870_5_103.ctrl_prm", FT_UINT8, BASE_DEC, VALS(iec60870_5_103_ctrl_prm_values), 0x40, "Primary Message", HFILL }},
4721
15
    { &hf_iec60870_5_103_ctrl_fcb,
4722
15
    { "FCB", "iec60870_5_103.ctrl_fcb", FT_UINT8, BASE_DEC, NULL, 0x20, "Frame Count Bit", HFILL }},
4723
15
    { &hf_iec60870_5_103_ctrl_fcv,
4724
15
    { "FCV", "iec60870_5_103.ctrl_fcv", FT_UINT8, BASE_DEC, NULL, 0x10, "Frame Count Bit Valid", HFILL }},
4725
15
    { &hf_iec60870_5_103_ctrl_dfc,
4726
15
    { "DFC", "iec60870_5_103.ctrl_dfc", FT_UINT8, BASE_DEC, NULL, 0x10, "Data Flow Control", HFILL }},
4727
15
    { &hf_iec60870_5_103_ctrl_func_pri_to_sec,
4728
15
    { "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
15
    { &hf_iec60870_5_103_ctrl_func_sec_to_pri,
4730
15
    { "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
15
    { &hf_iec60870_5_103_dco,
4732
15
    { "Double Command Type", "iec60870_5_103.dco", FT_UINT8, BASE_DEC, VALS(iec103_quadstate_types), 0x0, NULL, HFILL }},
4733
15
    { &hf_iec60870_5_103_dpi,
4734
15
    { "Double Point Information", "iec60870_5_103.dpi", FT_UINT8, BASE_DEC, VALS(iec103_quadstate_types), 0x0, NULL, HFILL }},
4735
15
    { &hf_iec60870_5_103_frame,
4736
15
    { "Frame Format", "iec60870_5_103.header", FT_UINT8, BASE_HEX, VALS(iec60870_5_103_frame_vals), 0x0, NULL, HFILL }},
4737
15
    { &hf_iec60870_5_103_func_type,
4738
15
    { "Function Type", "iec60870_5_103.func_type", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4739
15
    { &hf_iec60870_5_103_info_num,
4740
15
    { "Information Number", "iec60870_5_103.info_num", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4741
15
    { &hf_iec60870_5_103_length,
4742
15
    { "Length", "iec60870_5_103.length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4743
15
    { &hf_iec60870_5_103_linkaddr,
4744
15
    { "Data Link Address", "iec60870_5_103.linkaddr", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4745
15
    { &hf_iec60870_5_103_mfg,
4746
15
    { "Manufacturer Identity", "iec60870_5_103.mfg", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
4747
15
    { &hf_iec60870_5_103_mfg_sw,
4748
15
    { "Manufacturer's Software Identification", "iec60870_5_103.mfg_sw", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4749
15
    { &hf_iec60870_5_103_num_user_octets,
4750
15
    { "Number of User Octets", "iec60870_5_103.num_user_octets", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4751
15
    { &hf_iec60870_5_103_rii,
4752
15
    { "Return Information Identifier", "iec60870_5_103.rii", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4753
15
    { &hf_iec60870_5_103_scn,
4754
15
    { "Scan Number", "iec60870_5_103.scn", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4755
15
    { &hf_iec60870_5_103_sin,
4756
15
    { "Supplementary Information", "iec60870_5_103.sin", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
4757
15
    { &hf_iec60870_5_103_sq,
4758
15
    { "Structured Qualifier", "iec60870_5_103.sq", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
4759
15
    { &hf_iec60870_5_103_stopchar,
4760
15
    { "Stop Character", "iec60870_5_103.stopchar", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
4761
15
  };
4762
4763
  /* Setup protocol subtree array */
4764
15
  static int *ett_serial[] = {
4765
15
    &ett_iec60870_5_103,
4766
15
    &ett_iec60870_5_103_ctrlfield,
4767
15
    &ett_iec60870_5_103_cp32time2a,
4768
15
  };
4769
4770
  /* Register the protocol name and description */
4771
15
  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
15
  proto_register_field_array(proto_iec60870_5_103, iec60870_5_103_hf, array_length(iec60870_5_103_hf));
4775
15
  proto_register_subtree_array(ett_serial, array_length(ett_serial));
4776
4777
15
  iec60870_5_103_handle = register_dissector("iec60870_5_103", dissect_iec60870_5_103_tcp, proto_iec60870_5_103);
4778
15
}
4779
4780
void
4781
proto_reg_handoff_iec60870_5_103(void)
4782
15
{
4783
  /* Add decode-as connection to determine user-customized TCP port */
4784
15
  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
15
  dissector_add_for_decode_as("rtacser.data", iec60870_5_103_handle);
4787
15
}
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
 */