HACK: pinfo->private_data points to smb_info again
[wireshark-wip.git] / epan / dissectors / packet-i2c.c
blobb67871421697494dd0e687db696009d437933003
1 /* packet-i2c.c
2 * Routines for I2C captures (using libpcap extensions)
4 * Pigeon Point Systems <www.pigeonpoint.com>
6 * $Id$
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include "config.h"
29 #include <glib.h>
31 #include <epan/packet.h>
32 #include <epan/exceptions.h>
33 #include <epan/prefs.h>
35 #include "packet-i2c.h"
36 #include "packet-hdcp.h"
38 static int proto_i2c = -1;
40 static int hf_i2c_bus = -1;
41 static int hf_i2c_event = -1;
42 static int hf_i2c_flags = -1;
43 static int hf_i2c_addr = -1;
45 static gint ett_i2c = -1;
47 enum {
48 SUB_DATA = 0,
49 SUB_IPMB,
50 SUB_HDCP,
52 SUB_MAX
55 typedef gboolean (*sub_checkfunc_t)(packet_info *);
57 static dissector_handle_t sub_handles[SUB_MAX];
58 static gint sub_selected = SUB_IPMB;
60 /* I2C packet flags. */
61 #define I2C_FLAG_RD 0x00000001
62 #define I2C_FLAG_TEN 0x00000010
63 #define I2C_FLAG_REV_DIR_ADDR 0x00002000
64 #define I2C_FLAG_NOSTART 0x00004000
66 /* I2C events. */
67 #define I2C_EVENT_PROM_ON (1 << 0) /* Promiscuous mode: on */
68 #define I2C_EVENT_PROM_OFF (1 << 1) /* Promiscuous mode: off */
69 #define I2C_EVENT_ONLINE_ON (1 << 2) /* Online state: on */
70 #define I2C_EVENT_ONLINE_OFF (1 << 3) /* Online state: off */
71 #define I2C_EVENT_ATTACHED_ON (1 << 4) /* Attached state: on */
72 #define I2C_EVENT_ATTACHED_OFF (1 << 5) /* Attached state: off */
73 #define I2C_EVENT_PROM_OVFL_ON (1 << 6) /* Prom. queue overflow: on */
74 #define I2C_EVENT_PROM_OVFL_OFF (1 << 7) /* Prom. queue overflow: off */
75 #define I2C_EVENT_OVFL_ON (1 << 8) /* Queue overflow: on */
76 #define I2C_EVENT_OVFL_OFF (1 << 9) /* Queue overflow: off */
78 /* I2C errors. */
79 #define I2C_EVENT_ERR_DATA_LO (1 << 16) /* Unable to drive data LO */
80 #define I2C_EVENT_ERR_DATA_HI (1 << 17) /* Unable to drive data HI */
81 #define I2C_EVENT_ERR_CLOCK_LO (1 << 18) /* Unable to drive clock LO */
82 #define I2C_EVENT_ERR_CLOCK_HI (1 << 19) /* Unable to drive clock HI */
83 #define I2C_EVENT_ERR_CLOCK_TO (1 << 20) /* Clock low timeout */
84 #define I2C_EVENT_ERR_PHYS (1 << 21) /* The I2C bus controller
85 has been physically
86 disconnected from the bus */
87 #define I2C_EVENT_ERR_FAIL (1 << 22) /* Undiagnosed failure */
89 void
90 capture_i2c(union wtap_pseudo_header *pseudo_header, packet_counts *ld)
92 if (pseudo_header->i2c.is_event) {
93 ld->i2c_event++;
94 } else {
95 ld->i2c_data++;
99 static const char *
100 i2c_get_event_desc(int event)
102 const char *desc;
104 switch (event & 0x0000ffff) {
105 case I2C_EVENT_PROM_ON:
106 desc = "Promiscuous mode is enabled";
107 break;
108 case I2C_EVENT_PROM_OFF:
109 desc = "Promiscuous mode is disabled";
110 break;
111 case I2C_EVENT_ONLINE_ON:
112 desc = "The I2C controller is operational";
113 break;
114 case I2C_EVENT_ONLINE_OFF:
115 desc = "The I2C controller is non-operational";
116 break;
117 case I2C_EVENT_ATTACHED_ON:
118 desc = "The I2C controller is attached to an I2C bus";
119 break;
120 case I2C_EVENT_ATTACHED_OFF:
121 desc = "The I2C controller is detached from an I2C bus";
122 if (event & I2C_EVENT_ERR_DATA_LO) {
123 desc = "The I2C controller is detached from an I2C bus: "
124 "unable to drive data LO";
125 } else if (event & I2C_EVENT_ERR_DATA_HI) {
126 desc = "The I2C controller is detached from an I2C bus: "
127 "unable to drive data HI";
128 } else if (event & I2C_EVENT_ERR_CLOCK_LO) {
129 desc = "The I2C controller is detached from an I2C bus: "
130 "unable to drive clock LO";
131 } else if (event & I2C_EVENT_ERR_CLOCK_HI) {
132 desc = "The I2C controller is detached from an I2C bus: "
133 "unable to drive clock HI";
134 } else if (event & I2C_EVENT_ERR_CLOCK_TO) {
135 desc = "The I2C controller is detached from an I2C bus: "
136 "clock low timeout";
137 } else if (event & I2C_EVENT_ERR_PHYS) {
138 desc = "The I2C controller is detached from an I2C bus: "
139 "the I2C bus controller has been physically "
140 "disconnected from the bus";
141 } else if (event & I2C_EVENT_ERR_FAIL) {
142 desc = "The I2C controller is detached from an I2C bus: "
143 "undiagnosed failure";
145 break;
146 case I2C_EVENT_PROM_OVFL_ON:
147 desc = "The incoming promiscuous data buffer has been overrun; "
148 "some data is lost";
149 break;
150 case I2C_EVENT_PROM_OVFL_OFF:
151 desc = "The incoming promiscuous data buffer is available";
152 break;
153 case I2C_EVENT_OVFL_ON:
154 desc = "The incoming I2C data buffer has been overrun; "
155 "some data is lost";
156 break;
157 case I2C_EVENT_OVFL_OFF:
158 desc = "The incoming I2C data buffer is available";
159 break;
160 default:
161 desc = "<unknown state event>";
162 break;
165 return desc;
168 static gboolean
169 sub_check_ipmb(packet_info *pinfo)
171 if (pinfo->pseudo_header->i2c.flags & I2C_FLAG_RD) {
172 /* Master-receive transactions are not possible on IPMB */
173 return FALSE;
176 return TRUE;
179 static sub_checkfunc_t sub_check[SUB_MAX] = {
180 NULL, /* raw data */
181 sub_check_ipmb, /* IPMI */
182 sub_check_hdcp /* HDCP */
185 static void
186 dissect_i2c(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
188 proto_item *ti;
189 proto_tree *i2c_tree = NULL;
190 int is_event, bus, flags, addr, len;
192 is_event = pinfo->pseudo_header->i2c.is_event;
193 flags = pinfo->pseudo_header->i2c.flags;
194 bus = pinfo->pseudo_header->i2c.bus;
195 len = tvb_length(tvb);
196 if (is_event) {
197 addr = 0;
198 } else {
199 if (len == 0) {
200 THROW(ReportedBoundsError);
202 /* Report 7-bit hardware address */
203 addr = tvb_get_guint8(tvb, 0) >> 1;
206 pinfo->ptype = PT_I2C;
208 if (is_event)
209 col_set_str(pinfo->cinfo, COL_PROTOCOL, "I2C Event");
210 else
211 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "I2C %s",
212 (flags & I2C_FLAG_RD) ? "Read" : "Write");
214 col_add_fstr(pinfo->cinfo, COL_DEF_SRC, "I2C-%d", bus);
216 if (is_event)
217 col_add_fstr(pinfo->cinfo, COL_DEF_DST, "----");
218 else
219 col_add_fstr(pinfo->cinfo, COL_DEF_DST, "0x%02x", addr);
221 if (is_event)
222 col_add_fstr(pinfo->cinfo, COL_INFO, "%s",
223 i2c_get_event_desc(flags));
224 else
225 col_add_fstr(pinfo->cinfo, COL_INFO, "I2C %s, %d bytes",
226 (flags & I2C_FLAG_RD) ? "Read" : "Write", len);
228 if (tree) {
229 ti = proto_tree_add_protocol_format(tree, proto_i2c, tvb, 0, -1,
230 "Inter-Integrated Circuit (%s)",
231 is_event ? "Event" : "Data");
233 i2c_tree = proto_item_add_subtree(ti, ett_i2c);
234 proto_tree_add_uint_format(i2c_tree, hf_i2c_bus, tvb, 0, 0, bus,
235 "Bus: I2C-%d", bus);
237 if (is_event) {
238 proto_tree_add_uint_format_value(i2c_tree, hf_i2c_event, tvb, 0, 0,
239 flags, "%s (0x%08x)",
240 i2c_get_event_desc(flags), flags);
241 } else {
242 proto_tree_add_uint_format_value(i2c_tree, hf_i2c_addr, tvb, 0, 1,
243 addr, "0x%02x%s", addr, addr ? "" : " (General Call)");
244 proto_tree_add_uint_format_value(i2c_tree, hf_i2c_flags, tvb, 0, 0,
245 flags, "0x%08x", flags);
249 if (!is_event) {
250 if (sub_check[sub_selected] && sub_check[sub_selected](pinfo)) {
251 call_dissector(sub_handles[sub_selected], tvb, pinfo, tree);
252 } else {
253 call_dissector(sub_handles[SUB_DATA], tvb, pinfo, tree);
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 gint *ett[] = {
268 &ett_i2c
270 static const enum_val_t sub_enum_vals[] = {
271 { "none", "None (raw I2C)", SUB_DATA },
272 { "ipmb", "IPMB", SUB_IPMB },
273 { "hdcp", "HDCP", SUB_HDCP },
274 { NULL, NULL, 0 }
276 module_t *m;
278 proto_i2c = proto_register_protocol("Inter-Integrated Circuit", "I2C", "i2c");
279 proto_register_field_array(proto_i2c, hf, array_length(hf));
280 proto_register_subtree_array(ett, array_length(ett));
282 m = prefs_register_protocol(proto_i2c, NULL);
283 prefs_register_enum_preference(m, "type", "Bus/Data type",
284 "How the I2C messages are interpreted",
285 &sub_selected, sub_enum_vals, FALSE);
288 void
289 proto_reg_handoff_i2c(void)
291 dissector_handle_t i2c_handle;
293 sub_handles[SUB_DATA] = find_dissector("data");
294 sub_handles[SUB_IPMB] = find_dissector("ipmi");
295 sub_handles[SUB_HDCP] = find_dissector("hdcp");
296 i2c_handle = create_dissector_handle(dissect_i2c, proto_i2c);
297 dissector_add_uint("wtap_encap", WTAP_ENCAP_I2C, i2c_handle);