aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-tds.c
diff options
context:
space:
mode:
authorCraig Jackson <cejackson51@gmail.com>2018-07-30 21:46:20 -0400
committerAnders Broman <a.broman58@gmail.com>2018-08-09 04:55:24 +0000
commit2fa2947be0bfffde5efc5ebd81dc2625c2d20147 (patch)
tree5a40ff0f45a3b77ad72c6afdb62f730c9c0a982c /epan/dissectors/packet-tds.c
parent0be9d149d0feaac8697b993926ffa87e156d7fa4 (diff)
TDS: Add support for non-nullable datetime and money types.
This was accomplished by factoring out the existing code supporting nullable datetime and money types. The non-nullable versions are older and more often used with TDS 4 and TDS 5. Change-Id: I1bbf942d2b5ff3ec6bb9f1a607f0c579949f6131 Reviewed-on: https://code.wireshark.org/review/29008 Reviewed-by: Alexis La Goutte <alexis.lagoutte@gmail.com> Petri-Dish: Alexis La Goutte <alexis.lagoutte@gmail.com> Tested-by: Petri Dish Buildbot Reviewed-by: Anders Broman <a.broman58@gmail.com>
Diffstat (limited to 'epan/dissectors/packet-tds.c')
-rw-r--r--epan/dissectors/packet-tds.c168
1 files changed, 119 insertions, 49 deletions
diff --git a/epan/dissectors/packet-tds.c b/epan/dissectors/packet-tds.c
index 1a584bdf47..695ac9eefb 100644
--- a/epan/dissectors/packet-tds.c
+++ b/epan/dissectors/packet-tds.c
@@ -462,16 +462,20 @@
/* Encodings */
-#define TDS_INT2_BIG_ENDIAN 2
-#define TDS_INT2_LITTLE_ENDIAN 3
-#define TDS_INT4_BIG_ENDIAN 0
-#define TDS_INT4_LITTLE_ENDIAN 1
-#define TDS_FLT8_BIG_ENDIAN 4
-#define TDS_FLT8_VAX_D 5
-#define TDS_FLT8_LITTLE_ENDIAN 10
-#define TDS_FLT8_ND5000 11
-#define TDS_CHAR_ASCII 6
-#define TDS_CHAR_EBCDIC 7
+#define TDS_INT2_BIG_ENDIAN 2
+#define TDS_INT2_LITTLE_ENDIAN 3
+#define TDS_INT4_BIG_ENDIAN 0
+#define TDS_INT4_LITTLE_ENDIAN 1
+#define TDS_FLT8_BIG_ENDIAN 4
+#define TDS_FLT8_VAX_D 5
+#define TDS_FLT8_LITTLE_ENDIAN 10
+#define TDS_FLT8_ND5000 11
+#define TDS_CHAR_ASCII 6
+#define TDS_CHAR_EBCDIC 7
+#define TDS_DATE4_TIME_FIRST 16
+#define TDS_DATE4_DATE_FIRST 17
+#define TDS_DATE8_TIME_FIRST 8
+#define TDS_DATE8_DATE_FIRST 9
/* Artificial, for TDS 7 */
#define TDS_CHAR_UTF16 120
@@ -1336,6 +1340,8 @@ typedef struct {
guint tds_encoding_int2;
guint tds_encoding_int4;
guint tds_encoding_char;
+ guint tds_encoding_date8;
+ guint tds_encoding_date4;
gboolean tds_packets_in_order;
} tds_conv_info_t;
@@ -1604,16 +1610,16 @@ static const value_string login_options[] = {
{TDS_FLT8_VAX_D, "VAX D"},
{TDS_CHAR_ASCII, "ASCII"},
{TDS_CHAR_EBCDIC, "EBCDIC"},
- {8, "High integer first"},
- {9, "Low integer first"},
+ {TDS_DATE8_TIME_FIRST, "Time first"},
+ {TDS_DATE8_DATE_FIRST, "Date first"},
{TDS_FLT8_LITTLE_ENDIAN, "IEEE Little-endian"},
{TDS_FLT8_ND5000, "ND5000"},
{12, "IEEE Big-endian"},
{13, "IEEE Little-endian"},
{14, "VAX F"},
{15, "ND5000 4"},
- {16, "High integer first"},
- {17, "Low integer first"},
+ {TDS_DATE4_TIME_FIRST, "Time first"},
+ {TDS_DATE4_DATE_FIRST, "Date first"},
{0, NULL}
};
@@ -1994,13 +2000,87 @@ dissect_tds_all_headers(tvbuff_t *tvb, guint *offset, packet_info *pinfo, proto_
}
static void
+handle_tds_sql_datetime(tvbuff_t *tvb, guint offset, proto_tree *sub_tree, tds_conv_info_t *tds_info)
+{
+ /* SQL datetime */
+ nstime_t tv = NSTIME_INIT_ZERO;
+ gint64 days; /* Note that days is signed, allowing dates back to 1753. */
+ guint64 threehndths;
+
+ if (tds_info->tds_encoding_date8 == TDS_DATE8_DATE_FIRST) {
+ days = tvb_get_gint32(tvb, offset, tds_get_int4_encoding(tds_info));
+ threehndths = tvb_get_guint32(tvb, offset + 4, tds_get_int4_encoding(tds_info));
+ }
+ else if (tds_info->tds_encoding_date8 == TDS_DATE8_TIME_FIRST) {
+ threehndths = tvb_get_guint32(tvb, offset, tds_get_int4_encoding(tds_info));
+ days = tvb_get_gint32(tvb, offset + 4, tds_get_int4_encoding(tds_info));
+ }
+ else {
+ /* TODO Check these values in the login packet and offer expert information.
+ * Here just make sure they're initialized.
+ */
+ days = threehndths = 0;
+ }
+
+ tv.secs = (time_t)((days * G_GUINT64_CONSTANT(86400)) + (threehndths/300) - G_GUINT64_CONSTANT(2208988800)); /* 2208988800 - seconds between Jan 1, 1900 and Jan 1, 1970 */
+ tv.nsecs = (threehndths%300) * 10000000 / 3;
+ proto_tree_add_time(sub_tree, hf_tds_type_varbyte_data_absdatetime, tvb, offset, 8, &tv);
+}
+
+static void
+handle_tds_sql_smalldatetime(tvbuff_t *tvb, guint offset, proto_tree *sub_tree, tds_conv_info_t *tds_info)
+{
+ /* SQL smalldatetime */
+ nstime_t tv = NSTIME_INIT_ZERO;
+ guint64 days, minutes;
+
+ if (tds_info->tds_encoding_date4 == TDS_DATE4_DATE_FIRST) {
+ days = tvb_get_guint16(tvb, offset, tds_get_int2_encoding(tds_info));
+ minutes = tvb_get_guint16(tvb, offset + 2, tds_get_int2_encoding(tds_info));
+ }
+ else if (tds_info->tds_encoding_date4 == TDS_DATE4_TIME_FIRST) {
+ minutes = tvb_get_guint16(tvb, offset, tds_get_int2_encoding(tds_info));
+ days = tvb_get_guint16(tvb, offset + 2, tds_get_int2_encoding(tds_info));
+ }
+ else {
+ /* TODO Check these values in the login packet and offer expert information.
+ * Here just make sure they're initialized.
+ */
+ days = minutes = 0;
+ }
+
+
+ tv.secs = (time_t)((days * G_GUINT64_CONSTANT(86400)) + (minutes * 60) - G_GUINT64_CONSTANT(2208988800)); /* 2208988800 - seconds between Jan 1, 1900 and Jan 1, 1970 */
+ tv.nsecs = 0;
+ proto_tree_add_time(sub_tree, hf_tds_type_varbyte_data_absdatetime, tvb, offset, 8, &tv);
+}
+
+static void
+handle_tds_sql_smallmoney(tvbuff_t *tvb, guint offset, proto_tree *sub_tree, tds_conv_info_t *tds_info)
+{
+ gdouble dblvalue = (gfloat)tvb_get_guint32(tvb, offset, tds_get_int4_encoding(tds_info));
+ proto_tree_add_double_format_value(sub_tree, hf_tds_type_varbyte_data_double,
+ tvb, offset, 4, dblvalue, "%.4f", dblvalue/10000);
+}
+
+static void
+handle_tds_sql_money(tvbuff_t *tvb, guint offset, proto_tree *sub_tree, tds_conv_info_t *tds_info)
+{
+ guint64 moneyval = tvb_get_guint32(tvb, offset, tds_get_int4_encoding(tds_info));
+ gdouble dblvalue = (gdouble)((moneyval << 32) + tvb_get_guint32(tvb, offset + 4,
+ tds_get_int4_encoding(tds_info)));
+
+ proto_tree_add_double_format_value(sub_tree, hf_tds_type_varbyte_data_double,
+ tvb, offset, 8, dblvalue, "%.4f", dblvalue/10000);
+}
+
+static void
dissect_tds_type_varbyte(tvbuff_t *tvb, guint *offset, packet_info *pinfo, proto_tree *tree, int hf, tds_conv_info_t *tds_info,
guint8 data_type, guint8 scale, gboolean plp, gint fieldnum, const guint8 *name)
{
guint length, textptrlen;
proto_tree *sub_tree = NULL;
proto_item *item = NULL, *length_item = NULL;
- int encoding = tds_little_endian ? ENC_LITTLE_ENDIAN : ENC_BIG_ENDIAN;
item = proto_tree_add_item(tree, hf, tvb, *offset, 0, ENC_NA);
sub_tree = proto_item_add_subtree(item, ett_tds_type_varbyte);
@@ -2086,14 +2166,20 @@ dissect_tds_type_varbyte(tvbuff_t *tvb, guint *offset, packet_info *pinfo, proto
proto_tree_add_item(sub_tree, hf_tds_type_varbyte_data_double, tvb, *offset, 8, ENC_LITTLE_ENDIAN);
*offset += 8;
break;
- case TDS_DATA_TYPE_MONEY4: /* SmallMoney (4 byte data representation) */
case TDS_DATA_TYPE_DATETIME4: /* SmallDateTime (4 byte data representation) */
- /*TODO*/
+ handle_tds_sql_smalldatetime(tvb, *offset, sub_tree, tds_info);
+ *offset += 4;
+ break;
+ case TDS_DATA_TYPE_MONEY4: /* SmallMoney (4 byte data representation) */
+ handle_tds_sql_smallmoney(tvb, *offset, sub_tree, tds_info);
*offset += 4;
break;
- case TDS_DATA_TYPE_MONEY: /* Money (8 byte data representation) */
case TDS_DATA_TYPE_DATETIME: /* DateTime (8 byte data representation) */
- /*TODO*/
+ handle_tds_sql_datetime(tvb, *offset, sub_tree, tds_info);
+ *offset += 8;
+ break;
+ case TDS_DATA_TYPE_MONEY: /* Money (8 byte data representation) */
+ handle_tds_sql_money(tvb, *offset, sub_tree, tds_info);
*offset += 8;
break;
@@ -2182,17 +2268,11 @@ dissect_tds_type_varbyte(tvbuff_t *tvb, guint *offset, packet_info *pinfo, proto
if(length > 0) {
if(length == 4)
{
- gdouble dblvalue = (gfloat)tvb_get_guint32(tvb, *offset, encoding);
- proto_tree_add_double_format_value(sub_tree, hf_tds_type_varbyte_data_double, tvb, *offset, 4, dblvalue, "%.4f", dblvalue/10000);
+ handle_tds_sql_smallmoney(tvb, *offset, sub_tree, tds_info);
}
if(length == 8)
{
- gdouble dblvalue;
- guint64 moneyval;
-
- moneyval = tvb_get_guint32(tvb, *offset, encoding);
- dblvalue = (gdouble)((moneyval << 32) + tvb_get_guint32(tvb, *offset + 4, encoding));
- proto_tree_add_double_format_value(sub_tree, hf_tds_type_varbyte_data_double, tvb, *offset, 8, dblvalue, "%.4f", dblvalue/10000);
+ handle_tds_sql_money(tvb, *offset, sub_tree, tds_info);
}
*offset += length;
}
@@ -2257,25 +2337,11 @@ dissect_tds_type_varbyte(tvbuff_t *tvb, guint *offset, packet_info *pinfo, proto
if(length > 0) {
if(length == 4)
{
- /* SQL smalldatetime */
- nstime_t tv;
- guint days = tvb_get_guint16(tvb, *offset, encoding);
- guint minutes = tvb_get_guint16(tvb, *offset + 2, encoding);
-
- tv.secs = (time_t)((days * G_GUINT64_CONSTANT(86400)) + (minutes * 60) - G_GUINT64_CONSTANT(2208988800)); /* 2208988800 - seconds between Jan 1, 1900 and Jan 1, 1970 */
- tv.nsecs = 0;
- proto_tree_add_time(sub_tree, hf_tds_type_varbyte_data_absdatetime, tvb, *offset, length, &tv);
+ handle_tds_sql_smalldatetime(tvb, *offset, sub_tree, tds_info);
}
- if(length == 8)
+ else if(length == 8)
{
- /* SQL datetime */
- nstime_t tv;
- guint days = tvb_get_guint32(tvb, *offset, encoding);
- guint threehndths = tvb_get_guint32(tvb, *offset + 4, encoding);
-
- tv.secs = (time_t)((days * G_GUINT64_CONSTANT(86400)) + (threehndths/300) - G_GUINT64_CONSTANT(2208988800)); /* 2208988800 - seconds between Jan 1, 1900 and Jan 1, 1970 */
- tv.nsecs = (threehndths%300) * 10000000 / 3;
- proto_tree_add_time(sub_tree, hf_tds_type_varbyte_data_absdatetime, tvb, *offset, length, &tv);
+ handle_tds_sql_datetime(tvb, *offset, sub_tree, tds_info);
}
*offset += length;
}
@@ -3995,7 +4061,8 @@ dissect_tds45_login(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, tds_con
offset++;
proto_tree_add_item(login_options_tree, hf_tdslogin_option_float, tvb, offset, 1, ENC_NA);
offset++;
- proto_tree_add_item(login_options_tree, hf_tdslogin_option_date8, tvb, offset, 1, ENC_NA);
+ proto_tree_add_item_ret_uint(login_options_tree, hf_tdslogin_option_date8, tvb,
+ offset, 1, ENC_NA, &tds_info->tds_encoding_date8);
offset++;
proto_tree_add_item(login_options_tree, hf_tdslogin_option_usedb, tvb, offset, 1, ENC_NA);
offset++;
@@ -4042,7 +4109,8 @@ dissect_tds45_login(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, tds_con
offset++;
proto_tree_add_item(login_options2_tree, hf_tdslogin_option2_flt4, tvb, offset, 1, ENC_NA );
offset++;
- proto_tree_add_item(login_options2_tree, hf_tdslogin_option2_date4, tvb, offset, 1, ENC_NA );
+ proto_tree_add_item_ret_uint(login_options2_tree, hf_tdslogin_option2_date4,
+ tvb, offset, 1, ENC_NA, &tds_info->tds_encoding_date4);
offset++;
offset = dissect_tds45_login_name(tvb, pinfo, login_tree,
@@ -6430,9 +6498,11 @@ fill_tds_info_defaults(tds_conv_info_t *tds_info)
case TDS_PROTOCOL_7_4:
case TDS_PROTOCOL_NOT_SPECIFIED:
default:
- tds_info->tds_encoding_int4 = TDS_INT4_LITTLE_ENDIAN;
- tds_info->tds_encoding_int2 = TDS_INT2_LITTLE_ENDIAN;
- tds_info->tds_encoding_char = TDS_CHAR_UTF16;
+ tds_info->tds_encoding_int4 = TDS_INT4_LITTLE_ENDIAN;
+ tds_info->tds_encoding_int2 = TDS_INT2_LITTLE_ENDIAN;
+ tds_info->tds_encoding_char = TDS_CHAR_UTF16;
+ tds_info->tds_encoding_date8 = TDS_DATE8_DATE_FIRST ;
+ tds_info->tds_encoding_date4 = TDS_DATE4_DATE_FIRST ;
break;
}
}