aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--epan/dissectors/packet-tds.c103
1 files changed, 76 insertions, 27 deletions
diff --git a/epan/dissectors/packet-tds.c b/epan/dissectors/packet-tds.c
index 9070e64bb6..91eba9a678 100644
--- a/epan/dissectors/packet-tds.c
+++ b/epan/dissectors/packet-tds.c
@@ -1406,6 +1406,9 @@ static const enum_val_t tds_protocol_type_options[] = {
#define TDS_PROTO_LESS_THAN_TDS7(tds_info) \
(TDS_PROTO_PREF_NOT_SPECIFIED ? ((tds_info)->tds_version <= TDS_PROTOCOL_7_0) \
: (tds_protocol_type <= TDS_PROTOCOL_7_0))
+#define TDS_PROTO_TDS5(tds_info) \
+ (TDS_PROTO_PREF_NOT_SPECIFIED ? ((tds_info)->tds_version == TDS_PROTOCOL_5) \
+ : (tds_protocol_type == TDS_PROTOCOL_5))
#define TDS_PROTO_TDS7(tds_info) \
(TDS_PROTO_PREF_NOT_SPECIFIED ? ((tds_info)->tds_version >= TDS_PROTOCOL_7_0) && \
((tds_info)->tds_version <= TDS_PROTOCOL_7_4) \
@@ -2552,38 +2555,84 @@ dissect_tds_type_varbyte(tvbuff_t *tvb, guint *offset, packet_info *pinfo, proto
if(length > 0) {
- if (TDS_PROTO_TDS7(tds_info)) {
- proto_tree_add_item(sub_tree, hf_tds_type_varbyte_data_sign, tvb, *offset, 1, ENC_NA);
- length -= 1;
- }
-
- switch(length)
- {
- case 4:
- {
- numericitem = proto_tree_add_item(sub_tree, hf_tds_type_varbyte_data_int4,
- tvb, *offset + 1, 4, tds_get_int4_encoding(tds_info));
+ if (TDS_PROTO_TDS5(tds_info)) {
+ /* Sybase rules:
+ * Data are big-endian.
+ * The size appears to be variable governed on the Precision specification.
+ * Sign of TRUE indicates negative.
+ */
+ gboolean sign = FALSE;
- if(scale != 0)
- proto_item_append_text(numericitem, " x 10^%u", scale);
- break;
- }
- case 8:
- {
- numericitem = proto_tree_add_item(sub_tree, hf_tds_type_varbyte_data_int8, tvb, *offset + 1, 8, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item_ret_boolean(sub_tree, hf_tds_type_varbyte_data_sign, tvb, *offset, 1, ENC_NA, &sign);
+ *offset += 1;
+ length -= 1;
- if(scale != 0)
- proto_item_append_text(numericitem, " x 10^%u", scale);
- break;
+ numericitem = proto_tree_add_item(sub_tree,
+ hf_tds_type_varbyte_data_bytes, tvb, *offset, length,
+ ENC_NA);
+ if (length <= 8) {
+ guint8 data_array[8];
+ guint j;
+ gint64 int64_value = 0;
+
+ (void) tvb_memcpy(tvb, data_array, *offset, length);
+ for (j = 0; j < length; j++) {
+ int64_value = (int64_value << 8) | data_array[j];
+ }
+ proto_item_append_text(numericitem,
+ " (%" G_GINT64_MODIFIER "d)",
+ (sign ? -int64_value : int64_value));
+ if(scale != 0) {
+ proto_item_append_text(numericitem, " x 10^-%u", scale);
+ }
}
- case 12:
- case 16:
- {
- proto_tree_add_item(sub_tree, hf_tds_type_varbyte_data_bytes, tvb, *offset + 1, length, ENC_NA);
- break;
+ *offset += length;
+ }
+ else {
+ /*
+ * Microsoft apparently allowed NUMERIC/DECIMAL while they
+ * still were negotiating TDS 4.x. Sybase did not, so
+ * assume any NUMERIC that's not TDS 5.0 is Microsoft's.
+ *
+ * Microsoft rules:
+ * Data are little-endian.
+ * The data size is documented as being 4, 8, 12, or 16 bytes,
+ * but this code does not rely on that.
+ * Sign of TRUE indicates positive.
+ */
+ gboolean sign = TRUE;
+
+ numericitem = proto_tree_add_item_ret_boolean(sub_tree,
+ hf_tds_type_varbyte_data_sign, tvb, *offset, 1,
+ ENC_NA, &sign);
+ length -= 1;
+ *offset += 1;
+
+ numericitem = proto_tree_add_item(sub_tree,
+ hf_tds_type_varbyte_data_bytes, tvb, *offset, length,
+ ENC_NA);
+ if (length <= 8) {
+ guint8 data_array[8];
+ gint j;
+ gint64 int64_value = 0;
+
+ (void) tvb_memcpy(tvb, data_array, *offset, length);
+ for (j = length - 1; j >= 0; j--) {
+ int64_value = (int64_value << 8) | data_array[j];
+ }
+ proto_item_append_text(numericitem,
+ " (%" G_GINT64_MODIFIER "d)",
+ (sign ? int64_value : -int64_value));
+ if(scale != 0) {
+ proto_item_append_text(numericitem, " x 10^-%u", scale);
+ }
}
+ *offset += length;
}
- *offset += length;
+ }
+ else {
+ proto_tree_add_item(sub_tree, hf_tds_type_varbyte_data_null, tvb, *offset,
+ 0, ENC_NA);
}
break;
}