2 * Routines for cEMI (Common External Message Interface) dissection
3 * By Jan Kessler <kessler@ise.de>
4 * Copyright 2004, Jan Kessler <kessler@ise.de>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
15 #include <epan/packet.h>
17 #include "packet-knxip.h"
19 void proto_register_cemi(void);
20 void proto_reg_handoff_cemi(void);
24 #define CEMI_L_BUSMON_IND 0x2B
25 #define CEMI_L_RAW_IND 0x2D
26 #define CEMI_L_RAW_REQ 0x10
27 #define CEMI_L_RAW_CON 0x2F
28 #define CEMI_L_DATA_REQ 0x11
29 #define CEMI_L_DATA_CON 0x2E
30 #define CEMI_L_DATA_IND 0x29
31 #define CEMI_L_POLL_DATA_REQ 0x13
32 #define CEMI_L_POLL_DATA_CON 0x25
33 #define CEMI_T_DATA_INDIVIDUAL_REQ 0x4A
34 #define CEMI_T_DATA_INDIVIDUAL_IND 0x94
35 #define CEMI_T_DATA_CONNECTED_REQ 0x41
36 #define CEMI_T_DATA_CONNECTED_IND 0x89
37 #define CEMI_M_PROPREAD_REQ 0xFC
38 #define CEMI_M_PROPREAD_CON 0xFB
39 #define CEMI_M_PROPWRITE_REQ 0xF6
40 #define CEMI_M_PROPWRITE_CON 0xF5
41 #define CEMI_M_PROPINFO_IND 0xF7
42 #define CEMI_M_FUNCPROPCMD_REQ 0xF8
43 #define CEMI_M_FUNCPROPREAD_REQ 0xF9
44 #define CEMI_M_FUNCPROP_CON 0xFA
45 #define CEMI_M_RESET_REQ 0xF1
46 #define CEMI_M_RESET_IND 0xF0
48 /* Additional Information Types
51 #define CEMI_PL_MEDIUM_INFORMATION 0x01 /*!< (2 octets) Domain Address used by PL medium; Client <-> Server */
52 #define CEMI_RF_MEDIUM_INFORMATION 0x02 /*!< (7 octet) RF-Control byte and serial number/DoA;
53 Client <-> Server Busmonitor */
54 #define CEMI_STATUS_INFO 0x03 /*!< (1 octet) Busmonitor Error Flags; see clause 2.5.5.5; Client <- Server */
55 #define CEMI_TIMESTAMP_RELATIVE 0x04 /*!< (2 octets) Relative timestamp; e.g. for L_Raw.ind; Client <- Server */
56 #define CEMI_TIME_DELAY_UNTIL_SENDING 0x05 /*!< (4 octets) Time delay (L_Raw.req, see clause 2.5.5.3); Client <- Server */
57 /* 0x06-0xFE Not used. */
58 /* 0xFF For future system extension (ESC Code). */
62 #define CEMI_UNSPECIFIED_ERROR 0x00 /*!< Unknown error (R/W). */
63 #define CEMI_OUT_OF_RANGE 0x01 /*!< Write value not allowed (general, if not error 2 or 3) (W). */
64 #define CEMI_OUT_OF_MAXRANGE 0x02 /*!< Write value to high (W). */
65 #define CEMI_OUT_OF_MINRANGE 0x03 /*!< Write value to low (W). */
66 #define CEMI_MEMORY_ERROR 0x04 /*!< Memory can not be written or only with fault(s) (W). */
67 #define CEMI_READ_ONLY 0x05 /*!< Write access to a 'read only' or a write protected property (W). */
68 #define CEMI_ILLEGAL_COMMAND 0x06 /*!< COMMAND not valid or not supported (W). */
69 #define CEMI_VOID_DP 0x07 /*!< Read or write access to an non existing property (R/W). */
70 #define CEMI_TYPE_CONFLICT 0x08 /*!< Write access with a wrong data type (datapoint length) (W). */
71 #define CEMI_PROP_INDEX_RANGE_ERROR 0x09 /* Read or write access to a non existing property array index (R/W). */
73 /* Common EMI specific device server properties
75 #define CEMI_PID_DOMAIN_ADDRESS 0x70 /*!< Domain Address of a PL medium (cEMI server) device.
76 PDT_UNSIGNED_INT O - r/w */
77 #define CEMI_PID_IO_LIST 0x71 /*!< List of Interface Objects in the (cEMI server) device.
78 PDT_UNSIGNED_INT O - r/w */
80 #define CEMI_PID_MEDIUM_TYPE 0x51 /*!< Media Type(s) supported by cEMI server.
81 DPT_Media M - read only */
82 #define CEMI_PID_COMM_MODE 0x52 /*!< Link Layer / Raw (Busmonitor) / Transport L.
83 DPT_CommMode O - r/w */
84 #define CEMI_PID_MEDIUM_AVAILABILITY 0x53 /*!< Bus available (1) or not (0) ?
85 DPT_Media O - read only */
86 #define CEMI_PID_ADD_INFO_TYPES 0x54 /*!< cEMI supported Additional Information Types.
87 DPT_AddInfoTypes O - read only */
88 #define CEMI_PID_TRANSP_ENABLE 0x56 /*!< LL Transparency Mode of cEMI server.
90 /* 0x57 Reserved for cEMI client's subnetwork address.
91 PDT_UNSIGNED_CHAR O - r/w */
92 /* 0x58 Reserved for cEMI client's device address.
93 PDT_UNSIGNED_CHAR O - r/w */
96 /* 0x61 DoA Filter. t.b.d. O - read only */
98 #define CEMI_PID_MEDIUM_TYPE_TP0 0x0001 /*!< TP 0 */
99 #define CEMI_PID_MEDIUM_TYPE_TP1 0x0002 /*!< TP 1 */
100 #define CEMI_PID_MEDIUM_TYPE_PL110 0x0004 /*!< PL 110 */
101 #define CEMI_PID_MEDIUM_TYPE_PL132 0x0008 /*!< PL 132 */
102 #define CEMI_PID_MEDIUM_TYPE_RF 0x0010 /*!< RF */
104 #define CEMI_PID_COMM_MODE_LL 0x00 /*!< Link Layer = default comm. mode. */
105 #define CEMI_PID_COMM_MODE_LLB 0x01 /*!< Link Layer Busmonitor. */
106 #define CEMI_PID_COMM_MODE_LLR 0x02 /*!< Link Layer Raw Frames. */
107 /* 0x03 Reserved for Network Layer. */
108 /* 0x04 Reserved for TL group oriented. */
109 /* 0x05 Reserved for TL connection oriented. */
110 /* 0x05-0xFF Reserved for other 'destination layers'. */
112 /* - - - - - - - T R E E V I E W I D E N T I F I E R - - - - - - - -
115 /* Initialize the protocol identifier that is needed for the
116 protocol hook and to register the fields in the protocol tree
118 static int proto_cemi
;
120 /* Initialize the registered fields identifiers. These fields
121 will be registered with the protocol during initialization.
122 Protocol fields are like type definitions. The protocol dissector
123 later on adds items of these types to the protocol tree.
126 static int hf_folder
;
127 static int hf_cemi_mc
;
128 static int hf_cemi_error
;
129 static int hf_cemi_ai_length
;
130 static int hf_cemi_aie_type
;
131 static int hf_cemi_aie_length
;
132 static int hf_cemi_ot
;
133 static int hf_cemi_oi
;
134 static int hf_cemi_ox
;
135 static int hf_cemi_px
;
136 static int hf_cemi_pid
;
137 static int hf_cemi_ne
;
138 static int hf_cemi_sx
;
139 static int hf_cemi_ft
;
140 static int hf_cemi_rep
;
141 static int hf_cemi_bt
;
142 static int hf_cemi_prio
;
143 static int hf_cemi_ack
;
144 static int hf_cemi_ce
;
145 static int hf_cemi_at
;
146 static int hf_cemi_hc
;
147 static int hf_cemi_eff
;
148 static int hf_cemi_sa
;
149 static int hf_cemi_da
;
150 static int hf_cemi_len
;
151 static int hf_cemi_tpt
;
152 static int hf_cemi_tst
;
153 static int hf_cemi_num
;
154 static int hf_cemi_tc
;
155 static int hf_cemi_ac
;
156 static int hf_cemi_ad
;
157 static int hf_cemi_ad_memory_length
;
158 static int hf_cemi_ad_channel
;
159 static int hf_cemi_ad_type
;
160 static int hf_cemi_ax
;
161 static int hf_cemi_pw
;
162 static int hf_cemi_pdt
;
163 static int hf_cemi_me
;
164 static int hf_cemi_ra
;
165 static int hf_cemi_wa
;
166 static int hf_cemi_ext_oi
;
167 static int hf_cemi_ext_pid
;
168 static int hf_cemi_ext_ne
;
169 static int hf_cemi_ext_sx
;
170 static int hf_cemi_ext_dt
;
171 static int hf_cemi_ext_px
;
172 static int hf_cemi_ext_memory_length
;
173 static int hf_cemi_ext_memory_address
;
174 static int hf_cemi_memory_length
;
175 static int hf_cemi_memory_address
;
176 static int hf_cemi_memory_address_ext
;
177 static int hf_cemi_level
;
178 static int hf_cemi_snp_pid
;
179 static int hf_cemi_snp_reserved
;
180 static int hf_cemi_dpt_major
;
181 static int hf_cemi_dpt_minor
;
182 static int hf_cemi_scf
;
183 static int hf_cemi_scf_t
;
184 static int hf_cemi_scf_sai
;
185 static int hf_cemi_scf_sbc
;
186 static int hf_cemi_scf_svc
;
187 static int hf_cemi_adc_count
;
189 /* Initialize the subtree pointers. These pointers are needed to
190 display the protocol in a structured tree. Subtrees hook on
191 already defined fields or (the topmost) on the protocol itself
194 static int ett_cemi_ai
;
195 static int ett_cemi_aie
;
196 static int ett_cemi_ctrl1
;
197 static int ett_cemi_ctrl2
;
198 static int ett_cemi_tpci
;
199 static int ett_cemi_apci
;
200 static int ett_cemi_range
;
201 static int ett_cemi_pd
;
202 static int ett_cemi_dpt
;
203 static int ett_cemi_scf
;
204 static int ett_cemi_decrypted
;
206 /* - - - - - - - - - - - V A L U E T A B L E S - - - - - - - - - - - -
209 /* See following docs:
211 "AN033 v03 cEMI.pdf",
212 "AN057 v01 System B RfV.pdf",
213 "KSG259 2004.02.03 Identifiers.pdf",
214 "03_07_03 Standardized Identifier Tables.pdf"
219 static const value_string mc_vals
[] = {
220 { CEMI_L_BUSMON_IND
, "L_Busmon.ind" },
221 { CEMI_L_RAW_IND
, "L_Raw.ind" },
222 { CEMI_L_RAW_REQ
, "L_Raw.req" },
223 { CEMI_L_RAW_CON
, "L_Raw.con" },
224 { CEMI_L_DATA_REQ
, "L_Data.req" },
225 { CEMI_L_DATA_CON
, "L_Data.con" },
226 { CEMI_L_DATA_IND
, "L_Data.ind" },
227 { CEMI_L_POLL_DATA_REQ
, "L_PollData.req" },
228 { CEMI_L_POLL_DATA_CON
, "L_PollData.con" },
229 { CEMI_T_DATA_INDIVIDUAL_REQ
, "T_Data_Individual.req" },
230 { CEMI_T_DATA_INDIVIDUAL_IND
, "T_Data_Individual.ind" },
231 { CEMI_T_DATA_CONNECTED_REQ
, "T_Data_Connected.req" },
232 { CEMI_T_DATA_CONNECTED_IND
, "T_Data_Connected.ind" },
233 { CEMI_M_PROPREAD_REQ
, "M_PropRead.req" },
234 { CEMI_M_PROPREAD_CON
, "M_PropRead.con" },
235 { CEMI_M_PROPWRITE_REQ
, "M_PropWrite.req" },
236 { CEMI_M_PROPWRITE_CON
, "M_PropWrite.con" },
237 { CEMI_M_PROPINFO_IND
, "M_PropInfo.ind" },
238 { CEMI_M_FUNCPROPCMD_REQ
, "M_FuncPropCmd.req" },
239 { CEMI_M_FUNCPROPREAD_REQ
, "M_FuncPropRead.req" },
240 { CEMI_M_FUNCPROP_CON
, "M_FuncProp.con" },
241 { CEMI_M_RESET_REQ
, "M_Reset.req" },
242 { CEMI_M_RESET_IND
, "M_Reset.ind" },
246 /* Property access flags
248 #define PA_RESPONSE 0x01
251 /* Additional Info Element Type
253 static const value_string aiet_vals
[] = {
254 { 1, "PL Medium Info" },
255 { 2, "RF Medium Info" },
256 { 3, "BusMonitor Status Info" },
257 { 4, "Timestamp Relative" },
258 { 5, "Time Delay Until Sending" },
259 { 6, "Extended Relative Timestamp" },
266 static const value_string ft_vals
[] = {
274 static const value_string bt_vals
[] = {
282 static const value_string prio_vals
[] = {
292 static const value_string at_vals
[] = {
300 static const value_string pt_vals
[] = {
308 static const value_string st_vals
[] = {
314 /* Transport Layer Code
316 static const value_string tc_vals
[] = {
324 /* Application Layer Code
326 #define AC_GroupValueRead 0
327 #define AC_GroupValueResp 1
328 #define AC_GroupValueWrite 2
329 #define AC_IndAddrWrite 3
330 #define AC_IndAddrRead 4
331 #define AC_IndAddrResp 5
336 #define AC_MemWrite 10
337 #define AC_UserMsg 11
338 #define AC_DevDescrRead 12
339 #define AC_DevDescrResp 13
340 #define AC_Restart 14
343 static const value_string ac_vals
[] =
345 { AC_GroupValueRead
, "GroupValueRead" },
346 { AC_GroupValueResp
, "GroupValueResp" },
347 { AC_GroupValueWrite
, "GroupValueWrite" },
348 { AC_IndAddrWrite
, "IndAddrWrite" },
349 { AC_IndAddrRead
, "IndAddrRead" },
350 { AC_IndAddrResp
, "IndAddrResp" },
351 { AC_AdcRead
, "AdcRead" },
352 { AC_AdcResp
, "AdcResp" },
353 { AC_MemRead
, "MemRead" },
354 { AC_MemResp
, "MemResp" },
355 { AC_MemWrite
, "MemWrite" },
356 { AC_UserMsg
, "UserMsg" },
357 { AC_DevDescrRead
, "DevDescrRead" },
358 { AC_DevDescrResp
, "DevDescrResp" },
359 { AC_Restart
, "Restart" },
360 { AC_Escape
, "Escape" },
366 #define AX_SysNwkParamRead 0x1C8
367 #define AX_SysNwkParamResp 0x1C9
368 #define AX_SysNwkParamWrite 0x1CA
369 #define AX_PropExtValueRead 0x1CC
370 #define AX_PropExtValueResp 0x1CD
371 #define AX_PropExtValueWriteCon 0x1CE
372 #define AX_PropExtValueWriteConRes 0x1CF
373 #define AX_PropExtValueWriteUnCon 0x1D0
374 #define AX_PropExtValueInfoReport 0x1D1
375 #define AX_PropExtDescrRead 0x1D2
376 #define AX_PropExtDescrResp 0x1D3
377 #define AX_FuncPropExtCmd 0x1D4
378 #define AX_FuncPropExtRead 0x1D5
379 #define AX_FuncPropExtResp 0x1D6
380 #define AX_MemExtWrite 0x1FB
381 #define AX_MemExtWriteResp 0x1FC
382 #define AX_MemExtRead 0x1FD
383 #define AX_MemExtReadResp 0x1FE
384 #define AX_UserMemRead 0x2C0
385 #define AX_UserMemResp 0x2C1
386 #define AX_UserMemWrite 0x2C2
387 #define AX_UserMemBitWrite 0x2C4
388 #define AX_UserMfrInfoRead 0x2C5
389 #define AX_UserMfrInfoResp 0x2C6
390 #define AX_FuncPropCmd 0x2C7
391 #define AX_FuncPropRead 0x2C8
392 #define AX_FuncPropResp 0x2C9
393 #define AX_Restart 0x380
394 #define AX_RestartReq 0x381
395 #define AX_RestartResp 0x3A1
396 #define AX_RoutingTableOpen 0x3C0
397 #define AX_RoutingTableRead 0x3C1
398 #define AX_RoutingTableResp 0x3C2
399 #define AX_RoutingTableWrite 0x3C3
400 #define AX_RouterMemRead 0x3C8
401 #define AX_RouterMemResp 0x3C9
402 #define AX_RouterMemWrite 0x3CA
403 #define AX_RouterStatusRead 0x3CD
404 #define AX_RouterStatusResp 0x3CE
405 #define AX_RouterStatusWrite 0x3CF
406 #define AX_MemBitWrite 0x3D0
407 #define AX_AuthReq 0x3D1
408 #define AX_AuthResp 0x3D2
409 #define AX_KeyWrite 0x3D3
410 #define AX_KeyResp 0x3D4
411 #define AX_PropValueRead 0x3D5
412 #define AX_PropValueResp 0x3D6
413 #define AX_PropValueWrite 0x3D7
414 #define AX_PropDescrRead 0x3D8
415 #define AX_PropDescrResp 0x3D9
416 #define AX_NwkParamRead 0x3DA
417 #define AX_NwkParamResp 0x3DB
418 #define AX_IndAddrSerNumRead 0x3DC
419 #define AX_IndAddrSerNumResp 0x3DD
420 #define AX_IndAddrSerNumWrite 0x3DE
421 #define AX_DomAddrWrite 0x3E0
422 #define AX_DomAddrRead 0x3E1
423 #define AX_DomAddrResp 0x3E2
424 #define AX_DomAddrSelRead 0x3E3
425 #define AX_NwkParamWrite 0x3E4
426 #define AX_LinkRead 0x3E5
427 #define AX_LinkResp 0x3E6
428 #define AX_LinkWrite 0x3E7
429 #define AX_GroupPropValueRead 0x3E8
430 #define AX_GroupPropValueResp 0x3E9
431 #define AX_GroupPropValueWrite 0x3EA
432 #define AX_GroupPropValueInfo 0x3EB
433 #define AX_DomAddrSerNumRead 0x3EC
434 #define AX_DomAddrSerNumResp 0x3ED
435 #define AX_DomAddrSerNumWrite 0x3EE
436 #define AX_FileStreamInfo 0x3F0
437 #define AX_DataSec 0x3F1
439 static const value_string ax_vals
[] =
441 { AX_SysNwkParamRead
, "SysNwkParamRead" },
442 { AX_SysNwkParamResp
, "SysNwkParamResp" },
443 { AX_SysNwkParamWrite
, "SysNwkParamWrite" },
444 { AX_PropExtValueRead
, "PropExtValueRead" },
445 { AX_PropExtValueResp
, "PropExtValueResp" },
446 { AX_PropExtValueWriteCon
, "PropExtValueWriteCon" },
447 { AX_PropExtValueWriteConRes
, "PropExtValueWriteConRes" },
448 { AX_PropExtValueWriteUnCon
, "PropExtValueWriteUnCon" },
449 { AX_PropExtDescrRead
, "PropExtDescrRead" },
450 { AX_PropExtDescrResp
, "PropExtDescrResp" },
451 { AX_FuncPropExtCmd
, "FuncPropExtCmd" },
452 { AX_FuncPropExtRead
, "FuncPropExtRead" },
453 { AX_FuncPropExtResp
, "FuncPropExtResp" },
454 { AX_MemExtWrite
, "MemExtWrite" },
455 { AX_MemExtWriteResp
, "MemExtWriteResp" },
456 { AX_MemExtRead
, "MemExtRead" },
457 { AX_MemExtReadResp
, "MemExtReadResp" },
458 { AX_UserMemRead
, "UserMemRead" },
459 { AX_UserMemResp
, "UserMemResp" },
460 { AX_UserMemWrite
, "UserMemWrite" },
461 { AX_UserMemBitWrite
, "UserMemBitWrite" },
462 { AX_UserMfrInfoRead
, "UserMfrInfoRead" },
463 { AX_UserMfrInfoResp
, "UserMfrInfoResp" },
464 { AX_FuncPropCmd
, "FuncPropCmd" },
465 { AX_FuncPropRead
, "FuncPropRead" },
466 { AX_FuncPropResp
, "FuncPropResp" },
467 { AX_Restart
, "Restart" },
468 { AX_RestartReq
, "RestartReq" },
469 { AX_RestartResp
, "RestartResp" },
470 { AX_RoutingTableOpen
, "RoutingTableOpen" },
471 { AX_RoutingTableRead
, "RoutingTableRead" },
472 { AX_RoutingTableResp
, "RoutingTableResp" },
473 { AX_RoutingTableWrite
, "RoutingTableWrite" },
474 { AX_RouterMemRead
, "RouterMemRead" },
475 { AX_RouterMemResp
, "RouterMemResp" },
476 { AX_RouterMemWrite
, "RouterMemWrite" },
477 { AX_RouterStatusRead
, "RouterStatusRead" },
478 { AX_RouterStatusResp
, "RouterStatusResp" },
479 { AX_RouterStatusWrite
, "RouterStatusWrite" },
480 { AX_MemBitWrite
, "MemBitWrite" },
481 { AX_AuthReq
, "AuthReq" },
482 { AX_AuthResp
, "AuthResp" },
483 { AX_KeyWrite
, "KeyWrite" },
484 { AX_KeyResp
, "KeyResp" },
485 { AX_PropValueRead
, "PropValueRead" },
486 { AX_PropValueResp
, "PropValueResp" },
487 { AX_PropValueWrite
, "PropValueWrite" },
488 { AX_PropDescrRead
, "PropDescrRead" },
489 { AX_PropDescrResp
, "PropDescrResp" },
490 { AX_NwkParamRead
, "NwkParamRead" },
491 { AX_NwkParamResp
, "NwkParamResp" },
492 { AX_IndAddrSerNumRead
, "IndAddrSerNumRead" },
493 { AX_IndAddrSerNumResp
, "IndAddrSerNumResp" },
494 { AX_IndAddrSerNumWrite
, "IndAddrSerNumWrite" },
495 { AX_DomAddrWrite
, "DomAddrWrite" },
496 { AX_DomAddrRead
, "DomAddrRead" },
497 { AX_DomAddrResp
, "DomAddrResp" },
498 { AX_DomAddrSelRead
, "DomAddrSelRead" },
499 { AX_NwkParamWrite
, "NwkParamWrite" },
500 { AX_LinkRead
, "LinkRead" },
501 { AX_LinkResp
, "LinkResp" },
502 { AX_LinkWrite
, "LinkWrite" },
503 { AX_GroupPropValueRead
, "GroupPropValueRead" },
504 { AX_GroupPropValueResp
, "GroupPropValueResp" },
505 { AX_GroupPropValueWrite
, "GroupPropValueWrite" },
506 { AX_GroupPropValueInfo
, "GroupPropValueInfo" },
507 { AX_DomAddrSerNumRead
, "DomAddrSerNumRead" },
508 { AX_DomAddrSerNumResp
, "DomAddrSerNumResp" },
509 { AX_DomAddrSerNumWrite
, "DomAddrSerNumWrite" },
510 { AX_FileStreamInfo
, "FileStreamInfo" },
511 { AX_DataSec
, "DataSec" },
515 /* SCF (Security Control Field)
517 static const value_string scf_vals
[] =
519 { 0x00, "CCM S-A_Data with Authentication-only" },
520 { 0x10, "CCM S-A_Data with Authentication+Confidentiality" },
521 { 0x12, "CCM S-A_Sync_Req with Authentication+Confidentiality" },
522 { 0x13, "CCM S-A_Sync_Res with Authentication+Confidentiality" },
523 { 0x08, "CCM S-A_Data with Authentication-only, System Broadcast" },
524 { 0x18, "CCM S-A_Data with Authentication+Confidentiality, System Broadcast" },
525 { 0x1a, "CCM S-A_Sync_Req with Authentication+Confidentiality, System Broadcast" },
526 { 0x1b, "CCM S-A_Sync_Res with Authentication+Confidentiality, System Broadcast" },
527 { 0x80, "CCM S-A_Data with Authentication-only, Tool Access" },
528 { 0x90, "CCM S-A_Data with Authentication+Confidentiality, Tool Access" },
529 { 0x92, "CCM S-A_Sync_Req with Authentication+Confidentiality, Tool Access" },
530 { 0x93, "CCM S-A_Sync_Res with Authentication+Confidentiality, Tool Access" },
531 { 0x88, "CCM S-A_Data with Authentication-only, System Broadcast, Tool Access" },
532 { 0x98, "CCM S-A_Data with Authentication+Confidentiality, Tool Access, System Broadcast" },
533 { 0x9a, "CCM S-A_Sync_Req with Authentication+Confidentiality, Tool Access, System Broadcast" },
534 { 0x9b, "CCM S-A_Sync_Res with Authentication+Confidentiality, Tool Access, System Broadcast" },
538 /* SCF (Security Control Field).
540 static const value_string scf_short_vals
[] =
543 { 0x10, "Data+A+C" },
546 { 0x08, "Data+A+SBC" },
547 { 0x18, "Data+A+C+SBC" },
548 { 0x1a, "SyncReq+SBC" },
549 { 0x1b, "SyncRes+SBC" },
550 { 0x80, "Data+A+T" },
551 { 0x90, "Data+A+C+T" },
552 { 0x92, "SyncReq+T" },
553 { 0x93, "SyncRes+T" },
554 { 0x88, "Data+A+T+SBC" },
555 { 0x98, "Data+A+C+T+SBC" },
556 { 0x9a, "SyncReq+T+SBC" },
557 { 0x9b, "SyncRes+T+SBC" },
561 /* SCF.SAI (Security Algorithm Identifier)
563 static const value_string scf_sai_vals
[] =
572 static const value_string scf_svc_vals
[] =
580 /* See KNX documents:
581 * "03_07_03 Standardized Identifier Tables v01.03.01 AS"
582 * "03_05_01 Resources v01.09.03 AS"
585 /* Property Data Types
586 * See "4 Property Datatypes Identifiers" in "03_07_03 Standardized Identifier Tables v01.03.01 AS"
588 static const value_string pdt_vals
[] = {
589 { 0x00, "PDT_CONTROL" },
590 { 0x01, "PDT_CHAR" },
591 { 0x02, "PDT_UNSIGNED_CHAR" },
593 { 0x04, "PDT_UNSIGNED_INT" },
594 { 0x05, "PDT_KNX_FLOAT" },
595 { 0x06, "PDT_DATE" },
596 { 0x07, "PDT_TIME" },
597 { 0x08, "PDT_LONG" },
598 { 0x09, "PDT_UNSIGNED_LONG" },
599 { 0x0A, "PDT_FLOAT" },
600 { 0x0B, "PDT_DOUBLE" },
601 { 0x0C, "PDT_CHAR_BLOCK" },
602 { 0x0D, "PDT_POLL_GROUP_SETTINGS" },
603 { 0x0E, "PDT_SHORT_CHAR_BLOCK" },
604 { 0x0F, "PDT_DATE_TIME" },
605 { 0x10, "PDT_VARIABLE_LENGTH" },
606 { 0x11, "PDT_GENERIC_01" },
607 { 0x12, "PDT_GENERIC_02" },
608 { 0x13, "PDT_GENERIC_03" },
609 { 0x14, "PDT_GENERIC_04" },
610 { 0x15, "PDT_GENERIC_05" },
611 { 0x16, "PDT_GENERIC_06" },
612 { 0x17, "PDT_GENERIC_07" },
613 { 0x18, "PDT_GENERIC_08" },
614 { 0x19, "PDT_GENERIC_09" },
615 { 0x1A, "PDT_GENERIC_10" },
616 { 0x1B, "PDT_GENERIC_11" },
617 { 0x1C, "PDT_GENERIC_12" },
618 { 0x1D, "PDT_GENERIC_13" },
619 { 0x1E, "PDT_GENERIC_14" },
620 { 0x1F, "PDT_GENERIC_15" },
621 { 0x20, "PDT_GENERIC_16" },
622 { 0x21, "PDT_GENERIC_17" },
623 { 0x22, "PDT_GENERIC_18" },
624 { 0x23, "PDT_GENERIC_19" },
625 { 0x24, "PDT_GENERIC_20" },
626 { 0x2F, "PDT_UTF-8" },
627 { 0x30, "PDT_VERSION" },
628 { 0x31, "PDT_ALARM_INFO" },
629 { 0x32, "PDT_BINARY_INFORMATION" },
630 { 0x33, "PDT_BITSET8" },
631 { 0x34, "PDT_BITSET16" },
632 { 0x35, "PDT_ENUM8" },
633 { 0x36, "PDT_SCALING" },
634 { 0x3C, "PDT_NE_VL" },
635 { 0x3D, "PDT_NE_FL" },
636 { 0x3E, "PDT_FUNCTION" },
637 { 0x3F, "PDT_ESCAPE" },
641 /* Interface Object Types
642 * See "2 Interface Object Types" in "03_07_03 Standardized Identifier Tables v01.03.01 AS"
644 static const value_string ot_vals
[] = {
646 { 1, "Address Table" },
647 { 2, "Association Table" },
648 { 3, "Application Program" },
649 { 4, "Interface Program" },
650 { 5, "KNX-Object Association Table" },
652 { 7, "LTE Address Routing Table" },
653 { 8, "cEMI Server" },
654 { 9, "Group Object Table" },
655 { 10, "Polling Master" },
656 { 11, "KNXnet/IP Parameter" },
657 { 13, "File Server" },
658 { 17, "Data Security" },
662 /* IOT independent PIDs
663 * See "3.2 Interface Object Type independent standard Properties" in "03_07_03 Standardized Identifier Tables v01.03.01 AS"
664 * See "4.2 Interface Object Type independent Properties" in "03_05_01 Resources v01.09.03 AS"
666 static const value_string pid_vals
[] = {
667 { 1, "PID_OBJECT_TYPE" },
668 { 2, "PID_OBJECT_NAME" },
669 { 3, "PID_SEMAPHOR" },
670 { 4, "PID_GROUP_OBJECT_REFERENCE" },
671 { 5, "PID_LOAD_STATE_CONTROL" },
672 { 6, "PID_RUN_STATE_CONTROL" },
673 { 7, "PID_TABLE_REFERENCE" },
674 { 8, "PID_SERVICE_CONTROL" },
675 { 9, "PID_FIRMWARE_REVISION" },
676 { 10, "PID_SERVICES_SUPPORTED" },
677 { 11, "PID_SERIAL_NUMBER" },
678 { 12, "PID_MANUFACTURER_ID" },
679 { 13, "PID_PROGRAM_VERSION" },
680 { 14, "PID_DEVICE_CONTROL" },
681 { 15, "PID_ORDER_INFO" },
682 { 16, "PID_PEI_TYPE" },
683 { 17, "PID_PORT_CONFIGURATION" },
684 { 18, "PID_POLL_GROUP_SETTINGS" },
685 { 19, "PID_MANUFACTURER_DATA" },
686 { 21, "PID_DESCRIPTION" },
689 { 25, "PID_VERSION" },
690 { 26, "PID_GROUP_OBJECT_LINK" },
691 { 27, "PID_MCB_TABLE" },
692 { 28, "PID_ERROR_CODE" },
693 { 29, "PID_OBJECT_INDEX" },
694 { 30, "PID_DOWNLOAD_COUNTER" },
698 /* PIDs for IOT = 0 (Device)
699 * See "3.3.1 Device Object Interface Object (Object Type = 0)" in "03_07_03 Standardized Identifier Tables v01.03.01 AS"
700 * See "4.3 Device Object (Object Type 0)" in "03_05_01 Resources v01.09.03 AS"
702 static const value_string pid0_vals
[] = {
703 { 51, "PID_ROUTING_COUNT" },
704 { 52, "PID_MAX_RETRY_COUNT" },
705 { 53, "PID_ERROR_FLAGS" },
706 { 54, "PID_PROGMODE" },
707 { 55, "PID_PRODUCT_ID" },
708 { 56, "PID_MAX_APDULENGTH" },
709 { 57, "PID_SUBNET_ADDR" },
710 { 58, "PID_DEVICE_ADDR" },
711 { 59, "PID_PB_CONFIG" },
712 { 60, "PID_ADDR_REPORT" },
713 { 61, "PID_ADDR_CHECK" },
714 { 62, "PID_OBJECT_VALUE" },
715 { 63, "PID_OBJECTLINK" },
716 { 64, "PID_APPLICATION" },
717 { 65, "PID_PARAMETER" },
718 { 66, "PID_OBJECTADDRESS" },
719 { 67, "PID_PSU_TYPE" },
720 { 68, "PID_PSU_STATUS" },
721 { 69, "PID_PSU_ENABLE" },
722 { 70, "PID_DOMAIN_ADDRESS" },
723 { 71, "PID_IO_LIST" },
724 { 72, "PID_MGT_DESCRIPTOR_01" },
725 { 73, "PID_PL110_PARAM" },
726 { 74, "PID_RF_REPEAT_COUNTER" },
727 { 75, "PID_RECEIVE_BLOCK_TABLE" },
728 { 76, "PID_RANDOM_PAUSE_TABLE" },
729 { 77, "PID_RECEIVE_BLOCK_NR" },
730 { 78, "PID_HARDWARE_TYPE" },
731 { 79, "PID_RETRANSMITTER_NUMBER" },
732 { 80, "PID_SERIAL_NR_TABLE" },
733 { 81, "PID_BIBATMASTER_ADDRESS" },
734 { 82, "PID_RF_DOMAIN_ADDRESS" },
735 { 83, "PID_DEVICE_DESCRIPTOR" },
736 { 84, "PID_METERING_FILTER_TABLE" },
737 { 85, "PID_GROUP_TELEGR_RATE_LIMIT_TIME_BASE" },
738 { 86, "PID_GROUP_TELEGR_RATE_LIMIT_NO_OF_TELEGR" },
742 /* PIDs for IOT = 1 (Address Table)
743 * See "4.10.6 Group Address Table - Realisation Type 6" in "03_05_01 Resources v01.09.03 AS"
744 * See "4.10.7 Group Address Table - Realisation Type 7" in "03_05_01 Resources v01.09.03 AS"
746 static const value_string pid1_vals
[] = {
747 { 51, "PID_EXT_FRAMEFORMAT" },
748 { 52, "PID_ADDRTAB1" },
749 { 53, "PID_GROUP_RESPONSER_TABLE" },
753 /* PIDs for IOT = 6 (Router)
754 * See "4.4 Router Object (Object Type 6)" in "03_05_01 Resources v01.09.03 AS"
755 * See "2.4.4 Router Object" in "AN161 v05 Coupler Model 2.0 AS"
757 static const value_string pid6_vals
[] = {
758 { 51, "PID_MEDIUM_STATUS" }, /* alias "PID_LINE_STATUS" */
759 { 52, "PID_MAIN_LCCONFIG" },
760 { 53, "PID_SUB_LCCONFIG" },
761 { 54, "PID_MAIN_LCGRPCONFIG" },
762 { 55, "PID_SUB_LCGRPCONFIG" },
763 { 56, "PID_ROUTETABLE_CONTROL" },
764 { 57, "PID_COUPL_SERV_CONTROL" },
765 { 58, "PID_MAX_APDU_LENGTH" },
766 { 59, "PID_L2_COUPLER_TYPE" },
767 { 61, "PID_HOP_COUNT" },
768 { 63, "PID_MEDIUM" },
769 { 67, "PID_FILTER_TABLE_USE" },
770 { 104, "PID_PL110_SBC_CONTROL" },
771 { 105, "PID_PL110_DOA" },
772 { 112, "PID_RF_SBC_CONTROL" },
776 /* PIDs for IOT = 7 (LTE Address Routing Table)
777 * See "4.5 LTE Address Routing Table Object (Object Type 7)" in "03_05_01 Resources v01.09.03 AS"
779 static const value_string pid7_vals
[] = {
780 { 51, "PID_LTE_ROUTESELECT" },
781 { 52, "PID_LTE_ROUTETABLE" },
785 /* PIDs for IOT = 8 (cEMI Server)
786 * See "4.6 cEMI Server Object (Object Type 8)" in "03_05_01 Resources v01.09.03 AS"
788 static const value_string pid8_vals
[] = {
789 { 51, "PID_MEDIUM_TYPE" },
790 { 52, "PID_COMM_MODE" },
791 { 53, "PID_MEDIUM_AVAILABILITY" },
792 { 54, "PID_ADD_INFO_TYPES" },
793 { 55, "PID_TIME_BASE" },
794 { 56, "PID_TRANSP_ENABLE" },
795 { 59, "PID_BIBAT_NEXTBLOCK" },
796 { 60, "PID_RF_MODE_SELECT" },
797 { 61, "PID_RF_MODE_SUPPORT" },
798 { 62, "PID_RF_FILTERING_MODE_SELECT" },
799 { 63, "PID_RF_FILTERING_MODE_SUPPORT" },
803 /* PIDs for IOT = 9 (Group Object Table)
804 * See "4.12.4 Group Object Table - Realisation Type 6" in "03_05_01 Resources v01.09.03 AS"
806 static const value_string pid9_vals
[] = {
807 { 51, "PID_GRPOBJTABLE" },
808 { 52, "PID_EXT_GRPOBJREFERENCE" },
812 /* PIDs for IOT = 11 (KNXnet/IP Parameter),
813 * See "2.5 KNXnet/IP Parameter Object" in "03_08_03 Management v01.06.02 AS"
814 * See "2.3.1 KNXnet/IP Parameter Object" in "AN159 v06 KNXnet-IP Secure AS"
816 static const value_string pid11_vals
[] = {
817 { 51, "PID_PROJECT_INSTALLATION_ID" },
818 { 52, "PID_KNX_INDIVIDUAL_ADDRESS" },
819 { 53, "PID_ADDITIONAL_INDIVIDUAL_ADDRESSES" },
820 { 54, "PID_CURRENT_IP_ASSIGNMENT_METHOD" },
821 { 55, "PID_IP_ASSIGNMENT_METHOD" },
822 { 56, "PID_IP_CAPABILITIES" },
823 { 57, "PID_CURRENT_IP_ADDRESS" },
824 { 58, "PID_CURRENT_SUBNET_MASK" },
825 { 59, "PID_CURRENT_DEFAULT_GATEWAY" },
826 { 60, "PID_IP_ADDRESS" },
827 { 61, "PID_SUBNET_MASK" },
828 { 62, "PID_DEFAULT_GATEWAY" },
829 { 63, "PID_DHCP_BOOTP_SERVER" },
830 { 64, "PID_MAC_ADDRESS" },
831 { 65, "PID_SYSTEM_SETUP_MULTICAST_ADDRESS" },
832 { 66, "PID_ROUTING_MULTICAST_ADDRESS" },
834 { 68, "PID_KNXNETIP_DEVICE_CAPABILITIES" },
835 { 69, "PID_KNXNETIP_DEVICE_STATE" },
836 { 70, "PID_KNXNETIP_ROUTING_CAPABILITIES" },
837 { 71, "PID_PRIORITY_FIFO_ENABLED" },
838 { 72, "PID_QUEUE_OVERFLOW_TO_IP" },
839 { 73, "PID_QUEUE_OVERFLOW_TO_KNX" },
840 { 74, "PID_MSG_TRANSMIT_TO_IP" },
841 { 75, "PID_MSG_TRANSMIT_TO_KNX" },
842 { 76, "PID_FRIENDLY_NAME" },
843 { 78, "PID_ROUTING_BUSY_WAIT_TIME" },
844 { 91, "PID_BACKBONE_KEY" },
845 { 92, "PID_DEVICE_AUTHENTICATION_CODE" },
846 { 93, "PID_PASSWORD_HASHES" },
847 { 94, "PID_SECURED_SERVICE_FAMILIES" },
848 { 95, "PID_MULTICAST_LATENCY_TOLERANCE" },
849 { 96, "PID_SYNC_LATENCY_FRACTION" },
850 { 97, "PID_TUNNELLING_USERS" },
854 /* PIDs for IOT = 17 (Security)
855 * See "2.3.5 Security Interface Object" in "KSG638-26.03 KNX Data Security"
857 static const value_string pid17_vals
[] = {
858 { 51, "PID_SECURITY_MODE" },
859 { 52, "PID_P2P_KEY_TABLE" },
860 { 53, "PID_GRP_KEY_TABLE" },
861 { 54, "PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE" },
862 { 55, "PID_SECURITY_FAILURES_LOG" },
863 { 56, "PID_TOOL_KEY" },
864 { 57, "PID_SECURITY_REPORT" },
865 { 58, "PID_SECURITY_REPORT_CONTROL" },
866 { 59, "PID_SEQUENCE_NUMBER_SENDING" },
867 { 60, "PID_ZONE_KEY_TABLE" },
868 { 61, "PID_GO_SECURITY_FLAGS" },
869 { 62, "PID_ROLE_TABLE" },
873 /* - - - - - - - - - H E L P E R F U N C T I O N S - - - - - - - - - -
876 /* Add raw data to list view, tree view, and parent folder
878 static proto_item
* proto_tree_add_data( proto_tree
* tree
, tvbuff_t
* tvb
, int offset
, int length
, column_info
* cinfo
, proto_item
* item
,
879 const char* name
, const char* text1
, const char* text2
)
881 proto_item
* new_item
= proto_tree_add_bytes_format( tree
, hf_bytes
, tvb
, offset
, length
, NULL
, "%s: $", name
);
882 if( text1
) col_append_str( cinfo
, COL_INFO
, text1
);
883 if( text2
) proto_item_append_text( item
, "%s", text2
);
887 uint8_t value
= tvb_get_uint8( tvb
, offset
);
888 if( text1
) col_append_fstr( cinfo
, COL_INFO
, "%02X", value
);
889 if( text2
) proto_item_append_text( item
, "%02X", value
);
890 proto_item_append_text( new_item
, " %02X", value
);
898 static const char* get_pid_name( int ot
, int pid
)
902 return try_val_to_str( pid
, pid_vals
);
905 const value_string
* vals
= NULL
;
935 return try_val_to_str( pid
, vals
);
941 /* Decrypt data security APDU with a specific key.
943 static const uint8_t* decrypt_data_security_data_with_key( wmem_allocator_t
*pool
, const uint8_t* key
, const uint8_t* encrypted
, int encrypted_size
, const uint8_t* cemi
, int cemi_size
)
945 uint8_t ctr_0
[ KNX_KEY_LENGTH
];
946 uint8_t b_0
[ KNX_KEY_LENGTH
];
947 uint8_t mac
[ KNX_KEY_LENGTH
];
948 uint8_t* a_bytes
= 0;
949 const uint8_t* p_bytes
= NULL
;
953 uint8_t* decrypted
= NULL
;
955 if( encrypted_size
> 4 ) // contains 4 bytes MAC
959 int additionalInfoLength
= cemi
[ 1 ];
960 int offsetToData
= additionalInfoLength
+ 11;
961 if( offsetToData
+ 6 <= cemi_size
)
963 /* 1 byte Security Control Field */
964 uint8_t scf
= cemi
[ offsetToData
];
967 if( (scf
& 0x30) == 0x10 ) // A+C
970 p_length
= encrypted_size
- 4;
974 b_0
[ 0 ] = cemi
[ offsetToData
+ 1 ]; // SeqNr
975 b_0
[ 1 ] = cemi
[ offsetToData
+ 2 ];
976 b_0
[ 2 ] = cemi
[ offsetToData
+ 3 ];
977 b_0
[ 3 ] = cemi
[ offsetToData
+ 4 ];
978 b_0
[ 4 ] = cemi
[ offsetToData
+ 5 ];
979 b_0
[ 5 ] = cemi
[ offsetToData
+ 6 ];
980 b_0
[ 6 ] = cemi
[ additionalInfoLength
+ 4 ]; // SA
981 b_0
[ 7 ] = cemi
[ additionalInfoLength
+ 5 ];
982 b_0
[ 8 ] = cemi
[ additionalInfoLength
+ 6 ]; // DA
983 b_0
[ 9 ] = cemi
[ additionalInfoLength
+ 7 ];
984 b_0
[ 10 ] = 0; // cemi[additionalInfoLength + 2] & 0x80; // FT
985 b_0
[ 11 ] = cemi
[ additionalInfoLength
+ 3 ] & 0x8F; // AT (AT+EFF)
986 b_0
[ 12 ] = cemi
[ additionalInfoLength
+ 9 ]; // TPCI + ApciSec
987 b_0
[ 13 ] = cemi
[ additionalInfoLength
+ 10 ];
989 b_0
[ 15 ] = (uint8_t) p_length
;
992 ctr_0
[ 0 ] = cemi
[ offsetToData
+ 1 ]; // SeqNr
993 ctr_0
[ 1 ] = cemi
[ offsetToData
+ 2 ];
994 ctr_0
[ 2 ] = cemi
[ offsetToData
+ 3 ];
995 ctr_0
[ 3 ] = cemi
[ offsetToData
+ 4 ];
996 ctr_0
[ 4 ] = cemi
[ offsetToData
+ 5 ];
997 ctr_0
[ 5 ] = cemi
[ offsetToData
+ 6 ];
998 ctr_0
[ 6 ] = cemi
[ additionalInfoLength
+ 4 ]; // SA
999 ctr_0
[ 7 ] = cemi
[ additionalInfoLength
+ 5 ];
1000 ctr_0
[ 8 ] = cemi
[ additionalInfoLength
+ 6 ]; // DA
1001 ctr_0
[ 9 ] = cemi
[ additionalInfoLength
+ 7 ];
1009 decrypted
= knx_ccm_encrypt( 0, key
, p_bytes
, p_length
, encrypted
+ encrypted_size
- 4, 4, ctr_0
, 4 );
1011 a_bytes
= (uint8_t*) wmem_alloc( pool
, encrypted_size
);
1012 if( (scf
& 0x30) == 0x10 ) // A+C
1016 p_bytes
= decrypted
;
1017 p_length
= encrypted_size
- 4;
1019 else if( (scf
& 0x30) == 0x00 ) // A
1022 memcpy( a_bytes
+ 1, decrypted
, encrypted_size
- 4 );
1023 a_length
= encrypted_size
- 3;
1026 knx_ccm_calc_cbc_mac( mac
, key
, a_bytes
, a_length
, p_bytes
, p_length
, b_0
);
1027 wmem_free( pool
, a_bytes
);
1029 if( memcmp( mac
, decrypted
+ p_length
, 4 ) != 0 )
1031 // Wrong mac. Return 0.
1032 wmem_free( pool
, decrypted
);
1042 /* Context info for decrypt_data_security_data
1044 struct data_security_info
1046 uint16_t source
; // KNX source address
1047 uint16_t dest
; // KNX source address
1048 uint8_t multicast
; // KNX multicast (group addressed)?
1049 uint64_t seq_nr
; // 6-byte data security sequence number
1050 char output_text
[ 128 ]; // buffer for diagnostic output text
1053 /* Decrypt data security APDU.
1055 static const uint8_t* decrypt_data_security_data( wmem_allocator_t
*pool
, const uint8_t* encrypted
, int encrypted_size
, const uint8_t* cemi
, int cemi_size
, struct data_security_info
* info
)
1057 const uint8_t* key
= NULL
;
1058 const uint8_t* decrypted
= NULL
;
1059 uint8_t keys_found
= 0;
1062 uint16_t source
= info
->source
;
1063 uint16_t dest
= info
->dest
;
1064 uint8_t multicast
= info
->multicast
;
1066 char* output
= info
->output_text
;
1067 int output_max
= sizeof info
->output_text
;
1068 snprintf( output
, output_max
, "with " );
1069 while( *output
) { ++output
; --output_max
; }
1071 // Try keys from keyring.XML
1074 // Try keys associated with GA
1075 struct knx_keyring_ga_keys
* ga_key
;
1077 for( ga_key
= knx_keyring_ga_keys
; ga_key
; ga_key
= ga_key
->next
)
1079 if( ga_key
->ga
== dest
)
1083 decrypted
= decrypt_data_security_data_with_key( pool
, key
, encrypted
, encrypted_size
, cemi
, cemi_size
);
1087 snprintf( output
, output_max
, "GA " );
1088 while( *output
) { ++output
; --output_max
; }
1096 // Try keys associated with dest IA
1097 struct knx_keyring_ia_keys
* ia_key
;
1099 for( ia_key
= knx_keyring_ia_keys
; ia_key
; ia_key
= ia_key
->next
)
1101 if( ia_key
->ia
== dest
)
1105 decrypted
= decrypt_data_security_data_with_key( pool
, key
, encrypted
, encrypted_size
, cemi
, cemi_size
);
1109 snprintf( output
, output_max
, "dest IA " );
1110 while( *output
) { ++output
; --output_max
; }
1119 // Try keys associated with source IA
1120 struct knx_keyring_ia_keys
* ia_key
;
1122 for( ia_key
= knx_keyring_ia_keys
; ia_key
; ia_key
= ia_key
->next
)
1124 if( ia_key
->ia
== source
)
1128 decrypted
= decrypt_data_security_data_with_key( pool
, key
, encrypted
, encrypted_size
, cemi
, cemi_size
);
1132 snprintf( output
, output_max
, "source IA " );
1133 while( *output
) { ++output
; --output_max
; }
1140 if( !decrypted
&& knx_decryption_key_count
)
1142 // Try all explicitly specified keys
1145 for( key_index
= 0; key_index
< knx_decryption_key_count
; ++key_index
)
1148 key
= knx_decryption_keys
[ key_index
];
1149 decrypted
= decrypt_data_security_data_with_key( pool
, key
, encrypted
, encrypted_size
, cemi
, cemi_size
);
1162 snprintf( output
, output_max
, "key" );
1164 for( count
= 16; count
; --count
)
1166 while( *output
) { ++output
; --output_max
; }
1167 snprintf( output
, output_max
, " %02X", *key
++ );
1172 snprintf( info
->output_text
, sizeof info
->output_text
, keys_found
? "failed" : "no keys found" );
1178 /* Dissect Object Index (1 byte)
1180 static uint8_t dissect_ox( tvbuff_t
*tvb
, packet_info
*pinfo
, proto_item
*node
, proto_tree
*list
, int *p_offset
, int end_pos
, uint8_t *p_error
)
1182 int offset
= *p_offset
;
1184 if( offset
< end_pos
)
1186 uint8_t ox
= tvb_get_uint8( tvb
, offset
);
1187 column_info
*cinfo
= pinfo
->cinfo
;
1189 col_append_fstr( cinfo
, COL_INFO
, " OX=%u", ox
);
1190 proto_item_append_text( node
, ", OX=%u", ox
);
1191 proto_tree_add_item( list
, hf_cemi_ox
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1193 *p_offset
= ++offset
;
1197 proto_tree_add_expert_format( list
, pinfo
, KIP_ERROR
, tvb
, offset
, 0, "? Object Index: expected 1 byte" );
1207 /* Dissect Object Type (2 bytes)
1209 static uint16_t dissect_ot( tvbuff_t
*tvb
, packet_info
*pinfo
, proto_item
*node
, proto_tree
*list
, int *p_offset
, int end_pos
, uint8_t *p_error
)
1211 int offset
= *p_offset
;
1213 if( offset
+ 1 < end_pos
)
1215 uint16_t ot
= tvb_get_ntohs( tvb
, offset
);
1216 column_info
*cinfo
= pinfo
->cinfo
;
1218 col_append_fstr( cinfo
, COL_INFO
, " OT=%u", ot
);
1219 proto_item_append_text( node
, ", OT=%u", ot
);
1221 proto_tree_add_item( list
, hf_cemi_ot
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
1228 node
= proto_tree_add_bytes_format( list
, hf_bytes
, tvb
, offset
, end_pos
- offset
, NULL
, "? Object Type" );
1229 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: 2 bytes" );
1236 *p_offset
= end_pos
;
1240 /* Dissect Property Identifier (1 byte)
1242 static uint8_t dissect_pid( tvbuff_t
*tvb
, packet_info
*pinfo
, proto_item
*node
, proto_tree
*list
, int *p_offset
, int end_pos
, int ot
, uint8_t show
, uint8_t *p_error
)
1244 int offset
= *p_offset
;
1246 if( offset
< end_pos
)
1248 uint8_t pid
= tvb_get_uint8( tvb
, offset
);
1249 column_info
*cinfo
= pinfo
->cinfo
;
1254 col_append_fstr( cinfo
, COL_INFO
, " P=%u", pid
);
1255 proto_item_append_text( node
, ", PID=%u", pid
);
1260 node
= proto_tree_add_item( list
, hf_cemi_pid
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1261 name
= get_pid_name( ot
, pid
);
1264 proto_item_append_text( node
, " = %s", name
);
1268 *p_offset
= ++offset
;
1272 proto_tree_add_expert_format( list
, pinfo
, KIP_ERROR
, tvb
, offset
, 0, "? Property ID: expected 1 byte" );
1282 /* Dissect Property Index (1 byte)
1284 static uint8_t dissect_px( tvbuff_t
*tvb
, packet_info
*pinfo
, proto_item
*node
, proto_tree
*list
, int *p_offset
, int end_pos
, uint8_t show
, uint8_t *p_error
)
1286 int offset
= *p_offset
;
1288 if( offset
< end_pos
)
1290 uint8_t px
= tvb_get_uint8( tvb
, offset
);
1294 column_info
*cinfo
= pinfo
->cinfo
;
1295 col_append_fstr( cinfo
, COL_INFO
, " PX=%u", px
);
1296 proto_item_append_text( node
, ", PX=%u", px
);
1299 proto_tree_add_item( list
, hf_cemi_px
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1301 *p_offset
= ++offset
;
1305 proto_tree_add_expert_format( list
, pinfo
, KIP_ERROR
, tvb
, offset
, 0, "? Property Index: expected 1 byte" );
1315 /* Dissect Property Range (2 bytes: Number Of Elements (4 bits), Start Index (12 bits))
1318 static void dissect_range( tvbuff_t
*tvb
, packet_info
*pinfo
, proto_item
*node
, proto_tree
*list
, int *p_offset
, int end_pos
, uint8_t pa_flags
, uint8_t *p_error
)
1320 int offset
= *p_offset
;
1323 if( offset
+ 1 >= end_pos
)
1325 node
= proto_tree_add_bytes_format( list
, hf_bytes
, tvb
, offset
, end_pos
- offset
, NULL
, "? Range" );
1326 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: 2 bytes" );
1328 *p_offset
= end_pos
;
1333 column_info
*cinfo
= pinfo
->cinfo
;
1334 proto_item
*cemi_node
= node
;
1335 uint16_t sx
= tvb_get_ntohs( tvb
, offset
);
1336 uint8_t ne
= sx
>> 12;
1339 /* 4 bits Number Of Elements */
1342 col_append_fstr( cinfo
, COL_INFO
, " N=%u", ne
);
1343 proto_item_append_text( node
, ", N=%u", ne
);
1345 if( ne
== 0 && !(pa_flags
& PA_RESPONSE
) )
1355 /* 12 bits Start Index */
1358 col_append_fstr( cinfo
, COL_INFO
, " X=%u", sx
);
1359 proto_item_append_text( node
, ", X=%u", sx
);
1364 proto_item
*range_node
= proto_tree_add_none_format( list
, hf_folder
, tvb
, offset
, 2, "Range: %u element%s at position %u", ne
, (ne
== 1) ? "" : "s", sx
);
1365 proto_tree
*range_list
= proto_item_add_subtree( range_node
, ett_cemi_range
);
1367 /* 4 bits Number Of Elements */
1368 node
= proto_tree_add_item( range_list
, hf_cemi_ne
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1372 proto_item_prepend_text( range_node
, "? " );
1373 proto_item_prepend_text( node
, "? " );
1374 expert_add_info_format( pinfo
, node
, KIP_ERROR
, (error
== 1) ? "Expected: >= 1 element(s)" : "Expected: 1 element" );
1377 /* 12 bits Start Index */
1378 proto_tree_add_item( range_list
, hf_cemi_sx
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
1385 int length
= end_pos
- offset
;
1388 node
= proto_tree_add_data( list
, tvb
, offset
, length
, cinfo
, cemi_node
, "Data", " $", ", $" );
1391 proto_item_prepend_text( node
, "? " );
1392 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Unexpected" );
1395 else if( (pa_flags
& PA_RESPONSE
) && (!(pa_flags
& PA_DATA
) || ne
== 0) && length
!= 1 )
1397 proto_item_prepend_text( node
, "? " );
1398 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: max 1 byte" );
1401 else if( pa_flags
& PA_DATA
)
1403 if( ne
== 1 && sx
== 0 && length
!= 2 )
1405 proto_item_prepend_text( node
, "? " );
1406 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: 2 bytes" );
1409 else if( ne
>= 2 && (length
% ne
) != 0 )
1411 proto_item_prepend_text( node
, "? " );
1412 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: multiple of %u bytes", ne
);
1419 *p_offset
= end_pos
;
1422 if( error
&& p_error
)
1428 /* Dissect Property Description: PDT (1 byte), Max Count (2 bytes), Access Levels (1 byte)
1430 static void dissect_prop_descr( tvbuff_t
* tvb
, packet_info
* pinfo
, proto_item
* cemi_node
, proto_tree
* cemi_list
, int* p_offset
, int size
, uint8_t* p_error
)
1432 int offset
= *p_offset
;
1433 column_info
* cinfo
= pinfo
->cinfo
;
1436 /* 4 bytes Property Description */
1437 if( offset
+ 4 > size
)
1439 proto_item
* node
= proto_tree_add_bytes_format( cemi_list
, hf_bytes
, tvb
, offset
, size
- offset
, NULL
, "? Property Description" );
1440 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: 4 bytes" );
1447 /* 1 bit Writability, 1 bit reserved, 6 bits Property Data Type */
1448 uint8_t pdt
= tvb_get_uint8( tvb
, offset
);
1449 uint8_t writable
= (pdt
& 0x80) != 0;
1451 col_append_fstr( cinfo
, COL_INFO
, " T=%u", pdt
);
1452 proto_item_append_text( cemi_node
, ", T=%u", pdt
);
1454 /* 4 bits reserved, 12 bits Max Elements */
1455 uint16_t me
= tvb_get_ntohs( tvb
, offset
+ 1) & 0x0FFF;
1458 col_append_fstr( cinfo
, COL_INFO
, " N=%u", me
);
1459 proto_item_append_text( cemi_node
, ", N=%u", me
);
1462 /* 4 bits Read Access, 4 bits Write Access */
1463 uint8_t wa
= tvb_get_uint8( tvb
, offset
+ 3 );
1464 uint8_t ra
= (wa
& 0xF0) >> 4;
1466 col_append_fstr( cinfo
, COL_INFO
, " R=%u", ra
);
1468 col_append_fstr( cinfo
, COL_INFO
, " W=%u", wa
);
1469 proto_item_append_text( cemi_node
, ", R=%u", ra
);
1471 proto_item_append_text( cemi_node
, ", W=%u", wa
);
1475 proto_item
*pd_node
= proto_tree_add_none_format( cemi_list
, hf_folder
, tvb
, offset
, 4, "Property Description: " );
1476 proto_tree
*pd_list
= proto_item_add_subtree( pd_node
, ett_cemi_pd
);
1478 const char* pdt_name
= try_val_to_str( pdt
, pdt_vals
);
1480 proto_item_append_text( pd_node
, "%s", pdt_name
);
1482 proto_item_append_text( pd_node
, "PDT = 0x%02X", pdt
);
1485 proto_item_append_text( pd_node
, ", Max Elements = %u", me
);
1487 proto_item_append_text( pd_node
, ", Read = %u", ra
);
1489 proto_item_append_text( pd_node
, ", Write = %u", wa
);
1491 proto_tree_add_item( pd_list
, hf_cemi_pw
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1492 proto_tree_add_item( pd_list
, hf_cemi_pdt
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1493 proto_tree_add_item( pd_list
, hf_cemi_me
, tvb
, offset
+ 1, 2, ENC_BIG_ENDIAN
);
1494 proto_tree_add_item( pd_list
, hf_cemi_ra
, tvb
, offset
+ 3, 1, ENC_BIG_ENDIAN
);
1495 proto_tree_add_item( pd_list
, hf_cemi_wa
, tvb
, offset
+ 3, 1, ENC_BIG_ENDIAN
);
1501 if( error
&& p_error
)
1509 /* Dissect OT (2 bytes), OI (12 bits), and PID (12 bits) for PropertyExt services
1511 static void dissect_pid_ext( tvbuff_t
*tvb
, packet_info
*pinfo
, proto_item
*cemi_node
, proto_tree
*cemi_list
, int *p_offset
, int size
, uint8_t *p_error
)
1513 int offset
= *p_offset
;
1514 column_info
* cinfo
= pinfo
->cinfo
;
1517 /* 2 bytes Object Type */
1518 uint16_t ot
= dissect_ot( tvb
, pinfo
, cemi_node
, cemi_list
, &offset
, size
, &error
);
1520 if( offset
+ 3 > size
)
1522 proto_item
* node
= proto_tree_add_bytes_format( cemi_list
, hf_bytes
, tvb
, offset
, size
- offset
, NULL
, "? Object Instance, PID" );
1523 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: 3 bytes" );
1530 /* 12 bits Object Instance */
1531 uint16_t cc
= tvb_get_ntohs( tvb
, offset
) >> 4;
1532 col_append_fstr( cinfo
, COL_INFO
, " OI=%u", cc
);
1533 proto_item_append_text( cemi_node
, ", OI=%u", cc
);
1534 proto_tree_add_item( cemi_list
, hf_cemi_ext_oi
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
1537 /* 12 bits Property ID */
1538 cc
= tvb_get_ntohs( tvb
, offset
) & 0x0FFF;
1539 col_append_fstr( cinfo
, COL_INFO
, " P=%u", cc
);
1540 proto_item_append_text( cemi_node
, ", PID=%u", cc
);
1544 proto_item
* node
= proto_tree_add_item( cemi_list
, hf_cemi_ext_pid
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
1545 const char* name
= get_pid_name( ot
, cc
);
1548 proto_item_append_text( node
, " = %s", name
);
1555 if( error
&& p_error
)
1563 /* Dissect cEMI Management packet
1564 (M_PropRead.req, M_PropRead.con, M_PropWrite.req, M_PropWrite.con, M_PropInfo.ind, M_Reset.req, M_Reset.ind)
1566 static void dissect_cemi_mgmt_packet( tvbuff_t
* tvb
, packet_info
* pinfo
, proto_item
*cemi_node
, proto_tree
*cemi_list
, uint8_t mc
, int *p_offset
, int size
, uint8_t* p_pa_flags
, uint8_t *p_error
)
1568 column_info
* cinfo
= pinfo
->cinfo
;
1569 int offset
= *p_offset
;
1570 uint8_t pa_flags
= *p_pa_flags
;
1571 uint8_t error
= *p_error
;
1573 uint8_t min_size
= 1;
1577 case CEMI_M_PROPREAD_REQ
:
1579 goto case_CEMI_M_PROP
;
1581 case CEMI_M_PROPWRITE_CON
:
1582 pa_flags
= PA_RESPONSE
;
1583 goto case_CEMI_M_PROP
;
1585 case CEMI_M_PROPREAD_CON
:
1586 pa_flags
= PA_RESPONSE
| PA_DATA
;
1587 goto case_CEMI_M_PROP
;
1589 case CEMI_M_PROPWRITE_REQ
:
1590 case CEMI_M_PROPINFO_IND
:
1591 //pa_flags = PA_DATA;
1597 case CEMI_M_FUNCPROPCMD_REQ
:
1598 case CEMI_M_FUNCPROPREAD_REQ
:
1599 case CEMI_M_FUNCPROP_CON
:
1600 //pa_flags = PA_DATA;
1604 case CEMI_M_RESET_REQ
:
1605 case CEMI_M_RESET_IND
:
1612 /* 2 bytes Object Type */
1613 uint16_t ot
= dissect_ot( tvb
, pinfo
, cemi_node
, cemi_list
, &offset
, size
, &error
);
1615 /* 1 byte Object Instance */
1618 proto_tree_add_expert_format( cemi_list
, pinfo
, KIP_ERROR
, tvb
, offset
, 0, "? Object Instance: expected 1 byte" );
1623 uint8_t oi
= tvb_get_uint8( tvb
, 3 );
1626 col_append_fstr( cinfo
, COL_INFO
, " OI=%u", oi
);
1627 proto_item_append_text( cemi_node
, ", OI=%u", oi
);
1629 proto_tree_add_item( cemi_list
, hf_cemi_oi
, tvb
, 3, 1, ENC_BIG_ENDIAN
);
1633 /* 1 byte Property ID
1635 dissect_pid( tvb
, pinfo
, cemi_node
, cemi_list
, &offset
, size
, ot
, 1, &error
);
1639 /* Range (Start Index, Number Of Elements) and Data
1641 dissect_range( tvb
, pinfo
, cemi_node
, cemi_list
, &offset
, size
, pa_flags
, &error
);
1647 *p_pa_flags
= pa_flags
;
1651 /* Dissect A_MemoryExt service */
1652 static void dissect_memory_ext_service( tvbuff_t
* tvb
, packet_info
* pinfo
, proto_item
* cemi_node
, proto_tree
* cemi_list
,
1653 uint16_t ax
, int* p_offset
, int size
, uint8_t* p_pa_flags
, uint8_t* p_error
)
1655 column_info
* cinfo
= pinfo
->cinfo
;
1656 int offset
= *p_offset
;
1657 uint8_t pa_flags
= *p_pa_flags
;
1658 uint8_t error
= *p_error
;
1660 /* 4 bytes Range (1 byte Memory Length, 3 bytes Memory Address) */
1661 if( offset
+ 4 > size
)
1663 proto_item
* node
= proto_tree_add_bytes_format( cemi_list
, hf_bytes
, tvb
, offset
, size
- offset
, NULL
, "? Range" );
1664 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: 4 bytes" );
1670 /* 1 byte Memory Length or Error Code */
1671 uint8_t is_response
= (ax
== AX_MemExtReadResp
|| ax
== AX_MemExtWriteResp
);
1672 uint8_t n
= tvb_get_uint8( tvb
, offset
);
1677 col_append_fstr( cinfo
, COL_INFO
, " E=$%02X", n
);
1678 proto_item_append_text( cemi_node
, ", E=$%02X", n
);
1685 col_append_fstr( cinfo
, COL_INFO
, " N=%u", n
);
1686 proto_item_append_text( cemi_node
, ", N=%u", n
);
1690 /* 3 bytes Memory Address */
1691 uint32_t x
= tvb_get_uint24( tvb
, offset
+ 1, ENC_BIG_ENDIAN
);
1692 col_append_fstr( cinfo
, COL_INFO
, " X=$%06" PRIX32
, x
);
1693 proto_item_append_text( cemi_node
, ", X=$%06" PRIX32
, x
);
1697 proto_tree_add_item( cemi_list
, hf_cemi_error
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1701 proto_tree_add_item( cemi_list
, hf_cemi_ext_memory_length
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1704 proto_tree_add_item( cemi_list
, hf_cemi_ext_memory_address
, tvb
, offset
+ 1, 3, ENC_BIG_ENDIAN
);
1710 *p_pa_flags
= pa_flags
;
1714 /* Dissect A_UserMemory service */
1715 static void dissect_user_memory_service( tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* tree
, proto_item
* cemi_node
, proto_tree
* cemi_list
,
1716 int* p_offset
, int size
, uint8_t* p_pa_flags
, uint8_t* p_error
)
1718 column_info
* cinfo
= pinfo
->cinfo
;
1719 int offset
= *p_offset
;
1720 uint8_t pa_flags
= *p_pa_flags
;
1721 uint8_t error
= *p_error
;
1726 /* 3 bytes Range (Memory Length, Memory Address) */
1727 if( offset
+ 3 > size
)
1729 node
= proto_tree_add_bytes_format( cemi_list
, hf_bytes
, tvb
, offset
, size
- offset
, NULL
, "? Range" );
1730 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: 3 bytes" );
1736 uint8_t c2
= tvb_get_uint8( tvb
, offset
);
1737 uint8_t c1
= c2
>> 4;
1738 uint32_t c3
= tvb_get_ntohs( tvb
, offset
+ 1 );
1742 col_append_fstr( cinfo
, COL_INFO
, " N=%u", c2
);
1743 col_append_fstr( cinfo
, COL_INFO
, " X=$%05X", c3
);
1747 proto_item_append_text( cemi_node
, ", N=%u", c2
);
1748 proto_item_append_text( cemi_node
, ", X=$%05X", c3
);
1749 node
= proto_tree_add_none_format( cemi_list
, hf_folder
, tvb
, offset
, 1,
1750 "Range: %u byte%s at address $%05X", c2
, (c2
== 1) ? "" : "s", c3
);
1751 list
= proto_item_add_subtree( node
, ett_cemi_range
);
1752 proto_tree_add_item( list
, hf_cemi_memory_address_ext
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1753 proto_tree_add_item( list
, hf_cemi_memory_length
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1754 proto_tree_add_item( list
, hf_cemi_memory_address
, tvb
, offset
+ 1, 2, ENC_BIG_ENDIAN
);
1760 *p_pa_flags
= pa_flags
;
1764 /* Dissect A_FunctionProperty service */
1765 static void dissect_function_property_service( tvbuff_t
* tvb
, packet_info
* pinfo
, proto_item
* cemi_node
, proto_tree
* cemi_list
,
1766 int* p_offset
, int size
, uint8_t* p_error
)
1768 /* 1 byte Object Index */
1769 dissect_ox( tvb
, pinfo
, cemi_node
, cemi_list
, p_offset
, size
, p_error
);
1771 /* 1 byte Property ID */
1772 dissect_pid( tvb
, pinfo
, cemi_node
, cemi_list
, p_offset
, size
, -1, 1, p_error
);
1775 /* Dissect (obsolete) A_Router service */
1776 static void dissect_router_service( tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* tree
, proto_item
* cemi_node
, proto_tree
* cemi_list
,
1777 int* p_offset
, int size
, uint8_t* p_pa_flags
, uint8_t* p_error
)
1779 column_info
* cinfo
= pinfo
->cinfo
;
1780 int offset
= *p_offset
;
1781 uint8_t pa_flags
= *p_pa_flags
;
1782 uint8_t error
= *p_error
;
1787 /* 3 bytes Range (1 byte Memory Length, 2 bytes Memory Address) */
1788 if( offset
+ 3 > size
)
1790 node
= proto_tree_add_bytes_format( cemi_list
, hf_bytes
, tvb
, offset
, size
- offset
, NULL
, "? Range" );
1791 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: 3 bytes" );
1797 uint8_t c
= tvb_get_uint8( tvb
, offset
);
1798 uint16_t cc
= tvb_get_ntohs( tvb
, offset
+ 1 );
1800 col_append_fstr( cinfo
, COL_INFO
, " N=%u", c
);
1801 col_append_fstr( cinfo
, COL_INFO
, " X=$%04X", cc
);
1804 proto_item_append_text( cemi_node
, ", N=%u, X=$%04X", c
, cc
);
1805 node
= proto_tree_add_none_format( cemi_list
, hf_folder
, tvb
, offset
, 3,
1806 "Range: %u byte%s at address $%04X", c
, (c
== 1) ? "" : "s", cc
);
1807 list
= proto_item_add_subtree( node
, ett_cemi_range
);
1808 proto_tree_add_item( list
, hf_cemi_ext_memory_length
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1809 proto_tree_add_item( list
, hf_cemi_ext_memory_address
, tvb
, offset
+ 1, 2, ENC_BIG_ENDIAN
);
1815 *p_pa_flags
= pa_flags
;
1819 /* Dissect A_Authenticate or A_Key service */
1820 static void dissect_authenticate_service( tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* tree
, proto_item
* cemi_node
, proto_tree
* cemi_list
,
1821 uint16_t ax
, int* p_offset
, int size
, uint8_t* p_pa_flags
, uint8_t* p_error
)
1823 column_info
* cinfo
= pinfo
->cinfo
;
1824 int offset
= *p_offset
;
1825 uint8_t pa_flags
= *p_pa_flags
;
1826 uint8_t error
= *p_error
;
1829 if( offset
>= size
)
1831 proto_tree_add_expert_format( cemi_list
, pinfo
, KIP_ERROR
, tvb
, offset
, 0, "? Level: expected 1 byte" );
1836 uint8_t c
= tvb_get_uint8( tvb
, offset
);
1837 if( ax
!= AX_AuthReq
|| c
!= 0 )
1839 col_append_fstr( cinfo
, COL_INFO
, " L=%u", c
);
1842 proto_item_append_text( cemi_node
, ", L=%u", c
);
1847 proto_tree_add_item( cemi_list
, hf_cemi_level
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1853 *p_pa_flags
= pa_flags
;
1857 /* Dissect A_PropertyValue service */
1858 static void dissect_property_value_service( tvbuff_t
* tvb
, packet_info
* pinfo
, proto_item
* cemi_node
, proto_tree
* cemi_list
,
1859 int* p_offset
, int size
, uint8_t* p_pa_flags
, uint8_t* p_error
)
1861 /* 1 byte Object Index */
1862 dissect_ox( tvb
, pinfo
, cemi_node
, cemi_list
, p_offset
, size
, p_error
);
1864 /* 1 byte Property ID */
1865 dissect_pid( tvb
, pinfo
, cemi_node
, cemi_list
, p_offset
, size
, -1, 1, p_error
);
1868 dissect_range( tvb
, pinfo
, cemi_node
, cemi_list
, p_offset
, size
, *p_pa_flags
, p_error
);
1871 /* Dissect A_PropertyDescription service */
1872 static void dissect_property_description_service( tvbuff_t
* tvb
, packet_info
* pinfo
, proto_item
* cemi_node
, proto_tree
* cemi_list
,
1873 int* p_offset
, int size
, uint8_t* p_pa_flags
, uint8_t* p_error
)
1875 /* 1 byte Object Index */
1876 dissect_ox( tvb
, pinfo
, cemi_node
, cemi_list
, p_offset
, size
, p_error
);
1878 /* 1 byte Property ID */
1880 uint8_t pa_flags
= *p_pa_flags
;
1881 uint8_t pid
= dissect_pid( tvb
, pinfo
, cemi_node
, cemi_list
, p_offset
, size
, -1, pa_flags
, p_error
);
1883 /* 1 byte Property Index */
1884 dissect_px( tvb
, pinfo
, cemi_node
, cemi_list
, p_offset
, size
, pa_flags
|| !pid
, p_error
);
1886 if( pa_flags
) /* A_PropertyDescription_Response */
1888 /* 1 byte PDT, 2 bytes Max Elements, 1 byte Access Levels */
1889 dissect_prop_descr( tvb
, pinfo
, cemi_node
, cemi_list
, p_offset
, size
, p_error
);
1891 /* No further trailing data */
1897 /* Dissect A_NetworkParameter or A_GroupPropertyValue service */
1898 static void dissect_network_parameter_service( tvbuff_t
* tvb
, packet_info
* pinfo
, proto_item
* cemi_node
, proto_tree
* cemi_list
,
1899 int* p_offset
, int size
, uint8_t* p_error
)
1901 /* 2 bytes Object Type */
1902 uint16_t ot
= dissect_ot( tvb
, pinfo
, cemi_node
, cemi_list
, p_offset
, size
, p_error
);
1904 /* 1 byte Property ID */
1905 dissect_pid( tvb
, pinfo
, cemi_node
, cemi_list
, p_offset
, size
, ot
, 1, p_error
);
1908 /* Dissect A_IndividualAddressSerialNumber or A_DomainAddressSerialNumber service */
1909 static void dissect_ia_serial_number_service( tvbuff_t
* tvb
, packet_info
* pinfo
, proto_item
* cemi_node
, proto_tree
* cemi_list
,
1910 int* p_offset
, int size
, uint8_t* p_pa_flags
, uint8_t* p_error
)
1912 column_info
* cinfo
= pinfo
->cinfo
;
1913 int offset
= *p_offset
;
1914 uint8_t pa_flags
= *p_pa_flags
;
1915 uint8_t error
= *p_error
;
1919 /* 6 bytes Serial Nr */
1920 if( offset
+ 6 > size
)
1922 node
= proto_tree_add_bytes_format( cemi_list
, hf_bytes
, tvb
, offset
, size
- offset
, NULL
, "? Serial Number" );
1923 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: 6 bytes" );
1929 proto_tree_add_data( cemi_list
, tvb
, offset
, 6, cinfo
, cemi_node
, "Serial Number", " SN=$", ", SerNr=$" );
1935 if( offset
>= size
)
1937 proto_tree_add_expert_format( cemi_list
, pinfo
, KIP_ERROR
, tvb
, offset
, 0, "? Data: missing" );
1943 *p_pa_flags
= pa_flags
;
1947 /* Dissect A_SystemNetworkParameter service */
1948 static void dissect_system_network_parameter_service( tvbuff_t
* tvb
, packet_info
* pinfo
, proto_item
* cemi_node
, proto_tree
* cemi_list
,
1949 int* p_offset
, int size
, uint8_t* p_pa_flags
, uint8_t* p_error
)
1951 column_info
* cinfo
= pinfo
->cinfo
;
1952 int offset
= *p_offset
;
1953 uint8_t pa_flags
= *p_pa_flags
;
1954 uint8_t error
= *p_error
;
1962 /* 2 bytes Object Type */
1963 if( offset
+ 1 >= size
)
1966 node
= proto_tree_add_bytes_format( cemi_list
, hf_bytes
, tvb
, offset
, size
- offset
, NULL
, "? Object Type" );
1967 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: 2 bytes" );
1973 ot
= cc
= tvb_get_ntohs( tvb
, offset
);
1977 col_append_fstr( cinfo
, COL_INFO
, " OT=%u", cc
);
1978 proto_item_append_text( cemi_node
, ", OT=%u", cc
);
1983 node
= proto_tree_add_item( cemi_list
, hf_cemi_ot
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
1984 name
= try_val_to_str( cc
, ot_vals
);
1987 proto_item_append_text( node
, " = %s", name
);
1994 /* 2 bytes Property ID (12 bits) and Reserved (4 bits) */
1995 if( offset
+ 1 >= size
)
1997 node
= proto_tree_add_bytes_format( cemi_list
, hf_bytes
, tvb
, offset
, size
- offset
, NULL
, "? Property ID" );
1998 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: 2 bytes" );
2004 /* 12 bits Property ID */
2005 cc
= tvb_get_ntohs( tvb
, offset
);
2009 col_append_fstr( cinfo
, COL_INFO
, " P=%u", cc
);
2010 proto_item_append_text( cemi_node
, ", PID=%u", cc
);
2014 node
= proto_tree_add_item( cemi_list
, hf_cemi_snp_pid
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
2015 name
= get_pid_name( ot
, cc
);
2018 proto_item_append_text( node
, " = %s", name
);
2024 /* 4 bits Reserved */
2027 col_append_fstr( cinfo
, COL_INFO
, " $%X", c
);
2028 proto_item_append_text( cemi_node
, ", $%X", c
);
2029 node
= proto_tree_add_item( cemi_list
, hf_cemi_snp_reserved
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
2030 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: zero" );
2038 *p_pa_flags
= pa_flags
;
2042 /* Dissect A_PropertyExtValue service */
2043 static void dissect_property_ext_value_service( tvbuff_t
* tvb
, packet_info
* pinfo
, proto_item
* cemi_node
, proto_tree
* cemi_list
,
2044 int* p_offset
, int size
, uint8_t* p_pa_flags
, uint8_t* p_error
)
2046 column_info
* cinfo
= pinfo
->cinfo
;
2047 int offset
= *p_offset
;
2048 uint8_t pa_flags
= *p_pa_flags
;
2049 uint8_t error
= *p_error
;
2053 /* 2 bytes OT, 12 bits OI, 12 bits PID */
2054 dissect_pid_ext( tvb
, pinfo
, cemi_node
, cemi_list
, &offset
, size
, &error
);
2056 /* 3 bytes Range (1 byte Count, 2 bytes Index) */
2057 if( offset
+ 3 > size
)
2059 node
= proto_tree_add_bytes_format( cemi_list
, hf_bytes
, tvb
, offset
, size
- offset
, NULL
, "? Range" );
2060 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: 3 bytes" );
2067 uint8_t ne
= tvb_get_uint8( tvb
, offset
);
2070 col_append_fstr( cinfo
, COL_INFO
, " N=%u", ne
);
2071 proto_item_append_text( cemi_node
, ", N=%u", ne
);
2075 uint16_t sx
= tvb_get_ntohs( tvb
, offset
+ 1 );
2078 col_append_fstr( cinfo
, COL_INFO
, " X=%u", sx
);
2079 proto_item_append_text( cemi_node
, ", X=%u", sx
);
2084 proto_item
*range_node
= proto_tree_add_none_format( cemi_list
, hf_folder
, tvb
, offset
, 3, "Range: %u element%s at position %u", ne
, (ne
== 1) ? "" : "s", sx
);
2085 proto_tree
*range_list
= proto_item_add_subtree( range_node
, ett_cemi_range
);
2086 proto_tree_add_item( range_list
, hf_cemi_ext_ne
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
2087 proto_tree_add_item( range_list
, hf_cemi_ext_sx
, tvb
, offset
+ 1, 2, ENC_BIG_ENDIAN
);
2094 *p_pa_flags
= pa_flags
;
2098 /* Dissect A_PropertyExtDescription service */
2099 static void dissect_property_ext_description_service( tvbuff_t
* tvb
, packet_info
* pinfo
, proto_item
* cemi_node
, proto_tree
* cemi_list
,
2100 int* p_offset
, int size
, uint8_t* p_pa_flags
, uint8_t* p_error
)
2102 column_info
* cinfo
= pinfo
->cinfo
;
2103 int offset
= *p_offset
;
2104 uint8_t pa_flags
= *p_pa_flags
;
2105 uint8_t error
= *p_error
;
2111 /* 2 bytes OT, 12 bits OI, 12 bits PID */
2112 dissect_pid_ext( tvb
, pinfo
, cemi_node
, cemi_list
, &offset
, size
, &error
);
2114 /* 4 bits Description Type */
2115 if( offset
>= size
)
2117 node
= proto_tree_add_bytes_format( cemi_list
, hf_bytes
, tvb
, offset
, size
- offset
, NULL
, "? Description Type" );
2118 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: 4 bits" );
2123 c
= tvb_get_uint8( tvb
, offset
) >> 4;
2124 col_append_fstr( cinfo
, COL_INFO
, " D=%u", c
);
2125 proto_item_append_text( cemi_node
, ", D=%u", c
);
2126 proto_tree_add_item( cemi_list
, hf_cemi_ext_dt
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
2129 /* 12 bits Property Index */
2130 if( offset
+ 2 > size
)
2132 node
= proto_tree_add_bytes_format( cemi_list
, hf_bytes
, tvb
, offset
, size
- offset
, NULL
, "? Property Index" );
2133 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: 12 bits" );
2139 cc
= tvb_get_ntohs( tvb
, offset
) & 0x0FFF;
2140 col_append_fstr( cinfo
, COL_INFO
, " PX=%u", cc
);
2141 proto_item_append_text( cemi_node
, ", PX=%u", cc
);
2142 proto_tree_add_item( cemi_list
, hf_cemi_ext_px
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
2146 if( pa_flags
) /* AX_PropExtDescrResp */
2148 /* 4 bytes DPT (2 bytes DPT Major, 2 bytes DPT Minor) */
2149 if( offset
+ 4 > size
)
2151 node
= proto_tree_add_bytes_format( cemi_list
, hf_bytes
, tvb
, offset
, size
- offset
, NULL
, "? Data Point Type" );
2152 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: 4 bytes" );
2158 uint16_t dpt_major
= tvb_get_ntohs( tvb
, offset
);
2159 uint16_t dpt_minor
= tvb_get_ntohs( tvb
, offset
+ 2 );
2163 proto_item
*dpt_node
= proto_tree_add_none_format( cemi_list
, hf_folder
, tvb
, offset
, 2, "Data Point Type: %u.%u", dpt_major
, dpt_minor
);
2164 proto_tree
*dpt_list
= proto_item_add_subtree( dpt_node
, ett_cemi_dpt
);
2165 proto_tree_add_item( dpt_list
, hf_cemi_dpt_major
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
2166 proto_tree_add_item( dpt_list
, hf_cemi_dpt_minor
, tvb
, offset
+ 2, 2, ENC_BIG_ENDIAN
);
2171 if( dpt_major
|| dpt_minor
)
2173 col_append_fstr( cinfo
, COL_INFO
, " DPT=%u.%u", dpt_major
, dpt_minor
);
2174 proto_item_append_text( cemi_node
, ", DPT=%u.%u", dpt_major
, dpt_minor
);
2178 /* 1 byte PDT, 2 bytes Max Elements, 1 byte Access Levels */
2179 dissect_prop_descr( tvb
, pinfo
, cemi_node
, cemi_list
, &offset
, size
, &error
);
2181 /* No further trailing data */
2186 *p_pa_flags
= pa_flags
;
2190 /* Dissect A_DataSecurity service */
2191 static void dissect_data_security_service( tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* tree
, proto_item
* cemi_node
, proto_tree
* cemi_list
,
2192 uint16_t source_addr
, proto_item
* source_node
, uint16_t dest_addr
, proto_item
* dest_node
, uint8_t unicast
,
2193 const char* name
, int* p_offset
, int size
, uint8_t* p_pa_flags
, uint8_t* p_error
)
2195 column_info
* cinfo
= pinfo
->cinfo
;
2196 proto_tree
* root_tree
= tree
;
2197 int offset
= *p_offset
;
2198 uint8_t pa_flags
= *p_pa_flags
;
2199 uint8_t error
= *p_error
;
2204 // 1 byte SCF, 6 bytes SeqNr, ...
2205 // and either another SeqNr for sync or Apci+Mac (2+4 bytes) for data.
2206 if( offset
+ 13 > size
)
2208 node
= proto_tree_add_bytes_format( cemi_list
, hf_bytes
, tvb
, offset
, size
- offset
, NULL
, "? SCF, SeqNr, ..." );
2209 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: min 13 bytes" );
2216 uint8_t scf
= tvb_get_uint8( tvb
, offset
);
2217 uint8_t is_sync
= (scf
& 6) == 0x02;
2218 uint8_t is_sync_req
= is_sync
&& (scf
& 1) == 0;
2219 uint8_t is_sync_res
= is_sync
&& !is_sync_req
;
2222 name
= try_val_to_str( scf
, scf_short_vals
);
2223 if( !name
) name
= "?";
2224 col_append_fstr( cinfo
, COL_INFO
, " %s", name
);
2225 proto_item_append_text( cemi_node
, ", %s", name
);
2227 node
= proto_tree_add_item( cemi_list
, hf_cemi_scf
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
2228 list
= proto_item_add_subtree( node
, ett_cemi_scf
);
2229 proto_tree_add_item( list
, hf_cemi_scf_t
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
2230 proto_tree_add_item( list
, hf_cemi_scf_sai
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
2231 proto_tree_add_item( list
, hf_cemi_scf_sbc
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
2232 proto_tree_add_item( list
, hf_cemi_scf_svc
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
2237 name
= is_sync_req
? "SeqNrLocal" : is_sync_res
? "Challenge" : "SeqNr";
2238 seq_nr
= tvb_get_ntoh48( tvb
, offset
);
2239 proto_tree_add_data( cemi_list
, tvb
, offset
, 6, cinfo
, cemi_node
, name
, NULL
, is_sync_res
? NULL
: ", SeqNrLocal=$" );
2244 /* 6 bytes SyncReq SerNr or SyncRes SeqNrRemote */
2245 name
= is_sync_req
? "SerNr" : "SeqNrRemote";
2246 proto_tree_add_data( cemi_list
, tvb
, offset
, 6, cinfo
, cemi_node
, name
, NULL
, is_sync_res
? ", SeqNrRemote=$" : NULL
);
2249 /* 6 bytes SyncReq Challenge or SyncRes SeqNrLocal */
2250 name
= is_sync_req
? "Challenge" : "SeqNrLocal";
2251 if( offset
+ 6 > size
)
2253 node
= proto_tree_add_bytes_format( cemi_list
, hf_bytes
, tvb
, offset
, size
- offset
, NULL
, "%s", name
);
2254 proto_item_prepend_text( node
, "? " );
2255 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: 6 bytes" );
2261 proto_tree_add_data( cemi_list
, tvb
, offset
, 6, NULL
, NULL
, name
, NULL
, NULL
);
2267 node
= proto_tree_add_data( cemi_list
, tvb
, offset
, size
- offset
, NULL
, NULL
, "Message Authentication Code", NULL
, NULL
);
2268 if( offset
+ 4 != size
)
2270 proto_item_prepend_text( node
, "? " );
2271 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: 4 bytes" );
2280 struct data_security_info info
;
2281 struct knx_keyring_ia_seqs
* ia_seq
;
2282 const uint8_t* cemi
;
2283 const uint8_t* encrypted
;
2285 const uint8_t* decrypted
;
2288 info
.source
= source_addr
;
2289 info
.dest
= dest_addr
;
2290 info
.multicast
= !unicast
;
2291 info
.seq_nr
= seq_nr
;
2292 *info
.output_text
= '\0';
2294 if( !unicast
) // multicast or broadcast
2297 uint8_t ga_found
= 0;
2299 struct knx_keyring_ga_senders
* ga_sender
= knx_keyring_ga_senders
;
2300 for( ; ga_sender
; ga_sender
= ga_sender
->next
)
2302 if( ga_sender
->ga
== dest_addr
)
2306 if( ga_sender
->ia
== source_addr
)
2318 expert_add_info_format( pinfo
, source_node
, KIP_ERROR
, "Unknown sender" );
2323 expert_add_info_format( pinfo
, dest_node
, KIP_WARNING
, "Unknown group address" );
2329 for( ia_seq
= knx_keyring_ia_seqs
; ia_seq
; ia_seq
= ia_seq
->next
)
2331 if( ia_seq
->ia
== source_addr
)
2333 if( ia_seq
->seq
> seq_nr
)
2335 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: min $%012" PRIX64
, ia_seq
->seq
);
2341 // Get encrypted data.
2342 cemi
= tvb_get_ptr( tvb
, 0, size
);
2343 encrypted
= cemi
+ offset
;
2344 encrypted_size
= size
- offset
;
2347 decrypted
= decrypt_data_security_data( pinfo
->pool
, encrypted
, encrypted_size
, cemi
, size
, &info
);
2351 tvbuff_t
* tvb2
= tvb_new_child_real_data( tvb
, decrypted
, encrypted_size
, encrypted_size
);
2352 int size2
= encrypted_size
- 4; // > 0, guaranteed by decrypt_data_security_data
2353 proto_item_append_text( cemi_node
, ", MAC OK" );
2354 //tvb_set_free_cb(tvb2, wmem_free);
2355 add_new_data_source( pinfo
, tvb2
, "Decrypted" );
2357 item
= proto_tree_add_none_format( cemi_list
, hf_folder
, tvb2
, 0, encrypted_size
, "Decrypted" );
2358 tree
= proto_item_add_subtree( item
, ett_cemi_decrypted
);
2360 if( *info
.output_text
)
2362 proto_item_append_text( item
, " (%s)", info
.output_text
);
2365 proto_tree_add_data( tree
, tvb2
, 0, size2
, NULL
, NULL
, "Embedded APDU", NULL
, NULL
);
2366 proto_tree_add_data( tree
, tvb2
, size2
, 4, NULL
, NULL
, "Message Authentication Code", NULL
, NULL
);
2368 /* Dissect embedded APDU */
2370 // Hack: To save us from splitting another sub dissector which only
2371 // dissects the Apci+Apdu
2372 // we synthesize a telegram from the outer ApciSec telegram fields and the inner
2373 // decrypted apci+apdu and then we dissect this as a new cEMI frame.
2374 int innerTelegramSize
= size
- 13; // > 0, already checked above
2375 int additionalInfoLength
= cemi
[ 1 ]; // cemi size > 13, already checked above
2376 int offsetToApci
= additionalInfoLength
+ 9;
2377 if( offsetToApci
< size
)
2379 if( offsetToApci
+ size2
<= innerTelegramSize
)
2381 uint8_t* innerTelegram
= (uint8_t*) wmem_alloc( pinfo
->pool
, innerTelegramSize
);
2383 memcpy( innerTelegram
, cemi
, offsetToApci
);
2384 memcpy( innerTelegram
+ offsetToApci
, decrypted
, size2
);
2385 innerTelegram
[ additionalInfoLength
+ 8 ] = (uint8_t) (size2
- 1);
2387 tvbuff_t
* tvb3
= tvb_new_child_real_data( tvb
, innerTelegram
, innerTelegramSize
, innerTelegramSize
);
2388 //tvb_set_free_cb(tvb3, wmem_free);
2389 add_new_data_source( pinfo
, tvb3
, "Inner Decrypted Telegram" );
2391 dissector_handle_t cemi_handle
= find_dissector( "cemi" );
2394 call_dissector( cemi_handle
, tvb3
, pinfo
, root_tree
);
2402 // Could not be decrypted.
2403 proto_item_append_text( cemi_node
, ", Could not be decrypted" );
2405 if( *info
.output_text
)
2407 proto_item_append_text( cemi_node
, " (%s)", info
.output_text
);
2416 *p_pa_flags
= pa_flags
;
2420 /* Dissect extended AL service (10 bit AL service code)
2422 static void dissect_extended_app_service( tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* tree
, proto_item
* cemi_node
, proto_tree
* cemi_list
,
2423 uint16_t source_addr
, proto_item
* source_node
, uint16_t dest_addr
, proto_item
* dest_node
, uint8_t unicast
,
2424 uint16_t ax
, const char* name
,
2425 int* p_offset
, int size
, uint8_t* p_pa_flags
, uint8_t* p_error
)
2427 column_info
* cinfo
= pinfo
->cinfo
;
2428 int offset
= *p_offset
;
2429 uint8_t pa_flags
= *p_pa_flags
;
2430 uint8_t error
= *p_error
;
2432 proto_item
* node
= NULL
;
2433 proto_tree
* list
= NULL
;
2435 col_append_fstr( cinfo
, COL_INFO
, " %s", name
);
2439 proto_item_append_text( cemi_node
, ", %s", name
);
2440 node
= proto_tree_add_none_format( cemi_list
, hf_folder
, tvb
, offset
, 2, "APCI: %s", name
);
2441 list
= proto_item_add_subtree( node
, ett_cemi_apci
);
2442 proto_tree_add_item( list
, hf_cemi_ax
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
2447 pa_flags
= PA_RESPONSE
| PA_DATA
;
2451 case AX_UserMemRead
:
2453 case AX_RoutingTableRead
:
2454 case AX_RouterMemRead
:
2455 case AX_PropValueRead
:
2456 case AX_PropDescrRead
:
2457 case AX_IndAddrSerNumRead
:
2458 case AX_DomAddrSerNumRead
:
2459 case AX_PropExtValueRead
:
2460 case AX_PropExtDescrRead
:
2468 case AX_MemExtReadResp
:
2469 case AX_MemExtWrite
:
2470 case AX_MemExtWriteResp
:
2471 dissect_memory_ext_service( tvb
, pinfo
, cemi_node
, cemi_list
, ax
, &offset
, size
, &pa_flags
, &error
);
2474 case AX_UserMemRead
:
2475 case AX_UserMemResp
:
2476 case AX_UserMemWrite
:
2477 case AX_UserMemBitWrite
:
2478 dissect_user_memory_service( tvb
, pinfo
, tree
, cemi_node
, cemi_list
, &offset
, size
, &pa_flags
, &error
);
2481 case AX_FuncPropCmd
:
2482 case AX_FuncPropRead
:
2483 case AX_FuncPropResp
:
2484 dissect_function_property_service( tvb
, pinfo
, cemi_node
, cemi_list
, &offset
, size
, &error
);
2487 case AX_RoutingTableRead
:
2488 case AX_RouterMemRead
:
2489 case AX_RoutingTableResp
:
2490 case AX_RoutingTableWrite
:
2491 case AX_RouterMemResp
:
2492 case AX_RouterMemWrite
:
2493 case AX_MemBitWrite
:
2494 dissect_router_service( tvb
, pinfo
, tree
, cemi_node
, cemi_list
, &offset
, size
, &pa_flags
, &error
);
2501 dissect_authenticate_service( tvb
, pinfo
, tree
, cemi_node
, cemi_list
, ax
, &offset
, size
, &pa_flags
, &error
);
2504 case AX_PropValueRead
:
2505 case AX_PropValueResp
:
2506 case AX_PropValueWrite
:
2507 dissect_property_value_service( tvb
, pinfo
, cemi_node
, cemi_list
, &offset
, size
, &pa_flags
, &error
);
2510 case AX_PropDescrRead
:
2511 case AX_PropDescrResp
:
2512 dissect_property_description_service( tvb
, pinfo
, cemi_node
, cemi_list
, &offset
, size
, &pa_flags
, &error
);
2515 case AX_NwkParamRead
:
2516 case AX_NwkParamResp
:
2517 case AX_NwkParamWrite
:
2518 case AX_GroupPropValueRead
:
2519 case AX_GroupPropValueResp
:
2520 case AX_GroupPropValueWrite
:
2521 case AX_GroupPropValueInfo
:
2522 dissect_network_parameter_service( tvb
, pinfo
, cemi_node
, cemi_list
, &offset
, size
, &error
);
2525 case AX_IndAddrSerNumRead
:
2526 case AX_DomAddrSerNumRead
:
2527 case AX_IndAddrSerNumResp
:
2528 case AX_IndAddrSerNumWrite
:
2529 case AX_DomAddrSerNumResp
:
2530 case AX_DomAddrSerNumWrite
:
2531 dissect_ia_serial_number_service( tvb
, pinfo
, cemi_node
, cemi_list
, &offset
, size
, &pa_flags
, &error
);
2534 case AX_SysNwkParamRead
:
2535 case AX_SysNwkParamResp
:
2536 case AX_SysNwkParamWrite
:
2537 dissect_system_network_parameter_service( tvb
, pinfo
, cemi_node
, cemi_list
, &offset
, size
, &pa_flags
, &error
);
2540 case AX_PropExtValueRead
:
2541 case AX_PropExtValueResp
:
2542 case AX_PropExtValueWriteCon
:
2543 case AX_PropExtValueWriteConRes
:
2544 case AX_PropExtValueWriteUnCon
:
2545 dissect_property_ext_value_service( tvb
, pinfo
, cemi_node
, cemi_list
, &offset
, size
, &pa_flags
, &error
);
2548 case AX_PropExtDescrRead
:
2549 case AX_PropExtDescrResp
:
2550 dissect_property_ext_description_service( tvb
, pinfo
, cemi_node
, cemi_list
, &offset
, size
, &pa_flags
, &error
);
2553 case AX_FuncPropExtCmd
:
2554 case AX_FuncPropExtRead
:
2555 case AX_FuncPropExtResp
:
2557 /* 2 bytes OT, 12 bits OI, 12 bits PID */
2558 dissect_pid_ext( tvb
, pinfo
, cemi_node
, cemi_list
, &offset
, size
, &error
);
2562 dissect_data_security_service( tvb
, pinfo
, tree
, cemi_node
, cemi_list
, source_addr
, source_node
, dest_addr
, dest_node
, unicast
,
2563 name
, &offset
, size
, &pa_flags
, &error
);
2568 *p_pa_flags
= pa_flags
;
2572 /* Dissect simple AL service (4 bit AL service code)
2574 static void dissect_simple_app_service( tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* tree
, proto_item
* cemi_node
, proto_tree
* cemi_list
,
2575 uint8_t ac
, uint8_t ad
, int* p_offset
, int size
, uint8_t* p_pa_flags
, uint8_t* p_error
)
2577 column_info
* cinfo
= pinfo
->cinfo
;
2578 int offset
= *p_offset
;
2579 uint8_t pa_flags
= *p_pa_flags
;
2580 uint8_t error
= *p_error
;
2582 proto_item
* node
= NULL
;
2583 proto_tree
* list
= NULL
;
2588 const char* name
= val_to_str( ac
, ac_vals
, "AC=%u" );
2589 col_append_fstr( cinfo
, COL_INFO
, " %s", name
);
2592 proto_item_append_text( cemi_node
, ", %s", name
);
2593 node
= proto_tree_add_none_format( cemi_list
, hf_folder
, tvb
, offset
, 2, "APCI: %s", name
);
2594 list
= proto_item_add_subtree( node
, ett_cemi_apci
);
2595 proto_tree_add_item( list
, hf_cemi_ac
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
2602 case AC_GroupValueRead
:
2605 case AC_DevDescrRead
:
2612 case AC_GroupValueRead
:
2613 case AC_GroupValueResp
:
2614 case AC_GroupValueWrite
:
2617 uint8_t expected
= ((pa_flags
&& offset
+ 1 >= size
) || ac
== AC_Restart
);
2619 if( expected
|| ad
!= 0 )
2621 /* Show APCI 6-bit data
2627 else if( ad
!= 0 || ac
!= AC_Restart
|| offset
+ 1 < size
)
2629 col_append_fstr( cinfo
, COL_INFO
, " $%02X", ad
);
2630 proto_item_append_text( cemi_node
, " $%02X", ad
);
2635 node
= proto_tree_add_none_format( cemi_list
, hf_folder
, tvb
, offset
, 1, "Data: %02X", ad
);
2636 list
= proto_item_add_subtree( node
, ett_cemi_apci
);
2637 proto_tree_add_item( list
, hf_cemi_ad
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
2641 proto_item_prepend_text( node
, "? " );
2642 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: 0x00" );
2653 /* 6 bits Memory Length, 2 bytes Memory Address */
2654 if( offset
+ 3 > size
)
2656 node
= proto_tree_add_bytes_format( cemi_list
, hf_bytes
, tvb
, offset
+ 1, size
- offset
- 1, NULL
, "? Memory Address" );
2657 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: 2 bytes" );
2663 cc
= tvb_get_ntohs( tvb
, offset
+ 1 );
2665 col_append_fstr( cinfo
, COL_INFO
, " N=%u", ad
);
2666 col_append_fstr( cinfo
, COL_INFO
, " X=$%04X", cc
);
2670 proto_item_append_text( cemi_node
, ", N=%u", ad
);
2671 proto_item_append_text( cemi_node
, ", X=$%04X", cc
);
2672 node
= proto_tree_add_none_format( cemi_list
, hf_folder
, tvb
, offset
, 3, "Range: %u byte%s at address $%04X", ad
, (ad
== 1) ? "" : "s", cc
);
2673 list
= proto_item_add_subtree( node
, ett_cemi_range
);
2674 proto_tree_add_item( list
, hf_cemi_ad_memory_length
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
2675 proto_tree_add_item( list
, hf_cemi_memory_address
, tvb
, offset
+ 1, 2, ENC_BIG_ENDIAN
);
2684 /* 6 bits Channel */
2685 col_append_fstr( cinfo
, COL_INFO
, " #%u", ad
);
2688 proto_item_append_text( cemi_node
, " #%u", ad
);
2689 node
= proto_tree_add_none_format( cemi_list
, hf_folder
, tvb
, offset
, 1, "Channel: %u", ad
);
2690 list
= proto_item_add_subtree( node
, ett_cemi_apci
);
2691 proto_tree_add_item( list
, hf_cemi_ad_channel
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
2696 if( offset
>= size
)
2698 proto_tree_add_expert_format( cemi_list
, pinfo
, KIP_ERROR
, tvb
, offset
, 0, "? Count: expected 1 byte" );
2704 c
= tvb_get_uint8( tvb
, offset
);
2707 col_append_fstr( cinfo
, COL_INFO
, " N=%u", c
);
2708 proto_item_append_text( cemi_node
, ", N=%u", c
);
2710 proto_tree_add_item( cemi_list
, hf_cemi_adc_count
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
2714 case AC_DevDescrRead
:
2715 case AC_DevDescrResp
:
2717 /* 6 bits Descriptor Type */
2719 col_append_fstr( cinfo
, COL_INFO
, " #%u", ad
);
2723 proto_item_append_text( cemi_node
, " #%u", ad
);
2724 node
= proto_tree_add_none_format( cemi_list
, hf_folder
, tvb
, offset
, 1, "Descriptor Type: %u", ad
);
2725 list
= proto_item_add_subtree( node
, ett_cemi_apci
);
2726 proto_tree_add_item( list
, hf_cemi_ad_type
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
2734 col_append_fstr( cinfo
, COL_INFO
, " #%u", ad
);
2737 proto_item_append_text( cemi_node
, " #%u", ad
);
2738 proto_item_append_text( node
, " $%02X", ad
);
2739 proto_tree_add_item( list
, hf_cemi_ad
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
2747 *p_pa_flags
= pa_flags
;
2751 /* Dissect cEMI Application Layer
2753 static void dissect_cemi_app_layer( tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* tree
, proto_item
* cemi_node
, proto_tree
* cemi_list
,
2754 uint16_t source_addr
, proto_item
* source_node
, uint16_t dest_addr
, proto_item
* dest_node
, uint8_t unicast
,
2755 int* p_offset
, int size
, uint8_t* p_pa_flags
, uint8_t* p_error
)
2757 int offset
= *p_offset
;
2758 uint8_t pa_flags
= *p_pa_flags
;
2759 uint8_t error
= *p_error
;
2763 if( offset
+ 1 >= size
)
2765 proto_item
* node
= proto_tree_add_bytes_format( cemi_list
, hf_bytes
, tvb
, offset
, size
- offset
, NULL
, "? APCI" );
2766 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: 2 bytes" );
2772 /* Extract and split AL service code */
2773 uint8_t tb
= tvb_get_uint8( tvb
, offset
);
2774 uint8_t ab
= tvb_get_uint8( tvb
, offset
+ 1 );
2776 /* 4 bits simple AL service code */
2777 uint8_t ac
= ((tb
& 0x03) << 2) | ((ab
& 0xC0) >> 6);
2780 uint8_t ad
= ab
& 0x3F;
2782 /* 10 = 4 + 6 bits extended AL service code */
2783 uint16_t ax
= (ac
<< 6) | ad
;
2785 const char* name
= try_val_to_str( ax
, ax_vals
);
2787 if( name
) /* Extended AL code (10 bits) */
2789 dissect_extended_app_service( tvb
, pinfo
, tree
, cemi_node
, cemi_list
, source_addr
, source_node
, dest_addr
, dest_node
, unicast
,
2790 ax
, name
, &offset
, size
, &pa_flags
, &error
);
2792 else /* Simple AL code (4 bits) followed by data (6 bits) */
2794 dissect_simple_app_service( tvb
, pinfo
, tree
, cemi_node
, cemi_list
, ac
, ad
, &offset
, size
, &pa_flags
, &error
);
2799 *p_pa_flags
= pa_flags
;
2803 /* Dissect cEMI Transport Layer
2805 static void dissect_cemi_transport_layer( tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* tree
, proto_item
* cemi_node
, proto_tree
* cemi_list
,
2806 uint8_t is_tdata
, uint16_t source_addr
, proto_item
* source_node
, uint16_t dest_addr
, proto_item
* dest_node
, uint8_t unicast
,
2807 int* p_offset
, int size
, uint8_t* p_pa_flags
, uint8_t* p_error
)
2809 column_info
* cinfo
= pinfo
->cinfo
;
2810 int offset
= *p_offset
;
2811 uint8_t pa_flags
= *p_pa_flags
;
2812 uint8_t error
= *p_error
;
2820 if( offset
>= size
)
2822 proto_tree_add_expert_format( cemi_list
, pinfo
, KIP_ERROR
, tvb
, offset
, 0, "? TPCI: expected 1 byte" );
2827 uint8_t tb
= tvb_get_uint8( tvb
, offset
);
2828 proto_item
*tpci_node
= proto_tree_add_none_format( cemi_list
, hf_folder
, tvb
, offset
, 1, "TPCI" );
2829 proto_tree
*tpci_list
= proto_item_add_subtree( tpci_node
, ett_cemi_tpci
);
2830 uint8_t tpci_error
= 0;
2832 node
= proto_tree_add_item( tpci_list
, hf_cemi_tpt
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
2833 if( is_tdata
&& (tb
& 0x80) )
2835 proto_item_prepend_text( node
, "? " );
2836 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: zero" );
2840 node
= proto_tree_add_item( tpci_list
, hf_cemi_tst
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
2841 if( is_tdata
&& (tb
& 0x40) )
2843 proto_item_prepend_text( node
, "? " );
2844 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: zero" );
2848 c
= (tb
& 0x3C) >> 2;
2850 if( c
|| tb
& 0x40 ) /* Numbered Packet? */
2852 node
= proto_tree_add_item( tpci_list
, hf_cemi_num
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
2853 proto_item_append_text( tpci_node
, ", SeqNum = %u", c
);
2856 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: zero" );
2861 if( tb
& 0x80 ) /* Control Packet */
2863 /* 2 bits TPCI Code */
2864 uint8_t tc
= tb
& 0x03;
2865 name
= try_val_to_str( tc
, tc_vals
);
2868 snprintf( text
, sizeof text
, "TC=%u", tc
);
2871 col_append_fstr( cinfo
, COL_INFO
, " %s", name
);
2874 proto_item_append_text( cemi_node
, ", %s", name
);
2875 proto_item_append_text( tpci_node
, ": %s", name
);
2876 proto_tree_add_item( tpci_list
, hf_cemi_tc
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
2882 proto_item_prepend_text( tpci_node
, "? " );
2886 if( tb
& 0x80 ) /* Control Packet */
2891 else /* Data Packet */
2894 dissect_cemi_app_layer( tvb
, pinfo
, tree
, cemi_node
, cemi_list
, source_addr
, source_node
, dest_addr
, dest_node
, unicast
, &offset
, size
, &pa_flags
, &error
);
2899 *p_pa_flags
= pa_flags
;
2903 /* Dissect cEMI Link Layer
2904 (typically L_Data or T_Data)
2906 static void dissect_cemi_link_layer( tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* tree
, proto_item
* cemi_node
, proto_tree
* cemi_list
, uint8_t mc
, int* p_offset
, int size
, uint8_t* p_pa_flags
, uint8_t* p_error
)
2908 column_info
* cinfo
= pinfo
->cinfo
;
2909 int offset
= *p_offset
;
2910 uint8_t pa_flags
= *p_pa_flags
;
2911 uint8_t error
= *p_error
;
2913 proto_item
* node
= NULL
;
2914 proto_tree
* list
= NULL
;
2920 uint8_t is_tdata
= 0;
2921 uint8_t is_ldata
= 0;
2922 uint16_t source_addr
= 0;
2923 uint16_t dest_addr
= 0;
2924 uint8_t unicast
= 0;
2926 proto_item
* source_node
= NULL
;
2927 proto_item
* dest_node
= NULL
;
2929 proto_item
* ai_node
;
2930 proto_tree
* ai_list
;
2934 ai_list
= proto_tree_add_subtree( cemi_list
, tvb
, offset
, 0, ett_cemi_ai
, &ai_node
, "? Additional Info" );
2935 proto_tree_add_expert_format( ai_list
, pinfo
, KIP_ERROR
, tvb
, offset
, 0, "? Length: expected 1 byte" );
2941 /* Additional Information */
2942 uint8_t ai_len
= tvb_get_uint8( tvb
, 1 );
2943 int ai_end
= 2 + ai_len
;
2944 int ai_size
= ai_len
;
2953 ai_node
= proto_tree_add_none_format( cemi_list
, hf_folder
, tvb
, 1, ai_size
+ 1, "Additional Info (%u bytes)", ai_len
);
2954 ai_list
= proto_item_add_subtree( ai_node
, ett_cemi_ai
);
2955 node
= proto_tree_add_item( ai_list
, hf_cemi_ai_length
, tvb
, 1, 1, ENC_BIG_ENDIAN
);
2959 proto_item_prepend_text( node
, "? " );
2960 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Available: %d bytes", ai_size
);
2964 while( offset
< ai_end
)
2966 /* Additional Information Element */
2967 uint8_t aie_type
= tvb_get_uint8( tvb
, offset
);
2970 proto_item
*aie_node
;
2971 proto_tree
*aie_list
;
2973 name
= try_val_to_str( aie_type
, aiet_vals
);
2975 if( offset
+ 1 >= ai_end
)
2983 aie_len
= tvb_get_uint8( tvb
, offset
+ 1 );
2984 aie_size
= ai_end
- offset
- 2;
2985 if( aie_size
< aie_len
)
2996 aie_node
= proto_tree_add_none_format( ai_list
, hf_folder
, tvb
, offset
, aie_size
, "Additional Info: %s", name
? name
: "?" );
2997 aie_list
= proto_item_add_subtree( aie_node
, ett_cemi_aie
);
2998 node
= proto_tree_add_item( aie_list
, hf_cemi_aie_type
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
2999 if( name
) proto_item_append_text( node
, " = %s", name
);
3004 proto_item_prepend_text( aie_node
, "? " );
3005 proto_tree_add_expert_format( aie_list
, pinfo
, KIP_ERROR
, tvb
, offset
, 0, "? Length: expected 1 byte" );
3009 proto_item_append_text( aie_node
, " (%u bytes)", aie_len
);
3010 node
= proto_tree_add_item( aie_list
, hf_cemi_aie_length
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
3015 proto_item_prepend_text( aie_node
, "? " );
3016 proto_item_prepend_text( node
, "? " );
3017 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Available: %d bytes", aie_size
- 2 );
3023 proto_tree_add_data( aie_list
, tvb
, offset
, aie_len
, NULL
, NULL
, "Data", NULL
, NULL
);
3028 proto_item_prepend_text( aie_node
, "? " );
3029 proto_item_append_text( node
, " (?)" );
3030 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: >= 1 byte(s)" );
3037 proto_item_prepend_text( ai_node
, "? " );
3045 case CEMI_L_BUSMON_IND
:
3046 case CEMI_L_RAW_IND
:
3047 case CEMI_L_RAW_REQ
:
3048 case CEMI_L_RAW_CON
:
3055 case CEMI_L_DATA_REQ
:
3056 case CEMI_L_DATA_CON
:
3057 case CEMI_L_DATA_IND
:
3061 case CEMI_T_DATA_INDIVIDUAL_REQ
:
3062 case CEMI_T_DATA_INDIVIDUAL_IND
:
3063 case CEMI_T_DATA_CONNECTED_REQ
:
3064 case CEMI_T_DATA_CONNECTED_IND
:
3071 int length
= (size
>= offset
+ 6) ? 6 : size
- offset
;
3072 node
= proto_tree_add_bytes_format( cemi_list
, hf_bytes
, tvb
, offset
, length
, NULL
, "Reserved" );
3075 proto_item_prepend_text( node
, "? " );
3076 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: 6 bytes" );
3082 for( ; pos
< 6; pos
++ )
3084 if( tvb_get_uint8( tvb
, offset
+ pos
) != 0 )
3086 proto_item_prepend_text( node
, "? " );
3087 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: zero" );
3099 /* 1 byte Control Field 1 */
3100 if( offset
>= size
)
3102 proto_tree_add_expert_format( cemi_list
, pinfo
, KIP_ERROR
, tvb
, offset
, 0, "? Ctrl1: expected 1 byte" );
3109 c
= tvb_get_uint8( tvb
, offset
);
3110 proto_item_append_text( cemi_node
, ", " );
3111 node
= proto_tree_add_none_format( cemi_list
, hf_folder
, tvb
, offset
, 1, "Ctrl1: " );
3114 proto_item_append_text( cemi_node
, "X " );
3115 proto_item_append_text( node
, "Extended, " );
3119 proto_item_append_text( cemi_node
, "R " );
3120 proto_item_append_text( node
, "Repeat On Error, " );
3124 proto_item_append_text( cemi_node
, "B " );
3125 proto_item_append_text( node
, "System Broadcast, " );
3129 proto_item_append_text( cemi_node
, "A " );
3130 proto_item_append_text( node
, "Ack Wanted, " );
3134 proto_item_append_text( cemi_node
, "C " );
3135 proto_item_append_text( node
, "Unconfirmed, " );
3138 name
= try_val_to_str( (c
& 0x0C) >> 2, prio_vals
);
3141 proto_item_append_text( cemi_node
, "P=%s", name
);
3142 proto_item_append_text( node
, "Prio = %s", name
);
3143 list
= proto_item_add_subtree( node
, ett_cemi_ctrl1
);
3144 proto_tree_add_item( list
, hf_cemi_ft
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
3145 proto_tree_add_item( list
, hf_cemi_rep
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
3146 proto_tree_add_item( list
, hf_cemi_bt
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
3147 proto_tree_add_item( list
, hf_cemi_prio
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
3148 proto_tree_add_item( list
, hf_cemi_ack
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
3149 proto_tree_add_item( list
, hf_cemi_ce
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
3155 /* 1 byte Control Field 2 */
3156 if( offset
>= size
)
3158 proto_tree_add_expert_format( cemi_list
, pinfo
, KIP_ERROR
, tvb
, offset
, 0, "? Ctrl2: expected 1 byte" );
3163 c
= tvb_get_uint8( tvb
, offset
);
3165 unicast
= !(c
& 0x80); /* Address Type (IA or GA) */
3169 uint8_t hc
= (c
& 0x70) >> 4; /* Hop Count */
3170 uint8_t eff
= c
& 0x0F; /* Extended Frame Format (0 = standard) */
3172 snprintf( text
, sizeof text
, "%u", (c
& 0x70) >> 4 ); /* hop count */
3173 proto_item_append_text( cemi_node
, ", H=%u", hc
);
3174 node
= proto_tree_add_none_format( cemi_list
, hf_folder
, tvb
, offset
, 1, "Ctrl2: Hops = %u", hc
);
3177 proto_item_append_text( cemi_node
, " F=%u", eff
);
3178 proto_item_append_text( cemi_node
, " Frame = %u", eff
);
3180 list
= proto_item_add_subtree( node
, ett_cemi_ctrl2
);
3181 proto_tree_add_item( list
, hf_cemi_at
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
3182 proto_tree_add_item( list
, hf_cemi_hc
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
3183 proto_tree_add_item( list
, hf_cemi_eff
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
3189 /* 2 bytes Source Address */
3190 if( offset
+ 1 >= size
)
3192 node
= proto_tree_add_bytes_format( cemi_list
, hf_bytes
, tvb
, offset
, size
- offset
, NULL
, "? Source" );
3193 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: 2 bytes" );
3199 source_addr
= tvb_get_ntohs( tvb
, offset
);
3200 snprintf( text
, sizeof text
, "%u.%u.%u", (source_addr
>> 12) & 0xF, (source_addr
>> 8) & 0xF, source_addr
& 0xFF );
3201 col_append_fstr( cinfo
, COL_INFO
, " %s", text
);
3204 proto_item_append_text( cemi_node
, ", Src=%s", text
);
3205 source_node
= proto_tree_add_item( cemi_list
, hf_cemi_sa
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
3206 proto_item_append_text( source_node
, " = %s", text
);
3212 /* 2 bytes Destination Address */
3213 if( offset
+ 1 >= size
)
3215 node
= proto_tree_add_bytes_format( cemi_list
, hf_bytes
, tvb
, offset
, size
- offset
, NULL
, "? Destination" );
3216 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Expected: 2 bytes" );
3222 dest_addr
= tvb_get_ntohs( tvb
, offset
);
3226 /* Individual Address */
3227 snprintf( text
, sizeof text
, "%u.%u.%u", (dest_addr
>> 12) & 0xF, (dest_addr
>> 8) & 0xF, dest_addr
& 0xFF );
3232 snprintf( text
, sizeof text
, "%u/%u/%u", (dest_addr
>> 11) & 0x1F, (dest_addr
>> 8) & 0x7, dest_addr
& 0xFF );
3235 col_append_fstr( cinfo
, COL_INFO
, "->%s", text
);
3239 proto_item_append_text( cemi_node
, ", Dst=%s", text
);
3240 dest_node
= proto_tree_add_item( cemi_list
, hf_cemi_da
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
3241 proto_item_append_text( dest_node
, " = %s", text
);
3248 if( is_ldata
|| is_tdata
)
3250 /* 1 byte NPDU Length */
3251 if( offset
>= size
)
3253 proto_tree_add_expert_format( cemi_list
, pinfo
, KIP_ERROR
, tvb
, offset
, 0, "? Length: expected 1 byte" );
3258 uint8_t data_len
= tvb_get_uint8( tvb
, offset
);
3259 node
= proto_tree_add_item( cemi_list
, hf_cemi_len
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
3261 if( offset
+ 2 + data_len
!= size
)
3263 proto_item_prepend_text( node
, "? " );
3264 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Available: %d bytes", size
- offset
- 2 );
3272 dissect_cemi_transport_layer( tvb
, pinfo
, tree
, cemi_node
, cemi_list
, is_tdata
, source_addr
, source_node
, dest_addr
, dest_node
, unicast
, &offset
, size
, &pa_flags
, &error
);
3279 *p_pa_flags
= pa_flags
;
3283 static int dissect_cemi( tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* tree
, void* data _U_
)
3286 int size
= tvb_captured_length_remaining( tvb
, 0 );
3288 column_info
* cinfo
= pinfo
->cinfo
;
3290 /* cEMI node in tree view */
3291 proto_item
* cemi_node
= proto_tree_add_item( tree
, proto_cemi
, tvb
, 0, size
, ENC_BIG_ENDIAN
);
3293 /* Subnodes of cEMI node */
3294 proto_tree
* cemi_list
= proto_item_add_subtree( cemi_node
, ett_cemi
);
3296 uint8_t pa_flags
= PA_DATA
;
3298 /* Only add cEMI information to the info column (not replacing it).
3299 This means that we do not have to clear that column here, but
3300 are adding a seperator here.
3302 col_append_str( cinfo
, COL_INFO
, " " );
3304 /* Replace long name "Common External Message Interface" by short name "cEMI" */
3305 proto_item_set_text( cemi_node
, "cEMI" );
3309 expert_add_info_format( pinfo
, cemi_node
, KIP_ERROR
, "Expected: min 1 byte" );
3314 /* 1 byte cEMI Message Code */
3315 uint8_t mc
= tvb_get_uint8( tvb
, 0 );
3316 const char* name
= try_val_to_str( mc
, mc_vals
);
3320 /* Unknown Message Code */
3321 col_append_str( cinfo
, COL_INFO
, "cEMI" );
3326 /* Add cEMI message code to info column */
3327 col_append_str( cinfo
, COL_INFO
, name
);
3329 /* Show MC in cEMI node, and more detailed in a subnode */
3330 proto_item_append_text( cemi_node
, " %s", name
);
3331 proto_tree_add_item( cemi_list
, hf_cemi_mc
, tvb
, 0, 1, ENC_BIG_ENDIAN
);
3337 /* cEMI Management packet */
3338 dissect_cemi_mgmt_packet( tvb
, pinfo
, cemi_node
, cemi_list
, mc
, &offset
, size
, &pa_flags
, &error
);
3342 /* cEMI Link Layer packet */
3343 dissect_cemi_link_layer( tvb
, pinfo
, tree
, cemi_node
, cemi_list
, mc
, &offset
, size
, &pa_flags
, &error
);
3351 proto_item
* node
= proto_tree_add_data( cemi_list
, tvb
, offset
, size
- offset
, cinfo
, cemi_node
, "Data", " $", ", $" );
3355 proto_item_prepend_text( node
, "? " );
3356 expert_add_info_format( pinfo
, node
, KIP_ERROR
, "Unexpected" );
3365 /* If not already done */
3369 col_prepend_fstr( cinfo
, COL_INFO
, "? " );
3372 proto_item_prepend_text( cemi_node
, "? " );
3378 void proto_register_cemi( void )
3381 static hf_register_info hf
[] = {
3382 { &hf_bytes
, { "Data", "cemi.data", FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
} },
3383 { &hf_folder
, { "Folder", "cemi.folder", FT_NONE
, BASE_NONE
, NULL
, 0, NULL
, HFILL
} },
3384 { &hf_cemi_mc
, { "Message Code", "cemi.mc", FT_UINT8
, BASE_HEX
, VALS( mc_vals
), 0, NULL
, HFILL
} },
3385 { &hf_cemi_error
, { "Error", "cemi.e", FT_UINT8
, BASE_HEX
, NULL
, 0, NULL
, HFILL
} },
3386 { &hf_cemi_ai_length
, { "Additional Information Length", "cemi.ai.n", FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
3387 { &hf_cemi_aie_type
, { "Additional Information Element Type", "cemi.ait.n", FT_UINT8
, BASE_HEX
, NULL
, 0, NULL
, HFILL
} },
3388 { &hf_cemi_aie_length
, { "Additional Information Element Length", "cemi.aie.n", FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
3389 { &hf_cemi_ot
, { "Object Type", "cemi.ot", FT_UINT16
, BASE_DEC
, VALS( ot_vals
), 0, NULL
, HFILL
} },
3390 { &hf_cemi_oi
, { "Object Instance", "cemi.oi", FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
3391 { &hf_cemi_ox
, { "Object Index", "cemi.ox", FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
3392 { &hf_cemi_px
, { "Property Index", "cemi.px",FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
3393 { &hf_cemi_pid
, { "Property ID", "cemi.pid", FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
3394 { &hf_cemi_ne
, { "Count", "cemi.n", FT_UINT8
, BASE_DEC
, NULL
, 0xF0, NULL
, HFILL
} },
3395 { &hf_cemi_sx
, { "Index", "cemi.x", FT_UINT16
, BASE_DEC
, NULL
, 0x0FFF, NULL
, HFILL
} },
3396 { &hf_cemi_ft
, { "Frame Type", "cemi.ft", FT_UINT8
, BASE_DEC
, VALS( ft_vals
), 0x80, NULL
, HFILL
} },
3397 { &hf_cemi_rep
, { "Repeat On Error", "cemi.rep", FT_BOOLEAN
, 8, TFS(&tfs_no_yes
), 0x20, NULL
, HFILL
} },
3398 { &hf_cemi_bt
, { "Broadcast Type", "cemi.bt", FT_UINT8
, BASE_DEC
, VALS( bt_vals
), 0x10, NULL
, HFILL
} },
3399 { &hf_cemi_prio
, { "Priority", "cemi.prio", FT_UINT8
, BASE_DEC
, VALS( prio_vals
), 0x0C, NULL
, HFILL
} },
3400 { &hf_cemi_ack
, { "Ack Wanted", "cemi.ack", FT_BOOLEAN
, 8, TFS(&tfs_no_yes
), 0x02, NULL
, HFILL
} },
3401 { &hf_cemi_ce
, { "Confirmation Error", "cemi.ce", FT_BOOLEAN
, 8, TFS(&tfs_no_yes
), 0x01, NULL
, HFILL
} },
3402 { &hf_cemi_at
, { "Address Type", "cemi.at", FT_UINT8
, BASE_DEC
, VALS( at_vals
), 0x80, NULL
, HFILL
} },
3403 { &hf_cemi_hc
, { "Hop Count", "cemi.hc", FT_UINT8
, BASE_DEC
, NULL
, 0x70, NULL
, HFILL
} },
3404 { &hf_cemi_eff
, { "Extended Frame Format", "cemi.eff", FT_UINT8
, BASE_HEX
, NULL
, 0x0F, NULL
, HFILL
} },
3405 { &hf_cemi_sa
, { "Source", "cemi.sa", FT_UINT16
, BASE_HEX
, NULL
, 0, NULL
, HFILL
} },
3406 { &hf_cemi_da
, { "Destination", "cemi.da", FT_UINT16
, BASE_HEX
, NULL
, 0, NULL
, HFILL
} },
3407 { &hf_cemi_len
, { "Length", "cemi.len", FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
3408 { &hf_cemi_tpt
, { "Packet Type", "cemi.tpt", FT_UINT8
, BASE_DEC
, VALS( pt_vals
), 0x80, NULL
, HFILL
} },
3409 { &hf_cemi_tst
, { "Sequence Type", "cemi.st", FT_UINT8
, BASE_DEC
, VALS( st_vals
), 0x40, NULL
, HFILL
} },
3410 { &hf_cemi_num
, { "Sequence Number", "cemi.num", FT_UINT8
, BASE_DEC
, NULL
, 0x3C, NULL
, HFILL
} },
3411 { &hf_cemi_tc
, { "Service", "cemi.tc", FT_UINT8
, BASE_HEX
, VALS( tc_vals
), 0x03, NULL
, HFILL
} },
3412 { &hf_cemi_ac
, { "Service", "cemi.ac", FT_UINT16
, BASE_HEX
, VALS( ac_vals
), 0x03C0, NULL
, HFILL
} },
3413 { &hf_cemi_ad
, { "Data", "cemi.ad", FT_UINT8
, BASE_HEX
, NULL
, 0x3F, NULL
, HFILL
} },
3414 { &hf_cemi_ad_memory_length
, { "Memory Length", "cemi.ad.ml", FT_UINT8
, BASE_HEX
, NULL
, 0x3F, NULL
, HFILL
} },
3415 { &hf_cemi_ad_channel
, { "Channel", "cemi.ad.ch", FT_UINT8
, BASE_HEX
, NULL
, 0x3F, NULL
, HFILL
} },
3416 { &hf_cemi_ad_type
, { "Data", "cemi.ad.type", FT_UINT8
, BASE_HEX
, NULL
, 0x3F, NULL
, HFILL
} },
3417 { &hf_cemi_ax
, { "Service", "cemi.ax", FT_UINT16
, BASE_HEX
, VALS( ax_vals
), 0x03FF, NULL
, HFILL
} },
3418 { &hf_cemi_pw
, { "Writable", "cemi.pw", FT_UINT8
, BASE_DEC
, NULL
, 0x80, NULL
, HFILL
} },
3419 { &hf_cemi_pdt
, { "Property Data Type", "cemi.pdt", FT_UINT8
, BASE_HEX
, VALS( pdt_vals
), 0x3F, NULL
, HFILL
} },
3420 { &hf_cemi_me
, { "Max Elements", "cemi.me", FT_UINT16
, BASE_DEC
, NULL
, 0x0FFF, NULL
, HFILL
} },
3421 { &hf_cemi_ra
, { "Read Access", "cemi.ra", FT_UINT8
, BASE_DEC
, NULL
, 0xF0, NULL
, HFILL
} },
3422 { &hf_cemi_wa
, { "Write Access", "cemi.wa", FT_UINT8
, BASE_DEC
, NULL
, 0x0F, NULL
, HFILL
} },
3423 { &hf_cemi_ext_oi
, { "Object Instance", "cemi.oi", FT_UINT16
, BASE_DEC
, NULL
, 0xFFF0, NULL
, HFILL
} },
3424 { &hf_cemi_ext_pid
, { "Property ID", "cemi.pid", FT_UINT16
, BASE_DEC
, NULL
, 0x0FFF, NULL
, HFILL
} },
3425 { &hf_cemi_ext_ne
, { "Count", "cemi.n", FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
3426 { &hf_cemi_ext_sx
, { "Index", "cemi.x", FT_UINT16
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
3427 { &hf_cemi_ext_dt
, { "Description Type", "cemi.dt", FT_UINT8
, BASE_DEC
, NULL
, 0xF0, NULL
, HFILL
} },
3428 { &hf_cemi_ext_px
, { "Property Index", "cemi.px", FT_UINT16
, BASE_DEC
, NULL
, 0x0FFF, NULL
, HFILL
} },
3429 { &hf_cemi_ext_memory_length
, { "Memory Length", "cemi.n", FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
3430 { &hf_cemi_ext_memory_address
, { "Memory Address", "cemi.x", FT_UINT16
, BASE_HEX
, NULL
, 0, NULL
, HFILL
} },
3431 { &hf_cemi_memory_length
, { "Memory Length", "cemi.n", FT_UINT8
, BASE_DEC
, NULL
, 0x0F, NULL
, HFILL
} },
3432 { &hf_cemi_memory_address
, { "Memory Address", "cemi.x", FT_UINT16
, BASE_HEX
, NULL
, 0, NULL
, HFILL
} },
3433 { &hf_cemi_memory_address_ext
, { "Memory Address Extension", "cemi.xx", FT_UINT8
, BASE_HEX
, NULL
, 0xF0, NULL
, HFILL
} },
3434 { &hf_cemi_level
, { "Level", "cemi.level", FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
3435 { &hf_cemi_snp_pid
, { "Property ID", "cemi.pid", FT_UINT16
, BASE_DEC
, NULL
, 0xFFF0, NULL
, HFILL
} },
3436 { &hf_cemi_snp_reserved
, { "Reserved", "cemi.reserved", FT_UINT16
, BASE_DEC
, NULL
, 0x0F, NULL
, HFILL
} },
3437 { &hf_cemi_dpt_major
, { "Data Point Type Major", "cemi.pdt.major", FT_UINT16
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
3438 { &hf_cemi_dpt_minor
, { "Data Point Type Minor", "cemi.pdt.minor", FT_UINT16
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
3439 { &hf_cemi_scf
, { "Security Control Field", "cemi.scf", FT_UINT8
, BASE_HEX
, VALS( scf_vals
), 0, NULL
, HFILL
} },
3440 { &hf_cemi_scf_t
, { "Tool Access", "cemi.scf.t", FT_UINT8
, BASE_DEC
, NULL
, 0x80, NULL
, HFILL
} },
3441 { &hf_cemi_scf_sai
, { "Security Algorithm Identifier", "cemi.scf.sai", FT_UINT8
, BASE_HEX
, VALS( scf_sai_vals
), 0x70, NULL
, HFILL
} },
3442 { &hf_cemi_scf_sbc
, { "System Broadcast", "cemi.scf.sbc", FT_UINT8
, BASE_DEC
, NULL
, 0x08, NULL
, HFILL
} },
3443 { &hf_cemi_scf_svc
, { "Service", "cemi.scf.svc", FT_UINT8
, BASE_HEX
, VALS( scf_svc_vals
), 0x07, NULL
, HFILL
} },
3444 { &hf_cemi_adc_count
, { "Count", "cemi.adc.n", FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
3448 static int *ett
[] = {
3463 proto_cemi
= proto_register_protocol( "Common External Message Interface", "cEMI", "cemi" );
3465 proto_register_field_array( proto_cemi
, hf
, array_length( hf
) );
3466 proto_register_subtree_array( ett
, array_length( ett
) );
3468 register_dissector( "cemi", dissect_cemi
, proto_cemi
);
3471 void proto_reg_handoff_cemi( void )
3476 * Editor modelines - https://www.wireshark.org/tools/modelines.html
3481 * indent-tabs-mode: nil
3484 * vi: set shiftwidth=2 tabstop=8 expandtab:
3485 * :indentSize=2:tabSize=8:noTabs=true: