diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
commit | e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch) | |
tree | 68cb5ef9081156392f1dd62a00c6ccc1451b93df /epan/ftypes | |
parent | Initial commit. (diff) | |
download | wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip |
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'epan/ftypes')
-rw-r--r-- | epan/ftypes/.editorconfig | 49 | ||||
-rw-r--r-- | epan/ftypes/CMakeLists.txt | 85 | ||||
-rw-r--r-- | epan/ftypes/ftype-bytes.c | 1013 | ||||
-rw-r--r-- | epan/ftypes/ftype-double.c | 272 | ||||
-rw-r--r-- | epan/ftypes/ftype-guid.c | 174 | ||||
-rw-r--r-- | epan/ftypes/ftype-ieee-11073-float.c | 1058 | ||||
-rw-r--r-- | epan/ftypes/ftype-integer.c | 2209 | ||||
-rw-r--r-- | epan/ftypes/ftype-ipv4.c | 246 | ||||
-rw-r--r-- | epan/ftypes/ftype-ipv6.c | 275 | ||||
-rw-r--r-- | epan/ftypes/ftype-none.c | 84 | ||||
-rw-r--r-- | epan/ftypes/ftype-protocol.c | 440 | ||||
-rw-r--r-- | epan/ftypes/ftype-string.c | 439 | ||||
-rw-r--r-- | epan/ftypes/ftype-time.c | 670 | ||||
-rw-r--r-- | epan/ftypes/ftypes-int.h | 205 | ||||
-rw-r--r-- | epan/ftypes/ftypes.c | 1249 | ||||
-rw-r--r-- | epan/ftypes/ftypes.h | 539 |
16 files changed, 9007 insertions, 0 deletions
diff --git a/epan/ftypes/.editorconfig b/epan/ftypes/.editorconfig new file mode 100644 index 0000000..3072778 --- /dev/null +++ b/epan/ftypes/.editorconfig @@ -0,0 +1,49 @@ +# +# Editor configuration +# +# https://editorconfig.org/ +# + +[ftype-bytes.[ch]] +indent_style = tab +indent_size = tab + +[ftype-double.[ch]] +indent_style = tab +indent_size = tab + +[ftype-integer.[ch]] +indent_style = tab +indent_size = tab + +[ftype-ipv4.[ch]] +indent_style = tab +indent_size = tab + +[ftype-ipv6.[ch]] +indent_style = tab +indent_size = tab + +[ftype-none.[ch]] +indent_style = tab +indent_size = tab + +[ftype-string.[ch]] +indent_style = tab +indent_size = tab + +[ftype-time.[ch]] +indent_style = tab +indent_size = tab + +[ftype-protocol.[ch]] +indent_style = tab +indent_size = tab + +[ftypes.[ch]] +indent_style = tab +indent_size = tab + +[ftypes-int.h] +indent_style = tab +indent_size = tab diff --git a/epan/ftypes/CMakeLists.txt b/epan/ftypes/CMakeLists.txt new file mode 100644 index 0000000..b63b55e --- /dev/null +++ b/epan/ftypes/CMakeLists.txt @@ -0,0 +1,85 @@ +# CMakeLists.txt +# +# Wireshark - Network traffic analyzer +# By Gerald Combs <gerald@wireshark.org> +# Copyright 1998 Gerald Combs +# +# SPDX-License-Identifier: GPL-2.0-or-later +# + +set(FTYPE_PUBLIC_HEADERS + ftypes.h +) + +set(FTYPE_HEADER_FILES + ${FTYPE_PUBLIC_HEADERS} + ftypes-int.h +) + +set(FTYPE_FILES + ftypes.c + ftype-bytes.c + ftype-double.c + ftype-ieee-11073-float.c + ftype-integer.c + ftype-ipv4.c + ftype-ipv6.c + ftype-guid.c + ftype-none.c + ftype-protocol.c + ftype-string.c + ftype-time.c +) +source_group(ftype FILES ${FTYPE_FILES}) + +set_source_files_properties( + ${FTYPE_FILES} + PROPERTIES + COMPILE_FLAGS "${WERROR_COMMON_FLAGS}" +) + +add_library(ftypes OBJECT + #Included so that Visual Studio can properly put header files in solution + ${FTYPE_HEADER_FILES} + + ${FTYPE_FILES} +) + +target_include_directories(ftypes + PRIVATE + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/epan +) + +set_target_properties(ftypes PROPERTIES + FOLDER "Libs/epan/ftypes" + COMPILE_DEFINITIONS "WS_BUILD_DLL" +) + +install(FILES ${FTYPE_PUBLIC_HEADERS} + DESTINATION "${PROJECT_INSTALL_INCLUDEDIR}/epan/ftypes" + COMPONENT "Development" + EXCLUDE_FROM_ALL +) + +CHECKAPI( + NAME + ftypes + SWITCHES + SOURCES + ${FTYPE_FILES} +) + +# +# Editor modelines - https://www.wireshark.org/tools/modelines.html +# +# Local variables: +# c-basic-offset: 8 +# tab-width: 8 +# indent-tabs-mode: t +# End: +# +# vi: set shiftwidth=8 tabstop=8 noexpandtab: +# :indentSize=8:tabSize=8:noTabs=false: +# diff --git a/epan/ftypes/ftype-bytes.c b/epan/ftypes/ftype-bytes.c new file mode 100644 index 0000000..39a58a3 --- /dev/null +++ b/epan/ftypes/ftype-bytes.c @@ -0,0 +1,1013 @@ +/* + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 2001 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include <ftypes-int.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> +#include <epan/addr_resolv.h> +#include <epan/strutil.h> +#include <epan/oids.h> +#include <epan/osi-utils.h> +#include <epan/to_str.h> + +static void +bytes_fvalue_new(fvalue_t *fv) +{ + fv->value.bytes = NULL; +} + +static void +bytes_fvalue_copy(fvalue_t *dst, const fvalue_t *src) +{ + dst->value.bytes = g_bytes_ref(src->value.bytes); +} + +static void +bytes_fvalue_free(fvalue_t *fv) +{ + if (fv->value.bytes) { + g_bytes_unref(fv->value.bytes); + fv->value.bytes = NULL; + } +} + + +static void +bytes_fvalue_set(fvalue_t *fv, GBytes *value) +{ + /* Free up the old value, if we have one */ + bytes_fvalue_free(fv); + + fv->value.bytes = g_bytes_ref(value); +} + +static GBytes * +bytes_fvalue_get(fvalue_t *fv) +{ + return g_bytes_ref(fv->value.bytes); +} + +static char * +oid_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_) +{ + return oid_encoded2string(scope, g_bytes_get_data(fv->value.bytes, NULL), (unsigned)g_bytes_get_size(fv->value.bytes)); +} + +static char * +rel_oid_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_) +{ + return rel_oid_encoded2string(scope, g_bytes_get_data(fv->value.bytes, NULL), (unsigned)g_bytes_get_size(fv->value.bytes)); +} + +static char * +system_id_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_) +{ + return print_system_id(scope, g_bytes_get_data(fv->value.bytes, NULL), (unsigned)g_bytes_get_size(fv->value.bytes)); +} + +char * +bytes_to_dfilter_repr(wmem_allocator_t *scope, + const uint8_t *src, size_t src_size) +{ + char *buf; + size_t max_char_size; + char *buf_ptr; + + /* Include space for extra punct and '\0'. */ + max_char_size = src_size * 3 + 1; + + buf = wmem_alloc(scope, max_char_size); + buf_ptr = bytes_to_hexstr_punct(buf, src, src_size, ':'); + if (src_size == 1) + *buf_ptr++ = ':'; + *buf_ptr = '\0'; + return buf; +} + +static char * +bytes_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype, int field_display) +{ + char separator; + const uint8_t *bytes; + size_t bytes_size; + + bytes = g_bytes_get_data(fv->value.bytes, &bytes_size); + + if (rtype == FTREPR_DFILTER) { + if (bytes_size == 0) { + /* An empty byte array in a display filter is represented as "" */ + return wmem_strdup(scope, "\"\""); + } + return bytes_to_dfilter_repr(scope, bytes, bytes_size); + } + + switch(FIELD_DISPLAY(field_display)) + { + case SEP_DOT: + separator = '.'; + break; + case SEP_DASH: + separator = '-'; + break; + case SEP_SPACE: + case SEP_COLON: + case BASE_NONE: + default: + separator = ':'; + break; + } + + if (bytes_size) { + return bytes_to_str_punct_maxlen(scope, bytes, bytes_size, separator, 0); + } + + return wmem_strdup(scope, ""); +} + +static bool +bytes_from_string(fvalue_t *fv, const char *s, size_t len, char **err_msg _U_) +{ + GByteArray *bytes; + + bytes = g_byte_array_new(); + + if (len == 0) + len = strlen(s); + + g_byte_array_append(bytes, (const uint8_t *)s, (unsigned)len); + + /* Free up the old value, if we have one */ + bytes_fvalue_free(fv); + fv->value.bytes = g_byte_array_free_to_bytes(bytes); + + return true; +} + +GByteArray * +byte_array_from_literal(const char *s, char **err_msg) +{ + GByteArray *bytes; + bool res; + + /* Skip leading colon if any. */ + if (*s == ':') + s++; + + /* + * Special case where the byte string is specified using a one byte + * hex literal. We can't allow this for byte strings that are longer + * than one byte, because then we'd have to know which endianness the + * byte string should be in. + */ + if (strlen(s) == 4 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) + s = s + 2; + + bytes = g_byte_array_new(); + + /* Hack: If we have a binary number 0bXXXXXXXX use that as a byte array + * of length one. This is ambiguous because it can also be + * parsed (without separators) as a byte array of length 5: + * 0bXXXXXXXX = 0b:XX:XX:XX:XX = { 0x0b, 0xXX, 0xXX, 0xXX, 0xXX } */ + if (strlen(s) == 10 && s[0] == '0' && (s[1] == 'b' || s[1] == 'B') && + (s[2] == '0' || s[2] == '1')) { + errno = 0; + char *endptr; + long number = strtol(s + 2, &endptr, 2); + if (errno == 0 && *endptr == '\0' && number >= 0x0 && number <= 0xff) { + uint8_t byte = (uint8_t)number; + g_byte_array_append(bytes, &byte, 1); + return bytes; + } + } + + res = hex_str_to_bytes(s, bytes, false); + + if (!res) { + if (err_msg != NULL) + *err_msg = ws_strdup_printf("\"%s\" is not a valid byte string.", s); + g_byte_array_free(bytes, true); + return NULL; + } + + return bytes; +} + +static bool +bytes_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg) +{ + GByteArray *bytes; + + bytes = byte_array_from_literal(s, err_msg); + if (bytes == NULL) + return false; + + /* Free up the old value, if we have one */ + bytes_fvalue_free(fv); + + fv->value.bytes = g_byte_array_free_to_bytes(bytes); + + return true; +} + +GByteArray * +byte_array_from_charconst(unsigned long num, char **err_msg) +{ + if (num > UINT8_MAX) { + if (err_msg) { + *err_msg = ws_strdup_printf("%lu is too large for a byte value", num); + } + return NULL; + } + + GByteArray *bytes = g_byte_array_new(); + uint8_t one_byte = (uint8_t)num; + g_byte_array_append(bytes, &one_byte, 1); + return bytes; +} + +static bool +bytes_from_charconst(fvalue_t *fv, unsigned long num, char **err_msg) +{ + GByteArray *bytes; + + bytes = byte_array_from_charconst(num, err_msg); + if (bytes == NULL) + return false; + + /* Free up the old value, if we have one */ + bytes_fvalue_free(fv); + + fv->value.bytes = g_byte_array_free_to_bytes(bytes); + + return true; +} + +static bool +ax25_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg) +{ + /* + * Don't request an error message if bytes_from_literal fails; + * if it does, we'll report an error specific to this address + * type. + */ + if (bytes_from_literal(fv, s, true, NULL)) { + if (g_bytes_get_size(fv->value.bytes) > FT_AX25_ADDR_LEN) { + if (err_msg != NULL) { + *err_msg = ws_strdup_printf("\"%s\" contains too many bytes to be a valid AX.25 address.", + s); + } + return false; + } + else if (g_bytes_get_size(fv->value.bytes) < FT_AX25_ADDR_LEN && !allow_partial_value) { + if (err_msg != NULL) { + *err_msg = ws_strdup_printf("\"%s\" contains too few bytes to be a valid AX.25 address.", + s); + } + return false; + } + + return true; + } + + /* + * XXX - what needs to be done here is something such as: + * + * Look for a "-" in the string. + * + * If we find it, make sure that there are 1-6 alphanumeric + * ASCII characters before it, and that there are 2 decimal + * digits after it, from 00 to 15; if we don't find it, make + * sure that there are 1-6 alphanumeric ASCII characters + * in the string. + * + * If so, make the first 6 octets of the address the ASCII + * characters, with lower-case letters mapped to upper-case + * letters, shifted left by 1 bit, padded to 6 octets with + * spaces, also shifted left by 1 bit, and, if we found a + * "-", convert what's after it to a number and make the 7th + * octet the number, shifted left by 1 bit, otherwise make the + * 7th octet zero. + * + * We should also change all the comparison functions for + * AX.25 addresses check the upper 7 bits of all but the last + * octet of the address, ignoring the "end of address" bit, + * and compare only the 4 bits above the low-order bit for + * the last octet, ignoring the "end of address" bit and + * various reserved bits and bits used for other purposes. + * + * See section 3.12 "Address-Field Encoding" of the AX.25 + * spec and + * + * http://www.itu.int/ITU-R/terrestrial/docs/fixedmobile/fxm-art19-sec3.pdf + */ + if (err_msg != NULL) + *err_msg = ws_strdup_printf("\"%s\" is not a valid AX.25 address.", s); + return false; +} + +static bool +vines_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg) +{ + /* + * Don't request an error message if bytes_from_literal fails; + * if it does, we'll report an error specific to this address + * type. + */ + if (bytes_from_literal(fv, s, true, NULL)) { + if (g_bytes_get_size(fv->value.bytes) > FT_VINES_ADDR_LEN) { + if (err_msg != NULL) { + *err_msg = ws_strdup_printf("\"%s\" contains too many bytes to be a valid Vines address.", + s); + } + return false; + } + else if (g_bytes_get_size(fv->value.bytes) < FT_VINES_ADDR_LEN && !allow_partial_value) { + if (err_msg != NULL) { + *err_msg = ws_strdup_printf("\"%s\" contains too few bytes to be a valid Vines address.", + s); + } + return false; + } + + return true; + } + + /* XXX - need better validation of Vines address */ + + if (err_msg != NULL) + *err_msg = ws_strdup_printf("\"%s\" is not a valid Vines address.", s); + return false; +} + +static bool +ether_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg) +{ + /* + * Don't request an error message if bytes_from_literal fails; + * if it does, we'll report an error specific to this address + * type. + */ + if (bytes_from_literal(fv, s, true, NULL)) { + if (g_bytes_get_size(fv->value.bytes) > FT_ETHER_LEN) { + if (err_msg != NULL) { + *err_msg = ws_strdup_printf("\"%s\" contains too many bytes to be a valid Ethernet address.", + s); + } + return false; + } + else if (g_bytes_get_size(fv->value.bytes) < FT_ETHER_LEN && !allow_partial_value) { + if (err_msg != NULL) { + *err_msg = ws_strdup_printf("\"%s\" contains too few bytes to be a valid Ethernet address.", + s); + } + return false; + } + + return true; + } + + /* XXX - Try resolving as an Ethernet host name and parse that? */ + + if (err_msg != NULL) + *err_msg = ws_strdup_printf("\"%s\" is not a valid Ethernet address.", s); + return false; +} + +static bool +oid_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg) +{ + GByteArray *bytes; + bool res; + + +#if 0 + /* + * Don't log a message if this fails; we'll try looking it + * up as an OID if it does, and if that fails, + * we'll log a message. + */ + /* do not try it as '.' is handled as valid separator for hexbytes :( */ + if (bytes_from_literal(fv, s, true, NULL)) { + return true; + } +#endif + + bytes = g_byte_array_new(); + res = oid_str_to_bytes(s, bytes); + if (!res) { + if (err_msg != NULL) + *err_msg = ws_strdup_printf("\"%s\" is not a valid OBJECT IDENTIFIER.", s); + g_byte_array_free(bytes, true); + return false; + } + + /* Free up the old value, if we have one */ + bytes_fvalue_free(fv); + fv->value.bytes = g_byte_array_free_to_bytes(bytes); + + return true; +} + +static bool +rel_oid_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg) +{ + GByteArray *bytes; + bool res; + + bytes = g_byte_array_new(); + res = rel_oid_str_to_bytes(s, bytes, false); + if (!res) { + if (err_msg != NULL) + *err_msg = ws_strdup_printf("\"%s\" is not a valid RELATIVE-OID.", s); + g_byte_array_free(bytes, true); + return false; + } + + /* Free up the old value, if we have one */ + bytes_fvalue_free(fv); + fv->value.bytes = g_byte_array_free_to_bytes(bytes); + + return true; +} + +static bool +system_id_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg) +{ + /* + * Don't request an error message if bytes_from_literal fails; + * if it does, we'll report an error specific to this address + * type. + */ + if (bytes_from_literal(fv, s, true, NULL)) { + if (g_bytes_get_size(fv->value.bytes) > MAX_SYSTEMID_LEN) { + if (err_msg != NULL) { + *err_msg = ws_strdup_printf("\"%s\" contains too many bytes to be a valid OSI System-ID.", + s); + } + return false; + } + + return true; + } + + /* XXX - need better validation of OSI System-ID address */ + + if (err_msg != NULL) + *err_msg = ws_strdup_printf("\"%s\" is not a valid OSI System-ID.", s); + return false; +} + +static bool +fcwwn_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg) +{ + /* + * Don't request an error message if bytes_from_literal fails; + * if it does, we'll report an error specific to this address + * type. + */ + if (bytes_from_literal(fv, s, true, NULL)) { + if (g_bytes_get_size(fv->value.bytes) > FT_FCWWN_LEN) { + if (err_msg != NULL) { + *err_msg = ws_strdup_printf("\"%s\" contains too many bytes to be a valid FCWWN.", + s); + } + return false; + } + + return true; + } + + /* XXX - need better validation of FCWWN address */ + + if (err_msg != NULL) + *err_msg = ws_strdup_printf("\"%s\" is not a valid FCWWN.", s); + return false; +} + +static unsigned +len(fvalue_t *fv) +{ + return (unsigned)g_bytes_get_size(fv->value.bytes); +} + +static void +slice(fvalue_t *fv, GByteArray *bytes, unsigned offset, unsigned length) +{ + const uint8_t *data = (const uint8_t *)g_bytes_get_data(fv->value.bytes, NULL) + offset; + g_byte_array_append(bytes, data, length); +} + +static enum ft_result +cmp_order(const fvalue_t *fv_a, const fvalue_t *fv_b, int *cmp) +{ + *cmp = g_bytes_compare(fv_a->value.bytes, fv_b->value.bytes); + return FT_OK; +} + +static enum ft_result +bytes_bitwise_and(fvalue_t *fv_dst, const fvalue_t *fv_a, const fvalue_t *fv_b, char **err_ptr _U_) +{ + GByteArray *dst; + const uint8_t *p_a, *p_b; + size_t size_a, size_b; + + p_a = g_bytes_get_data(fv_a->value.bytes, &size_a); + p_b = g_bytes_get_data(fv_b->value.bytes, &size_b); + + size_t len = MIN(size_a, size_b); + if (len == 0) { + fv_dst->value.bytes = g_bytes_new(NULL, 0); + return FT_OK; + } + + dst = g_byte_array_sized_new((unsigned)len); + for (size_t i = 0; i < len; i++) { + uint8_t byte = p_a[i] & p_b[i]; + g_byte_array_append(dst, &byte, 1); + } + fv_dst->value.bytes = g_byte_array_free_to_bytes(dst); + return FT_OK; +} + +static enum ft_result +cmp_contains(const fvalue_t *fv_a, const fvalue_t *fv_b, bool *contains) +{ + const void *data_a, *data_b; + size_t size_a, size_b; + + data_a = g_bytes_get_data(fv_a->value.bytes, &size_a); + data_b = g_bytes_get_data(fv_b->value.bytes, &size_b); + + if (ws_memmem(data_a, size_a, data_b, size_b)) { + *contains = true; + } + else { + *contains = false; + } + + return FT_OK; +} + +static enum ft_result +cmp_matches(const fvalue_t *fv, const ws_regex_t *regex, bool *matches) +{ + const void *data; + size_t data_size; + + data = g_bytes_get_data(fv->value.bytes, &data_size); + + *matches = ws_regex_matches_length(regex, data, data_size); + return FT_OK; +} + +static unsigned +bytes_hash(const fvalue_t *fv) +{ + return g_bytes_hash(fv->value.bytes); +} + +static bool +bytes_is_zero(const fvalue_t *fv) +{ + const uint8_t *data; + size_t data_size; + + data = g_bytes_get_data(fv->value.bytes, &data_size); + + if (data_size == 0) + return true; + + for (size_t i = 0; i < data_size; i++) { + if (data[i] != 0) { + return false; + } + } + return true; +} + +void +ftype_register_bytes(void) +{ + + static ftype_t bytes_type = { + FT_BYTES, /* ftype */ + "FT_BYTES", /* name */ + "Byte sequence", /* pretty_name */ + 0, /* wire_size */ + bytes_fvalue_new, /* new_value */ + bytes_fvalue_copy, /* copy_value */ + bytes_fvalue_free, /* free_value */ + bytes_from_literal, /* val_from_literal */ + bytes_from_string, /* val_from_string */ + bytes_from_charconst, /* val_from_charconst */ + bytes_to_repr, /* val_to_string_repr */ + + NULL, /* val_to_uinteger64 */ + NULL, /* val_to_sinteger64 */ + + { .set_value_bytes = bytes_fvalue_set }, /* union set_value */ + { .get_value_bytes = bytes_fvalue_get }, /* union get_value */ + + cmp_order, + cmp_contains, + cmp_matches, + + bytes_hash, /* hash */ + bytes_is_zero, /* is_zero */ + NULL, /* is_negative */ + len, + (FvalueSlice)slice, + bytes_bitwise_and, /* bitwise_and */ + NULL, /* unary_minus */ + NULL, /* add */ + NULL, /* subtract */ + NULL, /* multiply */ + NULL, /* divide */ + NULL, /* modulo */ + }; + + static ftype_t uint_bytes_type = { + FT_UINT_BYTES, /* ftype */ + "FT_UINT_BYTES", /* name */ + "Byte sequence", /* pretty_name */ + 0, /* wire_size */ + bytes_fvalue_new, /* new_value */ + bytes_fvalue_copy, /* copy_value */ + bytes_fvalue_free, /* free_value */ + bytes_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + NULL, /* val_from_charconst */ + bytes_to_repr, /* val_to_string_repr */ + + NULL, /* val_to_uinteger64 */ + NULL, /* val_to_sinteger64 */ + + { .set_value_bytes = bytes_fvalue_set }, /* union set_value */ + { .get_value_bytes = bytes_fvalue_get }, /* union get_value */ + + cmp_order, + cmp_contains, + NULL, /* cmp_matches */ + + bytes_hash, /* hash */ + bytes_is_zero, /* is_zero */ + NULL, /* is_negative */ + len, + (FvalueSlice)slice, + bytes_bitwise_and, /* bitwise_and */ + NULL, /* unary_minus */ + NULL, /* add */ + NULL, /* subtract */ + NULL, /* multiply */ + NULL, /* divide */ + NULL, /* modulo */ + }; + + static ftype_t ax25_type = { + FT_AX25, /* ftype */ + "FT_AX25", /* name */ + "AX.25 address", /* pretty_name */ + FT_AX25_ADDR_LEN, /* wire_size */ + bytes_fvalue_new, /* new_value */ + bytes_fvalue_copy, /* copy_value */ + bytes_fvalue_free, /* free_value */ + ax25_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + NULL, /* val_from_charconst */ + bytes_to_repr, /* val_to_string_repr */ + + NULL, /* val_to_uinteger64 */ + NULL, /* val_to_sinteger64 */ + + { .set_value_bytes = bytes_fvalue_set }, /* union set_value */ + { .get_value_bytes = bytes_fvalue_get }, /* union get_value */ + + cmp_order, + cmp_contains, + cmp_matches, + + bytes_hash, /* hash */ + bytes_is_zero, /* is_zero */ + NULL, /* is_negative */ + len, + (FvalueSlice)slice, + bytes_bitwise_and, /* bitwise_and */ + NULL, /* unary_minus */ + NULL, /* add */ + NULL, /* subtract */ + NULL, /* multiply */ + NULL, /* divide */ + NULL, /* modulo */ + }; + + static ftype_t vines_type = { + FT_VINES, /* ftype */ + "FT_VINES", /* name */ + "VINES address", /* pretty_name */ + FT_VINES_ADDR_LEN, /* wire_size */ + bytes_fvalue_new, /* new_value */ + bytes_fvalue_copy, /* copy_value */ + bytes_fvalue_free, /* free_value */ + vines_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + NULL, /* val_from_charconst */ + bytes_to_repr, /* val_to_string_repr */ + + NULL, /* val_to_uinteger64 */ + NULL, /* val_to_sinteger64 */ + + { .set_value_bytes = bytes_fvalue_set }, /* union set_value */ + { .get_value_bytes = bytes_fvalue_get }, /* union get_value */ + + cmp_order, + cmp_contains, + cmp_matches, + + bytes_hash, /* hash */ + bytes_is_zero, /* is_zero */ + NULL, /* is_negative */ + len, + (FvalueSlice)slice, + bytes_bitwise_and, /* bitwise_and */ + NULL, /* unary_minus */ + NULL, /* add */ + NULL, /* subtract */ + NULL, /* multiply */ + NULL, /* divide */ + NULL, /* modulo */ + }; + + static ftype_t ether_type = { + FT_ETHER, /* ftype */ + "FT_ETHER", /* name */ + "Ethernet or other MAC address",/* pretty_name */ + FT_ETHER_LEN, /* wire_size */ + bytes_fvalue_new, /* new_value */ + bytes_fvalue_copy, /* copy_value */ + bytes_fvalue_free, /* free_value */ + ether_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + NULL, /* val_from_charconst */ + bytes_to_repr, /* val_to_string_repr */ + + NULL, /* val_to_uinteger64 */ + NULL, /* val_to_sinteger64 */ + + { .set_value_bytes = bytes_fvalue_set }, /* union set_value */ + { .get_value_bytes = bytes_fvalue_get }, /* union get_value */ + + cmp_order, + cmp_contains, + cmp_matches, + + bytes_hash, /* hash */ + bytes_is_zero, /* is_zero */ + NULL, /* is_negative */ + len, + (FvalueSlice)slice, + bytes_bitwise_and, /* bitwise_and */ + NULL, /* unary_minus */ + NULL, /* add */ + NULL, /* subtract */ + NULL, /* multiply */ + NULL, /* divide */ + NULL, /* modulo */ + }; + + static ftype_t oid_type = { + FT_OID, /* ftype */ + "FT_OID", /* name */ + "ASN.1 object identifier", /* pretty_name */ + 0, /* wire_size */ + bytes_fvalue_new, /* new_value */ + bytes_fvalue_copy, /* copy_value */ + bytes_fvalue_free, /* free_value */ + oid_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + NULL, /* val_from_charconst */ + oid_to_repr, /* val_to_string_repr */ + + NULL, /* val_to_uinteger64 */ + NULL, /* val_to_sinteger64 */ + + { .set_value_bytes = bytes_fvalue_set }, /* union set_value */ + { .get_value_bytes = bytes_fvalue_get }, /* union get_value */ + + cmp_order, + cmp_contains, + NULL, /* cmp_matches */ + + bytes_hash, /* hash */ + bytes_is_zero, /* is_zero */ + NULL, /* is_negative */ + len, + (FvalueSlice)slice, + bytes_bitwise_and, /* bitwise_and */ + NULL, /* unary_minus */ + NULL, /* add */ + NULL, /* subtract */ + NULL, /* multiply */ + NULL, /* divide */ + NULL, /* modulo */ + }; + + static ftype_t rel_oid_type = { + FT_REL_OID, /* ftype */ + "FT_REL_OID", /* name */ + "ASN.1 relative object identifier", /* pretty_name */ + 0, /* wire_size */ + bytes_fvalue_new, /* new_value */ + bytes_fvalue_copy, /* copy_value */ + bytes_fvalue_free, /* free_value */ + rel_oid_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + NULL, /* val_from_charconst */ + rel_oid_to_repr, /* val_to_string_repr */ + + NULL, /* val_to_uinteger64 */ + NULL, /* val_to_sinteger64 */ + + { .set_value_bytes = bytes_fvalue_set }, /* union set_value */ + { .get_value_bytes = bytes_fvalue_get }, /* union get_value */ + + cmp_order, + cmp_contains, + NULL, /* cmp_matches */ + + bytes_hash, /* hash */ + bytes_is_zero, /* is_zero */ + NULL, /* is_negative */ + len, + (FvalueSlice)slice, + bytes_bitwise_and, /* bitwise_and */ + NULL, /* unary_minus */ + NULL, /* add */ + NULL, /* subtract */ + NULL, /* multiply */ + NULL, /* divide */ + NULL, /* modulo */ + }; + + static ftype_t system_id_type = { + FT_SYSTEM_ID, /* ftype */ + "FT_SYSTEM_ID", /* name */ + "OSI System-ID", /* pretty_name */ + 0, /* wire_size */ + bytes_fvalue_new, /* new_value */ + bytes_fvalue_copy, /* copy_value */ + bytes_fvalue_free, /* free_value */ + system_id_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + NULL, /* val_from_charconst */ + system_id_to_repr, /* val_to_string_repr */ + + NULL, /* val_to_uinteger64 */ + NULL, /* val_to_sinteger64 */ + + { .set_value_bytes = bytes_fvalue_set }, /* union set_value */ + { .get_value_bytes = bytes_fvalue_get }, /* union get_value */ + + cmp_order, + cmp_contains, + NULL, /* cmp_matches */ + + bytes_hash, /* hash */ + bytes_is_zero, /* is_zero */ + NULL, /* is_negative */ + len, + (FvalueSlice)slice, + bytes_bitwise_and, /* bitwise_and */ + NULL, /* unary_minus */ + NULL, /* add */ + NULL, /* subtract */ + NULL, /* multiply */ + NULL, /* divide */ + NULL, /* modulo */ + }; + + static ftype_t fcwwn_type = { + FT_FCWWN, /* ftype */ + "FT_FCWWN", /* name */ + "Fibre Channel WWN", /* pretty_name */ + FT_FCWWN_LEN, /* wire_size */ + bytes_fvalue_new, /* new_value */ + bytes_fvalue_copy, /* copy_value */ + bytes_fvalue_free, /* free_value */ + fcwwn_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + NULL, /* val_from_charconst */ + bytes_to_repr, /* val_to_string_repr */ + + NULL, /* val_to_uinteger64 */ + NULL, /* val_to_sinteger64 */ + + { .set_value_bytes = bytes_fvalue_set }, /* union set_value */ + { .get_value_bytes = bytes_fvalue_get }, /* union get_value */ + + cmp_order, + cmp_contains, + cmp_matches, + + bytes_hash, /* hash */ + bytes_is_zero, /* is_zero */ + NULL, /* is_negative */ + len, + (FvalueSlice)slice, + bytes_bitwise_and, /* bitwise_and */ + NULL, /* unary_minus */ + NULL, /* add */ + NULL, /* subtract */ + NULL, /* multiply */ + NULL, /* divide */ + NULL, /* modulo */ + }; + + ftype_register(FT_BYTES, &bytes_type); + ftype_register(FT_UINT_BYTES, &uint_bytes_type); + ftype_register(FT_AX25, &ax25_type); + ftype_register(FT_VINES, &vines_type); + ftype_register(FT_ETHER, ðer_type); + ftype_register(FT_OID, &oid_type); + ftype_register(FT_REL_OID, &rel_oid_type); + ftype_register(FT_SYSTEM_ID, &system_id_type); + ftype_register(FT_FCWWN, &fcwwn_type); +} + +void +ftype_register_pseudofields_bytes(int proto) +{ + static int hf_ft_bytes; + static int hf_ft_uint_bytes; + static int hf_ft_ax25; + static int hf_ft_vines; + static int hf_ft_ether; + static int hf_ft_oid; + static int hf_ft_rel_oid; + static int hf_ft_system_id; + + static hf_register_info hf_ftypes[] = { + { &hf_ft_bytes, + { "FT_BYTES", "_ws.ftypes.bytes", + FT_BYTES, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_uint_bytes, + { "FT_UINT_BYTES", "_ws.ftypes.uint_bytes", + FT_UINT_BYTES, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_ax25, + { "FT_AX25", "_ws.ftypes.ax25", + FT_AX25, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_vines, + { "FT_VINES", "_ws.ftypes.vines", + FT_VINES, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_ether, + { "FT_ETHER", "_ws.ftypes.ether", + FT_ETHER, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_oid, + { "FT_OID", "_ws.ftypes.oid", + FT_OID, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_rel_oid, + { "FT_REL_OID", "_ws.ftypes.rel_oid", + FT_REL_OID, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_system_id, + { "FT_SYSTEM_ID", "_ws.ftypes.system_id", + FT_SYSTEM_ID, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + }; + + proto_register_field_array(proto, hf_ftypes, array_length(hf_ftypes)); +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 8 + * tab-width: 8 + * indent-tabs-mode: t + * End: + * + * vi: set shiftwidth=8 tabstop=8 noexpandtab: + * :indentSize=8:tabSize=8:noTabs=false: + */ diff --git a/epan/ftypes/ftype-double.c b/epan/ftypes/ftype-double.c new file mode 100644 index 0000000..4bec884 --- /dev/null +++ b/epan/ftypes/ftype-double.c @@ -0,0 +1,272 @@ +/* + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 2001 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include <stdio.h> +#include <ftypes-int.h> +#include <math.h> +#include <errno.h> +#include <float.h> + +#include "strutil.h" + +static void +double_fvalue_new(fvalue_t *fv) +{ + fv->value.floating = 0.0; +} + +static void +double_fvalue_set_floating(fvalue_t *fv, double value) +{ + fv->value.floating = value; +} + +static double +value_get_floating(fvalue_t *fv) +{ + return fv->value.floating; +} + +static bool +val_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg) +{ + char *endptr = NULL; + + fv->value.floating = g_ascii_strtod(s, &endptr); + + if (endptr == s || *endptr != '\0') { + /* This isn't a valid number. */ + if (err_msg != NULL) + *err_msg = ws_strdup_printf("\"%s\" is not a valid floating-point number.", s); + return false; + } + if (errno == ERANGE) { + if (fv->value.floating == 0) { + if (err_msg != NULL) + *err_msg = ws_strdup_printf("\"%s\" causes floating-point underflow.", s); + } + else if (fv->value.floating == HUGE_VAL) { + if (err_msg != NULL) + *err_msg = ws_strdup_printf("\"%s\" causes floating-point overflow.", s); + } + else { + if (err_msg != NULL) + *err_msg = ws_strdup_printf("\"%s\" is not a valid floating-point number.", + s); + } + return false; + } + + return true; +} + +static char * +float_val_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype, int field_display _U_) +{ + char *buf = wmem_alloc(scope, G_ASCII_DTOSTR_BUF_SIZE); + if (rtype == FTREPR_DFILTER) + g_ascii_dtostr(buf, G_ASCII_DTOSTR_BUF_SIZE, fv->value.floating); + else + g_ascii_formatd(buf, G_ASCII_DTOSTR_BUF_SIZE, "%." G_STRINGIFY(FLT_DIG) "g", fv->value.floating); + return buf; +} + +static char * +double_val_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype, int field_display _U_) +{ + char *buf = wmem_alloc(scope, G_ASCII_DTOSTR_BUF_SIZE); + if (rtype == FTREPR_DFILTER) + g_ascii_dtostr(buf, G_ASCII_DTOSTR_BUF_SIZE, fv->value.floating); + else + g_ascii_formatd(buf, G_ASCII_DTOSTR_BUF_SIZE, "%." G_STRINGIFY(DBL_DIG) "g", fv->value.floating); + return buf; +} + +static enum ft_result +val_unary_minus(fvalue_t * dst, const fvalue_t *src, char **err_ptr _U_) +{ + dst->value.floating = -src->value.floating; + return FT_OK; +} + +static enum ft_result +val_add(fvalue_t * dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr _U_) +{ + dst->value.floating = a->value.floating + b->value.floating; + return FT_OK; +} + +static enum ft_result +val_subtract(fvalue_t * dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr _U_) +{ + dst->value.floating = a->value.floating - b->value.floating; + return FT_OK; +} + +static enum ft_result +val_multiply(fvalue_t * dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr _U_) +{ + dst->value.floating = a->value.floating * b->value.floating; + return FT_OK; +} + +static enum ft_result +val_divide(fvalue_t * dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr _U_) +{ + dst->value.floating = a->value.floating / b->value.floating; + return FT_OK; +} + +static enum ft_result +cmp_order(const fvalue_t *a, const fvalue_t *b, int *cmp) +{ + if (a->value.floating < b->value.floating) + *cmp = -1; + else if (a->value.floating > b->value.floating) + *cmp = 1; + else + *cmp = 0; + return FT_OK; +} + +static bool +val_is_zero(const fvalue_t *fv_a) +{ + return fv_a->value.floating == 0; +} + +static bool +val_is_negative(const fvalue_t *fv_a) +{ + return fv_a->value.floating < 0; +} + +static unsigned +val_hash(const fvalue_t *fv) +{ + return g_double_hash(&fv->value.floating); +} + +void +ftype_register_double(void) +{ + + static ftype_t float_type = { + FT_FLOAT, /* ftype */ + "FT_FLOAT", /* name */ + "Floating point (single-precision)", /* pretty_name */ + 0, /* wire_size */ + double_fvalue_new, /* new_value */ + NULL, /* copy_value */ + NULL, /* free_value */ + val_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + NULL, /* val_from_charconst */ + float_val_to_repr, /* val_to_string_repr */ + + NULL, /* val_to_uinteger64 */ + NULL, /* val_to_sinteger64 */ + + { .set_value_floating = double_fvalue_set_floating }, /* union set_value */ + { .get_value_floating = value_get_floating }, /* union get_value */ + + cmp_order, + NULL, /* cmp_contains */ + NULL, /* cmp_matches */ + + val_hash, /* hash */ + val_is_zero, /* is_zero */ + val_is_negative, /* is_negative */ + NULL, /* len */ + NULL, /* slice */ + NULL, /* bitwise_and */ + val_unary_minus, /* unary_minus */ + val_add, /* add */ + val_subtract, /* subtract */ + val_multiply, /* multiply */ + val_divide, /* divide */ + NULL, /* modulo */ + }; + + static ftype_t double_type = { + FT_DOUBLE, /* ftype */ + "FT_DOUBLE", /* name */ + "Floating point (double-precision)", /* pretty_name */ + 0, /* wire_size */ + double_fvalue_new, /* new_value */ + NULL, /* copy_value */ + NULL, /* free_value */ + val_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + NULL, /* val_from_charconst */ + double_val_to_repr, /* val_to_string_repr */ + + NULL, /* val_to_uinteger64 */ + NULL, /* val_to_sinteger64 */ + + { .set_value_floating = double_fvalue_set_floating }, /* union set_value */ + { .get_value_floating = value_get_floating }, /* union get_value */ + + cmp_order, + NULL, /* cmp_contains */ + NULL, /* cmp_matches */ + + val_hash, /* hash */ + val_is_zero, /* is_zero */ + val_is_negative, /* is_negative */ + NULL, /* len */ + NULL, /* slice */ + NULL, /* bitwise_and */ + val_unary_minus, /* unary_minus */ + val_add, /* add */ + val_subtract, /* subtract */ + val_multiply, /* multiply */ + val_divide, /* divide */ + NULL, /* modulo */ + }; + + ftype_register(FT_FLOAT, &float_type); + ftype_register(FT_DOUBLE, &double_type); +} + +void +ftype_register_pseudofields_double(int proto) +{ + static int hf_ft_float; + static int hf_ft_double; + + static hf_register_info hf_ftypes[] = { + { &hf_ft_float, + { "FT_FLOAT", "_ws.ftypes.float", + FT_FLOAT, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_double, + { "FT_DOUBLE", "_ws.ftypes.double", + FT_DOUBLE, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + }; + + proto_register_field_array(proto, hf_ftypes, array_length(hf_ftypes)); +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 8 + * tab-width: 8 + * indent-tabs-mode: t + * End: + * + * vi: set shiftwidth=8 tabstop=8 noexpandtab: + * :indentSize=8:tabSize=8:noTabs=false: + */ diff --git a/epan/ftypes/ftype-guid.c b/epan/ftypes/ftype-guid.c new file mode 100644 index 0000000..311a017 --- /dev/null +++ b/epan/ftypes/ftype-guid.c @@ -0,0 +1,174 @@ +/* + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 2001 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include <string.h> +#include <stdlib.h> + +#include <ftypes-int.h> +#include <epan/guid-utils.h> +#include <epan/to_str.h> + +static void +guid_fvalue_set_guid(fvalue_t *fv, const e_guid_t *value) +{ + fv->value.guid = *value; +} + +static const e_guid_t * +value_get(fvalue_t *fv) +{ + return &(fv->value.guid); +} + +static bool +get_guid(const char *s, e_guid_t *guid) +{ + size_t i, n; + const char *p; + char digits[3]; + static const char fmt[] = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"; + const size_t fmtchars = sizeof(fmt) - 1; + + n = strnlen(s, fmtchars); + if (n != fmtchars) + return false; + for (i=0; i<n; i++) { + if (fmt[i] == 'X') { + if (!g_ascii_isxdigit(s[i])) + return false; + } else { + if (s[i] != fmt[i]) + return false; + } + } + + p = s; + guid->data1 = (uint32_t)strtoul(p, NULL, 16); + p += 9; + guid->data2 = (uint16_t)strtoul(p, NULL, 16); + p += 5; + guid->data3 = (uint16_t)strtoul(p, NULL, 16); + p += 5; + for (i=0; i < sizeof(guid->data4); i++) { + if (*p == '-') p++; + digits[0] = *(p++); + digits[1] = *(p++); + digits[2] = '\0'; + guid->data4[i] = (uint8_t)strtoul(digits, NULL, 16); + } + return true; +} + +static bool +guid_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg) +{ + e_guid_t guid; + + if (!get_guid(s, &guid)) { + if (err_msg != NULL) + *err_msg = ws_strdup_printf("\"%s\" is not a valid GUID.", s); + return false; + } + + fv->value.guid = guid; + return true; +} + +static char * +guid_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_) +{ + return guid_to_str(scope, &fv->value.guid); +} + +static enum ft_result +cmp_order(const fvalue_t *a, const fvalue_t *b, int *cmp) +{ + *cmp = memcmp(&a->value.guid, &b->value.guid, sizeof(e_guid_t)); + return FT_OK; +} + +static unsigned +value_hash(const fvalue_t *fv) +{ + return guid_hash(&fv->value.guid); +} + +void +ftype_register_guid(void) +{ + + static ftype_t guid_type = { + FT_GUID, /* ftype */ + "FT_GUID", /* name */ + "Globally Unique Identifier", /* pretty_name */ + GUID_LEN, /* wire_size */ + NULL, /* new_value */ + NULL, /* copy_value */ + NULL, /* free_value */ + guid_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + NULL, /* val_from_charconst */ + guid_to_repr, /* val_to_string_repr */ + + NULL, /* val_to_uinteger64 */ + NULL, /* val_to_sinteger64 */ + + { .set_value_guid = guid_fvalue_set_guid }, /* union set_value */ + { .get_value_guid = value_get }, /* union get_value */ + + cmp_order, + NULL, + NULL, /* cmp_matches */ + + value_hash, /* hash */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, /* unary_minus */ + NULL, /* add */ + NULL, /* subtract */ + NULL, /* multiply */ + NULL, /* divide */ + NULL, /* modulo */ + }; + + ftype_register(FT_GUID, &guid_type); +} + +void +ftype_register_pseudofields_guid(int proto) +{ + static int hf_ft_guid; + + static hf_register_info hf_ftypes[] = { + { &hf_ft_guid, + { "FT_GUID", "_ws.ftypes.guid", + FT_GUID, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + }; + + proto_register_field_array(proto, hf_ftypes, array_length(hf_ftypes)); +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/epan/ftypes/ftype-ieee-11073-float.c b/epan/ftypes/ftype-ieee-11073-float.c new file mode 100644 index 0000000..bb4d628 --- /dev/null +++ b/epan/ftypes/ftype-ieee-11073-float.c @@ -0,0 +1,1058 @@ +/* FLOATs as specified by ISO/IEEE Std. 11073-20601-2014 + * + * Personal Health Devices Transcoding White Paper v1.5 + * https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=272346 + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 2001 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include <ftypes-int.h> +#include <inttypes.h> +#include <stdio.h> +#include <math.h> +#include <float.h> + +#include "strutil.h" + +#define DOUBLE_REPR_LENGTH 27 + +#define SFLOAT_VALUE_INFINITY_PLUS 0x07FE +#define SFLOAT_VALUE_NAN 0x07FF +#define SFLOAT_VALUE_NRES 0x0800 +#define SFLOAT_VALUE_RFU 0x0801 +#define SFLOAT_VALUE_INFINITY_MINUS 0x0802 + +#define FLOAT_VALUE_INFINITY_PLUS 0x007FFFFE +#define FLOAT_VALUE_NAN 0x007FFFFF +#define FLOAT_VALUE_NRES 0x00800000 +#define FLOAT_VALUE_RFU 0x00800001 +#define FLOAT_VALUE_INFINITY_MINUS 0x00800002 + +static void +sfloat_ieee_11073_fvalue_new(fvalue_t *fv) +{ + fv->value.sfloat_ieee_11073 = 0x0000; +} + +static bool +sfloat_ieee_11073_val_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg _U_) +{ + const char *i_char = s; + char c; + uint8_t mantissa_sign = 0; + uint32_t mantissa = 0; + int8_t exponent = 0; + bool fraction_mode = false; + const uint16_t mantissa_max = 0x07FF; + + c = *i_char; + + if (c== '\0') + return false; + + if (c == '.') + return false; + + if (c == '-' && s[1] == '.') + return false; + + if (c == '-' && (s[1] == 'I' || s[1] == 'i')) { + if (!g_ascii_strcasecmp(s, "-INFINITY")) { + fv->value.sfloat_ieee_11073 = SFLOAT_VALUE_INFINITY_MINUS; + return true; + } + + return false; + } else if (c == 'R' || c == 'r') { + if (!g_ascii_strcasecmp(s, "RFU")) { + fv->value.sfloat_ieee_11073 = SFLOAT_VALUE_RFU; + return true; + } + + return false; + } else if (c == 'N' || c == 'n') { + if (!g_ascii_strcasecmp(s, "NRes")) { + fv->value.sfloat_ieee_11073 = SFLOAT_VALUE_NRES; + return true; + } + + if (!g_ascii_strcasecmp(s, "NaN")) { + fv->value.sfloat_ieee_11073 = SFLOAT_VALUE_NAN; + return true; + } + + return false; + } else if (c == '+') { + if (!g_ascii_strcasecmp(s, "+INFINITY")) { + fv->value.sfloat_ieee_11073 = SFLOAT_VALUE_INFINITY_PLUS; + return true; + } + + return false; + } + + if (c == '-') { + if (s[1] == '\0') + return false; + + mantissa_sign = 1; + i_char += 1; + } + + while (*i_char == '0') { + i_char += 1; + } + + c = *i_char; + + do { + if (c == '0') { + if (mantissa * 10 > (uint32_t) mantissa_max + mantissa_sign) { + exponent += 1; + if (exponent > 7) + return false; + } else { + mantissa *= 10; + } + } else if (c == '1') { + mantissa *= 10; + mantissa += 1; + } else if (c == '2') { + mantissa *= 10; + mantissa += 2; + } else if (c == '3') { + mantissa *= 10; + mantissa += 3; + } else if (c == '4') { + mantissa *= 10; + mantissa += 4; + } else if (c == '5') { + mantissa *= 10; + mantissa += 5; + } else if (c == '6') { + mantissa *= 10; + mantissa += 6; + } else if (c == '7') { + mantissa *= 10; + mantissa += 7; + } else if (c == '8') { + mantissa *= 10; + mantissa += 8; + } else if (c == '9') { + mantissa *= 10; + mantissa += 9; + } else if (c == '.') { + if (fraction_mode) + return false; + fraction_mode = true; + i_char += 1; + + while (*i_char == '0') { + i_char += 1; + if (mantissa * 10 <= (uint32_t) mantissa_max + mantissa_sign) { + mantissa *= 10; + if (exponent > -8 - 4) /* -8 is min exponent; 4 is mantissa size */ + exponent -= 1; + } + } + + i_char -= 1; + } else if (c != '\0') { + /* NOTE: Maybe 5e-10, 5e3 notation should be also supported */ + return false; + } + + if (mantissa > (uint32_t) mantissa_max + mantissa_sign) + return false; + + if (c != '.' && fraction_mode) + exponent -= 1; + + i_char += 1; + } while ((c = *i_char)); + + if (mantissa_sign) { + mantissa = ~(mantissa - 1); + mantissa &= 0x0FFF; + } + + /* Transform to normal form */ + + if (mantissa == 0) + exponent = 0; + + while (mantissa > 0 && mantissa % 10 == 0 && exponent < 7) { + mantissa /= 10; + exponent += 1; + } + + if (exponent < -8) + return false; + + fv->value.sfloat_ieee_11073 = ((exponent & 0x0F) << 12) | mantissa; + + return true; +} + +static char * +sfloat_ieee_11073_val_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_) +{ + int8_t exponent; + uint16_t mantissa; + uint16_t mantissa_sign; + uint32_t offset = 0; + char mantissa_buf[5]; + char *mantissa_str; + uint8_t mantissa_digits; + + /* Predefinied: +INFINITY, -INFINITY, RFU, NRes, NaN */ + if (fv->value.sfloat_ieee_11073 >= 0x07FE && fv->value.sfloat_ieee_11073 <= 0x0802) { + char *s = NULL; + + switch (fv->value.sfloat_ieee_11073) { + case SFLOAT_VALUE_INFINITY_PLUS: + s = "+INFINITY"; + break; + case SFLOAT_VALUE_NAN: + s = "NaN"; + break; + case SFLOAT_VALUE_NRES: + s = "NRes"; + break; + case SFLOAT_VALUE_RFU: + s = "RFU"; + break; + case SFLOAT_VALUE_INFINITY_MINUS: + s = "-INFINITY"; + break; + } + return wmem_strdup(scope, s); + } + + /* Longest Signed Float Number: -0.00002048 (11 characters without NULL) */ + /* Longest Signed Float Number -0.00000001 */ + /* Longest Signed Nonfloat Number: -20480000000 (12 characters without NULL) */ + char buf[13]; + + exponent = fv->value.sfloat_ieee_11073 >> 12; + if (exponent & 0x8) + exponent |= 0xF0; /* It is signed (4bits), so make it signed in int8_t */ + mantissa = fv->value.sfloat_ieee_11073 & 0x07FF; + mantissa_sign = (fv->value.sfloat_ieee_11073 & 0x0800); + if (mantissa_sign) + mantissa = -((int16_t)mantissa | 0xF800); + + if (mantissa == 0) { + return wmem_strdup(scope, "0"); + } + + if (mantissa_sign) { + buf[0] = '-'; + offset += 1; + } + + mantissa_digits = snprintf(mantissa_buf, sizeof(mantissa_buf), "%"PRIu16, mantissa); + mantissa_str = mantissa_buf; + + if (exponent == 0) { + memcpy(buf + offset, mantissa_str, mantissa_digits); + offset += mantissa_digits; + } else if (exponent > 0) { + memcpy(buf + offset, mantissa_str, mantissa_digits); + offset += mantissa_digits; + + memset(buf + offset, '0', exponent); + offset += exponent; + } else /* if (exponent < 0)*/ { + if (-exponent < mantissa_digits) { + memcpy(buf + offset, mantissa_str, mantissa_digits + exponent); + offset += mantissa_digits + exponent; + + buf[offset] = '.'; + offset += 1; + + memcpy(buf + offset, mantissa_str + mantissa_digits + exponent, -exponent); + offset += -exponent; + } else { + buf[offset] = '0'; + offset += 1; + + buf[offset] = '.'; + offset += 1; + + if (-exponent - mantissa_digits > 0) { + memset(buf + offset, '0', -exponent - mantissa_digits); + offset += -exponent - mantissa_digits; + } + + memcpy(buf + offset, mantissa_str, mantissa_digits); + offset += mantissa_digits; + } + } + + buf[offset] = '\0'; + return wmem_strdup(scope, buf); +} + +static void +sfloat_ieee_11073_value_set(fvalue_t *fv, uint32_t value) +{ + fv->value.sfloat_ieee_11073 = (uint16_t) value; +} + +static uint32_t +sfloat_ieee_11073_value_get(fvalue_t *fv) +{ + return (uint32_t) fv->value.sfloat_ieee_11073; +} + +static uint16_t sfloat_to_normal_form(uint16_t value) +{ + int8_t exponent; + uint16_t mantissa; + uint8_t mantissa_sign; + + if (value >= 0x07FE && value <= 0x0802) /* Save special values */ + return value; + + mantissa = value & 0x07FF; + if (value & 0x0800) { + mantissa = -((int16_t)mantissa | 0xF800); + mantissa_sign = 1; + } else { + mantissa_sign = 0; + } + + exponent = value >> 12; + + if (exponent & 0x08) { + exponent |= 0xF0; + } + + while ((!(mantissa % 10)) && mantissa != 0) { + mantissa /= 10; + + if (exponent == 7) + break; + + exponent += 1; + } + + return ((((exponent & 0x80) ? 0x8 : 0x0 ) | (exponent & 0x7)) << 12) | (mantissa_sign << 11) | mantissa; +} + +static bool +sfloat_ieee_11073_cmp_eq(const fvalue_t *a, const fvalue_t *b) +{ + return sfloat_to_normal_form(a->value.sfloat_ieee_11073) == sfloat_to_normal_form(b->value.sfloat_ieee_11073); +} + +static bool +sfloat_ieee_11073_cmp_lt(const fvalue_t *a, const fvalue_t *b) +{ + uint16_t a_norm; + uint16_t b_norm; + int16_t a_norm_mantissa; + int16_t b_norm_mantissa; + int8_t a_norm_exponent; + int8_t b_norm_exponent; + + a_norm = sfloat_to_normal_form(a->value.sfloat_ieee_11073); + b_norm = sfloat_to_normal_form(b->value.sfloat_ieee_11073); + + if (a_norm == b_norm) + return false; + + switch (a_norm) { + case SFLOAT_VALUE_NAN: + case SFLOAT_VALUE_NRES: + case SFLOAT_VALUE_RFU: + case SFLOAT_VALUE_INFINITY_PLUS: + return false; + case SFLOAT_VALUE_INFINITY_MINUS: + switch (b_norm) { + case SFLOAT_VALUE_NAN: + case SFLOAT_VALUE_NRES: + case SFLOAT_VALUE_RFU: + case SFLOAT_VALUE_INFINITY_MINUS: /* Dead, informative case */ + return false; + case SFLOAT_VALUE_INFINITY_PLUS: + default: + return true; + } + } + + a_norm_mantissa = a_norm & 0x0FFF; + b_norm_mantissa = b_norm & 0x0FFF; + if (a_norm & 0x0800) + a_norm_mantissa |= 0xFFFFF000; + + if (b_norm & 0x0800) + b_norm_mantissa |= 0xFFFFF000; + + a_norm_exponent = a_norm >> 12; + b_norm_exponent = b_norm >> 12; + + if (a_norm_exponent & 0x08) { + a_norm_exponent |= 0xF0; + } + + if (b_norm_exponent & 0x08) { + b_norm_exponent |= 0xF0; + } + + if (a_norm_mantissa == b_norm_mantissa && a_norm_exponent < b_norm_exponent) + return true; + + if (a_norm_exponent == b_norm_exponent && a_norm_mantissa < b_norm_mantissa) + return true; + + if (a_norm_exponent < b_norm_exponent) { + uint8_t exponent_difference; + + exponent_difference = b_norm_exponent - a_norm_exponent; + + if (exponent_difference >= 4) + return true; + + while (exponent_difference--) { + b_norm_mantissa *= 10; + } + } else { + uint8_t exponent_difference; + + exponent_difference = a_norm_exponent - b_norm_exponent; + + if (exponent_difference >= 4) + return false; + + while (exponent_difference--) { + a_norm_mantissa *= 10; + } + } + + if (a_norm_mantissa < b_norm_mantissa) + return true; + + return false; +} + +static enum ft_result +sfloat_ieee_11073_cmp_order(const fvalue_t *a, const fvalue_t *b, int *cmp) +{ + if (sfloat_ieee_11073_cmp_lt(a, b)) + *cmp = -1; + else + *cmp = sfloat_ieee_11073_cmp_eq(a, b) ? 0 : 1; + + return FT_OK; +} + +static bool +sfloat_ieee_11073_is_zero(const fvalue_t *a) +{ + return a->value.sfloat_ieee_11073 == 0; +} + +static unsigned +sfloat_ieee_11073_hash(const fvalue_t *fv) +{ + int64_t value = fv->value.sfloat_ieee_11073; + return g_int64_hash(&value); +} + +/*============================================================================*/ + +static void +float_ieee_11073_fvalue_new(fvalue_t *fv) +{ + fv->value.float_ieee_11073 = 0x0000; +} + +static bool +float_ieee_11073_val_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg _U_) +{ + const char *i_char = s; + char c; + uint8_t mantissa_sign = 0; + uint32_t mantissa = 0; + int16_t exponent = 0; + bool fraction_mode = false; + const uint32_t mantissa_max = 0x007FFFFF; + + c = *i_char; + + if (c== '\0') + return false; + + if (c == '.') + return false; + + if (c == '-' && s[1] == '.') + return false; + + if (c == '-' && (s[1] == 'I' || s[1] == 'i')) { + if (!g_ascii_strcasecmp(s, "-INFINITY")) { + fv->value.float_ieee_11073 = FLOAT_VALUE_INFINITY_MINUS; + return true; + } + + return false; + } else if (c == 'R' || c == 'r') { + if (!g_ascii_strcasecmp(s, "RFU")) { + fv->value.float_ieee_11073 = FLOAT_VALUE_RFU; + return true; + } + + return false; + } else if (c == 'N' || c == 'n') { + if (!g_ascii_strcasecmp(s, "NRes")) { + fv->value.float_ieee_11073 = FLOAT_VALUE_NRES; + return true; + } + + if (!g_ascii_strcasecmp(s, "NaN")) { + fv->value.float_ieee_11073 = FLOAT_VALUE_NAN; + return true; + } + + return false; + } else if (c == '+') { + if (!g_ascii_strcasecmp(s, "+INFINITY")) { + fv->value.float_ieee_11073 = FLOAT_VALUE_INFINITY_PLUS; + return true; + } + + return false; + } + + if (c == '-') { + if (s[1] == '\0') + return false; + + mantissa_sign = 1; + i_char += 1; + } + + while (*i_char == '0') { + i_char += 1; + } + + c = *i_char; + + do { + if (c == '0') { + if (mantissa * 10 > mantissa_sign + mantissa_max) { + exponent += 1; + if (exponent <= 127) + return false; + } else { + mantissa *= 10; + } + } else if (c == '1') { + mantissa *= 10; + mantissa += 1; + } else if (c == '2') { + mantissa *= 10; + mantissa += 2; + } else if (c == '3') { + mantissa *= 10; + mantissa += 3; + } else if (c == '4') { + mantissa *= 10; + mantissa += 4; + } else if (c == '5') { + mantissa *= 10; + mantissa += 5; + } else if (c == '6') { + mantissa *= 10; + mantissa += 6; + } else if (c == '7') { + mantissa *= 10; + mantissa += 7; + } else if (c == '8') { + mantissa *= 10; + mantissa += 8; + } else if (c == '9') { + mantissa *= 10; + mantissa += 9; + } else if (c == '.') { + if (fraction_mode) + return false; + fraction_mode = true; + i_char += 1; + + while (*i_char == '0') { + i_char += 1; + if (mantissa * 10 <= mantissa_max + mantissa_sign) { + mantissa *= 10; + if (exponent > -128 - 7) /* -8 is min exponent; 4 is mantissa size */ + exponent -= 1; + } + } + + i_char -= 1; + } else if (c != '\0') { + /* NOTE: Maybe 5e-10, 5e3 notation should be also supported */ + return false; + } + + if (mantissa > mantissa_max + mantissa_sign) + return false; + + if (c != '.' && fraction_mode) + exponent -= 1; + + i_char += 1; + } while ((c = *i_char)); + + if (mantissa_sign) { + mantissa = ~(mantissa - 1); + mantissa &= 0x00FFFFFF; + } + + /* Transform to normal form */ + + if (mantissa == 0) + exponent = 0; + + while (mantissa > 0 && mantissa % 10 == 0 && exponent < 127) { + mantissa /= 10; + exponent += 1; + } + + if (exponent < -128) + return false; + + fv->value.float_ieee_11073 = ((exponent & 0xFF) << 24) | mantissa; + + return true; +} + +static char * +float_ieee_11073_val_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_) +{ + int8_t exponent; + uint32_t mantissa; + uint32_t mantissa_sign; + uint32_t offset = 0; + char mantissa_buf[8]; + char *mantissa_str; + uint8_t mantissa_digits; + + /* Predefinied: +INFINITY, -INFINITY, RFU, NRes, NaN */ + if (fv->value.float_ieee_11073 >= 0x007FFFFE && fv->value.float_ieee_11073 <= 0x00800002) { + char *s = NULL; + switch (fv->value.float_ieee_11073) { + case FLOAT_VALUE_INFINITY_PLUS: + s = "+INFINITY"; + break; + case FLOAT_VALUE_NAN: + s = "NaN"; + break; + case FLOAT_VALUE_NRES: + s = "NRes"; + break; + case FLOAT_VALUE_RFU: + s = "RFU"; + break; + case FLOAT_VALUE_INFINITY_MINUS: + s = "-INFINITY"; + break; + } + return wmem_strdup(scope, s); + } + + /* Longest Signed Nonfloat Number: -8388608*(10^-128) (1 character for sign, 7 for mantisa digits, 127 zeros, 1 character for NULL) */ + char buf[136]; + + exponent = fv->value.float_ieee_11073 >> 24; + + mantissa = fv->value.float_ieee_11073 & 0x007FFFFF; + mantissa_sign = (fv->value.float_ieee_11073 & 0x00800000); + if (mantissa_sign) + mantissa = (uint32_t)(-((int32_t)(mantissa | 0xFF000000))); + + if (mantissa == 0) { + return wmem_strdup(scope, "0"); + } + + if (mantissa_sign) { + buf[0] = '-'; + offset += 1; + } + + mantissa_digits = snprintf(mantissa_buf, sizeof(mantissa_buf), "%"PRIu32, mantissa); + mantissa_str = mantissa_buf; + + if (exponent == 0) { + memcpy(buf + offset, mantissa_str, mantissa_digits); + offset += mantissa_digits; + } else if (exponent > 0) { + memcpy(buf + offset, mantissa_str, mantissa_digits); + offset += mantissa_digits; + + memset(buf + offset, '0', exponent); + offset += exponent; + } else /* if (exponent < 0)*/ { + if (-exponent < mantissa_digits) { + memcpy(buf + offset, mantissa_str, mantissa_digits + exponent); + offset += mantissa_digits + exponent; + + buf[offset] = '.'; + offset += 1; + + memcpy(buf + offset, mantissa_str + mantissa_digits + exponent, -exponent); + offset += -exponent; + } else { + buf[offset] = '0'; + offset += 1; + + buf[offset] = '.'; + offset += 1; + + if (-exponent - mantissa_digits > 0) { + memset(buf + offset, '0', -exponent - mantissa_digits); + offset += -exponent - mantissa_digits; + } + + memcpy(buf + offset, mantissa_str, mantissa_digits); + offset += mantissa_digits; + } + } + + buf[offset] = '\0'; + return wmem_strdup(scope, buf); +} + +static void +float_ieee_11073_value_set(fvalue_t *fv, uint32_t value) +{ + fv->value.float_ieee_11073 = value; +} + +static uint32_t +float_ieee_11073_value_get(fvalue_t *fv) +{ + return fv->value.float_ieee_11073; +} + +static uint32_t float_to_normal_form(uint32_t value) +{ + int8_t exponent; + uint16_t mantissa; + uint8_t mantissa_sign; + + if (value >= 0x007FFFFE && value <= 0x00800002) /* Save special values */ + return value; + + mantissa = value & 0x907FFFFF; + if (value & 0x00800000) { + mantissa = (uint32_t)(-((int32_t)(mantissa | 0xFF000000))); + mantissa_sign = 1; + } else { + mantissa_sign = 0; + } + + exponent = value >> 24; + + while ((!(mantissa % 10)) && mantissa != 0) { + mantissa /= 10; + + if (exponent == 127) + break; + + exponent += 1; + } + + return (exponent << 24) | (mantissa_sign << 23) | mantissa; +} + +static bool +float_ieee_11073_cmp_eq(const fvalue_t *a, const fvalue_t *b) +{ + return float_to_normal_form(a->value.float_ieee_11073) == float_to_normal_form(b->value.float_ieee_11073); +} + +static bool +float_ieee_11073_cmp_lt(const fvalue_t *a, const fvalue_t *b) +{ + uint32_t a_norm; + uint32_t b_norm; + int32_t a_norm_mantissa; + int32_t b_norm_mantissa; + int8_t a_norm_exponent; + int8_t b_norm_exponent; + + a_norm = float_to_normal_form(a->value.float_ieee_11073); + b_norm = float_to_normal_form(b->value.float_ieee_11073); + + if (a_norm == b_norm) + return false; + + switch (a_norm) { + case FLOAT_VALUE_NAN: + case FLOAT_VALUE_NRES: + case FLOAT_VALUE_RFU: + case FLOAT_VALUE_INFINITY_PLUS: + return false; + case FLOAT_VALUE_INFINITY_MINUS: + switch (b_norm) { + case FLOAT_VALUE_NAN: + case FLOAT_VALUE_NRES: + case FLOAT_VALUE_RFU: + case FLOAT_VALUE_INFINITY_MINUS: /* Dead, informative case */ + return false; + case FLOAT_VALUE_INFINITY_PLUS: + default: + return true; + } + } + + a_norm_mantissa = a_norm & 0x00FFFFFF; + b_norm_mantissa = b_norm & 0x00FFFFFF; + if (a_norm & 0x00800000) + a_norm_mantissa |= 0xFF000000; + + if (b_norm & 0x00800000) + b_norm_mantissa |= 0xFF000000; + + a_norm_exponent = a_norm >> 24; + b_norm_exponent = b_norm >> 24; + + if (a_norm_mantissa == b_norm_mantissa && a_norm_exponent < b_norm_exponent) + return true; + + if (a_norm_exponent == b_norm_exponent && a_norm_mantissa < b_norm_mantissa) + return true; + + if (a_norm_exponent < b_norm_exponent) { + uint8_t exponent_difference; + + exponent_difference = b_norm_exponent - a_norm_exponent; + + if (exponent_difference >= 7) + return true; + + while (exponent_difference--) { + b_norm_mantissa *= 10; + } + } else { + uint8_t exponent_difference; + + exponent_difference = a_norm_exponent - b_norm_exponent; + + if (exponent_difference >= 7) + return false; + + while (exponent_difference--) { + a_norm_mantissa *= 10; + } + } + + if (a_norm_mantissa < b_norm_mantissa) + return true; + + return false; +} + +static enum ft_result +float_ieee_11073_cmp_order(const fvalue_t *a, const fvalue_t *b, int *cmp) +{ + if (float_ieee_11073_cmp_lt(a, b)) + *cmp = -1; + else + *cmp = float_ieee_11073_cmp_eq(a, b) ? 0 : 1; + + return FT_OK; +} + +static bool +float_ieee_11073_is_zero(const fvalue_t *a) +{ + return a->value.float_ieee_11073 == 0; +} + +static unsigned +float_ieee_11073_hash(const fvalue_t *fv) +{ + int64_t value = fv->value.float_ieee_11073; + return g_int64_hash(&value); +} + +/*============================================================================*/ + +void +ftype_register_ieee_11073_float(void) +{ +/* +Size: 16bits = 2 octets + +Exponent: 4 bits (signed integer - 2's complement) +Mantissa: 12 bits (signed integer - 2's complement) +Base: 10 + +x = M * (10 ^ E) + +Exponent range: from -8 to 7 +Mantissa range: from -2048 to 2047 (4 digits) + +Special values: + + INFINITY [exponent 0, mantissa +(2^11 -2) = 0x07FE] + NaN (Not a Number) [exponent 0, mantissa +(2^11 -1) = 0x07FF] + NRes (Not at this Resolution) [exponent 0, mantissa -(2^11) = 0x0800] + Reserved for future use [exponent 0, mantissa -(2^11 -1) = 0x0801] + - INFINITY [exponent 0, mantissa -(2^11 -2) = 0x0802] + +Note: +be carefour when comparing: 1e == 10e-1 == 10e-2 == ... (solution: compare only if the lowest mantissa % 10 != 0) + +Example: 114 is 0x0072 + +*/ + static ftype_t sfloat_type = { + FT_IEEE_11073_SFLOAT, /* ftype */ + "FT_IEEE_11073_SFLOAT", /* name */ + "IEEE-11073 floating point (16-bit)", /* pretty_name */ + 2, /* wire_size */ + + sfloat_ieee_11073_fvalue_new, /* new_value */ + NULL, /* copy_value */ + NULL, /* free_value */ + sfloat_ieee_11073_val_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + NULL, /* val_from_charconst */ + sfloat_ieee_11073_val_to_repr, /* val_to_string_repr */ + + NULL, /* val_to_uinteger64 */ + NULL, /* val_to_sinteger64 */ + + { .set_value_uinteger = sfloat_ieee_11073_value_set }, /* union set_value */ + { .get_value_uinteger = sfloat_ieee_11073_value_get }, /* union get_value */ + + sfloat_ieee_11073_cmp_order, + NULL, /* cmp_contains */ + NULL, /* cmp_matches */ + + sfloat_ieee_11073_hash, /* hash */ + sfloat_ieee_11073_is_zero, /* is_zero */ + NULL, /* is_negative */ + NULL, /* len */ + NULL, /* slice */ + NULL, /* bitwise_and */ + NULL, /* unary_minus */ + NULL, /* add */ + NULL, /* subtract */ + NULL, /* multiply */ + NULL, /* divide */ + NULL, /* modulo */ + }; + +/* +Size: 32bits = 4 octets + +Exponent: 1 octet (signed integer - 2's complement) +Mantissa: 3 octets (signed integer - 2's complement) +Base: 10 + +x = M * (10 ^ E) + +Exponent range: from -128 to 127 +Mantissa range: from -8388608 to 8388607 (7 digits) + +Special values: + + INFINITY [exponent 0, mantissa +(2^23 -2) = 0x007FFFFE] + NaN (Not a Number) [exponent 0, mantissa +(2^23 -1) = 0x007FFFFF] + NRes (Not at this Resolution) [exponent 0, mantissa -(2^23) = 0x00800000] + Reserved for future use [exponent 0, mantissa -(2^23-1) = 0x00800001] + - INFINITY [exponent 0, mantissa -(2^23 -2) = 0x00800002] + +Note: +be carefour when comparing: 1e == 10e-1 == 10e-2 == ... (solution: compare only if the lowest mantissa % 10 != 0) + +Example: 36.4 is 0xFF00016C + +*/ + + static ftype_t float_type = { + FT_IEEE_11073_FLOAT, /* ftype */ + "FT_IEEE_11073_FLOAT", /* name */ + "IEEE-11073 Floating point (32-bit)", /* pretty_name */ + 4, /* wire_size */ + + float_ieee_11073_fvalue_new, /* new_value */ + NULL, /* copy_value */ + NULL, /* free_value */ + float_ieee_11073_val_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + NULL, /* val_from_charconst */ + float_ieee_11073_val_to_repr, /* val_to_string_repr */ + + NULL, /* val_to_uinteger64 */ + NULL, /* val_to_sinteger64 */ + + { .set_value_uinteger = float_ieee_11073_value_set }, /* union set_value */ + { .get_value_uinteger = float_ieee_11073_value_get }, /* union get_value */ + + float_ieee_11073_cmp_order, + NULL, /* cmp_contains */ + NULL, /* cmp_matches */ + + float_ieee_11073_hash, /* hash */ + float_ieee_11073_is_zero, /* is_zero */ + NULL, /* is_negative */ + NULL, /* len */ + NULL, /* slice */ + NULL, /* bitwise_and */ + NULL, /* unary_minus */ + NULL, /* add */ + NULL, /* subtract */ + NULL, /* multiply */ + NULL, /* divide */ + NULL, /* modulo */ + }; + + ftype_register(FT_IEEE_11073_SFLOAT, &sfloat_type); + ftype_register(FT_IEEE_11073_FLOAT, &float_type); +} + +void +ftype_register_pseudofields_ieee_11073_float(int proto) +{ + static int hf_ft_ieee_11073_sfloat; + static int hf_ft_ieee_11073_float; + + static hf_register_info hf_ftypes[] = { + { &hf_ft_ieee_11073_sfloat, + { "FT_IEEE_11073_SFLOAT", "_ws.ftypes.ieee_11073_sfloat", + FT_IEEE_11073_SFLOAT, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_ieee_11073_float, + { "FT_IEEE_11073_FLOAT", "_ws.ftypes.ieee_11073_float", + FT_IEEE_11073_FLOAT, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + }; + + proto_register_field_array(proto, hf_ftypes, array_length(hf_ftypes)); +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/epan/ftypes/ftype-integer.c b/epan/ftypes/ftype-integer.c new file mode 100644 index 0000000..608fca0 --- /dev/null +++ b/epan/ftypes/ftype-integer.c @@ -0,0 +1,2209 @@ +/* + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 2001 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include <stdlib.h> +#include <errno.h> +#include "ftypes-int.h" +#include <epan/addr_resolv.h> +#include <epan/strutil.h> +#include <epan/to_str.h> + +#include <wsutil/pint.h> +#include <wsutil/safe-math.h> + +static bool +binary_strtoll(const char *s, int64_t *ptr, char **err_msg); + +static bool +binary_strtoull(const char *s, uint64_t *ptr, char **err_msg); + +static void +int_fvalue_new(fvalue_t *fv) +{ + memset(&fv->value, 0, sizeof(fv->value)); +} + +static void +set_uinteger(fvalue_t *fv, uint32_t value) +{ + fv->value.uinteger = value; +} + +static void +set_sinteger(fvalue_t *fv, int32_t value) +{ + fv->value.sinteger = value; +} + + +static uint32_t +get_uinteger(fvalue_t *fv) +{ + return fv->value.uinteger; +} + +static int32_t +get_sinteger(fvalue_t *fv) +{ + return fv->value.sinteger; +} + +static bool +_uint_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg, + uint64_t max) +{ + uint64_t value; + + if (!binary_strtoull(s, &value, err_msg)) + return false; + + if (value > max) { + if (err_msg != NULL) + *err_msg = ws_strdup_printf("\"%s\" too big for this field, maximum %"PRIu64".", s, max); + return false; + } + + fv->value.uinteger = (uint32_t)value; + return true; +} + +static bool +uint32_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg) +{ + return _uint_from_literal (fv, s, allow_partial_value, err_msg, UINT32_MAX); +} + +static bool +uint24_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg) +{ + return _uint_from_literal (fv, s, allow_partial_value, err_msg, 0xFFFFFF); +} + +static bool +uint16_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg) +{ + return _uint_from_literal (fv, s, allow_partial_value, err_msg, UINT16_MAX); +} + +static bool +uint8_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg) +{ + return _uint_from_literal (fv, s, allow_partial_value, err_msg, UINT8_MAX); +} + +static bool +uint_from_charconst(fvalue_t *fv, unsigned long num, char **err_msg _U_) +{ + fv->value.uinteger = (uint32_t)num; + return true; +} + +static bool +_sint_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg, + int64_t max, int64_t min) +{ + int64_t value; + + if (!binary_strtoll(s, &value, err_msg)) + return false; + + if (value > max) { + if (err_msg != NULL) + *err_msg = ws_strdup_printf("\"%s\" too big for this field, maximum %"PRId64".", + s, max); + return false; + } + else if (value < min) { + if (err_msg != NULL) + *err_msg = ws_strdup_printf("\"%s\" too small for this field, minimum %"PRId64".", + s, min); + return false; + } + + fv->value.sinteger = (int32_t)value; + return true; +} + +static bool +sint32_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg) +{ + return _sint_from_literal (fv, s, allow_partial_value, err_msg, INT32_MAX, INT32_MIN); +} + +static bool +sint24_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg) +{ + return _sint_from_literal (fv, s, allow_partial_value, err_msg, 0x7FFFFF, -0x800000); +} + +static bool +sint16_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg) +{ + return _sint_from_literal (fv, s, allow_partial_value, err_msg, INT16_MAX, INT16_MIN); +} + +static bool +sint8_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg) +{ + return _sint_from_literal (fv, s, allow_partial_value, err_msg, INT8_MAX, INT8_MIN); +} + +static bool +sint_from_charconst(fvalue_t *fv, unsigned long num, char **err_msg _U_) +{ + fv->value.sinteger = (int32_t)num; + return true; +} + +static char * +integer_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_) +{ + uint32_t val; + + size_t size = 11 + 1; /* enough for 2^31-1, in decimal */ + char *result = wmem_alloc(scope, size); + char *buf = result; + + if (fv->value.sinteger < 0) { + *buf++ = '-'; + val = -fv->value.sinteger; + } else { + val = fv->value.sinteger; + } + guint32_to_str_buf(val, buf, size); + return result; +} + +static char * +uinteger_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display) +{ + size_t size = 10 + 1; /* enough for 2^32-1, in decimal or 0xXXXXXXXX */ + char *result = wmem_alloc(scope, size); + char *buf = result; + + if ((field_display & 0xff) == BASE_HEX || + (field_display & 0xff) == BASE_HEX_DEC) { + /* This format perfectly fits into 11 bytes. */ + *buf++ = '0'; + *buf++ = 'x'; + + switch (fv->ftype->ftype) { + + case FT_UINT8: + buf = guint8_to_hex(buf, fv->value.uinteger); + break; + + case FT_UINT16: + buf = word_to_hex(buf, fv->value.uinteger); + break; + + case FT_UINT24: + buf = guint8_to_hex(buf, (fv->value.uinteger & 0x00ff0000) >> 16); + buf = word_to_hex(buf, (fv->value.uinteger & 0x0000ffff)); + break; + + default: + buf = dword_to_hex(buf, fv->value.uinteger); + break; + } + + *buf++ = '\0'; + } + else { + guint32_to_str_buf(fv->value.uinteger, buf, size); + } + return result; +} + +static char * +char_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display) +{ + size_t size = 7 + 1; /* enough for '\OOO' or '\xXX' */ + char *result = wmem_alloc(scope, size); + char *buf = result; + + /* + * The longest possible strings are "'\OOO'" and "'\xXX'", which + * take 7 bytes, including the terminating '\0'. + */ + *buf++ = '\''; + if (g_ascii_isprint(fv->value.uinteger)) { + /* This perfectly fits into 4 or 5 bytes. */ + if (fv->value.uinteger == '\\' || fv->value.uinteger == '\'') + *buf++ = '\\'; + *buf++ = (char)fv->value.uinteger; + } + else { + *buf++ = '\\'; + switch (fv->value.uinteger) { + + case '\0': + *buf++ = '0'; + break; + + case '\a': + *buf++ = 'a'; + break; + + case '\b': + *buf++ = 'b'; + break; + + case '\f': + *buf++ = 'f'; + break; + + case '\n': + *buf++ = 'n'; + break; + + case '\r': + *buf++ = 'r'; + break; + + case '\t': + *buf++ = 't'; + break; + + case '\v': + *buf++ = 'v'; + break; + + default: + if (field_display == BASE_HEX) { + *buf++ = 'x'; + buf = guint8_to_hex(buf, fv->value.uinteger); + } + else { + *buf++ = ((fv->value.uinteger >> 6) & 0x7) + '0'; + *buf++ = ((fv->value.uinteger >> 3) & 0x7) + '0'; + *buf++ = ((fv->value.uinteger >> 0) & 0x7) + '0'; + } + break; + } + } + *buf++ = '\''; + *buf++ = '\0'; + return result; +} + +static bool +ipxnet_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg) +{ + /* + * Don't request an error message if bytes_from_literal fails; + * if it does, we'll report an error specific to this address + * type. + */ + if (uint32_from_literal(fv, s, true, NULL)) { + return true; + } + + /* XXX - Try resolving as an IPX host name and parse that? */ + + if (err_msg != NULL) + *err_msg = ws_strdup_printf("\"%s\" is not a valid IPX network address.", s); + return false; +} + +static char * +ipxnet_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype, int field_display _U_) +{ + return uinteger_to_repr(scope, fv, rtype, BASE_HEX); +} + +static enum ft_result +uint64_cmp_order(const fvalue_t *a, const fvalue_t *b, int *cmp) +{ + uint64_t val_a, val_b; + enum ft_result res; + + res = fvalue_to_uinteger64(a, &val_a); + if (res != FT_OK) + return res; + + res = fvalue_to_uinteger64(b, &val_b); + if (res != FT_OK) + return res; + + if (val_a == val_b) + *cmp = 0; + else + *cmp = val_a < val_b ? -1 : 1; + + return FT_OK; +} + +static enum ft_result +uint_cmp_order(const fvalue_t *a, const fvalue_t *b, int *cmp) +{ + return uint64_cmp_order(a, b, cmp); +} + +static enum ft_result +sint64_cmp_order(const fvalue_t *a, const fvalue_t *b, int *cmp) +{ + int64_t val_a, val_b; + enum ft_result res; + + res = fvalue_to_sinteger64(a, &val_a); + if (res != FT_OK) + return res; + + res = fvalue_to_sinteger64(b, &val_b); + if (res != FT_OK) + return res; + + if (val_a == val_b) + *cmp = 0; + else + *cmp = val_a < val_b ? -1 : 1; + + return FT_OK; +} + +static enum ft_result +sint_cmp_order(const fvalue_t *a, const fvalue_t *b, int *cmp) +{ + return sint64_cmp_order(a, b, cmp); +} + +static void +int64_fvalue_new(fvalue_t *fv) +{ + fv->value.sinteger64 = 0; +} + +static void +set_uinteger64(fvalue_t *fv, uint64_t value) +{ + fv->value.uinteger64 = value; +} + +static void +set_sinteger64(fvalue_t *fv, int64_t value) +{ + fv->value.sinteger64 = value; +} + +static uint64_t +get_uinteger64(fvalue_t *fv) +{ + return fv->value.uinteger64; +} + +static int64_t +get_sinteger64(fvalue_t *fv) +{ + return fv->value.sinteger64; +} + +static bool +binary_strtoull(const char *s, uint64_t *ptr, char **err_msg) +{ + char *endptr; + + errno = 0; + if (s[0] == '0' && (s[1] == 'b' || s[1] == 'B')) { + *ptr = g_ascii_strtoull(s + 2, &endptr, 2); + } + else { + *ptr = g_ascii_strtoull(s, &endptr, 0); + } + + if (errno == EINVAL || endptr == s || *endptr != '\0') { + /* This isn't a valid number. */ + if (err_msg != NULL) + *err_msg = ws_strdup_printf("\"%s\" is not a valid number.", s); + return false; + } + if (errno == ERANGE) { + if (*ptr == UINT64_MAX) { + if (err_msg != NULL) { + *err_msg = ws_strdup_printf("\"%s\" causes an integer overflow.", s); + } + } + else if (err_msg != NULL) { + /* + * XXX - can "strtol()" set errno to + * ERANGE without returning LONG_MAX? + */ + *err_msg = ws_strdup_printf("\"%s\" is not an integer.", s); + } + return false; + } + + return true; +} + +static bool +_uint64_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg, + uint64_t max) +{ + uint64_t value; + + if (!binary_strtoull(s, &value, err_msg)) + return false; + + if (value > max) { + if (err_msg != NULL) + *err_msg = ws_strdup_printf("\"%s\" too big for this field, maximum %" PRIu64".", s, max); + return false; + } + + fv->value.uinteger64 = value; + return true; +} + +static bool +uint64_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg) +{ + return _uint64_from_literal (fv, s, allow_partial_value, err_msg, UINT64_MAX); +} + +static bool +uint56_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg) +{ + return _uint64_from_literal (fv, s, allow_partial_value, err_msg, G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFF)); +} + +static bool +uint48_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg) +{ + return _uint64_from_literal (fv, s, allow_partial_value, err_msg, G_GUINT64_CONSTANT(0xFFFFFFFFFFFF)); +} + +static bool +uint40_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg) +{ + return _uint64_from_literal (fv, s, allow_partial_value, err_msg, G_GUINT64_CONSTANT(0xFFFFFFFFFF)); +} + +static bool +uint64_from_charconst(fvalue_t *fv, unsigned long num, char **err_msg _U_) +{ + fv->value.uinteger64 = (uint64_t)num; + return true; +} + +static bool +binary_strtoll(const char *s, int64_t *ptr, char **err_msg) +{ + char *endptr; + + errno = 0; + if (s[0] == '0' && (s[1] == 'b' || s[1] == 'B')) { + *ptr = g_ascii_strtoll(s + 2, &endptr, 2); + } + else { + *ptr = g_ascii_strtoll(s, &endptr, 0); + } + + if (errno == EINVAL || endptr == s || *endptr != '\0') { + /* This isn't a valid number. */ + if (err_msg != NULL) + *err_msg = ws_strdup_printf("\"%s\" is not a valid number.", s); + return false; + } + if (errno == ERANGE) { + if (*ptr == INT64_MAX) { + if (err_msg != NULL) { + *err_msg = ws_strdup_printf("\"%s\" causes an integer overflow.", s); + } + } + else if (*ptr == INT64_MIN) { + if (err_msg != NULL) { + *err_msg = ws_strdup_printf("\"%s\" causes an integer underflow.", s); + } + } + else if (err_msg != NULL) { + /* + * XXX - can "strtol()" set errno to + * ERANGE without returning LONG_MAX? + */ + *err_msg = ws_strdup_printf("\"%s\" is not an integer.", s); + } + return false; + } + + return true; +} + +static bool +_sint64_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg, + int64_t max, int64_t min) +{ + int64_t value; + + if (!binary_strtoll(s, &value, err_msg)) + return false; + + if (value > max) { + if (err_msg != NULL) + *err_msg = ws_strdup_printf("\"%s\" too big for this field, maximum %" PRId64".", s, max); + return false; + } + else if (value < min) { + if (err_msg != NULL) + *err_msg = ws_strdup_printf("\"%s\" too small for this field, minimum %" PRId64 ".", s, min); + return false; + } + + fv->value.sinteger64 = value; + return true; +} + +static bool +sint64_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg) +{ + return _sint64_from_literal (fv, s, allow_partial_value, err_msg, INT64_MAX, INT64_MIN); +} + +static bool +sint56_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg) +{ + return _sint64_from_literal (fv, s, allow_partial_value, err_msg, G_GINT64_CONSTANT(0x7FFFFFFFFFFFFF), G_GINT64_CONSTANT(-0x80000000000000)); +} + +static bool +sint48_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg) +{ + return _sint64_from_literal (fv, s, allow_partial_value, err_msg, G_GINT64_CONSTANT(0x7FFFFFFFFFFF), G_GINT64_CONSTANT(-0x800000000000)); +} + +static bool +sint40_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value, char **err_msg) +{ + return _sint64_from_literal (fv, s, allow_partial_value, err_msg, G_GINT64_CONSTANT(0x7FFFFFFFFF), G_GINT64_CONSTANT(-0x8000000000)); +} + +static bool +sint64_from_charconst(fvalue_t *fv, unsigned long num, char **err_msg _U_) +{ + fv->value.sinteger64 = (int64_t)num; + return true; +} + +static char * +integer64_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_) +{ + uint64_t val; + + size_t size = 20 + 1; /* enough for -2^63-1, in decimal */ + char *result = wmem_alloc(scope, size); + char *buf = result; + + if (fv->value.sinteger64 < 0) { + *buf++ = '-'; + val = -fv->value.sinteger64; + } + else { + val = fv->value.sinteger64; + } + guint64_to_str_buf(val, buf, size); + return result; +} + +static char * +uinteger64_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_) +{ + size_t size = 20 + 1; /* enough for 2^64-1, in decimal or 0xXXXXXXXXXXXXXXXX */ + char *result = wmem_alloc(scope, size); + char *buf = result; + + if (field_display == BASE_HEX || field_display == BASE_HEX_DEC) { + /* This format perfectly fits into 19 bytes. */ + *buf++ = '0'; + *buf++ = 'x'; + + buf = qword_to_hex(buf, fv->value.uinteger64); + *buf++ = '\0'; + } + else { + guint64_to_str_buf(fv->value.uinteger64, buf, size); + } + return result; +} + +static enum ft_result +uint_bitwise_and(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr _U_) +{ + dst->value.uinteger = a->value.uinteger & b->value.uinteger; + return FT_OK; +} + +static unsigned +uint_hash(const fvalue_t *fv) +{ + int64_t val = fv->value.uinteger; + return g_int64_hash(&val); +} + +static bool +uint_is_zero(const fvalue_t *fv) +{ + return fv->value.uinteger == 0; +} + +static bool +uint_is_negative(const fvalue_t *fv _U_) +{ + return false; +} + +static enum ft_result +uint_unary_minus(fvalue_t *dst, const fvalue_t *src, char **err_ptr) +{ + /* Unsigned integers are promoted to signed 32 bits. */ + if (src->value.uinteger > INT32_MAX) { + if (err_ptr) + *err_ptr = ws_strdup_printf("%"G_GUINT32_FORMAT" overflows gint32", + src->value.uinteger); + return FT_ERROR; + } + FTYPE_LOOKUP(FT_INT32, dst->ftype); + dst->value.sinteger = -(int32_t)src->value.uinteger; + return FT_OK; +} + +static enum ft_result +uint64_bitwise_and(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr _U_) +{ + dst->value.uinteger64 = a->value.uinteger64 & b->value.uinteger64; + return FT_OK; +} + +static unsigned +uint64_hash(const fvalue_t *fv) +{ + int64_t val = fv->value.uinteger64; + return g_int64_hash(&val); +} + +static bool +uint64_is_zero(const fvalue_t *fv) +{ + return fv->value.uinteger64 == 0; +} + +static bool +uint64_is_negative(const fvalue_t *fv _U_) +{ + return false; +} + +static enum ft_result +uint64_unary_minus(fvalue_t *dst, const fvalue_t *src, char **err_ptr) +{ + /* Unsigned64 integers are promoted to signed 64 bits. */ + if (src->value.uinteger64 > INT64_MAX) { + if (err_ptr) + *err_ptr = ws_strdup_printf("%"PRIu64" overflows gint64", + src->value.uinteger64); + return FT_ERROR; + } + FTYPE_LOOKUP(FT_INT64, dst->ftype); + dst->value.sinteger64 = -(int64_t)src->value.uinteger64; + return FT_OK; +} + +static enum ft_result +sint_bitwise_and(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr _U_) +{ + dst->value.sinteger = a->value.sinteger & b->value.sinteger; + return FT_OK; +} + +static unsigned +sint_hash(const fvalue_t *fv) +{ + int64_t val = fv->value.sinteger; + return g_int64_hash(&val); +} + +static bool +sint_is_zero(const fvalue_t *fv) +{ + return fv->value.sinteger == 0; +} + +static bool +sint_is_negative(const fvalue_t *fv) +{ + return fv->value.sinteger < 0; +} + +static enum ft_result +sint_unary_minus(fvalue_t * dst, const fvalue_t *src, char **err_ptr _U_) +{ + dst->value.sinteger = -src->value.sinteger; + return FT_OK; +} + +static enum ft_result +sint64_bitwise_and(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr _U_) +{ + dst->value.sinteger64 = a->value.sinteger64 & b->value.sinteger64; + return FT_OK; +} + +static unsigned +sint64_hash(const fvalue_t *fv) +{ + int64_t val = fv->value.sinteger64; + return g_int64_hash(&val); +} + +static bool +sint64_is_zero(const fvalue_t *fv) +{ + return fv->value.sinteger64 == 0; +} + +static bool +sint64_is_negative(const fvalue_t *fv) +{ + return fv->value.sinteger64 < 0; +} + +static enum ft_result +sint64_unary_minus(fvalue_t * dst, const fvalue_t *src, char **err_ptr _U_) +{ + dst->value.sinteger64 = -src->value.sinteger64; + return FT_OK; +} + +static enum ft_result +sint_add(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr) +{ + if (!psnip_safe_int32_add(&dst->value.sinteger, a->value.sinteger, b->value.sinteger)) { + *err_ptr = ws_strdup_printf("sint_add: overflow"); + return FT_ERROR; + } + return FT_OK; +} + +static enum ft_result +_sint_subtract(int32_t *sint_dst, int32_t sint_a, int32_t sint_b, char **err_ptr) +{ + if (!psnip_safe_int32_sub(sint_dst, sint_a, sint_b)) { + *err_ptr = ws_strdup_printf("sint_subtract: overflow"); + return FT_ERROR; + } + return FT_OK; +} + +static enum ft_result +sint_subtract(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr) +{ + return _sint_subtract(&dst->value.sinteger, a->value.sinteger, b->value.sinteger, err_ptr); +} + +static enum ft_result +sint_multiply(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr) +{ + if (!psnip_safe_int32_mul(&dst->value.sinteger, a->value.sinteger, b->value.sinteger)) { + *err_ptr = ws_strdup_printf("sint_multiply: overflow"); + return FT_ERROR; + } + return FT_OK; +} + +static enum ft_result +sint_divide(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr) +{ + if (b->value.sinteger == 0) { + *err_ptr = ws_strdup_printf("sint_divide: division by zero"); + return FT_ERROR; + } + + if (!psnip_safe_int32_div(&dst->value.sinteger, a->value.sinteger, b->value.sinteger)) { + *err_ptr = ws_strdup_printf("sint_divide: overflow"); + return FT_ERROR; + } + return FT_OK; +} + +static enum ft_result +sint_modulo(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr) +{ + if (b->value.sinteger == 0) { + *err_ptr = ws_strdup_printf("sint_modulo: division by zero"); + return FT_ERROR; + } + + if (!psnip_safe_int32_mod(&dst->value.sinteger, a->value.sinteger, b->value.sinteger)) { + *err_ptr = ws_strdup_printf("sint_modulo: overflow"); + return FT_ERROR; + } + return FT_OK; +} + +static enum ft_result +uint_add(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr) +{ + if (!psnip_safe_uint32_add(&dst->value.uinteger, a->value.uinteger, b->value.uinteger)) { + *err_ptr = ws_strdup_printf("uint_add: overflow"); + return FT_ERROR; + } + return FT_OK; +} + +static enum ft_result +uint_subtract(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr) +{ + if (b->value.uinteger > a->value.uinteger) { + /* Uses signed arithmetic. */ + if (a->value.uinteger > INT32_MAX || + b->value.uinteger > INT32_MAX) { + *err_ptr = ws_strdup_printf("uint_subtract: signed overflow"); + return FT_ERROR; + } + FTYPE_LOOKUP(FT_INT32, dst->ftype); + return _sint_subtract(&dst->value.sinteger, (int32_t)a->value.uinteger, (int32_t)b->value.uinteger, err_ptr); + } + + if (!psnip_safe_uint32_sub(&dst->value.uinteger, a->value.uinteger, b->value.uinteger)) { + *err_ptr = ws_strdup_printf("uint_subtract: overflow"); + return FT_ERROR; + } + return FT_OK; +} + +static enum ft_result +uint_multiply(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr) +{ + if (!psnip_safe_uint32_mul(&dst->value.uinteger, a->value.uinteger, b->value.uinteger)) { + *err_ptr = ws_strdup_printf("uint_multiply: overflow"); + return FT_ERROR; + } + return FT_OK; +} + +static enum ft_result +uint_divide(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr) +{ + if (b->value.uinteger == 0) { + *err_ptr = ws_strdup_printf("uint_divide: division by zero"); + return FT_ERROR; + } + + if (!psnip_safe_uint32_div(&dst->value.uinteger, a->value.uinteger, b->value.uinteger)) { + *err_ptr = ws_strdup_printf("uint_divide: overflow"); + return FT_ERROR; + } + return FT_OK; +} + +static enum ft_result +uint_modulo(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr) +{ + if (b->value.uinteger == 0) { + *err_ptr = ws_strdup_printf("uint_modulo: division by zero"); + return FT_ERROR; + } + + if (!psnip_safe_uint32_mod(&dst->value.uinteger, a->value.uinteger, b->value.uinteger)) { + *err_ptr = ws_strdup_printf("uint_modulo: overflow"); + return FT_ERROR; + } + return FT_OK; +} + +static enum ft_result +sint64_add(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr) +{ + if (!psnip_safe_int64_add(&dst->value.sinteger64, a->value.sinteger64, b->value.sinteger64)) { + *err_ptr = ws_strdup_printf("sint64_add: overflow"); + return FT_ERROR; + } + return FT_OK; +} + +static enum ft_result +_sint64_subtract(int64_t *sint_dst, int64_t sint_a, int64_t sint_b, char **err_ptr) +{ + if (!psnip_safe_int64_sub(sint_dst, sint_a, sint_b)) { + *err_ptr = ws_strdup_printf("sint64_subtract: overflow"); + return FT_ERROR; + } + return FT_OK; +} + +static enum ft_result +sint64_subtract(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr) +{ + return _sint64_subtract(&dst->value.sinteger64, a->value.sinteger64, b->value.sinteger64, err_ptr); +} + +static enum ft_result +sint64_multiply(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr) +{ + if (!psnip_safe_int64_mul(&dst->value.sinteger64, a->value.sinteger64, b->value.sinteger64)) { + *err_ptr = ws_strdup_printf("sint64_multiply: overflow"); + return FT_ERROR; + } + return FT_OK; +} + +static enum ft_result +sint64_divide(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr) +{ + if (b->value.sinteger64 == 0) { + *err_ptr = ws_strdup_printf("sint64_divide: division by zero"); + return FT_ERROR; + } + + if (!psnip_safe_int64_div(&dst->value.sinteger64, a->value.sinteger64, b->value.sinteger64)) { + *err_ptr = ws_strdup_printf("sint64_divide: overflow"); + return FT_ERROR; + } + return FT_OK; +} + +static enum ft_result +sint64_modulo(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr) +{ + if (b->value.sinteger64 == 0) { + *err_ptr = ws_strdup_printf("sint64_modulo: division by zero"); + return FT_ERROR; + } + + if (!psnip_safe_int64_mod(&dst->value.sinteger64, a->value.sinteger64, b->value.sinteger64)) { + *err_ptr = ws_strdup_printf("sint64_modulo: overflow"); + return FT_ERROR; + } + return FT_OK; +} + +static enum ft_result +uint64_add(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr) +{ + if (!psnip_safe_uint64_add(&dst->value.uinteger64, a->value.uinteger64, b->value.uinteger64)) { + *err_ptr = ws_strdup_printf("uint64_add: overflow"); + return FT_ERROR; + } + return FT_OK; +} + +static enum ft_result +uint64_subtract(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr) +{ + if (b->value.uinteger64 > a->value.uinteger64) { + /* Uses signed arithmetic. */ + if (a->value.uinteger64 > INT64_MAX || + b->value.uinteger64 > INT64_MAX) { + *err_ptr = ws_strdup_printf("uint64_subtract: signed overflow"); + return FT_ERROR; + } + FTYPE_LOOKUP(FT_INT64, dst->ftype); + return _sint64_subtract(&dst->value.sinteger64, (int64_t)a->value.uinteger64, (int64_t)b->value.uinteger64, err_ptr); + } + + if (!psnip_safe_uint64_sub(&dst->value.uinteger64, a->value.uinteger64, b->value.uinteger64)) { + *err_ptr = ws_strdup_printf("uint64_subtract: overflow"); + return FT_ERROR; + } + return FT_OK; +} + +static enum ft_result +uint64_multiply(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr) +{ + if (!psnip_safe_uint64_mul(&dst->value.uinteger64, a->value.uinteger64, b->value.uinteger64)) { + *err_ptr = ws_strdup_printf("uint64_multiply: overflow"); + return FT_ERROR; + } + return FT_OK; +} + +static enum ft_result +uint64_divide(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr) +{ + if (b->value.uinteger64 == 0) { + *err_ptr = ws_strdup_printf("uint64_divide: division by zero"); + return FT_ERROR; + } + + if (!psnip_safe_uint64_div(&dst->value.uinteger64, a->value.uinteger64, b->value.uinteger64)) { + *err_ptr = ws_strdup_printf("uint64_divide: overflow"); + return FT_ERROR; + } + return FT_OK; +} + +static enum ft_result +uint64_modulo(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr) +{ + if (b->value.uinteger64 == 0) { + *err_ptr = ws_strdup_printf("uint64_modulo: division by zero"); + return FT_ERROR; + } + + if (!psnip_safe_uint64_mod(&dst->value.uinteger64, a->value.uinteger64, b->value.uinteger64)) { + *err_ptr = ws_strdup_printf("uint64_modulo: overflow"); + return FT_ERROR; + } + return FT_OK; +} + +static enum ft_result uint_val_to_uinteger64(const fvalue_t *src, uint64_t *dst) +{ + *dst = src->value.uinteger; + return FT_OK; +} + +static enum ft_result uint_val_to_sinteger64(const fvalue_t *src, int64_t *dst) +{ + *dst = (int64_t)src->value.uinteger; + return FT_OK; +} + +static enum ft_result sint_val_to_uinteger64(const fvalue_t *src, uint64_t *dst) +{ + if (src->value.sinteger < 0) + return FT_OVERFLOW; + + *dst = (uint64_t)src->value.sinteger; + return FT_OK; +} + +static enum ft_result sint_val_to_sinteger64(const fvalue_t *src, int64_t *dst) +{ + *dst = src->value.sinteger; + return FT_OK; +} + +static enum ft_result uint64_val_to_uinteger64(const fvalue_t *src, uint64_t *dst) +{ + *dst = src->value.uinteger64; + return FT_OK; +} + +static enum ft_result uint64_val_to_sinteger64(const fvalue_t *src, int64_t *dst) +{ + if (src->value.uinteger64 > INT64_MAX) + return FT_OVERFLOW; + + *dst = (int64_t)src->value.uinteger64; + return FT_OK; +} + +static enum ft_result sint64_val_to_uinteger64(const fvalue_t *src, uint64_t *dst) +{ + if (src->value.sinteger64 < 0) + return FT_OVERFLOW; + + *dst = (uint64_t)src->value.sinteger64; + return FT_OK; +} + +static enum ft_result sint64_val_to_sinteger64(const fvalue_t *src, int64_t *dst) +{ + *dst = src->value.sinteger64; + return FT_OK; +} + +/* BOOLEAN-specific */ + +static bool +boolean_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg) +{ + if (g_ascii_strcasecmp(s, "true") == 0) { + fv->value.uinteger64 = 1; + return true; + } + if (g_ascii_strcasecmp(s, "false") == 0) { + fv->value.uinteger64 = 0; + return true; + } + + char *endptr; + errno = 0; + int64_t val = g_ascii_strtoll(s, &endptr, 0); + if (errno == 0 && *endptr == '\0') { + /* This is a valid number. */ + fv->value.uinteger64 = (val != 0); + return true; + } + if (err_msg) + *err_msg = ws_strdup_printf("\"%s\" is not a valid boolean", s); + return false; +} + +static bool +boolean_from_string(fvalue_t *fv, const char *s, size_t len, char **err_msg _U_) +{ + if (g_ascii_strncasecmp(s, "true", len) == 0) { + fv->value.uinteger64 = 1; + return true; + } + if (g_ascii_strncasecmp(s, "false", len) == 0) { + fv->value.uinteger64 = 0; + return true; + } + + if (err_msg) + *err_msg = ws_strdup_printf("expected \"True\" or \"False\", not \"%s\"", s); + return false; +} + +static char * +boolean_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype, int field_display _U_) +{ + bool val = fv->value.uinteger64; + const char *str = NULL; + + switch (rtype) { + case FTREPR_DFILTER: + case FTREPR_DISPLAY: + str = val ? "True" : "False"; + break; + case FTREPR_JSON: + str = val ? "1" : "0"; + break; + } + + return wmem_strdup(scope, str); +} + +/* False is less than True (arbitrary): + * A B cmp(A, B) + * T T 0 + * F F 0 + * F T -1 + * T F 1 + */ +static enum ft_result +boolean_cmp_order(const fvalue_t *a, const fvalue_t *b, int *cmp) +{ + uint64_t val_a, val_b; + enum ft_result res; + + val_a = a->value.uinteger64; + res = fvalue_to_uinteger64(b, &val_b); + if (res != FT_OK) + return res; + + if (val_a) { + if (val_b) { + *cmp = 0; + } + else { + *cmp = 1; + } + } + else if (val_b) { + *cmp = -1; + } + else { + *cmp = 0; + } + + return FT_OK; +} + +static unsigned +boolean_hash(const fvalue_t *fv) +{ + int val; + + if (fv->value.uinteger64) + val = 1; + else + val = 0; + return g_int_hash(&val); +} + +/* EUI64-specific */ +static bool +eui64_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg) +{ + GByteArray *bytes; + bool res; + union { + uint64_t value; + uint8_t bytes[8]; + } eui64; + + /* + * Don't request an error message if uint64_from_literal fails; + * if it does, we'll try parsing it as a sequence of bytes, and + * report an error if *that* fails. + */ + if (uint64_from_literal(fv, s, true, NULL)) { + return true; + } + + bytes = g_byte_array_new(); + res = hex_str_to_bytes(s, bytes, true); + if (!res || bytes->len != 8) { + if (err_msg != NULL) + *err_msg = ws_strdup_printf("\"%s\" is not a valid EUI-64 address.", s); + g_byte_array_free(bytes, true); + return false; + } + + memcpy(eui64.bytes, bytes->data, 8); + g_byte_array_free(bytes, true); + fv->value.uinteger64 = GUINT64_FROM_BE(eui64.value); + return true; +} + +static char * +eui64_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_) +{ + union { + uint64_t value; + uint8_t bytes[8]; + } eui64; + + /* Copy and convert the address from host to network byte order. */ + eui64.value = GUINT64_TO_BE(fv->value.uinteger64); + + return wmem_strdup_printf(scope, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", + eui64.bytes[0], eui64.bytes[1], eui64.bytes[2], eui64.bytes[3], + eui64.bytes[4], eui64.bytes[5], eui64.bytes[6], eui64.bytes[7]); +} + +void +ftype_register_integers(void) +{ + static ftype_t char_type = { + FT_CHAR, /* ftype */ + "FT_CHAR", /* name */ + "Character (8 bits)", /* pretty name */ + 1, /* wire_size */ + int_fvalue_new, /* new_value */ + NULL, /* copy_value */ + NULL, /* free_value */ + uint8_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + uint_from_charconst, /* val_from_charconst */ + char_to_repr, /* val_to_string_repr */ + + uint_val_to_uinteger64, /* val_to_uinteger64 */ + uint_val_to_sinteger64, /* val_to_sinteger64 */ + + { .set_value_uinteger = set_uinteger }, /* union set_value */ + { .get_value_uinteger = get_uinteger }, /* union get_value */ + + uint_cmp_order, /* cmp_order */ + NULL, /* cmp_contains */ + NULL, /* cmp_matches */ + + uint_hash, /* hash */ + uint_is_zero, /* is_zero */ + uint_is_negative, /* is_negative */ + NULL, /* len */ + NULL, /* slice */ + uint_bitwise_and, /* bitwise_and */ + uint_unary_minus, /* unary_minus */ + uint_add, /* add */ + uint_subtract, /* subtract */ + uint_multiply, /* multiply */ + uint_divide, /* divide */ + uint_modulo, /* modulo */ + }; + static ftype_t uint8_type = { + FT_UINT8, /* ftype */ + "FT_UINT8", /* name */ + "Unsigned integer (8 bits)", /* pretty name */ + 1, /* wire_size */ + int_fvalue_new, /* new_value */ + NULL, /* copy_value */ + NULL, /* free_value */ + uint8_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + uint_from_charconst, /* val_from_charconst */ + uinteger_to_repr, /* val_to_string_repr */ + + uint_val_to_uinteger64, /* val_to_uinteger64 */ + uint_val_to_sinteger64, /* val_to_sinteger64 */ + + { .set_value_uinteger = set_uinteger }, /* union set_value */ + { .get_value_uinteger = get_uinteger }, /* union get_value */ + + uint_cmp_order, /* cmp_order */ + NULL, /* cmp_contains */ + NULL, /* cmp_matches */ + + uint_hash, /* hash */ + uint_is_zero, /* is_zero */ + uint_is_negative, /* is_negative */ + NULL, /* len */ + NULL, /* slice */ + uint_bitwise_and, /* bitwise_and */ + uint_unary_minus, /* unary_minus */ + uint_add, /* add */ + uint_subtract, /* subtract */ + uint_multiply, /* multiply */ + uint_divide, /* divide */ + uint_modulo, /* modulo */ + }; + static ftype_t uint16_type = { + FT_UINT16, /* ftype */ + "FT_UINT16", /* name */ + "Unsigned integer (16 bits)", /* pretty_name */ + 2, /* wire_size */ + int_fvalue_new, /* new_value */ + NULL, /* copy_value */ + NULL, /* free_value */ + uint16_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + uint_from_charconst, /* val_from_charconst */ + uinteger_to_repr, /* val_to_string_repr */ + + uint_val_to_uinteger64, /* val_to_uinteger64 */ + uint_val_to_sinteger64, /* val_to_sinteger64 */ + + { .set_value_uinteger = set_uinteger }, /* union set_value */ + { .get_value_uinteger = get_uinteger }, /* union get_value */ + + uint_cmp_order, /* cmp_order */ + NULL, /* cmp_contains */ + NULL, /* cmp_matches */ + + uint_hash, /* hash */ + uint_is_zero, /* is_zero */ + uint_is_negative, /* is_negative */ + NULL, /* len */ + NULL, /* slice */ + uint_bitwise_and, /* bitwise_and */ + uint_unary_minus, /* unary_minus */ + uint_add, /* add */ + uint_subtract, /* subtract */ + uint_multiply, /* multiply */ + uint_divide, /* divide */ + uint_modulo, /* modulo */ + }; + static ftype_t uint24_type = { + FT_UINT24, /* ftype */ + "FT_UINT24", /* name */ + "Unsigned integer (24 bits)", /* pretty_name */ + 3, /* wire_size */ + int_fvalue_new, /* new_value */ + NULL, /* copy_value */ + NULL, /* free_value */ + uint24_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + uint_from_charconst, /* val_from_charconst */ + uinteger_to_repr, /* val_to_string_repr */ + + uint_val_to_uinteger64, /* val_to_uinteger64 */ + uint_val_to_sinteger64, /* val_to_sinteger64 */ + + { .set_value_uinteger = set_uinteger }, /* union set_value */ + { .get_value_uinteger = get_uinteger }, /* union get_value */ + + uint_cmp_order, /* cmp_order */ + NULL, /* cmp_contains */ + NULL, /* cmp_matches */ + + uint_hash, /* hash */ + uint_is_zero, /* is_zero */ + uint_is_negative, /* is_negative */ + NULL, /* len */ + NULL, /* slice */ + uint_bitwise_and, /* bitwise_and */ + uint_unary_minus, /* unary_minus */ + uint_add, /* add */ + uint_subtract, /* subtract */ + uint_multiply, /* multiply */ + uint_divide, /* divide */ + uint_modulo, /* modulo */ + }; + static ftype_t uint32_type = { + FT_UINT32, /* ftype */ + "FT_UINT32", /* name */ + "Unsigned integer (32 bits)", /* pretty_name */ + 4, /* wire_size */ + int_fvalue_new, /* new_value */ + NULL, /* copy_value */ + NULL, /* free_value */ + uint32_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + uint_from_charconst, /* val_from_charconst */ + uinteger_to_repr, /* val_to_string_repr */ + + uint_val_to_uinteger64, /* val_to_uinteger64 */ + uint_val_to_sinteger64, /* val_to_sinteger64 */ + + { .set_value_uinteger = set_uinteger }, /* union set_value */ + { .get_value_uinteger = get_uinteger }, /* union get_value */ + + uint_cmp_order, /* cmp_order */ + NULL, /* cmp_contains */ + NULL, /* cmp_matches */ + + uint_hash, /* hash */ + uint_is_zero, /* is_zero */ + uint_is_negative, /* is_negative */ + NULL, /* len */ + NULL, /* slice */ + uint_bitwise_and, /* bitwise_and */ + uint_unary_minus, /* unary_minus */ + uint_add, /* add */ + uint_subtract, /* subtract */ + uint_multiply, /* multiply */ + uint_divide, /* divide */ + uint_modulo, /* modulo */ + }; + static ftype_t uint40_type = { + FT_UINT40, /* ftype */ + "FT_UINT40", /* name */ + "Unsigned integer (40 bits)", /* pretty_name */ + 5, /* wire_size */ + int64_fvalue_new, /* new_value */ + NULL, /* copy_value */ + NULL, /* free_value */ + uint40_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + uint64_from_charconst, /* val_from_charconst */ + uinteger64_to_repr, /* val_to_string_repr */ + + uint64_val_to_uinteger64, /* val_to_uinteger64 */ + uint64_val_to_sinteger64, /* val_to_sinteger64 */ + + { .set_value_uinteger64 = set_uinteger64 }, /* union set_value */ + { .get_value_uinteger64 = get_uinteger64 }, /* union get_value */ + + uint64_cmp_order, /* cmp_order */ + NULL, /* cmp_contains */ + NULL, /* cmp_matches */ + + uint64_hash, /* hash */ + uint64_is_zero, /* is_zero */ + uint64_is_negative, /* is_negative */ + NULL, /* len */ + NULL, /* slice */ + uint64_bitwise_and, /* bitwise_and */ + uint64_unary_minus, /* unary_minus */ + uint64_add, /* add */ + uint64_subtract, /* subtract */ + uint64_multiply, /* multiply */ + uint64_divide, /* divide */ + uint64_modulo, /* modulo */ + }; + static ftype_t uint48_type = { + FT_UINT48, /* ftype */ + "FT_UINT48", /* name */ + "Unsigned integer (48 bits)", /* pretty_name */ + 6, /* wire_size */ + int64_fvalue_new, /* new_value */ + NULL, /* copy_value */ + NULL, /* free_value */ + uint48_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + uint64_from_charconst, /* val_from_charconst */ + uinteger64_to_repr, /* val_to_string_repr */ + + uint64_val_to_uinteger64, /* val_to_uinteger64 */ + uint64_val_to_sinteger64, /* val_to_sinteger64 */ + + { .set_value_uinteger64 = set_uinteger64 }, /* union set_value */ + { .get_value_uinteger64 = get_uinteger64 }, /* union get_value */ + + uint64_cmp_order, /* cmp_order */ + NULL, /* cmp_contains */ + NULL, /* cmp_matches */ + + uint64_hash, /* hash */ + uint64_is_zero, /* is_zero */ + uint64_is_negative, /* is_negative */ + NULL, /* len */ + NULL, /* slice */ + uint64_bitwise_and, /* bitwise_and */ + uint64_unary_minus, /* unary_minus */ + uint64_add, /* add */ + uint64_subtract, /* subtract */ + uint64_multiply, /* multiply */ + uint64_divide, /* divide */ + uint64_modulo, /* modulo */ + }; + static ftype_t uint56_type = { + FT_UINT56, /* ftype */ + "FT_UINT56", /* name */ + "Unsigned integer (56 bits)", /* pretty_name */ + 7, /* wire_size */ + int64_fvalue_new, /* new_value */ + NULL, /* copy_value */ + NULL, /* free_value */ + uint56_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + uint64_from_charconst, /* val_from_charconst */ + uinteger64_to_repr, /* val_to_string_repr */ + + uint64_val_to_uinteger64, /* val_to_uinteger64 */ + uint64_val_to_sinteger64, /* val_to_sinteger64 */ + + { .set_value_uinteger64 = set_uinteger64 }, /* union set_value */ + { .get_value_uinteger64 = get_uinteger64 }, /* union get_value */ + + uint64_cmp_order, /* cmp_order */ + NULL, /* cmp_contains */ + NULL, /* cmp_matches */ + + uint64_hash, /* hash */ + uint64_is_zero, /* is_zero */ + uint64_is_negative, /* is_negative */ + NULL, /* len */ + NULL, /* slice */ + uint64_bitwise_and, /* bitwise_and */ + uint64_unary_minus, /* unary_minus */ + uint64_add, /* add */ + uint64_subtract, /* subtract */ + uint64_multiply, /* multiply */ + uint64_divide, /* divide */ + uint64_modulo, /* modulo */ + }; + static ftype_t uint64_type = { + FT_UINT64, /* ftype */ + "FT_UINT64", /* name */ + "Unsigned integer (64bits)", /* pretty_name */ + 8, /* wire_size */ + int64_fvalue_new, /* new_value */ + NULL, /* copy_value */ + NULL, /* free_value */ + uint64_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + uint64_from_charconst, /* val_from_charconst */ + uinteger64_to_repr, /* val_to_string_repr */ + + uint64_val_to_uinteger64, /* val_to_uinteger64 */ + uint64_val_to_sinteger64, /* val_to_sinteger64 */ + + { .set_value_uinteger64 = set_uinteger64 }, /* union set_value */ + { .get_value_uinteger64 = get_uinteger64 }, /* union get_value */ + + uint64_cmp_order, /* cmp_order */ + NULL, /* cmp_contains */ + NULL, /* cmp_matches */ + + uint64_hash, /* hash */ + uint64_is_zero, /* is_zero */ + uint64_is_negative, /* is_negative */ + NULL, /* len */ + NULL, /* slice */ + uint64_bitwise_and, /* bitwise_and */ + uint64_unary_minus, /* unary_minus */ + uint64_add, /* add */ + uint64_subtract, /* subtract */ + uint64_multiply, /* multiply */ + uint64_divide, /* divide */ + uint64_modulo, /* modulo */ + }; + static ftype_t int8_type = { + FT_INT8, /* ftype */ + "FT_INT8", /* name */ + "Signed integer (8bits)", /* pretty_name */ + 1, /* wire_size */ + int_fvalue_new, /* new_value */ + NULL, /* copy_value */ + NULL, /* free_value */ + sint8_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + sint_from_charconst, /* val_from_charconst */ + integer_to_repr, /* val_to_string_repr */ + + sint_val_to_uinteger64, /* val_to_uinteger64 */ + sint_val_to_sinteger64, /* val_to_sinteger64 */ + + { .set_value_sinteger = set_sinteger }, /* union set_value */ + { .get_value_sinteger = get_sinteger }, /* union get_value */ + + sint_cmp_order, /* cmp_order */ + NULL, /* cmp_contains */ + NULL, /* cmp_matches */ + + sint_hash, /* hash */ + sint_is_zero, /* is_zero */ + sint_is_negative, /* is_negative */ + NULL, /* len */ + NULL, /* slice */ + sint_bitwise_and, /* bitwise_and */ + sint_unary_minus, /* unary_minus */ + sint_add, /* add */ + sint_subtract, /* subtract */ + sint_multiply, /* multiply */ + sint_divide, /* divide */ + sint_modulo, /* modulo */ + }; + static ftype_t int16_type = { + FT_INT16, /* ftype */ + "FT_INT16", /* name */ + "Signed integer (16 bits)", /* pretty_name */ + 2, /* wire_size */ + int_fvalue_new, /* new_value */ + NULL, /* copy_value */ + NULL, /* free_value */ + sint16_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + sint_from_charconst, /* val_from_charconst */ + integer_to_repr, /* val_to_string_repr */ + + sint_val_to_uinteger64, /* val_to_uinteger64 */ + sint_val_to_sinteger64, /* val_to_sinteger64 */ + + { .set_value_sinteger = set_sinteger }, /* union set_value */ + { .get_value_sinteger = get_sinteger }, /* union get_value */ + + sint_cmp_order, /* cmp_order */ + NULL, /* cmp_contains */ + NULL, /* cmp_matches */ + + sint_hash, /* hash */ + sint_is_zero, /* is_zero */ + sint_is_negative, /* is_negative */ + NULL, /* len */ + NULL, /* slice */ + sint_bitwise_and, /* bitwise_and */ + sint_unary_minus, /* unary_minus */ + sint_add, /* add */ + sint_subtract, /* subtract */ + sint_multiply, /* multiply */ + sint_divide, /* divide */ + sint_modulo, /* modulo */ + }; + static ftype_t int24_type = { + FT_INT24, /* ftype */ + "FT_INT24", /* name */ + "Signed integer (24 bits)", /* pretty_name */ + 3, /* wire_size */ + int_fvalue_new, /* new_value */ + NULL, /* copy_value */ + NULL, /* free_value */ + sint24_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + sint_from_charconst, /* val_from_charconst */ + integer_to_repr, /* val_to_string_repr */ + + sint_val_to_uinteger64, /* val_to_uinteger64 */ + sint_val_to_sinteger64, /* val_to_sinteger64 */ + + { .set_value_sinteger = set_sinteger }, /* union set_value */ + { .get_value_sinteger = get_sinteger }, /* union get_value */ + + sint_cmp_order, /* cmp_order */ + NULL, /* cmp_contains */ + NULL, /* cmp_matches */ + + sint_hash, /* hash */ + sint_is_zero, /* is_zero */ + sint_is_negative, /* is_negative */ + NULL, /* len */ + NULL, /* slice */ + sint_bitwise_and, /* bitwise_and */ + sint_unary_minus, /* unary_minus */ + sint_add, /* add */ + sint_subtract, /* subtract */ + sint_multiply, /* multiply */ + sint_divide, /* divide */ + sint_modulo, /* modulo */ + }; + static ftype_t int32_type = { + FT_INT32, /* ftype */ + "FT_INT32", /* name */ + "Signed integer (32 bits)", /* pretty_name */ + 4, /* wire_size */ + int_fvalue_new, /* new_value */ + NULL, /* copy_value */ + NULL, /* free_value */ + sint32_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + sint_from_charconst, /* val_from_charconst */ + integer_to_repr, /* val_to_string_repr */ + + sint_val_to_uinteger64, /* val_to_uinteger64 */ + sint_val_to_sinteger64, /* val_to_sinteger64 */ + + { .set_value_sinteger = set_sinteger }, /* union set_value */ + { .get_value_sinteger = get_sinteger }, /* union get_value */ + + sint_cmp_order, /* cmp_order */ + NULL, /* cmp_contains */ + NULL, /* cmp_matches */ + + sint_hash, /* hash */ + sint_is_zero, /* is_zero */ + sint_is_negative, /* is_negative */ + NULL, /* len */ + NULL, /* slice */ + sint_bitwise_and, /* bitwise_and */ + sint_unary_minus, /* unary_minus */ + sint_add, /* add */ + sint_subtract, /* subtract */ + sint_multiply, /* multiply */ + sint_divide, /* divide */ + sint_modulo, /* modulo */ + }; + static ftype_t int40_type = { + FT_INT40, /* ftype */ + "FT_INT40", /* name */ + "Signed integer (40 bits)", /* pretty_name */ + 5, /* wire_size */ + int64_fvalue_new, /* new_value */ + NULL, /* copy_value */ + NULL, /* free_value */ + sint40_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + sint64_from_charconst, /* val_from_charconst */ + integer64_to_repr, /* val_to_string_repr */ + + sint64_val_to_uinteger64, /* val_to_uinteger64 */ + sint64_val_to_sinteger64, /* val_to_sinteger64 */ + + { .set_value_sinteger64 = set_sinteger64 }, /* union set_value */ + { .get_value_sinteger64 = get_sinteger64 }, /* union get_value */ + + sint64_cmp_order, /* cmp_order */ + NULL, /* cmp_contains */ + NULL, /* cmp_matches */ + + sint64_hash, /* hash */ + sint64_is_zero, /* is_zero */ + sint64_is_negative, /* is_negative */ + NULL, /* len */ + NULL, /* slice */ + sint64_bitwise_and, /* bitwise_and */ + sint64_unary_minus, /* unary_minus */ + sint64_add, /* add */ + sint64_subtract, /* subtract */ + sint64_multiply, /* multiply */ + sint64_divide, /* divide */ + sint64_modulo, /* modulo */ + }; + static ftype_t int48_type = { + FT_INT48, /* ftype */ + "FT_INT48", /* name */ + "Signed integer (48 bits)", /* pretty_name */ + 6, /* wire_size */ + int64_fvalue_new, /* new_value */ + NULL, /* copy_value */ + NULL, /* free_value */ + sint48_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + sint64_from_charconst, /* val_from_charconst */ + integer64_to_repr, /* val_to_string_repr */ + + sint64_val_to_uinteger64, /* val_to_uinteger64 */ + sint64_val_to_sinteger64, /* val_to_sinteger64 */ + + { .set_value_sinteger64 = set_sinteger64 }, /* union set_value */ + { .get_value_sinteger64 = get_sinteger64 }, /* union get_value */ + + sint64_cmp_order, /* cmp_order */ + NULL, /* cmp_contains */ + NULL, /* cmp_matches */ + + sint64_hash, /* hash */ + sint64_is_zero, /* is_zero */ + sint64_is_negative, /* is_negative */ + NULL, /* len */ + NULL, /* slice */ + sint64_bitwise_and, /* bitwise_and */ + sint64_unary_minus, /* unary_minus */ + sint64_add, /* add */ + sint64_subtract, /* subtract */ + sint64_multiply, /* multiply */ + sint64_divide, /* divide */ + sint64_modulo, /* modulo */ + }; + static ftype_t int56_type = { + FT_INT56, /* ftype */ + "FT_INT56", /* name */ + "Signed integer (56 bits)", /* pretty_name */ + 7, /* wire_size */ + int64_fvalue_new, /* new_value */ + NULL, /* copy_value */ + NULL, /* free_value */ + sint56_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + sint64_from_charconst, /* val_from_charconst */ + integer64_to_repr, /* val_to_string_repr */ + + sint64_val_to_uinteger64, /* val_to_uinteger64 */ + sint64_val_to_sinteger64, /* val_to_sinteger64 */ + + { .set_value_sinteger64 = set_sinteger64 }, /* union set_value */ + { .get_value_sinteger64 = get_sinteger64 }, /* union get_value */ + + sint64_cmp_order, /* cmp_order */ + NULL, /* cmp_contains */ + NULL, /* cmp_matches */ + + sint64_hash, /* hash */ + sint64_is_zero, /* is_zero */ + sint64_is_negative, /* is_negative */ + NULL, /* len */ + NULL, /* slice */ + sint64_bitwise_and, /* bitwise_and */ + sint64_unary_minus, /* unary_minus */ + sint64_add, /* add */ + sint64_subtract, /* subtract */ + sint64_multiply, /* multiply */ + sint64_divide, /* divide */ + sint64_modulo, /* modulo */ + }; + static ftype_t int64_type = { + FT_INT64, /* ftype */ + "FT_INT64", /* name */ + "Signed integer (64 bits)", /* pretty_name */ + 8, /* wire_size */ + int64_fvalue_new, /* new_value */ + NULL, /* copy_value */ + NULL, /* free_value */ + sint64_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + sint64_from_charconst, /* val_from_charconst */ + integer64_to_repr, /* val_to_string_repr */ + + sint64_val_to_uinteger64, /* val_to_uinteger64 */ + sint64_val_to_sinteger64, /* val_to_sinteger64 */ + + { .set_value_sinteger64 = set_sinteger64 }, /* union set_value */ + { .get_value_sinteger64 = get_sinteger64 }, /* union get_value */ + + sint64_cmp_order, /* cmp_order */ + NULL, /* cmp_contains */ + NULL, /* cmp_matches */ + + sint64_hash, /* hash */ + sint64_is_zero, /* is_zero */ + sint64_is_negative, /* is_negative */ + NULL, /* len */ + NULL, /* slice */ + sint64_bitwise_and, /* bitwise_and */ + sint64_unary_minus, /* unary_minus */ + sint64_add, /* add */ + sint64_subtract, /* subtract */ + sint64_multiply, /* multiply */ + sint64_divide, /* divide */ + sint64_modulo, /* modulo */ + }; + static ftype_t boolean_type = { + FT_BOOLEAN, /* ftype */ + "FT_BOOLEAN", /* name */ + "Boolean", /* pretty_name */ + 0, /* wire_size */ + int_fvalue_new, /* new_value */ + NULL, /* copy_value */ + NULL, /* free_value */ + boolean_from_literal, /* val_from_literal */ + boolean_from_string, /* val_from_string */ + uint64_from_charconst, /* val_from_charconst */ + boolean_to_repr, /* val_to_string_repr */ + + uint64_val_to_uinteger64, /* val_to_uinteger64 */ + uint64_val_to_sinteger64, /* val_to_sinteger64 */ + + { .set_value_uinteger64 = set_uinteger64 }, /* union set_value */ + { .get_value_uinteger64 = get_uinteger64 }, /* union get_value */ + + boolean_cmp_order, /* cmp_order */ + NULL, /* cmp_contains */ + NULL, /* cmp_matches */ + + boolean_hash, /* hash */ + uint64_is_zero, /* is_zero */ + uint64_is_negative, /* is_negative */ + NULL, /* len */ + NULL, /* slice */ + NULL, /* bitwise_and */ + NULL, /* unary_minus */ + NULL, /* add */ + NULL, /* subtract */ + NULL, /* multiply */ + NULL, /* divide */ + NULL, /* modulo */ + }; + + static ftype_t ipxnet_type = { + FT_IPXNET, /* ftype */ + "FT_IPXNET", /* name */ + "IPX network number", /* pretty_name */ + 4, /* wire_size */ + int_fvalue_new, /* new_value */ + NULL, /* copy_value */ + NULL, /* free_value */ + ipxnet_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + NULL, /* val_from_charconst */ + ipxnet_to_repr, /* val_to_string_repr */ + + uint_val_to_uinteger64, /* val_to_uinteger64 */ + uint_val_to_sinteger64, /* val_to_sinteger64 */ + + { .set_value_uinteger = set_uinteger }, /* union set_value */ + { .get_value_uinteger = get_uinteger }, /* union get_value */ + + uint_cmp_order, /* cmp_order */ + NULL, /* cmp_contains */ + NULL, /* cmp_matches */ + + uint_hash, /* hash */ + uint_is_zero, /* is_zero */ + uint_is_negative, /* is_negative */ + NULL, /* len */ + NULL, /* slice */ + uint_bitwise_and, /* bitwise_and */ + uint_unary_minus, /* unary_minus */ + NULL, /* add */ + NULL, /* subtract */ + NULL, /* multiply */ + NULL, /* divide */ + NULL, /* modulo */ + }; + + static ftype_t framenum_type = { + FT_FRAMENUM, /* ftype */ + "FT_FRAMENUM", /* name */ + "Frame number", /* pretty_name */ + 4, /* wire_size */ + int_fvalue_new, /* new_value */ + NULL, /* copy_value */ + NULL, /* free_value */ + uint32_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + uint_from_charconst, /* val_from_charconst */ + uinteger_to_repr, /* val_to_string_repr */ + + uint_val_to_uinteger64, /* val_to_uinteger64 */ + uint_val_to_sinteger64, /* val_to_sinteger64 */ + + { .set_value_uinteger = set_uinteger }, /* union set_value */ + { .get_value_uinteger = get_uinteger }, /* union get_value */ + + uint_cmp_order, /* cmp_order */ + NULL, /* cmp_contains */ + NULL, /* cmp_matches */ + + uint_hash, /* hash */ + uint_is_zero, /* is_zero */ + uint_is_negative, /* is_negative */ + NULL, /* len */ + NULL, /* slice */ + uint_bitwise_and, /* bitwise_and */ + uint_unary_minus, /* unary_minus */ + uint_add, /* add */ + uint_subtract, /* subtract */ + uint_multiply, /* multiply */ + uint_divide, /* divide */ + uint_modulo, /* modulo */ + }; + + static ftype_t eui64_type = { + FT_EUI64, /* ftype */ + "FT_EUI64", /* name */ + "EUI64 address", /* pretty_name */ + FT_EUI64_LEN, /* wire_size */ + int64_fvalue_new, /* new_value */ + NULL, /* copy_value */ + NULL, /* free_value */ + eui64_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + NULL, /* val_from_charconst */ + eui64_to_repr, /* val_to_string_repr */ + + uint64_val_to_uinteger64, /* val_to_uinteger64 */ + uint64_val_to_sinteger64, /* val_to_sinteger64 */ + + { .set_value_uinteger64 = set_uinteger64 }, /* union set_value */ + { .get_value_uinteger64 = get_uinteger64 }, /* union get_value */ + + uint64_cmp_order, /* cmp_order */ + NULL, /* cmp_contains */ + NULL, /* cmp_matches */ + + uint64_hash, /* hash */ + uint64_is_zero, /* is_zero */ + uint64_is_negative, /* is_negative */ + NULL, /* len */ + NULL, /* slice */ + uint64_bitwise_and, /* bitwise_and */ + uint64_unary_minus, /* unary_minus */ + uint64_add, /* add */ + uint64_subtract, /* subtract */ + NULL, /* multiply */ + NULL, /* divide */ + NULL, /* modulo */ + }; + + ftype_register(FT_CHAR, &char_type); + ftype_register(FT_UINT8, &uint8_type); + ftype_register(FT_UINT16, &uint16_type); + ftype_register(FT_UINT24, &uint24_type); + ftype_register(FT_UINT32, &uint32_type); + ftype_register(FT_UINT40, &uint40_type); + ftype_register(FT_UINT48, &uint48_type); + ftype_register(FT_UINT56, &uint56_type); + ftype_register(FT_UINT64, &uint64_type); + ftype_register(FT_INT8, &int8_type); + ftype_register(FT_INT16, &int16_type); + ftype_register(FT_INT24, &int24_type); + ftype_register(FT_INT32, &int32_type); + ftype_register(FT_INT40, &int40_type); + ftype_register(FT_INT48, &int48_type); + ftype_register(FT_INT56, &int56_type); + ftype_register(FT_INT64, &int64_type); + ftype_register(FT_BOOLEAN, &boolean_type); + ftype_register(FT_IPXNET, &ipxnet_type); + ftype_register(FT_FRAMENUM, &framenum_type); + ftype_register(FT_EUI64, &eui64_type); +} + +void +ftype_register_pseudofields_integer(int proto) +{ + static int hf_ft_char; + static int hf_ft_uint8; + static int hf_ft_uint16; + static int hf_ft_uint24; + static int hf_ft_uint32; + static int hf_ft_uint40; + static int hf_ft_uint48; + static int hf_ft_uint56; + static int hf_ft_uint64; + static int hf_ft_int8; + static int hf_ft_int16; + static int hf_ft_int24; + static int hf_ft_int32; + static int hf_ft_int40; + static int hf_ft_int48; + static int hf_ft_int56; + static int hf_ft_int64; + static int hf_ft_boolean; + static int hf_ft_ipxnet; + static int hf_ft_framenum; + static int hf_ft_eui64; + + static hf_register_info hf_ftypes[] = { + { &hf_ft_char, + { "FT_CHAR", "_ws.ftypes.char", + FT_CHAR, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_uint8, + { "FT_UINT8", "_ws.ftypes.uint8", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_uint16, + { "FT_UINT16", "_ws.ftypes.uint16", + FT_UINT16, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_uint24, + { "FT_UINT24", "_ws.ftypes.uint24", + FT_UINT24, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_uint32, + { "FT_UINT32", "_ws.ftypes.uint32", + FT_UINT32, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_uint40, + { "FT_UINT40", "_ws.ftypes.uint40", + FT_UINT40, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_uint48, + { "FT_UINT48", "_ws.ftypes.uint48", + FT_UINT48, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_uint56, + { "FT_UINT56", "_ws.ftypes.uint56", + FT_UINT56, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_uint64, + { "FT_UINT64", "_ws.ftypes.uint64", + FT_UINT64, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_int8, + { "FT_INT8", "_ws.ftypes.int8", + FT_INT8, BASE_DEC, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_int16, + { "FT_INT16", "_ws.ftypes.int16", + FT_INT16, BASE_DEC, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_int24, + { "FT_INT24", "_ws.ftypes.int24", + FT_INT24, BASE_DEC, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_int32, + { "FT_INT32", "_ws.ftypes.int32", + FT_INT32, BASE_DEC, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_int40, + { "FT_INT40", "_ws.ftypes.int40", + FT_INT40, BASE_DEC, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_int48, + { "FT_INT48", "_ws.ftypes.int48", + FT_INT48, BASE_DEC, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_int56, + { "FT_INT56", "_ws.ftypes.int56", + FT_INT56, BASE_DEC, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_int64, + { "FT_INT64", "_ws.ftypes.int64", + FT_INT64, BASE_DEC, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_boolean, + { "FT_BOOLEAN", "_ws.ftypes.boolean", + FT_BOOLEAN, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_ipxnet, + { "FT_IPXNET", "_ws.ftypes.ipxnet", + FT_IPXNET, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_framenum, + { "FT_FRAMENUM", "_ws.ftypes.framenum", + FT_FRAMENUM, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_eui64, + { "FT_EUI64", "_ws.ftypes.eui64", + FT_EUI64, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + }; + + proto_register_field_array(proto, hf_ftypes, array_length(hf_ftypes)); +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 8 + * tab-width: 8 + * indent-tabs-mode: t + * End: + * + * vi: set shiftwidth=8 tabstop=8 noexpandtab: + * :indentSize=8:tabSize=8:noTabs=false: + */ diff --git a/epan/ftypes/ftype-ipv4.c b/epan/ftypes/ftype-ipv4.c new file mode 100644 index 0000000..b39788e --- /dev/null +++ b/epan/ftypes/ftype-ipv4.c @@ -0,0 +1,246 @@ +/* + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 2001 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include <string.h> + +#include <ftypes-int.h> +#include <epan/ipv4.h> +#include <epan/addr_and_mask.h> +#include <epan/addr_resolv.h> +#include <wsutil/bits_count_ones.h> + +static void +set_uinteger(fvalue_t *fv, uint32_t value) +{ + fv->value.ipv4.addr = g_ntohl(value); + fv->value.ipv4.nmask = ip_get_subnet_mask(32); +} + +static uint32_t +value_get(fvalue_t *fv) +{ + return g_htonl(fv->value.ipv4.addr); +} + +static bool +val_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg) +{ + uint32_t addr; + unsigned int nmask_bits; + + const char *slash, *net_str; + const char *addr_str; + char *addr_str_to_free = NULL; + fvalue_t *nmask_fvalue; + + /* Look for CIDR: Is there a single slash in the string? */ + slash = strchr(s, '/'); + if (slash) { + /* Make a copy of the string up to but not including the + * slash; that's the address portion. */ + addr_str_to_free = wmem_strndup(NULL, s, slash - s); + addr_str = addr_str_to_free; + } + else { + addr_str = s; + } + + if (!get_host_ipaddr(addr_str, &addr)) { + if (err_msg != NULL) { + *err_msg = ws_strdup_printf("\"%s\" is not a valid hostname or IPv4 address.", + addr_str); + } + if (addr_str_to_free) + wmem_free(NULL, addr_str_to_free); + return false; + } + + if (addr_str_to_free) + wmem_free(NULL, addr_str_to_free); + fv->value.ipv4.addr = g_ntohl(addr); + + /* If CIDR, get netmask bits. */ + if (slash) { + /* Skip past the slash */ + net_str = slash + 1; + + /* XXX - this is inefficient */ + nmask_fvalue = fvalue_from_literal(FT_UINT32, net_str, false, err_msg); + if (!nmask_fvalue) { + return false; + } + nmask_bits = fvalue_get_uinteger(nmask_fvalue); + fvalue_free(nmask_fvalue); + + if (nmask_bits > 32) { + if (err_msg != NULL) { + *err_msg = ws_strdup_printf("Netmask bits in a CIDR IPv4 address should be <= 32, not %u", + nmask_bits); + } + return false; + } + fv->value.ipv4.nmask = ip_get_subnet_mask(nmask_bits); + } + else { + /* Not CIDR; mask covers entire address. */ + fv->value.ipv4.nmask = ip_get_subnet_mask(32); + } + + return true; +} + +static char * +val_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_) +{ + char buf[WS_INET_ADDRSTRLEN]; + char *repr; + + uint32_t ipv4_net_order = g_htonl(fv->value.ipv4.addr); + ip_to_str_buf((uint8_t*)&ipv4_net_order, buf, sizeof(buf)); + + if (fv->value.ipv4.nmask != 0 && fv->value.ipv4.nmask != 0xffffffff) + repr = wmem_strdup_printf(scope, "%s/%d", buf, ws_count_ones(fv->value.ipv4.nmask)); + else + repr = wmem_strdup(scope, buf); + + return repr; +} + + +/* Compares two ipv4_addr_and_masks, taking into account the less restrictive of the + * two netmasks, applying that netmask to both addrs. + * + * So, for example, w.x.y.z/32 eq w.x.y.0/24 is true. + */ + +static enum ft_result +cmp_order(const fvalue_t *fv_a, const fvalue_t *fv_b, int *cmp) +{ + uint32_t addr_a, addr_b, nmask; + + nmask = MIN(fv_a->value.ipv4.nmask, fv_b->value.ipv4.nmask); + addr_a = fv_a->value.ipv4.addr & nmask; + addr_b = fv_b->value.ipv4.addr & nmask; + if (addr_a == addr_b) + *cmp = 0; + else + *cmp = addr_a < addr_b ? -1 : 1; + return FT_OK; +} + +static enum ft_result +bitwise_and(fvalue_t *dst, const fvalue_t *fv_a, const fvalue_t *fv_b, char **err_ptr _U_) +{ + dst->value.ipv4 = fv_a->value.ipv4; + dst->value.ipv4.addr &= (fv_b->value.ipv4.addr & fv_b->value.ipv4.nmask); + return FT_OK; +} + +static unsigned +len(fvalue_t *fv _U_) +{ + return 4; +} + +static void +slice(fvalue_t *fv, GByteArray *bytes, unsigned offset, unsigned length) +{ + uint8_t* data; + uint32_t addr = g_htonl(fv->value.ipv4.addr); + data = ((uint8_t*)&addr)+offset; + g_byte_array_append(bytes, data, length); +} + +static unsigned +ipv4_hash(const fvalue_t *fv) +{ + int64_t val1 = fv->value.ipv4.addr; + int64_t val2 = fv->value.ipv4.nmask; + return g_int64_hash(&val1) ^ g_int64_hash(&val2); +} + +static bool +is_zero(const fvalue_t *fv_a) +{ + return fv_a->value.ipv4.addr == 0; +} + +void +ftype_register_ipv4(void) +{ + + static ftype_t ipv4_type = { + FT_IPv4, /* ftype */ + "FT_IPv4", /* name */ + "IPv4 address", /* pretty_name */ + 4, /* wire_size */ + NULL, /* new_value */ + NULL, /* copy_value */ + NULL, /* free_value */ + val_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + NULL, /* val_from_charconst */ + val_to_repr, /* val_to_string_repr */ + + NULL, /* val_to_uinteger64 */ + NULL, /* val_to_sinteger64 */ + + { .set_value_uinteger = set_uinteger }, /* union set_value */ + { .get_value_uinteger = value_get }, /* union get_value */ + + cmp_order, + NULL, /* cmp_contains */ + NULL, /* cmp_matches */ + + ipv4_hash, + is_zero, + NULL, + len, + (FvalueSlice)slice, + bitwise_and, + NULL, /* unary_minus */ + NULL, /* add */ + NULL, /* subtract */ + NULL, /* multiply */ + NULL, /* divide */ + NULL, /* modulo */ + }; + + ftype_register(FT_IPv4, &ipv4_type); +} + +void +ftype_register_pseudofields_ipv4(int proto) +{ + static int hf_ft_ipv4; + + static hf_register_info hf_ftypes[] = { + { &hf_ft_ipv4, + { "FT_IPv4", "_ws.ftypes.ipv4", + FT_IPv4, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + }; + + proto_register_field_array(proto, hf_ftypes, array_length(hf_ftypes)); +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 8 + * tab-width: 8 + * indent-tabs-mode: t + * End: + * + * vi: set shiftwidth=8 tabstop=8 noexpandtab: + * :indentSize=8:tabSize=8:noTabs=false: + */ diff --git a/epan/ftypes/ftype-ipv6.c b/epan/ftypes/ftype-ipv6.c new file mode 100644 index 0000000..3b06bfd --- /dev/null +++ b/epan/ftypes/ftype-ipv6.c @@ -0,0 +1,275 @@ +/* + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 2001 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include <string.h> + +#include <ftypes-int.h> +#include <epan/ipv6.h> +#include <epan/addr_resolv.h> +#include <epan/to_str.h> + +static bool +ipv6_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg) +{ + const char *slash; + const char *addr_str; + char *addr_str_to_free = NULL; + unsigned int nmask_bits; + fvalue_t *nmask_fvalue; + + /* Look for prefix: Is there a single slash in the string? */ + slash = strchr(s, '/'); + if (slash) { + /* Make a copy of the string up to but not including the + * slash; that's the address portion. */ + addr_str_to_free = wmem_strndup(NULL, s, slash-s); + addr_str = addr_str_to_free; + } + else + addr_str = s; + + if (!get_host_ipaddr6(addr_str, &(fv->value.ipv6.addr))) { + if (err_msg != NULL) + *err_msg = ws_strdup_printf("\"%s\" is not a valid hostname or IPv6 address.", s); + if (addr_str_to_free) + wmem_free(NULL, addr_str_to_free); + return false; + } + + if (addr_str_to_free) + wmem_free(NULL, addr_str_to_free); + + /* If prefix */ + if (slash) { + /* XXX - this is inefficient */ + nmask_fvalue = fvalue_from_literal(FT_UINT32, slash+1, false, err_msg); + if (!nmask_fvalue) { + return false; + } + nmask_bits = fvalue_get_uinteger(nmask_fvalue); + fvalue_free(nmask_fvalue); + + if (nmask_bits > 128) { + if (err_msg != NULL) { + *err_msg = ws_strdup_printf("Prefix in a IPv6 address should be <= 128, not %u", + nmask_bits); + } + return false; + } + fv->value.ipv6.prefix = nmask_bits; + } else { + /* Not CIDR; mask covers entire address. */ + fv->value.ipv6.prefix = 128; + } + + return true; +} + +static char * +ipv6_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_) +{ + char buf[WS_INET6_ADDRSTRLEN]; + char *repr; + + ip6_to_str_buf(&fv->value.ipv6.addr, buf, sizeof(buf)); + + if (fv->value.ipv6.prefix != 0 && fv->value.ipv6.prefix != 128) + repr = wmem_strdup_printf(scope, "%s/%"PRIu32, buf, fv->value.ipv6.prefix); + else + repr = wmem_strdup(scope, buf); + + return repr; +} + +static void +ipv6_set(fvalue_t *fv, const ws_in6_addr *value) +{ + memcpy(&fv->value.ipv6.addr, value, FT_IPv6_LEN); + fv->value.ipv6.prefix = 128; +} + + +static const ws_in6_addr * +ipv6_get(fvalue_t *fv) +{ + return &fv->value.ipv6.addr; +} + +static const uint8_t bitmasks[9] = + { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; + +static enum ft_result +cmp_order(const fvalue_t *fv_a, const fvalue_t *fv_b, int *cmp) +{ + const ipv6_addr_and_prefix *a = &(fv_a->value.ipv6); + const ipv6_addr_and_prefix *b = &(fv_b->value.ipv6); + uint32_t prefix; + int pos = 0; + + prefix = MIN(a->prefix, b->prefix); /* MIN() like IPv4 */ + prefix = MIN(prefix, 128); /* sanitize, max prefix is 128 */ + + while (prefix >= 8) { + int byte_a = (int) (a->addr.bytes[pos]); + int byte_b = (int) (b->addr.bytes[pos]); + + if (byte_a != byte_b) { + *cmp = byte_a - byte_b; + return FT_OK; + } + + prefix -= 8; + pos++; + } + + if (prefix != 0) { + int byte_a = (int) (a->addr.bytes[pos] & (bitmasks[prefix])); + int byte_b = (int) (b->addr.bytes[pos] & (bitmasks[prefix])); + + if (byte_a != byte_b) { + *cmp = byte_a - byte_b; + return FT_OK; + } + } + *cmp = 0; + return FT_OK; +} + +static enum ft_result +bitwise_and(fvalue_t *dst, const fvalue_t *fv_a, const fvalue_t *fv_b, char **err_ptr _U_) +{ + const ipv6_addr_and_prefix *a = &(fv_a->value.ipv6); + const ipv6_addr_and_prefix *b = &(fv_b->value.ipv6); + uint32_t prefix; + int pos = 0; + + prefix = MIN(a->prefix, b->prefix); /* MIN() like in IPv4 */ + prefix = MIN(prefix, 128); /* sanitize, max prefix is 128 */ + + while (prefix >= 8) { + dst->value.ipv6.addr.bytes[pos] = + a->addr.bytes[pos] & b->addr.bytes[pos]; + + prefix -= 8; + pos++; + } + + if (prefix != 0) { + dst->value.ipv6.addr.bytes[pos] = + a->addr.bytes[pos] & b->addr.bytes[pos] & bitmasks[prefix]; + } + return FT_OK; +} + +static unsigned +len(fvalue_t *fv _U_) +{ + return FT_IPv6_LEN; +} + +static void +slice(fvalue_t *fv, GByteArray *bytes, unsigned offset, unsigned length) +{ + uint8_t* data; + + data = fv->value.ipv6.addr.bytes + offset; + + g_byte_array_append(bytes, data, length); +} + +static unsigned +ipv6_hash(const fvalue_t *fv) +{ + struct _ipv6 { + int64_t val[2]; + } *addr = (struct _ipv6 *)&fv->value.ipv6.addr; + int64_t mask = fv->value.ipv6.prefix; + + return g_int64_hash(&addr->val[0]) ^ g_int64_hash(&addr->val[1]) ^ g_int64_hash(&mask); +} + +static bool +is_zero(const fvalue_t *fv_a) +{ + ws_in6_addr zero = { 0 }; + return memcmp(&fv_a->value.ipv6.addr, &zero, sizeof(ws_in6_addr)) == 0; +} + +void +ftype_register_ipv6(void) +{ + static ftype_t ipv6_type = { + FT_IPv6, /* ftype */ + "FT_IPv6", /* name */ + "IPv6 address", /* pretty_name */ + FT_IPv6_LEN, /* wire_size */ + NULL, /* new_value */ + NULL, /* copy_value */ + NULL, /* free_value */ + ipv6_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + NULL, /* val_from_charconst */ + ipv6_to_repr, /* val_to_string_repr */ + + NULL, /* val_to_uinteger64 */ + NULL, /* val_to_sinteger64 */ + + { .set_value_ipv6 = ipv6_set }, /* union set_value */ + { .get_value_ipv6 = ipv6_get }, /* union get_value */ + + cmp_order, + NULL, /* XXX, cmp_contains, needed? ipv4 doesn't support it */ + NULL, /* cmp_matches */ + + ipv6_hash, + is_zero, + NULL, + len, + (FvalueSlice)slice, + bitwise_and, + NULL, /* unary_minus */ + NULL, /* add */ + NULL, /* subtract */ + NULL, /* multiply */ + NULL, /* divide */ + NULL, /* modulo */ + }; + + ftype_register(FT_IPv6, &ipv6_type); +} + +void +ftype_register_pseudofields_ipv6(int proto) +{ + static int hf_ft_ipv6; + + static hf_register_info hf_ftypes[] = { + { &hf_ft_ipv6, + { "FT_IPv6", "_ws.ftypes.ipv6", + FT_IPv6, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + }; + + proto_register_field_array(proto, hf_ftypes, array_length(hf_ftypes)); +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 8 + * tab-width: 8 + * indent-tabs-mode: t + * End: + * + * vi: set shiftwidth=8 tabstop=8 noexpandtab: + * :indentSize=8:tabSize=8:noTabs=false: + */ diff --git a/epan/ftypes/ftype-none.c b/epan/ftypes/ftype-none.c new file mode 100644 index 0000000..909fcba --- /dev/null +++ b/epan/ftypes/ftype-none.c @@ -0,0 +1,84 @@ +/* + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 2001 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include <ftypes-int.h> + + +void +ftype_register_none(void) +{ + + static ftype_t none_type = { + FT_NONE, /* ftype */ + "FT_NONE", /* name */ + "Label", /* pretty_name */ + 0, /* wire_size */ + NULL, /* new_value */ + NULL, /* copy_value */ + NULL, /* free_value */ + NULL, /* val_from_literal */ + NULL, /* val_from_string */ + NULL, /* val_from_charconst */ + NULL, /* val_to_string_repr */ + + NULL, /* val_to_uinteger64 */ + NULL, /* val_to_sinteger64 */ + + { NULL }, /* union set_value */ + { NULL }, /* union get_value */ + + NULL, /* cmp_order */ + NULL, /* cmp_contains */ + NULL, /* cmp_matches */ + + NULL, /* hash */ + NULL, /* is_zero */ + NULL, /* is_negative */ + NULL, /* len */ + NULL, /* slice */ + NULL, /* biwise_and */ + NULL, /* unary_minus */ + NULL, /* add */ + NULL, /* subtract */ + NULL, /* multiply */ + NULL, /* divide */ + NULL, /* modulo */ + }; + ftype_register(FT_NONE, &none_type); +} + +void +ftype_register_pseudofields_none(int proto) +{ + static int hf_ft_none; + + static hf_register_info hf_ftypes[] = { + { &hf_ft_none, + { "FT_NONE", "_ws.ftypes.none", + FT_NONE, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + }; + + proto_register_field_array(proto, hf_ftypes, array_length(hf_ftypes)); +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 8 + * tab-width: 8 + * indent-tabs-mode: t + * End: + * + * vi: set shiftwidth=8 tabstop=8 noexpandtab: + * :indentSize=8:tabSize=8:noTabs=false: + */ diff --git a/epan/ftypes/ftype-protocol.c b/epan/ftypes/ftype-protocol.c new file mode 100644 index 0000000..a0e964c --- /dev/null +++ b/epan/ftypes/ftype-protocol.c @@ -0,0 +1,440 @@ +/* + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 2001 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include <ftypes-int.h> +#include <epan/strutil.h> +#include <epan/to_str.h> +#include <string.h> +#include <wsutil/glib-compat.h> + +#include <epan/exceptions.h> +#include <wsutil/ws_assert.h> + +static void +value_new(fvalue_t *fv) +{ + fv->value.protocol.tvb = NULL; + fv->value.protocol.proto_string = NULL; + fv->value.protocol.tvb_is_private = false; + fv->value.protocol.length = -1; +} + +static void +value_copy(fvalue_t *dst, const fvalue_t *src) +{ + dst->value.protocol.tvb = tvb_clone(src->value.protocol.tvb); + dst->value.protocol.proto_string = g_strdup(src->value.protocol.proto_string); + dst->value.protocol.tvb_is_private = true; + dst->value.protocol.length = src->value.protocol.length; +} + +static void +value_free(fvalue_t *fv) +{ + if (fv->value.protocol.tvb && fv->value.protocol.tvb_is_private) { + tvb_free_chain(fv->value.protocol.tvb); + } + g_free(fv->value.protocol.proto_string); +} + +static void +value_set(fvalue_t *fv, tvbuff_t *value, const char *name, int length) +{ + if (value != NULL) { + /* Free up the old value, if we have one */ + value_free(fv); + + /* Set the protocol description and an (optional, nullable) tvbuff. */ + fv->value.protocol.tvb = value; + fv->value.protocol.proto_string = g_strdup(name); + } + fv->value.protocol.length = length; +} + +static bool +val_from_string(fvalue_t *fv, const char *s, size_t len, char **err_msg _U_) +{ + tvbuff_t *new_tvb; + uint8_t *private_data; + + /* Free up the old value, if we have one */ + value_free(fv); + + if (len == 0) + len = strlen(s); + + /* Make a tvbuff from the string. We can drop the + * terminating NUL. */ + private_data = (uint8_t *)g_memdup2(s, (unsigned)len); + new_tvb = tvb_new_real_data(private_data, + (unsigned)len, (int)len); + + /* Let the tvbuff know how to delete the data. */ + tvb_set_free_cb(new_tvb, g_free); + + /* And let us know that we need to free the tvbuff */ + fv->value.protocol.tvb_is_private = true; + /* This "field" is a value, it has no protocol description, but + * we might compare it to a protocol with NULL tvb. + * (e.g., proto_expert) */ + fv->value.protocol.tvb = new_tvb; + fv->value.protocol.proto_string = g_strdup(""); + fv->value.protocol.length = -1; + return true; +} + +static bool +val_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg) +{ + GByteArray *bytes; + tvbuff_t *new_tvb; + + /* Free up the old value, if we have one */ + value_free(fv); + fv->value.protocol.tvb = NULL; + fv->value.protocol.proto_string = NULL; + fv->value.protocol.length = -1; + + /* Does this look like a byte string? */ + bytes = byte_array_from_literal(s, err_msg); + if (bytes != NULL) { + /* Make a tvbuff from the bytes */ + new_tvb = tvb_new_real_data(bytes->data, bytes->len, bytes->len); + + /* Let the tvbuff know how to delete the data. */ + tvb_set_free_cb(new_tvb, g_free); + + /* Free GByteArray, but keep data. */ + g_byte_array_free(bytes, false); + + /* And let us know that we need to free the tvbuff */ + fv->value.protocol.tvb_is_private = true; + fv->value.protocol.tvb = new_tvb; + + /* This "field" is a value, it has no protocol description, but + * we might compare it to a protocol with NULL tvb. + * (e.g., proto_expert) */ + fv->value.protocol.proto_string = g_strdup(""); + return true; + } + + /* Not a byte array, forget about it. */ + return false; +} + +static bool +val_from_charconst(fvalue_t *fv, unsigned long num, char **err_msg) +{ + GByteArray *bytes; + tvbuff_t *new_tvb; + + /* Free up the old value, if we have one */ + value_free(fv); + fv->value.protocol.tvb = NULL; + fv->value.protocol.proto_string = NULL; + fv->value.protocol.length = -1; + + /* Does this look like a byte string? */ + bytes = byte_array_from_charconst(num, err_msg); + if (bytes != NULL) { + /* Make a tvbuff from the bytes */ + new_tvb = tvb_new_real_data(bytes->data, bytes->len, bytes->len); + + /* Let the tvbuff know how to delete the data. */ + tvb_set_free_cb(new_tvb, g_free); + + /* Free GByteArray, but keep data. */ + g_byte_array_free(bytes, false); + + /* And let us know that we need to free the tvbuff */ + fv->value.protocol.tvb_is_private = true; + fv->value.protocol.tvb = new_tvb; + + /* This "field" is a value, it has no protocol description, but + * we might compare it to a protocol with NULL tvb. + * (e.g., proto_expert) */ + fv->value.protocol.proto_string = g_strdup(""); + return true; + } + + /* Not a byte array, forget about it. */ + return false; +} + +static char * +val_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype, int field_display _U_) +{ + unsigned length; + char *volatile buf = NULL; + + if (rtype != FTREPR_DFILTER) + return NULL; + + TRY { + if (fv->value.protocol.length >= 0) + length = fv->value.protocol.length; + else + length = tvb_captured_length(fv->value.protocol.tvb); + + if (length) { + if (rtype == FTREPR_DFILTER) + buf = bytes_to_dfilter_repr(scope, tvb_get_ptr(fv->value.protocol.tvb, 0, length), length); + else + buf = bytes_to_str_punct_maxlen(scope, tvb_get_ptr(fv->value.protocol.tvb, 0, length), length, ':', 0); + } + } + CATCH_ALL { + /* nothing */ + } + ENDTRY; + return buf; +} + +static tvbuff_t * +value_get(fvalue_t *fv) +{ + if (fv->value.protocol.length < 0) + return fv->value.protocol.tvb; + return tvb_new_subset_length_caplen(fv->value.protocol.tvb, 0, fv->value.protocol.length, fv->value.protocol.length); +} + +static unsigned +len(fvalue_t *fv) +{ + volatile unsigned length = 0; + + TRY { + if (fv->value.protocol.tvb) { + if (fv->value.protocol.length >= 0) + length = fv->value.protocol.length; + else + length = tvb_captured_length(fv->value.protocol.tvb); + + } + } + CATCH_ALL { + /* nothing */ + } + ENDTRY; + + return length; +} + +static void +slice(fvalue_t *fv, GByteArray *bytes, unsigned offset, unsigned length) +{ + const uint8_t* data; + volatile unsigned len = length; + + if (fv->value.protocol.tvb) { + if (fv->value.protocol.length >= 0 && (unsigned)fv->value.protocol.length < len) { + len = fv->value.protocol.length; + } + + TRY { + data = tvb_get_ptr(fv->value.protocol.tvb, offset, len); + g_byte_array_append(bytes, data, len); + } + CATCH_ALL { + /* nothing */ + } + ENDTRY; + + } +} + +static int +_tvbcmp(const protocol_value_t *a, const protocol_value_t *b) +{ + unsigned a_len; + unsigned b_len; + + if (a->length < 0) + a_len = tvb_captured_length(a->tvb); + else + a_len = a->length; + + if (b->length < 0) + b_len = tvb_captured_length(b->tvb); + else + b_len = b->length; + + if (a_len != b_len) + return a_len < b_len ? -1 : 1; + return memcmp(tvb_get_ptr(a->tvb, 0, a_len), tvb_get_ptr(b->tvb, 0, a_len), a_len); +} + +static enum ft_result +cmp_order(const fvalue_t *fv_a, const fvalue_t *fv_b, int *cmp) +{ + const protocol_value_t *a = (const protocol_value_t *)&fv_a->value.protocol; + const protocol_value_t *b = (const protocol_value_t *)&fv_b->value.protocol; + volatile int c = 0; + + TRY { + if ((a->tvb != NULL) && (b->tvb != NULL)) { + c = _tvbcmp(a, b); + } else { + c = strcmp(a->proto_string, b->proto_string); + } + } + CATCH_ALL { + /* nothing */ + } + ENDTRY; + + *cmp = c; + return FT_OK; +} + +static enum ft_result +cmp_contains(const fvalue_t *fv_a, const fvalue_t *fv_b, bool *contains) +{ + volatile bool yes = false; + + TRY { + /* First see if tvb exists for both sides */ + if ((fv_a->value.protocol.tvb != NULL) && (fv_b->value.protocol.tvb != NULL)) { + if (tvb_find_tvb(fv_a->value.protocol.tvb, fv_b->value.protocol.tvb, 0) > -1) { + yes = true; + } + } else { + /* Otherwise just compare strings */ + if ((strlen(fv_b->value.protocol.proto_string) != 0) && + strstr(fv_a->value.protocol.proto_string, fv_b->value.protocol.proto_string)) { + yes = true; + } + } + } + CATCH_ALL { + /* nothing */ + } + ENDTRY; + + *contains = yes; + return FT_OK; +} + +static enum ft_result +cmp_matches(const fvalue_t *fv, const ws_regex_t *regex, bool *matches) +{ + const protocol_value_t *a = (const protocol_value_t *)&fv->value.protocol; + volatile bool rc = false; + const char *data = NULL; /* tvb data */ + uint32_t tvb_len; /* tvb length */ + + if (! regex) { + return FT_BADARG; + } + TRY { + if (a->tvb != NULL) { + tvb_len = tvb_captured_length(a->tvb); + data = (const char *)tvb_get_ptr(a->tvb, 0, tvb_len); + rc = ws_regex_matches_length(regex, data, tvb_len); + } else { + rc = ws_regex_matches(regex, a->proto_string); + } + } + CATCH_ALL { + rc = false; + } + ENDTRY; + + *matches = rc; + return FT_OK; +} + +static unsigned +val_hash(const fvalue_t *fv) +{ + const protocol_value_t *value = &fv->value.protocol; + return g_direct_hash(value->tvb) ^ g_int_hash(&value->length) ^ g_str_hash(value->proto_string); +} + +static bool +is_zero(const fvalue_t *fv) +{ + const protocol_value_t *a = &fv->value.protocol; + return a->tvb == NULL && a->proto_string == NULL; +} + +void +ftype_register_tvbuff(void) +{ + + static ftype_t protocol_type = { + FT_PROTOCOL, /* ftype */ + "FT_PROTOCOL", /* name */ + "Protocol", /* pretty_name */ + 0, /* wire_size */ + value_new, /* new_value */ + value_copy, /* copy_value */ + value_free, /* free_value */ + val_from_literal, /* val_from_literal */ + val_from_string, /* val_from_string */ + val_from_charconst, /* val_from_charconst */ + val_to_repr, /* val_to_string_repr */ + + NULL, /* val_to_uinteger64 */ + NULL, /* val_to_sinteger64 */ + + { .set_value_protocol = value_set }, /* union set_value */ + { .get_value_protocol = value_get }, /* union get_value */ + + cmp_order, + cmp_contains, + cmp_matches, + + val_hash, + is_zero, + NULL, + len, + (FvalueSlice)slice, + NULL, + NULL, /* unary_minus */ + NULL, /* add */ + NULL, /* subtract */ + NULL, /* multiply */ + NULL, /* divide */ + NULL, /* modulo */ + }; + + + ftype_register(FT_PROTOCOL, &protocol_type); +} + +void +ftype_register_pseudofields_tvbuff(int proto) +{ + static int hf_ft_protocol; + + static hf_register_info hf_ftypes[] = { + { &hf_ft_protocol, + { "FT_PROTOCOL", "_ws.ftypes.protocol", + FT_PROTOCOL, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + }; + + proto_register_field_array(proto, hf_ftypes, array_length(hf_ftypes)); +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 8 + * tab-width: 8 + * indent-tabs-mode: t + * End: + * + * vi: set shiftwidth=8 tabstop=8 noexpandtab: + * :indentSize=8:tabSize=8:noTabs=false: + */ diff --git a/epan/ftypes/ftype-string.c b/epan/ftypes/ftype-string.c new file mode 100644 index 0000000..28c33a7 --- /dev/null +++ b/epan/ftypes/ftype-string.c @@ -0,0 +1,439 @@ +/* + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 2001 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include <stdio.h> +#include <ftypes-int.h> +#include <string.h> + +#include <strutil.h> +#include <wsutil/ws_assert.h> +#include <wsutil/unicode-utils.h> + + +static void +string_fvalue_new(fvalue_t *fv) +{ + fv->value.strbuf = NULL; +} + +static void +string_fvalue_copy(fvalue_t *dst, const fvalue_t *src) +{ + dst->value.strbuf = wmem_strbuf_dup(NULL, src->value.strbuf); +} + +static void +string_fvalue_free(fvalue_t *fv) +{ + wmem_strbuf_destroy(fv->value.strbuf); +} + +static void +string_fvalue_set_strbuf(fvalue_t *fv, wmem_strbuf_t *value) +{ + DISSECTOR_ASSERT(value != NULL); + + /* Free up the old value, if we have one */ + string_fvalue_free(fv); + + fv->value.strbuf = value; +} + +static char * +string_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_) +{ + if (rtype == FTREPR_DISPLAY || rtype == FTREPR_JSON) { + return ws_escape_null(scope, fv->value.strbuf->str, fv->value.strbuf->len, false); + } + if (rtype == FTREPR_DFILTER) { + return ws_escape_string_len(scope, fv->value.strbuf->str, fv->value.strbuf->len, true); + } + ws_assert_not_reached(); +} + + +static const wmem_strbuf_t * +value_get(fvalue_t *fv) +{ + return fv->value.strbuf; +} + +static bool +val_from_string(fvalue_t *fv, const char *s, size_t len, char **err_msg _U_) +{ + /* Free up the old value, if we have one */ + string_fvalue_free(fv); + + if (len > 0) + fv->value.strbuf = wmem_strbuf_new_len(NULL, s, len); + else + fv->value.strbuf = wmem_strbuf_new(NULL, s); + + return true; +} + +static bool +val_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg) +{ + /* Just turn it into a string */ + /* XXX Should probably be a syntax error instead. It's more user-friendly to ask the + * user to be explicit about the meaning of an unquoted literal than them trying to figure out + * why a valid filter expression is giving wrong results. */ + return val_from_string(fv, s, 0, err_msg); +} + +static bool +val_from_charconst(fvalue_t *fv, unsigned long num, char **err_msg) +{ + /* XXX Should be a syntax error if literal is also a syntax error. */ + + /* Free up the old value, if we have one */ + string_fvalue_free(fv); + fv->value.strbuf = NULL; + + if (num > UINT8_MAX) { + if (err_msg) { + *err_msg = ws_strdup_printf("%lu is too large for a byte value", num); + } + return false; + } + + char c = (char)num; + fv->value.strbuf = wmem_strbuf_new(NULL, NULL); + wmem_strbuf_append_c(fv->value.strbuf, c); + + return true; +} + +static unsigned +string_hash(const fvalue_t *fv) +{ + return g_str_hash(wmem_strbuf_get_str(fv->value.strbuf)); +} + +static bool +string_is_zero(const fvalue_t *fv) +{ + return fv->value.strbuf == NULL || fv->value.strbuf->len == 0; +} + +static unsigned +len(fvalue_t *fv) +{ + /* g_utf8_strlen returns long for no apparent reason*/ + long len = g_utf8_strlen(fv->value.strbuf->str, -1); + if (len < 0) + return 0; + return (unsigned)len; +} + +static void +slice(fvalue_t *fv, wmem_strbuf_t *buf, unsigned offset, unsigned length) +{ + const char *str = fv->value.strbuf->str; + + /* Go to the starting offset */ + const char *p = g_utf8_offset_to_pointer(str, (long)offset); + const char *n; + /* Copy 'length' codepoints to dst. Skip the terminating NULL */ + while (*p != '\0' && length-- > 0) { + n = g_utf8_next_char(p); + /* Append n - p bytes (one codepoint)*/ + wmem_strbuf_append_len(buf, p, n - p); + p = n; + } +} + +static enum ft_result +cmp_order(const fvalue_t *a, const fvalue_t *b, int *cmp) +{ + *cmp = wmem_strbuf_strcmp(a->value.strbuf, b->value.strbuf); + return FT_OK; +} + +static enum ft_result +cmp_contains(const fvalue_t *fv_a, const fvalue_t *fv_b, bool *contains) +{ + /* According to + * http://www.introl.com/introl-demo/Libraries/C/ANSI_C/string/strstr.html + * strstr() returns a non-NULL value if needle is an empty + * string. We don't that behavior for cmp_contains. */ + if (fv_b->value.strbuf->len == 0) { + *contains = false; + return FT_OK; + } + + if (wmem_strbuf_strstr(fv_a->value.strbuf, fv_b->value.strbuf)) { + *contains = true; + } + else { + *contains = false; + } + + return FT_OK; +} + +static enum ft_result +cmp_matches(const fvalue_t *fv, const ws_regex_t *regex, bool *matches) +{ + wmem_strbuf_t *buf = fv->value.strbuf; + + if (regex == NULL) { + return FT_BADARG; + } + + *matches = ws_regex_matches_length(regex, buf->str, buf->len); + return FT_OK; +} + +void +ftype_register_string(void) +{ + + static ftype_t string_type = { + FT_STRING, /* ftype */ + "FT_STRING", /* name */ + "Character string", /* pretty_name */ + 0, /* wire_size */ + string_fvalue_new, /* new_value */ + string_fvalue_copy, /* copy_value */ + string_fvalue_free, /* free_value */ + val_from_literal, /* val_from_literal */ + val_from_string, /* val_from_string */ + val_from_charconst, /* val_from_charconst */ + string_to_repr, /* val_to_string_repr */ + + NULL, /* val_to_uinteger64 */ + NULL, /* val_to_sinteger64 */ + + { .set_value_strbuf = string_fvalue_set_strbuf }, /* union set_value */ + { .get_value_strbuf = value_get }, /* union get_value */ + + cmp_order, + cmp_contains, + cmp_matches, + + string_hash, /* hash */ + string_is_zero, /* is_zero */ + NULL, /* is_negative */ + len, + (FvalueSlice)slice, + NULL, /* bitwise_and */ + NULL, /* unary_minus */ + NULL, /* add */ + NULL, /* subtract */ + NULL, /* multiply */ + NULL, /* divide */ + NULL, /* modulo */ + }; + static ftype_t stringz_type = { + FT_STRINGZ, /* ftype */ + "FT_STRINGZ", /* name */ + "Character string", /* pretty name */ + 0, /* wire_size */ + string_fvalue_new, /* new_value */ + string_fvalue_copy, /* copy_value */ + string_fvalue_free, /* free_value */ + val_from_literal, /* val_from_literal */ + val_from_string, /* val_from_string */ + val_from_charconst, /* val_from_charconst */ + string_to_repr, /* val_to_string_repr */ + + NULL, /* val_to_uinteger64 */ + NULL, /* val_to_sinteger64 */ + + { .set_value_strbuf = string_fvalue_set_strbuf }, /* union set_value */ + { .get_value_strbuf = value_get }, /* union get_value */ + + cmp_order, + cmp_contains, /* cmp_contains */ + cmp_matches, + + string_hash, /* hash */ + string_is_zero, /* is_zero */ + NULL, /* is_negative */ + len, + (FvalueSlice)slice, + NULL, /* bitwise_and */ + NULL, /* unary_minus */ + NULL, /* add */ + NULL, /* subtract */ + NULL, /* multiply */ + NULL, /* divide */ + NULL, /* modulo */ + }; + static ftype_t uint_string_type = { + FT_UINT_STRING, /* ftype */ + "FT_UINT_STRING", /* name */ + "Character string", /* pretty_name */ + 0, /* wire_size */ + string_fvalue_new, /* new_value */ + string_fvalue_copy, /* copy_value */ + string_fvalue_free, /* free_value */ + val_from_literal, /* val_from_literal */ + val_from_string, /* val_from_string */ + val_from_charconst, /* val_from_charconst */ + string_to_repr, /* val_to_string_repr */ + + NULL, /* val_to_uinteger64 */ + NULL, /* val_to_sinteger64 */ + + { .set_value_strbuf = string_fvalue_set_strbuf }, /* union set_value */ + { .get_value_strbuf = value_get }, /* union get_value */ + + cmp_order, + cmp_contains, /* cmp_contains */ + cmp_matches, + + string_hash, /* hash */ + string_is_zero, /* is_zero */ + NULL, /* is_negative */ + len, + (FvalueSlice)slice, + NULL, /* bitwise_and */ + NULL, /* unary_minus */ + NULL, /* add */ + NULL, /* subtract */ + NULL, /* multiply */ + NULL, /* divide */ + NULL, /* modulo */ + }; + static ftype_t stringzpad_type = { + FT_STRINGZPAD, /* ftype */ + "FT_STRINGZPAD", /* name */ + "Character string", /* pretty name */ + 0, /* wire_size */ + string_fvalue_new, /* new_value */ + string_fvalue_copy, /* copy_value */ + string_fvalue_free, /* free_value */ + val_from_literal, /* val_from_literal */ + val_from_string, /* val_from_string */ + val_from_charconst, /* val_from_charconst */ + string_to_repr, /* val_to_string_repr */ + + NULL, /* val_to_uinteger64 */ + NULL, /* val_to_sinteger64 */ + + { .set_value_strbuf = string_fvalue_set_strbuf }, /* union set_value */ + { .get_value_strbuf = value_get }, /* union get_value */ + + cmp_order, + cmp_contains, /* cmp_contains */ + cmp_matches, + + string_hash, /* hash */ + string_is_zero, /* is_zero */ + NULL, /* is_negative */ + len, + (FvalueSlice)slice, + NULL, /* bitwise_and */ + NULL, /* unary_minus */ + NULL, /* add */ + NULL, /* subtract */ + NULL, /* multiply */ + NULL, /* divide */ + NULL, /* modulo */ + }; + static ftype_t stringztrunc_type = { + FT_STRINGZTRUNC, /* ftype */ + "FT_STRINGZTRUNC", /* name */ + "Character string", /* pretty name */ + 0, /* wire_size */ + string_fvalue_new, /* new_value */ + string_fvalue_copy, /* copy_value */ + string_fvalue_free, /* free_value */ + val_from_literal, /* val_from_literal */ + val_from_string, /* val_from_string */ + val_from_charconst, /* val_from_charconst */ + string_to_repr, /* val_to_string_repr */ + + NULL, /* val_to_uinteger64 */ + NULL, /* val_to_sinteger64 */ + + { .set_value_strbuf = string_fvalue_set_strbuf }, /* union set_value */ + { .get_value_strbuf = value_get }, /* union get_value */ + + cmp_order, + cmp_contains, /* cmp_contains */ + cmp_matches, + + string_hash, /* hash */ + string_is_zero, /* is_zero */ + NULL, /* is_negative */ + len, + (FvalueSlice)slice, + NULL, /* bitwise_and */ + NULL, /* unary_minus */ + NULL, /* add */ + NULL, /* subtract */ + NULL, /* multiply */ + NULL, /* divide */ + NULL, /* modulo */ + }; + + ftype_register(FT_STRING, &string_type); + ftype_register(FT_STRINGZ, &stringz_type); + ftype_register(FT_UINT_STRING, &uint_string_type); + ftype_register(FT_STRINGZPAD, &stringzpad_type); + ftype_register(FT_STRINGZTRUNC, &stringztrunc_type); +} + +void +ftype_register_pseudofields_string(int proto) +{ + static int hf_ft_string; + static int hf_ft_stringz; + static int hf_ft_uint_string; + static int hf_ft_stringzpad; + static int hf_ft_stringztrunc; + + static hf_register_info hf_ftypes[] = { + { &hf_ft_string, + { "FT_STRING", "_ws.ftypes.string", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_stringz, + { "FT_STRINGZ", "_ws.ftypes.stringz", + FT_STRINGZ, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_uint_string, + { "FT_UINT_STRING", "_ws.ftypes.uint_string", + FT_UINT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_stringzpad, + { "FT_STRINGZPAD", "_ws.ftypes.stringzpad", + FT_STRINGZPAD, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_stringztrunc, + { "FT_STRINGZTRUNC", "_ws.ftypes.stringztrunc", + FT_STRINGZTRUNC, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + }; + + proto_register_field_array(proto, hf_ftypes, array_length(hf_ftypes)); +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 8 + * tab-width: 8 + * indent-tabs-mode: t + * End: + * + * vi: set shiftwidth=8 tabstop=8 noexpandtab: + * :indentSize=8:tabSize=8:noTabs=false: + */ diff --git a/epan/ftypes/ftype-time.c b/epan/ftypes/ftype-time.c new file mode 100644 index 0000000..568f9e0 --- /dev/null +++ b/epan/ftypes/ftype-time.c @@ -0,0 +1,670 @@ +/* + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 2001 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#define _GNU_SOURCE +#include "config.h" +#include "ftypes-int.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <epan/to_str.h> +#include <wsutil/time_util.h> +#include <wsutil/ws_strptime.h> +#include <wsutil/safe-math.h> + + +static enum ft_result +cmp_order(const fvalue_t *a, const fvalue_t *b, int *cmp) +{ + *cmp = nstime_cmp(&(a->value.time), &(b->value.time)); + return FT_OK; +} + +/* + * Get a nanoseconds value, starting at "p". + * + * Returns true on success, false on failure. + * + * If successful endptr points to the first invalid character. + */ +static bool +get_nsecs(const char *startp, int *nsecs, const char **endptr) +{ + int ndigits = 0; + int scale; + const char *p; + int val; + int digit; + int i; + + /* + * How many digits are in the string? + */ + for (p = startp; g_ascii_isdigit(*p); p++) + ndigits++; + + /* + * If there are N characters in the string, the last of the + * characters would be the digit corresponding to 10^(9-N) + * nanoseconds. + */ + scale = 9 - ndigits; + + /* + * Start at the last character, and work backwards. + */ + val = 0; + while (p != startp) { + p--; + + if (!g_ascii_isdigit(*p)) { + /* + * Not a digit - error. + */ + return false; + } + digit = *p - '0'; + if (digit != 0) { + /* + * Non-zero digit corresponding to that number + * of (10^scale) units. + * + * If scale is less than zero, this digit corresponds + * to a value less than a nanosecond, so this number + * isn't valid. + */ + if (scale < 0) + return false; + for (i = 0; i < scale; i++) + digit *= 10; + val += digit; + } + scale++; + } + *nsecs = val; + if (endptr) + *endptr = startp + ndigits; + return true; +} + +static bool +val_from_unix_time(fvalue_t *fv, const char *s) +{ + const char *curptr; + char *endptr; + bool negative = false; + + curptr = s; + + if (*curptr == '-') { + negative = true; + curptr++; + } + + /* + * If it doesn't begin with ".", it should contain a seconds + * value. + */ + if (*curptr != '.') { + /* + * Get the seconds value. + */ + fv->value.time.secs = strtoul(curptr, &endptr, 10); + if (endptr == curptr || (*endptr != '\0' && *endptr != '.')) + return false; + curptr = endptr; + if (*curptr == '.') + curptr++; /* skip the decimal point */ + } else { + /* + * No seconds value - it's 0. + */ + fv->value.time.secs = 0; + curptr++; /* skip the decimal point */ + } + + /* + * If there's more stuff left in the string, it should be the + * nanoseconds value. + */ + if (*curptr != '\0') { + /* + * Get the nanoseconds value. + */ + if (!get_nsecs(curptr, &fv->value.time.nsecs, NULL)) + return false; + } else { + /* + * No nanoseconds value - it's 0. + */ + fv->value.time.nsecs = 0; + } + + if (negative) { + fv->value.time.secs = -fv->value.time.secs; + fv->value.time.nsecs = -fv->value.time.nsecs; + } + return true; +} + +static bool +relative_val_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg) +{ + if (val_from_unix_time(fv, s)) + return true; + + if (err_msg != NULL) + *err_msg = ws_strdup_printf("\"%s\" is not a valid time.", s); + return false; +} + +/* + * Parses an absolute time value from a string. The string can have + * a UTC time zone suffix. In that case it is interpreted in UTC. Otherwise + * it is interpreted in local time. + * + * OS-dependent; e.g., on 32 bit versions of Windows when compiled to use + * _mktime32 treats dates before January 1, 1970 as invalid. + * (https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/mktime-mktime32-mktime64) + */ + +/* + * Timezone support: + * + %z an ISO 8601, RFC-2822, or RFC-3339 time zone specification. (A + NetBSD extension.) This is one of the following: + - The offset from Coordinated Universal Time (`UTC') speci- + fied as: + · [+-]hhmm + · [+-]hh:mm + · [+-]hh + - `UTC' specified as: + · UTC (`Coordinated Universal Time') + · GMT (`Greenwich Mean Time') + · UT (`Universal Time') + · Z (`Zulu Time') + - A three character US time zone specified as: + · EDT + · EST + · CDT + · CST + · MDT + · MST + · PDT + · PST + with the first letter standing for `Eastern' (``E''), + `Central' (``C''), `Mountain' (``M'') or `Pacific' + (``P''), and the second letter standing for `Daylight' + (``D'' or summer) time or `Standard' (``S'') time + - a single letter military or nautical time zone specified + as: + · ``A'' through ``I'' + · ``K'' through ``Y'' + · ``J'' (non-nautical local time zone) + + %Z time zone name or no characters when time zone information is + unavailable. (A NetBSD extension.) +*/ + +/* + * POSIX and C11 calendar time APIs are limited, poorly documented and have + * loads of bagage and surprising behavior and quirks (most stemming from + * the fact that the struct tm argument is sometimes both input and output). + * See the following reference for a reliable method of handling arbitrary timezones: + * C: Converting struct tm times with timezone to time_t + * http://kbyanc.blogspot.com/2007/06/c-converting-struct-tm-times-with.html + * Relevant excerpt: + * "However, if your libc implements both tm_gmtoff and timegm(3) you are + * in luck. You just need to use timegm(3) to get the time_t representing + * the time in GMT and then subtract the offset stored in tm_gmtoff. + * The tricky part is that calling timegm(3) will modify the struct tm, + * clearing the tm_gmtoff field to zero." + */ + +#define EXAMPLE "Example: \"Nov 12, 1999 08:55:44.123\" or \"2011-07-04 12:34:56\"" + +static bool +absolute_val_from_string(fvalue_t *fv, const char *s, size_t len _U_, char **err_msg_ptr) +{ + struct tm tm; + const char *bufptr, *curptr = NULL; + const char *endptr; + bool has_seconds = true; + bool has_timezone = true; + char *err_msg = NULL; + struct ws_timezone zoneinfo = { 0, NULL }; + + /* Try Unix time first. */ + if (val_from_unix_time(fv, s)) + return true; + + /* Try ISO 8601 format. */ + endptr = iso8601_to_nstime(&fv->value.time, s, ISO8601_DATETIME); + /* Check whether it parsed all of the string */ + if (endptr != NULL && *endptr == '\0') + return true; + + /* No - try other legacy formats. */ + memset(&tm, 0, sizeof(tm)); + /* Let the computer figure out if it's DST. */ + tm.tm_isdst = -1; + + /* Parse the date. ws_strptime() always uses the "C" locale. */ + bufptr = s; + curptr = ws_strptime(bufptr, "%b %d, %Y", &tm, &zoneinfo); + if (curptr == NULL) + curptr = ws_strptime(bufptr,"%Y-%m-%d", &tm, &zoneinfo); + if (curptr == NULL) + goto fail; + + /* Parse the time, it is optional. */ + bufptr = curptr; + curptr = ws_strptime(bufptr, " %H:%M:%S", &tm, &zoneinfo); + if (curptr == NULL) { + has_seconds = false; + /* Seconds can be omitted but minutes (and hours) are required + * for a valid time value. */ + curptr = ws_strptime(bufptr," %H:%M", &tm, &zoneinfo); + } + if (curptr == NULL) + curptr = bufptr; + + if (*curptr == '.') { + /* Nanoseconds */ + if (!has_seconds) { + err_msg = ws_strdup("Subsecond precision requires a seconds field."); + goto fail; /* Requires seconds */ + } + curptr++; /* skip the "." */ + if (!g_ascii_isdigit((unsigned char)*curptr)) { + /* not a digit, so not valid */ + err_msg = ws_strdup("Subseconds value is not a number."); + goto fail; + } + if (!get_nsecs(curptr, &fv->value.time.nsecs, &endptr)) { + err_msg = ws_strdup("Subseconds value is invalid."); + goto fail; + } + curptr = endptr; + } + else { + /* + * No nanoseconds value - it's 0. + */ + fv->value.time.nsecs = 0; + } + + /* Timezone */ + bufptr = curptr; + curptr = ws_strptime(bufptr, "%n%z", &tm, &zoneinfo); + if (curptr == NULL) { + /* No timezone, assume localtime. */ + has_timezone = false; + curptr = bufptr; + } + + /* Skip whitespace */ + while (g_ascii_isspace(*curptr)) { + curptr++; + } + + if (*curptr != '\0') { + err_msg = ws_strdup("Unexpected data after time value."); + goto fail; + } + + if (has_timezone) { + /* Convert our calendar time (presumed in UTC, possibly with + * an extra timezone offset correction datum) to epoch time. */ + fv->value.time.secs = mktime_utc(&tm); + } + else { + /* Convert our calendar time (in the local timezone) to epoch time. */ + fv->value.time.secs = mktime(&tm); + } + if (fv->value.time.secs == (time_t)-1) { + /* + * XXX - should we supply an error message that mentions + * that the time specified might be syntactically valid + * but might not actually have occurred, e.g. a time in + * the non-existent time range after the clocks are + * set forward during daylight savings time (or possibly + * that it's in the time range after the clocks are set + * backward, so that there are two different times that + * it could be)? + */ + err_msg = ws_strdup_printf("\"%s\" cannot be converted to a valid calendar time.", s); + goto fail; + } + + if (has_timezone) { + /* Normalize to UTC with the offset we have saved. */ + fv->value.time.secs -= zoneinfo.tm_gmtoff; + } + + return true; + +fail: + if (err_msg_ptr != NULL) { + if (err_msg == NULL) { + *err_msg_ptr = ws_strdup_printf("\"%s\" is not a valid absolute time. " EXAMPLE, s); + } + else { + *err_msg_ptr = err_msg; + } + } + else { + g_free(err_msg); + } + + return false; +} + +static bool +absolute_val_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg) +{ + return absolute_val_from_string(fv, s, 0, err_msg); +} + +static void +time_fvalue_new(fvalue_t *fv) +{ + fv->value.time.secs = 0; + fv->value.time.nsecs = 0; +} + +static void +time_fvalue_copy(fvalue_t *dst, const fvalue_t *src) +{ + nstime_copy(&dst->value.time, &src->value.time); +} + +static void +time_fvalue_set(fvalue_t *fv, const nstime_t *value) +{ + fv->value.time = *value; +} + +static const nstime_t * +value_get(fvalue_t *fv) +{ + return &(fv->value.time); +} + +static char * +abs_time_to_ftrepr_dfilter(wmem_allocator_t *scope, + const nstime_t *nstime, bool use_utc) +{ + struct tm *tm; + char datetime_format[128]; + char nsecs_buf[32]; + + if (use_utc) { + tm = gmtime(&nstime->secs); + if (tm != NULL) + strftime(datetime_format, sizeof(datetime_format), "\"%Y-%m-%d %H:%M:%S%%sZ\"", tm); + else + snprintf(datetime_format, sizeof(datetime_format), "Not representable"); + } + else { + tm = localtime(&nstime->secs); + /* Displaying the timezone could be made into a preference. */ + if (tm != NULL) + strftime(datetime_format, sizeof(datetime_format), "\"%Y-%m-%d %H:%M:%S%%s%z\"", tm); + else + snprintf(datetime_format, sizeof(datetime_format), "Not representable"); + } + + if (nstime->nsecs == 0) + return wmem_strdup_printf(scope, datetime_format, ""); + + snprintf(nsecs_buf, sizeof(nsecs_buf), ".%09d", nstime->nsecs); + + return wmem_strdup_printf(scope, datetime_format, nsecs_buf); +} + +static char * +absolute_val_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype, int field_display) +{ + char *rep; + + if (field_display == BASE_NONE) + field_display = ABSOLUTE_TIME_LOCAL; + + switch (rtype) { + case FTREPR_DISPLAY: + case FTREPR_JSON: + rep = abs_time_to_str_ex(scope, &fv->value.time, + field_display, ABS_TIME_TO_STR_SHOW_ZONE); + break; + + case FTREPR_DFILTER: + if (field_display == ABSOLUTE_TIME_UNIX) { + rep = abs_time_to_unix_str(scope, &fv->value.time); + } + else { + /* Only ABSOLUTE_TIME_LOCAL and ABSOLUTE_TIME_UTC + * are supported. Normalize the field_display value. */ + if (field_display != ABSOLUTE_TIME_LOCAL) + field_display = ABSOLUTE_TIME_UTC; + rep = abs_time_to_ftrepr_dfilter(scope, &fv->value.time, field_display != ABSOLUTE_TIME_LOCAL); + } + break; + + default: + ws_assert_not_reached(); + break; + } + + return rep; +} + +static char * +relative_val_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_) +{ + return rel_time_to_secs_str(scope, &fv->value.time); +} + +static unsigned +time_hash(const fvalue_t *fv) +{ + return nstime_hash(&fv->value.time); +} + +static bool +time_is_zero(const fvalue_t *fv) +{ + return nstime_is_zero(&fv->value.time); +} + +static bool +time_is_negative(const fvalue_t *fv) +{ + return fv->value.time.secs < 0; +} + +static enum ft_result +time_unary_minus(fvalue_t * dst, const fvalue_t *src, char **err_ptr _U_) +{ + dst->value.time.secs = -src->value.time.secs; + dst->value.time.nsecs = -src->value.time.nsecs; + return FT_OK; +} + +#define NS_PER_S 1000000000 + +static void +check_ns_wraparound(nstime_t *ns, jmp_buf env) +{ + if (ns->nsecs >= NS_PER_S || (ns->nsecs > 0 && ns->secs < 0)) { + ws_safe_sub_jmp(&ns->nsecs, ns->nsecs, NS_PER_S, env); + ws_safe_add_jmp(&ns->secs, ns->secs, 1, env); + } + else if(ns->nsecs <= -NS_PER_S || (ns->nsecs < 0 && ns->secs > 0)) { + ws_safe_add_jmp(&ns->nsecs, ns->nsecs, NS_PER_S, env); + ws_safe_sub_jmp(&ns->secs, ns->secs, 1, env); + } +} + +static void +_nstime_add(nstime_t *res, nstime_t a, const nstime_t b, jmp_buf env) +{ + ws_safe_add_jmp(&res->secs, a.secs, b.secs, env); + ws_safe_add_jmp(&res->nsecs, a.nsecs, b.nsecs, env); + check_ns_wraparound(res, env); +} + +static void +_nstime_sub(nstime_t *res, nstime_t a, const nstime_t b, jmp_buf env) +{ + ws_safe_sub_jmp(&res->secs, a.secs, b.secs, env); + ws_safe_sub_jmp(&res->nsecs, a.nsecs, b.nsecs, env); + check_ns_wraparound(res, env); +} + +static enum ft_result +time_add(fvalue_t * dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr) +{ + jmp_buf env; + if (setjmp(env) != 0) { + *err_ptr = ws_strdup_printf("time_add: overflow"); + return FT_ERROR; + } + _nstime_add(&dst->value.time, a->value.time, b->value.time, env); + return FT_OK; +} + +static enum ft_result +time_subtract(fvalue_t * dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr) +{ + jmp_buf env; + if (setjmp(env) != 0) { + *err_ptr = ws_strdup_printf("time_subtract: overflow"); + return FT_ERROR; + } + _nstime_sub(&dst->value.time, a->value.time, b->value.time, env); + return FT_OK; +} + +void +ftype_register_time(void) +{ + + static ftype_t abstime_type = { + FT_ABSOLUTE_TIME, /* ftype */ + "FT_ABSOLUTE_TIME", /* name */ + "Date and time", /* pretty_name */ + 0, /* wire_size */ + time_fvalue_new, /* new_value */ + time_fvalue_copy, /* copy_value */ + NULL, /* free_value */ + absolute_val_from_literal, /* val_from_literal */ + absolute_val_from_string, /* val_from_string */ + NULL, /* val_from_charconst */ + absolute_val_to_repr, /* val_to_string_repr */ + + NULL, /* val_to_uinteger64 */ + NULL, /* val_to_sinteger64 */ + + { .set_value_time = time_fvalue_set }, /* union set_value */ + { .get_value_time = value_get }, /* union get_value */ + + cmp_order, + NULL, /* cmp_contains */ + NULL, /* cmp_matches */ + + time_hash, /* hash */ + time_is_zero, /* is_zero */ + time_is_negative, /* is_negative */ + NULL, + NULL, + NULL, /* bitwise_and */ + time_unary_minus, /* unary_minus */ + time_add, /* add */ + time_subtract, /* subtract */ + NULL, /* multiply */ + NULL, /* divide */ + NULL, /* modulo */ + }; + static ftype_t reltime_type = { + FT_RELATIVE_TIME, /* ftype */ + "FT_RELATIVE_TIME", /* name */ + "Time offset", /* pretty_name */ + 0, /* wire_size */ + time_fvalue_new, /* new_value */ + time_fvalue_copy, /* copy_value */ + NULL, /* free_value */ + relative_val_from_literal, /* val_from_literal */ + NULL, /* val_from_string */ + NULL, /* val_from_charconst */ + relative_val_to_repr, /* val_to_string_repr */ + + NULL, /* val_to_uinteger64 */ + NULL, /* val_to_sinteger64 */ + + { .set_value_time = time_fvalue_set }, /* union set_value */ + { .get_value_time = value_get }, /* union get_value */ + + cmp_order, + NULL, /* cmp_contains */ + NULL, /* cmp_matches */ + + time_hash, /* hash */ + time_is_zero, /* is_zero */ + time_is_negative, /* is_negative */ + NULL, + NULL, + NULL, /* bitwise_and */ + time_unary_minus, /* unary_minus */ + time_add, /* add */ + time_subtract, /* subtract */ + NULL, /* multiply */ + NULL, /* divide */ + NULL, /* modulo */ + }; + + ftype_register(FT_ABSOLUTE_TIME, &abstime_type); + ftype_register(FT_RELATIVE_TIME, &reltime_type); +} + +void +ftype_register_pseudofields_time(int proto) +{ + static int hf_ft_rel_time; + static int hf_ft_abs_time; + + static hf_register_info hf_ftypes[] = { + { &hf_ft_abs_time, + { "FT_ABSOLUTE_TIME", "_ws.ftypes.abs_time", + FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC, NULL, 0x00, + NULL, HFILL } + }, + { &hf_ft_rel_time, + { "FT_RELATIVE_TIME", "_ws.ftypes.rel_time", + FT_RELATIVE_TIME, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + }; + + proto_register_field_array(proto, hf_ftypes, array_length(hf_ftypes)); +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 8 + * tab-width: 8 + * indent-tabs-mode: t + * End: + * + * vi: set shiftwidth=8 tabstop=8 noexpandtab: + * :indentSize=8:tabSize=8:noTabs=false: + */ diff --git a/epan/ftypes/ftypes-int.h b/epan/ftypes/ftypes-int.h new file mode 100644 index 0000000..3dbd34e --- /dev/null +++ b/epan/ftypes/ftypes-int.h @@ -0,0 +1,205 @@ +/** @file + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 2001 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef FTYPES_INT_H +#define FTYPES_INT_H + +#include "ftypes.h" +#include <epan/proto.h> +#include <epan/packet.h> + +struct _fvalue_t { + ftype_t *ftype; + union { + /* Put a few basic types in here */ + uint32_t uinteger; + int32_t sinteger; + uint64_t uinteger64; + int64_t sinteger64; + double floating; + wmem_strbuf_t *strbuf; + GBytes *bytes; + ipv4_addr_and_mask ipv4; + ipv6_addr_and_prefix ipv6; + e_guid_t guid; + nstime_t time; + protocol_value_t protocol; + uint16_t sfloat_ieee_11073; + uint32_t float_ieee_11073; + } value; +}; + +extern ftype_t* type_list[FT_NUM_TYPES]; + +/* Given an ftenum number, return an ftype_t* */ +#define FTYPE_LOOKUP(ftype, result) \ + /* Check input */ \ + ws_assert(ftype < FT_NUM_TYPES); \ + result = type_list[ftype]; + +typedef void (*FvalueNewFunc)(fvalue_t*); +typedef void (*FvalueCopyFunc)(fvalue_t*, const fvalue_t*); +typedef void (*FvalueFreeFunc)(fvalue_t*); + +typedef bool (*FvalueFromLiteral)(fvalue_t*, const char*, bool, char **); +typedef bool (*FvalueFromString)(fvalue_t*, const char*, size_t, char **); +typedef bool (*FvalueFromCharConst)(fvalue_t*, unsigned long, char **); +typedef char *(*FvalueToStringRepr)(wmem_allocator_t *, const fvalue_t*, ftrepr_t, int field_display); + +typedef enum ft_result (*FvalueToUnsignedInteger64Func)(const fvalue_t*, uint64_t *); +typedef enum ft_result (*FvalueToSignedInteger64Func)(const fvalue_t*, int64_t *); + +typedef void (*FvalueSetBytesFunc)(fvalue_t*, GBytes *); +typedef void (*FvalueSetGuidFunc)(fvalue_t*, const e_guid_t *); +typedef void (*FvalueSetTimeFunc)(fvalue_t*, const nstime_t *); +typedef void (*FvalueSetStrbufFunc)(fvalue_t*, wmem_strbuf_t *); +typedef void (*FvalueSetProtocolFunc)(fvalue_t*, tvbuff_t *value, const char *name, int length); +typedef void (*FvalueSetUnsignedIntegerFunc)(fvalue_t*, uint32_t); +typedef void (*FvalueSetSignedIntegerFunc)(fvalue_t*, int32_t); +typedef void (*FvalueSetUnsignedInteger64Func)(fvalue_t*, uint64_t); +typedef void (*FvalueSetSignedInteger64Func)(fvalue_t*, int64_t); +typedef void (*FvalueSetFloatingFunc)(fvalue_t*, double); +typedef void (*FvalueSetIpv6)(fvalue_t*, const ws_in6_addr *); + +typedef GBytes *(*FvalueGetBytesFunc)(fvalue_t*); +typedef const e_guid_t *(*FvalueGetGuidFunc)(fvalue_t*); +typedef const nstime_t *(*FvalueGetTimeFunc)(fvalue_t*); +typedef const wmem_strbuf_t *(*FvalueGetStrbufFunc)(fvalue_t*); +typedef tvbuff_t *(*FvalueGetProtocolFunc)(fvalue_t*); +typedef uint32_t (*FvalueGetUnsignedIntegerFunc)(fvalue_t*); +typedef int32_t (*FvalueGetSignedIntegerFunc)(fvalue_t*); +typedef uint64_t (*FvalueGetUnsignedInteger64Func)(fvalue_t*); +typedef int64_t (*FvalueGetSignedInteger64Func)(fvalue_t*); +typedef double (*FvalueGetFloatingFunc)(fvalue_t*); +typedef const ws_in6_addr *(*FvalueGetIpv6)(fvalue_t*); + +typedef enum ft_result (*FvalueCmp)(const fvalue_t*, const fvalue_t*, int*); +typedef enum ft_result (*FvalueContains)(const fvalue_t*, const fvalue_t*, bool*); +typedef enum ft_result (*FvalueMatches)(const fvalue_t*, const ws_regex_t*, bool*); + +typedef bool (*FvalueIs)(const fvalue_t*); +typedef unsigned (*FvalueLen)(fvalue_t*); +typedef unsigned (*FvalueHashFunc)(const fvalue_t *); +typedef void (*FvalueSlice)(fvalue_t*, void *, unsigned offset, unsigned length); +typedef enum ft_result (*FvalueUnaryOp)(fvalue_t *, const fvalue_t*, char **); +typedef enum ft_result (*FvalueBinaryOp)(fvalue_t *, const fvalue_t*, const fvalue_t*, char **); + +struct _ftype_t { + ftenum_t ftype; + const char *name; + const char *pretty_name; + int wire_size; + FvalueNewFunc new_value; + FvalueCopyFunc copy_value; + FvalueFreeFunc free_value; + FvalueFromLiteral val_from_literal; + FvalueFromString val_from_string; + FvalueFromCharConst val_from_charconst; + FvalueToStringRepr val_to_string_repr; + + FvalueToUnsignedInteger64Func val_to_uinteger64; + FvalueToSignedInteger64Func val_to_sinteger64; + + union { + FvalueSetBytesFunc set_value_bytes; + FvalueSetGuidFunc set_value_guid; + FvalueSetTimeFunc set_value_time; + FvalueSetStrbufFunc set_value_strbuf; + FvalueSetProtocolFunc set_value_protocol; + FvalueSetUnsignedIntegerFunc set_value_uinteger; + FvalueSetSignedIntegerFunc set_value_sinteger; + FvalueSetUnsignedInteger64Func set_value_uinteger64; + FvalueSetSignedInteger64Func set_value_sinteger64; + FvalueSetFloatingFunc set_value_floating; + FvalueSetIpv6 set_value_ipv6; + } set_value; + + union { + FvalueGetBytesFunc get_value_bytes; + FvalueGetGuidFunc get_value_guid; + FvalueGetTimeFunc get_value_time; + FvalueGetStrbufFunc get_value_strbuf; + FvalueGetProtocolFunc get_value_protocol; + FvalueGetUnsignedIntegerFunc get_value_uinteger; + FvalueGetSignedIntegerFunc get_value_sinteger; + FvalueGetUnsignedInteger64Func get_value_uinteger64; + FvalueGetSignedInteger64Func get_value_sinteger64; + FvalueGetFloatingFunc get_value_floating; + FvalueGetIpv6 get_value_ipv6; + } get_value; + + FvalueCmp cmp_order; + FvalueContains cmp_contains; + FvalueMatches cmp_matches; + + FvalueHashFunc hash; + FvalueIs is_zero; + FvalueIs is_negative; + FvalueLen len; + FvalueSlice slice; + FvalueBinaryOp bitwise_and; + FvalueUnaryOp unary_minus; + FvalueBinaryOp add; + FvalueBinaryOp subtract; + FvalueBinaryOp multiply; + FvalueBinaryOp divide; + FvalueBinaryOp modulo; +}; + +void ftype_register(enum ftenum ftype, ftype_t *ft); + +void ftype_register_bytes(void); +void ftype_register_double(void); +void ftype_register_ieee_11073_float(void); +void ftype_register_integers(void); +void ftype_register_ipv4(void); +void ftype_register_ipv6(void); +void ftype_register_guid(void); +void ftype_register_none(void); +void ftype_register_string(void); +void ftype_register_time(void); +void ftype_register_tvbuff(void); + +/* For debugging. */ +void ftype_register_pseudofields_bytes(int proto); +void ftype_register_pseudofields_double(int proto); +void ftype_register_pseudofields_ieee_11073_float(int proto); +void ftype_register_pseudofields_integer(int proto); +void ftype_register_pseudofields_ipv4(int proto); +void ftype_register_pseudofields_ipv6(int proto); +void ftype_register_pseudofields_guid(int proto); +void ftype_register_pseudofields_none(int proto); +void ftype_register_pseudofields_string(int proto); +void ftype_register_pseudofields_time(int proto); +void ftype_register_pseudofields_tvbuff(int proto); + +GByteArray * +byte_array_from_literal(const char *s, char **err_msg); + +GByteArray * +byte_array_from_charconst(unsigned long num, char **err_msg); + +char * +bytes_to_dfilter_repr(wmem_allocator_t *scope, + const uint8_t *src, size_t src_size); + +#endif /* FTYPES_INT_H */ + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 8 + * tab-width: 8 + * indent-tabs-mode: t + * End: + * + * vi: set shiftwidth=8 tabstop=8 noexpandtab: + * :indentSize=8:tabSize=8:noTabs=false: + */ diff --git a/epan/ftypes/ftypes.c b/epan/ftypes/ftypes.c new file mode 100644 index 0000000..163a662 --- /dev/null +++ b/epan/ftypes/ftypes.c @@ -0,0 +1,1249 @@ +/* + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 2001 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include "ftypes-int.h" + +#include <wsutil/ws_assert.h> + +/* Keep track of ftype_t's via their ftenum number */ +ftype_t* type_list[FT_NUM_TYPES]; + +/* Initialize the ftype module. */ +void +ftypes_initialize(void) +{ + ftype_register_bytes(); + ftype_register_double(); + ftype_register_ieee_11073_float(); + ftype_register_integers(); + ftype_register_ipv4(); + ftype_register_ipv6(); + ftype_register_guid(); + ftype_register_none(); + ftype_register_string(); + ftype_register_time(); + ftype_register_tvbuff(); +} + +void +ftypes_register_pseudofields(void) +{ + static int proto_ftypes; + + proto_ftypes = proto_register_protocol( + "Wireshark Field/Fundamental Types", + "Wireshark FTypes", + "_ws.ftypes"); + + ftype_register_pseudofields_bytes(proto_ftypes); + ftype_register_pseudofields_double(proto_ftypes); + ftype_register_pseudofields_ieee_11073_float(proto_ftypes); + ftype_register_pseudofields_integer(proto_ftypes); + ftype_register_pseudofields_ipv4(proto_ftypes); + ftype_register_pseudofields_ipv6(proto_ftypes); + ftype_register_pseudofields_guid(proto_ftypes); + ftype_register_pseudofields_none(proto_ftypes); + ftype_register_pseudofields_string(proto_ftypes); + ftype_register_pseudofields_time(proto_ftypes); + ftype_register_pseudofields_tvbuff(proto_ftypes); + + proto_set_cant_toggle(proto_ftypes); +} + +/* Each ftype_t is registered via this function */ +void +ftype_register(enum ftenum ftype, ftype_t *ft) +{ + /* Check input */ + ws_assert(ftype < FT_NUM_TYPES); + ws_assert(ftype == ft->ftype); + + /* Don't re-register. */ + ws_assert(type_list[ftype] == NULL); + + type_list[ftype] = ft; +} + + +/* from README.dissector: + Note that the formats used must all belong to the same list as defined below: + - FT_INT8, FT_INT16, FT_INT24 and FT_INT32 + - FT_UINT8, FT_UINT16, FT_UINT24, FT_UINT32, FT_IPXNET and FT_FRAMENUM + - FT_UINT64 and FT_EUI64 + - FT_STRING, FT_STRINGZ and FT_UINT_STRING + - FT_FLOAT and FT_DOUBLE + - FT_BYTES, FT_UINT_BYTES, FT_AX25, FT_ETHER, FT_VINES, FT_OID and FT_REL_OID + - FT_ABSOLUTE_TIME and FT_RELATIVE_TIME +*/ +static enum ftenum +same_ftype(const enum ftenum ftype) +{ + switch (ftype) { + case FT_INT8: + case FT_INT16: + case FT_INT24: + case FT_INT32: + return FT_INT32; + + case FT_UINT8: + case FT_UINT16: + case FT_UINT24: + case FT_UINT32: + return FT_UINT32; + + case FT_INT40: + case FT_INT48: + case FT_INT56: + case FT_INT64: + return FT_INT64; + + case FT_UINT40: + case FT_UINT48: + case FT_UINT56: + case FT_UINT64: + return FT_UINT64; + + case FT_STRING: + case FT_STRINGZ: + case FT_UINT_STRING: + return FT_STRING; + + case FT_FLOAT: + case FT_DOUBLE: + return FT_DOUBLE; + + case FT_BYTES: + case FT_UINT_BYTES: + return FT_BYTES; + + case FT_OID: + case FT_REL_OID: + return FT_OID; + + /* XXX: the folowing are unique for now */ + case FT_IPv4: + case FT_IPv6: + + /* everything else is unique */ + default: + return ftype; + } +} + +/* given two types, are they similar - for example can two + * duplicate fields be registered of these two types. */ +bool +ftype_similar_types(const enum ftenum ftype_a, const enum ftenum ftype_b) +{ + return (same_ftype(ftype_a) == same_ftype(ftype_b)); +} + +/* Returns a string representing the name of the type. Useful + * for glossary production. */ +const char* +ftype_name(enum ftenum ftype) +{ + ftype_t *ft; + + FTYPE_LOOKUP(ftype, ft); + return ft->name; +} + +const char* +ftype_pretty_name(enum ftenum ftype) +{ + ftype_t *ft; + + FTYPE_LOOKUP(ftype, ft); + return ft->pretty_name; +} + +int +ftype_wire_size(enum ftenum ftype) +{ + ftype_t *ft; + + FTYPE_LOOKUP(ftype, ft); + return ft->wire_size; +} + +bool +ftype_can_length(enum ftenum ftype) +{ + ftype_t *ft; + + FTYPE_LOOKUP(ftype, ft); + return ft->len ? true : false; +} + +bool +ftype_can_slice(enum ftenum ftype) +{ + ftype_t *ft; + + FTYPE_LOOKUP(ftype, ft); + return ft->slice ? true : false; +} + +bool +ftype_can_eq(enum ftenum ftype) +{ + ftype_t *ft; + + FTYPE_LOOKUP(ftype, ft); + return ft->cmp_order != NULL; +} + +bool +ftype_can_cmp(enum ftenum ftype) +{ + ftype_t *ft; + + FTYPE_LOOKUP(ftype, ft); + return ft->cmp_order != NULL; +} + +bool +ftype_can_bitwise_and(enum ftenum ftype) +{ + ftype_t *ft; + + FTYPE_LOOKUP(ftype, ft); + return ft->bitwise_and ? true : false; +} + +bool +ftype_can_unary_minus(enum ftenum ftype) +{ + ftype_t *ft; + + FTYPE_LOOKUP(ftype, ft); + return ft->unary_minus != NULL; +} + +bool +ftype_can_add(enum ftenum ftype) +{ + ftype_t *ft; + + FTYPE_LOOKUP(ftype, ft); + return ft->add != NULL; +} + +bool +ftype_can_subtract(enum ftenum ftype) +{ + ftype_t *ft; + + FTYPE_LOOKUP(ftype, ft); + return ft->subtract != NULL; +} + +bool +ftype_can_multiply(enum ftenum ftype) +{ + ftype_t *ft; + + FTYPE_LOOKUP(ftype, ft); + return ft->multiply != NULL; +} + +bool +ftype_can_divide(enum ftenum ftype) +{ + ftype_t *ft; + + FTYPE_LOOKUP(ftype, ft); + return ft->divide != NULL; +} + +bool +ftype_can_modulo(enum ftenum ftype) +{ + ftype_t *ft; + + FTYPE_LOOKUP(ftype, ft); + return ft->modulo != NULL; +} + +bool +ftype_can_contains(enum ftenum ftype) +{ + ftype_t *ft; + + FTYPE_LOOKUP(ftype, ft); + return ft->cmp_contains ? true : false; +} + +bool +ftype_can_matches(enum ftenum ftype) +{ + ftype_t *ft; + + FTYPE_LOOKUP(ftype, ft); + return ft->cmp_matches ? true : false; +} + +bool +ftype_can_is_zero(enum ftenum ftype) +{ + ftype_t *ft; + + FTYPE_LOOKUP(ftype, ft); + return ft->is_zero ? true : false; +} + +bool +ftype_can_is_negative(enum ftenum ftype) +{ + ftype_t *ft; + + FTYPE_LOOKUP(ftype, ft); + return ft->is_negative ? true : false; +} + +bool +ftype_can_val_to_sinteger(enum ftenum ftype) +{ + ftype_t *ft; + + FTYPE_LOOKUP(ftype, ft); + /* We first convert to 64 bit and then check for overflow. */ + return ft->val_to_sinteger64 ? true : false; +} + +bool +ftype_can_val_to_uinteger(enum ftenum ftype) +{ + ftype_t *ft; + + FTYPE_LOOKUP(ftype, ft); + /* We first convert to 64 bit and then check for overflow. */ + return ft->val_to_uinteger64 ? true : false; +} + +bool +ftype_can_val_to_sinteger64(enum ftenum ftype) +{ + ftype_t *ft; + + FTYPE_LOOKUP(ftype, ft); + return ft->val_to_sinteger64 ? true : false; +} + +bool +ftype_can_val_to_uinteger64(enum ftenum ftype) +{ + ftype_t *ft; + + FTYPE_LOOKUP(ftype, ft); + return ft->val_to_uinteger64 ? true : false; +} + +/* ---------------------------------------------------------- */ + +/* Allocate and initialize an fvalue_t, given an ftype */ +fvalue_t* +fvalue_new(ftenum_t ftype) +{ + fvalue_t *fv; + ftype_t *ft; + FvalueNewFunc new_value; + + fv = g_slice_new(fvalue_t); + + FTYPE_LOOKUP(ftype, ft); + fv->ftype = ft; + + new_value = ft->new_value; + if (new_value) { + new_value(fv); + } + + return fv; +} + +fvalue_t* +fvalue_dup(const fvalue_t *fv_orig) +{ + fvalue_t *fv_new; + FvalueCopyFunc copy_value; + + fv_new = g_slice_new(fvalue_t); + fv_new->ftype = fv_orig->ftype; + copy_value = fv_new->ftype->copy_value; + if (copy_value != NULL) { + /* deep copy */ + copy_value(fv_new, fv_orig); + } + else { + /* shallow copy */ + memcpy(&fv_new->value, &fv_orig->value, sizeof(fv_orig->value)); + } + + return fv_new; +} + +void +fvalue_init(fvalue_t *fv, ftenum_t ftype) +{ + ftype_t *ft; + FvalueNewFunc new_value; + + FTYPE_LOOKUP(ftype, ft); + fv->ftype = ft; + + new_value = ft->new_value; + if (new_value) { + new_value(fv); + } +} + +void +fvalue_cleanup(fvalue_t *fv) +{ + if (!fv->ftype->free_value) + return; + fv->ftype->free_value(fv); +} + +void +fvalue_free(fvalue_t *fv) +{ + fvalue_cleanup(fv); + g_slice_free(fvalue_t, fv); +} + +fvalue_t* +fvalue_from_literal(ftenum_t ftype, const char *s, bool allow_partial_value, char **err_msg) +{ + fvalue_t *fv; + bool ok = false; + + fv = fvalue_new(ftype); + if (fv->ftype->val_from_literal) { + ok = fv->ftype->val_from_literal(fv, s, allow_partial_value, err_msg); + if (ok) { + /* Success */ + if (err_msg != NULL) + *err_msg = NULL; + return fv; + } + } + else { + if (err_msg != NULL) { + *err_msg = ws_strdup_printf("\"%s\" cannot be converted to %s.", + s, ftype_pretty_name(ftype)); + } + } + fvalue_free(fv); + return NULL; +} + +fvalue_t* +fvalue_from_string(ftenum_t ftype, const char *str, size_t len, char **err_msg) +{ + fvalue_t *fv; + + fv = fvalue_new(ftype); + if (fv->ftype->val_from_string) { + if (fv->ftype->val_from_string(fv, str, len, err_msg)) { + /* Success */ + if (err_msg != NULL) + *err_msg = NULL; + return fv; + } + } + else { + if (err_msg != NULL) { + *err_msg = ws_strdup_printf("%s cannot be converted from a string (\"%s\").", + ftype_pretty_name(ftype), str); + } + } + fvalue_free(fv); + return NULL; +} + +fvalue_t* +fvalue_from_charconst(ftenum_t ftype, unsigned long num, char **err_msg) +{ + fvalue_t *fv; + + fv = fvalue_new(ftype); + if (fv->ftype->val_from_charconst) { + if (fv->ftype->val_from_charconst(fv, num, err_msg)) { + /* Success */ + if (err_msg != NULL) + *err_msg = NULL; + return fv; + } + } + else { + if (err_msg != NULL) { + if (num <= 0x7f && g_ascii_isprint(num)) { + *err_msg = ws_strdup_printf("Character constant '%c' (0x%lx) cannot be converted to %s.", + (int)num, num, ftype_pretty_name(ftype)); + } + else { + *err_msg = ws_strdup_printf("Character constant 0x%lx cannot be converted to %s.", + num, ftype_pretty_name(ftype)); + } + } + } + fvalue_free(fv); + return NULL; +} + +ftenum_t +fvalue_type_ftenum(fvalue_t *fv) +{ + return fv->ftype->ftype; +} + +const char* +fvalue_type_name(const fvalue_t *fv) +{ + return fv->ftype->name; +} + + +size_t +fvalue_length2(fvalue_t *fv) +{ + if (!fv->ftype->len) { + ws_critical("fv->ftype->len is NULL"); + return 0; + } + return fv->ftype->len(fv); +} + +char * +fvalue_to_string_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype, int field_display) +{ + if (fv->ftype->val_to_string_repr == NULL) { + /* no value-to-string-representation function, so the value cannot be represented */ + return NULL; + } + + return fv->ftype->val_to_string_repr(scope, fv, rtype, field_display); +} + +enum ft_result +fvalue_to_uinteger(const fvalue_t *fv, uint32_t *repr) +{ + uint64_t val; + enum ft_result res = fv->ftype->val_to_uinteger64(fv, &val); + if (res != FT_OK) + return res; + if (val > UINT32_MAX) + return FT_OVERFLOW; + + *repr = (uint32_t)val; + return FT_OK; +} + +enum ft_result +fvalue_to_sinteger(const fvalue_t *fv, int32_t *repr) +{ + int64_t val; + enum ft_result res = fv->ftype->val_to_sinteger64(fv, &val); + if (res != FT_OK) + return res; + if (val > INT32_MAX) + return FT_OVERFLOW; + + *repr = (int32_t)val; + return FT_OK; +} + +enum ft_result +fvalue_to_uinteger64(const fvalue_t *fv, uint64_t *repr) +{ + return fv->ftype->val_to_uinteger64(fv, repr); +} + +enum ft_result +fvalue_to_sinteger64(const fvalue_t *fv, int64_t *repr) +{ + return fv->ftype->val_to_sinteger64(fv, repr); +} + +typedef struct { + fvalue_t *fv; + void *ptr; + bool slice_failure; +} slice_data_t; + +static bool +compute_drnode(size_t field_length, drange_node *drnode, size_t *offset_ptr, size_t *length_ptr) +{ + ssize_t start_offset; + ssize_t length = 0; + ssize_t end_offset = 0; + drange_node_end_t ending; + + start_offset = drange_node_get_start_offset(drnode); + ending = drange_node_get_ending(drnode); + + /* Check for negative start */ + if (start_offset < 0) { + start_offset = field_length + start_offset; + if (start_offset < 0) { + return false; + } + } + + /* Check the end type and set the length */ + + if (ending == DRANGE_NODE_END_T_TO_THE_END) { + length = field_length - start_offset; + if (length <= 0) { + return false; + } + } + else if (ending == DRANGE_NODE_END_T_LENGTH) { + length = drange_node_get_length(drnode); + if (start_offset + length > (int) field_length) { + return false; + } + } + else if (ending == DRANGE_NODE_END_T_OFFSET) { + end_offset = drange_node_get_end_offset(drnode); + if (end_offset < 0) { + end_offset = field_length + end_offset; + if (end_offset < start_offset) { + return false; + } + } else if (end_offset >= (int) field_length) { + return false; + } + length = end_offset - start_offset + 1; + } + else { + ws_assert_not_reached(); + } + + *offset_ptr = start_offset; + *length_ptr = length; + return true; +} + +static void +slice_func(void * data, void * user_data) +{ + drange_node *drnode = (drange_node *)data; + slice_data_t *slice_data = (slice_data_t *)user_data; + size_t start_offset; + size_t length = 0; + fvalue_t *fv; + + if (slice_data->slice_failure) { + return; + } + + fv = slice_data->fv; + if (!compute_drnode((unsigned)fvalue_length2(fv), drnode, &start_offset, &length)) { + slice_data->slice_failure = true; + return; + } + + ws_assert(length > 0); + fv->ftype->slice(fv, slice_data->ptr, (unsigned)start_offset, (unsigned)length); +} + +static fvalue_t * +slice_string(fvalue_t *fv, drange_t *d_range) +{ + slice_data_t slice_data; + fvalue_t *new_fv; + + slice_data.fv = fv; + slice_data.ptr = wmem_strbuf_create(NULL); + slice_data.slice_failure = false; + + /* XXX - We could make some optimizations here based on + * drange_has_total_length() and + * drange_get_max_offset(). + */ + + drange_foreach_drange_node(d_range, slice_func, &slice_data); + + new_fv = fvalue_new(FT_STRING); + fvalue_set_strbuf(new_fv, slice_data.ptr); + return new_fv; +} + +static fvalue_t * +slice_bytes(fvalue_t *fv, drange_t *d_range) +{ + slice_data_t slice_data; + fvalue_t *new_fv; + + slice_data.fv = fv; + slice_data.ptr = g_byte_array_new(); + slice_data.slice_failure = false; + + /* XXX - We could make some optimizations here based on + * drange_has_total_length() and + * drange_get_max_offset(). + */ + + drange_foreach_drange_node(d_range, slice_func, &slice_data); + + new_fv = fvalue_new(FT_BYTES); + fvalue_set_byte_array(new_fv, slice_data.ptr); + return new_fv; +} + +/* Returns a new slice fvalue_t* if possible, otherwise NULL */ +fvalue_t* +fvalue_slice(fvalue_t *fv, drange_t *d_range) +{ + if (FT_IS_STRING(fvalue_type_ftenum(fv))) { + return slice_string(fv, d_range); + } + return slice_bytes(fv, d_range); +} + +void +fvalue_set_bytes(fvalue_t *fv, GBytes *value) +{ + ws_assert(fv->ftype->ftype == FT_BYTES || + fv->ftype->ftype == FT_UINT_BYTES || + fv->ftype->ftype == FT_OID || + fv->ftype->ftype == FT_REL_OID || + fv->ftype->ftype == FT_SYSTEM_ID || + fv->ftype->ftype == FT_AX25 || + fv->ftype->ftype == FT_VINES || + fv->ftype->ftype == FT_ETHER || + fv->ftype->ftype == FT_FCWWN); + ws_assert(fv->ftype->set_value.set_value_bytes); + fv->ftype->set_value.set_value_bytes(fv, value); +} + +void +fvalue_set_byte_array(fvalue_t *fv, GByteArray *value) +{ + GBytes *bytes = g_byte_array_free_to_bytes(value); + fvalue_set_bytes(fv, bytes); + g_bytes_unref(bytes); +} + +void +fvalue_set_bytes_data(fvalue_t *fv, const void *data, size_t size) +{ + GBytes *bytes = g_bytes_new(data, size); + fvalue_set_bytes(fv, bytes); + g_bytes_unref(bytes); +} + +void +fvalue_set_fcwwn(fvalue_t *fv, const uint8_t *value) +{ + GBytes *bytes = g_bytes_new(value, FT_FCWWN_LEN); + fvalue_set_bytes(fv, bytes); + g_bytes_unref(bytes); +} + +void +fvalue_set_ax25(fvalue_t *fv, const uint8_t *value) +{ + GBytes *bytes = g_bytes_new(value, FT_AX25_ADDR_LEN); + fvalue_set_bytes(fv, bytes); + g_bytes_unref(bytes); +} + +void +fvalue_set_vines(fvalue_t *fv, const uint8_t *value) +{ + GBytes *bytes = g_bytes_new(value, FT_VINES_ADDR_LEN); + fvalue_set_bytes(fv, bytes); + g_bytes_unref(bytes); +} + +void +fvalue_set_ether(fvalue_t *fv, const uint8_t *value) +{ + GBytes *bytes = g_bytes_new(value, FT_ETHER_LEN); + fvalue_set_bytes(fv, bytes); + g_bytes_unref(bytes); +} + +void +fvalue_set_guid(fvalue_t *fv, const e_guid_t *value) +{ + ws_assert(fv->ftype->ftype == FT_GUID); + ws_assert(fv->ftype->set_value.set_value_guid); + fv->ftype->set_value.set_value_guid(fv, value); +} + +void +fvalue_set_time(fvalue_t *fv, const nstime_t *value) +{ + ws_assert(FT_IS_TIME(fv->ftype->ftype)); + ws_assert(fv->ftype->set_value.set_value_time); + fv->ftype->set_value.set_value_time(fv, value); +} + +void +fvalue_set_string(fvalue_t *fv, const char *value) +{ + wmem_strbuf_t *buf = wmem_strbuf_new(NULL, value); + fvalue_set_strbuf(fv, buf); +} + +void +fvalue_set_strbuf(fvalue_t *fv, wmem_strbuf_t *value) +{ + if (value->allocator != NULL) { + /* XXX Can this condition be relaxed? */ + ws_critical("Fvalue strbuf allocator must be NULL"); + } + ws_assert(FT_IS_STRING(fv->ftype->ftype)); + ws_assert(fv->ftype->set_value.set_value_strbuf); + fv->ftype->set_value.set_value_strbuf(fv, value); +} + +void +fvalue_set_protocol(fvalue_t *fv, tvbuff_t *value, const char *name, int length) +{ + ws_assert(fv->ftype->ftype == FT_PROTOCOL); + ws_assert(fv->ftype->set_value.set_value_protocol); + fv->ftype->set_value.set_value_protocol(fv, value, name, length); +} + +void +fvalue_set_uinteger(fvalue_t *fv, uint32_t value) +{ + ws_assert(fv->ftype->ftype == FT_IEEE_11073_SFLOAT || + fv->ftype->ftype == FT_IEEE_11073_FLOAT || + fv->ftype->ftype == FT_CHAR || + fv->ftype->ftype == FT_UINT8 || + fv->ftype->ftype == FT_UINT16 || + fv->ftype->ftype == FT_UINT24 || + fv->ftype->ftype == FT_UINT32 || + fv->ftype->ftype == FT_IPXNET || + fv->ftype->ftype == FT_FRAMENUM || + fv->ftype->ftype == FT_IPv4); + ws_assert(fv->ftype->set_value.set_value_uinteger); + fv->ftype->set_value.set_value_uinteger(fv, value); +} + +void +fvalue_set_sinteger(fvalue_t *fv, int32_t value) +{ + ws_assert(fv->ftype->ftype == FT_INT8 || + fv->ftype->ftype == FT_INT16 || + fv->ftype->ftype == FT_INT24 || + fv->ftype->ftype == FT_INT32); + ws_assert(fv->ftype->set_value.set_value_sinteger); + fv->ftype->set_value.set_value_sinteger(fv, value); +} + +void +fvalue_set_uinteger64(fvalue_t *fv, uint64_t value) +{ + ws_assert(fv->ftype->ftype == FT_UINT40 || + fv->ftype->ftype == FT_UINT48 || + fv->ftype->ftype == FT_UINT56 || + fv->ftype->ftype == FT_UINT64 || + fv->ftype->ftype == FT_BOOLEAN || + fv->ftype->ftype == FT_EUI64); + ws_assert(fv->ftype->set_value.set_value_uinteger64); + fv->ftype->set_value.set_value_uinteger64(fv, value); +} + +void +fvalue_set_sinteger64(fvalue_t *fv, int64_t value) +{ + ws_assert(fv->ftype->ftype == FT_INT40 || + fv->ftype->ftype == FT_INT48 || + fv->ftype->ftype == FT_INT56 || + fv->ftype->ftype == FT_INT64); + ws_assert(fv->ftype->set_value.set_value_sinteger64); + fv->ftype->set_value.set_value_sinteger64(fv, value); +} + +void +fvalue_set_floating(fvalue_t *fv, double value) +{ + ws_assert(fv->ftype->ftype == FT_FLOAT || + fv->ftype->ftype == FT_DOUBLE); + ws_assert(fv->ftype->set_value.set_value_floating); + fv->ftype->set_value.set_value_floating(fv, value); +} + +void +fvalue_set_ipv6(fvalue_t *fv, const ws_in6_addr *value) +{ + ws_assert(fv->ftype->ftype == FT_IPv6); + ws_assert(fv->ftype->set_value.set_value_ipv6); + fv->ftype->set_value.set_value_ipv6(fv, value); +} + +GBytes * +fvalue_get_bytes(fvalue_t *fv) +{ + ws_assert(fv->ftype->ftype == FT_BYTES || + fv->ftype->ftype == FT_UINT_BYTES || + fv->ftype->ftype == FT_AX25 || + fv->ftype->ftype == FT_VINES || + fv->ftype->ftype == FT_ETHER || + fv->ftype->ftype == FT_OID || + fv->ftype->ftype == FT_REL_OID || + fv->ftype->ftype == FT_SYSTEM_ID || + fv->ftype->ftype == FT_FCWWN || + fv->ftype->ftype == FT_IPv6); + ws_assert(fv->ftype->get_value.get_value_bytes); + return fv->ftype->get_value.get_value_bytes(fv); +} + +size_t +fvalue_get_bytes_size(fvalue_t *fv) +{ + GBytes *bytes = fvalue_get_bytes(fv); + size_t size = g_bytes_get_size(bytes); + g_bytes_unref(bytes); + return size; +} + +const void * +fvalue_get_bytes_data(fvalue_t *fv) +{ + GBytes *bytes = fvalue_get_bytes(fv); + const void *data = g_bytes_get_data(bytes, NULL); + g_bytes_unref(bytes); + return data; +} + +const e_guid_t * +fvalue_get_guid(fvalue_t *fv) +{ + ws_assert(fv->ftype->ftype == FT_GUID); + ws_assert(fv->ftype->get_value.get_value_guid); + return fv->ftype->get_value.get_value_guid(fv); +} + +const nstime_t * +fvalue_get_time(fvalue_t *fv) +{ + ws_assert(FT_IS_TIME(fv->ftype->ftype)); + ws_assert(fv->ftype->get_value.get_value_time); + return fv->ftype->get_value.get_value_time(fv); +} + +const char * +fvalue_get_string(fvalue_t *fv) +{ + return wmem_strbuf_get_str(fvalue_get_strbuf(fv)); +} + +const wmem_strbuf_t * +fvalue_get_strbuf(fvalue_t *fv) +{ + ws_assert(FT_IS_STRING(fv->ftype->ftype)); + ws_assert(fv->ftype->get_value.get_value_strbuf); + return fv->ftype->get_value.get_value_strbuf(fv); +} + +tvbuff_t * +fvalue_get_protocol(fvalue_t *fv) +{ + ws_assert(fv->ftype->ftype == FT_PROTOCOL); + ws_assert(fv->ftype->get_value.get_value_protocol); + return fv->ftype->get_value.get_value_protocol(fv); +} + +uint32_t +fvalue_get_uinteger(fvalue_t *fv) +{ + ws_assert(fv->ftype->ftype == FT_IEEE_11073_SFLOAT || + fv->ftype->ftype == FT_IEEE_11073_FLOAT || + fv->ftype->ftype == FT_CHAR || + fv->ftype->ftype == FT_UINT8 || + fv->ftype->ftype == FT_UINT16 || + fv->ftype->ftype == FT_UINT24 || + fv->ftype->ftype == FT_UINT32 || + fv->ftype->ftype == FT_IPXNET || + fv->ftype->ftype == FT_FRAMENUM || + fv->ftype->ftype == FT_IPv4); + ws_assert(fv->ftype->get_value.get_value_uinteger); + return fv->ftype->get_value.get_value_uinteger(fv); +} + +int32_t +fvalue_get_sinteger(fvalue_t *fv) +{ + ws_assert(fv->ftype->ftype == FT_INT8 || + fv->ftype->ftype == FT_INT16 || + fv->ftype->ftype == FT_INT24 || + fv->ftype->ftype == FT_INT32); + ws_assert(fv->ftype->get_value.get_value_sinteger); + return fv->ftype->get_value.get_value_sinteger(fv); +} + +uint64_t +fvalue_get_uinteger64(fvalue_t *fv) +{ + ws_assert(fv->ftype->ftype == FT_UINT40 || + fv->ftype->ftype == FT_UINT48 || + fv->ftype->ftype == FT_UINT56 || + fv->ftype->ftype == FT_UINT64 || + fv->ftype->ftype == FT_BOOLEAN || + fv->ftype->ftype == FT_EUI64); + ws_assert(fv->ftype->get_value.get_value_uinteger64); + return fv->ftype->get_value.get_value_uinteger64(fv); +} + +int64_t +fvalue_get_sinteger64(fvalue_t *fv) +{ + ws_assert(fv->ftype->ftype == FT_INT40 || + fv->ftype->ftype == FT_INT48 || + fv->ftype->ftype == FT_INT56 || + fv->ftype->ftype == FT_INT64); + ws_assert(fv->ftype->get_value.get_value_sinteger64); + return fv->ftype->get_value.get_value_sinteger64(fv); +} + +double +fvalue_get_floating(fvalue_t *fv) +{ + ws_assert(fv->ftype->ftype == FT_FLOAT || + fv->ftype->ftype == FT_DOUBLE); + ws_assert(fv->ftype->get_value.get_value_floating); + return fv->ftype->get_value.get_value_floating(fv); +} + +WS_DLL_PUBLIC const ws_in6_addr * +fvalue_get_ipv6(fvalue_t *fv) +{ + ws_assert(fv->ftype->ftype == FT_IPv6); + ws_assert(fv->ftype->get_value.get_value_ipv6); + return fv->ftype->get_value.get_value_ipv6(fv); +} + +ft_bool_t +fvalue_eq(const fvalue_t *a, const fvalue_t *b) +{ + int cmp; + enum ft_result res; + + ws_assert(a->ftype->cmp_order); + res = a->ftype->cmp_order(a, b, &cmp); + if (res != FT_OK) + return -res; + return cmp == 0 ? FT_TRUE : FT_FALSE; +} + +ft_bool_t +fvalue_ne(const fvalue_t *a, const fvalue_t *b) +{ + int cmp; + enum ft_result res; + + ws_assert(a->ftype->cmp_order); + res = a->ftype->cmp_order(a, b, &cmp); + if (res != FT_OK) + return -res; + return cmp != 0 ? FT_TRUE : FT_FALSE; +} + +ft_bool_t +fvalue_gt(const fvalue_t *a, const fvalue_t *b) +{ + int cmp; + enum ft_result res; + + ws_assert(a->ftype->cmp_order); + res = a->ftype->cmp_order(a, b, &cmp); + if (res != FT_OK) + return -res; + return cmp > 0 ? FT_TRUE : FT_FALSE; +} + +ft_bool_t +fvalue_ge(const fvalue_t *a, const fvalue_t *b) +{ + int cmp; + enum ft_result res; + + ws_assert(a->ftype->cmp_order); + res = a->ftype->cmp_order(a, b, &cmp); + if (res != FT_OK) + return -res; + return cmp >= 0 ? FT_TRUE : FT_FALSE; +} + +ft_bool_t +fvalue_lt(const fvalue_t *a, const fvalue_t *b) +{ + int cmp; + enum ft_result res; + + ws_assert(a->ftype->cmp_order); + res = a->ftype->cmp_order(a, b, &cmp); + if (res != FT_OK) + return -res; + return cmp < 0 ? FT_TRUE : FT_FALSE; +} + +ft_bool_t +fvalue_le(const fvalue_t *a, const fvalue_t *b) +{ + int cmp; + enum ft_result res; + + ws_assert(a->ftype->cmp_order); + res = a->ftype->cmp_order(a, b, &cmp); + if (res != FT_OK) + return -res; + return cmp <= 0 ? FT_TRUE : FT_FALSE; +} + +ft_bool_t +fvalue_contains(const fvalue_t *a, const fvalue_t *b) +{ + bool yes; + enum ft_result res; + + ws_assert(a->ftype->cmp_contains); + res = a->ftype->cmp_contains(a, b, &yes); + if (res != FT_OK) + return -res; + return yes ? FT_TRUE : FT_FALSE; +} + +ft_bool_t +fvalue_matches(const fvalue_t *a, const ws_regex_t *re) +{ + bool yes; + enum ft_result res; + + ws_assert(a->ftype->cmp_matches); + res = a->ftype->cmp_matches(a, re, &yes); + if (res != FT_OK) + return -res; + return yes ? FT_TRUE : FT_FALSE; +} + +bool +fvalue_is_zero(const fvalue_t *a) +{ + return a->ftype->is_zero(a); +} + +bool +fvalue_is_negative(const fvalue_t *a) +{ + return a->ftype->is_negative(a); +} + +static fvalue_t * +_fvalue_binop(FvalueBinaryOp op, const fvalue_t *a, const fvalue_t *b, char **err_msg) +{ + fvalue_t *result; + + result = fvalue_new(a->ftype->ftype); + if (op(result, a, b, err_msg) != FT_OK) { + fvalue_free(result); + return NULL; + } + return result; +} + +fvalue_t * +fvalue_bitwise_and(const fvalue_t *a, const fvalue_t *b, char **err_msg) +{ + /* XXX - check compatibility of a and b */ + ws_assert(a->ftype->bitwise_and); + return _fvalue_binop(a->ftype->bitwise_and, a, b, err_msg); +} + +fvalue_t * +fvalue_add(const fvalue_t *a, const fvalue_t *b, char **err_msg) +{ + /* XXX - check compatibility of a and b */ + ws_assert(a->ftype->add); + return _fvalue_binop(a->ftype->add, a, b, err_msg); +} + +fvalue_t * +fvalue_subtract(const fvalue_t *a, const fvalue_t *b, char **err_msg) +{ + /* XXX - check compatibility of a and b */ + ws_assert(a->ftype->subtract); + return _fvalue_binop(a->ftype->subtract, a, b, err_msg); +} + +fvalue_t * +fvalue_multiply(const fvalue_t *a, const fvalue_t *b, char **err_msg) +{ + /* XXX - check compatibility of a and b */ + ws_assert(a->ftype->multiply); + return _fvalue_binop(a->ftype->multiply, a, b, err_msg); +} + +fvalue_t * +fvalue_divide(const fvalue_t *a, const fvalue_t *b, char **err_msg) +{ + /* XXX - check compatibility of a and b */ + ws_assert(a->ftype->divide); + return _fvalue_binop(a->ftype->divide, a, b, err_msg); +} + +fvalue_t * +fvalue_modulo(const fvalue_t *a, const fvalue_t *b, char **err_msg) +{ + /* XXX - check compatibility of a and b */ + ws_assert(a->ftype->modulo); + return _fvalue_binop(a->ftype->modulo, a, b, err_msg); +} + +fvalue_t* +fvalue_unary_minus(const fvalue_t *fv, char **err_msg) +{ + fvalue_t *result; + + ws_assert(fv->ftype->unary_minus); + + result = fvalue_new(fv->ftype->ftype); + if (fv->ftype->unary_minus(result, fv, err_msg) != FT_OK) { + fvalue_free(result); + return NULL; + } + return result; +} + +unsigned +fvalue_hash(const fvalue_t *fv) +{ + ws_assert(fv->ftype->hash); + return fv->ftype->hash(fv); +} + +bool +fvalue_equal(const fvalue_t *a, const fvalue_t *b) +{ + return fvalue_eq(a, b) == FT_TRUE; +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 8 + * tab-width: 8 + * indent-tabs-mode: t + * End: + * + * vi: set shiftwidth=8 tabstop=8 noexpandtab: + * :indentSize=8:tabSize=8:noTabs=false: + */ diff --git a/epan/ftypes/ftypes.h b/epan/ftypes/ftypes.h new file mode 100644 index 0000000..c8e81b3 --- /dev/null +++ b/epan/ftypes/ftypes.h @@ -0,0 +1,539 @@ +/** @file + * Definitions for field types + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 2001 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + + +#ifndef __FTYPES_H__ +#define __FTYPES_H__ + +#include <wireshark.h> + +#include <wsutil/regex.h> +#include <epan/wmem_scopes.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* field types */ +enum ftenum { + FT_NONE, /* used for text labels with no value */ + FT_PROTOCOL, + FT_BOOLEAN, /* true and false come from <glib.h> */ + FT_CHAR, /* 1-octet character as 0-255 */ + FT_UINT8, + FT_UINT16, + FT_UINT24, /* really a UINT32, but displayed as 6 hex-digits if FD_HEX*/ + FT_UINT32, + FT_UINT40, /* really a UINT64, but displayed as 10 hex-digits if FD_HEX*/ + FT_UINT48, /* really a UINT64, but displayed as 12 hex-digits if FD_HEX*/ + FT_UINT56, /* really a UINT64, but displayed as 14 hex-digits if FD_HEX*/ + FT_UINT64, + FT_INT8, + FT_INT16, + FT_INT24, /* same as for UINT24 */ + FT_INT32, + FT_INT40, /* same as for UINT40 */ + FT_INT48, /* same as for UINT48 */ + FT_INT56, /* same as for UINT56 */ + FT_INT64, + FT_IEEE_11073_SFLOAT, + FT_IEEE_11073_FLOAT, + FT_FLOAT, + FT_DOUBLE, + FT_ABSOLUTE_TIME, + FT_RELATIVE_TIME, + FT_STRING, /* counted string, with no null terminator */ + FT_STRINGZ, /* null-terminated string */ + FT_UINT_STRING, /* counted string, with count being the first part of the value */ + FT_ETHER, + FT_BYTES, + FT_UINT_BYTES, + FT_IPv4, + FT_IPv6, + FT_IPXNET, + FT_FRAMENUM, /* a UINT32, but if selected lets you go to frame with that number */ + FT_GUID, /* GUID, UUID */ + FT_OID, /* OBJECT IDENTIFIER */ + FT_EUI64, + FT_AX25, + FT_VINES, + FT_REL_OID, /* RELATIVE-OID */ + FT_SYSTEM_ID, + FT_STRINGZPAD, /* null-padded string */ + FT_FCWWN, + FT_STRINGZTRUNC, /* null-truncated string */ + FT_NUM_TYPES /* last item number plus one */ +}; + +#define FT_IS_INT32(ft) \ + ((ft) == FT_INT8 || \ + (ft) == FT_INT16 || \ + (ft) == FT_INT24 || \ + (ft) == FT_INT32) + +#define FT_IS_INT64(ft) \ + ((ft) == FT_INT40 || \ + (ft) == FT_INT48 || \ + (ft) == FT_INT56 || \ + (ft) == FT_INT64) + +#define FT_IS_INT(ft) (FT_IS_INT32(ft) || FT_IS_INT64(ft)) + +#define FT_IS_UINT32(ft) \ + ((ft) == FT_CHAR || \ + (ft) == FT_UINT8 || \ + (ft) == FT_UINT16 || \ + (ft) == FT_UINT24 || \ + (ft) == FT_UINT32 || \ + (ft) == FT_FRAMENUM) + +#define FT_IS_UINT64(ft) \ + ((ft) == FT_UINT40 || \ + (ft) == FT_UINT48 || \ + (ft) == FT_UINT56 || \ + (ft) == FT_UINT64) + +#define FT_IS_UINT(ft) (FT_IS_UINT32(ft) || FT_IS_UINT64(ft)) + +#define FT_IS_INTEGER(ft) (FT_IS_INT(ft) || FT_IS_UINT(ft)) + +#define FT_IS_FLOATING(ft) ((ft) == FT_FLOAT || (ft) == FT_DOUBLE) + +#define FT_IS_TIME(ft) \ + ((ft) == FT_ABSOLUTE_TIME || (ft) == FT_RELATIVE_TIME) + +#define FT_IS_STRING(ft) \ + ((ft) == FT_STRING || (ft) == FT_STRINGZ || (ft) == FT_STRINGZPAD || \ + (ft) == FT_STRINGZTRUNC || (ft) == FT_UINT_STRING) + +/* field types lengths */ +#define FT_ETHER_LEN 6 +#define FT_GUID_LEN 16 +#define FT_IPv4_LEN 4 +#define FT_IPv6_LEN 16 +#define FT_IPXNET_LEN 4 +#define FT_EUI64_LEN 8 +#define FT_AX25_ADDR_LEN 7 +#define FT_VINES_ADDR_LEN 6 +#define FT_FCWWN_LEN 8 +#define FT_VARINT_MAX_LEN 10 /* Because 64 / 7 = 9 and 64 % 7 = 1, get an uint64 varint need reads up to 10 bytes. */ + +typedef enum ftenum ftenum_t; + +enum ft_framenum_type { + FT_FRAMENUM_NONE, + FT_FRAMENUM_REQUEST, + FT_FRAMENUM_RESPONSE, + FT_FRAMENUM_ACK, + FT_FRAMENUM_DUP_ACK, + FT_FRAMENUM_RETRANS_PREV, + FT_FRAMENUM_RETRANS_NEXT, + FT_FRAMENUM_NUM_TYPES /* last item number plus one */ +}; + +typedef enum ft_framenum_type ft_framenum_type_t; + +struct _ftype_t; +typedef struct _ftype_t ftype_t; + +enum ft_result { + FT_OK = 0, + FT_OVERFLOW, + FT_BADARG, + FT_ERROR, /* Generic. */ +}; + +/* + * True, false or error if negative. + * Note that + * ft_bool == FT_FALSE + * and + * ft_bool != FT_TRUE + * are different results (three-state logic). + */ +typedef bool ft_bool_t; +#define FT_TRUE 1 +#define FT_FALSE 0 + +/* String representation types. */ +enum ftrepr { + FTREPR_DISPLAY, + FTREPR_DFILTER, + FTREPR_JSON, +}; + +typedef enum ftrepr ftrepr_t; + +/* Initialize the ftypes subsystem. Called once. */ +void +ftypes_initialize(void); + +void +ftypes_register_pseudofields(void); + +/* ---------------- FTYPE ----------------- */ + +/* given two types, are they similar - for example can two + * duplicate fields be registered of these two types. */ +bool +ftype_similar_types(const enum ftenum ftype_a, const enum ftenum ftype_b); + +/* Return a string representing the name of the type */ +WS_DLL_PUBLIC +const char* +ftype_name(ftenum_t ftype); + +/* Return a string presenting a "pretty" representation of the + * name of the type. The pretty name means more to the user than + * that "FT_*" name. */ +WS_DLL_PUBLIC +const char* +ftype_pretty_name(ftenum_t ftype); + +/* Returns length of field in packet, or 0 if not determinable/defined. */ +int +ftype_wire_size(ftenum_t ftype); + +bool +ftype_can_length(enum ftenum ftype); + +WS_DLL_PUBLIC +bool +ftype_can_slice(enum ftenum ftype); + +WS_DLL_PUBLIC +bool +ftype_can_eq(enum ftenum ftype); + +WS_DLL_PUBLIC +bool +ftype_can_cmp(enum ftenum ftype); + +bool +ftype_can_bitwise_and(enum ftenum ftype); + +bool +ftype_can_unary_minus(enum ftenum ftype); + +bool +ftype_can_add(enum ftenum ftype); + +bool +ftype_can_subtract(enum ftenum ftype); + +bool +ftype_can_multiply(enum ftenum ftype); + +bool +ftype_can_divide(enum ftenum ftype); + +bool +ftype_can_modulo(enum ftenum ftype); + +WS_DLL_PUBLIC +bool +ftype_can_contains(enum ftenum ftype); + +WS_DLL_PUBLIC +bool +ftype_can_matches(enum ftenum ftype); + +WS_DLL_PUBLIC +bool +ftype_can_is_zero(enum ftenum ftype); + +WS_DLL_PUBLIC +bool +ftype_can_is_negative(enum ftenum ftype); + +WS_DLL_PUBLIC +bool +ftype_can_val_to_sinteger(enum ftenum ftype); + +WS_DLL_PUBLIC +bool +ftype_can_val_to_uinteger(enum ftenum ftype); + +WS_DLL_PUBLIC +bool +ftype_can_val_to_sinteger64(enum ftenum ftype); + +WS_DLL_PUBLIC +bool +ftype_can_val_to_uinteger64(enum ftenum ftype); + +/* ---------------- FVALUE ----------------- */ + +#include <epan/ipv4.h> +#include <epan/ipv6.h> +#include <epan/guid-utils.h> + +#include <epan/tvbuff.h> +#include <wsutil/nstime.h> +#include <epan/dfilter/drange.h> + +typedef struct _protocol_value_t +{ + tvbuff_t *tvb; + int length; + char *proto_string; + bool tvb_is_private; +} protocol_value_t; + +typedef struct _fvalue_t fvalue_t; + +fvalue_t* +fvalue_new(ftenum_t ftype); + +fvalue_t* +fvalue_dup(const fvalue_t *fv); + +void +fvalue_init(fvalue_t *fv, ftenum_t ftype); + +void +fvalue_cleanup(fvalue_t *fv); + +void +fvalue_free(fvalue_t *fv); + +WS_DLL_PUBLIC +fvalue_t* +fvalue_from_literal(ftenum_t ftype, const char *s, bool allow_partial_value, char **err_msg); + +/* String *MUST* be null-terminated. Length is optional (pass zero) and does not include the null terminator. */ +fvalue_t* +fvalue_from_string(ftenum_t ftype, const char *s, size_t len, char **err_msg); + +fvalue_t* +fvalue_from_charconst(ftenum_t ftype, unsigned long number, char **err_msg); + +/* Creates the string representation of the field value. + * Memory for the buffer is allocated based on wmem allocator + * provided. + * + * field_display parameter should be a BASE_ value (enum field_display_e) + * BASE_NONE should be used if field information isn't available. + * + * Returns NULL if the string cannot be represented in the given rtype.*/ +WS_DLL_PUBLIC char * +fvalue_to_string_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype, int field_display); + +#define fvalue_to_debug_repr(scope, fv) \ + fvalue_to_string_repr(scope, fv, FTREPR_DFILTER, 0) + +WS_DLL_PUBLIC enum ft_result +fvalue_to_uinteger(const fvalue_t *fv, uint32_t *repr); + +WS_DLL_PUBLIC enum ft_result +fvalue_to_sinteger(const fvalue_t *fv, int32_t *repr); + +WS_DLL_PUBLIC enum ft_result +fvalue_to_uinteger64(const fvalue_t *fv, uint64_t *repr); + +WS_DLL_PUBLIC enum ft_result +fvalue_to_sinteger64(const fvalue_t *fv, int64_t *repr); + +WS_DLL_PUBLIC ftenum_t +fvalue_type_ftenum(fvalue_t *fv); + +const char* +fvalue_type_name(const fvalue_t *fv); + +/* GBytes reference count is automatically incremented. */ +void +fvalue_set_bytes(fvalue_t *fv, GBytes *value); + +void +fvalue_set_byte_array(fvalue_t *fv, GByteArray *value); + +void +fvalue_set_bytes_data(fvalue_t *fv, const void *data, size_t size); + +void +fvalue_set_fcwwn(fvalue_t *fv, const uint8_t *value); + +void +fvalue_set_ax25(fvalue_t *fv, const uint8_t *value); + +void +fvalue_set_vines(fvalue_t *fv, const uint8_t *value); + +void +fvalue_set_ether(fvalue_t *fv, const uint8_t *value); + +void +fvalue_set_guid(fvalue_t *fv, const e_guid_t *value); + +void +fvalue_set_time(fvalue_t *fv, const nstime_t *value); + +void +fvalue_set_string(fvalue_t *fv, const char *value); + +void +fvalue_set_strbuf(fvalue_t *fv, wmem_strbuf_t *value); + +void +fvalue_set_protocol(fvalue_t *fv, tvbuff_t *value, const char *name, int length); + +void +fvalue_set_uinteger(fvalue_t *fv, uint32_t value); + +void +fvalue_set_sinteger(fvalue_t *fv, int32_t value); + +void +fvalue_set_uinteger64(fvalue_t *fv, uint64_t value); + +void +fvalue_set_sinteger64(fvalue_t *fv, int64_t value); + +void +fvalue_set_floating(fvalue_t *fv, double value); + +void +fvalue_set_ipv6(fvalue_t *fv, const ws_in6_addr *value); + +/* GBytes reference count is automatically incremented. */ +WS_DLL_PUBLIC +GBytes * +fvalue_get_bytes(fvalue_t *fv); + +WS_DLL_PUBLIC +size_t +fvalue_get_bytes_size(fvalue_t *fv); + +/* Same as fvalue_length() */ +WS_DLL_PUBLIC +const void * +fvalue_get_bytes_data(fvalue_t *fv); + +WS_DLL_PUBLIC +const e_guid_t * +fvalue_get_guid(fvalue_t *fv); + +WS_DLL_PUBLIC +const nstime_t * +fvalue_get_time(fvalue_t *fv); + +WS_DLL_PUBLIC +const char * +fvalue_get_string(fvalue_t *fv); + +WS_DLL_PUBLIC +const wmem_strbuf_t * +fvalue_get_strbuf(fvalue_t *fv); + +WS_DLL_PUBLIC +tvbuff_t * +fvalue_get_protocol(fvalue_t *fv); + +WS_DLL_PUBLIC uint32_t +fvalue_get_uinteger(fvalue_t *fv); + +WS_DLL_PUBLIC int32_t +fvalue_get_sinteger(fvalue_t *fv); + +WS_DLL_PUBLIC +uint64_t +fvalue_get_uinteger64(fvalue_t *fv); + +WS_DLL_PUBLIC +int64_t +fvalue_get_sinteger64(fvalue_t *fv); + +WS_DLL_PUBLIC double +fvalue_get_floating(fvalue_t *fv); + +WS_DLL_PUBLIC const ws_in6_addr * +fvalue_get_ipv6(fvalue_t *fv); + +ft_bool_t +fvalue_eq(const fvalue_t *a, const fvalue_t *b); + +ft_bool_t +fvalue_ne(const fvalue_t *a, const fvalue_t *b); + +ft_bool_t +fvalue_gt(const fvalue_t *a, const fvalue_t *b); + +ft_bool_t +fvalue_ge(const fvalue_t *a, const fvalue_t *b); + +ft_bool_t +fvalue_lt(const fvalue_t *a, const fvalue_t *b); + +ft_bool_t +fvalue_le(const fvalue_t *a, const fvalue_t *b); + +ft_bool_t +fvalue_contains(const fvalue_t *a, const fvalue_t *b); + +ft_bool_t +fvalue_matches(const fvalue_t *a, const ws_regex_t *re); + +bool +fvalue_is_zero(const fvalue_t *a); + +bool +fvalue_is_negative(const fvalue_t *a); + +size_t +fvalue_length2(fvalue_t *fv); + +fvalue_t* +fvalue_slice(fvalue_t *fv, drange_t *dr); + +fvalue_t* +fvalue_bitwise_and(const fvalue_t *a, const fvalue_t *b, char **err_msg); + +fvalue_t* +fvalue_unary_minus(const fvalue_t *fv, char **err_msg); + +fvalue_t* +fvalue_add(const fvalue_t *a, const fvalue_t *b, char **err_msg); + +fvalue_t* +fvalue_subtract(const fvalue_t *a, const fvalue_t *b, char **err_msg); + +fvalue_t* +fvalue_multiply(const fvalue_t *a, const fvalue_t *b, char **err_msg); + +fvalue_t* +fvalue_divide(const fvalue_t *a, const fvalue_t *b, char **err_msg); + +fvalue_t* +fvalue_modulo(const fvalue_t *a, const fvalue_t *b, char **err_msg); + +unsigned +fvalue_hash(const fvalue_t *fv); + +bool +fvalue_equal(const fvalue_t *a, const fvalue_t *b); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __FTYPES_H__ */ + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 8 + * tab-width: 8 + * indent-tabs-mode: t + * End: + * + * vi: set shiftwidth=8 tabstop=8 noexpandtab: + * :indentSize=8:tabSize=8:noTabs=false: + */ |