Coverage Report

Created: 2025-08-04 07:15

/src/wireshark/epan/funnel.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *  funnel.c
3
 *
4
 * EPAN's GUI mini-API
5
 *
6
 * (c) 2006, Luis E. Garcia Ontanon <luis@ontanon.org>
7
 *
8
 * Wireshark - Network traffic analyzer
9
 * By Gerald Combs <gerald@wireshark.org>
10
 * Copyright 1998 Gerald Combs
11
 *
12
 * SPDX-License-Identifier: GPL-2.0-or-later
13
 */
14
15
#include "config.h"
16
17
#include <epan/funnel.h>
18
#include <wsutil/glib-compat.h>
19
20
typedef struct _funnel_menu_t {
21
    char *name;
22
    register_stat_group_t group;
23
    funnel_menu_callback callback;
24
    void *callback_data;
25
    funnel_menu_callback_data_free callback_data_free;
26
    bool retap;
27
    struct _funnel_menu_t* next;
28
} funnel_menu_t;
29
30
typedef struct _console_menu {
31
    char *name;
32
    funnel_console_eval_cb_t eval_cb;
33
    funnel_console_open_cb_t open_cb;
34
    funnel_console_close_cb_t close_cb;
35
    void *user_data;
36
    funnel_console_data_free_cb_t data_free_cb;
37
} funnel_console_menu_t;
38
39
/* XXX This assumes one main window and one capture file. */
40
static const funnel_ops_t* ops;
41
static funnel_menu_t* registered_menus;
42
static funnel_menu_t* added_menus;
43
static funnel_menu_t* removed_menus;
44
static bool menus_registered;
45
46
/**
47
 * Represents a single packet menu entry and callback
48
 */
49
typedef struct _funnel_packet_menu_t {
50
    char *name;                           /**< Name to display in the GUI */
51
    char *required_fields;                /**< comma-separated list of fields
52
                                               that must be present for the
53
                                               packet menu to be displayed */
54
    funnel_packet_menu_callback callback; /**< Lua function to be called on
55
                                               menu item selection. */
56
    void *callback_data;                  /**< Lua state for the callback
57
                                               function */
58
    bool retap;                           /**< Whether or not to rescan the
59
                                               capture file's packets */
60
    struct _funnel_packet_menu_t* next;   /**< Pointer to the next
61
                                               _funnel_packet_menu_t for the
62
                                               singly-linked list
63
                                               implemenation */
64
} funnel_packet_menu_t;
65
66
/*
67
 * List of all registered funnel_packet_menu_t's
68
 */
69
static funnel_packet_menu_t* registered_packet_menus;
70
71
static GSList *registered_console_menus;
72
73
/*
74
 * true if the packet menus were modified since the last registration
75
 */
76
static bool packet_menus_modified;
77
static void funnel_clear_packet_menu (funnel_packet_menu_t** menu_list);
78
79
0
const funnel_ops_t* funnel_get_funnel_ops(void) { return ops;  }
80
0
void funnel_set_funnel_ops(const funnel_ops_t* o) { ops = o; }
81
82
static void funnel_clear_console_menu(void);
83
84
static void funnel_insert_menu (funnel_menu_t** menu_list, funnel_menu_t *menu)
85
0
{
86
0
    if (!(*menu_list))  {
87
0
        *menu_list = menu;
88
0
    } else {
89
0
        funnel_menu_t* c;
90
0
        for (c = *menu_list; c->next; c = c->next);
91
0
        c->next = menu;
92
0
    }
93
0
}
94
95
static void funnel_remove_menu (funnel_menu_t ** menu_list, funnel_menu_t *menu)
96
0
{
97
0
    funnel_menu_t *m = *menu_list, *p = NULL;
98
99
0
    while (m) {
100
0
        if (m->callback == menu->callback) {
101
0
            if (p) {
102
0
                p->next = m->next;
103
0
            } else {
104
0
                *menu_list = m->next;
105
0
            }
106
0
            g_free(m->name);
107
0
            if (m->callback_data_free) {
108
0
                m->callback_data_free(m->callback_data);
109
0
            }
110
0
            g_free(m);
111
0
            if (p) {
112
0
                m = p->next;
113
0
            } else {
114
0
                m = *menu_list;
115
0
            }
116
0
        } else {
117
0
            p = m;
118
0
            m = m->next;
119
0
        }
120
0
    }
121
0
}
122
123
static void funnel_clear_menu (funnel_menu_t** menu_list)
124
0
{
125
0
    funnel_menu_t *m;
126
127
0
    while (*menu_list) {
128
0
        m = *menu_list;
129
0
        *menu_list = m->next;
130
0
        g_free(m->name);
131
0
        g_free(m);
132
0
    }
133
0
    *menu_list = NULL;
134
0
}
135
136
void funnel_register_menu(const char *name,
137
                          register_stat_group_t group,
138
                          funnel_menu_callback callback,
139
                          void *callback_data,
140
                          funnel_menu_callback_data_free callback_data_free,
141
                          bool retap)
142
0
{
143
0
    funnel_menu_t* m = g_new(funnel_menu_t, 1);
144
0
    m->name = g_strdup(name);
145
0
    m->group = group;
146
0
    m->callback = callback;
147
0
    m->callback_data = callback_data;
148
0
    m->callback_data_free = callback_data_free;
149
0
    m->retap = retap;
150
0
    m->next = NULL;
151
152
0
    funnel_insert_menu(&registered_menus, m);
153
0
    if (menus_registered) {
154
0
        funnel_menu_t* m_r = (funnel_menu_t *)g_memdup2(m, sizeof *m);
155
0
        m_r->name = g_strdup(name);
156
0
        funnel_insert_menu(&added_menus, m_r);
157
0
    }
158
0
}
159
160
void funnel_deregister_menus(funnel_menu_callback callback)
161
0
{
162
0
    funnel_menu_t* m = g_new0(funnel_menu_t, 1);
163
0
    m->callback = callback;
164
165
0
    funnel_remove_menu(&registered_menus, m);
166
0
    funnel_insert_menu(&removed_menus, m);
167
168
    // Clear and free memory of packet menus
169
0
    funnel_clear_packet_menu(&registered_packet_menus);
170
0
    packet_menus_modified = true;
171
0
}
172
173
void funnel_register_all_menus(funnel_registration_cb_t r_cb)
174
0
{
175
0
    funnel_menu_t* c;
176
0
    for (c = registered_menus; c; c = c->next) {
177
0
        r_cb(c->name,c->group,c->callback,c->callback_data,c->retap);
178
0
    }
179
0
    menus_registered = true;
180
0
}
181
182
void funnel_reload_menus(funnel_deregistration_cb_t d_cb,
183
                         funnel_registration_cb_t r_cb)
184
0
{
185
0
    funnel_menu_t* c;
186
0
    for (c = removed_menus; c; c = c->next) {
187
0
        d_cb(c->callback);
188
0
    }
189
0
    for (c = added_menus; c; c = c->next) {
190
0
        r_cb(c->name,c->group,c->callback,c->callback_data,c->retap);
191
0
    }
192
193
0
    funnel_clear_menu(&removed_menus);
194
0
    funnel_clear_menu(&added_menus);
195
0
}
196
197
198
/*
199
 * Inserts a funnel_packet_menu_t into a list of funnel_packet_menu_t's
200
 *
201
 * @param menu_list the list of menus that the menu will be added to
202
 * @param menu the menu to add to the list of menus
203
 */
204
static void funnel_insert_packet_menu (funnel_packet_menu_t** menu_list, funnel_packet_menu_t *menu)
205
0
{
206
0
    if (!(*menu_list))  {
207
0
        *menu_list = menu;
208
0
    } else {
209
0
        funnel_packet_menu_t* c;
210
0
        for (c = *menu_list; c->next; c = c->next);
211
0
        c->next = menu;
212
0
    }
213
0
}
214
215
/**
216
 * Entry point for Lua code to register a packet menu
217
 *
218
 * Stores the menu name and callback from the Lua code
219
 * into registered_packet_menus so that the
220
 * Wireshark GUI code can retrieve it with
221
 * funnel_register_all_packet_menus().
222
 */
223
void funnel_register_packet_menu(const char *name,
224
                                 const char *required_fields,
225
                                 funnel_packet_menu_callback callback,
226
                                 void *callback_data,
227
                                 bool retap)
228
0
{
229
0
    funnel_packet_menu_t* m = g_new0(funnel_packet_menu_t, 1);
230
0
    m->name = g_strdup(name);
231
0
    m->required_fields = g_strdup(required_fields);
232
0
    m->callback = callback;
233
0
    m->callback_data = callback_data;
234
0
    m->retap = retap;
235
0
    m->next = NULL;
236
237
0
    funnel_insert_packet_menu(&registered_packet_menus, m);
238
0
    packet_menus_modified = true;
239
0
}
240
241
/**
242
 * Clears a list of funnel_packet_menu_t's and free()s all associated memory
243
 *
244
 * @param menu_list the list of menus to clear
245
 */
246
static void funnel_clear_packet_menu (funnel_packet_menu_t** menu_list)
247
0
{
248
0
    funnel_packet_menu_t *m;
249
250
0
    while (*menu_list) {
251
0
        m = *menu_list;
252
0
        *menu_list = m->next;
253
0
        g_free(m->name);
254
0
        g_free(m->required_fields);
255
0
        if (m->callback_data) {
256
0
            g_free(m->callback_data);
257
0
        }
258
0
        g_free(m);
259
0
    }
260
0
    *menu_list = NULL;
261
0
}
262
263
/**
264
 * Entry point for Wireshark GUI to obtain all registered packet menus
265
 *
266
 * Calls the supplied callback for each packet menu registered with
267
 * funnel_register_packet_menu().
268
 *
269
 * @param r_cb the callback function to call with each registered packet menu
270
 */
271
void funnel_register_all_packet_menus(funnel_registration_packet_cb_t r_cb)
272
0
{
273
0
    funnel_packet_menu_t* c;
274
0
    for (c = registered_packet_menus; c; c = c->next) {
275
0
        r_cb(c->name,c->required_fields,c->callback,c->callback_data,c->retap);
276
0
    }
277
0
    packet_menus_modified = false;
278
0
}
279
280
/**
281
 * Returns whether the packet menus have been modified since they were last registered
282
 *
283
 * @return true if the packet menus were modified since the last registration
284
 */
285
bool funnel_packet_menus_modified(void)
286
0
{
287
0
    return packet_menus_modified;
288
0
}
289
290
void funnel_cleanup(void)
291
0
{
292
0
    funnel_clear_menu(&registered_menus);
293
0
    funnel_clear_packet_menu(&registered_packet_menus);
294
0
    funnel_clear_console_menu();
295
0
}
296
297
/**
298
 * Entry point for code to register a console menu
299
 */
300
void funnel_register_console_menu(const char *name,
301
                                funnel_console_eval_cb_t eval_cb,
302
                                funnel_console_open_cb_t open_cb,
303
                                funnel_console_close_cb_t close_cb,
304
                                void *callback_data,
305
                                funnel_console_data_free_cb_t free_data)
306
0
{
307
0
    funnel_console_menu_t* m = g_new0(funnel_console_menu_t, 1);
308
0
    m->name = g_strdup(name);
309
0
    m->eval_cb = eval_cb;
310
0
    m->open_cb = open_cb;
311
0
    m->close_cb = close_cb;
312
0
    m->user_data = callback_data;
313
0
    m->data_free_cb = free_data;
314
315
0
    registered_console_menus = g_slist_prepend(registered_console_menus, m);
316
0
}
317
318
void funnel_register_all_console_menus(funnel_registration_console_cb_t r_cb)
319
0
{
320
0
    GSList *l;
321
0
    for (l = registered_console_menus; l != NULL; l = l->next) {
322
0
        funnel_console_menu_t *m = l->data;
323
0
        r_cb(m->name, m->eval_cb, m->open_cb, m->close_cb, m->user_data);
324
0
    }
325
0
}
326
327
static void funnel_clear_console_menu(void)
328
0
{
329
0
    GSList *l;
330
0
    for (l = registered_console_menus; l != NULL; l = l->next) {
331
0
        funnel_console_menu_t *m = l->data;
332
0
        g_free(m->name);
333
0
        if (m->data_free_cb && m->user_data) {
334
0
            m->data_free_cb(m->user_data);
335
0
        }
336
0
        g_free(l->data);
337
0
        l->data = NULL;
338
0
    }
339
0
    g_slist_free(registered_console_menus);
340
0
    registered_console_menus = NULL;
341
0
}
342
343
/*
344
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
345
 *
346
 * Local variables:
347
 * c-basic-offset: 4
348
 * tab-width: 8
349
 * indent-tabs-mode: nil
350
 * End:
351
 *
352
 * vi: set shiftwidth=4 tabstop=8 expandtab:
353
 * :indentSize=4:tabSize=8:noTabs=true:
354
 */