Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-i2c.c
blob36ab0adcad21ac11dc99b49f6b2d38d6d09d4635
1 /* packet-i2c.c
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
13 #include "config.h"
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;
27 static int proto_i2c;
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;
37 static int ett_i2c;
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
49 /* I2C events. */
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 */
61 /* I2C errors. */
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
68 has been physically
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");
77 static bool
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);
82 } else {
83 capture_dissector_increment_count(cpinfo, proto_i2c_data);
86 return true;
89 static const char *
90 i2c_linux_get_event_desc(uint32_t event)
92 const char *desc;
94 switch (event & 0x0000ffff) {
95 case I2C_EVENT_PROM_ON:
96 desc = "Promiscuous mode is enabled";
97 break;
98 case I2C_EVENT_PROM_OFF:
99 desc = "Promiscuous mode is disabled";
100 break;
101 case I2C_EVENT_ONLINE_ON:
102 desc = "The I2C controller is operational";
103 break;
104 case I2C_EVENT_ONLINE_OFF:
105 desc = "The I2C controller is non-operational";
106 break;
107 case I2C_EVENT_ATTACHED_ON:
108 desc = "The I2C controller is attached to an I2C bus";
109 break;
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: "
126 "clock low timeout";
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";
135 break;
136 case I2C_EVENT_PROM_OVFL_ON:
137 desc = "The incoming promiscuous data buffer has been overrun; "
138 "some data is lost";
139 break;
140 case I2C_EVENT_PROM_OVFL_OFF:
141 desc = "The incoming promiscuous data buffer is available";
142 break;
143 case I2C_EVENT_OVFL_ON:
144 desc = "The incoming I2C data buffer has been overrun; "
145 "some data is lost";
146 break;
147 case I2C_EVENT_OVFL_OFF:
148 desc = "The incoming I2C data buffer is available";
149 break;
150 default:
151 desc = "<unknown state event>";
152 break;
155 return desc;
158 static int
159 dissect_i2c_linux(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
161 proto_item *ti;
162 proto_tree *i2c_tree;
163 uint8_t is_event;
164 uint8_t bus, addr;
165 uint32_t flags;
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;
173 if (is_event) {
174 addr = 0;
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));
179 } else {
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,
197 "Bus: I2C-%d", bus);
199 if (is_event) {
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);
203 } else {
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 */
217 static int
218 dissect_i2c_kontron(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
220 proto_item *ti;
221 proto_tree *i2c_tree;
222 int offset = 0;
223 uint8_t addr;
224 tvbuff_t *new_tvb;
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 */
233 offset++;
235 /* Port number on which the message was received */
236 offset++;
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);
258 void
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[] = {
268 &ett_i2c
270 module_t *m;
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);
290 void
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
304 * Local variables:
305 * c-basic-offset: 8
306 * tab-width: 8
307 * indent-tabs-mode: t
308 * End:
310 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
311 * :indentSize=8:tabSize=8:noTabs=false: