regen pidl all: rm epan/dissectors/pidl/*-stamp; pushd epan/dissectors/pidl/ && make...
[wireshark-sm.git] / epan / ftypes / ftype-protocol.c
blob78140e824f317d3251771473b6c513c142afb584
1 /*
2 * Wireshark - Network traffic analyzer
3 * By Gerald Combs <gerald@wireshark.org>
4 * Copyright 2001 Gerald Combs
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
9 #include "config.h"
11 #include <ftypes-int.h>
12 #include <epan/to_str.h>
13 #include <string.h>
14 #include <wsutil/array.h>
16 #include <epan/exceptions.h>
17 #include <wsutil/ws_assert.h>
19 static void
20 value_new(fvalue_t *fv)
22 fv->value.protocol.tvb = NULL;
23 fv->value.protocol.proto_string = NULL;
24 fv->value.protocol.tvb_is_private = false;
25 fv->value.protocol.length = -1;
28 static void
29 value_copy(fvalue_t *dst, const fvalue_t *src)
31 dst->value.protocol.tvb = tvb_clone(src->value.protocol.tvb);
32 dst->value.protocol.proto_string = g_strdup(src->value.protocol.proto_string);
33 dst->value.protocol.tvb_is_private = true;
34 dst->value.protocol.length = src->value.protocol.length;
37 static void
38 value_free(fvalue_t *fv)
40 if (fv->value.protocol.tvb && fv->value.protocol.tvb_is_private) {
41 tvb_free_chain(fv->value.protocol.tvb);
43 g_free(fv->value.protocol.proto_string);
46 static void
47 value_set(fvalue_t *fv, tvbuff_t *value, const char *name, int length)
49 /* Free up the old value, if we have one */
50 value_free(fv);
52 /* Set the protocol description and an (optional, nullable) tvbuff. */
53 fv->value.protocol.tvb = value;
54 fv->value.protocol.proto_string = g_strdup(name);
55 fv->value.protocol.length = length;
58 static bool
59 val_from_string(fvalue_t *fv, const char *s, size_t len, char **err_msg _U_)
61 tvbuff_t *new_tvb;
62 uint8_t *private_data;
64 /* Free up the old value, if we have one */
65 value_free(fv);
67 if (len == 0)
68 len = strlen(s);
70 /* Make a tvbuff from the string. We can drop the
71 * terminating NUL. */
72 private_data = (uint8_t *)g_memdup2(s, (unsigned)len);
73 new_tvb = tvb_new_real_data(private_data,
74 (unsigned)len, (int)len);
76 /* Let the tvbuff know how to delete the data. */
77 tvb_set_free_cb(new_tvb, g_free);
79 /* And let us know that we need to free the tvbuff */
80 fv->value.protocol.tvb_is_private = true;
81 /* This "field" is a value, it has no protocol description, but
82 * we might compare it to a protocol with NULL tvb.
83 * (e.g., proto_expert) */
84 fv->value.protocol.tvb = new_tvb;
85 fv->value.protocol.proto_string = g_strdup("");
86 fv->value.protocol.length = -1;
87 return true;
90 static bool
91 val_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg)
93 GByteArray *bytes;
94 tvbuff_t *new_tvb;
96 /* Free up the old value, if we have one */
97 value_free(fv);
98 fv->value.protocol.tvb = NULL;
99 fv->value.protocol.proto_string = NULL;
100 fv->value.protocol.length = -1;
102 /* Does this look like a byte string? */
103 bytes = byte_array_from_literal(s, err_msg);
104 if (bytes != NULL) {
105 /* Make a tvbuff from the bytes */
106 new_tvb = tvb_new_real_data(bytes->data, bytes->len, bytes->len);
108 /* Let the tvbuff know how to delete the data. */
109 tvb_set_free_cb(new_tvb, g_free);
111 /* Free GByteArray, but keep data. */
112 g_byte_array_free(bytes, false);
114 /* And let us know that we need to free the tvbuff */
115 fv->value.protocol.tvb_is_private = true;
116 fv->value.protocol.tvb = new_tvb;
118 /* This "field" is a value, it has no protocol description, but
119 * we might compare it to a protocol with NULL tvb.
120 * (e.g., proto_expert) */
121 fv->value.protocol.proto_string = g_strdup("");
122 return true;
125 /* Not a byte array, forget about it. */
126 return false;
129 static bool
130 val_from_charconst(fvalue_t *fv, unsigned long num, char **err_msg)
132 GByteArray *bytes;
133 tvbuff_t *new_tvb;
135 /* Free up the old value, if we have one */
136 value_free(fv);
137 fv->value.protocol.tvb = NULL;
138 fv->value.protocol.proto_string = NULL;
139 fv->value.protocol.length = -1;
141 /* Does this look like a byte string? */
142 bytes = byte_array_from_charconst(num, err_msg);
143 if (bytes != NULL) {
144 /* Make a tvbuff from the bytes */
145 new_tvb = tvb_new_real_data(bytes->data, bytes->len, bytes->len);
147 /* Let the tvbuff know how to delete the data. */
148 tvb_set_free_cb(new_tvb, g_free);
150 /* Free GByteArray, but keep data. */
151 g_byte_array_free(bytes, false);
153 /* And let us know that we need to free the tvbuff */
154 fv->value.protocol.tvb_is_private = true;
155 fv->value.protocol.tvb = new_tvb;
157 /* This "field" is a value, it has no protocol description, but
158 * we might compare it to a protocol with NULL tvb.
159 * (e.g., proto_expert) */
160 fv->value.protocol.proto_string = g_strdup("");
161 return true;
164 /* Not a byte array, forget about it. */
165 return false;
168 static char *
169 val_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype, int field_display _U_)
171 unsigned length;
172 char *volatile buf = NULL;
174 if (rtype != FTREPR_DFILTER)
175 return NULL;
177 TRY {
178 if (fv->value.protocol.length >= 0)
179 length = fv->value.protocol.length;
180 else
181 length = tvb_captured_length(fv->value.protocol.tvb);
183 if (length) {
184 if (rtype == FTREPR_DFILTER)
185 buf = bytes_to_dfilter_repr(scope, tvb_get_ptr(fv->value.protocol.tvb, 0, length), length);
186 else
187 buf = bytes_to_str_punct_maxlen(scope, tvb_get_ptr(fv->value.protocol.tvb, 0, length), length, ':', 0);
190 CATCH_ALL {
191 /* nothing */
193 ENDTRY;
194 return buf;
197 static tvbuff_t *
198 value_get(fvalue_t *fv)
200 if (fv->value.protocol.tvb == NULL)
201 return NULL;
202 if (fv->value.protocol.length < 0)
203 return fv->value.protocol.tvb;
204 return tvb_new_subset_length_caplen(fv->value.protocol.tvb, 0, fv->value.protocol.length, fv->value.protocol.length);
207 static unsigned
208 len(fvalue_t *fv)
210 volatile unsigned length = 0;
212 TRY {
213 if (fv->value.protocol.tvb) {
214 if (fv->value.protocol.length >= 0)
215 length = fv->value.protocol.length;
216 else
217 length = tvb_captured_length(fv->value.protocol.tvb);
221 CATCH_ALL {
222 /* nothing */
224 ENDTRY;
226 return length;
229 static void
230 slice(fvalue_t *fv, GByteArray *bytes, unsigned offset, unsigned length)
232 const uint8_t* data;
233 volatile unsigned len = length;
235 if (fv->value.protocol.tvb) {
236 if (fv->value.protocol.length >= 0 && (unsigned)fv->value.protocol.length < len) {
237 len = fv->value.protocol.length;
240 TRY {
241 data = tvb_get_ptr(fv->value.protocol.tvb, offset, len);
242 g_byte_array_append(bytes, data, len);
244 CATCH_ALL {
245 /* nothing */
247 ENDTRY;
252 static int
253 _tvbcmp(const protocol_value_t *a, const protocol_value_t *b)
255 unsigned a_len;
256 unsigned b_len;
258 if (a->length < 0)
259 a_len = tvb_captured_length(a->tvb);
260 else
261 a_len = a->length;
263 if (b->length < 0)
264 b_len = tvb_captured_length(b->tvb);
265 else
266 b_len = b->length;
268 if (a_len != b_len)
269 return a_len < b_len ? -1 : 1;
270 return memcmp(tvb_get_ptr(a->tvb, 0, a_len), tvb_get_ptr(b->tvb, 0, a_len), a_len);
273 static enum ft_result
274 cmp_order(const fvalue_t *fv_a, const fvalue_t *fv_b, int *cmp)
276 const protocol_value_t *a = (const protocol_value_t *)&fv_a->value.protocol;
277 const protocol_value_t *b = (const protocol_value_t *)&fv_b->value.protocol;
278 volatile int c = 0;
280 TRY {
281 if ((a->tvb != NULL) && (b->tvb != NULL)) {
282 c = _tvbcmp(a, b);
283 } else {
284 c = strcmp(a->proto_string, b->proto_string);
287 CATCH_ALL {
288 /* nothing */
290 ENDTRY;
292 *cmp = c;
293 return FT_OK;
296 static enum ft_result
297 cmp_contains(const fvalue_t *fv_a, const fvalue_t *fv_b, bool *contains)
299 volatile bool yes = false;
301 TRY {
302 /* First see if tvb exists for both sides */
303 if ((fv_a->value.protocol.tvb != NULL) && (fv_b->value.protocol.tvb != NULL)) {
304 if (tvb_find_tvb(fv_a->value.protocol.tvb, fv_b->value.protocol.tvb, 0) > -1) {
305 yes = true;
307 } else {
308 /* Otherwise just compare strings */
309 if ((strlen(fv_b->value.protocol.proto_string) != 0) &&
310 strstr(fv_a->value.protocol.proto_string, fv_b->value.protocol.proto_string)) {
311 yes = true;
315 CATCH_ALL {
316 /* nothing */
318 ENDTRY;
320 *contains = yes;
321 return FT_OK;
324 static enum ft_result
325 cmp_matches(const fvalue_t *fv, const ws_regex_t *regex, bool *matches)
327 const protocol_value_t *a = (const protocol_value_t *)&fv->value.protocol;
328 volatile bool rc = false;
329 const char *data = NULL; /* tvb data */
330 uint32_t tvb_len; /* tvb length */
332 if (! regex) {
333 return FT_BADARG;
335 TRY {
336 if (a->tvb != NULL) {
337 tvb_len = tvb_captured_length(a->tvb);
338 data = (const char *)tvb_get_ptr(a->tvb, 0, tvb_len);
339 rc = ws_regex_matches_length(regex, data, tvb_len);
340 } else {
341 rc = ws_regex_matches(regex, a->proto_string);
344 CATCH_ALL {
345 rc = false;
347 ENDTRY;
349 *matches = rc;
350 return FT_OK;
353 static unsigned
354 val_hash(const fvalue_t *fv)
356 const protocol_value_t *value = &fv->value.protocol;
357 return g_direct_hash(value->tvb) ^ g_int_hash(&value->length) ^ g_str_hash(value->proto_string);
360 static bool
361 is_zero(const fvalue_t *fv)
363 const protocol_value_t *a = &fv->value.protocol;
364 return a->tvb == NULL && a->proto_string == NULL;
367 void
368 ftype_register_tvbuff(void)
371 static const ftype_t protocol_type = {
372 FT_PROTOCOL, /* ftype */
373 0, /* wire_size */
374 value_new, /* new_value */
375 value_copy, /* copy_value */
376 value_free, /* free_value */
377 val_from_literal, /* val_from_literal */
378 val_from_string, /* val_from_string */
379 val_from_charconst, /* val_from_charconst */
380 NULL, /* val_from_uinteger64 */
381 NULL, /* val_from_sinteger64 */
382 NULL, /* val_from_double */
383 val_to_repr, /* val_to_string_repr */
385 NULL, /* val_to_uinteger64 */
386 NULL, /* val_to_sinteger64 */
387 NULL, /* val_to_double */
389 { .set_value_protocol = value_set }, /* union set_value */
390 { .get_value_protocol = value_get }, /* union get_value */
392 cmp_order,
393 cmp_contains,
394 cmp_matches,
396 val_hash,
397 is_zero,
398 NULL,
399 len,
400 (FvalueSlice)slice,
401 NULL,
402 NULL, /* unary_minus */
403 NULL, /* add */
404 NULL, /* subtract */
405 NULL, /* multiply */
406 NULL, /* divide */
407 NULL, /* modulo */
411 ftype_register(FT_PROTOCOL, &protocol_type);
414 void
415 ftype_register_pseudofields_tvbuff(int proto)
417 static int hf_ft_protocol;
419 static hf_register_info hf_ftypes[] = {
420 { &hf_ft_protocol,
421 { "FT_PROTOCOL", "_ws.ftypes.protocol",
422 FT_PROTOCOL, BASE_NONE, NULL, 0x00,
423 NULL, HFILL }
427 proto_register_field_array(proto, hf_ftypes, array_length(hf_ftypes));
431 * Editor modelines - https://www.wireshark.org/tools/modelines.html
433 * Local variables:
434 * c-basic-offset: 8
435 * tab-width: 8
436 * indent-tabs-mode: t
437 * End:
439 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
440 * :indentSize=8:tabSize=8:noTabs=false: