Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-cemi.c
blob321b6a54ad3052706f452bc5f2e51e6607c1c015
1 /* packet-cemi.c
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
13 #include "config.h"
15 #include <epan/packet.h>
16 #include <epan/tfs.h>
17 #include "packet-knxip.h"
19 void proto_register_cemi(void);
20 void proto_reg_handoff_cemi(void);
22 /* cEMI Message Codes
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
50 /* 0x00 Reserved. */
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). */
60 /* Error Codes
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.
89 DPT_Enable O - r/w */
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 */
94 /* 0x59 t.b.d.*/
95 /* 0x60 t.b.d.*/
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.
125 static int hf_bytes;
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
193 static int ett_cemi;
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"
217 /* Message Code
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" },
243 { 0, NULL }
246 /* Property access flags
248 #define PA_RESPONSE 0x01
249 #define PA_DATA 0x02
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" },
260 { 7, "BiBat Info" },
261 { 0, NULL }
264 /* Frame Type
266 static const value_string ft_vals[] = {
267 { 0, "Extended" },
268 { 1, "Standard" },
269 { 0, NULL }
272 /* Broadcast Type
274 static const value_string bt_vals[] = {
275 { 0, "System" },
276 { 1, "Domain" },
277 { 0, NULL }
280 /* Priority
282 static const value_string prio_vals[] = {
283 { 0, "System" },
284 { 2, "Urgent" },
285 { 1, "Normal" },
286 { 3, "Low" },
287 { 0, NULL }
290 /* Address Type
292 static const value_string at_vals[] = {
293 { 0, "Individual" },
294 { 1, "Group" },
295 { 0, NULL }
298 /* Packet Type
300 static const value_string pt_vals[] = {
301 { 0, "Data" },
302 { 1, "Control" },
303 { 0, NULL }
306 /* Sequence Type
308 static const value_string st_vals[] = {
309 { 0, "Unnumbered" },
310 { 1, "Numbered" },
311 { 0, NULL }
314 /* Transport Layer Code
316 static const value_string tc_vals[] = {
317 { 0, "Connect" },
318 { 1, "Disconnect" },
319 { 2, "ACK" },
320 { 3, "NAK" },
321 { 0, NULL }
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
332 #define AC_AdcRead 6
333 #define AC_AdcResp 7
334 #define AC_MemRead 8
335 #define AC_MemResp 9
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
341 #define AC_Escape 15
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" },
361 { 0, NULL }
364 /* Extended AL codes
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" },
512 { 0, NULL }
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" },
535 { 0, NULL }
538 /* SCF (Security Control Field).
540 static const value_string scf_short_vals[] =
542 { 0x00, "Data+A" },
543 { 0x10, "Data+A+C" },
544 { 0x12, "SyncReq" },
545 { 0x13, "SyncRes" },
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" },
558 { 0, NULL }
561 /* SCF.SAI (Security Algorithm Identifier)
563 static const value_string scf_sai_vals[] =
565 { 0, "CCM A" },
566 { 1, "CCM A+S" },
567 { 0, NULL }
570 /* SCF.Service
572 static const value_string scf_svc_vals[] =
574 { 0, "Data" },
575 { 2, "Sync_Req" },
576 { 3, "Sync_Res" },
577 { 0, NULL }
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" },
592 { 0x03, "PDT_INT" },
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" },
638 { 0, NULL }
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[] = {
645 { 0, "Device" },
646 { 1, "Address Table" },
647 { 2, "Association Table" },
648 { 3, "Application Program" },
649 { 4, "Interface Program" },
650 { 5, "KNX-Object Association Table" },
651 { 6, "Router" },
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" },
659 { 0, NULL }
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" },
687 { 23, "PID_TABLE" },
688 { 24, "PID_ENROL" },
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" },
695 { 0, NULL }
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" },
739 { 0, NULL }
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" },
750 { 0, NULL }
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" },
773 { 0, NULL }
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" },
782 { 0, NULL }
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" },
800 { 0, NULL }
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" },
809 { 0, NULL }
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" },
833 { 67, "PID_TTL" },
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" },
851 { 0, NULL }
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" },
870 { 0, NULL }
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 );
885 while( length > 0 )
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 );
891 offset++;
892 length--;
895 return new_item;
898 static const char* get_pid_name( int ot, int pid )
900 if( pid <= 50 )
902 return try_val_to_str( pid, pid_vals );
905 const value_string* vals = NULL;
906 switch( ot )
908 case 0:
909 vals = pid0_vals;
910 break;
911 case 1:
912 vals = pid1_vals;
913 break;
914 case 6:
915 vals = pid6_vals;
916 break;
917 case 7:
918 vals = pid7_vals;
919 break;
920 case 8:
921 vals = pid8_vals;
922 break;
923 case 9:
924 vals = pid9_vals;
925 break;
926 case 11:
927 vals = pid11_vals;
928 break;
929 case 17:
930 vals = pid17_vals;
931 break;
933 if( vals )
935 return try_val_to_str( pid, vals );
938 return NULL;
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;
950 int a_length = 0;
951 int p_length = 0;
953 uint8_t* decrypted = NULL;
955 if( encrypted_size > 4 ) // contains 4 bytes MAC
957 if( cemi_size >= 2 )
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 ];
966 // Get A and P.
967 if( (scf & 0x30) == 0x10 ) // A+C
969 p_bytes = encrypted;
970 p_length = encrypted_size - 4;
973 // Build b_0.
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 ];
988 b_0[ 14 ] = 0;
989 b_0[ 15 ] = (uint8_t) p_length;
991 // Build ctr_0.
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 ];
1002 ctr_0[ 10 ] = 0;
1003 ctr_0[ 11 ] = 0;
1004 ctr_0[ 12 ] = 0;
1005 ctr_0[ 13 ] = 0;
1006 ctr_0[ 14 ] = 0x01;
1007 ctr_0[ 15 ] = 0;
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
1014 a_bytes[ 0 ] = scf;
1015 a_length = 1;
1016 p_bytes = decrypted;
1017 p_length = encrypted_size - 4;
1019 else if( (scf & 0x30) == 0x00 ) // A
1021 a_bytes[ 0 ] = scf;
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 );
1033 decrypted = NULL;
1039 return 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;
1061 // Get context info
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
1072 if( multicast )
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 )
1081 keys_found = 1;
1082 key = ga_key->key;
1083 decrypted = decrypt_data_security_data_with_key( pool, key, encrypted, encrypted_size, cemi, cemi_size );
1085 if( decrypted )
1087 snprintf( output, output_max, "GA " );
1088 while( *output ) { ++output; --output_max; }
1089 break;
1094 else
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 )
1103 keys_found = 1;
1104 key = ia_key->key;
1105 decrypted = decrypt_data_security_data_with_key( pool, key, encrypted, encrypted_size, cemi, cemi_size );
1107 if( decrypted )
1109 snprintf( output, output_max, "dest IA " );
1110 while( *output ) { ++output; --output_max; }
1111 break;
1117 if( !decrypted )
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 )
1126 keys_found = 1;
1127 key = ia_key->key;
1128 decrypted = decrypt_data_security_data_with_key( pool, key, encrypted, encrypted_size, cemi, cemi_size );
1130 if( decrypted )
1132 snprintf( output, output_max, "source IA " );
1133 while( *output ) { ++output; --output_max; }
1134 break;
1140 if( !decrypted && knx_decryption_key_count )
1142 // Try all explicitly specified keys
1143 uint8_t key_index;
1145 for( key_index = 0; key_index < knx_decryption_key_count; ++key_index )
1147 keys_found = 1;
1148 key = knx_decryption_keys[ key_index ];
1149 decrypted = decrypt_data_security_data_with_key( pool, key, encrypted, encrypted_size, cemi, cemi_size );
1151 if( decrypted )
1153 break;
1158 if( decrypted )
1160 uint8_t count;
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++ );
1170 else
1172 snprintf( info->output_text, sizeof info->output_text, keys_found ? "failed" : "no keys found" );
1175 return decrypted;
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;
1194 return ox;
1197 proto_tree_add_expert_format( list, pinfo, KIP_ERROR, tvb, offset, 0, "? Object Index: expected 1 byte" );
1199 if( p_error )
1201 *p_error = 1;
1204 return 0;
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 );
1222 offset += 2;
1224 *p_offset = offset;
1225 return ot;
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" );
1231 if( p_error )
1233 *p_error = 1;
1236 *p_offset = end_pos;
1237 return 0;
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;
1250 const char* name;
1252 if( pid || show )
1254 col_append_fstr( cinfo, COL_INFO, " P=%u", pid );
1255 proto_item_append_text( node, ", PID=%u", pid );
1258 if( list )
1260 node = proto_tree_add_item( list, hf_cemi_pid, tvb, offset, 1, ENC_BIG_ENDIAN );
1261 name = get_pid_name( ot, pid );
1262 if( name )
1264 proto_item_append_text( node, " = %s", name );
1268 *p_offset = ++offset;
1269 return pid;
1272 proto_tree_add_expert_format( list, pinfo, KIP_ERROR, tvb, offset, 0, "? Property ID: expected 1 byte" );
1274 if( p_error )
1276 *p_error = 1;
1279 return 0;
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 );
1292 if( show )
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;
1302 return px;
1305 proto_tree_add_expert_format( list, pinfo, KIP_ERROR, tvb, offset, 0, "? Property Index: expected 1 byte" );
1307 if( p_error )
1309 *p_error = 1;
1312 return 0;
1315 /* Dissect Property Range (2 bytes: Number Of Elements (4 bits), Start Index (12 bits))
1316 and subsequent Data
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;
1321 uint8_t error = 0;
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;
1329 error = 1;
1331 else
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;
1337 sx &= 0x0FFF;
1339 /* 4 bits Number Of Elements */
1340 if( ne != 1 )
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) )
1347 error = 1;
1349 else if( sx == 0 )
1351 error = 2;
1355 /* 12 bits Start Index */
1356 if( sx != 1 )
1358 col_append_fstr( cinfo, COL_INFO, " X=%u", sx );
1359 proto_item_append_text( node, ", X=%u", sx );
1362 if( list )
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 );
1370 if( error )
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 );
1381 offset += 2;
1383 /* Data */
1385 int length = end_pos - offset;
1386 if( length > 0 )
1388 node = proto_tree_add_data( list, tvb, offset, length, cinfo, cemi_node, "Data", " $", ", $" );
1389 if( !pa_flags )
1391 proto_item_prepend_text( node, "? " );
1392 expert_add_info_format( pinfo, node, KIP_ERROR, "Unexpected" );
1393 error = 1;
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" );
1399 error = 1;
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" );
1407 error = 1;
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 );
1413 error = 1;
1419 *p_offset = end_pos;
1422 if( error && p_error )
1424 *p_error = 1;
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;
1434 uint8_t error = 0;
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" );
1442 error = 1;
1443 offset = size;
1445 else
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;
1450 pdt &= 0x3F;
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;
1456 if( me != 1 )
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;
1465 wa &= 0x0F;
1466 col_append_fstr( cinfo, COL_INFO, " R=%u", ra );
1467 if( writable )
1468 col_append_fstr( cinfo, COL_INFO, " W=%u", wa );
1469 proto_item_append_text( cemi_node, ", R=%u", ra );
1470 if( writable )
1471 proto_item_append_text( cemi_node, ", W=%u", wa );
1473 if( cemi_list )
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 );
1479 if( pdt_name )
1480 proto_item_append_text( pd_node, "%s", pdt_name );
1481 else
1482 proto_item_append_text( pd_node, "PDT = 0x%02X", pdt );
1484 if( me != 1 )
1485 proto_item_append_text( pd_node, ", Max Elements = %u", me );
1487 proto_item_append_text( pd_node, ", Read = %u", ra );
1488 if( writable )
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 );
1498 offset += 4;
1501 if( error && p_error )
1503 *p_error = 1;
1506 *p_offset = offset;
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;
1515 uint8_t error = 0;
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" );
1525 error = 1;
1526 offset = size;
1528 else
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 );
1535 ++offset;
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 );
1542 if( cemi_list )
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 );
1546 if( name )
1548 proto_item_append_text( node, " = %s", name );
1552 offset += 2;
1555 if( error && p_error )
1557 *p_error = 1;
1560 *p_offset = offset;
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;
1575 switch( mc )
1577 case CEMI_M_PROPREAD_REQ:
1578 pa_flags = 0;
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;
1593 case_CEMI_M_PROP:
1594 min_size = 7;
1595 break;
1597 case CEMI_M_FUNCPROPCMD_REQ:
1598 case CEMI_M_FUNCPROPREAD_REQ:
1599 case CEMI_M_FUNCPROP_CON:
1600 //pa_flags = PA_DATA;
1601 min_size = 5;
1602 break;
1604 case CEMI_M_RESET_REQ:
1605 case CEMI_M_RESET_IND:
1606 pa_flags = 0;
1607 break;
1610 if( min_size >= 5 )
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 */
1616 if( size < 4 )
1618 proto_tree_add_expert_format( cemi_list, pinfo, KIP_ERROR, tvb, offset, 0, "? Object Instance: expected 1 byte" );
1619 error = 1;
1621 else
1623 uint8_t oi = tvb_get_uint8( tvb, 3 );
1624 if( oi != 1 )
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 );
1630 offset = 4;
1633 /* 1 byte Property ID
1635 dissect_pid( tvb, pinfo, cemi_node, cemi_list, &offset, size, ot, 1, &error );
1637 if( min_size >= 7 )
1639 /* Range (Start Index, Number Of Elements) and Data
1641 dissect_range( tvb, pinfo, cemi_node, cemi_list, &offset, size, pa_flags, &error );
1642 pa_flags = 0;
1646 *p_offset = offset;
1647 *p_pa_flags = pa_flags;
1648 *p_error = error;
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" );
1665 error = 1;
1666 offset = size;
1668 else
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 );
1673 if( is_response )
1675 if( n != 0 )
1677 col_append_fstr( cinfo, COL_INFO, " E=$%02X", n );
1678 proto_item_append_text( cemi_node, ", E=$%02X", n );
1681 else
1683 if( n != 1 )
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 );
1695 if( is_response )
1697 proto_tree_add_item( cemi_list, hf_cemi_error, tvb, offset, 1, ENC_BIG_ENDIAN );
1699 else
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 );
1706 offset += 4;
1709 *p_offset = offset;
1710 *p_pa_flags = pa_flags;
1711 *p_error = error;
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;
1723 proto_item* node;
1724 proto_tree* list;
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" );
1731 error = 1;
1732 offset = size;
1734 else
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 );
1739 c2 &= 0x0F;
1740 c3 |= c1 << 16UL;
1741 if( c2 != 1 )
1742 col_append_fstr( cinfo, COL_INFO, " N=%u", c2 );
1743 col_append_fstr( cinfo, COL_INFO, " X=$%05X", c3 );
1744 if( tree )
1746 if( c2 != 1 )
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 );
1756 offset += 3;
1759 *p_offset = offset;
1760 *p_pa_flags = pa_flags;
1761 *p_error = error;
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;
1784 proto_item* node;
1785 proto_tree* list;
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" );
1792 error = 1;
1793 offset = size;
1795 else
1797 uint8_t c = tvb_get_uint8( tvb, offset );
1798 uint16_t cc = tvb_get_ntohs( tvb, offset + 1 );
1799 if( c != 1 )
1800 col_append_fstr( cinfo, COL_INFO, " N=%u", c );
1801 col_append_fstr( cinfo, COL_INFO, " X=$%04X", cc );
1802 if( tree )
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 );
1811 offset += 3;
1814 *p_offset = offset;
1815 *p_pa_flags = pa_flags;
1816 *p_error = error;
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;
1828 /* 1 byte Level */
1829 if( offset >= size )
1831 proto_tree_add_expert_format( cemi_list, pinfo, KIP_ERROR, tvb, offset, 0, "? Level: expected 1 byte" );
1832 error = 1;
1834 else
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 );
1840 if( tree )
1842 proto_item_append_text( cemi_node, ", L=%u", c );
1845 if( tree )
1847 proto_tree_add_item( cemi_list, hf_cemi_level, tvb, offset, 1, ENC_BIG_ENDIAN );
1849 offset++;
1852 *p_offset = offset;
1853 *p_pa_flags = pa_flags;
1854 *p_error = error;
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 );
1867 /* 2 bytes Range */
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 */
1892 *p_pa_flags = 0;
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;
1917 proto_item* node;
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" );
1924 error = 1;
1925 offset = size;
1927 else
1929 proto_tree_add_data( cemi_list, tvb, offset, 6, cinfo, cemi_node, "Serial Number", " SN=$", ", SerNr=$" );
1930 offset += 6;
1933 if( pa_flags )
1935 if( offset >= size )
1937 proto_tree_add_expert_format( cemi_list, pinfo, KIP_ERROR, tvb, offset, 0, "? Data: missing" );
1938 error = 1;
1942 *p_offset = offset;
1943 *p_pa_flags = pa_flags;
1944 *p_error = error;
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;
1956 proto_item* node;
1957 const char* name;
1958 uint16_t ot;
1959 uint16_t cc;
1960 uint8_t c;
1962 /* 2 bytes Object Type */
1963 if( offset + 1 >= size )
1965 ot = 0;
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" );
1968 error = 1;
1969 offset = size;
1971 else
1973 ot = cc = tvb_get_ntohs( tvb, offset );
1975 if( cc )
1977 col_append_fstr( cinfo, COL_INFO, " OT=%u", cc );
1978 proto_item_append_text( cemi_node, ", OT=%u", cc );
1981 if( cemi_list )
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 );
1985 if( name )
1987 proto_item_append_text( node, " = %s", name );
1991 offset += 2;
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" );
1999 error = 1;
2000 offset = size;
2002 else
2004 /* 12 bits Property ID */
2005 cc = tvb_get_ntohs( tvb, offset );
2006 c = cc & 0x000F;
2007 cc >>= 4;
2009 col_append_fstr( cinfo, COL_INFO, " P=%u", cc );
2010 proto_item_append_text( cemi_node, ", PID=%u", cc );
2012 if( cemi_list )
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 );
2016 if( name )
2018 proto_item_append_text( node, " = %s", name );
2022 ++offset;
2024 /* 4 bits Reserved */
2025 if( c )
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" );
2031 error = 1;
2034 ++offset;
2037 *p_offset = offset;
2038 *p_pa_flags = pa_flags;
2039 *p_error = error;
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;
2051 proto_item* node;
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" );
2061 error = 1;
2062 offset = size;
2064 else
2066 /* 1 byte Count */
2067 uint8_t ne = tvb_get_uint8( tvb, offset );
2068 if( ne != 1 )
2070 col_append_fstr( cinfo, COL_INFO, " N=%u", ne );
2071 proto_item_append_text( cemi_node, ", N=%u", ne );
2074 /* 2 bytes Index */
2075 uint16_t sx = tvb_get_ntohs( tvb, offset + 1 );
2076 if( sx != 1 )
2078 col_append_fstr( cinfo, COL_INFO, " X=%u", sx );
2079 proto_item_append_text( cemi_node, ", X=%u", sx );
2082 if( cemi_list )
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 );
2090 offset += 3;
2093 *p_offset = offset;
2094 *p_pa_flags = pa_flags;
2095 *p_error = error;
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;
2107 proto_item* node;
2108 uint16_t cc;
2109 uint8_t c;
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" );
2119 error = 1;
2121 else
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" );
2134 error = 1;
2135 offset = size;
2137 else
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 );
2143 offset += 2;
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" );
2153 error = 1;
2154 offset = size;
2156 else
2158 uint16_t dpt_major = tvb_get_ntohs( tvb, offset );
2159 uint16_t dpt_minor = tvb_get_ntohs( tvb, offset + 2 );
2161 if( cemi_list )
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 );
2169 offset += 4;
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 */
2182 pa_flags = 0;
2185 *p_offset = offset;
2186 *p_pa_flags = pa_flags;
2187 *p_error = error;
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;
2201 proto_item* node;
2202 proto_tree* list;
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" );
2210 error = 1;
2211 offset = size;
2213 else
2215 /* 1 byte SCF */
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;
2220 uint64_t seq_nr;
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 );
2234 ++offset;
2236 /* 6 bytes SeqNr */
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=$" );
2240 offset += 6;
2242 if( is_sync )
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 );
2247 offset += 6;
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" );
2256 error = 1;
2257 offset = size;
2259 else
2261 proto_tree_add_data( cemi_list, tvb, offset, 6, NULL, NULL, name, NULL, NULL );
2262 offset += 6;
2264 if( offset < size )
2266 /* 4 bytes MAC */
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" );
2272 error = 1;
2274 offset = size;
2278 else // Data
2280 struct data_security_info info;
2281 struct knx_keyring_ia_seqs* ia_seq;
2282 const uint8_t* cemi;
2283 const uint8_t* encrypted;
2284 int encrypted_size;
2285 const uint8_t* decrypted;
2286 proto_item* item;
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
2296 // Check sending IA
2297 uint8_t ga_found = 0;
2298 uint8_t ia_ok = 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 )
2304 ga_found = 1;
2306 if( ga_sender->ia == source_addr )
2308 ia_ok = 1;
2309 break;
2314 if( !ia_ok )
2316 if( ga_found )
2318 expert_add_info_format( pinfo, source_node, KIP_ERROR, "Unknown sender" );
2319 error = 1;
2321 else
2323 expert_add_info_format( pinfo, dest_node, KIP_WARNING, "Unknown group address" );
2328 // Check SeqNr
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 );
2336 break;
2341 // Get encrypted data.
2342 cemi = tvb_get_ptr( tvb, 0, size );
2343 encrypted = cemi + offset;
2344 encrypted_size = size - offset;
2346 // Decrypt.
2347 decrypted = decrypt_data_security_data( pinfo->pool, encrypted, encrypted_size, cemi, size, &info );
2349 if( decrypted )
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" );
2392 if( cemi_handle )
2394 call_dissector( cemi_handle, tvb3, pinfo, root_tree );
2400 else
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 );
2411 offset = size;
2415 *p_offset = offset;
2416 *p_pa_flags = pa_flags;
2417 *p_error = error;
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 );
2437 if( tree )
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 );
2445 offset += 2;
2447 pa_flags = PA_RESPONSE | PA_DATA;
2449 switch( ax )
2451 case AX_UserMemRead:
2452 case AX_MemExtRead:
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:
2461 pa_flags = 0;
2462 break;
2465 switch( ax )
2467 case AX_MemExtRead:
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 );
2472 break;
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 );
2479 break;
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 );
2485 break;
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 );
2495 break;
2497 case AX_AuthReq:
2498 case AX_AuthResp:
2499 case AX_KeyWrite:
2500 case AX_KeyResp:
2501 dissect_authenticate_service( tvb, pinfo, tree, cemi_node, cemi_list, ax, &offset, size, &pa_flags, &error );
2502 break;
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 );
2508 break;
2510 case AX_PropDescrRead:
2511 case AX_PropDescrResp:
2512 dissect_property_description_service( tvb, pinfo, cemi_node, cemi_list, &offset, size, &pa_flags, &error );
2513 break;
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 );
2523 break;
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 );
2532 break;
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 );
2538 break;
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 );
2546 break;
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 );
2551 break;
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 );
2559 break;
2561 case AX_DataSec:
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 );
2564 break;
2567 *p_offset = offset;
2568 *p_pa_flags = pa_flags;
2569 *p_error = error;
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;
2585 uint8_t c;
2586 uint16_t cc;
2588 const char* name = val_to_str( ac, ac_vals, "AC=%u" );
2589 col_append_fstr( cinfo, COL_INFO, " %s", name );
2590 if( tree )
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 );
2598 offset++;
2600 switch( ac )
2602 case AC_GroupValueRead:
2603 case AC_MemRead:
2604 case AC_AdcRead:
2605 case AC_DevDescrRead:
2606 pa_flags = 0;
2607 break;
2610 switch( ac )
2612 case AC_GroupValueRead:
2613 case AC_GroupValueResp:
2614 case AC_GroupValueWrite:
2615 case AC_Restart:
2617 uint8_t expected = ((pa_flags && offset + 1 >= size) || ac == AC_Restart);
2619 if( expected || ad != 0 )
2621 /* Show APCI 6-bit data
2623 if( !expected )
2625 error = 1;
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 );
2633 if( tree )
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 );
2639 if( !expected )
2641 proto_item_prepend_text( node, "? " );
2642 expert_add_info_format( pinfo, node, KIP_ERROR, "Expected: 0x00" );
2647 break;
2649 case AC_MemRead:
2650 case AC_MemResp:
2651 case AC_MemWrite:
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" );
2658 error = 1;
2659 offset = size - 1;
2661 else
2663 cc = tvb_get_ntohs( tvb, offset + 1 );
2664 if( ad != 1 )
2665 col_append_fstr( cinfo, COL_INFO, " N=%u", ad );
2666 col_append_fstr( cinfo, COL_INFO, " X=$%04X", cc );
2667 if( tree )
2669 if( ad != 1 )
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 );
2677 offset += 2;
2679 break;
2681 case AC_AdcRead:
2682 case AC_AdcResp:
2684 /* 6 bits Channel */
2685 col_append_fstr( cinfo, COL_INFO, " #%u", ad );
2686 if( tree )
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 );
2693 ++offset;
2695 /* 1 byte Count */
2696 if( offset >= size )
2698 proto_tree_add_expert_format( cemi_list, pinfo, KIP_ERROR, tvb, offset, 0, "? Count: expected 1 byte" );
2699 error = 1;
2700 --offset;
2702 else
2704 c = tvb_get_uint8( tvb, offset );
2705 if( c != 1 )
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 );
2712 break;
2714 case AC_DevDescrRead:
2715 case AC_DevDescrResp:
2717 /* 6 bits Descriptor Type */
2718 if( ad != 0 )
2719 col_append_fstr( cinfo, COL_INFO, " #%u", ad );
2720 if( tree )
2722 if( ad != 0 )
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 );
2728 break;
2730 case AC_UserMsg:
2731 case AC_Escape:
2733 /* 6 bits Data */
2734 col_append_fstr( cinfo, COL_INFO, " #%u", ad );
2735 if( tree )
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 );
2741 break;
2744 offset++;
2746 *p_offset = offset;
2747 *p_pa_flags = pa_flags;
2748 *p_error = error;
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;
2761 /* 10 bits APCI
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" );
2767 error = 1;
2768 offset = size;
2770 else
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);
2779 /* 6 bits data */
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 );
2798 *p_offset = offset;
2799 *p_pa_flags = pa_flags;
2800 *p_error = error;
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;
2814 proto_item* node;
2815 const char* name;
2816 char text[ 128 ];
2817 uint8_t c;
2819 /* 6 bits TPCI */
2820 if( offset >= size )
2822 proto_tree_add_expert_format( cemi_list, pinfo, KIP_ERROR, tvb, offset, 0, "? TPCI: expected 1 byte" );
2823 error = 1;
2825 else
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" );
2837 tpci_error = 1;
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" );
2845 tpci_error = 1;
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 );
2854 if( !(tb & 0x40) )
2856 expert_add_info_format( pinfo, node, KIP_ERROR, "Expected: zero" );
2857 tpci_error = 1;
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 );
2866 if( !name )
2868 snprintf( text, sizeof text, "TC=%u", tc );
2869 name = text;
2871 col_append_fstr( cinfo, COL_INFO, " %s", name );
2872 if( tree )
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 );
2880 if( tpci_error )
2882 proto_item_prepend_text( tpci_node, "? " );
2883 error = 1;
2886 if( tb & 0x80 ) /* Control Packet */
2888 pa_flags = 0;
2889 offset++;
2891 else /* Data Packet */
2893 /* APCI etc */
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 );
2898 *p_offset = offset;
2899 *p_pa_flags = pa_flags;
2900 *p_error = error;
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;
2916 const char* name;
2917 char text[ 128 ];
2918 uint8_t c;
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;
2932 if( size < 2 )
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" );
2936 offset = size;
2937 error = 1;
2939 else
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;
2946 if( ai_end > size )
2948 error = 2;
2949 ai_size = size - 2;
2950 ai_end = size;
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 );
2957 if( error == 2 )
2959 proto_item_prepend_text( node, "? " );
2960 expert_add_info_format( pinfo, node, KIP_ERROR, "Available: %d bytes", ai_size );
2963 offset = 2;
2964 while( offset < ai_end )
2966 /* Additional Information Element */
2967 uint8_t aie_type = tvb_get_uint8( tvb, offset );
2968 uint8_t aie_len;
2969 int aie_size;
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 )
2977 error = 3;
2978 aie_len = 0;
2979 aie_size = 1;
2981 else
2983 aie_len = tvb_get_uint8( tvb, offset + 1 );
2984 aie_size = ai_end - offset - 2;
2985 if( aie_size < aie_len )
2987 error = 4;
2989 else
2991 aie_size = aie_len;
2993 aie_size += 2;
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 );
3000 offset++;
3002 if( error == 3 )
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" );
3006 break;
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 );
3011 offset++;
3013 if( error == 4 )
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 );
3018 break;
3021 if( aie_len > 0 )
3023 proto_tree_add_data( aie_list, tvb, offset, aie_len, NULL, NULL, "Data", NULL, NULL );
3024 offset += aie_len;
3026 else
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)" );
3031 error = 5;
3035 if( error >= 2 )
3037 proto_item_prepend_text( ai_node, "? " );
3040 offset = ai_end;
3043 switch( mc )
3045 case CEMI_L_BUSMON_IND:
3046 case CEMI_L_RAW_IND:
3047 case CEMI_L_RAW_REQ:
3048 case CEMI_L_RAW_CON:
3049 break;
3051 default:
3053 switch( mc )
3055 case CEMI_L_DATA_REQ:
3056 case CEMI_L_DATA_CON:
3057 case CEMI_L_DATA_IND:
3058 is_ldata = 1;
3059 break;
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:
3065 is_tdata = 1;
3066 break;
3069 if( is_tdata )
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" );
3073 if( length < 6 )
3075 proto_item_prepend_text( node, "? " );
3076 expert_add_info_format( pinfo, node, KIP_ERROR, "Expected: 6 bytes" );
3077 error = 1;
3079 else
3081 int pos = 0;
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" );
3088 error = 1;
3089 break;
3094 is_tdata = 1;
3095 offset += length;
3097 else
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" );
3103 error = 1;
3105 else
3107 if( tree )
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: " );
3112 if( !(c & 0x80) )
3114 proto_item_append_text( cemi_node, "X " );
3115 proto_item_append_text( node, "Extended, " );
3117 if( !(c & 0x20) )
3119 proto_item_append_text( cemi_node, "R " );
3120 proto_item_append_text( node, "Repeat On Error, " );
3122 if( !(c & 0x10) )
3124 proto_item_append_text( cemi_node, "B " );
3125 proto_item_append_text( node, "System Broadcast, " );
3127 if( c & 0x02 )
3129 proto_item_append_text( cemi_node, "A " );
3130 proto_item_append_text( node, "Ack Wanted, " );
3132 if( c & 0x01 )
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 );
3139 if( !name )
3140 name = "?";
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 );
3152 offset++;
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" );
3159 error = 1;
3161 else
3163 c = tvb_get_uint8( tvb, offset );
3165 unicast = !(c & 0x80); /* Address Type (IA or GA) */
3167 if( tree )
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 );
3175 if( eff )
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 );
3186 offset++;
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" );
3194 error = 1;
3195 offset = size;
3197 else
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 );
3202 if( tree )
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 );
3209 offset += 2;
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" );
3217 error = 1;
3218 offset = size;
3220 else
3222 dest_addr = tvb_get_ntohs( tvb, offset );
3224 if( unicast )
3226 /* Individual Address */
3227 snprintf( text, sizeof text, "%u.%u.%u", (dest_addr >> 12) & 0xF, (dest_addr >> 8) & 0xF, dest_addr & 0xFF );
3229 else
3231 /* Group Address */
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 );
3237 if( tree )
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 );
3244 offset += 2;
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" );
3254 error = 1;
3256 else
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 );
3265 error = 1;
3268 offset++;
3271 /* TPCI etc */
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 );
3275 break;
3278 *p_offset = offset;
3279 *p_pa_flags = pa_flags;
3280 *p_error = error;
3283 static int dissect_cemi( tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data _U_ )
3285 int offset = 0;
3286 int size = tvb_captured_length_remaining( tvb, 0 );
3287 uint8_t error = 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" );
3307 if( size <= 0 )
3309 expert_add_info_format( pinfo, cemi_node, KIP_ERROR, "Expected: min 1 byte" );
3310 error = 1;
3312 else
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 );
3318 if( !name )
3320 /* Unknown Message Code */
3321 col_append_str( cinfo, COL_INFO, "cEMI" );
3322 pa_flags = 0;
3324 else
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 );
3333 offset = 1;
3335 if( mc >= 0xF0 )
3337 /* cEMI Management packet */
3338 dissect_cemi_mgmt_packet( tvb, pinfo, cemi_node, cemi_list, mc, &offset, size, &pa_flags, &error );
3340 else
3342 /* cEMI Link Layer packet */
3343 dissect_cemi_link_layer( tvb, pinfo, tree, cemi_node, cemi_list, mc, &offset, size, &pa_flags, &error );
3348 if( offset < size )
3350 /* Trailing data */
3351 proto_item* node = proto_tree_add_data( cemi_list, tvb, offset, size - offset, cinfo, cemi_node, "Data", " $", ", $" );
3353 if( !pa_flags )
3355 proto_item_prepend_text( node, "? " );
3356 expert_add_info_format( pinfo, node, KIP_ERROR, "Unexpected" );
3357 error = 1;
3360 offset = size;
3363 if( error )
3365 /* If not already done */
3366 if( !knxip_error )
3368 knxip_error = 1;
3369 col_prepend_fstr( cinfo, COL_INFO, "? " );
3372 proto_item_prepend_text( cemi_node, "? " );
3375 return size;
3378 void proto_register_cemi( void )
3380 /* Header fields */
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 } },
3447 /* Subtrees */
3448 static int *ett[] = {
3449 &ett_cemi,
3450 &ett_cemi_ai,
3451 &ett_cemi_aie,
3452 &ett_cemi_ctrl1,
3453 &ett_cemi_ctrl2,
3454 &ett_cemi_tpci,
3455 &ett_cemi_apci,
3456 &ett_cemi_range,
3457 &ett_cemi_pd,
3458 &ett_cemi_dpt,
3459 &ett_cemi_scf,
3460 &ett_cemi_decrypted
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
3478 * Local variables:
3479 * c-basic-offset: 2
3480 * tab-width: 8
3481 * indent-tabs-mode: nil
3482 * End:
3484 * vi: set shiftwidth=2 tabstop=8 expandtab:
3485 * :indentSize=2:tabSize=8:noTabs=true: