2 * Routines for I2C captures (using libpcap extensions)
4 * Pigeon Point Systems <www.pigeonpoint.com>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
15 #include <epan/packet.h>
16 #include <epan/capture_dissectors.h>
17 #include <epan/prefs.h>
18 #include <epan/decode_as.h>
20 void proto_register_i2c(void);
21 void proto_reg_handoff_i2c(void);
23 static dissector_handle_t i2c_linux_handle
;
24 static capture_dissector_handle_t i2c_linux_cap_handle
;
25 static dissector_handle_t i2c_kontron_handle
;
28 static int proto_i2c_event
;
29 static int proto_i2c_data
;
32 static int hf_i2c_bus
;
33 static int hf_i2c_event
;
34 static int hf_i2c_flags
;
35 static int hf_i2c_addr
;
39 static dissector_table_t subdissector_table
;
41 static dissector_handle_t ipmb_handle
;
43 /* I2C packet flags. */
44 #define I2C_FLAG_RD 0x00000001
45 #define I2C_FLAG_TEN 0x00000010
46 #define I2C_FLAG_REV_DIR_ADDR 0x00002000
47 #define I2C_FLAG_NOSTART 0x00004000
50 #define I2C_EVENT_PROM_ON (1 << 0) /* Promiscuous mode: on */
51 #define I2C_EVENT_PROM_OFF (1 << 1) /* Promiscuous mode: off */
52 #define I2C_EVENT_ONLINE_ON (1 << 2) /* Online state: on */
53 #define I2C_EVENT_ONLINE_OFF (1 << 3) /* Online state: off */
54 #define I2C_EVENT_ATTACHED_ON (1 << 4) /* Attached state: on */
55 #define I2C_EVENT_ATTACHED_OFF (1 << 5) /* Attached state: off */
56 #define I2C_EVENT_PROM_OVFL_ON (1 << 6) /* Prom. queue overflow: on */
57 #define I2C_EVENT_PROM_OVFL_OFF (1 << 7) /* Prom. queue overflow: off */
58 #define I2C_EVENT_OVFL_ON (1 << 8) /* Queue overflow: on */
59 #define I2C_EVENT_OVFL_OFF (1 << 9) /* Queue overflow: off */
62 #define I2C_EVENT_ERR_DATA_LO (1 << 16) /* Unable to drive data LO */
63 #define I2C_EVENT_ERR_DATA_HI (1 << 17) /* Unable to drive data HI */
64 #define I2C_EVENT_ERR_CLOCK_LO (1 << 18) /* Unable to drive clock LO */
65 #define I2C_EVENT_ERR_CLOCK_HI (1 << 19) /* Unable to drive clock HI */
66 #define I2C_EVENT_ERR_CLOCK_TO (1 << 20) /* Clock low timeout */
67 #define I2C_EVENT_ERR_PHYS (1 << 21) /* The I2C bus controller
69 disconnected from the bus */
70 #define I2C_EVENT_ERR_FAIL (1 << 22) /* Undiagnosed failure */
72 static void i2c_prompt(packet_info
*pinfo _U_
, char* result
)
74 snprintf(result
, MAX_DECODE_AS_PROMPT_LEN
, "Interpret I2C messages as");
78 capture_i2c_linux(const unsigned char *pd _U_
, int offset _U_
, int len _U_
, capture_packet_info_t
*cpinfo
, const union wtap_pseudo_header
*pseudo_header
)
80 if (pseudo_header
->i2c
.is_event
) {
81 capture_dissector_increment_count(cpinfo
, proto_i2c_event
);
83 capture_dissector_increment_count(cpinfo
, proto_i2c_data
);
90 i2c_linux_get_event_desc(uint32_t event
)
94 switch (event
& 0x0000ffff) {
95 case I2C_EVENT_PROM_ON
:
96 desc
= "Promiscuous mode is enabled";
98 case I2C_EVENT_PROM_OFF
:
99 desc
= "Promiscuous mode is disabled";
101 case I2C_EVENT_ONLINE_ON
:
102 desc
= "The I2C controller is operational";
104 case I2C_EVENT_ONLINE_OFF
:
105 desc
= "The I2C controller is non-operational";
107 case I2C_EVENT_ATTACHED_ON
:
108 desc
= "The I2C controller is attached to an I2C bus";
110 case I2C_EVENT_ATTACHED_OFF
:
111 desc
= "The I2C controller is detached from an I2C bus";
112 if (event
& I2C_EVENT_ERR_DATA_LO
) {
113 desc
= "The I2C controller is detached from an I2C bus: "
114 "unable to drive data LO";
115 } else if (event
& I2C_EVENT_ERR_DATA_HI
) {
116 desc
= "The I2C controller is detached from an I2C bus: "
117 "unable to drive data HI";
118 } else if (event
& I2C_EVENT_ERR_CLOCK_LO
) {
119 desc
= "The I2C controller is detached from an I2C bus: "
120 "unable to drive clock LO";
121 } else if (event
& I2C_EVENT_ERR_CLOCK_HI
) {
122 desc
= "The I2C controller is detached from an I2C bus: "
123 "unable to drive clock HI";
124 } else if (event
& I2C_EVENT_ERR_CLOCK_TO
) {
125 desc
= "The I2C controller is detached from an I2C bus: "
127 } else if (event
& I2C_EVENT_ERR_PHYS
) {
128 desc
= "The I2C controller is detached from an I2C bus: "
129 "the I2C bus controller has been physically "
130 "disconnected from the bus";
131 } else if (event
& I2C_EVENT_ERR_FAIL
) {
132 desc
= "The I2C controller is detached from an I2C bus: "
133 "undiagnosed failure";
136 case I2C_EVENT_PROM_OVFL_ON
:
137 desc
= "The incoming promiscuous data buffer has been overrun; "
140 case I2C_EVENT_PROM_OVFL_OFF
:
141 desc
= "The incoming promiscuous data buffer is available";
143 case I2C_EVENT_OVFL_ON
:
144 desc
= "The incoming I2C data buffer has been overrun; "
147 case I2C_EVENT_OVFL_OFF
:
148 desc
= "The incoming I2C data buffer is available";
151 desc
= "<unknown state event>";
159 dissect_i2c_linux(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
162 proto_tree
*i2c_tree
;
167 flags
= pinfo
->pseudo_header
->i2c
.flags
;
169 bus
= pinfo
->pseudo_header
->i2c
.bus
;
170 col_add_fstr(pinfo
->cinfo
, COL_DEF_SRC
, "I2C-%d", bus
);
172 is_event
= pinfo
->pseudo_header
->i2c
.is_event
;
175 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "I2C Event");
176 col_set_str(pinfo
->cinfo
, COL_DEF_DST
, "----");
177 col_add_str(pinfo
->cinfo
, COL_INFO
,
178 i2c_linux_get_event_desc(flags
));
180 /* Report 7-bit hardware address */
181 addr
= tvb_get_uint8(tvb
, 0) >> 1;
182 col_add_fstr(pinfo
->cinfo
, COL_PROTOCOL
, "I2C %s",
183 (flags
& I2C_FLAG_RD
) ? "Read" : "Write");
184 col_add_fstr(pinfo
->cinfo
, COL_DEF_DST
, "0x%02x", addr
);
185 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "I2C %s, %d bytes",
186 (flags
& I2C_FLAG_RD
) ? "Read" : "Write", tvb_captured_length(tvb
));
189 pinfo
->ptype
= PT_I2C
;
191 ti
= proto_tree_add_protocol_format(tree
, proto_i2c
, tvb
, 0, -1,
192 "Inter-Integrated Circuit (%s)",
193 is_event
? "Event" : "Data");
195 i2c_tree
= proto_item_add_subtree(ti
, ett_i2c
);
196 proto_tree_add_uint_format(i2c_tree
, hf_i2c_bus
, tvb
, 0, 0, bus
,
200 proto_tree_add_uint_format_value(i2c_tree
, hf_i2c_event
, tvb
, 0, 0,
201 flags
, "%s (0x%08x)",
202 i2c_linux_get_event_desc(flags
), flags
);
204 proto_tree_add_uint_format_value(i2c_tree
, hf_i2c_addr
, tvb
, 0, 1,
205 addr
, "0x%02x%s", addr
, addr
? "" : " (General Call)");
206 proto_tree_add_uint(i2c_tree
, hf_i2c_flags
, tvb
, 0, 0, flags
);
208 if (!dissector_try_payload_with_data(subdissector_table
, tvb
, pinfo
, tree
, true, NULL
))
210 call_data_dissector(tvb
, pinfo
, tree
);
213 return tvb_captured_length(tvb
);
216 /* IPMB-over-I2C, with Kontron pseudo-header */
218 dissect_i2c_kontron(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
221 proto_tree
*i2c_tree
;
226 col_set_str(pinfo
->cinfo
, COL_DEF_SRC
, "I2C");
227 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "I2C");
229 ti
= proto_tree_add_protocol_format(tree
, proto_i2c
, tvb
, 0, -1,
230 "Inter-Integrated Circuit (Data)");
232 /* Data length field */
235 /* Port number on which the message was received */
238 /* Report 7-bit hardware address */
239 addr
= tvb_get_uint8(tvb
, offset
) >> 1;
240 col_append_fstr(pinfo
->cinfo
, COL_PROTOCOL
, " %s",
241 tvb_get_uint8(tvb
, 0) & 0x01 ? "Read" : "Write");
242 col_add_fstr(pinfo
->cinfo
, COL_DEF_DST
, "0x%02x", addr
);
243 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "I2C, %d bytes",
244 tvb_captured_length(tvb
));
246 pinfo
->ptype
= PT_I2C
;
248 i2c_tree
= proto_item_add_subtree(ti
, ett_i2c
);
250 proto_tree_add_uint_format_value(i2c_tree
, hf_i2c_addr
, tvb
, 0, 3,
251 addr
, "0x%02x%s", addr
, addr
? "" : " (General Call)");
253 new_tvb
= tvb_new_subset_remaining(tvb
, offset
);
254 call_dissector(ipmb_handle
, new_tvb
, pinfo
, tree
);
255 return tvb_captured_length(tvb
);
259 proto_register_i2c(void)
261 static hf_register_info hf
[] = {
262 { &hf_i2c_bus
, { "Bus ID", "i2c.bus", FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}},
263 { &hf_i2c_addr
, { "Target address", "i2c.addr", FT_UINT8
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}},
264 { &hf_i2c_event
, { "Event", "i2c.event", FT_UINT32
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}},
265 { &hf_i2c_flags
, { "Flags", "i2c.flags", FT_UINT32
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}},
267 static int *ett
[] = {
272 proto_i2c
= proto_register_protocol("Inter-Integrated Circuit", "I2C", "i2c");
273 proto_register_field_array(proto_i2c
, hf
, array_length(hf
));
274 proto_register_subtree_array(ett
, array_length(ett
));
276 /* Placeholders for capture statistics */
277 proto_i2c_event
= proto_register_protocol_in_name_only("I2C Events", "I2C Events", "i2c_event", proto_i2c
, FT_PROTOCOL
);
278 proto_i2c_data
= proto_register_protocol_in_name_only("I2C Data", "I2C Data", "i2c_data", proto_i2c
, FT_PROTOCOL
);
280 m
= prefs_register_protocol_obsolete(proto_i2c
);
281 prefs_register_obsolete_preference(m
, "type");
283 subdissector_table
= register_decode_as_next_proto(proto_i2c
, "i2c.message", "I2C messages dissector", i2c_prompt
);
285 i2c_linux_handle
= register_dissector("i2c_linux", dissect_i2c_linux
, proto_i2c
);
286 i2c_linux_cap_handle
= register_capture_dissector("i2c_linux", capture_i2c_linux
, proto_i2c
);
287 i2c_kontron_handle
= register_dissector("i2c_kontron", dissect_i2c_kontron
, proto_i2c
);
291 proto_reg_handoff_i2c(void)
293 dissector_add_uint("wtap_encap", WTAP_ENCAP_I2C_LINUX
, i2c_linux_handle
);
294 capture_dissector_add_uint("wtap_encap", WTAP_ENCAP_I2C_LINUX
, i2c_linux_cap_handle
);
296 dissector_add_uint("wtap_encap", WTAP_ENCAP_IPMB_KONTRON
, i2c_kontron_handle
);
298 ipmb_handle
= find_dissector("ipmb");
302 * Editor modelines - https://www.wireshark.org/tools/modelines.html
307 * indent-tabs-mode: t
310 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
311 * :indentSize=8:tabSize=8:noTabs=false: