Snort: speed up parsing of options by avoiding g_snprintf()
[metze/wireshark/wip.git] / epan / expert.c
1 /* expert.c
2  * Collecting Expert information.
3  *
4  * Implemented as a tap named "expert".
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24
25 #include "config.h"
26
27 #include <stdio.h>
28 #include <stdlib.h>
29
30 #include <wsutil/ws_printf.h>
31
32 #include "packet.h"
33 #include "expert.h"
34 #include "uat.h"
35 #include "prefs.h"
36 #include "wmem/wmem.h"
37 #include "tap.h"
38
39 /* proto_expert cannot be static because it's referenced in the
40  * print routines
41  */
42 int proto_expert              = -1;
43
44 static int proto_malformed    = -1;
45
46 static int expert_tap         = -1;
47 static int highest_severity   =  0;
48
49 static int ett_expert         = -1;
50 static int ett_subexpert      = -1;
51
52 static int hf_expert_msg      = -1;
53 static int hf_expert_group    = -1;
54 static int hf_expert_severity = -1;
55
56 struct expert_module
57 {
58         const char *proto_name;
59         int         proto_id;      /* Cache this for registering hfs */
60 };
61
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;
69
70 /* Hash table of abbreviations and IDs */
71 static GHashTable *gpa_name_map = NULL;
72
73 /* Deregistered expert infos */
74 static GPtrArray *deregistered_expertinfos = NULL;
75
76 const value_string expert_group_vals[] = {
77         { PI_CHECKSUM,          "Checksum" },
78         { PI_SEQUENCE,          "Sequence" },
79         { PI_RESPONSE_CODE,     "Response" },
80         { PI_REQUEST_CODE,      "Request" },
81         { PI_UNDECODED,         "Undecoded" },
82         { PI_REASSEMBLE,        "Reassemble" },
83         { PI_MALFORMED,         "Malformed" },
84         { PI_DEBUG,             "Debug" },
85         { PI_PROTOCOL,          "Protocol" },
86         { PI_SECURITY,          "Security" },
87         { PI_COMMENTS_GROUP,    "Comment" },
88         { PI_DECRYPTION,        "Decryption" },
89         { PI_ASSUMPTION,        "Assumption" },
90         { PI_DEPRECATED,        "Deprecated" },
91         { 0, NULL }
92 };
93
94 const value_string expert_severity_vals[] = {
95         { PI_ERROR,             "Error" },
96         { PI_WARN,              "Warning" },
97         { PI_NOTE,              "Note" },
98         { PI_CHAT,              "Chat" },
99         { PI_COMMENT,           "Comment" },
100         { 1,                    "Ok" },
101         { 0, NULL }
102 };
103
104 /* Possible values for a checksum evaluation */
105 const value_string expert_checksum_vals[] = {
106         { EXPERT_CHECKSUM_DISABLED,   "Disabled"  },
107         { EXPERT_CHECKSUM_UNKNOWN,    "Unknown"  },
108         { EXPERT_CHECKSUM_GOOD,       "Good"  },
109         { EXPERT_CHECKSUM_BAD,        "Bad" },
110         { 0,        NULL }
111 };
112
113 static expert_field_info *expert_registrar_get_byname(const char *field_name);
114
115 /*----------------------------------------------------------------------------*/
116 /* UAT for customizing severity levels.                                       */
117 /*----------------------------------------------------------------------------*/
118 typedef struct
119 {
120         char    *field;
121         guint32  severity;
122 } expert_level_entry_t;
123
124 static expert_level_entry_t *uat_expert_entries = NULL;
125 static guint expert_level_entry_count = 0;
126 /* Array of field names currently in UAT */
127 static GArray *uat_saved_fields = NULL;
128
129 UAT_CSTRING_CB_DEF(uat_expert_entries, field, expert_level_entry_t)
130 UAT_VS_DEF(uat_expert_entries, severity, expert_level_entry_t, guint32, PI_ERROR, "Error")
131
132 static gboolean uat_expert_update_cb(void *r, char **err)
133 {
134         expert_level_entry_t *rec = (expert_level_entry_t *)r;
135
136         if (expert_registrar_get_byname(rec->field) == NULL) {
137                 *err = g_strdup_printf("Expert Info field doesn't exist");
138                 return FALSE;
139         }
140         return TRUE;
141 }
142
143 static void *uat_expert_copy_cb(void *n, const void *o, size_t siz _U_)
144 {
145         expert_level_entry_t       *new_record = (expert_level_entry_t*)n;
146         const expert_level_entry_t *old_record = (const expert_level_entry_t *)o;
147
148         new_record->field = g_strdup(old_record->field);
149
150         new_record->severity = old_record->severity;
151
152         return new_record;
153 }
154
155 static void uat_expert_free_cb(void*r)
156 {
157         expert_level_entry_t *rec = (expert_level_entry_t *)r;
158
159         g_free(rec->field);
160 }
161
162 static void uat_expert_post_update_cb(void)
163 {
164         guint              i;
165         expert_field_info *field;
166
167         /* Reset any of the previous list of expert info fields to their original severity */
168         for ( i = 0 ; i < uat_saved_fields->len; i++ ) {
169                 field = g_array_index(uat_saved_fields, expert_field_info*, i);
170                 if (field != NULL) {
171                         field->severity = field->orig_severity;
172                 }
173         }
174
175         g_array_set_size(uat_saved_fields, 0);
176
177         for (i = 0; i < expert_level_entry_count; i++)
178         {
179                 field = expert_registrar_get_byname(uat_expert_entries[i].field);
180                 if (field != NULL)
181                 {
182                         field->severity = uat_expert_entries[i].severity;
183                         g_array_append_val(uat_saved_fields, field);
184                 }
185         }
186 }
187
188 #define EXPERT_REGISTRAR_GET_NTH(eiindex, expinfo)                                               \
189         if((guint)eiindex >= gpa_expertinfo.len && getenv("WIRESHARK_ABORT_ON_DISSECTOR_BUG"))   \
190                 g_error("Unregistered expert info! index=%d", eiindex);                          \
191         DISSECTOR_ASSERT_HINT((guint)eiindex < gpa_expertinfo.len, "Unregistered expert info!"); \
192         DISSECTOR_ASSERT_HINT(gpa_expertinfo.ei[eiindex] != NULL, "Unregistered expert info!"); \
193         expinfo = gpa_expertinfo.ei[eiindex];
194
195 void
196 expert_packet_init(void)
197 {
198         module_t *module_expert;
199         uat_t    *expert_uat;
200
201         static hf_register_info hf[] = {
202                 { &hf_expert_msg,
203                         { "Message", "_ws.expert.message", FT_STRING, BASE_NONE, NULL, 0, "Wireshark expert information", HFILL }
204                 },
205                 { &hf_expert_group,
206                         { "Group", "_ws.expert.group", FT_UINT32, BASE_NONE, VALS(expert_group_vals), 0, "Wireshark expert group", HFILL }
207                 },
208                 { &hf_expert_severity,
209                         { "Severity level", "_ws.expert.severity", FT_UINT32, BASE_NONE, VALS(expert_severity_vals), 0, "Wireshark expert severity level", HFILL }
210                 }
211         };
212         static gint *ett[] = {
213                 &ett_expert,
214                 &ett_subexpert
215         };
216
217         /* UAT for overriding severity levels */
218         static uat_field_t custom_expert_fields[] = {
219                 UAT_FLD_CSTRING(uat_expert_entries, field, "Field name", "Expert Info filter name"),
220                 UAT_FLD_VS(uat_expert_entries, severity, "Severity", expert_severity_vals, "Custom severity level"),
221                 UAT_END_FIELDS
222         };
223
224         if (expert_tap == -1) {
225                 expert_tap = register_tap("expert");
226         }
227
228         if (proto_expert == -1) {
229                 proto_expert = proto_register_protocol("Expert Info", "Expert", "_ws.expert");
230                 proto_register_field_array(proto_expert, hf, array_length(hf));
231                 proto_register_subtree_array(ett, array_length(ett));
232                 proto_set_cant_toggle(proto_expert);
233
234                 module_expert = prefs_register_protocol(proto_expert, NULL);
235
236                 expert_uat = uat_new("Expert Info Severity Level Configuration",
237                         sizeof(expert_level_entry_t),
238                         "expert_severity",
239                         TRUE,
240                         (void **)&uat_expert_entries,
241                         &expert_level_entry_count,
242                         UAT_AFFECTS_DISSECTION,
243                         NULL,
244                         uat_expert_copy_cb,
245                         uat_expert_update_cb,
246                         uat_expert_free_cb,
247                         uat_expert_post_update_cb,
248                         NULL,
249                         custom_expert_fields);
250
251                 prefs_register_uat_preference(module_expert,
252                         "expert_severity_levels",
253                         "Severity Level Configuration",
254                         "A table that overrides Expert Info field severity levels to user configured levels",
255                         expert_uat);
256
257         }
258
259         highest_severity = 0;
260
261         proto_malformed = proto_get_id_by_filter_name("_ws.malformed");
262 }
263
264 void
265 expert_init(void)
266 {
267         gpa_expertinfo.len           = 0;
268         gpa_expertinfo.allocated_len = 0;
269         gpa_expertinfo.ei            = NULL;
270         gpa_name_map                 = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
271         uat_saved_fields             = g_array_new(FALSE, FALSE, sizeof(expert_field_info*));
272         deregistered_expertinfos     = g_ptr_array_new();
273 }
274
275 void
276 expert_packet_cleanup(void)
277 {
278 }
279
280 void
281 expert_cleanup(void)
282 {
283         if (gpa_expertinfo.allocated_len) {
284                 gpa_expertinfo.len           = 0;
285                 gpa_expertinfo.allocated_len = 0;
286                 g_free(gpa_expertinfo.ei);
287                 gpa_expertinfo.ei          = NULL;
288         }
289
290         /* Free the abbrev/ID GTree */
291         if (gpa_name_map) {
292                 g_hash_table_destroy(gpa_name_map);
293                 gpa_name_map = NULL;
294         }
295
296         /* Free the UAT saved fields */
297         if (uat_saved_fields) {
298                 g_array_free(uat_saved_fields, TRUE);
299                 uat_saved_fields = NULL;
300         }
301
302         if (deregistered_expertinfos) {
303                 g_ptr_array_free(deregistered_expertinfos, FALSE);
304                 deregistered_expertinfos = NULL;
305         }
306 }
307
308
309 int
310 expert_get_highest_severity(void)
311 {
312         return highest_severity;
313 }
314
315 void
316 expert_update_comment_count(guint64 count)
317 {
318         if (count==0 && highest_severity==PI_COMMENT)
319                 highest_severity = 0;
320 }
321
322 expert_module_t *expert_register_protocol(int id)
323 {
324         expert_module_t *module;
325         protocol_t      *protocol;
326
327         protocol = find_protocol_by_id(id);
328
329         module = wmem_new(wmem_epan_scope(), expert_module_t);
330         module->proto_id = id;
331         module->proto_name = proto_get_protocol_short_name(protocol);
332
333         return module;
334 }
335
336 void
337 expert_deregister_expertinfo (const char *abbrev)
338 {
339         expert_field_info *expinfo = (expert_field_info*)g_hash_table_lookup(gpa_name_map, abbrev);
340         if (expinfo) {
341                 g_ptr_array_add(deregistered_expertinfos, gpa_expertinfo.ei[expinfo->id]);
342                 g_hash_table_steal(gpa_name_map, abbrev);
343         }
344 }
345
346 void
347 expert_deregister_protocol (expert_module_t *module)
348 {
349         wmem_free(wmem_epan_scope(), module);
350 }
351
352 static void
353 free_deregistered_expertinfo (gpointer data, gpointer user_data _U_)
354 {
355         expert_field_info *expinfo = (expert_field_info *) data;
356         gpa_expertinfo.ei[expinfo->id] = NULL; /* Invalidate this id */
357 }
358
359 void
360 expert_free_deregistered_expertinfos (void)
361 {
362         g_ptr_array_foreach(deregistered_expertinfos, free_deregistered_expertinfo, NULL);
363         g_ptr_array_free(deregistered_expertinfos, TRUE);
364         deregistered_expertinfos = g_ptr_array_new();
365 }
366
367 static int
368 expert_register_field_init(expert_field_info *expinfo, expert_module_t *module)
369 {
370         expinfo->protocol      = module->proto_name;
371
372         /* if we always add and never delete, then id == len - 1 is correct */
373         if (gpa_expertinfo.len >= gpa_expertinfo.allocated_len) {
374                 if (!gpa_expertinfo.ei) {
375                         gpa_expertinfo.allocated_len = PRE_ALLOC_EXPERT_FIELDS_MEM;
376                         gpa_expertinfo.ei = (expert_field_info **)g_malloc(sizeof(expert_field_info *)*PRE_ALLOC_EXPERT_FIELDS_MEM);
377                 } else {
378                         gpa_expertinfo.allocated_len += 1000;
379                         gpa_expertinfo.ei = (expert_field_info **)g_realloc(gpa_expertinfo.ei,
380                                                    sizeof(expert_field_info *)*gpa_expertinfo.allocated_len);
381                 }
382         }
383         gpa_expertinfo.ei[gpa_expertinfo.len] = expinfo;
384         gpa_expertinfo.len++;
385         expinfo->id = gpa_expertinfo.len - 1;
386         /* Save the original severity so it can be restored by the UAT */
387         expinfo->orig_severity = expinfo->severity;
388
389         /* save field name for lookup */
390         g_hash_table_insert(gpa_name_map, (gpointer) (expinfo->name), expinfo);
391
392         return expinfo->id;
393 }
394
395
396 /* for use with static arrays only, since we don't allocate our own copies
397 of the expert_field_info struct contained within the exp_register_info struct */
398 void
399 expert_register_field_array(expert_module_t *module, ei_register_info *exp, const int num_records)
400 {
401         int               i;
402         ei_register_info *ptr = exp;
403
404         for (i = 0; i < num_records; i++, ptr++) {
405                 /*
406                  * Make sure we haven't registered this yet.
407                  * Most fields have variables associated with them
408                  * that are initialized to -1; some have array elements,
409                  * or possibly uninitialized variables, so we also allow
410                  * 0 (which is unlikely to be the field ID we get back
411                  * from "expert_register_field_init()").
412                  */
413                 if (ptr->ids->ei != -1 && ptr->ids->ei != 0) {
414                         fprintf(stderr,
415                                 "Duplicate field detected in call to expert_register_field_array: '%s' is already registered, name=%s\n",
416                                 ptr->eiinfo.summary, ptr->eiinfo.name);
417                         return;
418                 }
419
420                 /* Register the field with the experts */
421                 ptr->ids->ei = expert_register_field_init(&ptr->eiinfo, module);
422
423                 /* Register with the header field info, so it's display filterable */
424                 ptr->eiinfo.hf_info.p_id = &ptr->ids->hf;
425                 ptr->eiinfo.hf_info.hfinfo.name = ptr->eiinfo.summary;
426                 ptr->eiinfo.hf_info.hfinfo.abbrev = ptr->eiinfo.name;
427
428                 proto_register_field_array(module->proto_id, &ptr->eiinfo.hf_info, 1);
429         }
430 }
431
432 /* Finds a record in the expert array by name.
433  * For the moment, this function is only used "internally"
434  * but may find a reason to be exported
435  */
436 static expert_field_info *
437 expert_registrar_get_byname(const char *field_name)
438 {
439         expert_field_info *hfinfo;
440
441         if (!field_name)
442                 return NULL;
443
444         hfinfo = (expert_field_info*)g_hash_table_lookup(gpa_name_map, field_name);
445
446         return hfinfo;
447 }
448
449 /**
450  * Get summary text of an expert_info field.
451  * This is intended for use in expert_add_info_format or proto_tree_add_expert_format
452  * to get the "base" string to then append additional information
453  */
454 const gchar* expert_get_summary(expert_field *eiindex)
455 {
456         expert_field_info *eiinfo;
457
458         /* Look up the item */
459         EXPERT_REGISTRAR_GET_NTH(eiindex->ei, eiinfo);
460
461     return eiinfo->summary;
462 }
463
464 /** clear flags according to the mask and set new flag values */
465 #define FI_REPLACE_FLAGS(fi, mask, flags_in) { \
466         (fi->flags = (fi)->flags & ~(mask)); \
467         (fi->flags = (fi)->flags | (flags_in)); \
468 }
469
470 /* set's the PI_ flags to a protocol item
471  * (and its parent items till the toplevel) */
472 static void
473 expert_set_item_flags(proto_item *pi, const int group, const guint severity)
474 {
475         if (pi != NULL && PITEM_FINFO(pi) != NULL && (severity >= FI_GET_FLAG(PITEM_FINFO(pi), PI_SEVERITY_MASK))) {
476                 FI_REPLACE_FLAGS(PITEM_FINFO(pi), PI_GROUP_MASK, group);
477                 FI_REPLACE_FLAGS(PITEM_FINFO(pi), PI_SEVERITY_MASK, severity);
478
479                 /* propagate till toplevel item */
480                 pi = proto_item_get_parent(pi);
481                 expert_set_item_flags(pi, group, severity);
482         }
483 }
484
485 static proto_tree*
486 expert_create_tree(proto_item *pi, int group, int severity, const char *msg)
487 {
488         proto_tree *tree;
489         proto_item *ti;
490
491         tree = proto_item_add_subtree(pi, ett_expert);
492         ti = proto_tree_add_protocol_format(tree, proto_expert, NULL, 0, 0, "Expert Info (%s/%s): %s",
493                                             val_to_str(severity, expert_severity_vals, "Unknown (%u)"),
494                                             val_to_str(group, expert_group_vals, "Unknown (%u)"),
495                                             msg);
496         PROTO_ITEM_SET_GENERATED(ti);
497
498         if (group == PI_MALFORMED) {
499                 /* Add hidden malformed protocol filter */
500                 proto_item *malformed_ti = proto_tree_add_item(tree, proto_malformed, NULL, 0, 0, ENC_NA);
501                 PROTO_ITEM_SET_HIDDEN(malformed_ti);
502         }
503
504         return proto_item_add_subtree(ti, ett_subexpert);
505 }
506
507 static void
508 expert_set_info_vformat(packet_info *pinfo, proto_item *pi, int group, int severity, int hf_index, gboolean use_vaformat,
509                         const char *format, va_list ap)
510 {
511         char           formatted[ITEM_LABEL_LENGTH];
512         int            tap;
513         expert_info_t *ei;
514         proto_tree    *tree;
515         proto_item    *ti;
516
517         if (pinfo == NULL && pi && pi->tree_data) {
518                 pinfo = PTREE_DATA(pi)->pinfo;
519         }
520
521         /* if this packet isn't loaded because of a read filter, don't output anything */
522         if (pinfo == NULL || pinfo->num == 0) {
523                 return;
524         }
525
526         if (severity > highest_severity) {
527                 highest_severity = severity;
528         }
529
530         /* XXX: can we get rid of these checks and make them programming errors instead now? */
531         if (pi != NULL && PITEM_FINFO(pi) != NULL) {
532                 expert_set_item_flags(pi, group, severity);
533         }
534
535         if ((pi == NULL) || (PITEM_FINFO(pi) == NULL) ||
536                 ((guint)severity >= FI_GET_FLAG(PITEM_FINFO(pi), PI_SEVERITY_MASK))) {
537                 col_add_str(pinfo->cinfo, COL_EXPERT, val_to_str(severity, expert_severity_vals, "Unknown (%u)"));
538         }
539
540         if (use_vaformat) {
541                 ws_vsnprintf(formatted, ITEM_LABEL_LENGTH, format, ap);
542         } else {
543                 g_strlcpy(formatted, format, ITEM_LABEL_LENGTH);
544         }
545
546         tree = expert_create_tree(pi, group, severity, formatted);
547
548         if (hf_index == -1) {
549                 /* If no filterable expert info, just add the message */
550                 ti = proto_tree_add_string(tree, hf_expert_msg, NULL, 0, 0, formatted);
551                 PROTO_ITEM_SET_GENERATED(ti);
552         } else {
553                 /* If filterable expert info, hide the "generic" form of the message,
554                    and generate the formatted filterable expert info */
555                 ti = proto_tree_add_none_format(tree, hf_index, NULL, 0, 0, "%s", formatted);
556                 PROTO_ITEM_SET_GENERATED(ti);
557                 ti = proto_tree_add_string(tree, hf_expert_msg, NULL, 0, 0, formatted);
558                 PROTO_ITEM_SET_HIDDEN(ti);
559         }
560
561         ti = proto_tree_add_uint_format_value(tree, hf_expert_severity, NULL, 0, 0, severity,
562                                               "%s", val_to_str_const(severity, expert_severity_vals, "Unknown"));
563         PROTO_ITEM_SET_GENERATED(ti);
564         ti = proto_tree_add_uint_format_value(tree, hf_expert_group, NULL, 0, 0, group,
565                                               "%s", val_to_str_const(group, expert_group_vals, "Unknown"));
566         PROTO_ITEM_SET_GENERATED(ti);
567
568         tap = have_tap_listener(expert_tap);
569
570         if (!tap)
571                 return;
572
573         ei = wmem_new(wmem_packet_scope(), expert_info_t);
574
575         ei->packet_num  = pinfo->num;
576         ei->group       = group;
577         ei->severity    = severity;
578         ei->hf_index    = hf_index;
579         ei->protocol    = pinfo->current_proto;
580         ei->summary     = wmem_strdup(wmem_packet_scope(), formatted);
581
582         /* if we have a proto_item (not a faked item), set expert attributes to it */
583         if (pi != NULL && PITEM_FINFO(pi) != NULL) {
584                 ei->pitem = pi;
585         }
586         /* XXX: remove this because we don't have an internal-only function now? */
587         else {
588                 ei->pitem = NULL;
589         }
590
591         tap_queue_packet(expert_tap, pinfo, ei);
592 }
593
594 /* Helper function for expert_add_info() to work around compiler's special needs on ARM */
595 static inline void
596 expert_add_info_internal(packet_info *pinfo, proto_item *pi, expert_field *expindex, ...)
597 {
598         /* the va_list is ignored */
599         va_list            unused;
600         expert_field_info *eiinfo;
601
602         /* Look up the item */
603         EXPERT_REGISTRAR_GET_NTH(expindex->ei, eiinfo);
604
605         va_start(unused, expindex);
606         expert_set_info_vformat(pinfo, pi, eiinfo->group, eiinfo->severity, *eiinfo->hf_info.p_id, FALSE, eiinfo->summary, unused);
607         va_end(unused);
608 }
609
610 void
611 expert_add_info(packet_info *pinfo, proto_item *pi, expert_field *expindex)
612 {
613         expert_add_info_internal(pinfo, pi, expindex);
614 }
615
616 void
617 expert_add_info_format(packet_info *pinfo, proto_item *pi, expert_field *expindex, const char *format, ...)
618 {
619         va_list            ap;
620         expert_field_info *eiinfo;
621
622         /* Look up the item */
623         EXPERT_REGISTRAR_GET_NTH(expindex->ei, eiinfo);
624
625         va_start(ap, format);
626         expert_set_info_vformat(pinfo, pi, eiinfo->group, eiinfo->severity, *eiinfo->hf_info.p_id, TRUE, format, ap);
627         va_end(ap);
628 }
629
630 /* Helper function for expert_add_expert() to work around compiler's special needs on ARM */
631 static inline proto_item *
632 proto_tree_add_expert_internal(proto_tree *tree, packet_info *pinfo, expert_field *expindex,
633                 tvbuff_t *tvb, gint start, gint length, ...)
634 {
635         expert_field_info *eiinfo;
636         proto_item        *ti;
637         va_list            unused;
638
639         /* Look up the item */
640         EXPERT_REGISTRAR_GET_NTH(expindex->ei, eiinfo);
641
642         ti = proto_tree_add_text_internal(tree, tvb, start, length, "%s", eiinfo->summary);
643         va_start(unused, length);
644         expert_set_info_vformat(pinfo, ti, eiinfo->group, eiinfo->severity, *eiinfo->hf_info.p_id, FALSE, eiinfo->summary, unused);
645         va_end(unused);
646         return ti;
647 }
648
649 proto_item *
650 proto_tree_add_expert(proto_tree *tree, packet_info *pinfo, expert_field *expindex,
651                 tvbuff_t *tvb, gint start, gint length)
652 {
653         return proto_tree_add_expert_internal(tree, pinfo, expindex, tvb, start, length);
654 }
655
656 proto_item *
657 proto_tree_add_expert_format(proto_tree *tree, packet_info *pinfo, expert_field *expindex,
658                 tvbuff_t *tvb, gint start, gint length, const char *format, ...)
659 {
660         va_list            ap;
661         expert_field_info *eiinfo;
662         proto_item        *ti;
663
664         /* Look up the item */
665         EXPERT_REGISTRAR_GET_NTH(expindex->ei, eiinfo);
666
667         va_start(ap, format);
668         ti = proto_tree_add_text_valist_internal(tree, tvb, start, length, format, ap);
669         va_end(ap);
670
671         va_start(ap, format);
672         expert_set_info_vformat(pinfo, ti, eiinfo->group, eiinfo->severity, *eiinfo->hf_info.p_id, TRUE, format, ap);
673         va_end(ap);
674
675         return ti;
676 }
677
678 /*
679  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
680  *
681  * Local variables:
682  * c-basic-offset: 8
683  * tab-width: 8
684  * indent-tabs-mode: t
685  * End:
686  *
687  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
688  * :indentSize=8:tabSize=8:noTabs=false:
689  */