aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStig Bjørlykke <stig@bjorlykke.org>2018-05-15 09:24:52 +0200
committerAnders Broman <a.broman58@gmail.com>2018-05-15 10:30:18 +0000
commit171d92cc148ee782fe5c900e11a1d8976ca77662 (patch)
tree2a71f1199911df3acc01b7266cf8cc2903601c28
parent4c1690ac4783c7334462b4140a9c41526edbae44 (diff)
lwm2mtlv: Add Resource name tables
Add one fixed table for OMA (Normative) defined resource names and one table for user defined resource names. All resources are identified by a object ID and a resource ID. Show number of elements in arrays instead of number of bytes. Next iteration will add proper hf entries for OMA elements. Change-Id: I4d6c053a7c448cc65692ba1d1e92a2033ff3b397 Reviewed-on: https://code.wireshark.org/review/27551 Petri-Dish: Stig Bjørlykke <stig@bjorlykke.org> Tested-by: Petri Dish Buildbot Reviewed-by: Anders Broman <a.broman58@gmail.com>
-rw-r--r--epan/dissectors/packet-coap.c6
-rw-r--r--epan/dissectors/packet-lwm2mtlv.c560
2 files changed, 503 insertions, 63 deletions
diff --git a/epan/dissectors/packet-coap.c b/epan/dissectors/packet-coap.c
index ae08aba66c..2a5dac9dc8 100644
--- a/epan/dissectors/packet-coap.c
+++ b/epan/dissectors/packet-coap.c
@@ -27,6 +27,7 @@
#include <epan/to_str.h>
#include "packet-dtls.h"
#include "packet-coap.h"
+#include "packet-http.h"
void proto_register_coap(void);
@@ -920,6 +921,7 @@ dissect_coap_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *coap_tree, p
tvbuff_t *payload_tvb;
guint payload_length = offset_end - offset;
const char *coap_ctype_str_dis;
+ http_message_info_t message_info;
char str_payload[80];
/* coinfo->ctype_value == DEFAULT_COAP_CTYPE_VALUE: No Content-Format option present */
@@ -965,8 +967,10 @@ dissect_coap_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *coap_tree, p
PROTO_ITEM_SET_GENERATED(length_item);
payload_tvb = tvb_new_subset_length(tvb, offset, payload_length);
+ message_info.type = HTTP_OTHERS;
+ message_info.media_str = wmem_strbuf_get_str(coinfo->uri_str_strbuf);
dissector_try_string(media_type_dissector_table, coap_ctype_str_dis,
- payload_tvb, pinfo, parent_tree, NULL);
+ payload_tvb, pinfo, parent_tree, &message_info);
if (coinfo->object_security && !oscore) {
proto_item_set_text(payload_item, "Encrypted OSCORE Data");
diff --git a/epan/dissectors/packet-lwm2mtlv.c b/epan/dissectors/packet-lwm2mtlv.c
index 81b72a25b1..991c624896 100644
--- a/epan/dissectors/packet-lwm2mtlv.c
+++ b/epan/dissectors/packet-lwm2mtlv.c
@@ -16,14 +16,17 @@
#include "config.h"
-
#include <epan/packet.h>
+#include <epan/to_str.h>
+#include <epan/uat.h>
#include <wsutil/str_util.h>
+#include "packet-http.h"
+
void proto_register_lwm2mtlv(void);
void proto_reg_handoff_lwm2mtlv(void);
-static void parseArrayOfElements(tvbuff_t *tvb, proto_tree *tlv_tree);
+static void parseArrayOfElements(tvbuff_t *tvb, proto_tree *tlv_tree, const char *uri_path);
static int proto_lwm2mtlv = -1;
@@ -91,9 +94,320 @@ typedef struct
guint identifier;
guint length;
guint totalLength;
- gboolean is_valid_utf8_string;
} lwm2mElement_t;
+typedef struct _lwm2m_resource_t {
+ guint object_id;
+ guint resource_id;
+ char *name;
+ guint data_type;
+ gint *hf_id;
+ char *field_name;
+} lwm2m_resource_t;
+
+#define DATA_TYPE_NONE 0
+#define DATA_TYPE_STRING 1
+#define DATA_TYPE_INTEGER 2
+#define DATA_TYPE_FLOAT 3
+#define DATA_TYPE_BOOLEAN 4
+#define DATA_TYPE_OPAQUE 5
+#define DATA_TYPE_TIME 6
+#define DATA_TYPE_OBJLNK 7
+
+static const value_string data_types[] = {
+ { DATA_TYPE_NONE, "None" },
+ { DATA_TYPE_STRING, "String" },
+ { DATA_TYPE_INTEGER, "Integer" },
+ { DATA_TYPE_FLOAT, "Float" },
+ { DATA_TYPE_BOOLEAN, "Boolean" },
+ { DATA_TYPE_OPAQUE, "Opaque" },
+ { DATA_TYPE_TIME, "Time" },
+ { DATA_TYPE_OBJLNK, "Objlnk" },
+ { 0, NULL }
+};
+
+/* LwM2M Objects defined by OMA (Normative) */
+static lwm2m_resource_t lwm2m_oma_resources[] =
+{
+ /* LwM2M Security (0) */
+ { 0, 0, "LwM2M Server URI", DATA_TYPE_STRING, NULL, NULL },
+ { 0, 1, "Bootstrap-Server", DATA_TYPE_BOOLEAN, NULL, NULL },
+ { 0, 2, "Security Mode", DATA_TYPE_INTEGER, NULL, NULL },
+ { 0, 3, "Public Key or Identity", DATA_TYPE_OPAQUE, NULL, NULL },
+ { 0, 4, "Server Public Key", DATA_TYPE_OPAQUE, NULL, NULL },
+ { 0, 5, "Secret Key", DATA_TYPE_OPAQUE, NULL, NULL },
+ { 0, 6, "SMS Security Mode", DATA_TYPE_INTEGER, NULL, NULL },
+ { 0, 7, "SMS Binding Key Parameters", DATA_TYPE_OPAQUE, NULL, NULL },
+ { 0, 8, "SMS Binding Secret Keys", DATA_TYPE_OPAQUE, NULL, NULL },
+ { 0, 9, "LwM2M Server SMS Number", DATA_TYPE_STRING, NULL, NULL },
+ { 0, 10, "Short Server ID", DATA_TYPE_INTEGER, NULL, NULL },
+ { 0, 11, "Client Hold Off Time", DATA_TYPE_INTEGER, NULL, NULL },
+ { 0, 12, "Bootstrap-Server Account Timeout", DATA_TYPE_INTEGER, NULL, NULL },
+
+ /* LwM2M Server (1) */
+ { 1, 0, "Short Server ID", DATA_TYPE_INTEGER, NULL, NULL },
+ { 1, 1, "Lifetime", DATA_TYPE_INTEGER, NULL, NULL },
+ { 1, 2, "Default Minimum Period", DATA_TYPE_INTEGER, NULL, NULL },
+ { 1, 3, "Default Maximum Period", DATA_TYPE_INTEGER, NULL, NULL },
+ { 1, 4, "Disable", DATA_TYPE_NONE, NULL, NULL },
+ { 1, 5, "Disable Timeout", DATA_TYPE_INTEGER, NULL, NULL },
+ { 1, 6, "Notification Storing When Disabled or Offline", DATA_TYPE_BOOLEAN, NULL, NULL },
+ { 1, 7, "Binding", DATA_TYPE_STRING, NULL, NULL },
+
+ /* Access Control (2) */
+ { 2, 0, "Object ID", DATA_TYPE_INTEGER, NULL, NULL },
+ { 2, 1, "Object Instance ID", DATA_TYPE_INTEGER, NULL, NULL },
+ { 2, 2, "ACL", DATA_TYPE_INTEGER, NULL, NULL },
+ { 2, 3, "Access Control Owner", DATA_TYPE_INTEGER, NULL, NULL },
+
+ /* Device (3) */
+ { 3, 0, "Manufacturer", DATA_TYPE_STRING, NULL, NULL },
+ { 3, 1, "Model Number", DATA_TYPE_STRING, NULL, NULL },
+ { 3, 2, "Serial Number", DATA_TYPE_STRING, NULL, NULL },
+ { 3, 3, "Firmware Version", DATA_TYPE_STRING, NULL, NULL },
+ { 3, 4, "Reboot", DATA_TYPE_NONE, NULL, NULL },
+ { 3, 5, "Factory Reset", DATA_TYPE_NONE, NULL, NULL },
+ { 3, 6, "Available Power Sources", DATA_TYPE_INTEGER, NULL, NULL },
+ { 3, 7, "Power Source Voltage", DATA_TYPE_INTEGER, NULL, NULL },
+ { 3, 8, "Power Source Current", DATA_TYPE_INTEGER, NULL, NULL },
+ { 3, 9, "Battery Level", DATA_TYPE_INTEGER, NULL, NULL },
+ { 3, 10, "Memory Free", DATA_TYPE_INTEGER, NULL, NULL },
+ { 3, 11, "Error Code", DATA_TYPE_INTEGER, NULL, NULL },
+ { 3, 12, "Reset Error Code", DATA_TYPE_NONE, NULL, NULL },
+ { 3, 13, "Current Time", DATA_TYPE_TIME, NULL, NULL },
+ { 3, 14, "UTC Offset", DATA_TYPE_STRING, NULL, NULL },
+ { 3, 15, "Timezone", DATA_TYPE_STRING, NULL, NULL },
+ { 3, 16, "Supported Binding and Modes", DATA_TYPE_STRING, NULL, NULL },
+ { 3, 17, "Device Type", DATA_TYPE_STRING, NULL, NULL },
+ { 3, 18, "Hardware Version", DATA_TYPE_STRING, NULL, NULL },
+ { 3, 19, "Software Version", DATA_TYPE_STRING, NULL, NULL },
+ { 3, 20, "Battery Status", DATA_TYPE_INTEGER, NULL, NULL },
+ { 3, 21, "Memory Total", DATA_TYPE_INTEGER, NULL, NULL },
+ { 3, 22, "ExtDevInfo", DATA_TYPE_OBJLNK, NULL, NULL },
+
+ /* Connectivity Monitoring (4) */
+ { 4, 0, "Network Bearer", DATA_TYPE_INTEGER, NULL, NULL },
+ { 4, 1, "Available Network Bearer", DATA_TYPE_INTEGER, NULL, NULL },
+ { 4, 2, "Radio Signal Strength", DATA_TYPE_INTEGER, NULL, NULL },
+ { 4, 3, "Link Quality", DATA_TYPE_INTEGER, NULL, NULL },
+ { 4, 4, "IP Addresses", DATA_TYPE_STRING, NULL, NULL },
+ { 4, 5, "Router IP Addresses", DATA_TYPE_STRING, NULL, NULL },
+ { 4, 6, "Link Utilization", DATA_TYPE_INTEGER, NULL, NULL },
+ { 4, 7, "APN", DATA_TYPE_STRING, NULL, NULL },
+ { 4, 8, "Cell ID", DATA_TYPE_INTEGER, NULL, NULL },
+ { 4, 9, "SMNC", DATA_TYPE_INTEGER, NULL, NULL },
+ { 4, 10, "SMCC", DATA_TYPE_INTEGER, NULL, NULL },
+
+ /* Firmware Update (5) */
+ { 5, 0, "Package", DATA_TYPE_OPAQUE, NULL, NULL },
+ { 5, 1, "Package URI", DATA_TYPE_STRING, NULL, NULL },
+ { 5, 2, "Update", DATA_TYPE_NONE, NULL, NULL },
+ { 5, 3, "State", DATA_TYPE_INTEGER, NULL, NULL },
+ /* { 5, 4, "", DATA_TYPE_NONE, NULL, NULL }, */
+ { 5, 5, "Update Result", DATA_TYPE_INTEGER, NULL, NULL },
+ { 5, 6, "PkgName", DATA_TYPE_STRING, NULL, NULL },
+ { 5, 7, "PkgVersion", DATA_TYPE_STRING, NULL, NULL },
+ { 5, 8, "Firmware Update Protocol Support", DATA_TYPE_INTEGER, NULL, NULL },
+ { 5, 9, "Firmware Update Delivery Method", DATA_TYPE_INTEGER, NULL, NULL },
+
+ /* Location (6) */
+ { 6, 0, "Latitude", DATA_TYPE_FLOAT, NULL, NULL },
+ { 6, 1, "Longitude", DATA_TYPE_FLOAT, NULL, NULL },
+ { 6, 2, "Altitude", DATA_TYPE_FLOAT, NULL, NULL },
+ { 6, 3, "Radius", DATA_TYPE_FLOAT, NULL, NULL },
+ { 6, 4, "Velocity", DATA_TYPE_OPAQUE, NULL, NULL },
+ { 6, 5, "Timestamp", DATA_TYPE_TIME, NULL, NULL },
+ { 6, 6, "Speed", DATA_TYPE_FLOAT, NULL, NULL },
+
+ /* Connectivity Statistics (7) */
+ { 7, 0, "SMS Tx Counter", DATA_TYPE_INTEGER, NULL, NULL },
+ { 7, 1, "SMS Rx Counter", DATA_TYPE_INTEGER, NULL, NULL },
+ { 7, 2, "Tx Data", DATA_TYPE_INTEGER, NULL, NULL },
+ { 7, 3, "Rx Data", DATA_TYPE_INTEGER, NULL, NULL },
+ { 7, 4, "Max Message Size", DATA_TYPE_INTEGER, NULL, NULL },
+ { 7, 5, "Average Message Size", DATA_TYPE_INTEGER, NULL, NULL },
+ { 7, 6, "Start", DATA_TYPE_NONE, NULL, NULL },
+ { 7, 7, "Stop", DATA_TYPE_NONE, NULL, NULL },
+ { 7, 8, "Collection Period", DATA_TYPE_INTEGER, NULL, NULL },
+};
+
+/* LwM2M Objects defined by User */
+static lwm2m_resource_t *lwm2m_uat_resources;
+static guint num_lwm2m_uat_resources;
+
+static gboolean lwm2m_resource_update_cb(void *record, char **error)
+{
+ lwm2m_resource_t *rec = (lwm2m_resource_t *)record;
+ char c;
+
+ if (rec->name == NULL) {
+ *error = g_strdup("Resource Name can't be empty");
+ return FALSE;
+ }
+
+ g_strstrip(rec->name);
+ if (rec->name[0] == 0) {
+ *error = g_strdup("Resource Name can't be empty");
+ return FALSE;
+ }
+
+ g_free(rec->field_name);
+ rec->field_name = g_ascii_strdown(rec->name, -1);
+ for (size_t i = 0; i < strlen(rec->field_name); i++) {
+ if (rec->field_name[i] == ' ' || rec->field_name[i] == '.') {
+ rec->field_name[i] = '_';
+ }
+ }
+
+ /* Check for invalid characters (to avoid asserting out when registering the field). */
+ c = proto_check_field_name(rec->field_name);
+ if (c) {
+ *error = g_strdup_printf("Resource Name can't contain '%c'", c);
+ return FALSE;
+ }
+
+ *error = NULL;
+ return TRUE;
+}
+
+static void *lwm2m_resource_copy_cb(void *dest, const void *source, size_t len _U_)
+{
+ const lwm2m_resource_t *s = (const lwm2m_resource_t *)source;
+ lwm2m_resource_t *d = (lwm2m_resource_t *)dest;
+
+ d->object_id = s->object_id;
+ d->resource_id = s->resource_id;
+ d->name = g_strdup(s->name);
+ d->field_name = g_strdup(s->field_name);
+ d->data_type = s->data_type;
+
+ return d;
+}
+
+static void lwm2m_resource_free_cb(void *record)
+{
+ lwm2m_resource_t *rec = (lwm2m_resource_t *)record;
+
+ g_free(rec->name);
+ g_free(rec->field_name);
+}
+
+static void lwm2m_add_resource(lwm2m_resource_t *resource, hf_register_info *hf)
+{
+ gchar *resource_abbrev;
+ gint *hf_id;
+
+ hf_id = g_new(gint,1);
+ *hf_id = -1;
+
+ if (resource->field_name) {
+ resource_abbrev = g_strdup(resource->field_name);
+ } else {
+ resource_abbrev = g_ascii_strdown(resource->name, -1);
+ for (size_t i = 0; i < strlen(resource_abbrev); i++) {
+ if (resource_abbrev[i] == ' ' || resource_abbrev[i] == '.') {
+ resource_abbrev[i] = '_';
+ }
+ }
+ }
+
+ resource->hf_id = hf_id;
+
+ hf->p_id = hf_id;
+ hf->hfinfo.name = g_strdup(resource->name);
+ hf->hfinfo.abbrev = g_strdup_printf("lwm2mtlv.resource.%s", resource_abbrev);
+ g_free (resource_abbrev);
+
+ switch (resource->data_type) {
+ case DATA_TYPE_STRING:
+ hf->hfinfo.display = BASE_NONE;
+ hf->hfinfo.type = FT_STRING;
+ break;
+ case DATA_TYPE_INTEGER:
+ hf->hfinfo.display = BASE_DEC;
+ hf->hfinfo.type = FT_INT64;
+ break;
+ case DATA_TYPE_FLOAT:
+ hf->hfinfo.display = BASE_NONE;
+ hf->hfinfo.type = FT_FLOAT;
+ break;
+ case DATA_TYPE_BOOLEAN:
+ hf->hfinfo.display = BASE_DEC;
+ hf->hfinfo.type = FT_BOOLEAN;
+ break;
+ case DATA_TYPE_TIME:
+ hf->hfinfo.display = ABSOLUTE_TIME_LOCAL;
+ hf->hfinfo.type = FT_ABSOLUTE_TIME;
+ break;
+ case DATA_TYPE_OPAQUE:
+ case DATA_TYPE_OBJLNK:
+ default:
+ hf->hfinfo.display = BASE_NONE;
+ hf->hfinfo.type = FT_BYTES;
+ break;
+ }
+ hf->hfinfo.strings = NULL;
+ hf->hfinfo.bitmask = 0;
+ hf->hfinfo.blurb = NULL;
+ HFILL_INIT(*hf);
+}
+
+static void lwm2m_resource_post_update_cb(void)
+{
+ static hf_register_info *hf;
+ static guint hf_size;
+
+ if (hf) {
+ /* Deregister all fields */
+ for (guint i = 0; i < hf_size; i++) {
+ proto_deregister_field(proto_lwm2mtlv, *(hf[i].p_id));
+ g_free (hf[i].p_id);
+ }
+ proto_add_deregistered_data(hf);
+ }
+
+ if (num_lwm2m_uat_resources) {
+ hf = g_new0(hf_register_info, num_lwm2m_uat_resources);
+ hf_size = 0;
+
+ for (guint i = 0; i < num_lwm2m_uat_resources; i++) {
+ lwm2m_add_resource(&lwm2m_uat_resources[i], &hf[hf_size++]);
+ }
+
+ proto_register_field_array(proto_lwm2mtlv, hf, hf_size);
+ }
+}
+
+static gint64
+decodeVariableInt(tvbuff_t *tvb, const gint offset, const guint length)
+{
+ switch(length)
+ {
+ case 1:
+ return tvb_get_gint8(tvb, offset);
+ case 2:
+ return tvb_get_ntohis(tvb, offset);
+ case 3:
+ return tvb_get_ntohi24(tvb, offset);
+ case 4:
+ return tvb_get_ntohil(tvb, offset);
+ case 5:
+ return tvb_get_ntohi40(tvb, offset);
+ case 6:
+ return tvb_get_ntohi48(tvb, offset);
+ case 7:
+ return tvb_get_ntohi56(tvb, offset);
+ case 8:
+ return tvb_get_ntohi64(tvb, offset);
+ default:
+ return 0;
+ }
+}
+
+UAT_DEC_CB_DEF(resource, object_id, lwm2m_resource_t)
+UAT_DEC_CB_DEF(resource, resource_id, lwm2m_resource_t)
+UAT_CSTRING_CB_DEF(resource, name, lwm2m_resource_t)
+UAT_VS_DEF(resource, data_type, lwm2m_resource_t, guint, DATA_TYPE_NONE, "None")
static void
addTlvHeaderElements(tvbuff_t *tvb, proto_tree *tlv_tree, lwm2mElement_t *element)
@@ -128,107 +442,178 @@ addTlvHeaderTree(tvbuff_t *tvb, proto_tree *tlv_tree, lwm2mElement_t *element)
}
static proto_tree*
-addElementTree(tvbuff_t *tvb, proto_tree *tlv_tree, lwm2mElement_t *element)
+addElementTree(tvbuff_t *tvb, proto_tree *tlv_tree, lwm2mElement_t *element, const lwm2m_resource_t *resource)
{
- guint valueOffset = 1 + element->length_of_identifier + element->length_of_length;
- guint8 *str;
+ gchar *identifier = NULL;
+
+ if (resource) {
+ identifier = wmem_strdup_printf(wmem_packet_scope(), "[%02u] %s", element->identifier, resource->name);
+ } else {
+ identifier = wmem_strdup_printf(wmem_packet_scope(), "[%02u]", element->identifier);
+ }
switch ( element->type )
{
case OBJECT_INSTANCE:
return proto_tree_add_subtree_format(tlv_tree, tvb, 0, element->totalLength, ett_lwm2mtlv_objectInstance, NULL,
- "Object Instance %02u (%u Bytes)", element->identifier, element->length_of_value);
+ "Object Instance %02u", element->identifier);
case RESOURCE_INSTANCE:
- str = tvb_get_string_enc(wmem_packet_scope(), tvb, valueOffset, element->length_of_value, ENC_UTF_8);
- if (isprint_utf8_string(str, element->length_of_value)) {
- element->is_valid_utf8_string = TRUE;
- } else {
- str = tvb_bytes_to_str(wmem_packet_scope(), tvb, valueOffset, element->length_of_value);
- }
return proto_tree_add_subtree_format(tlv_tree, tvb, 0, element->totalLength, ett_lwm2mtlv_resourceInstance, NULL,
- "%02u: %s", element->identifier, str);
+ "%02u", element->identifier);
case RESOURCE_ARRAY:
return proto_tree_add_subtree_format(tlv_tree, tvb, 0, element->totalLength, ett_lwm2mtlv_resourceArray, NULL,
- "%02u: (Array of %u Bytes)", element->identifier, element->length_of_value);
+ "%s", identifier);
case RESOURCE:
- str = tvb_get_string_enc(wmem_packet_scope(), tvb, valueOffset, element->length_of_value, ENC_UTF_8);
- if (isprint_utf8_string(str, element->length_of_value)) {
- element->is_valid_utf8_string = TRUE;
- } else {
- str = tvb_bytes_to_str(wmem_packet_scope(), tvb, valueOffset, element->length_of_value);
- }
return proto_tree_add_subtree_format(tlv_tree, tvb, 0, element->totalLength, ett_lwm2mtlv_resource, NULL,
- "%02u: %s", element->identifier, str);
+ "%s", identifier);
}
return NULL;
}
static void
-addValueInterpretations(tvbuff_t *tvb, proto_tree *tlv_tree, lwm2mElement_t *element)
+addValueInterpretations(tvbuff_t *tvb, proto_tree *tlv_tree, lwm2mElement_t *element, const lwm2m_resource_t *resource)
{
guint valueOffset;
if ( element->length_of_value == 0 ) return;
valueOffset = 1 + element->length_of_identifier + element->length_of_length;
- if (element->is_valid_utf8_string) {
- proto_tree_add_item(tlv_tree, hf_lwm2mtlv_value_string, tvb, valueOffset, element->length_of_value, ENC_UTF_8|ENC_NA);
- }
-
- switch(element->length_of_value)
- {
- case 0x01:
- proto_tree_add_item(tlv_tree, hf_lwm2mtlv_value_integer, tvb, valueOffset, element->length_of_value, ENC_BIG_ENDIAN);
- if (tvb_get_guint8(tvb, valueOffset) < 2) {
- proto_tree_add_item(tlv_tree, hf_lwm2mtlv_value_boolean, tvb, valueOffset, element->length_of_value, ENC_BIG_ENDIAN);
+ if (resource && resource->data_type != DATA_TYPE_NONE) {
+ switch (resource->data_type) {
+ case DATA_TYPE_STRING:
+ {
+ const guint8 *strval;
+ proto_tree_add_item_ret_string(tlv_tree, *resource->hf_id, tvb, valueOffset, element->length_of_value, ENC_UTF_8, wmem_packet_scope(), &strval);
+ proto_item_append_text(tlv_tree, ": %s", strval);
+ break;
+ }
+ case DATA_TYPE_INTEGER:
+ proto_tree_add_item(tlv_tree, *resource->hf_id, tvb, valueOffset, element->length_of_value, ENC_BIG_ENDIAN);
+ proto_item_append_text(tlv_tree, ": %" G_GINT64_FORMAT, decodeVariableInt(tvb, valueOffset, element->length_of_value));
+ break;
+ case DATA_TYPE_FLOAT:
+ proto_tree_add_item(tlv_tree, *resource->hf_id, tvb, valueOffset, element->length_of_value, ENC_BIG_ENDIAN);
+ proto_item_append_text(tlv_tree, ": %." G_STRINGIFY(FLT_DIG) "g", tvb_get_ieee_float(tvb, valueOffset, ENC_BIG_ENDIAN));
+ break;
+ case DATA_TYPE_BOOLEAN:
+ {
+ gboolean boolval;
+ proto_tree_add_item_ret_boolean(tlv_tree, *resource->hf_id, tvb, valueOffset, element->length_of_value, ENC_BIG_ENDIAN, &boolval);
+ proto_item_append_text(tlv_tree, ": %s", boolval ? "True" : "False");
+ break;
+ }
+ case DATA_TYPE_TIME:
+ {
+ nstime_t ts;
+ ts.secs = (time_t)decodeVariableInt(tvb, valueOffset, element->length_of_value);
+ ts.nsecs = 0;
+ proto_tree_add_time(tlv_tree, *resource->hf_id, tvb, valueOffset, element->length_of_value, &ts);
+ proto_item_append_text(tlv_tree, ": %s", abs_time_to_str(wmem_packet_scope(), &ts, ABSOLUTE_TIME_LOCAL, FALSE));
+ break;
+ }
+ case DATA_TYPE_OPAQUE:
+ case DATA_TYPE_OBJLNK:
+ default:
+ proto_tree_add_item(tlv_tree, *resource->hf_id, tvb, valueOffset, element->length_of_value, ENC_BIG_ENDIAN);
+ proto_item_append_text(tlv_tree, ": %s", tvb_bytes_to_str(wmem_packet_scope(), tvb, valueOffset, element->length_of_value));
+ break;
+ }
+ } else {
+ guint8 *str = tvb_get_string_enc(wmem_packet_scope(), tvb, valueOffset, element->length_of_value, ENC_UTF_8);
+ if (isprint_utf8_string(str, element->length_of_value)) {
+ proto_tree_add_item(tlv_tree, hf_lwm2mtlv_value_string, tvb, valueOffset, element->length_of_value, ENC_UTF_8|ENC_NA);
+ } else {
+ str = tvb_bytes_to_str(wmem_packet_scope(), tvb, valueOffset, element->length_of_value);
+ }
+ proto_item_append_text(tlv_tree, ": %s", str);
+
+ switch(element->length_of_value) {
+ case 0x01:
+ proto_tree_add_item(tlv_tree, hf_lwm2mtlv_value_integer, tvb, valueOffset, element->length_of_value, ENC_BIG_ENDIAN);
+ if (tvb_get_guint8(tvb, valueOffset) < 2) {
+ proto_tree_add_item(tlv_tree, hf_lwm2mtlv_value_boolean, tvb, valueOffset, element->length_of_value, ENC_BIG_ENDIAN);
+ }
+ break;
+ case 0x02:
+ proto_tree_add_item(tlv_tree, hf_lwm2mtlv_value_integer, tvb, valueOffset, element->length_of_value, ENC_BIG_ENDIAN);
+ break;
+ case 0x04:
+ proto_tree_add_item(tlv_tree, hf_lwm2mtlv_value_integer, tvb, valueOffset, element->length_of_value, ENC_BIG_ENDIAN);
+ proto_tree_add_item(tlv_tree, hf_lwm2mtlv_value_float, tvb, valueOffset, element->length_of_value, ENC_BIG_ENDIAN);
+ proto_tree_add_item(tlv_tree, hf_lwm2mtlv_value_timestamp, tvb, valueOffset, element->length_of_value, ENC_BIG_ENDIAN);
+ break;
+ case 0x08:
+ proto_tree_add_item(tlv_tree, hf_lwm2mtlv_value_integer, tvb, valueOffset, element->length_of_value, ENC_BIG_ENDIAN);
+ proto_tree_add_item(tlv_tree, hf_lwm2mtlv_value_double, tvb, valueOffset, element->length_of_value, ENC_BIG_ENDIAN);
+ /* apparently, wireshark does not deal well with 8 bytes. */
+ proto_tree_add_item(tlv_tree, hf_lwm2mtlv_value_timestamp, tvb, valueOffset+4, element->length_of_value-4, ENC_BIG_ENDIAN);
+ break;
}
- break;
- case 0x02:
- proto_tree_add_item(tlv_tree, hf_lwm2mtlv_value_integer, tvb, valueOffset, element->length_of_value, ENC_BIG_ENDIAN);
- break;
- case 0x04:
- proto_tree_add_item(tlv_tree, hf_lwm2mtlv_value_integer, tvb, valueOffset, element->length_of_value, ENC_BIG_ENDIAN);
- proto_tree_add_item(tlv_tree, hf_lwm2mtlv_value_float, tvb, valueOffset, element->length_of_value, ENC_BIG_ENDIAN);
- proto_tree_add_item(tlv_tree, hf_lwm2mtlv_value_timestamp, tvb, valueOffset, element->length_of_value, ENC_BIG_ENDIAN);
- break;
- case 0x08:
- proto_tree_add_item(tlv_tree, hf_lwm2mtlv_value_integer, tvb, valueOffset, element->length_of_value, ENC_BIG_ENDIAN);
- proto_tree_add_item(tlv_tree, hf_lwm2mtlv_value_double, tvb, valueOffset, element->length_of_value, ENC_BIG_ENDIAN);
- /* apparently, wireshark does not deal well with 8 bytes. */
- proto_tree_add_item(tlv_tree, hf_lwm2mtlv_value_timestamp, tvb, valueOffset+4, element->length_of_value-4, ENC_BIG_ENDIAN);
- break;
}
}
static void
-addValueTree(tvbuff_t *tvb, proto_tree *tlv_tree, lwm2mElement_t *element)
+addValueTree(tvbuff_t *tvb, proto_tree *tlv_tree, lwm2mElement_t *element, const char *uri_path, const lwm2m_resource_t *resource)
{
guint valueOffset = 1 + element->length_of_identifier + element->length_of_length;
if ( element->type == RESOURCE || element->type == RESOURCE_INSTANCE ) {
proto_tree_add_item(tlv_tree, hf_lwm2mtlv_value, tvb, valueOffset, element->length_of_value, ENC_NA);
- addValueInterpretations(tvb, tlv_tree, element);
+ addValueInterpretations(tvb, tlv_tree, element, resource);
} else {
tvbuff_t* sub = tvb_new_subset_length(tvb, valueOffset, element->length_of_value);
- parseArrayOfElements(sub, tlv_tree);
+ parseArrayOfElements(sub, tlv_tree, uri_path);
}
}
static void
-addTlvElement(tvbuff_t *tvb, proto_tree *tlv_tree, lwm2mElement_t *element)
+addTlvElement(tvbuff_t *tvb, proto_tree *tlv_tree, lwm2mElement_t *element, const char *uri_path)
{
proto_tree *element_tree = NULL;
+ const lwm2m_resource_t *resource = NULL;
+
+ gchar **ids = wmem_strsplit(wmem_packet_scope(), uri_path, "/", 4);
+ if (ids && ids[0] && ids[1] && ids[2]) {
+ /* URI path is defined as:
+ * ids[0] = Object ID
+ * ids[1] = Object Instance
+ * ids[2] = Resource ID
+ * ids[3] = Resource Instance
+ */
+ guint object_id = (guint)strtol(ids[0], NULL, 10);
+ guint resource_id = (guint)strtol(ids[2], NULL, 10);
+
+ /* First search OMA objects */
+ for (guint i = 0; i < array_length(lwm2m_oma_resources); i++) {
+ if ((object_id == lwm2m_oma_resources[i].object_id) &&
+ (resource_id == lwm2m_oma_resources[i].resource_id))
+ {
+ resource = &lwm2m_oma_resources[i];
+ break;
+ }
+ }
+
+ /* Then search user configured objects */
+ for (guint i = 0; i < num_lwm2m_uat_resources; i++) {
+ if ((object_id == lwm2m_uat_resources[i].object_id) &&
+ (resource_id == lwm2m_uat_resources[i].resource_id))
+ {
+ resource = &lwm2m_uat_resources[i];
+ break;
+ }
+ }
+ }
- element_tree = addElementTree(tvb, tlv_tree, element);
+ element_tree = addElementTree(tvb, tlv_tree, element, resource);
addTlvHeaderTree(tvb, element_tree, element);
- addValueTree(tvb, element_tree, element);
+ addValueTree(tvb, element_tree, element, uri_path, resource);
}
static guint64
-decodeVariableInt(tvbuff_t *tvb, const gint offset, const guint length)
+decodeVariableUInt(tvbuff_t *tvb, const gint offset, const guint length)
{
switch(length)
{
@@ -262,30 +647,35 @@ static guint parseTLVHeader(tvbuff_t *tvb, lwm2mElement_t *element)
element->length_of_value = (( type_field >> 0 ) & 0x07 );
/* It is ok to shorten identifier and length_of_value, they are never more than 24 bits long */
- element->identifier = (guint) decodeVariableInt(tvb, 1, element->length_of_identifier);
+ element->identifier = (guint) decodeVariableUInt(tvb, 1, element->length_of_identifier);
if ( element->length_of_length > 0 ) {
- element->length_of_value = (guint) decodeVariableInt(tvb, 1 + element->length_of_identifier, element->length_of_length);
+ element->length_of_value = (guint) decodeVariableUInt(tvb, 1 + element->length_of_identifier, element->length_of_length);
}
element->totalLength = 1 + element->length_of_identifier + element->length_of_length + element->length_of_value;
- element->is_valid_utf8_string = FALSE;
return element->totalLength;
}
-static void parseArrayOfElements(tvbuff_t *tvb, proto_tree *tlv_tree)
+static void parseArrayOfElements(tvbuff_t *tvb, proto_tree *tlv_tree, const char *uri_path)
{
guint length;
guint offset = 0;
guint elementLength = 0;
+ guint element_count = 0;
lwm2mElement_t element;
+ const char *next_uri_path = NULL;
length = tvb_reported_length(tvb);
while ( length > 0 ) {
tvbuff_t* sub = tvb_new_subset_length(tvb, offset, length);
elementLength = parseTLVHeader(sub, &element);
- addTlvElement(sub, tlv_tree, &element);
+ if (uri_path) {
+ next_uri_path = wmem_strdup_printf(wmem_packet_scope(), "%s/%d", uri_path, element.identifier);
+ }
+ addTlvElement(sub, tlv_tree, &element, next_uri_path);
+ element_count++;
length -= elementLength;
offset += elementLength;
@@ -294,19 +684,27 @@ static void parseArrayOfElements(tvbuff_t *tvb, proto_tree *tlv_tree)
break;
}
}
+
+ proto_item_append_text(tlv_tree, " (%u element%s)", element_count, plurality(element_count, "", "s"));
}
static int
-dissect_lwm2mtlv(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void* data _U_)
+dissect_lwm2mtlv(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data)
{
proto_tree* lwm2mtlv_tree;
proto_item* lwm2mtlv_item;
+ http_message_info_t *message_info = (http_message_info_t *) data;
+ const char *uri_path = NULL;
+
+ if (message_info && message_info->media_str && message_info->media_str[0]) {
+ uri_path = message_info->media_str;
+ }
if (tree) { /* we are being asked for details */
lwm2mtlv_item = proto_tree_add_item(tree, proto_lwm2mtlv, tvb, 0, -1, ENC_NA);
lwm2mtlv_tree = proto_item_add_subtree(lwm2mtlv_item, ett_lwm2mtlv);
- parseArrayOfElements(tvb, lwm2mtlv_tree);
+ parseArrayOfElements(tvb, lwm2mtlv_tree, uri_path);
}
return tvb_captured_length(tvb);
}
@@ -400,6 +798,31 @@ void proto_register_lwm2mtlv(void)
&ett_lwm2mtlv_objectInstance
};
+ static uat_field_t lwm2m_resource_flds[] = {
+ UAT_FLD_DEC(resource, object_id, "Object ID", "Object ID"),
+ UAT_FLD_DEC(resource, resource_id, "Resource ID", "Resource ID"),
+ UAT_FLD_CSTRING(resource, name, "Resource Name", "Resource Name"),
+ UAT_FLD_VS(resource, data_type, "Data Type", data_types, "Data Type"),
+ UAT_END_FIELDS
+ };
+
+ uat_t *resource_uat = uat_new("User Resource Names",
+ sizeof(lwm2m_resource_t),
+ "lwm2m_resource_names",
+ TRUE,
+ &lwm2m_uat_resources,
+ &num_lwm2m_uat_resources,
+ UAT_AFFECTS_DISSECTION|UAT_AFFECTS_FIELDS,
+ "ChLwM2MResourceNames",
+ lwm2m_resource_copy_cb,
+ lwm2m_resource_update_cb,
+ lwm2m_resource_free_cb,
+ lwm2m_resource_post_update_cb,
+ NULL,
+ lwm2m_resource_flds);
+
+ module_t *lwm2mtlv_module;
+
/* Register our configuration options */
proto_lwm2mtlv = proto_register_protocol (
"Lightweight M2M TLV",
@@ -411,6 +834,19 @@ void proto_register_lwm2mtlv(void)
proto_register_subtree_array(ett, array_length(ett));
register_dissector("lwm2mtlv", dissect_lwm2mtlv, proto_lwm2mtlv);
+
+ lwm2mtlv_module = prefs_register_protocol(proto_lwm2mtlv, NULL);
+
+ prefs_register_uat_preference(lwm2mtlv_module, "resource_table",
+ "Resource Names",
+ "User Resource Names",
+ resource_uat);
+
+ hf_register_info *hf2 = g_new0(hf_register_info, array_length(lwm2m_oma_resources));
+ for (guint i = 0; i < array_length(lwm2m_oma_resources); i++) {
+ lwm2m_add_resource(&lwm2m_oma_resources[i], &hf2[i]);
+ }
+ proto_register_field_array(proto_lwm2mtlv, hf2, array_length(lwm2m_oma_resources));
}
void