aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCraig Jackson <cejackson51@gmail.com>2018-05-10 12:52:22 -0400
committerAnders Broman <a.broman58@gmail.com>2018-07-30 10:33:59 +0000
commit0049a1afaedef13d13d479f5b860449a51ca0c7e (patch)
tree3acd430e16403a2ab16ff5034b268ab770b6dcb1
parente7f7e04eff286557a86ff152b0faba02223aa070 (diff)
Add basic support for TDS 5 (Sybase) cursors.
Change-Id: Ie04489b5445dc473d9bc6d772c1c33270da9b363 Reviewed-on: https://code.wireshark.org/review/28835 Petri-Dish: Alexis La Goutte <alexis.lagoutte@gmail.com> Tested-by: Petri Dish Buildbot Reviewed-by: Anders Broman <a.broman58@gmail.com>
-rw-r--r--epan/dissectors/packet-tds.c850
1 files changed, 839 insertions, 11 deletions
diff --git a/epan/dissectors/packet-tds.c b/epan/dissectors/packet-tds.c
index 3ec7a42b99..61f70ab8bb 100644
--- a/epan/dissectors/packet-tds.c
+++ b/epan/dissectors/packet-tds.c
@@ -141,6 +141,7 @@
#include <epan/reassemble.h>
#include <epan/prefs.h>
#include <epan/expert.h>
+#include <epan/proto_data.h>
#include "packet-tcp.h"
#define TDS_QUERY_PKT 1 /* SQLBatch in MS-TDS revision 18.0 */
@@ -229,6 +230,20 @@
#define TDS_CAP_REQUEST 1
#define TDS_CAP_RESPONSE 2
+/* TDS 5 Cursor fetch options */
+#define TDS_CUR_NEXT 1
+#define TDS_CUR_PREV 2
+#define TDS_CUR_FIRST 3
+#define TDS_CUR_LAST 4
+#define TDS_CUR_ABS 5
+#define TDS_CUR_REL 6
+
+/* TDS 5 Cursor Info Commands */
+#define TDS_CURINFO_SET_FETCH_COUNT 1
+#define TDS_CURINFO_INQUIRE 2
+#define TDS_CURINFO_INFORM 3
+#define TDS_CURINFO_LISTALL 4
+
/* TDS 7 Prelogin options */
#define TDS7_PRELOGIN_OPTION_VERSION 0x00
#define TDS7_PRELOGIN_OPTION_ENCRYPTION 0x01
@@ -867,6 +882,59 @@ static int hf_tds_control = -1;
static int hf_tds_control_length = -1;
static int hf_tds_control_fmt = -1;
+/* CURCLOSE token (TDS_CURCLOSE_TOKEN) */
+static int hf_tds_curclose = -1;
+static int hf_tds_curclose_length = -1;
+static int hf_tds_curclose_cursorid = -1;
+static int hf_tds_curclose_cursor_name = -1;
+static int hf_tds_curclose_option_deallocate = -1;
+
+/* CURDECLARE token (TDS_CURDECLARE_TOKEN) */
+static int hf_tds_curdeclare = -1;
+static int hf_tds_curdeclare_length = -1;
+static int hf_tds_curdeclare_cursor_name = -1;
+static int hf_tds_curdeclare_options = -1;
+static int hf_tds_curdeclare_options_rdonly = -1;
+static int hf_tds_curdeclare_options_updatable = -1;
+static int hf_tds_curdeclare_options_sensitive = -1;
+static int hf_tds_curdeclare_options_dynamic = -1;
+static int hf_tds_curdeclare_options_implicit = -1;
+static int hf_tds_curdeclare_status_parameterized = -1;
+static int hf_tds_curdeclare_statement = -1;
+static int hf_tds_curdeclare_update_columns_num = -1;
+static int hf_tds_curdeclare_update_columns_name = -1;
+
+/* CURFETCH token (TDS_CURFETCH_TOKEN) */
+static int hf_tds_curfetch = -1;
+static int hf_tds_curfetch_length = -1;
+static int hf_tds_curfetch_cursorid = -1;
+static int hf_tds_curfetch_cursor_name = -1;
+static int hf_tds_curfetch_type = -1;
+static int hf_tds_curfetch_rowcnt = -1;
+
+/* CURINFO token (TDS_CURINFO_TOKEN) */
+static int hf_tds_curinfo = -1;
+static int hf_tds_curinfo_length = -1;
+static int hf_tds_curinfo_cursorid = -1;
+static int hf_tds_curinfo_cursor_name = -1;
+static int hf_tds_curinfo_cursor_command = -1;
+static int hf_tds_curinfo_cursor_status = -1;
+static int hf_tds_curinfo_cursor_status_declared = -1;
+static int hf_tds_curinfo_cursor_status_open = -1;
+static int hf_tds_curinfo_cursor_status_closed = -1;
+static int hf_tds_curinfo_cursor_status_rdonly = -1;
+static int hf_tds_curinfo_cursor_status_updatable = -1;
+static int hf_tds_curinfo_cursor_status_rowcnt = -1;
+static int hf_tds_curinfo_cursor_status_dealloc = -1;
+static int hf_tds_curinfo_cursor_rowcnt = -1;
+
+/* CUROPEN token (TDS_CUROPEN_TOKEN) */
+static int hf_tds_curopen = -1;
+static int hf_tds_curopen_length = -1;
+static int hf_tds_curopen_cursorid = -1;
+static int hf_tds_curopen_cursor_name = -1;
+static int hf_tds_curopen_status_parameterized = -1;
+
/* TDS5 DBRPC Token (TDS5_DBRPC_TOKEN) */
static int hf_tds_dbrpc = -1;
static int hf_tds_dbrpc_length = -1;
@@ -1200,6 +1268,8 @@ static gint ett_tds_prelogin_option = -1;
static gint ett_tds7_featureextack = -1;
static gint ett_tds7_featureextack_feature = -1;
static gint ett_tds5_dbrpc_options = -1;
+static gint ett_tds5_curdeclare_options = -1;
+static gint ett_tds5_curinfo_status = -1;
/* static expert_field ei_tds_type_info_type_undecoded = EI_INIT; */
static expert_field ei_tds_invalid_length = EI_INIT;
@@ -1208,6 +1278,7 @@ static expert_field ei_tds_type_info_type = EI_INIT;
static expert_field ei_tds_all_headers_header_type = EI_INIT;
/* static expert_field ei_tds_token_stats = EI_INIT; */
static expert_field ei_tds_invalid_plp_type = EI_INIT;
+static expert_field ei_tds_cursor_name_mismatch = EI_INIT;
/* Desegmentation of Netlib buffers crossing TCP segment boundaries. */
static gboolean tds_desegment = TRUE;
@@ -1241,12 +1312,31 @@ static dissector_handle_t ntlmssp_handle;
static dissector_handle_t gssapi_handle;
static dissector_handle_t smp_handle;
+#define TDS_CURSOR_NAME_VALID 0x01
+#define TDS_CURSOR_ID_VALID 0x02
+#define TDS_CURSOR_ROWINFO_VALID 0x04
+#define TDS_CURSOR_IN_CONV_TABLE 0x08
+#define TDS_CURSOR_FETCH_PENDING 0x10
+
+typedef struct {
+ const guint8 *tds_cursor_name;
+ guint tds_cursor_id;
+ struct _netlib_data *tds_cursor_rowinfo;
+ guint tds_cursor_flags;
+} tds_cursor_info_t;
+
+typedef struct {
+ tds_cursor_info_t *tds_conv_cursor_current;
+ wmem_tree_t *tds_conv_cursor_table;
+} tds_conv_cursor_info_t;
+
typedef struct {
+ tds_conv_cursor_info_t *tds_conv_cursor_info;
gint tds_version;
- gboolean tds_packets_in_order;
guint tds_encoding_int2;
guint tds_encoding_int4;
guint tds_encoding_char;
+ gboolean tds_packets_in_order;
} tds_conv_info_t;
/* The actual TDS protocol values used on the wire. */
@@ -1553,6 +1643,24 @@ static const value_string tds_capability_type[] = {
{0, NULL}
};
+static const value_string tds_curfetch_types[] = {
+ {TDS_CUR_NEXT, "Next"},
+ {TDS_CUR_PREV, "Previous"},
+ {TDS_CUR_FIRST, "First"},
+ {TDS_CUR_LAST, "Last"},
+ {TDS_CUR_ABS, "Absolute"},
+ {TDS_CUR_REL, "Relative"},
+ {0, NULL}
+};
+
+static const value_string tds_curinfo_commands[] = {
+ {TDS_CURINFO_SET_FETCH_COUNT, "Set fetch count"},
+ {TDS_CURINFO_INQUIRE, "Inquire cursor state"},
+ {TDS_CURINFO_INFORM, "Report information about a cursor"},
+ {TDS_CURINFO_LISTALL, "List all open cursors"},
+ {0, NULL}
+};
+
static const value_string login_field_names[] = {
{0, "Client Name"},
{1, "Username"},
@@ -1800,6 +1908,32 @@ get_size_by_coltype(int servertype)
}
}
+static struct _netlib_data *
+copy_nl_data(wmem_allocator_t *allocator, struct _netlib_data *nl_data)
+{
+ struct _netlib_data *new_nl_data;
+ guint col;
+
+
+ new_nl_data = wmem_new0(allocator, struct _netlib_data);
+ new_nl_data->num_cols = nl_data->num_cols;
+ for (col=0; col < nl_data->num_cols; col++) {
+ struct _tds_col *old_column = nl_data->columns[col];
+ struct _tds_col *new_column = wmem_new0(allocator, struct _tds_col);
+ new_nl_data->columns[col] = new_column;
+ if (old_column->name) {
+ new_column->name = wmem_strdup(allocator, old_column->name);
+ }
+ new_column->csize = old_column->csize;
+ new_column->utype = old_column->utype;
+ new_column->ctype = old_column->ctype;
+ new_column->precision = old_column->precision;
+ new_column->scale = old_column->scale;
+ }
+
+ return new_nl_data;
+}
+
static void
dissect_tds_all_headers(tvbuff_t *tvb, guint *offset, packet_info *pinfo, proto_tree *tree)
{
@@ -2469,8 +2603,410 @@ dissect_tds5_lang_token(tvbuff_t *tvb, guint offset, proto_tree *tree, tds_conv_
return cur - offset;
}
+static void
+tds5_check_cursor_name(packet_info *pinfo, proto_item *pi,
+ tds_cursor_info_t *cursor_current, const guint8 *cursorname)
+{
+ if (cursorname && cursor_current &&
+ ( cursor_current->tds_cursor_flags & TDS_CURSOR_NAME_VALID)) {
+ if (g_strcmp0(cursorname,
+ cursor_current->tds_cursor_name) != 0) {
+ expert_add_info_format(pinfo, pi, &ei_tds_cursor_name_mismatch,
+ "Cursor name %s does not match current cursor name %s",
+ cursorname, cursor_current->tds_cursor_name);
+ }
+ }
+}
+
+static void
+tds_cursor_info_init(tds_conv_info_t *tds_info)
+{
+ tds_conv_cursor_info_t *conv_cursor_info = tds_info->tds_conv_cursor_info;
+
+ if (!conv_cursor_info) {
+ conv_cursor_info =
+ wmem_new0(wmem_file_scope(), tds_conv_cursor_info_t);
+ conv_cursor_info->tds_conv_cursor_table =
+ wmem_tree_new(wmem_file_scope());
+ tds_info->tds_conv_cursor_info = conv_cursor_info;
+ }
+}
+
+static guint
+dissect_tds5_curclose_token(tvbuff_t *tvb, packet_info *pinfo, guint offset,
+ proto_tree *tree, tds_conv_info_t *tds_info)
+{
+ guint len, cur = offset;
+ guint cursorid;
+ proto_item *cursor_id_pi;
+ tds_cursor_info_t *packet_cursor =
+ (tds_cursor_info_t *) p_get_proto_data(wmem_file_scope(), pinfo, proto_tds, 0);
+
+ proto_tree_add_item_ret_uint(tree, hf_tds_curclose_length, tvb, cur, 2, tds_get_int2_encoding(tds_info), &len);
+ cur += 2;
+
+ cursor_id_pi = proto_tree_add_item_ret_uint(tree, hf_tds_curclose_cursorid,
+ tvb, cur, 4, tds_get_int4_encoding(tds_info), &cursorid);
+ cur += 4;
+
+ if (cursorid == 0) {
+ guint cursorname_len;
+ const guint8 *cursorname;
+ proto_item *cursor_name_pi;
+
+ cursor_name_pi = proto_tree_add_item_ret_string_and_length(tree,
+ hf_tds_curclose_cursor_name,
+ tvb, cur + 1, cursorname_len, tds_get_char_encoding(tds_info)|ENC_NA,
+ wmem_packet_scope(), &cursorname, &cursorname_len);
+ cur += cursorname_len;
+ tds5_check_cursor_name(pinfo, cursor_name_pi, packet_cursor, cursorname);
+ }
+ else if (packet_cursor && cursor_id_pi &&
+ (packet_cursor->tds_cursor_flags & TDS_CURSOR_NAME_VALID)) {
+ proto_item_append_text(cursor_id_pi, " (%s)",
+ packet_cursor->tds_cursor_name);
+ }
+
+ proto_tree_add_item(tree, hf_tds_curclose_option_deallocate, tvb, cur, 1, ENC_NA);
+ cur += 1;
+
+ if (!PINFO_FD_VISITED(pinfo) && !packet_cursor) {
+ tds_conv_cursor_info_t *conv_cursor_info;
+
+ tds_cursor_info_init(tds_info);
+ conv_cursor_info = tds_info->tds_conv_cursor_info;
+ if (cursorid) {
+ tds_cursor_info_t *cursor_current;
+ cursor_current =
+ (tds_cursor_info_t *) wmem_tree_lookup32(conv_cursor_info->tds_conv_cursor_table,
+ cursorid);
+ if (cursor_current) {
+ p_add_proto_data(wmem_file_scope(),
+ pinfo, proto_tds, 0, cursor_current);
+ }
+ }
+ }
+
+ return cur - offset;
+}
+
+static const int *tds_curdeclare_hf_fields[] = {
+ &hf_tds_curdeclare_options_rdonly,
+ &hf_tds_curdeclare_options_updatable,
+ &hf_tds_curdeclare_options_sensitive,
+ &hf_tds_curdeclare_options_dynamic,
+ &hf_tds_curdeclare_options_implicit,
+ NULL
+};
+
+static guint
+dissect_tds5_curdeclare_token(tvbuff_t *tvb, packet_info *pinfo, guint offset,
+ proto_tree *tree, tds_conv_info_t *tds_info)
+{
+ guint len, cur = offset, stmtlen, num_updatable_columns;
+ guint cursorname_len;
+ const guint8 *cursorname;
+ tds_cursor_info_t *packet_cursor =
+ (tds_cursor_info_t *) p_get_proto_data(wmem_file_scope(), pinfo, proto_tds, 0);
+
+ proto_tree_add_item_ret_uint(tree, hf_tds_curdeclare_length, tvb, cur, 2,
+ tds_get_int2_encoding(tds_info), &len);
+ cur += 2;
+
+ proto_tree_add_item_ret_string_and_length(tree, hf_tds_curdeclare_cursor_name,
+ tvb, cur, 1, tds_get_char_encoding(tds_info)|ENC_NA,
+ wmem_packet_scope(), &cursorname, &cursorname_len);
+ cur += cursorname_len;
+
+ /* Options is one byte, as is status. */
+ proto_tree_add_bitmask(tree, tvb, cur, hf_tds_curdeclare_options,
+ ett_tds5_curdeclare_options, tds_curdeclare_hf_fields, ENC_NA);
+ proto_tree_add_item(tree, hf_tds_curdeclare_status_parameterized, tvb,
+ cur + 1, 1, ENC_NA);
+ cur += 2;
+
+ proto_tree_add_item_ret_length(tree, hf_tds_curdeclare_statement, tvb, cur, 2,
+ tds_get_char_encoding(tds_info)|tds_get_int2_encoding(tds_info), &stmtlen);
+ cur += stmtlen;
+
+ proto_tree_add_item_ret_uint(tree, hf_tds_curdeclare_update_columns_num, tvb, cur, 1,
+ ENC_NA, &num_updatable_columns);
+ cur += 1;
+
+ if (num_updatable_columns > 0) {
+ guint column_name_len;
+
+ proto_tree_add_item_ret_length(tree, hf_tds_curdeclare_update_columns_name,
+ tvb, cur, 1, tds_get_char_encoding(tds_info)|ENC_NA, &column_name_len);
+ cur += column_name_len;
+ }
+
+ /*
+ * If being processed in order (first time through) prepare to correlate the
+ * curdeclare with the curinfo response.
+ */
+ if (!PINFO_FD_VISITED(pinfo)) {
+ tds_conv_cursor_info_t *conv_cursor_info;
+ tds_cursor_info_t *cursor_current;
+
+ tds_cursor_info_init(tds_info);
+ conv_cursor_info = tds_info->tds_conv_cursor_info;
+
+ cursor_current = conv_cursor_info->tds_conv_cursor_current;
+ if (!cursor_current) {
+ cursor_current = wmem_new0(wmem_file_scope(), tds_cursor_info_t);
+ conv_cursor_info->tds_conv_cursor_current = cursor_current;
+ }
+ else if (!(cursor_current->tds_cursor_flags & TDS_CURSOR_IN_CONV_TABLE)) {
+ /*
+ * The cursor was allocated, but never entered into the table.
+ * This won't happen normally, but it could happen if the client were
+ * coded unusually and pending activity were to be aborted mid-sequence.
+ * Free possible existing values to avoid a file-level leak.
+ */
+ wmem_free(wmem_file_scope(), (void *) cursor_current->tds_cursor_name);
+ wmem_free(wmem_file_scope(), (void *) cursor_current->tds_cursor_rowinfo);
+ (void) memset(cursor_current, 0, sizeof (tds_cursor_info_t));
+ }
+ cursor_current->tds_cursor_name = wmem_strdup(wmem_file_scope(), cursorname);
+ cursor_current->tds_cursor_flags |= TDS_CURSOR_NAME_VALID;
+ if (packet_cursor && packet_cursor != cursor_current) {
+ p_remove_proto_data(wmem_file_scope(), pinfo, proto_tds, 0);
+ packet_cursor = NULL;
+ }
+ if (!packet_cursor) {
+ p_add_proto_data(wmem_file_scope(), pinfo, proto_tds, 0, cursor_current);
+ }
+
+ }
+ return cur - offset;
+}
+
+static guint
+dissect_tds5_curfetch_token(tvbuff_t *tvb, packet_info *pinfo, guint offset,
+ proto_tree *tree, tds_conv_info_t *tds_info)
+{
+ guint len, cur = offset;
+ guint cursorid;
+ gint curfetch_type;
+ const guint8 *cursorname;
+ proto_item *cursor_id_pi;
+ tds_cursor_info_t *packet_cursor =
+ (tds_cursor_info_t *) p_get_proto_data(wmem_file_scope(), pinfo, proto_tds, 0);
+
+ proto_tree_add_item_ret_uint(tree, hf_tds_curfetch_length, tvb, cur, 2, tds_get_int2_encoding(tds_info), &len);
+ cur += 2;
+
+ cursor_id_pi = proto_tree_add_item_ret_uint(tree, hf_tds_curfetch_cursorid,
+ tvb, cur, 4, tds_get_int4_encoding(tds_info), &cursorid);
+ cur += 4;
+
+ if (cursorid == 0) {
+ guint cursorname_len;
+ proto_item *cursor_name_pi;
+
+ cursor_name_pi = proto_tree_add_item_ret_string_and_length(tree, hf_tds_curfetch_cursor_name,
+ tvb, cur, 1, tds_get_char_encoding(tds_info)|ENC_NA,
+ wmem_packet_scope(), &cursorname, &cursorname_len);
+ tds5_check_cursor_name(pinfo, cursor_name_pi, packet_cursor, cursorname);
+ cur += cursorname_len;
+ }
+ else if (packet_cursor && cursor_id_pi &&
+ (packet_cursor->tds_cursor_flags & TDS_CURSOR_NAME_VALID)) {
+ proto_item_append_text(cursor_id_pi, " (%s)",
+ packet_cursor->tds_cursor_name);
+ }
+
+ proto_tree_add_item_ret_uint(tree, hf_tds_curfetch_type, tvb, cur, 1,
+ ENC_NA, &curfetch_type);
+ cur += 1;
+
+ if (curfetch_type >= TDS_CUR_ABS) {
+ proto_tree_add_item(tree, hf_tds_curfetch_rowcnt, tvb, cur, 4,
+ tds_get_int4_encoding(tds_info));
+ cur += 4;
+ }
+
+ if (!PINFO_FD_VISITED(pinfo) && !packet_cursor) {
+ tds_conv_cursor_info_t *conv_cursor_info = tds_info->tds_conv_cursor_info;
+ tds_cursor_info_t *cursor_current;
+
+ if (!conv_cursor_info) {
+ conv_cursor_info =
+ wmem_new0(wmem_file_scope(), tds_conv_cursor_info_t);
+ conv_cursor_info->tds_conv_cursor_table =
+ wmem_tree_new(wmem_file_scope());
+ tds_info->tds_conv_cursor_info = conv_cursor_info;
+ }
+ if (cursorid) {
+ cursor_current =
+ (tds_cursor_info_t *) wmem_tree_lookup32(conv_cursor_info->tds_conv_cursor_table,
+ cursorid);
+ if (cursor_current) {
+ p_add_proto_data(wmem_file_scope(),
+ pinfo, proto_tds, 0, cursor_current);
+ cursor_current->tds_cursor_flags |= TDS_CURSOR_FETCH_PENDING;
+ conv_cursor_info->tds_conv_cursor_current = cursor_current;
+ }
+ }
+ }
+
+ return cur - offset;
+}
+
+static const int *tds_curinfo_hf_fields[] = {
+ &hf_tds_curinfo_cursor_status_declared,
+ &hf_tds_curinfo_cursor_status_open,
+ &hf_tds_curinfo_cursor_status_closed,
+ &hf_tds_curinfo_cursor_status_rdonly,
+ &hf_tds_curinfo_cursor_status_updatable,
+ &hf_tds_curinfo_cursor_status_rowcnt,
+ &hf_tds_curinfo_cursor_status_dealloc,
+ NULL
+};
+
+static guint
+dissect_tds5_curinfo_token(tvbuff_t *tvb, packet_info *pinfo, guint offset,
+ proto_tree *tree, tds_conv_info_t *tds_info)
+{
+ guint len, cur = offset;
+ const guint8 *cursorname = NULL;
+ guint cursorid;
+ guint cursor_command;
+ tds_cursor_info_t *packet_cursor =
+ (tds_cursor_info_t *) p_get_proto_data(wmem_file_scope(), pinfo, proto_tds, 0);
+ proto_item *cursor_id_pi;
+
+ proto_tree_add_item_ret_uint(tree, hf_tds_curinfo_length, tvb, cur, 2,
+ tds_get_int2_encoding(tds_info), &len);
+ cur += 2;
+
+ cursor_id_pi = proto_tree_add_item_ret_uint(tree, hf_tds_curinfo_cursorid,
+ tvb, cur, 4, tds_get_int4_encoding(tds_info), &cursorid);
+ cur += 4;
+
+ if (cursorid == 0) {
+ guint cursorname_len;
+ proto_item *cursor_name_pi;
+ cursor_name_pi = proto_tree_add_item_ret_string_and_length(tree,
+ hf_tds_curinfo_cursor_name, tvb, cur, 1,
+ tds_get_char_encoding(tds_info)|ENC_NA,
+ wmem_packet_scope(), &cursorname, &cursorname_len);
+ cur += cursorname_len;
+ tds5_check_cursor_name(pinfo, cursor_name_pi, packet_cursor, cursorname);
+ }
+ else if (packet_cursor && cursor_id_pi &&
+ (packet_cursor->tds_cursor_flags & TDS_CURSOR_NAME_VALID)) {
+ proto_item_append_text(cursor_id_pi, " (%s)",
+ packet_cursor->tds_cursor_name);
+ }
+
+
+ proto_tree_add_item_ret_uint(tree, hf_tds_curinfo_cursor_command,
+ tvb, cur, 1, ENC_NA, &cursor_command);
+ cur += 1;
+
+ proto_tree_add_bitmask(tree, tvb, cur, hf_tds_curinfo_cursor_status,
+ ett_tds5_curinfo_status, tds_curinfo_hf_fields,
+ tds_get_int2_encoding(tds_info));
+ cur += 2;
+
+ /* offset + 2 to skip past the length, which does not include itself. */
+ if (len - (cur - (offset + 2)) == 4) {
+ proto_tree_add_item(tree, hf_tds_curinfo_cursor_rowcnt, tvb, cur, 4,
+ tds_get_int4_encoding(tds_info));
+ cur += 4;
+ }
+
+ /*
+ * If we're going through sequentially, and it's an INFORM response,
+ * try to correlate cursor names with cursor ids.
+ */
+ if (!PINFO_FD_VISITED(pinfo) &&
+ cursor_command == TDS_CURINFO_INFORM &&
+ !packet_cursor) {
+ tds_conv_cursor_info_t *conv_cursor_info = tds_info->tds_conv_cursor_info;
+ tds_cursor_info_t *cursor_current;
+
+ if (!conv_cursor_info) {
+ conv_cursor_info =
+ wmem_new0(wmem_file_scope(), tds_conv_cursor_info_t);
+ conv_cursor_info->tds_conv_cursor_table =
+ wmem_tree_new(wmem_file_scope());
+ tds_info->tds_conv_cursor_info = conv_cursor_info;
+ }
+ cursor_current = conv_cursor_info->tds_conv_cursor_current;
+ if (!cursor_current) {
+ cursor_current = wmem_new0(wmem_file_scope(), tds_cursor_info_t);
+ conv_cursor_info->tds_conv_cursor_current = cursor_current;
+ }
+ p_add_proto_data(wmem_file_scope(), pinfo, proto_tds, 0, cursor_current);
+ packet_cursor = cursor_current;
+ if (cursorid != 0) {
+ if (!(cursor_current->tds_cursor_flags & TDS_CURSOR_ID_VALID)) {
+ cursor_current->tds_cursor_id = cursorid;
+ cursor_current->tds_cursor_flags |= TDS_CURSOR_ID_VALID;
+ wmem_tree_insert32(conv_cursor_info->tds_conv_cursor_table,
+ cursorid, cursor_current);
+ cursor_current->tds_cursor_flags |= TDS_CURSOR_IN_CONV_TABLE;
+ } else if (cursor_current->tds_cursor_id != cursorid) {
+ tds_cursor_info_t *temp_cursor =
+ (tds_cursor_info_t *) wmem_tree_lookup32(conv_cursor_info->tds_conv_cursor_table,
+ cursorid);
+ if (temp_cursor != cursor_current) {
+ cursor_current = temp_cursor;
+ conv_cursor_info->tds_conv_cursor_current = cursor_current;
+ p_remove_proto_data(wmem_file_scope(), pinfo, proto_tds, 0);
+ p_add_proto_data(wmem_file_scope(), pinfo, proto_tds, 0, cursor_current);
+
+ }
+ }
+ }
+ }
+ return cur - offset;
+}
+
+static guint
+dissect_tds5_curopen_token(tvbuff_t *tvb, packet_info *pinfo, guint offset,
+ proto_tree *tree, tds_conv_info_t *tds_info)
+{
+ guint len, cur = offset;
+ guint cursorid;
+ proto_item *cursor_id_pi;
+ tds_cursor_info_t *packet_cursor =
+ (tds_cursor_info_t *) p_get_proto_data(wmem_file_scope(), pinfo, proto_tds, 0);
+
+ proto_tree_add_item_ret_uint(tree, hf_tds_curopen_length, tvb, cur, 2, tds_get_int2_encoding(tds_info), &len);
+ cur += 2;
+
+ cursor_id_pi = proto_tree_add_item_ret_uint(tree, hf_tds_curopen_cursorid,
+ tvb, cur, 4, tds_get_int4_encoding(tds_info), &cursorid);
+ cur += 4;
+
+ if (cursorid == 0) {
+ guint cursorname_len;
+ const guint8 *cursorname;
+ proto_item *pi;
+
+ pi = proto_tree_add_item_ret_string_and_length(tree, hf_tds_curopen_cursor_name,
+ tvb, cur, 1, tds_get_char_encoding(tds_info)|ENC_NA,
+ wmem_packet_scope(), &cursorname, &cursorname_len);
+ cur += cursorname_len;
+ tds5_check_cursor_name(pinfo, pi, packet_cursor, cursorname);
+ }
+ else if (packet_cursor && cursor_id_pi &&
+ (packet_cursor->tds_cursor_flags & TDS_CURSOR_NAME_VALID)) {
+ proto_item_append_text(cursor_id_pi, " (%s)",
+ packet_cursor->tds_cursor_name);
+ }
+
+ proto_tree_add_item(tree, hf_tds_curopen_status_parameterized, tvb, cur, 1, ENC_NA);
+ cur += 1;
+
+ return cur - offset;
+}
static const int *hf_req_0[9] = {
&hf_tds_capability_req_lang,
@@ -2965,7 +3501,7 @@ dissect_tds5_params_token(tvbuff_t *tvb, packet_info *pinfo,
{
guint cur = offset, i;
- /* TDS5 does not have the Paritially Length-Prefixed concept, so the "plp"
+ /* TDS5 does not have the Partially Length-Prefixed concept, so the "plp"
* parameter is always FALSE. */
for (i = 0; i < nl_data->num_cols; i++) {
dissect_tds_type_varbyte(tvb, &cur, pinfo, tree, hf_tds_params_field, tds_info,
@@ -2998,6 +3534,11 @@ tds45_token_to_idx(guint8 token)
case TDS_COLFMT_TOKEN: return hf_tds_colfmt;
case TDS_COL_NAME_TOKEN: return hf_tds_colname;
case TDS_CONTROL_TOKEN: return hf_tds_control;
+ case TDS_CURCLOSE_TOKEN: return hf_tds_curclose;
+ case TDS_CURDECLARE_TOKEN: return hf_tds_curdeclare;
+ case TDS_CURFETCH_TOKEN: return hf_tds_curfetch;
+ case TDS_CURINFO_TOKEN: return hf_tds_curinfo;
+ case TDS_CUROPEN_TOKEN: return hf_tds_curopen;
case TDS5_DBRPC_TOKEN: return hf_tds_dbrpc;
case TDS_DONE_TOKEN: return hf_tds_done;
case TDS_DONEPROC_TOKEN: return hf_tds_doneproc;
@@ -3072,6 +3613,21 @@ dissect_tds5_tokenized_request_packet(tvbuff_t *tvb, packet_info *pinfo, proto_t
case TDS_LANG_TOKEN:
token_sz = dissect_tds5_lang_token(tvb, pos + 1, token_tree, tds_info) + 1;
break;
+ case TDS_CURCLOSE_TOKEN:
+ token_sz = dissect_tds5_curclose_token(tvb, pinfo, pos + 1, token_tree, tds_info) + 1;
+ break;
+ case TDS_CURDECLARE_TOKEN:
+ token_sz = dissect_tds5_curdeclare_token(tvb, pinfo, pos + 1, token_tree, tds_info) + 1;
+ break;
+ case TDS_CURFETCH_TOKEN:
+ token_sz = dissect_tds5_curfetch_token(tvb, pinfo, pos + 1, token_tree, tds_info) + 1;
+ break;
+ case TDS_CURINFO_TOKEN:
+ token_sz = dissect_tds5_curinfo_token(tvb, pinfo, pos + 1, token_tree, tds_info) + 1;
+ break;
+ case TDS_CUROPEN_TOKEN:
+ token_sz = dissect_tds5_curopen_token(tvb, pinfo, pos + 1, token_tree, tds_info) + 1;
+ break;
case TDS5_LOGOUT_TOKEN:
token_sz = dissect_tds5_logout_token(token_tree, tvb, pos + 1, tds_info) + 1;
break;
@@ -3904,11 +4460,13 @@ dissect_tds_colfmt_token(proto_tree *tree, tvbuff_t *tvb, guint offset, tds_conv
*
*/
static guint
-dissect_tds_rowfmt_token(proto_tree *tree, tvbuff_t *tvb, guint offset, tds_conv_info_t *tds_info,
- struct _netlib_data *nl_data)
+dissect_tds_rowfmt_token(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo,
+ guint offset, tds_conv_info_t *tds_info, struct _netlib_data *nl_data)
{
guint next, cur;
guint col, len, numcols;
+ tds_cursor_info_t *packet_cursor =
+ (tds_cursor_info_t *) p_get_proto_data(wmem_file_scope(), pinfo, proto_tds, 0);
proto_tree_add_item_ret_uint(tree, hf_tds_rowfmt_length, tvb, offset, 2,
tds_get_int4_encoding(tds_info), &len);
@@ -4020,6 +4578,17 @@ dissect_tds_rowfmt_token(proto_tree *tree, tvbuff_t *tvb, guint offset, tds_conv
} /* while */
nl_data->num_cols = col;
+
+ /*
+ * If there is a packet cursor, we need to copy the struct _netlib_data into it
+ * for use by later packets referencing the same cursor.
+ */
+
+ if (packet_cursor && !(packet_cursor->tds_cursor_flags & TDS_CURSOR_ROWINFO_VALID)) {
+ packet_cursor->tds_cursor_rowinfo = copy_nl_data(wmem_file_scope(), nl_data);
+ packet_cursor->tds_cursor_flags |= TDS_CURSOR_ROWINFO_VALID;
+ }
+
return cur - offset;
}
@@ -4029,11 +4598,13 @@ dissect_tds_rowfmt_token(proto_tree *tree, tvbuff_t *tvb, guint offset, tds_conv
*
*/
static guint
-dissect_tds_rowfmt2_token(proto_tree *tree, tvbuff_t *tvb, guint offset, tds_conv_info_t *tds_info,
- struct _netlib_data *nl_data)
+dissect_tds_rowfmt2_token(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo,
+ guint offset, tds_conv_info_t *tds_info, struct _netlib_data *nl_data)
{
guint next, cur;
guint col, len, numcols;
+ tds_cursor_info_t *packet_cursor =
+ (tds_cursor_info_t *) p_get_proto_data(wmem_file_scope(), pinfo, proto_tds, 0);
proto_tree_add_item_ret_uint(tree, hf_tds_rowfmt2_length, tvb, offset, 4,
tds_get_int4_encoding(tds_info), &len);
@@ -4177,6 +4748,17 @@ dissect_tds_rowfmt2_token(proto_tree *tree, tvbuff_t *tvb, guint offset, tds_con
} /* while */
nl_data->num_cols = col;
+
+ /*
+ * If there is a packet cursor, we need to copy the struct _netlib_data into it
+ * for use by later packets referencing the same cursor.
+ */
+
+ if (packet_cursor && !(packet_cursor->tds_cursor_flags & TDS_CURSOR_ROWINFO_VALID)) {
+ packet_cursor->tds_cursor_rowinfo = copy_nl_data(wmem_file_scope(), nl_data);
+ packet_cursor->tds_cursor_flags |= TDS_CURSOR_ROWINFO_VALID;
+ }
+
return cur - offset;
}
@@ -4395,6 +4977,21 @@ dissect_tds_row_token(tvbuff_t *tvb, packet_info *pinfo, struct _netlib_data *nl
{
guint cur = offset, i, type;
gboolean plp = FALSE;
+ tds_cursor_info_t *packet_cursor;
+
+ if (!PINFO_FD_VISITED(pinfo)) {
+ if (tds_info->tds_conv_cursor_info && tds_info->tds_conv_cursor_info->tds_conv_cursor_current) {
+ tds_cursor_info_t *cursor_current = tds_info->tds_conv_cursor_info->tds_conv_cursor_current;
+ p_add_proto_data(wmem_file_scope(), pinfo, proto_tds, 0,
+ cursor_current);
+ }
+ }
+
+ packet_cursor = (tds_cursor_info_t *) p_get_proto_data(wmem_file_scope(), pinfo, proto_tds, 0);
+
+ if (packet_cursor && (packet_cursor->tds_cursor_flags & TDS_CURSOR_ROWINFO_VALID)) {
+ nl_data = packet_cursor->tds_cursor_rowinfo;
+ }
for (i = 0; i < nl_data->num_cols; i++) {
type = nl_data->columns[i]->ctype;
@@ -5666,7 +6263,9 @@ dissect_tds_resp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, tds_conv_i
switch (token) {
case TDS_CAPABILITY_TOKEN:
token_sz = dissect_tds5_capability_token(tvb, pinfo, pos + 1, token_tree, tds_info) + 1;
-
+ break;
+ case TDS_CURINFO_TOKEN:
+ token_sz = dissect_tds5_curinfo_token(tvb, pinfo, pos + 1, token_tree, tds_info) + 1;
break;
case TDS_DONE_TOKEN:
token_sz = dissect_tds_done_token(tvb, pos + 1, token_tree, tds_info) + 1;
@@ -5711,10 +6310,10 @@ dissect_tds_resp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, tds_conv_i
token_sz = dissect_tds_row_token(tvb, pinfo, &nl_data, pos + 1, token_tree, tds_info) + 1;
break;
case TDS5_ROWFMT_TOKEN:
- token_sz = dissect_tds_rowfmt_token(token_tree, tvb, pos + 1, tds_info, &nl_data) + 1;
+ token_sz = dissect_tds_rowfmt_token(token_tree, tvb, pinfo, pos + 1, tds_info, &nl_data) + 1;
break;
case TDS5_ROWFMT2_TOKEN:
- token_sz = dissect_tds_rowfmt2_token(token_tree, tvb, pos + 1, tds_info, &nl_data) + 1;
+ token_sz = dissect_tds_rowfmt2_token(token_tree, tvb, pinfo, pos + 1, tds_info, &nl_data) + 1;
break;
default:
@@ -5807,6 +6406,7 @@ dissect_tds_resp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, tds_conv_i
static void
fill_tds_info_defaults(tds_conv_info_t *tds_info)
{
+ tds_info->tds_conv_cursor_info = NULL;
if (tds_little_endian) {
tds_info->tds_encoding_int4 = TDS_INT4_LITTLE_ENDIAN;
tds_info->tds_encoding_int2 = TDS_INT2_LITTLE_ENDIAN;
@@ -7263,6 +7863,231 @@ proto_register_tds(void)
NULL, HFILL }
},
+ /* CURCLOSE token (TDS_CURCLOSE_TOKEN) */
+ { &hf_tds_curclose,
+ { "Token - CurClose", "tds.curclose",
+ FT_NONE, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_tds_curclose_length,
+ { "Token Length - CurClose", "tds.curclose.length",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_tds_curclose_cursorid,
+ { "CursorId", "tds.curclose.cursorid",
+ FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_tds_curclose_cursor_name,
+ { "Cursorname", "tds.curclose.cursor.name_len",
+ FT_UINT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_tds_curclose_option_deallocate,
+ { "Deallocate", "tds.curclose.option.deallocate",
+ FT_BOOLEAN, 8, NULL, 0x01,
+ NULL, HFILL }
+ },
+
+ /* CURDECLARE token (TDS_CURDECLARE_TOKEN) */
+ { &hf_tds_curdeclare,
+ { "Token - CurDeclare", "tds.curdeclare",
+ FT_NONE, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_tds_curdeclare_length,
+ { "Token Length - CurDeclare", "tds.curdeclare.length",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_tds_curdeclare_cursor_name,
+ { "Cursorname", "tds.curdeclare.cursor.name_len",
+ FT_UINT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_tds_curdeclare_options,
+ { "Options", "tds.curdeclare.options",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_tds_curdeclare_options_rdonly,
+ { "Read Only", "tds.curdeclare.options.rdonly",
+ FT_BOOLEAN, 8, NULL, 0x01,
+ NULL, HFILL }
+ },
+ { &hf_tds_curdeclare_options_updatable,
+ { "Updatable", "tds.curdeclare.options.updatable",
+ FT_BOOLEAN, 8, NULL, 0x02,
+ NULL, HFILL }
+ },
+ { &hf_tds_curdeclare_options_sensitive,
+ { "Sensitive", "tds.curdeclare.options.sensitive",
+ FT_BOOLEAN, 8, NULL, 0x04,
+ NULL, HFILL }
+ },
+ { &hf_tds_curdeclare_options_dynamic,
+ { "Dynamic", "tds.curdeclare.options.dynamic",
+ FT_BOOLEAN, 8, NULL, 0x08,
+ NULL, HFILL }
+ },
+ { &hf_tds_curdeclare_options_implicit,
+ { "Implict", "tds.curdeclare.options.implicit",
+ FT_BOOLEAN, 8, NULL, 0x10,
+ NULL, HFILL }
+ },
+ { &hf_tds_curdeclare_status_parameterized,
+ { "Status Parameterized", "tds.curdeclare.status.parameterized",
+ FT_BOOLEAN, 8, NULL, 0x01,
+ NULL, HFILL }
+ },
+ { &hf_tds_curdeclare_statement,
+ { "Statement", "tds.curdeclare.statement",
+ FT_UINT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_tds_curdeclare_update_columns_num,
+ { "Number of updatable columns", "tds.curdeclare.update_columns_num",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_tds_curdeclare_update_columns_name,
+ { "Updatable Column Name", "tds.curdeclare.update_columns_name",
+ FT_UINT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+
+ /* CURFETCH token (TDS_CURFETCH_TOKEN) */
+ { &hf_tds_curfetch,
+ { "Token - CurFetch", "tds.curfetch",
+ FT_NONE, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_tds_curfetch_length,
+ { "Token Length - CurFetch", "tds.curfetch.length",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_tds_curfetch_cursorid,
+ { "CursorId", "tds.curfetch.cursorid",
+ FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_tds_curfetch_cursor_name,
+ { "CurFetch - Cursorname", "tds.curfetch.cursor.name_len",
+ FT_UINT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_tds_curfetch_type,
+ { "CurFetch - Type", "tds.curinfo.type",
+ FT_UINT8, BASE_DEC, VALS(tds_curfetch_types), 0x0,
+ NULL, HFILL }
+ },
+ { &hf_tds_curfetch_rowcnt,
+ { "CurFetch - Rowcnt", "tds.curfetch.rowcnt",
+ FT_INT32, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+
+ /* CURINFO token (TDS_CURINFO_TOKEN) */
+ { &hf_tds_curinfo,
+ { "Token - CurInfo", "tds.curinfo",
+ FT_NONE, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_tds_curinfo_length,
+ { "Token Length - Curinfo", "tds.curinfo.length",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_tds_curinfo_cursorid,
+ { "CursorId", "tds.curinfo.cursorid",
+ FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_tds_curinfo_cursor_name,
+ { "Cursorname", "tds.curinfo.cursor.name_len",
+ FT_UINT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_tds_curinfo_cursor_command,
+ { "Cursor Command", "tds.curinfo.cursor.command",
+ FT_UINT8, BASE_DEC, VALS(tds_curinfo_commands), 0x0,
+ NULL, HFILL }
+ },
+ { &hf_tds_curinfo_cursor_status,
+ { "Cursor Status", "tds.curinfo.cursor.status",
+ FT_UINT16, BASE_HEX, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_tds_curinfo_cursor_status_declared,
+ { "Declared", "tds.curinfo.cursor.status.declared",
+ FT_BOOLEAN, 16, NULL, 0x0001,
+ NULL, HFILL }
+ },
+ { &hf_tds_curinfo_cursor_status_open,
+ { "Open", "tds.curinfo.cursor.status.open",
+ FT_BOOLEAN, 16, NULL, 0x0002,
+ NULL, HFILL }
+ },
+ { &hf_tds_curinfo_cursor_status_closed,
+ { "Closed", "tds.curinfo.cursor.status.closed",
+ FT_BOOLEAN, 16, NULL, 0x0004,
+ NULL, HFILL }
+ },
+ { &hf_tds_curinfo_cursor_status_rdonly,
+ { "Read only", "tds.curinfo.cursor.status.rdonly",
+ FT_BOOLEAN, 16, NULL, 0x0008,
+ NULL, HFILL }
+ },
+ { &hf_tds_curinfo_cursor_status_updatable,
+ { "Updatable", "tds.curinfo.cursor.status.updatable",
+ FT_BOOLEAN, 16, NULL, 0x0010,
+ NULL, HFILL }
+ },
+ { &hf_tds_curinfo_cursor_status_rowcnt,
+ { "Rowcount valid", "tds.curinfo.cursor.status.rowcnt",
+ FT_BOOLEAN, 16, NULL, 0x0020,
+ NULL, HFILL }
+ },
+ { &hf_tds_curinfo_cursor_status_dealloc,
+ { "Deallocated", "tds.curinfo.cursor.status.dealloc",
+ FT_BOOLEAN, 16, NULL, 0x0040,
+ NULL, HFILL }
+ },
+ { &hf_tds_curinfo_cursor_rowcnt,
+ { "Cursor Rowcnt", "tds.curinfo.cursor.rowcnt",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+
+ /* CUROPEN token (TDS_CUROPEN_TOKEN) */
+ { &hf_tds_curopen,
+ { "Token - CurOpen", "tds.curopen",
+ FT_NONE, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_tds_curopen_length,
+ { "Token Length - CurOpen", "tds.curopen.length",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_tds_curopen_cursorid,
+ { "CursorId", "tds.curopen.cursorid",
+ FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_tds_curopen_cursor_name,
+ { "Cursorname", "tds.curopen.cursor.name_len",
+ FT_UINT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_tds_curopen_status_parameterized,
+ { "Status Parameterized", "tds.curopen.status.parameterized",
+ FT_BOOLEAN, 8, NULL, 0x01,
+ NULL, HFILL }
+ },
+
/* DBRPC token (TDS5_DBRPC_TOKEN) */
{ &hf_tds_dbrpc,
{ "Token - DBRPC", "tds.dbrpc",
@@ -9065,7 +9890,9 @@ proto_register_tds(void)
&ett_tds_flags,
&ett_tds7_featureextack,
&ett_tds7_featureextack_feature,
- &ett_tds5_dbrpc_options
+ &ett_tds5_dbrpc_options,
+ &ett_tds5_curdeclare_options,
+ &ett_tds5_curinfo_status
};
static ei_register_info ei[] = {
@@ -9079,7 +9906,8 @@ proto_register_tds(void)
#if 0
{ &ei_tds_token_stats, { "tds.token.stats", PI_PROTOCOL, PI_NOTE, "Token stats", EXPFILL }},
#endif
- { &ei_tds_invalid_plp_type, { "tds.type_info.type.invalidplp", PI_PROTOCOL, PI_NOTE, "Invalid PLP type", EXPFILL }}
+ { &ei_tds_invalid_plp_type, { "tds.type_info.type.invalidplp", PI_PROTOCOL, PI_NOTE, "Invalid PLP type", EXPFILL }},
+ { &ei_tds_cursor_name_mismatch, { "tds.cursor.name_mismatch", PI_PROTOCOL, PI_WARN, "Cursor name mismatch", EXPFILL }}
};
module_t *tds_module;