Witness: add pidl output
[wireshark-wip.git] / epan / expert.c
blobe41654505345731adc55f332bd53bc5528931fdc
1 /* expert.c
2 * Collecting Expert information.
4 * Implemented as a tap named "expert".
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 <stdio.h>
30 #include <stdlib.h>
32 #include "packet.h"
33 #include "expert.h"
34 #include "emem.h"
35 #include "wmem/wmem.h"
36 #include "tap.h"
39 /* proto_expert cannot be static because it's referenced in the
40 * print routines
42 int proto_expert = -1;
44 static int proto_malformed = -1;
46 static int expert_tap = -1;
47 static int highest_severity = 0;
49 static int ett_expert = -1;
50 static int ett_subexpert = -1;
52 static int hf_expert_msg = -1;
53 static int hf_expert_group = -1;
54 static int hf_expert_severity = -1;
56 struct expert_module
58 const char* proto_name;
59 int proto_id; /* Cache this for registering hfs */
62 /* List which stores protocols and expert_info that have been registered */
63 typedef struct _gpa_expertinfo_t {
64 guint32 len;
65 guint32 allocated_len;
66 expert_field_info **ei;
67 } gpa_expertinfo_t;
68 static gpa_expertinfo_t gpa_expertinfo;
70 /* Possible values for a checksum evaluation */
71 const value_string expert_checksum_vals[] = {
72 { EXPERT_CHECKSUM_DISABLED, "Disabled" },
73 { EXPERT_CHECKSUM_UNKNOWN, "Unknown" },
74 { EXPERT_CHECKSUM_GOOD, "Good" },
75 { EXPERT_CHECKSUM_BAD, "Bad" },
76 { 0, NULL }
80 #define EXPERT_REGISTRAR_GET_NTH(eiindex, expinfo) \
81 if((guint)eiindex >= gpa_expertinfo.len && getenv("WIRESHARK_ABORT_ON_DISSECTOR_BUG")) \
82 g_error("Unregistered expert info! index=%d", eiindex); \
83 DISSECTOR_ASSERT_HINT((guint)eiindex < gpa_expertinfo.len, "Unregistered expert info!");\
84 expinfo = gpa_expertinfo.ei[eiindex];
86 void
87 expert_packet_init(void)
89 static hf_register_info hf[] = {
90 { &hf_expert_msg,
91 { "Message", "_ws.expert.message", FT_STRING, BASE_NONE, NULL, 0, "Wireshark expert information", HFILL }
93 { &hf_expert_group,
94 { "Group", "_ws.expert.group", FT_UINT32, BASE_HEX, VALS(expert_group_vals), 0, "Wireshark expert group", HFILL }
96 { &hf_expert_severity,
97 { "Severity level", "_ws.expert.severity", FT_UINT32, BASE_HEX, VALS(expert_severity_vals), 0, "Wireshark expert severity level", HFILL }
100 static gint *ett[] = {
101 &ett_expert,
102 &ett_subexpert
105 if (expert_tap == -1) {
106 expert_tap = register_tap("expert");
109 if (proto_expert == -1) {
110 proto_expert = proto_register_protocol("Expert Info", "Expert", "_ws.expert");
111 proto_register_field_array(proto_expert, hf, array_length(hf));
112 proto_register_subtree_array(ett, array_length(ett));
113 proto_set_cant_toggle(proto_expert);
116 highest_severity = 0;
118 proto_malformed = proto_get_id_by_filter_name("_ws.malformed");
121 void
122 expert_init(void)
124 gpa_expertinfo.len = 0;
125 gpa_expertinfo.allocated_len = 0;
126 gpa_expertinfo.ei = NULL;
129 void
130 expert_packet_cleanup(void)
134 void
135 expert_cleanup(void)
137 if (gpa_expertinfo.allocated_len) {
138 gpa_expertinfo.len = 0;
139 gpa_expertinfo.allocated_len = 0;
140 g_free(gpa_expertinfo.ei);
141 gpa_expertinfo.ei = NULL;
147 expert_get_highest_severity(void)
149 return highest_severity;
152 void
153 expert_update_comment_count(guint64 count)
155 if (count==0 && highest_severity==PI_COMMENT)
156 highest_severity = 0;
159 expert_module_t *expert_register_protocol(int id)
161 expert_module_t *module;
162 protocol_t *protocol;
164 protocol = find_protocol_by_id(id);
166 module = wmem_new(wmem_epan_scope(), expert_module_t);
167 module->proto_id = id;
168 module->proto_name = proto_get_protocol_short_name(protocol);
170 return module;
173 static int
174 expert_register_field_init(expert_field_info *expinfo, expert_module_t* module)
176 expinfo->protocol = module->proto_name;
178 /* if we always add and never delete, then id == len - 1 is correct */
179 if (gpa_expertinfo.len >= gpa_expertinfo.allocated_len) {
180 if (!gpa_expertinfo.ei) {
181 gpa_expertinfo.allocated_len = PRE_ALLOC_EXPERT_FIELDS_MEM;
182 gpa_expertinfo.ei = (expert_field_info **)g_malloc(sizeof(expert_field_info *)*PRE_ALLOC_EXPERT_FIELDS_MEM);
183 } else {
184 gpa_expertinfo.allocated_len += 1000;
185 gpa_expertinfo.ei = (expert_field_info **)g_realloc(gpa_expertinfo.ei,
186 sizeof(expert_field_info *)*gpa_expertinfo.allocated_len);
189 gpa_expertinfo.ei[gpa_expertinfo.len] = expinfo;
190 gpa_expertinfo.len++;
191 expinfo->id = gpa_expertinfo.len - 1;
193 return expinfo->id;
197 /* for use with static arrays only, since we don't allocate our own copies
198 of the expert_field_info struct contained within the exp_register_info struct */
199 void
200 expert_register_field_array(expert_module_t* module, ei_register_info *exp, const int num_records)
202 int i;
203 ei_register_info *ptr = exp;
205 for (i = 0; i < num_records; i++, ptr++) {
207 * Make sure we haven't registered this yet.
208 * Most fields have variables associated with them
209 * that are initialized to -1; some have array elements,
210 * or possibly uninitialized variables, so we also allow
211 * 0 (which is unlikely to be the field ID we get back
212 * from "expert_register_field_init()").
214 if (ptr->ids->ei != -1 && ptr->ids->ei != 0) {
215 fprintf(stderr,
216 "Duplicate field detected in call to expert_register_field_array: '%s' is already registered\n",
217 ptr->eiinfo.summary);
218 return;
221 /* Register the field with the experts */
222 ptr->ids->ei = expert_register_field_init(&ptr->eiinfo, module);
224 /* Register with the header field info, so it's display filterable */
225 ptr->eiinfo.hf_info.p_id = &ptr->ids->hf;
226 ptr->eiinfo.hf_info.hfinfo.abbrev = ptr->eiinfo.name;
227 ptr->eiinfo.hf_info.hfinfo.blurb = ptr->eiinfo.summary;
229 proto_register_field_array(module->proto_id, &ptr->eiinfo.hf_info, 1);
233 /** clear flags according to the mask and set new flag values */
234 #define FI_REPLACE_FLAGS(fi, mask, flags_in) { \
235 (fi->flags = (fi)->flags & ~(mask)); \
236 (fi->flags = (fi)->flags | (flags_in)); \
239 /* set's the PI_ flags to a protocol item
240 * (and its parent items till the toplevel) */
241 static void
242 expert_set_item_flags(proto_item *pi, const int group, const guint severity)
244 if (pi != NULL && PITEM_FINFO(pi) != NULL && (severity >= FI_GET_FLAG(PITEM_FINFO(pi), PI_SEVERITY_MASK))) {
245 FI_REPLACE_FLAGS(PITEM_FINFO(pi), PI_GROUP_MASK, group);
246 FI_REPLACE_FLAGS(PITEM_FINFO(pi), PI_SEVERITY_MASK, severity);
248 /* propagate till toplevel item */
249 pi = proto_item_get_parent(pi);
250 expert_set_item_flags(pi, group, severity);
254 static proto_tree*
255 expert_create_tree(proto_item *pi, int group, int severity, const char *msg)
257 proto_tree *tree;
258 proto_item *ti;
260 tree = proto_item_add_subtree(pi, ett_expert);
261 ti = proto_tree_add_protocol_format(tree, proto_expert, NULL, 0, 0, "Expert Info (%s/%s): %s",
262 val_to_str(severity, expert_severity_vals, "Unknown (%u)"),
263 val_to_str(group, expert_group_vals, "Unknown (%u)"),
264 msg);
265 PROTO_ITEM_SET_GENERATED(ti);
267 if (group == PI_MALFORMED) {
268 /* Add hidden malformed protocol filter */
269 proto_item *malformed_ti = proto_tree_add_item(tree, proto_malformed, NULL, 0, 0, ENC_NA);
270 PROTO_ITEM_SET_HIDDEN(malformed_ti);
273 return proto_item_add_subtree(ti, ett_subexpert);
276 static void
277 expert_set_info_vformat(packet_info *pinfo, proto_item *pi, int group, int severity, int hf_index, gboolean use_vaformat,
278 const char *format, va_list ap)
280 char formatted[ITEM_LABEL_LENGTH];
281 int tap;
282 expert_info_t *ei;
283 proto_tree *tree;
284 proto_item *ti;
286 if (pinfo == NULL && pi && pi->tree_data) {
287 pinfo = PTREE_DATA(pi)->pinfo;
290 /* if this packet isn't loaded because of a read filter, don't output anything */
291 if (pinfo == NULL || PINFO_FD_NUM(pinfo) == 0) {
292 return;
295 if (severity > highest_severity) {
296 highest_severity = severity;
299 if (pi != NULL && PITEM_FINFO(pi) != NULL) {
300 expert_set_item_flags(pi, group, severity);
303 if ((pi == NULL) || (PITEM_FINFO(pi) == NULL) ||
304 ((guint)severity >= FI_GET_FLAG(PITEM_FINFO(pi), PI_SEVERITY_MASK))) {
305 col_add_str(pinfo->cinfo, COL_EXPERT, val_to_str(severity, expert_severity_vals, "Unknown (%u)"));
308 if (use_vaformat) {
309 g_vsnprintf(formatted, ITEM_LABEL_LENGTH, format, ap);
310 } else {
311 g_strlcpy(formatted, format, ITEM_LABEL_LENGTH);
314 tree = expert_create_tree(pi, group, severity, formatted);
316 if (hf_index == -1) {
317 /* If no filterable expert info, just add the message */
318 ti = proto_tree_add_string(tree, hf_expert_msg, NULL, 0, 0, formatted);
319 PROTO_ITEM_SET_GENERATED(ti);
320 } else {
321 /* If filterable expert info, hide the "generic" form of the message,
322 and generate the formatted filterable expert info */
323 ti = proto_tree_add_none_format(tree, hf_index, NULL, 0, 0, "%s", formatted);
324 PROTO_ITEM_SET_GENERATED(ti);
325 ti = proto_tree_add_string(tree, hf_expert_msg, NULL, 0, 0, formatted);
326 PROTO_ITEM_SET_HIDDEN(ti);
329 ti = proto_tree_add_uint_format_value(tree, hf_expert_severity, NULL, 0, 0, severity,
330 "%s", val_to_str_const(severity, expert_severity_vals, "Unknown"));
331 PROTO_ITEM_SET_GENERATED(ti);
332 ti = proto_tree_add_uint_format_value(tree, hf_expert_group, NULL, 0, 0, group,
333 "%s", val_to_str_const(group, expert_group_vals, "Unknown"));
334 PROTO_ITEM_SET_GENERATED(ti);
336 tap = have_tap_listener(expert_tap);
338 if (!tap)
339 return;
341 ei = ep_new(expert_info_t);
343 ei->packet_num = PINFO_FD_NUM(pinfo);
344 ei->group = group;
345 ei->severity = severity;
346 ei->protocol = pinfo->current_proto;
347 ei->summary = ep_strdup(formatted);
349 /* if we have a proto_item (not a faked item), set expert attributes to it */
350 if (pi != NULL && PITEM_FINFO(pi) != NULL) {
351 ei->pitem = pi;
352 } else {
353 ei->pitem = NULL;
356 tap_queue_packet(expert_tap, pinfo, ei);
360 void
361 expert_add_info_format_internal(packet_info *pinfo, proto_item *pi, int group, int severity, const char *format, ...)
363 va_list ap;
365 va_start(ap, format);
366 expert_set_info_vformat(pinfo, pi, group, severity, -1, TRUE, format, ap);
367 va_end(ap);
370 void
371 expert_add_info(packet_info *pinfo, proto_item *pi, expert_field *expindex)
373 expert_field_info* eiinfo;
375 /* Look up the item */
376 EXPERT_REGISTRAR_GET_NTH(expindex->ei, eiinfo);
378 expert_set_info_vformat(pinfo, pi, eiinfo->group, eiinfo->severity, *eiinfo->hf_info.p_id, FALSE, eiinfo->summary, NULL);
381 void
382 expert_add_info_format(packet_info *pinfo, proto_item *pi, expert_field *expindex, const char *format, ...)
384 va_list ap;
385 expert_field_info* eiinfo;
387 /* Look up the item */
388 EXPERT_REGISTRAR_GET_NTH(expindex->ei, eiinfo);
390 va_start(ap, format);
391 expert_set_info_vformat(pinfo, pi, eiinfo->group, eiinfo->severity, *eiinfo->hf_info.p_id, TRUE, format, ap);
392 va_end(ap);
395 proto_item *
396 proto_tree_add_expert(proto_tree *tree, packet_info *pinfo, expert_field* expindex,
397 tvbuff_t *tvb, gint start, gint length)
399 expert_field_info* eiinfo;
400 proto_item *ti;
402 /* Look up the item */
403 EXPERT_REGISTRAR_GET_NTH(expindex->ei, eiinfo);
405 ti = proto_tree_add_text(tree, tvb, start, length, "%s", eiinfo->summary);
406 expert_set_info_vformat(pinfo, ti, eiinfo->group, eiinfo->severity, *eiinfo->hf_info.p_id, FALSE, eiinfo->summary, NULL);
407 return ti;
410 proto_item *
411 proto_tree_add_expert_format(proto_tree *tree, packet_info *pinfo, expert_field* expindex,
412 tvbuff_t *tvb, gint start, gint length, const char *format, ...)
414 va_list ap;
415 expert_field_info* eiinfo;
416 proto_item *ti;
418 /* Look up the item */
419 EXPERT_REGISTRAR_GET_NTH(expindex->ei, eiinfo);
421 va_start(ap, format);
422 ti = proto_tree_add_text_valist(tree, tvb, start, length, format, ap);
423 va_end(ap);
425 va_start(ap, format);
426 expert_set_info_vformat(pinfo, ti, eiinfo->group, eiinfo->severity, *eiinfo->hf_info.p_id, TRUE, format, ap);
427 va_end(ap);
429 return ti;