Coverage Report

Created: 2026-05-14 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/funnel.c
Line
Count
Source
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
} funnel_menu_t;
28
29
typedef struct _console_menu {
30
    char *name;
31
    funnel_console_eval_cb_t eval_cb;
32
    funnel_console_open_cb_t open_cb;
33
    funnel_console_close_cb_t close_cb;
34
    void *user_data;
35
    funnel_console_data_free_cb_t data_free_cb;
36
} funnel_console_menu_t;
37
38
/**
39
 * Represents a single packet menu entry and callback
40
 */
41
typedef struct _funnel_packet_menu_t {
42
    char *name;                           /**< Name to display in the GUI */
43
    char *required_fields;                /**< comma-separated list of fields
44
                                               that must be present for the
45
                                               packet menu to be displayed */
46
    funnel_packet_menu_callback callback; /**< Lua function to be called on
47
                                               menu item selection. */
48
    void *callback_data;                  /**< Lua state for the callback
49
                                               function */
50
    bool retap;                           /**< Whether or not to rescan the
51
                                               capture file's packets */
52
} funnel_packet_menu_t;
53
54
55
/* XXX This assumes one main window and one capture file. */
56
static const funnel_ops_t* ops;
57
static GSList* registered_menus;
58
static GSList* added_menus;
59
static GSList* removed_menus;
60
static bool menus_registered;
61
62
/*
63
 * List of all registered funnel_packet_menu_t's
64
 */
65
static GSList* registered_packet_menus;
66
static GSList* registered_console_menus;
67
68
/*
69
 * true if the packet menus were modified since the last registration
70
 */
71
static bool packet_menus_modified;
72
73
static void free_funnel_packet_menu(gpointer data, gpointer user_data);
74
75
const funnel_ops_t* funnel_get_funnel_ops(void)
76
0
{
77
0
    return ops;
78
0
}
79
80
static void free_funnel_menu(gpointer data, gpointer user_data _U_)
81
0
{
82
0
    funnel_menu_t* m = (funnel_menu_t*)data;
83
84
0
    g_free(m->name);
85
0
    g_free(m);
86
0
}
87
88
static void funnel_remove_menu(GSList** menu_list, funnel_menu_t *menu)
89
0
{
90
0
    GSList* current = *menu_list;
91
92
0
    while (current != NULL) {
93
0
        GSList* next = current->next; // Store the next pointer BEFORE potentially removing current
94
0
        funnel_menu_t* m = (funnel_menu_t*)current->data;
95
0
        if (m->callback == menu->callback) {
96
0
            if (m->callback_data_free) {
97
0
                m->callback_data_free(m->callback_data);
98
0
            }
99
0
            free_funnel_menu(m, NULL);
100
0
            *menu_list = g_slist_remove(*menu_list, current->data);
101
0
        }
102
103
0
        current = next; // Move to the stored next pointer
104
0
    }
105
0
}
106
107
static void funnel_clear_menu(GSList** menu_list, GFunc free_func)
108
0
{
109
0
    g_slist_foreach(*menu_list, free_func, NULL);
110
0
    g_slist_free(*menu_list);
111
112
0
    *menu_list = NULL;
113
0
}
114
115
void funnel_register_menu(const char *name,
116
                          register_stat_group_t group,
117
                          funnel_menu_callback callback,
118
                          void *callback_data,
119
                          funnel_menu_callback_data_free callback_data_free,
120
                          bool retap)
121
0
{
122
0
    funnel_menu_t* m = g_new(funnel_menu_t, 1);
123
124
0
    m->name = g_strdup(name);
125
0
    m->group = group;
126
0
    m->callback = callback;
127
0
    m->callback_data = callback_data;
128
0
    m->callback_data_free = callback_data_free;
129
0
    m->retap = retap;
130
131
0
    registered_menus = g_slist_append(registered_menus, m);
132
133
0
    if (menus_registered) {
134
0
        funnel_menu_t* m_r = (funnel_menu_t *)g_memdup2(m, sizeof *m);
135
0
        m_r->name = g_strdup(name);
136
0
        added_menus = g_slist_append(added_menus, m_r);
137
0
    }
138
0
}
139
140
void funnel_deregister_menus(funnel_menu_callback callback)
141
0
{
142
0
    funnel_menu_t* m = g_new0(funnel_menu_t, 1);
143
144
0
    m->callback = callback;
145
146
0
    funnel_remove_menu(&registered_menus, m);
147
0
    removed_menus = g_slist_append(removed_menus, m);
148
149
    // Clear and free memory of packet menus
150
0
    funnel_clear_menu(&registered_packet_menus, free_funnel_packet_menu);
151
0
    packet_menus_modified = true;
152
0
}
153
154
static void funnel_register_all_menus(funnel_registration_cb_t r_cb)
155
0
{
156
0
    if (r_cb == NULL) {
157
0
        return;
158
0
    }
159
160
0
    for (GSList* l = registered_menus; l; l = l->next) {
161
0
        funnel_menu_t* c = (funnel_menu_t*)l->data;
162
0
        r_cb(c->name,c->group,c->callback,c->callback_data,c->retap);
163
0
    }
164
0
}
165
166
void funnel_reload_menus(funnel_deregistration_cb_t d_cb,
167
                         funnel_registration_cb_t r_cb)
168
0
{
169
0
    for (GSList* l = removed_menus; l; l = l->next) {
170
0
        funnel_menu_t* c = (funnel_menu_t*)l->data;
171
0
        d_cb(c->callback);
172
0
    }
173
174
0
    for (GSList* l = added_menus; l; l = l->next) {
175
0
        funnel_menu_t* c = (funnel_menu_t*)l->data;
176
0
        r_cb(c->name,c->group,c->callback,c->callback_data,c->retap);
177
0
    }
178
179
0
    funnel_clear_menu(&removed_menus, free_funnel_menu);
180
0
    funnel_clear_menu(&added_menus, free_funnel_menu);
181
0
}
182
183
/**
184
 * Entry point for Lua code to register a packet menu
185
 *
186
 * Stores the menu name and callback from the Lua code
187
 * into registered_packet_menus so that the
188
 * Wireshark GUI code can retrieve it with
189
 * funnel_register_all_packet_menus().
190
 */
191
void funnel_register_packet_menu(const char *name,
192
                                 const char *required_fields,
193
                                 funnel_packet_menu_callback callback,
194
                                 void *callback_data,
195
                                 bool retap)
196
0
{
197
0
    funnel_packet_menu_t* m = g_new0(funnel_packet_menu_t, 1);
198
199
0
    m->name = g_strdup(name);
200
0
    m->required_fields = g_strdup(required_fields);
201
0
    m->callback = callback;
202
0
    m->callback_data = callback_data;
203
0
    m->retap = retap;
204
205
0
    registered_packet_menus = g_slist_append(registered_packet_menus, m);
206
207
0
    packet_menus_modified = true;
208
0
}
209
210
static void free_funnel_packet_menu(gpointer data, gpointer user_data _U_)
211
0
{
212
0
    funnel_packet_menu_t* m = (funnel_packet_menu_t*)data;
213
214
0
    g_free(m->name);
215
0
    g_free(m->required_fields);
216
0
    if (m->callback_data) {
217
0
        g_free(m->callback_data);
218
0
    }
219
0
    g_free(m);
220
0
}
221
222
/**
223
 * Entry point for Wireshark GUI to obtain all registered packet menus
224
 *
225
 * Calls the supplied callback for each packet menu registered with
226
 * funnel_register_packet_menu().
227
 *
228
 * @param r_cb the callback function to call with each registered packet menu
229
 */
230
void funnel_register_all_packet_menus(funnel_registration_packet_cb_t r_cb)
231
0
{
232
0
    for (GSList* l = registered_packet_menus; l; l = l->next) {
233
0
        funnel_packet_menu_t* c = (funnel_packet_menu_t*)l->data;
234
0
        r_cb(c->name, c->required_fields, c->callback, c->callback_data, c->retap);
235
0
    }
236
237
0
    packet_menus_modified = false;
238
0
}
239
240
/**
241
 * Returns whether the packet menus have been modified since they were last registered
242
 *
243
 * @return true if the packet menus were modified since the last registration
244
 */
245
bool funnel_packet_menus_modified(void)
246
0
{
247
0
    return packet_menus_modified;
248
0
}
249
250
/**
251
 * Entry point for code to register a console menu
252
 */
253
void funnel_register_console_menu(const char *name,
254
                                  funnel_console_eval_cb_t eval_cb,
255
                                  funnel_console_open_cb_t open_cb,
256
                                  funnel_console_close_cb_t close_cb,
257
                                  void *callback_data,
258
                                  funnel_console_data_free_cb_t free_data)
259
0
{
260
0
    funnel_console_menu_t* m = g_new0(funnel_console_menu_t, 1);
261
262
0
    m->name = g_strdup(name);
263
0
    m->eval_cb = eval_cb;
264
0
    m->open_cb = open_cb;
265
0
    m->close_cb = close_cb;
266
0
    m->user_data = callback_data;
267
0
    m->data_free_cb = free_data;
268
269
0
    registered_console_menus = g_slist_prepend(registered_console_menus, m);
270
0
}
271
272
static void funnel_register_all_console_menus(funnel_registration_console_cb_t r_cb)
273
0
{
274
0
    if (r_cb == NULL) {
275
0
        return;
276
0
    }
277
278
0
    for (GSList* l = registered_console_menus; l != NULL; l = l->next) {
279
0
        funnel_console_menu_t *m = l->data;
280
0
        r_cb(m->name, m->eval_cb, m->open_cb, m->close_cb, m->user_data);
281
0
    }
282
0
}
283
284
static void free_funnel_console_menu(gpointer data, gpointer user_data _U_)
285
0
{
286
0
    funnel_console_menu_t* m = data;
287
288
0
    g_free(m->name);
289
0
    if (m->data_free_cb) {
290
0
        m->data_free_cb(m->user_data);
291
0
    }
292
0
    g_free(m);
293
0
}
294
295
void funnel_ops_init(const funnel_ops_t* o, funnel_registration_cb_t r_cb, funnel_registration_console_cb_t rconsole_cb)
296
0
{
297
0
    ops = o;
298
0
    funnel_register_all_menus(r_cb);
299
0
    funnel_register_all_console_menus(rconsole_cb);
300
0
    menus_registered = true;
301
0
}
302
303
bool funnel_menu_registered(void)
304
0
{
305
0
    return menus_registered;
306
0
}
307
308
void funnel_cleanup(void)
309
0
{
310
0
    funnel_clear_menu(&registered_menus, free_funnel_menu);
311
0
    funnel_clear_menu(&registered_packet_menus, free_funnel_packet_menu);
312
0
    funnel_clear_menu(&registered_console_menus, free_funnel_console_menu);
313
0
}
314
315
/*
316
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
317
 *
318
 * Local variables:
319
 * c-basic-offset: 4
320
 * tab-width: 8
321
 * indent-tabs-mode: nil
322
 * End:
323
 *
324
 * vi: set shiftwidth=4 tabstop=8 expandtab:
325
 * :indentSize=4:tabSize=8:noTabs=true:
326
 */