From András Veres-Szentkirályi: Added cursor type decoding to MySQL dissector
[obnox/wireshark/wip.git] / epan / dissectors / packet-mysql.c
index 660a13afc92d607518d06f9913010e29240f83c2..2afee644176f7084637188033d278255aee8fdeb 100644 (file)
@@ -48,6 +48,7 @@
 
 #include <epan/dissectors/packet-tcp.h>
 #include <epan/prefs.h>
+#include <epan/expert.h>
 
 /* port for protocol registration */
 #define TCP_PORT_MySQL   3306
 #define MYSQL_RFSH_SLAVE   64  /* Reset master info and restart slave thread */
 #define MYSQL_RFSH_MASTER  128 /* Remove all bin logs in the index and truncate the index */
 
-/* MySQL operation codes */
+/* MySQL command codes */
 #define MYSQL_SLEEP               0  /* not from client */
 #define MYSQL_QUIT                1
 #define MYSQL_INIT_DB             2
 #define MYSQL_SET_OPTION          27
 #define MYSQL_STMT_FETCH          28
 
+/* MySQL cursor types */
 
-/* decoding table: opcodes */
-static const value_string mysql_opcode_vals[] = {
+#define MYSQL_CURSOR_TYPE_NO_CURSOR  0
+#define MYSQL_CURSOR_TYPE_READ_ONLY  1
+#define MYSQL_CURSOR_TYPE_FOR_UPDATE 2
+#define MYSQL_CURSOR_TYPE_SCROLLABLE 4
+
+
+/* decoding table: command */
+static const value_string mysql_command_vals[] = {
        {MYSQL_SLEEP,   "SLEEP"},
        {MYSQL_QUIT,   "Quit"},
        {MYSQL_INIT_DB,  "Use Database"},
@@ -176,6 +184,14 @@ static const value_string mysql_opcode_vals[] = {
        {0, NULL}
 };
 
+/* decoding table: exec_flags */
+static const value_string mysql_exec_flags_vals[] = {
+       {MYSQL_CURSOR_TYPE_NO_CURSOR, "Defaults"},
+       {MYSQL_CURSOR_TYPE_READ_ONLY, "Read-only cursor"},
+       {MYSQL_CURSOR_TYPE_FOR_UPDATE, "Cursor for update"},
+       {MYSQL_CURSOR_TYPE_SCROLLABLE, "Scrollable cursor"},
+       {0, NULL}
+};
 
 /* charset: pre-4.1 used the term 'charset', later changed to 'collation' */
 static const value_string mysql_charset_vals[] = {
@@ -343,6 +359,7 @@ static gboolean mysql_showquery = FALSE;
 /* expand-the-tree flags */
 static gint ett_mysql = -1;
 static gint ett_server_greeting = -1;
+static gint ett_login_request = -1;
 static gint ett_caps = -1;
 static gint ett_extcaps = -1;
 static gint ett_stat = -1;
@@ -351,82 +368,93 @@ static gint ett_refresh = -1;
 static gint ett_field_flags = -1;
 
 /* protocol fields */
-static int hf_mysql_caps= -1;
-static int hf_mysql_cap_long_password= -1;
-static int hf_mysql_cap_found_rows= -1;
-static int hf_mysql_cap_long_flag= -1;
-static int hf_mysql_cap_connect_with_db= -1;
-static int hf_mysql_cap_no_schema= -1;
-static int hf_mysql_cap_compress= -1;
-static int hf_mysql_cap_odbc= -1;
-static int hf_mysql_cap_local_files= -1;
-static int hf_mysql_cap_ignore_space= -1;
-static int hf_mysql_cap_change_user= -1;
-static int hf_mysql_cap_interactive= -1;
-static int hf_mysql_cap_ssl= -1;
-static int hf_mysql_cap_ignore_sigpipe= -1;
-static int hf_mysql_cap_transactions= -1;
-static int hf_mysql_cap_reserved= -1;
-static int hf_mysql_cap_secure_connect= -1;
-static int hf_mysql_extcaps= -1;
-static int hf_mysql_cap_multi_statements= -1;
-static int hf_mysql_cap_multi_results= -1;
-static int hf_mysql_status= -1;
-static int hf_mysql_stat_it= -1;
-static int hf_mysql_stat_ac= -1;
-static int hf_mysql_stat_mr= -1;
-static int hf_mysql_stat_mu= -1;
-static int hf_mysql_stat_bi= -1;
-static int hf_mysql_stat_ni= -1;
-static int hf_mysql_stat_cr= -1;
-static int hf_mysql_stat_lr= -1;
-static int hf_mysql_stat_dr= -1;
-static int hf_mysql_stat_bs= -1;
-static int hf_mysql_refresh= -1;
-static int hf_mysql_rfsh_grants= -1;
-static int hf_mysql_rfsh_log= -1;
-static int hf_mysql_rfsh_tables= -1;
-static int hf_mysql_rfsh_hosts= -1;
-static int hf_mysql_rfsh_status= -1;
-static int hf_mysql_rfsh_threads= -1;
-static int hf_mysql_rfsh_slave= -1;
-static int hf_mysql_rfsh_master= -1;
-static int hf_mysql_packet_length= -1;
-static int hf_mysql_packet_number= -1;
-static int hf_mysql_opcode= -1;
-static int hf_mysql_response_code= -1;
-static int hf_mysql_error_code= -1;
-static int hf_mysql_error_string= -1;
-static int hf_mysql_sqlstate= -1;
-static int hf_mysql_message= -1;
-static int hf_mysql_payload= -1;
-static int hf_mysql_protocol= -1;
-static int hf_mysql_version = -1;
-static int hf_mysql_max_packet= -1;
-static int hf_mysql_user= -1;
-static int hf_mysql_schema= -1;
-static int hf_mysql_thread_id = -1;
-static int hf_mysql_salt= -1;
-static int hf_mysql_salt2= -1;
-static int hf_mysql_charset= -1;
-static int hf_mysql_passwd= -1;
-static int hf_mysql_unused= -1;
-static int hf_mysql_parameter= -1;
-static int hf_mysql_affected_rows= -1;
-static int hf_mysql_insert_id= -1;
-static int hf_mysql_num_warn= -1;
-static int hf_mysql_thd_id= -1;
-static int hf_mysql_stmt_id= -1;
-static int hf_mysql_query= -1;
-static int hf_mysql_option= -1;
-static int hf_mysql_num_rows= -1;
-static int hf_mysql_param= -1;
-static int hf_mysql_exec_flags= -1;
-static int hf_mysql_exec_iter= -1;
-static int hf_mysql_eof= -1;
-static int hf_mysql_num_fields= -1;
-static int hf_mysql_extra= -1;
-static int hf_mysql_fld_catalog = -1;
+static int hf_mysql_caps_server = -1;
+static int hf_mysql_caps_client = -1;
+static int hf_mysql_cap_long_password = -1;
+static int hf_mysql_cap_found_rows = -1;
+static int hf_mysql_cap_long_flag = -1;
+static int hf_mysql_cap_connect_with_db = -1;
+static int hf_mysql_cap_no_schema = -1;
+static int hf_mysql_cap_compress = -1;
+static int hf_mysql_cap_odbc = -1;
+static int hf_mysql_cap_local_files = -1;
+static int hf_mysql_cap_ignore_space = -1;
+static int hf_mysql_cap_change_user = -1;
+static int hf_mysql_cap_interactive = -1;
+static int hf_mysql_cap_ssl = -1;
+static int hf_mysql_cap_ignore_sigpipe = -1;
+static int hf_mysql_cap_transactions = -1;
+static int hf_mysql_cap_reserved = -1;
+static int hf_mysql_cap_secure_connect = -1;
+static int hf_mysql_extcaps_client = -1;
+static int hf_mysql_cap_multi_statements = -1;
+static int hf_mysql_cap_multi_results = -1;
+static int hf_mysql_server_language = -1;
+static int hf_mysql_server_status = -1;
+static int hf_mysql_stat_it = -1;
+static int hf_mysql_stat_ac = -1;
+static int hf_mysql_stat_mr = -1;
+static int hf_mysql_stat_mu = -1;
+static int hf_mysql_stat_bi = -1;
+static int hf_mysql_stat_ni = -1;
+static int hf_mysql_stat_cr = -1;
+static int hf_mysql_stat_lr = -1;
+static int hf_mysql_stat_dr = -1;
+static int hf_mysql_stat_bs = -1;
+static int hf_mysql_refresh = -1;
+static int hf_mysql_rfsh_grants = -1;
+static int hf_mysql_rfsh_log = -1;
+static int hf_mysql_rfsh_tables = -1;
+static int hf_mysql_rfsh_hosts = -1;
+static int hf_mysql_rfsh_status = -1;
+static int hf_mysql_rfsh_threads = -1;
+static int hf_mysql_rfsh_slave = -1;
+static int hf_mysql_rfsh_master = -1;
+static int hf_mysql_packet_length = -1;
+static int hf_mysql_packet_number = -1;
+static int hf_mysql_request = -1;
+static int hf_mysql_command = -1;
+static int hf_mysql_error_code = -1;
+static int hf_mysql_error_string = -1;
+static int hf_mysql_sqlstate = -1;
+static int hf_mysql_message = -1;
+static int hf_mysql_payload = -1;
+static int hf_mysql_server_greeting = -1;
+static int hf_mysql_protocol = -1;
+static int hf_mysql_version  = -1;
+static int hf_mysql_login_request = -1;
+static int hf_mysql_max_packet = -1;
+static int hf_mysql_user = -1;
+static int hf_mysql_table_name = -1;
+static int hf_mysql_schema = -1;
+static int hf_mysql_thread_id  = -1;
+static int hf_mysql_salt = -1;
+static int hf_mysql_salt2 = -1;
+static int hf_mysql_charset = -1;
+static int hf_mysql_passwd = -1;
+static int hf_mysql_unused = -1;
+static int hf_mysql_affected_rows = -1;
+static int hf_mysql_insert_id = -1;
+static int hf_mysql_num_warn = -1;
+static int hf_mysql_thd_id = -1;
+static int hf_mysql_stmt_id = -1;
+static int hf_mysql_query = -1;
+static int hf_mysql_shutdown = -1;
+static int hf_mysql_option = -1;
+static int hf_mysql_num_rows = -1;
+static int hf_mysql_param = -1;
+static int hf_mysql_num_params = -1;
+static int hf_mysql_exec_flags4 = -1;
+static int hf_mysql_exec_flags5 = -1;
+static int hf_mysql_exec_iter = -1;
+static int hf_mysql_binlog_position = -1;
+static int hf_mysql_binlog_flags = -1;
+static int hf_mysql_binlog_server_id = -1;
+static int hf_mysql_binlog_file_name = -1;
+static int hf_mysql_eof = -1;
+static int hf_mysql_num_fields = -1;
+static int hf_mysql_extra = -1;
+static int hf_mysql_fld_catalog  = -1;
 static int hf_mysql_fld_db = -1;
 static int hf_mysql_fld_table = -1;
 static int hf_mysql_fld_org_table = -1;
@@ -450,7 +478,6 @@ static int hf_mysql_fld_timestamp = -1;
 static int hf_mysql_fld_set = -1;
 static int hf_mysql_fld_decimals = -1;
 static int hf_mysql_fld_default = -1;
-static int hf_mysql_row_length = -1;
 static int hf_mysql_row_text = -1;
 
 /* type constants */
@@ -498,7 +525,8 @@ typedef enum mysql_state
        FIELD_PACKET,
        ROW_PACKET,
        RESPONSE_PREPARE,
-       PARAM_PACKET
+    PREPARED_PARAMETERS,
+    PREPARED_FIELDS
 } mysql_state_t;
 
 #ifdef CTDEBUG
@@ -513,7 +541,8 @@ static const value_string state_vals[] = {
        {FIELD_PACKET,         "field packet"},
        {ROW_PACKET,           "row packet"},
        {RESPONSE_PREPARE,     "response to PREPARE"},
-       {PARAM_PACKET,         "parameter packet"},
+       {RESPONSE_PARAMETERS,  "parameters in response to PREPARE"},
+       {RESPONSE_FIELDS,      "fields in response to PREPARE"},
        {0, NULL}
 };
 #endif
@@ -524,10 +553,13 @@ typedef struct mysql_conn_data
        guint16 clnt_caps;
        guint16 clnt_caps_ext;
        mysql_state_t state;
+       guint16 stmt_num_params;
+       guint16 stmt_num_fields;
        GHashTable* stmts;
 #ifdef CTDEBUG
        guint32 generation;
 #endif
+       guint8 major_version;
 } mysql_conn_data_t;
 
 struct mysql_frame_data {
@@ -551,1630 +583,1676 @@ static int mysql_dissect_response(tvbuff_t *tvb, packet_info *pinfo, int offset,
 static int mysql_dissect_error_packet(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree);
 static int mysql_dissect_ok_packet(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data);
 static int mysql_dissect_server_status(tvbuff_t *tvb, int offset, proto_tree *tree);
-static void mysql_dissect_collation(tvbuff_t *tvb, int offset, proto_tree *tree, guint16 caps, gint charset, int field);
-static int mysql_dissect_caps(tvbuff_t *tvb, int offset, proto_tree *tree, guint16 *caps, const char* whom);
-static int mysql_dissect_ext_caps(tvbuff_t *tvb, int offset, proto_tree *tree, guint16 *caps, const char* whom);
+static int mysql_dissect_caps_server(tvbuff_t *tvb, int offset, proto_tree *tree, guint16 *caps);
+static int mysql_dissect_caps_client(tvbuff_t *tvb, int offset, proto_tree *tree, guint16 *caps);
+static int mysql_dissect_ext_caps_client(tvbuff_t *tvb, int offset, proto_tree *tree, guint16 *caps);
 static int mysql_dissect_result_header(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data);
 static int mysql_dissect_field_packet(tvbuff_t *tvb, int offset, proto_tree *tree, mysql_conn_data_t *conn_data);
 static int mysql_dissect_row_packet(tvbuff_t *tvb, int offset, proto_tree *tree);
-static int mysql_dissect_response_prepare(tvbuff_t *tvb, int offset, proto_tree *tree);
-static int mysql_dissect_param_packet(tvbuff_t *tvb, int offset, proto_tree *tree);
+static int mysql_dissect_response_prepare(tvbuff_t *tvb, int offset, proto_tree *tree, mysql_conn_data_t *conn_data);
 static gint my_tvb_strsize(tvbuff_t *tvb, int offset);
 static int tvb_get_fle(tvbuff_t *tvb, int offset, guint64 *res, guint8 *is_null);
 
+/* dissector entrypoint, handles TCP-desegmentation */
+static void
+dissect_mysql(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+       tcp_dissect_pdus(tvb, pinfo, tree, mysql_desegment, 3,
+                        get_mysql_pdu_len, dissect_mysql_pdu);
+}
+
 
-/* dissector registration */
-void proto_reg_handoff_mysql(void)
+/* dissector helper: length of PDU */
+static guint
+get_mysql_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
 {
-       dissector_handle_t mysql_handle;
-       mysql_handle = create_dissector_handle(dissect_mysql, proto_mysql);
-       dissector_add("tcp.port", TCP_PORT_MySQL, mysql_handle);
+       guint plen= tvb_get_letoh24(tvb, offset);
+       return plen + 4; /* add length field + packet number */
 }
 
-/* protocol registration */
-void proto_register_mysql(void)
+/* dissector main function: handle one PDU */
+static void
+dissect_mysql_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
-       static hf_register_info hf[]=
-       {
-               { &hf_mysql_packet_length,
-               { "Packet Length", "mysql.packet_length",
-               FT_UINT24, BASE_DEC, NULL,  0x0,
-               NULL, HFILL }},
+       proto_tree      *mysql_tree= NULL;
+       proto_item      *ti;
+       conversation_t  *conversation;
+       int             offset = 0;
+       guint           packet_number;
+       gboolean        is_response;
+       mysql_conn_data_t  *conn_data;
+#ifdef CTDEBUG
+       mysql_state_t conn_state_in, conn_state_out, frame_state;
+       guint64         generation;
+       proto_item *pi;
+#endif
+       struct mysql_frame_data  *mysql_frame_data_p;
 
-               { &hf_mysql_packet_number,
-               { "Packet Number", "mysql.packet_number",
-               FT_UINT8, BASE_DEC, NULL, 0x0,
-               NULL, HFILL }},
+       /* get conversation, create if neccessary*/
+       conversation= find_or_create_conversation(pinfo);
 
-               { &hf_mysql_opcode,
-               { "Command", "mysql.opcode",
-               FT_UINT8, BASE_DEC, NULL, 0x0,
-               NULL, HFILL }},
+       /* get associated state information, create if neccessary */
+       conn_data= conversation_get_proto_data(conversation, proto_mysql);
+       if (!conn_data) {
+               conn_data= se_alloc(sizeof(mysql_conn_data_t));
+               conn_data->srv_caps= 0;
+               conn_data->clnt_caps= 0;
+               conn_data->clnt_caps_ext= 0;
+               conn_data->state= UNDEFINED;
+               conn_data->stmts= g_hash_table_new(g_int_hash, g_int_equal);
+#ifdef CTDEBUG
+               conn_data->generation= 0;
+#endif
+                conn_data->major_version= 0;
+               conversation_add_proto_data(conversation, proto_mysql, conn_data);
+       }
 
-               { &hf_mysql_response_code,
-               { "Response Code", "mysql.response_code",
-               FT_UINT8, BASE_DEC, NULL, 0x0,
-               NULL, HFILL }},
+       mysql_frame_data_p = p_get_proto_data(pinfo->fd, proto_mysql);
+       if (!mysql_frame_data_p) {
+               /*  We haven't seen this frame before.  Store the state of the
+                *  conversation now so if/when we dissect the frame again
+                *  we'll start with the same state.
+                */
+               mysql_frame_data_p = se_alloc(sizeof(struct mysql_frame_data));
+               mysql_frame_data_p->state = conn_data->state;
+               p_add_proto_data(pinfo->fd, proto_mysql, mysql_frame_data_p);
 
-               { &hf_mysql_error_code,
-               { "Error Code", "mysql.error_code",
-               FT_UINT16, BASE_DEC, NULL, 0x0,
-               NULL, HFILL }},
+       } else if (conn_data->state != FIELD_PACKET  && conn_data->state != ROW_PACKET ) {
+               /*  We have seen this frame before.  Set the connection state
+                *  to whatever state it had the first time we saw this frame
+                *  (e.g., based on whatever frames came before it).
+                *  The state may change as we dissect this packet.
+                *  XXX: I think the logic of the above else if test is as follows:
+                *       During the first (sequential) dissection pass thru the capture
+                *       file the conversation connection state as of the beginning of each frame
+                *       is saved in the connection_state for that frame.
+                *       Any state changes *within* a mysql "message" (ie: query/response/etc)
+                *       while processing mysql PDUS (aka "packets") in that message must be preserved.
+                *       It appears that FIELD_PACKET & ROW_PACKET are the only two
+                *       state changes which can occur within a mysql message which affect
+                *       subsequent processing within the message.
+                *       Question: Does this logic work OK for a reassembled message ?
+                */
+                conn_data->state= mysql_frame_data_p->state;
+       }
 
-               { &hf_mysql_error_string,
-               { "Error message", "mysql.error.message",
-               FT_STRING, BASE_NONE, NULL, 0x0,
-               "Error string in case of MySQL error message", HFILL }},
+       if (tree) {
+               ti = proto_tree_add_item(tree, proto_mysql, tvb, offset, -1, ENC_NA);
+               mysql_tree = proto_item_add_subtree(ti, ett_mysql);
+               proto_tree_add_item(mysql_tree, hf_mysql_packet_length, tvb, offset, 3, ENC_LITTLE_ENDIAN);
+       }
+       offset+= 3;
 
-               { &hf_mysql_sqlstate,
-               { "SQL state", "mysql.sqlstate",
-               FT_STRING, BASE_NONE, NULL, 0x0,
-               NULL, HFILL }},
+       col_set_str(pinfo->cinfo, COL_PROTOCOL, "MySQL");
 
-               { &hf_mysql_message,
-               { "Message", "mysql.message",
-               FT_STRINGZ, BASE_NONE, NULL, 0x0,
-               NULL, HFILL }},
+       if (pinfo->destport == pinfo->match_uint) {
+               is_response= FALSE;
+       } else {
+               is_response= TRUE;
+       }
 
-               { &hf_mysql_protocol,
-               { "Protocol", "mysql.protocol",
-               FT_UINT8, BASE_DEC, NULL, 0x0,
-               "Protocol Version", HFILL }},
+       packet_number = tvb_get_guint8(tvb, offset);
+       proto_tree_add_item(mysql_tree, hf_mysql_packet_number, tvb, offset, 1, ENC_NA);
+       offset += 1;
 
-               { &hf_mysql_version,
-               { "Version", "mysql.version",
-               FT_STRINGZ, BASE_NONE, NULL, 0x0,
-               "MySQL Version", HFILL }},
+#ifdef CTDEBUG
+       conn_state_in= conn_data->state;
+       frame_state = mysql_frame_data_p->state;
+       generation= conn_data->generation;
+       if (tree) {
+               pi= proto_tree_add_text(mysql_tree, tvb, offset, 0, "conversation: %p", conversation);
+               PROTO_ITEM_SET_GENERATED(pi);
+               pi= proto_tree_add_text(mysql_tree, tvb, offset, 0, "generation: %" G_GINT64_MODIFIER "d", generation);
+               PROTO_ITEM_SET_GENERATED(pi);
+               pi= proto_tree_add_text(mysql_tree, tvb, offset, 0, "conn state: %s (%u)",
+                                   val_to_str(conn_state_in, state_vals, "Unknown (%u)"),
+                                   conn_state_in);
+               PROTO_ITEM_SET_GENERATED(pi);
+               pi= proto_tree_add_text(mysql_tree, tvb, offset, 0, "frame state: %s (%u)",
+                                   val_to_str(frame_state, state_vals, "Unknown (%u)"),
+                                   frame_state);
+               PROTO_ITEM_SET_GENERATED(pi);
+       }
+#endif
 
-               { &hf_mysql_caps,
-               { "Caps", "mysql.caps",
-               FT_UINT16, BASE_DEC, NULL, 0x0,
-               "MySQL Capabilities", HFILL }},
+       if (is_response) {
+               if (packet_number == 0) {
+                       col_set_str(pinfo->cinfo, COL_INFO, "Server Greeting");
+                       offset = mysql_dissect_greeting(tvb, pinfo, offset, mysql_tree, conn_data);
+               } else {
+                       col_set_str(pinfo->cinfo, COL_INFO, "Response");
+                       offset = mysql_dissect_response(tvb, pinfo, offset, mysql_tree, conn_data);
+               }
+       } else {
+               if (packet_number == 1) {
+                       col_set_str(pinfo->cinfo, COL_INFO, "Login Request");
+                       offset = mysql_dissect_login(tvb, pinfo, offset, mysql_tree, conn_data);
+               } else {
+                       col_set_str(pinfo->cinfo, COL_INFO, "Request");
+                       offset = mysql_dissect_request(tvb, pinfo, offset, mysql_tree, conn_data);
+               }
+       }
 
-               { &hf_mysql_cap_long_password,
-               { "Long Password","mysql.caps.lp",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_LP,
-               NULL, HFILL }},
+#ifdef CTDEBUG
+       conn_state_out= conn_data->state;
+       ++(conn_data->generation);
+       pi= proto_tree_add_text(mysql_tree, tvb, offset, 0, "next proto state: %s (%u)",
+                           val_to_str(conn_state_out, state_vals, "Unknown (%u)"),
+                           conn_state_out);
+       PROTO_ITEM_SET_GENERATED(pi);
+#endif
 
-               { &hf_mysql_cap_found_rows,
-               { "Found Rows","mysql.caps.fr",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_FR,
-               NULL, HFILL }},
+       /* remaining payload indicates an error */
+       if (tree && tvb_reported_length_remaining(tvb, offset) > 0) {
+               ti = proto_tree_add_item(mysql_tree, hf_mysql_payload, tvb, offset, -1, ENC_NA);
+               expert_add_info_format(pinfo, ti, PI_UNDECODED, PI_WARN, "FIXME - dissector is incomplete");
+       }
+}
 
-               { &hf_mysql_cap_long_flag,
-               { "Long Column Flags","mysql.caps.lf",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_LF,
-               NULL, HFILL }},
 
-               { &hf_mysql_cap_connect_with_db,
-               { "Connect With Database","mysql.caps.cd",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_CD,
-               NULL, HFILL }},
+static int
+mysql_dissect_greeting(tvbuff_t *tvb, packet_info *pinfo, int offset,
+                      proto_tree *tree, mysql_conn_data_t *conn_data)
+{
+       gint protocol;
+       gint strlen;
+       int ver_offset;
 
-               { &hf_mysql_cap_no_schema,
-               { "Don't Allow database.table.column","mysql.caps.ns",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_NS,
-               NULL, HFILL }},
+       proto_item *tf;
+       proto_item *greeting_tree= NULL;
 
-               { &hf_mysql_cap_compress,
-               { "Can use compression protocol","mysql.caps.cp",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_CP,
-               NULL, HFILL }},
+       protocol= tvb_get_guint8(tvb, offset);
 
-               { &hf_mysql_cap_odbc,
-               { "ODBC Client","mysql.caps.ob",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_OB,
-               NULL, HFILL }},
+       if (protocol == 0xff) {
+               return mysql_dissect_error_packet(tvb, pinfo, offset+1, tree);
+       }
 
-               { &hf_mysql_cap_local_files,
-               { "Can Use LOAD DATA LOCAL","mysql.caps.li",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_LI,
-               NULL, HFILL }},
+       conn_data->state= LOGIN;
 
-               { &hf_mysql_cap_ignore_space,
-               { "Ignore Spaces before '('","mysql.caps.is",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_IS,
-               NULL, HFILL }},
+       if (tree) {
+               tf = proto_tree_add_item(tree, hf_mysql_server_greeting, tvb, offset, -1, ENC_NA);
+               greeting_tree = proto_item_add_subtree(tf, ett_server_greeting);
+       }
 
-               { &hf_mysql_cap_change_user,
-               { "Speaks 4.1 protocol (new flag)","mysql.caps.cu",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_CU,
-               NULL, HFILL }},
+       if (check_col(pinfo->cinfo, COL_INFO)) {
+               col_append_fstr(pinfo->cinfo, COL_INFO, " proto=%d", protocol) ;
+       }
+       proto_tree_add_item(greeting_tree, hf_mysql_protocol, tvb, offset, 1, ENC_NA);
 
-               { &hf_mysql_cap_interactive,
-               { "Interactive Client","mysql.caps.ia",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_IA,
-               NULL, HFILL }},
+       offset += 1;
 
-               { &hf_mysql_cap_ssl,
-               { "Switch to SSL after handshake","mysql.caps.sl",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_SL,
-               NULL, HFILL }},
+       /* version string */
+       strlen = tvb_strsize(tvb,offset);
+       if (check_col(pinfo->cinfo, COL_INFO)) {
+               col_append_fstr(pinfo->cinfo, COL_INFO, " version=%s", tvb_get_ephemeral_string(tvb, offset, strlen));
+       }
+       proto_tree_add_item(greeting_tree, hf_mysql_version, tvb, offset, strlen, ENC_NA);
+       conn_data->major_version = 0;
+       for (ver_offset = 0; ver_offset < strlen; ver_offset++) {
+               guint8 ver_char = tvb_get_guint8(tvb, offset + ver_offset);
+               if (ver_char == '.') break;
+               conn_data->major_version = conn_data->major_version * 10 + ver_char - '0';
+       }
+       offset += strlen;
 
-               { &hf_mysql_cap_ignore_sigpipe,
-               { "Ignore sigpipes","mysql.caps.ii",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_II,
-               NULL, HFILL }},
+       /* 4 bytes little endian thread_id */
+       proto_tree_add_item(greeting_tree, hf_mysql_thread_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+       offset += 4;
 
-               { &hf_mysql_cap_transactions,
-               { "Knows about transactions","mysql.caps.ta",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_TA,
-               NULL, HFILL }},
+       /* salt string */
+       strlen = tvb_strsize(tvb,offset);
+       proto_tree_add_item(greeting_tree, hf_mysql_salt, tvb, offset, strlen, ENC_NA);
+       offset += strlen;
 
-               { &hf_mysql_cap_reserved,
-               { "Speaks 4.1 protocol (old flag)","mysql.caps.rs",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_RS,
-               NULL, HFILL }},
+       /* rest is optional */
+       if (!tvb_reported_length_remaining(tvb, offset)) return offset;
 
-               { &hf_mysql_cap_secure_connect,
-               { "Can do 4.1 authentication","mysql.caps.sc",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_SC,
-               NULL, HFILL }},
+       /* 2 bytes CAPS */
+       offset = mysql_dissect_caps_server(tvb, offset, greeting_tree, &conn_data->srv_caps);
 
-               { &hf_mysql_extcaps,
-               { "Ext. Caps", "mysql.extcaps",
-               FT_UINT16, BASE_DEC, NULL, 0x0,
-               "MySQL Extended Capabilities", HFILL }},
+       /* rest is optional */
+       if (!tvb_reported_length_remaining(tvb, offset)) return offset;
 
-               { &hf_mysql_cap_multi_statements,
-               { "Supports multiple statements","mysql.caps.ms",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_MS,
-               NULL, HFILL }},
+       proto_tree_add_item(greeting_tree, hf_mysql_server_language, tvb, offset, 1, ENC_NA);
+       offset += 1; /* for charset */
 
-               { &hf_mysql_cap_multi_results,
-               { "Supports multiple results","mysql.caps.mr",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_MR,
-               NULL, HFILL }},
+       offset = mysql_dissect_server_status(tvb, offset, greeting_tree);
 
-               { &hf_mysql_max_packet,
-               { "MAX Packet", "mysql.max_packet",
-               FT_UINT24, BASE_DEC, NULL,  0x0,
-               "MySQL Max packet", HFILL }},
+       /* 13 bytes unused */
+       proto_tree_add_item(greeting_tree, hf_mysql_unused, tvb, offset, 13, ENC_NA);
+       offset += 13;
 
-               { &hf_mysql_user,
-               { "Username", "mysql.user",
-               FT_STRINGZ, BASE_NONE, NULL, 0x0,
-               "Login Username", HFILL }},
+       /* 4.1+ server: rest of salt */
+       if (tvb_reported_length_remaining(tvb, offset)) {
+               strlen = tvb_strsize(tvb,offset);
+               proto_tree_add_item(greeting_tree, hf_mysql_salt2, tvb, offset, strlen, ENC_NA);
+               offset += strlen;
+       }
 
-               { &hf_mysql_schema,
-               { "Schema", "mysql.schema",
-               FT_STRING, BASE_NONE, NULL, 0x0,
-               "Login Schema", HFILL }},
+       return offset;
+}
 
-               { &hf_mysql_salt,
-               { "Salt", "mysql.salt",
-               FT_STRINGZ, BASE_NONE, NULL, 0x0,
-               NULL, HFILL }},
 
-               { &hf_mysql_salt2,
-               { "Salt", "mysql.salt2",
-               FT_STRINGZ, BASE_NONE, NULL, 0x0,
-               NULL, HFILL }},
+static int
+mysql_dissect_login(tvbuff_t *tvb, packet_info *pinfo, int offset,
+                   proto_tree *tree, mysql_conn_data_t *conn_data)
+{
+       gint strlen;
 
-               { &hf_mysql_thread_id,
-               { "Thread ID", "mysql.thread_id",
-               FT_UINT32, BASE_DEC, NULL,  0x0,
-               "MySQL Thread ID", HFILL }},
+       proto_item *tf;
+       proto_item *login_tree= NULL;
 
-               { &hf_mysql_charset,
-               { "Charset", "mysql.charset",
-               FT_UINT8, BASE_DEC, NULL,  0x0,
-               "MySQL Charset", HFILL }},
+       /* after login there can be OK or DENIED */
+       conn_data->state = RESPONSE_OK;
 
-               { &hf_mysql_status,
-               { "Status", "mysql.status",
-               FT_UINT16, BASE_DEC, NULL,  0x0,
-               "MySQL Status", HFILL }},
+       if (tree) {
+               tf = proto_tree_add_item(tree, hf_mysql_login_request, tvb, offset, -1, ENC_NA);
+               login_tree = proto_item_add_subtree(tf, ett_login_request);
+       }
 
-               { &hf_mysql_stat_it,
-               { "In transaction", "mysql.stat.it",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_IT,
-               NULL, HFILL }},
+       offset = mysql_dissect_caps_client(tvb, offset, login_tree, &conn_data->clnt_caps);
 
-               { &hf_mysql_stat_ac,
-               { "AUTO_COMMIT", "mysql.stat.ac",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_AC,
-               NULL, HFILL }},
+       if (conn_data->clnt_caps & MYSQL_CAPS_CU) /* 4.1 protocol */
+       {
+               offset = mysql_dissect_ext_caps_client(tvb, offset, login_tree, &conn_data->clnt_caps_ext);
 
-               { &hf_mysql_stat_mr,
-               { "More results", "mysql.stat.mr",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_MR,
-               NULL, HFILL }},
+               proto_tree_add_item(login_tree, hf_mysql_max_packet, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+               offset += 4;
 
-               { &hf_mysql_stat_mu,
-               { "Multi query - more resultsets", "mysql.stat.mu",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_MU,
-               NULL, HFILL }},
+               proto_tree_add_item(login_tree, hf_mysql_charset, tvb, offset, 1, ENC_NA);
+               offset += 1; /* for charset */
 
-               { &hf_mysql_stat_bi,
-               { "Bad index used", "mysql.stat.bi",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_BI,
-               NULL, HFILL }},
+               offset += 23; /* filler bytes */
 
-               { &hf_mysql_stat_ni,
-               { "No index used", "mysql.stat.ni",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_NI,
-               NULL, HFILL }},
+       } else { /* pre-4.1 */
+               proto_tree_add_item(login_tree, hf_mysql_max_packet, tvb, offset, 3, ENC_LITTLE_ENDIAN);
+               offset += 3;
+       }
 
-               { &hf_mysql_stat_cr,
-               { "Cursor exists", "mysql.stat.cr",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_CR,
-               NULL, HFILL }},
+       /* User name */
+       strlen = my_tvb_strsize(tvb, offset);
+       if (check_col(pinfo->cinfo, COL_INFO)) {
+               col_append_fstr(pinfo->cinfo, COL_INFO, " user=%s", tvb_get_ephemeral_string(tvb, offset, strlen));
+       }
+       proto_tree_add_item(login_tree, hf_mysql_user, tvb, offset, strlen, ENC_NA);
+       offset += strlen;
 
-               { &hf_mysql_stat_lr,
-               { "Last row sebd", "mysql.stat.lr",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_LR,
-               NULL, HFILL }},
+       /* rest is optional */
+       if (!tvb_reported_length_remaining(tvb, offset)) return offset;
 
-               { &hf_mysql_stat_dr,
-               { "database dropped", "mysql.stat.dr",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_DR,
-               NULL, HFILL }},
+       /* password: asciiz or length+ascii */
+       if (conn_data->clnt_caps & MYSQL_CAPS_SC) {
+               strlen = tvb_get_guint8(tvb, offset);
+               offset += 1;
+       } else {
+               strlen = my_tvb_strsize(tvb, offset);
+       }
+       if (tree && strlen > 1) {
+               proto_tree_add_item(login_tree, hf_mysql_passwd, tvb, offset, strlen, ENC_NA);
+       }
+       offset += strlen;
 
-               { &hf_mysql_stat_bs,
-               { "No backslash escapes", "mysql.stat.bs",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_BS,
-               NULL, HFILL }},
+       /* optional: initial schema */
+       if (conn_data->clnt_caps & MYSQL_CAPS_CD)
+       {
+               strlen= my_tvb_strsize(tvb,offset);
+               if(strlen<0){
+                       return offset;
+               }
 
-               { &hf_mysql_refresh,
-               { "Refresh Option", "mysql.refresh",
-               FT_UINT8, BASE_DEC, NULL,  0x0,
-               NULL, HFILL }},
+               if (check_col(pinfo->cinfo, COL_INFO)) {
+                       col_append_fstr(pinfo->cinfo, COL_INFO, " db=%s", tvb_get_ephemeral_string(tvb, offset, strlen));
+               }
+               proto_tree_add_item(login_tree, hf_mysql_schema, tvb, offset, strlen, ENC_NA);
+               offset += strlen;
+       }
 
-               { &hf_mysql_rfsh_grants,
-               { "reload permissions", "mysql.rfsh.grants",
-               FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_GRANT,
-               NULL, HFILL }},
+       return offset;
+}
 
-               { &hf_mysql_rfsh_log,
-               { "flush logfiles", "mysql.rfsh.log",
-               FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_LOG,
-               NULL, HFILL }},
 
-               { &hf_mysql_rfsh_tables,
-               { "flush tables", "mysql.rfsh.tables",
-               FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_TABLES,
-               NULL, HFILL }},
+static int
+mysql_dissect_request(tvbuff_t *tvb,packet_info *pinfo, int offset,
+                     proto_tree *tree, mysql_conn_data_t *conn_data)
+{
+       gint opcode;
+       gint strlen;
+       proto_item *tf = NULL, *ti;
+       proto_item *req_tree = NULL;
 
-               { &hf_mysql_rfsh_hosts,
-               { "flush hosts", "mysql.rfsh.hosts",
-               FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_HOSTS,
-               NULL, HFILL }},
+       if (tree) {
+               tf = proto_tree_add_item(tree, hf_mysql_request, tvb, offset, 1, ENC_NA);
+               req_tree = proto_item_add_subtree(tf, ett_request);
+       }
 
-               { &hf_mysql_rfsh_status,
-               { "reset statistics", "mysql.rfsh.status",
-               FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_STATUS,
-               NULL, HFILL }},
+       opcode = tvb_get_guint8(tvb, offset);
+       if (check_col(pinfo->cinfo, COL_INFO)) {
+               col_append_fstr(pinfo->cinfo, COL_INFO, " %s", val_to_str(opcode, mysql_command_vals, "Unknown (%u)"));
+       }
+       proto_tree_add_item(req_tree, hf_mysql_command, tvb, offset, 1, ENC_NA);
+       proto_item_append_text(tf, " %s", val_to_str(opcode, mysql_command_vals, "Unknown (%u)"));
+       offset += 1;
 
-               { &hf_mysql_rfsh_threads,
-               { "empty thread cache", "mysql.rfsh.threads",
-               FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_THREADS,
-               NULL, HFILL }},
 
-               { &hf_mysql_rfsh_slave,
-               { "flush slave status", "mysql.rfsh.slave",
-               FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_SLAVE,
-               NULL, HFILL }},
+       switch (opcode) {
 
-               { &hf_mysql_rfsh_master,
-               { "flush master status", "mysql.rfsh.master",
-               FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_MASTER,
-               NULL, HFILL }},
+       case MYSQL_QUIT:
+               if (conn_data->stmts) {
+                       g_hash_table_destroy(conn_data->stmts);
+                       conn_data->stmts = NULL;
+               }
+               break;
 
-               { &hf_mysql_unused,
-               { "Unused", "mysql.unused",
-               FT_STRING, BASE_NONE, NULL, 0x0,
-               NULL, HFILL }},
+       case MYSQL_PROCESS_INFO:
+               conn_data->state = RESPONSE_TABULAR;
+               break;
 
-               { &hf_mysql_passwd,
-               { "Password", "mysql.passwd",
-               FT_STRING, BASE_NONE, NULL, 0x0,
-               NULL, HFILL }},
+       case MYSQL_DEBUG:
+       case MYSQL_PING:
+               conn_data->state = RESPONSE_OK;
+               break;
 
-               { &hf_mysql_parameter,
-               { "Parameter", "mysql.parameter",
-               FT_STRING, BASE_NONE, NULL, 0x0,
-               NULL, HFILL }},
+       case MYSQL_STATISTICS:
+               conn_data->state = RESPONSE_MESSAGE;
+               break;
 
-               { &hf_mysql_payload,
-               { "Payload", "mysql.payload",
-               FT_STRING, BASE_NONE, NULL, 0x0,
-               "Additional Payload", HFILL }},
+       case MYSQL_INIT_DB:
+       case MYSQL_CREATE_DB:
+       case MYSQL_DROP_DB:
+               strlen = my_tvb_strsize(tvb, offset);
+               proto_tree_add_item(req_tree, hf_mysql_schema, tvb, offset, strlen, ENC_NA);
+               offset += strlen;
+               conn_data->state = RESPONSE_OK;
+               break;
 
-               { &hf_mysql_affected_rows,
-               { "Affected Rows", "mysql.affected_rows",
-               FT_UINT64, BASE_DEC, NULL, 0x0,
-               NULL, HFILL }},
+       case MYSQL_QUERY:
+               strlen = my_tvb_strsize(tvb, offset);
+               proto_tree_add_item(req_tree, hf_mysql_query, tvb, offset, strlen, ENC_NA);
+               if (mysql_showquery) {
+                       if (check_col(pinfo->cinfo, COL_INFO))
+                               col_append_fstr(pinfo->cinfo, COL_INFO, " { %s } ", tvb_get_ephemeral_string(tvb, offset, strlen));
+               }
+               offset += strlen;
+               conn_data->state = RESPONSE_TABULAR;
+               break;
 
-               { &hf_mysql_insert_id,
-               { "Last INSERT ID", "mysql.insert_id",
-               FT_UINT64, BASE_DEC, NULL, 0x0,
-               NULL, HFILL }},
+       case MYSQL_STMT_PREPARE:
+               strlen = my_tvb_strsize(tvb, offset);
+               proto_tree_add_item(req_tree, hf_mysql_query, tvb, offset, strlen, ENC_NA);
+               offset += strlen;
+               conn_data->state = RESPONSE_PREPARE;
+               break;
 
-               { &hf_mysql_num_warn,
-               { "Warnings", "mysql.warnings",
-               FT_UINT16, BASE_DEC, NULL, 0x0,
-               NULL, HFILL }},
+       case MYSQL_STMT_CLOSE:
+               if (conn_data->stmts) {
+                       gint stmt = tvb_get_letohl(tvb, offset);
+                       g_hash_table_remove(conn_data->stmts, &stmt);
+               }
+               proto_tree_add_item(req_tree, hf_mysql_stmt_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+               offset += 4;
+               conn_data->state = REQUEST;
+               break;
 
-               { &hf_mysql_thd_id,
-               { "Thread ID", "mysql.thd_id",
-               FT_UINT32, BASE_DEC, NULL, 0x0,
-               NULL, HFILL }},
+       case MYSQL_STMT_RESET:
+               proto_tree_add_item(req_tree, hf_mysql_stmt_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+               offset += 4;
+               conn_data->state = RESPONSE_OK;
+               break;
 
-               { &hf_mysql_stmt_id,
-               { "Statement ID", "mysql.stmt_id",
-               FT_UINT32, BASE_DEC, NULL, 0x0,
-               NULL, HFILL }},
+       case MYSQL_FIELD_LIST:
+               strlen = my_tvb_strsize(tvb, offset);
+               proto_tree_add_item(req_tree, hf_mysql_table_name, tvb,  offset, strlen, ENC_NA);
+               offset += strlen;
+               conn_data->state = RESPONSE_SHOW_FIELDS;
+               break;
 
-               { &hf_mysql_query,
-               { "Statement", "mysql.query",
-               FT_STRING, BASE_NONE, NULL, 0x0,
-               NULL, HFILL }},
+       case MYSQL_PROCESS_KILL:
+               proto_tree_add_item(req_tree, hf_mysql_thd_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+               offset += 4;
+               conn_data->state = RESPONSE_OK;
+               break;
 
-               { &hf_mysql_option,
-               { "Option", "mysql.option",
-               FT_UINT16, BASE_DEC, NULL, 0x0,
-               NULL, HFILL }},
+       case MYSQL_CHANGE_USER:
+               strlen = tvb_strsize(tvb, offset);
+               proto_tree_add_item(req_tree, hf_mysql_user, tvb,  offset, strlen, ENC_NA);
+               offset += strlen;
 
-               { &hf_mysql_param,
-               { "Parameter", "mysql.param",
-               FT_UINT16, BASE_DEC, NULL, 0x0,
-               NULL, HFILL }},
+               strlen = tvb_strsize(tvb, offset);
+               proto_tree_add_item(req_tree, hf_mysql_passwd, tvb, offset, strlen, ENC_NA);
+               offset += strlen;
 
-               { &hf_mysql_num_rows,
-               { "Rows to fetch", "mysql.num_rows",
-               FT_UINT32, BASE_DEC, NULL, 0x0,
-               NULL, HFILL }},
+               strlen = my_tvb_strsize(tvb, offset);
+               proto_tree_add_item(req_tree, hf_mysql_schema, tvb, offset, strlen, ENC_NA);
+               offset += strlen;
 
-               { &hf_mysql_exec_flags,
-               { "Flags (unused)", "mysql.exec_flags",
-               FT_UINT8, BASE_DEC, NULL, 0x0,
-               NULL, HFILL }},
+               conn_data->state= RESPONSE_OK;
+               break;
 
-               { &hf_mysql_exec_iter,
-               { "Iterations (unused)", "mysql.exec_iter",
-               FT_UINT32, BASE_DEC, NULL, 0x0,
-               NULL, HFILL }},
+       case MYSQL_REFRESH:
+               {
+                       proto_item *tff;
+                       proto_item *rfsh_tree;
 
-               { &hf_mysql_eof,
-               { "EOF", "mysql.eof",
-               FT_UINT8, BASE_DEC, NULL,  0x0,
-               NULL, HFILL }},
+                       tff = proto_tree_add_item(req_tree, hf_mysql_refresh, tvb, offset, 1, ENC_NA);
+                       rfsh_tree = proto_item_add_subtree(tff, ett_refresh);
+                       proto_tree_add_item(rfsh_tree, hf_mysql_rfsh_grants, tvb, offset, 1, ENC_NA);
+                       proto_tree_add_item(rfsh_tree, hf_mysql_rfsh_log, tvb, offset, 1, ENC_NA);
+                       proto_tree_add_item(rfsh_tree, hf_mysql_rfsh_tables, tvb, offset, 1, ENC_NA);
+                       proto_tree_add_item(rfsh_tree, hf_mysql_rfsh_hosts, tvb, offset, 1, ENC_NA);
+                       proto_tree_add_item(rfsh_tree, hf_mysql_rfsh_status, tvb, offset, 1, ENC_NA);
+                       proto_tree_add_item(rfsh_tree, hf_mysql_rfsh_threads, tvb, offset, 1, ENC_NA);
+                       proto_tree_add_item(rfsh_tree, hf_mysql_rfsh_slave, tvb, offset, 1, ENC_NA);
+                       proto_tree_add_item(rfsh_tree, hf_mysql_rfsh_master, tvb, offset, 1, ENC_NA);
 
-               { &hf_mysql_num_fields,
-               { "Number of fields", "mysql.num_fields",
-               FT_UINT64, BASE_DEC, NULL,  0x0,
-               NULL, HFILL }},
+               }
+               offset += 1;
+               conn_data->state= RESPONSE_OK;
+               break;
 
-               { &hf_mysql_extra,
-               { "Extra data", "mysql.extra",
-               FT_UINT64, BASE_DEC, NULL,  0x0,
-               NULL, HFILL }},
+       case MYSQL_SHUTDOWN:
+               proto_tree_add_item(req_tree, hf_mysql_shutdown, tvb, offset, 1, ENC_NA);
+               offset += 1;
+               conn_data->state = RESPONSE_OK;
+               break;
 
-               { &hf_mysql_fld_catalog,
-               { "Catalog", "mysql.field.catalog",
-               FT_STRING, BASE_NONE, NULL, 0x0,
-               "Field: catalog", HFILL }},
+       case MYSQL_SET_OPTION:
+               proto_tree_add_item(req_tree, hf_mysql_option, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               offset += 2;
+               conn_data->state = RESPONSE_OK;
+               break;
 
-               { &hf_mysql_fld_db,
-               { "Database", "mysql.field.db",
-               FT_STRING, BASE_NONE, NULL, 0x0,
-               "Field: database", HFILL }},
+       case MYSQL_STMT_FETCH:
+               proto_tree_add_item(req_tree, hf_mysql_stmt_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+               offset += 4;
 
-               { &hf_mysql_fld_table,
-               { "Table", "mysql.field.table",
-               FT_STRING, BASE_NONE, NULL, 0x0,
-               "Field: table", HFILL }},
+               proto_tree_add_item(req_tree, hf_mysql_num_rows, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+               offset += 4;
+               conn_data->state = RESPONSE_TABULAR;
+               break;
 
-               { &hf_mysql_fld_org_table,
-               { "Original table", "mysql.field.org_table",
-               FT_STRING, BASE_NONE, NULL, 0x0,
-               "Field: original table", HFILL }},
+       case MYSQL_STMT_SEND_LONG_DATA:
+               proto_tree_add_item(req_tree, hf_mysql_stmt_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+               offset += 4;
 
-               { &hf_mysql_fld_name,
-               { "Name", "mysql.field.name",
-               FT_STRING, BASE_NONE, NULL, 0x0,
-               "Field: name", HFILL }},
+               proto_tree_add_item(req_tree, hf_mysql_param, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               offset += 2;
 
-               { &hf_mysql_fld_org_name,
-               { "Original name", "mysql.field.org_name",
-               FT_STRING, BASE_NONE, NULL, 0x0,
-               "Field: original name", HFILL }},
+               /* rest is data */
+               strlen = tvb_reported_length_remaining(tvb, offset);
+               if (tree &&  strlen > 0) {
+                       proto_tree_add_item(req_tree, hf_mysql_payload, tvb, offset, strlen, ENC_NA);
+               }
+               offset += strlen;
+               conn_data->state = REQUEST;
+               break;
 
-               { &hf_mysql_fld_charsetnr,
-               { "Charset number", "mysql.field.charsetnr",
-               FT_UINT16, BASE_DEC, NULL, 0x0,
-               "Field: charset number", HFILL }},
+       case MYSQL_STMT_EXECUTE:
+               proto_tree_add_item(req_tree, hf_mysql_stmt_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+               offset += 4;
 
-               { &hf_mysql_fld_length,
-               { "Length", "mysql.field.length",
-               FT_UINT32, BASE_DEC, NULL, 0x0,
-               "Field: length", HFILL }},
+               if (conn_data->major_version >= 5) {
+                       proto_tree_add_item(req_tree, hf_mysql_exec_flags5, tvb, offset, 1, ENC_NA);
+               } else {
+                       proto_tree_add_item(req_tree, hf_mysql_exec_flags4, tvb, offset, 1, ENC_NA);
+               }
+               offset += 1;
 
-               { &hf_mysql_fld_type,
-               { "Type", "mysql.field.type",
-               FT_UINT8, BASE_DEC, VALS(type_constants), 0x0,
-               "Field: type", HFILL }},
+               proto_tree_add_item(req_tree, hf_mysql_exec_iter, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+               offset += 4;
 
-               { &hf_mysql_fld_flags,
-               { "Flags", "mysql.field.flags",
-               FT_UINT16, BASE_DEC, NULL, 0x0,
-               "Field: flags", HFILL }},
+#if 0
+/* FIXME: rest needs metadata about statement */
+#else
+               strlen = tvb_reported_length_remaining(tvb, offset);
+               if (tree &&  strlen > 0) {
+                       ti = proto_tree_add_item(req_tree, hf_mysql_payload, tvb, offset, strlen, ENC_NA);
+                       expert_add_info_format(pinfo, ti, PI_UNDECODED, PI_WARN, "FIXME: execute dissector incomplete");
+               }
+               offset += strlen;
+#endif
+               conn_data->state= RESPONSE_TABULAR;
+               break;
 
-               { &hf_mysql_fld_not_null,
-               { "Not null", "mysql.field.flags.not_null",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_NOT_NULL_FLAG,
-               "Field: flag not null", HFILL }},
+       case MYSQL_BINLOG_DUMP:
+               proto_tree_add_item(req_tree, hf_mysql_binlog_position, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+               offset += 4;
 
-               { &hf_mysql_fld_primary_key,
-               { "Primary key", "mysql.field.flags.primary_key",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_PRI_KEY_FLAG,
-               "Field: flag primary key", HFILL }},
+               proto_tree_add_item(req_tree, hf_mysql_binlog_flags, tvb, offset, 2, ENC_NA);
+               offset += 2;
 
-               { &hf_mysql_fld_unique_key,
-               { "Unique key", "mysql.field.flags.unique_key",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_UNIQUE_KEY_FLAG,
-               "Field: flag unique key", HFILL }},
+               proto_tree_add_item(req_tree, hf_mysql_binlog_server_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+               offset += 4;
 
-               { &hf_mysql_fld_multiple_key,
-               { "Multiple key", "mysql.field.flags.multiple_key",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_MULTIPLE_KEY_FLAG,
-               "Field: flag multiple key", HFILL }},
+               /* binlog file name ? */
+               strlen = tvb_reported_length_remaining(tvb, offset);
+               if (tree &&  strlen > 0) {
+                       proto_tree_add_item(req_tree, hf_mysql_binlog_file_name, tvb, offset, strlen, ENC_NA);
+               }
+               offset += strlen;
 
-               { &hf_mysql_fld_blob,
-               { "Blob", "mysql.field.flags.blob",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_BLOB_FLAG,
-               "Field: flag blob", HFILL }},
+               conn_data->state = REQUEST;
+               break;
+/* FIXME: implement replication packets */
+       case MYSQL_TABLE_DUMP:
+       case MYSQL_CONNECT_OUT:
+       case MYSQL_REGISTER_SLAVE:
+               ti = proto_tree_add_item(req_tree, hf_mysql_payload, tvb, offset, -1, ENC_NA);
+               expert_add_info_format(pinfo, ti, PI_UNDECODED, PI_WARN, "FIXME: implement replication packets");
+               offset += tvb_reported_length_remaining(tvb, offset);
+               conn_data->state = REQUEST;
+               break;
 
-               { &hf_mysql_fld_unsigned,
-               { "Unsigned", "mysql.field.flags.unsigned",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_UNSIGNED_FLAG,
-               "Field: flag unsigned", HFILL }},
+       default:
+               ti = proto_tree_add_item(req_tree, hf_mysql_payload, tvb, offset, -1, ENC_NA);
+               expert_add_info_format(pinfo, ti, PI_PROTOCOL, PI_WARN, "Unknown/invalid command code");
+               offset += tvb_reported_length_remaining(tvb, offset);
+               conn_data->state = UNDEFINED;
+       }
 
-               { &hf_mysql_fld_zero_fill,
-               { "Zero fill", "mysql.field.flags.zero_fill",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_ZEROFILL_FLAG,
-               "Field: flag zero fill", HFILL }},
+       return offset;
+}
 
-               { &hf_mysql_fld_binary,
-               { "Binary", "mysql.field.flags.binary",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_BINARY_FLAG,
-               "Field: flag binary", HFILL }},
 
-               { &hf_mysql_fld_enum,
-               { "Enum", "mysql.field.flags.enum",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_ENUM_FLAG,
-               "Field: flag enum", HFILL }},
+static int
+mysql_dissect_response(tvbuff_t *tvb, packet_info *pinfo, int offset,
+                      proto_tree *tree, mysql_conn_data_t *conn_data)
+{
+       gint response_code;
+       gint strlen;
+    gint server_status = 0;
 
-               { &hf_mysql_fld_auto_increment,
-               { "Auto increment", "mysql.field.flags.auto_increment",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_AUTO_INCREMENT_FLAG,
-               "Field: flag auto increment", HFILL }},
+       response_code = tvb_get_guint8(tvb, offset);
 
-               { &hf_mysql_fld_timestamp,
-               { "Timestamp", "mysql.field.flags.timestamp",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_TIMESTAMP_FLAG,
-               "Field: flag timestamp", HFILL }},
+       if (response_code == 0xff ) {
+               offset = mysql_dissect_error_packet(tvb, pinfo, offset+1, tree);
+               conn_data->state= REQUEST;
+       }
 
-               { &hf_mysql_fld_set,
-               { "Set", "mysql.field.flags.set",
-               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_SET_FLAG,
-               "Field: flag set", HFILL }},
+       else if (response_code == 0xfe && tvb_reported_length_remaining(tvb, offset) < 9) {
 
-               { &hf_mysql_fld_decimals,
-               { "Decimals", "mysql.field.decimals",
-               FT_UINT8, BASE_DEC, NULL, 0x0,
-               "Field: decimals", HFILL }},
+               proto_tree_add_item(tree, hf_mysql_eof, tvb, offset, 1, ENC_NA);
 
-               { &hf_mysql_fld_default,
-               { "Default", "mysql.field.default",
-               FT_STRING, BASE_NONE, NULL, 0x0,
-               "Field: default", HFILL }},
+               offset += 1;
 
-               { &hf_mysql_row_length,
-               { "length", "mysql.row.length",
-               FT_UINT8, BASE_DEC, NULL, 0x0,
-               "Field: row packet text length", HFILL }},
+               /* pre-4.1 packet ends here */
+               if (tvb_reported_length_remaining(tvb, offset)) {
+                       proto_tree_add_item(tree, hf_mysql_num_warn, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+                       server_status = tvb_get_letohs(tvb, offset+2);
+                       offset = mysql_dissect_server_status(tvb, offset+2, tree);
+               }
 
-               { &hf_mysql_row_text,
-               { "text", "mysql.row.text",
-               FT_STRING, BASE_NONE, NULL, 0x0,
-               "Field: row packet text", HFILL }},
-       };
+               if (conn_data->state == FIELD_PACKET) {
+                       conn_data->state= ROW_PACKET;
+               } else if (conn_data->state == ROW_PACKET) {
+                       if (server_status & MYSQL_STAT_MU) {
+                               conn_data->state= RESPONSE_TABULAR;
+                       } else {
+                               conn_data->state= REQUEST;
+                       }
+               } else if (conn_data->state == PREPARED_PARAMETERS) {
+                       if (conn_data->stmt_num_fields > 0) {
+                               conn_data->state= PREPARED_FIELDS;
+                       } else {
+                               conn_data->state= REQUEST;
+                       }
+               } else if (conn_data->state == PREPARED_FIELDS) {
+                       conn_data->state= REQUEST;
+               } else {
+                       /* This should be an unreachable case */
+                       conn_data->state= REQUEST;
+               }
+       }
 
-       static gint *ett[]=
-       {
-               &ett_mysql,
-               &ett_server_greeting,
-               &ett_caps,
-               &ett_extcaps,
-               &ett_stat,
-               &ett_request,
-               &ett_refresh,
-               &ett_field_flags
-       };
+       else if (response_code == 0) {
+               if (conn_data->state == RESPONSE_PREPARE) {
+                       offset = mysql_dissect_response_prepare(tvb, offset, tree, conn_data);
+               } else if (tvb_reported_length_remaining(tvb, offset+1)  > tvb_get_fle(tvb, offset+1, NULL, NULL)) {
+                       offset = mysql_dissect_ok_packet(tvb, pinfo, offset+1, tree, conn_data);
+               } else {
+                       offset = mysql_dissect_result_header(tvb, pinfo, offset, tree, conn_data);
+               }
+       }
 
-       module_t *mysql_module;
+       else {
+               switch (conn_data->state) {
+               case RESPONSE_MESSAGE:
+                       if ((strlen = tvb_reported_length_remaining(tvb, offset))) {
+                               proto_tree_add_item(tree, hf_mysql_message, tvb, offset, strlen, ENC_NA);
+                               offset += strlen;
+                       }
+                       conn_data->state = REQUEST;
+                       break;
 
-       proto_mysql= proto_register_protocol("MySQL Protocol", "MySQL", "mysql");
-       proto_register_field_array(proto_mysql, hf, array_length(hf));
-       proto_register_subtree_array(ett, array_length(ett));
+               case RESPONSE_TABULAR:
+                       offset = mysql_dissect_result_header(tvb, pinfo, offset, tree, conn_data);
+                       break;
 
-       mysql_module= prefs_register_protocol(proto_mysql, NULL);
-       prefs_register_bool_preference(mysql_module, "desegment_buffers",
-                                      "Reassemble MySQL buffers spanning multiple TCP segments",
-                                      "Whether the MySQL dissector should reassemble MySQL buffers spanning multiple TCP segments."
-                                      " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
-                                      &mysql_desegment);
-       prefs_register_bool_preference(mysql_module, "show_sql_query",
-                                      "Show SQL Query string in INFO column",
-                                      "Whether the MySQL dissector should display the SQL query string in the INFO column.",
-                                      &mysql_showquery);
+               case FIELD_PACKET:
+               case RESPONSE_SHOW_FIELDS:
+               case RESPONSE_PREPARE:
+               case PREPARED_PARAMETERS:
+                       offset = mysql_dissect_field_packet(tvb, offset, tree, conn_data);
+                       break;
 
-        register_dissector("mysql", dissect_mysql_pdu, proto_mysql);
-}
+               case ROW_PACKET:
+                       offset = mysql_dissect_row_packet(tvb, offset, tree);
+                       break;
 
+               case PREPARED_FIELDS:
+                       offset = mysql_dissect_field_packet(tvb, offset, tree, conn_data);
+                       break;
 
-/* dissector entrypoint, handles TCP-desegmentation */
-static void
-dissect_mysql(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
-{
-       tcp_dissect_pdus(tvb, pinfo, tree, mysql_desegment, 3,
-                        get_mysql_pdu_len, dissect_mysql_pdu);
+               default:
+                       proto_tree_add_string(tree, hf_mysql_payload, tvb, offset, -1,
+                                             "unknown/invalid response");
+                       offset += tvb_reported_length_remaining(tvb, offset);
+                       conn_data->state = UNDEFINED;
+               }
+       }
+
+       return offset;
 }
 
 
-/* dissector helper: length of PDU */
-static guint
-get_mysql_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
-{
-       guint plen= tvb_get_letoh24(tvb, offset);
-       return plen + 4; /* add length field + packet number */
-}
-
-/* dissector main function: handle one PDU */
-static void
-dissect_mysql_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+static int
+mysql_dissect_error_packet(tvbuff_t *tvb, packet_info *pinfo,
+                          int offset, proto_tree *tree)
 {
-       proto_tree      *mysql_tree= NULL;
-       proto_item      *ti;
-       conversation_t  *conversation;
-       int             offset = 0;
-       guint           packet_number;
-       gboolean        is_response;
-       mysql_conn_data_t  *conn_data;
-#ifdef CTDEBUG
-       mysql_state_t conn_state_in, conn_state_out, frame_state;
-       guint64         generation;
-       proto_item *pi;
-#endif
-       struct mysql_frame_data  *mysql_frame_data_p;
-
-       /* get conversation, create if neccessary*/
-       conversation= find_or_create_conversation(pinfo);
+       if (check_col(pinfo->cinfo, COL_INFO)) {
+               col_append_fstr(pinfo->cinfo, COL_INFO, " Error %d", tvb_get_letohs(tvb, offset));
+       }
+       proto_tree_add_item(tree, hf_mysql_error_code, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+       offset += 2;
 
-       /* get associated state information, create if neccessary */
-       conn_data= conversation_get_proto_data(conversation, proto_mysql);
-       if (!conn_data) {
-               conn_data= se_alloc(sizeof(mysql_conn_data_t));
-               conn_data->srv_caps= 0;
-               conn_data->clnt_caps= 0;
-               conn_data->clnt_caps_ext= 0;
-               conn_data->state= UNDEFINED;
-               conn_data->stmts= g_hash_table_new(g_int_hash, g_int_equal);
-#ifdef CTDEBUG
-               conn_data->generation= 0;
-#endif
-               conversation_add_proto_data(conversation, proto_mysql, conn_data);
+       if (tvb_get_guint8(tvb, offset) == '#')
+       {
+               offset += 1;
+               proto_tree_add_item(tree, hf_mysql_sqlstate, tvb, offset, 5, ENC_NA);
+               offset += 5;
        }
 
-       mysql_frame_data_p = p_get_proto_data(pinfo->fd, proto_mysql);
-       if (!mysql_frame_data_p) {
-               /*  We haven't seen this frame before.  Store the state of the
-                *  conversation now so if/when we dissect the frame again
-                *  we'll start with the same state.
-                */
-               mysql_frame_data_p = se_alloc(sizeof(struct mysql_frame_data));
-               mysql_frame_data_p->state = conn_data->state;
-               p_add_proto_data(pinfo->fd, proto_mysql, mysql_frame_data_p);
+       proto_tree_add_item(tree, hf_mysql_error_string, tvb, offset, -1, ENC_NA);
+       offset += tvb_reported_length_remaining(tvb, offset);
 
-       } else if (conn_data->state != FIELD_PACKET  && conn_data->state != ROW_PACKET ) {
-               /*  We have seen this frame before.  Set the connection state
-                *  to whatever state it had the first time we saw this frame
-                *  (e.g., based on whatever frames came before it).
-                *  The state may change as we dissect this packet.
-                *  XXX: I think the logic of the above else if test is as follows:
-                *       During the first (sequential) dissection pass thru the capture
-                *       file the conversation connection state as of the beginning of each frame
-                *       is saved in the connection_state for that frame.
-                *       Any state changes *within* a mysql "message" (ie: query/response/etc)
-                *       while processing mysql PDUS (aka "packets") in that message must be preserved.
-                *       It appears that FIELD_PACKET & ROW_PACKET are the only two
-                *       state changes which can occur within a mysql message which affect
-                *       subsequent processing within the message.
-                *       Question: Does this logic work OK for a reassembled message ?
-                */
-                conn_data->state= mysql_frame_data_p->state;
-       }
+       return offset;
+}
 
-       if (tree) {
-               ti= proto_tree_add_item(tree, proto_mysql, tvb, offset, -1, FALSE);
-               mysql_tree= proto_item_add_subtree(ti, ett_mysql);
-               proto_tree_add_item(mysql_tree, hf_mysql_packet_length, tvb,
-                                   offset, 3, TRUE);
-       }
-       offset+= 3;
 
-       col_set_str(pinfo->cinfo, COL_PROTOCOL, "MySQL");
+static int
+mysql_dissect_ok_packet(tvbuff_t *tvb, packet_info *pinfo, int offset,
+                       proto_tree *tree, mysql_conn_data_t *conn_data)
+{
+       gint strlen;
+       guint64 affected_rows;
+       guint64 insert_id;
+       int fle;
 
-       if (pinfo->destport == pinfo->match_port) {
-               is_response= FALSE;
-       } else {
-               is_response= TRUE;
-       }
+       col_append_str(pinfo->cinfo, COL_INFO, " OK" );
 
-       packet_number= tvb_get_guint8(tvb, offset);
-       proto_tree_add_uint(mysql_tree, hf_mysql_packet_number, tvb,
-                           offset, 1, packet_number);
-       offset+= 1;
+       fle = tvb_get_fle(tvb, offset, &affected_rows, NULL);
+       proto_tree_add_uint64(tree, hf_mysql_affected_rows, tvb, offset, fle, affected_rows);
+       offset += fle;
 
-#ifdef CTDEBUG
-       conn_state_in= conn_data->state;
-       frame_state = mysql_frame_data_p->state;
-       generation= conn_data->generation;
-       if (tree) {
-               pi= proto_tree_add_text(mysql_tree, tvb, offset, 0, "conversation: %p", conversation);
-               PROTO_ITEM_SET_GENERATED(pi);
-               pi= proto_tree_add_text(mysql_tree, tvb, offset, 0, "generation: %" G_GINT64_MODIFIER "d", generation);
-               PROTO_ITEM_SET_GENERATED(pi);
-               pi= proto_tree_add_text(mysql_tree, tvb, offset, 0, "conn state: %s (%u)",
-                                   val_to_str(conn_state_in, state_vals, "Unknown (%u)"),
-                                   conn_state_in);
-               PROTO_ITEM_SET_GENERATED(pi);
-               pi= proto_tree_add_text(mysql_tree, tvb, offset, 0, "frame state: %s (%u)",
-                                   val_to_str(frame_state, state_vals, "Unknown (%u)"),
-                                   frame_state);
-               PROTO_ITEM_SET_GENERATED(pi);
+       fle= tvb_get_fle(tvb, offset, &insert_id, NULL);
+       if (tree && insert_id) {
+               proto_tree_add_uint64(tree, hf_mysql_insert_id, tvb, offset, fle, insert_id);
        }
-#endif
+       offset += fle;
 
-       if (is_response) {
-               if (packet_number == 0) {
-                       col_set_str(pinfo->cinfo, COL_INFO, "Server Greeting");
-                       offset= mysql_dissect_greeting(tvb, pinfo, offset,
-                                                      mysql_tree, conn_data);
-               } else {
-                       col_set_str(pinfo->cinfo, COL_INFO, "Response");
-                       offset= mysql_dissect_response(tvb, pinfo, offset,
-                                                      mysql_tree, conn_data);
-               }
-       } else {
-               if (packet_number == 1) {
-                       col_set_str(pinfo->cinfo, COL_INFO, "Login Request");
-                       offset= mysql_dissect_login(tvb, pinfo, offset,
-                                                   mysql_tree, conn_data);
-               } else {
-                       col_set_str(pinfo->cinfo, COL_INFO, "Request");
-                       offset= mysql_dissect_request(tvb, pinfo, offset,
-                                                     mysql_tree, conn_data);
+       if (tvb_reported_length_remaining(tvb, offset) > 0) {
+               offset = mysql_dissect_server_status(tvb, offset, tree);
+
+               /* 4.1+ protocol only: 2 bytes number of warnings */
+               if (conn_data->clnt_caps & conn_data->srv_caps & MYSQL_CAPS_CU) {
+                       proto_tree_add_item(tree, hf_mysql_num_warn, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               offset += 2;
                }
        }
 
-#ifdef CTDEBUG
-       conn_state_out= conn_data->state;
-       ++(conn_data->generation);
-       pi= proto_tree_add_text(mysql_tree, tvb, offset, 0, "next proto state: %s (%u)",
-                           val_to_str(conn_state_out, state_vals, "Unknown (%u)"),
-                           conn_state_out);
-       PROTO_ITEM_SET_GENERATED(pi);
-#endif
-
-       /* remaining payload indicates an error */
-       if (tree && tvb_reported_length_remaining(tvb, offset) > 0) {
-               proto_tree_add_string(mysql_tree, hf_mysql_payload, tvb, offset, -1,
-                                     "FIXME - dissector is incomplete");
+       /* optional: message string */
+       if (tvb_reported_length_remaining(tvb, offset) > 0) {
+               strlen = tvb_reported_length_remaining(tvb, offset);
+               proto_tree_add_item(tree, hf_mysql_message, tvb, offset, strlen, ENC_NA);
+               offset += strlen;
        }
+
+       conn_data->state = REQUEST;
+       return offset;
 }
 
 
 static int
-mysql_dissect_greeting(tvbuff_t *tvb, packet_info *pinfo, int offset,
-                      proto_tree *tree, mysql_conn_data_t *conn_data)
+mysql_dissect_server_status(tvbuff_t *tvb, int offset, proto_tree *tree)
 {
-       gint protocol;
-       gint strlen;
-       gint32 thread_id;
-
        proto_item *tf;
-       proto_item *greeting_tree= NULL;
-
-       protocol= tvb_get_guint8(tvb, offset);
-
-       if (protocol == 0xff) {
-               return mysql_dissect_error_packet(tvb, pinfo, offset+1, tree);
-       }
-
-       conn_data->state= LOGIN;
+       proto_item *stat_tree;
 
        if (tree) {
-               tf= proto_tree_add_text(tree, tvb, offset, -1, "Server Greeting");
-               greeting_tree= proto_item_add_subtree(tf, ett_server_greeting);
-       }
-
-       if (check_col(pinfo->cinfo, COL_INFO)) {
-               col_append_fstr(pinfo->cinfo, COL_INFO, " proto=%d", protocol) ;
+               tf= proto_tree_add_item(tree, hf_mysql_server_status, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               stat_tree= proto_item_add_subtree(tf, ett_stat);
+               proto_tree_add_item(stat_tree, hf_mysql_stat_it, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(stat_tree, hf_mysql_stat_ac, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(stat_tree, hf_mysql_stat_mr, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(stat_tree, hf_mysql_stat_mu, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(stat_tree, hf_mysql_stat_bi, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(stat_tree, hf_mysql_stat_ni, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(stat_tree, hf_mysql_stat_cr, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(stat_tree, hf_mysql_stat_lr, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(stat_tree, hf_mysql_stat_dr, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(stat_tree, hf_mysql_stat_bs, tvb, offset, 2, ENC_LITTLE_ENDIAN);
        }
-       proto_tree_add_uint(greeting_tree, hf_mysql_protocol, tvb,
-                           offset, 1, protocol);
-       offset+= 1;
-
-       /* version string */
-       strlen= tvb_strsize(tvb,offset);
+       offset += 2;
 
-       if (check_col(pinfo->cinfo, COL_INFO)) {
-               col_append_fstr(pinfo->cinfo, COL_INFO, " version=%s",
-                               tvb_get_ptr(tvb, offset, strlen));
-       }
-       proto_tree_add_item(greeting_tree, hf_mysql_version, tvb,
-                           offset, strlen, FALSE );
-       offset+= strlen;
+       return offset;
+}
 
-       /* 4 bytes little endian thread_id */
-       thread_id= tvb_get_letohl(tvb, offset);
-       proto_tree_add_uint(greeting_tree, hf_mysql_thread_id, tvb,
-                           offset, 4, thread_id);
-       offset+= 4;
 
-       /* salt string */
-       strlen= tvb_strsize(tvb,offset);
-       proto_tree_add_item(greeting_tree, hf_mysql_salt, tvb,
-                           offset, strlen, FALSE );
-       offset+=strlen;
+static int
+mysql_dissect_caps_server(tvbuff_t *tvb, int offset, proto_tree *tree, guint16 *caps)
+{
+       proto_item *tf;
+       proto_item *cap_tree;
 
-       /* rest is optional */
-       if (!tvb_reported_length_remaining(tvb, offset)) return offset;
+       *caps= tvb_get_letohs(tvb, offset);
 
-       /* 2 bytes CAPS */
-       offset= mysql_dissect_caps(tvb, offset, greeting_tree, &conn_data->srv_caps, "Server");
+       if (tree) {
+               tf = proto_tree_add_item(tree, hf_mysql_caps_server, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               cap_tree= proto_item_add_subtree(tf, ett_caps);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_long_password, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_found_rows, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_long_flag, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_connect_with_db, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_no_schema, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_compress, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_odbc, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_local_files, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_ignore_space, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_change_user, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_interactive, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_ssl, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_ignore_sigpipe, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_transactions, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_reserved, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_secure_connect, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+       }
 
-       /* rest is optional */
-       if (!tvb_reported_length_remaining(tvb, offset)) return offset;
+       offset += 2;
+       return offset;
+}
 
-       mysql_dissect_collation(tvb, offset, greeting_tree, conn_data->srv_caps,
-                               tvb_get_guint8(tvb, offset), hf_mysql_charset);
-       offset++; /* for charset */
-       offset= mysql_dissect_server_status(tvb, offset, greeting_tree);
+static int
+mysql_dissect_caps_client(tvbuff_t *tvb, int offset, proto_tree *tree, guint16 *caps)
+{
+       proto_item *tf;
+       proto_item *cap_tree;
 
-       /* 13 bytes unused */
-       proto_tree_add_item(greeting_tree, hf_mysql_unused, tvb,
-                           offset, 13, FALSE );
-       offset+= 13;
+       *caps= tvb_get_letohs(tvb, offset);
 
-       /* 4.1+ server: rest of salt */
-       if (tvb_reported_length_remaining(tvb, offset)) {
-               strlen= tvb_strsize(tvb,offset);
-               proto_tree_add_item(greeting_tree, hf_mysql_salt2, tvb,
-                                   offset, strlen, FALSE );
-               offset+= strlen;
+       if (tree) {
+               tf = proto_tree_add_item(tree, hf_mysql_caps_client, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               cap_tree= proto_item_add_subtree(tf, ett_caps);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_long_password, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_found_rows, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_long_flag, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_connect_with_db, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_no_schema, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_compress, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_odbc, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_local_files, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_ignore_space, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_change_user, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_interactive, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_ssl, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_ignore_sigpipe, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_transactions, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_reserved, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(cap_tree, hf_mysql_cap_secure_connect, tvb, offset, 2, ENC_LITTLE_ENDIAN);
        }
 
+       offset += 2;
        return offset;
 }
-
-
 static int
-mysql_dissect_login(tvbuff_t *tvb, packet_info *pinfo, int offset,
-                   proto_tree *tree, mysql_conn_data_t *conn_data)
+mysql_dissect_ext_caps_client(tvbuff_t *tvb, int offset, proto_tree *tree, guint16 *ext_caps)
 {
-       guint16  ext_caps;
-       guint32  max_packet;
-       gint     strlen;
-
        proto_item *tf;
-       proto_item *login_tree= NULL;
-
-       /* after login there can be OK or DENIED */
-       conn_data->state= RESPONSE_OK;
-
+       proto_item *extcap_tree;
+       *ext_caps= tvb_get_letohs(tvb, offset);
        if (tree) {
-               tf= proto_tree_add_text(tree, tvb, offset, -1, "Login Request");
-               login_tree= proto_item_add_subtree(tf, ett_server_greeting);
+               tf = proto_tree_add_item(tree, hf_mysql_extcaps_client, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               extcap_tree = proto_item_add_subtree(tf, ett_extcaps);
+               proto_tree_add_item(extcap_tree, hf_mysql_cap_multi_statements, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+               proto_tree_add_item(extcap_tree, hf_mysql_cap_multi_results, tvb, offset, 2, ENC_LITTLE_ENDIAN);
        }
 
-       offset= mysql_dissect_caps(tvb, offset, login_tree, &conn_data->clnt_caps, "Client");
+       offset += 2;
+       return offset;
+}
 
-       if (conn_data->clnt_caps & MYSQL_CAPS_CU) /* 4.1 protocol */
-       {
-               offset= mysql_dissect_ext_caps(tvb, offset, login_tree, &ext_caps, "Client");
-               conn_data->clnt_caps_ext= ext_caps;
 
-               max_packet= tvb_get_letohl(tvb, offset);
-               proto_tree_add_uint(login_tree, hf_mysql_max_packet, tvb,
-                                   offset, 4, max_packet);
-               offset+= 4;
+static int
+mysql_dissect_result_header(tvbuff_t *tvb, packet_info *pinfo, int offset,
+                           proto_tree *tree, mysql_conn_data_t *conn_data)
+{
+       gint fle;
+       guint64 num_fields, extra;
 
-               mysql_dissect_collation(tvb, offset, login_tree, conn_data->clnt_caps,
-                                       tvb_get_guint8(tvb, offset), hf_mysql_charset);
-               offset++; /* for charset */
+       col_append_str(pinfo->cinfo, COL_INFO, " TABULAR" );
 
-               offset+= 23; /* filler bytes */
+       fle = tvb_get_fle(tvb, offset, &num_fields, NULL);
+       proto_tree_add_uint64(tree, hf_mysql_num_fields, tvb, offset, fle, num_fields);
+       offset += fle;
 
-       } else { /* pre-4.1 */
-               max_packet= 0xffffff - tvb_get_letoh24(tvb, offset);
-               proto_tree_add_uint(login_tree, hf_mysql_max_packet, tvb,
-                                   offset, 3, max_packet);
-               offset+= 3;
+       if (tvb_reported_length_remaining(tvb, offset)) {
+               fle = tvb_get_fle(tvb, offset, &extra, NULL);
+               proto_tree_add_uint64(tree, hf_mysql_extra, tvb, offset, fle, extra);
+               offset += fle;
        }
 
-       /* User name */
-       strlen= my_tvb_strsize(tvb, offset);
-       if (check_col(pinfo->cinfo, COL_INFO)) {
-               col_append_fstr(pinfo->cinfo, COL_INFO, " user=%s",
-                               tvb_get_ptr(tvb,offset,strlen));
+       if (num_fields) {
+               conn_data->state = FIELD_PACKET;
+       } else {
+               conn_data->state = ROW_PACKET;
        }
-       proto_tree_add_item(login_tree, hf_mysql_user, tvb,
-                           offset, strlen, FALSE );
-       offset+= strlen;
 
-       /* rest is optional */
-       if (!tvb_reported_length_remaining(tvb, offset)) return offset;
+       return offset;
+}
 
-       /* password: asciiz or length+ascii */
-       if (conn_data->clnt_caps & MYSQL_CAPS_SC) {
-               strlen= tvb_get_guint8(tvb, offset);
-               offset+= 1;
-       } else {
-               strlen= my_tvb_strsize(tvb, offset);
-       }
-       if (tree && strlen > 1) {
-               proto_tree_add_item(login_tree, hf_mysql_passwd,
-                                   tvb, offset, strlen, FALSE);
-       }
-       offset+= strlen;
 
-       /* optional: initial schema */
-       if (conn_data->clnt_caps & MYSQL_CAPS_CD)
-       {
-               strlen= my_tvb_strsize(tvb,offset);
-               if(strlen<0){
-                       return offset;
-               }
+/*
+ * Add length encoded string to tree
+ */
+static int
+mysql_field_add_lestring(tvbuff_t *tvb, int offset, proto_tree *tree, int field)
+{
+       guint64 lelen;
+       guint8 is_null;
 
-               if (check_col(pinfo->cinfo, COL_INFO)) {
-                       /* ugly hack: copy database to new buffer*/
-                       guint8 buf[65];
-                       if (strlen > 64)
-                               strlen= 64;
-                       tvb_memcpy(tvb, buf, offset, strlen);
-                       buf[strlen]= '\0';
-                       col_append_fstr(pinfo->cinfo, COL_INFO, " db=%s", buf);
-               }
-               proto_tree_add_item(login_tree, hf_mysql_schema, tvb,
-                                   offset, strlen, FALSE );
-               offset+= strlen;
+       offset += tvb_get_fle(tvb, offset, &lelen, &is_null);
+       if(is_null)
+               proto_tree_add_string(tree, field, tvb, offset, 4, "NULL");
+       else
+       {
+               proto_tree_add_item(tree, field, tvb, offset, (int)lelen, ENC_NA);
+               offset += (int)lelen;
        }
-
        return offset;
 }
 
 
 static int
-mysql_dissect_request(tvbuff_t *tvb,packet_info *pinfo, int offset,
-                     proto_tree *tree, mysql_conn_data_t *conn_data)
+mysql_dissect_field_packet(tvbuff_t *tvb, int offset, proto_tree *tree, mysql_conn_data_t *conn_data _U_)
 {
-       gint opcode;
-       gint strlen;
        proto_item *tf;
-       proto_item *req_tree= NULL;
-       guint16 option;
-
-       if (tree) {
-               tf= proto_tree_add_text(tree, tvb, offset, -1, "Command");
-               req_tree= proto_item_add_subtree(tf, ett_request);
-       }
+       proto_item *flags_tree;
 
-       opcode= tvb_get_guint8(tvb, offset);
-       if (check_col(pinfo->cinfo, COL_INFO)) {
-               col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
-                               val_to_str(opcode, mysql_opcode_vals, "Unknown (%u)"));
-       }
-       proto_tree_add_uint_format(req_tree, hf_mysql_opcode, tvb,
-                                  offset, 1, opcode, "Command: %s (%u)",
-                                  val_to_str(opcode, mysql_opcode_vals, "Unknown (%u)"),
-                                  opcode);
-       offset+= 1;
+       offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_catalog);
+       offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_db);
+       offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_table);
+       offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_org_table);
+       offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_name);
+       offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_org_name);
+       offset +=1; /* filler */
 
+       proto_tree_add_item(tree, hf_mysql_fld_charsetnr, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+       offset += 2; /* charset */
 
-       switch (opcode) {
+       proto_tree_add_item(tree, hf_mysql_fld_length, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+       offset += 4; /* length */
 
-       case MYSQL_QUIT:
-               if (conn_data->stmts) {
-                       g_hash_table_destroy(conn_data->stmts);
-                       conn_data->stmts= NULL;
-               }
-               break;
+       proto_tree_add_item(tree, hf_mysql_fld_type, tvb, offset, 1, ENC_NA);
+       offset += 1; /* type */
 
-       case MYSQL_PROCESS_INFO:
-               conn_data->state= RESPONSE_TABULAR;
-               break;
+       tf = proto_tree_add_item(tree, hf_mysql_fld_flags, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+       flags_tree = proto_item_add_subtree(tf, ett_field_flags);
+       proto_tree_add_item(flags_tree, hf_mysql_fld_not_null, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+       proto_tree_add_item(flags_tree, hf_mysql_fld_primary_key, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+       proto_tree_add_item(flags_tree, hf_mysql_fld_unique_key, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+       proto_tree_add_item(flags_tree, hf_mysql_fld_multiple_key, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+       proto_tree_add_item(flags_tree, hf_mysql_fld_blob, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+       proto_tree_add_item(flags_tree, hf_mysql_fld_unsigned, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+       proto_tree_add_item(flags_tree, hf_mysql_fld_zero_fill, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+       proto_tree_add_item(flags_tree, hf_mysql_fld_binary, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+       proto_tree_add_item(flags_tree, hf_mysql_fld_enum, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+       proto_tree_add_item(flags_tree, hf_mysql_fld_auto_increment, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+       proto_tree_add_item(flags_tree, hf_mysql_fld_timestamp, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+       proto_tree_add_item(flags_tree, hf_mysql_fld_set, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+       offset += 2; /* flags */
 
-       case MYSQL_DEBUG:
-       case MYSQL_PING:
-               conn_data->state= RESPONSE_OK;
-               break;
+       proto_tree_add_item(tree, hf_mysql_fld_decimals, tvb, offset, 1, ENC_NA);
+       offset += 1; /* decimals */
 
-       case MYSQL_STATISTICS:
-               conn_data->state= RESPONSE_MESSAGE;
-               break;
+       offset += 2; /* filler */
 
-       case MYSQL_INIT_DB:
-       case MYSQL_CREATE_DB:
-       case MYSQL_DROP_DB:
-               strlen= my_tvb_strsize(tvb, offset);
-               proto_tree_add_item(req_tree, hf_mysql_schema, tvb,
-                                   offset, strlen, FALSE);
-               offset+= strlen;
-               conn_data->state= RESPONSE_OK;
-               break;
+       /* default (Only use for show fields) */
+       if (tree && tvb_reported_length_remaining(tvb, offset) > 0) {
+               offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_default);
+       }
+       return offset;
+}
 
-       case MYSQL_QUERY:
-               strlen= my_tvb_strsize(tvb, offset);
-               proto_tree_add_item(req_tree, hf_mysql_query, tvb,
-                                   offset, strlen, FALSE);
-               if (mysql_showquery) {
-                       if (check_col(pinfo->cinfo, COL_INFO))
-                               col_append_fstr(pinfo->cinfo, COL_INFO, " { %s } ",
-                                               tvb_get_ephemeral_string(tvb, offset, strlen));
-               }
-               offset+= strlen;
-               conn_data->state= RESPONSE_TABULAR;
-               break;
 
-       case MYSQL_STMT_PREPARE:
-               strlen= my_tvb_strsize(tvb, offset);
-               proto_tree_add_item(req_tree, hf_mysql_query, tvb,
-                                   offset, strlen, FALSE);
-               offset+= strlen;
-               conn_data->state= RESPONSE_PREPARE;
-               break;
+static int
+mysql_dissect_row_packet(tvbuff_t *tvb, int offset, proto_tree *tree)
+{
+       while (tvb_reported_length_remaining(tvb, offset) > 0)  {
+               offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_row_text);
+       }
 
-       case MYSQL_STMT_CLOSE:
-               if (conn_data->stmts) {
-                       gint stmt= tvb_get_letohl(tvb, offset);
-                       g_hash_table_remove(conn_data->stmts, &stmt);
-               }
-               proto_tree_add_item(req_tree, hf_mysql_stmt_id,
-                                   tvb, offset, 4, TRUE);
-               offset+= 4;
-               conn_data->state= REQUEST;
-               break;
+       return offset;
+}
 
-       case MYSQL_STMT_RESET:
-               proto_tree_add_item(req_tree, hf_mysql_stmt_id,
-                                   tvb, offset, 4, TRUE);
-               offset+= 4;
-               conn_data->state= RESPONSE_OK;
-               break;
 
-       case MYSQL_FIELD_LIST:
-               strlen= my_tvb_strsize(tvb, offset);
-               proto_tree_add_text(req_tree, tvb, offset, strlen, "Table name: %s",
-                                   tvb_get_ephemeral_string(tvb, offset, strlen));
-               offset+= strlen;
-               conn_data->state= RESPONSE_SHOW_FIELDS;
-               break;
+static int
+mysql_dissect_response_prepare(tvbuff_t *tvb, int offset, proto_tree *tree, mysql_conn_data_t *conn_data)
+{
+    /* 0, marker for OK packet */
+    offset += 1;
+    proto_tree_add_item(tree, hf_mysql_stmt_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+    offset += 4;
+    proto_tree_add_item(tree, hf_mysql_num_fields, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+    conn_data->stmt_num_fields = tvb_get_letohs(tvb, offset);
+    offset += 2;
+    proto_tree_add_item(tree, hf_mysql_num_params, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+    conn_data->stmt_num_params = tvb_get_letohs(tvb, offset);
+    offset += 2;
+    /* Filler */
+    offset += 1;
+    proto_tree_add_item(tree, hf_mysql_num_warn, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+
+    if (conn_data->stmt_num_params > 0)
+        conn_data->state = PREPARED_PARAMETERS;
+    else if (conn_data->stmt_num_fields > 0)
+        conn_data->state = PREPARED_FIELDS;
+    else
+        conn_data->state = REQUEST;
 
-       case MYSQL_PROCESS_KILL:
-               proto_tree_add_item(req_tree, hf_mysql_thd_id,
-                                   tvb, offset, 4, TRUE);
-               offset+= 4;
-               conn_data->state= RESPONSE_OK;
-               break;
+       return offset + tvb_reported_length_remaining(tvb, offset);
+}
 
-       case MYSQL_CHANGE_USER:
-               strlen= tvb_strsize(tvb, offset);
-               proto_tree_add_item(req_tree, hf_mysql_user, tvb,
-                                   offset, strlen, FALSE);
-               offset+= strlen;
-
-               strlen= tvb_strsize(tvb, offset);
-               proto_tree_add_item(req_tree, hf_mysql_passwd, tvb,
-                                   offset, strlen, FALSE);
-               offset+= strlen;
-
-               strlen= my_tvb_strsize(tvb, offset);
-               proto_tree_add_item(req_tree, hf_mysql_schema, tvb,
-                                   offset, strlen, FALSE);
-               offset+= strlen;
-               conn_data->state= RESPONSE_OK;
-               break;
 
-       case MYSQL_REFRESH:
-               {
-                       proto_item *tff;
-                       proto_item *rfsh_tree;
-                       gint refresh= tvb_get_guint8(tvb, offset);
-
-                       if (req_tree) {
-                               tff= proto_tree_add_uint_format(req_tree, hf_mysql_refresh, tvb, offset, 1, refresh, "Refresh Bitmap: 0x%02X ", refresh);
-                               rfsh_tree= proto_item_add_subtree(tff, ett_refresh);
-                               proto_tree_add_boolean(rfsh_tree, hf_mysql_rfsh_grants, tvb, offset, 1, refresh);
-                               proto_tree_add_boolean(rfsh_tree, hf_mysql_rfsh_log, tvb, offset, 1, refresh);
-                               proto_tree_add_boolean(rfsh_tree, hf_mysql_rfsh_tables, tvb, offset, 1, refresh);
-                               proto_tree_add_boolean(rfsh_tree, hf_mysql_rfsh_hosts, tvb, offset, 1, refresh);
-                               proto_tree_add_boolean(rfsh_tree, hf_mysql_rfsh_status, tvb, offset, 1, refresh);
-                               proto_tree_add_boolean(rfsh_tree, hf_mysql_rfsh_threads, tvb, offset, 1, refresh);
-                               proto_tree_add_boolean(rfsh_tree, hf_mysql_rfsh_slave, tvb, offset, 1, refresh);
-                               proto_tree_add_boolean(rfsh_tree, hf_mysql_rfsh_master, tvb, offset, 1, refresh);
-                       }
-               }
-               offset+= 1;
-               conn_data->state= RESPONSE_OK;
-               break;
 
-       case MYSQL_SHUTDOWN:
-               opcode= tvb_get_guint8(tvb, offset);
-               proto_tree_add_uint_format(req_tree, hf_mysql_opcode, tvb, offset,
-                                          1, opcode, "Shutdown-Level: %s",
-                                          val_to_str(opcode, mysql_shutdown_vals, "Unknown (%u)"));
-               offset+= 1;
-               conn_data->state= RESPONSE_OK;
-               break;
+/*
+ get length of string in packet buffer
 
-       case MYSQL_SET_OPTION:
-               option= tvb_get_letohs(tvb, offset);
-               proto_tree_add_uint_format(req_tree, hf_mysql_option, tvb, offset,
-                                          2, option, "Option: %s",
-                                          val_to_str(option, mysql_option_vals, "Unknown (%u)"));
-               offset+= 2;
-               conn_data->state= RESPONSE_OK;
-               break;
+ SYNOPSIS
+   my_tvb_strsize()
+     tvb      packet buffer
+     offset   current offset
 
-       case MYSQL_STMT_FETCH:
-               proto_tree_add_item(req_tree, hf_mysql_stmt_id,
-                                   tvb, offset, 4, TRUE);
-               offset+= 4;
+ DESCRIPTION
+   deliver length of string, delimited by either \0 or end of buffer
 
-               proto_tree_add_item(req_tree, hf_mysql_num_rows,
-                                   tvb, offset, 4, TRUE);
-               offset+= 4;
-               conn_data->state= RESPONSE_TABULAR;
-               break;
+ RETURN VALUE
+   length of string found, including \0 (if present)
 
-       case MYSQL_STMT_SEND_LONG_DATA:
-               proto_tree_add_item(req_tree, hf_mysql_stmt_id,
-                                   tvb, offset, 4, TRUE);
-               offset+= 4;
+*/
+static gint
+my_tvb_strsize(tvbuff_t *tvb, int offset)
+{
+       gint len = tvb_strnlen(tvb, offset, -1);
+       if (len == -1) {
+               len = tvb_reported_length_remaining(tvb, offset);
+       } else {
+               len++; /* the trailing \0 */
+       }
+       return len;
+}
 
-               proto_tree_add_item(req_tree, hf_mysql_param,
-                                   tvb, offset, 2, TRUE);
-               offset+= 2;
 
-               /* rest is data */
-               strlen= tvb_reported_length_remaining(tvb, offset);
-               if (tree &&  strlen > 0) {
-                       proto_tree_add_item(req_tree, hf_mysql_payload,
-                                           tvb, offset, strlen, FALSE);
-               }
-               offset+= strlen;
-               conn_data->state= REQUEST;
-               break;
+/*
+ read "field length encoded" value from packet buffer
 
-       case MYSQL_STMT_EXECUTE:
-               proto_tree_add_item(req_tree, hf_mysql_stmt_id,
-                                   tvb, offset, 4, TRUE);
-               offset+= 4;
+ SYNOPSIS
+   tvb_get_fle()
+     tvb     in    packet buffer
+     offset  in    offset in buffer
+     res     out   where to store FLE value, may be NULL
+     is_null out   where to store ISNULL flag, may be NULL
 
-               proto_tree_add_item(req_tree, hf_mysql_exec_flags,
-                                   tvb, offset, 1, TRUE);
-               offset+= 1;
+ DESCRIPTION
+   read FLE from packet buffer and store its value and ISNULL flag
+   in caller provided variables
 
-               proto_tree_add_item(req_tree, hf_mysql_exec_iter,
-                                   tvb, offset, 4, TRUE);
-               offset+= 4;
+ RETURN VALUE
+   length of FLE
+*/
+static int
+tvb_get_fle(tvbuff_t *tvb, int offset, guint64 *res, guint8 *is_null)
+{
+       guint8 prefix;
 
-#if 0
-/* FIXME: rest needs metadata about statement */
-#else
-               strlen= tvb_reported_length_remaining(tvb, offset);
-               if (tree &&  strlen > 0) {
-                       proto_tree_add_string(req_tree, hf_mysql_payload, tvb, offset,
-                                             strlen, "FIXME: execute dissector incomplete");
-               }
-               offset+= strlen;
-#endif
-               conn_data->state= RESPONSE_TABULAR;
-               break;
+       prefix = tvb_get_guint8(tvb, offset);
 
-/* FIXME: implement replication packets */
-       case MYSQL_BINLOG_DUMP:
-       case MYSQL_TABLE_DUMP:
-       case MYSQL_CONNECT_OUT:
-       case MYSQL_REGISTER_SLAVE:
-               proto_tree_add_string(req_tree, hf_mysql_payload, tvb, offset, -1,
-                                     "FIXME: implement replication packets");
-               offset+= tvb_reported_length_remaining(tvb, offset);
-               conn_data->state= REQUEST;
-               break;
+       if (is_null)
+               *is_null = 0;
 
+       switch (prefix) {
+       case 251:
+               if (res)
+                       *res = 0;
+               if (is_null)
+                       *is_null = 1;
+               break;
+       case 252:
+               if (res)
+                       *res = tvb_get_letohs(tvb, offset+1);
+               return 3;
+       case 253:
+               if (res)
+                       *res = tvb_get_letohl(tvb, offset+1);
+               return 5;
+       case 254:
+               if (res)
+                       *res = tvb_get_letoh64(tvb, offset+1);
+               return 9;
        default:
-               proto_tree_add_string(req_tree, hf_mysql_payload, tvb, offset, -1,
-                                     "unknown/invalid command code");
-               offset+= tvb_reported_length_remaining(tvb, offset);
-               conn_data->state= UNDEFINED;
+               if (res)
+                       *res = prefix;
        }
 
-       return offset;
+       return 1;
 }
 
-
-static int
-mysql_dissect_response(tvbuff_t *tvb, packet_info *pinfo, int offset,
-                      proto_tree *tree, mysql_conn_data_t *conn_data)
+/* protocol registration */
+void proto_register_mysql(void)
 {
-       gint response_code;
-       gint strlen;
+       static hf_register_info hf[]=
+       {
+               { &hf_mysql_packet_length,
+               { "Packet Length", "mysql.packet_length",
+               FT_UINT24, BASE_DEC, NULL,  0x0,
+               NULL, HFILL }},
 
-       response_code= tvb_get_guint8(tvb, offset);
+               { &hf_mysql_packet_number,
+               { "Packet Number", "mysql.packet_number",
+               FT_UINT8, BASE_DEC, NULL, 0x0,
+               NULL, HFILL }},
 
-       if (response_code == 0xff ) {
-               offset= mysql_dissect_error_packet(tvb, pinfo, offset+1, tree);
-               conn_data->state= REQUEST;
-       }
+               { &hf_mysql_request,
+               { "Request Command", "mysql.request",
+               FT_NONE, BASE_NONE, NULL, 0x0,
+               NULL, HFILL }},
 
-       else if (response_code == 0xfe && tvb_reported_length_remaining(tvb, offset) < 9) {
+               { &hf_mysql_command,
+               { "Command", "mysql.command",
+               FT_UINT8, BASE_DEC, VALS(mysql_command_vals), 0x0,
+               NULL, HFILL }},
 
-               proto_tree_add_uint_format(tree, hf_mysql_eof, tvb, offset, 1,
-                                          response_code, "EOF marker (%u)",
-                                          response_code);
-               offset+= 1;
+               { &hf_mysql_error_code,
+               { "Error Code", "mysql.error_code",
+               FT_UINT16, BASE_DEC, NULL, 0x0,
+               NULL, HFILL }},
 
-               /* pre-4.1 packet ends here */
-               if (tvb_reported_length_remaining(tvb, offset)) {
-                       proto_tree_add_item(tree, hf_mysql_num_warn,
-                                           tvb, offset, 2, FALSE);
-                       offset= mysql_dissect_server_status(tvb, offset+2, tree);
-               }
+               { &hf_mysql_error_string,
+               { "Error message", "mysql.error.message",
+               FT_STRING, BASE_NONE, NULL, 0x0,
+               "Error string in case of MySQL error message", HFILL }},
 
-               if (conn_data->state == FIELD_PACKET) {
-                       conn_data->state= ROW_PACKET;
-               } else {
-                       conn_data->state= REQUEST;
-               }
-       }
+               { &hf_mysql_sqlstate,
+               { "SQL state", "mysql.sqlstate",
+               FT_STRING, BASE_NONE, NULL, 0x0,
+               NULL, HFILL }},
 
-       else if (response_code == 0) {
-               if (tvb_reported_length_remaining(tvb, offset+1)
-                   > tvb_get_fle(tvb, offset+1, NULL, NULL)) {
-                       offset= mysql_dissect_ok_packet(tvb, pinfo, offset+1,
-                                                       tree, conn_data);
-               } else {
-                       offset= mysql_dissect_result_header(tvb, pinfo, offset,
-                                                           tree, conn_data);
-               }
-       }
+               { &hf_mysql_message,
+               { "Message", "mysql.message",
+               FT_STRINGZ, BASE_NONE, NULL, 0x0,
+               NULL, HFILL }},
 
-       else {
-               switch (conn_data->state) {
-               case RESPONSE_MESSAGE:
-                       if ((strlen= tvb_reported_length_remaining(tvb, offset))) {
-                               proto_tree_add_item(tree, hf_mysql_message, tvb,
-                                                   offset, strlen, FALSE);
-                               offset+= strlen;
-                       }
-                       conn_data->state= REQUEST;
-                       break;
+               { &hf_mysql_server_greeting,
+               { "Server Greeting", "mysql.server_greeting",
+               FT_NONE, BASE_NONE, NULL, 0x0,
+               NULL, HFILL }},
 
-               case RESPONSE_TABULAR:
-                       offset= mysql_dissect_result_header(tvb, pinfo, offset,
-                                                           tree, conn_data);
-                       break;
+               { &hf_mysql_protocol,
+               { "Protocol", "mysql.protocol",
+               FT_UINT8, BASE_DEC, NULL, 0x0,
+               "Protocol Version", HFILL }},
 
-               case FIELD_PACKET:
-               case RESPONSE_SHOW_FIELDS:
-                       offset= mysql_dissect_field_packet(tvb, offset, tree, conn_data);
-                       break;
+               { &hf_mysql_version,
+               { "Version", "mysql.version",
+               FT_STRINGZ, BASE_NONE, NULL, 0x0,
+               "MySQL Version", HFILL }},
 
-               case ROW_PACKET:
-                       offset= mysql_dissect_row_packet(tvb, offset, tree);
-                       break;
+               { &hf_mysql_caps_server,
+               { "Server Capabilities", "mysql.caps.server",
+               FT_UINT16, BASE_HEX, NULL, 0x0,
+               "MySQL Capabilities", HFILL }},
 
-               case RESPONSE_PREPARE:
-                       offset= mysql_dissect_response_prepare(tvb, offset, tree);
-                       break;
+               { &hf_mysql_caps_client,
+               { "Client Capabilities", "mysql.caps.client",
+               FT_UINT16, BASE_HEX, NULL, 0x0,
+               "MySQL Capabilities", HFILL }},
 
-               case PARAM_PACKET:
-                       offset= mysql_dissect_param_packet(tvb, offset, tree);
-                       break;
+               { &hf_mysql_cap_long_password,
+               { "Long Password","mysql.caps.lp",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_LP,
+               NULL, HFILL }},
 
-               default:
-                       proto_tree_add_string(tree, hf_mysql_payload, tvb, offset, -1,
-                                             "unknown/invalid response");
-                       offset+= tvb_reported_length_remaining(tvb, offset);
-                       conn_data->state= UNDEFINED;
-               }
-       }
+               { &hf_mysql_cap_found_rows,
+               { "Found Rows","mysql.caps.fr",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_FR,
+               NULL, HFILL }},
 
-       return offset;
-}
+               { &hf_mysql_cap_long_flag,
+               { "Long Column Flags","mysql.caps.lf",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_LF,
+               NULL, HFILL }},
 
+               { &hf_mysql_cap_connect_with_db,
+               { "Connect With Database","mysql.caps.cd",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_CD,
+               NULL, HFILL }},
 
-static int
-mysql_dissect_error_packet(tvbuff_t *tvb, packet_info *pinfo,
-                          int offset, proto_tree *tree)
-{
-       gint error_code;
-       error_code= tvb_get_letohs(tvb, offset);
+               { &hf_mysql_cap_no_schema,
+               { "Don't Allow database.table.column","mysql.caps.ns",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_NS,
+               NULL, HFILL }},
 
-       if (check_col(pinfo->cinfo, COL_INFO)) {
-               col_append_fstr(pinfo->cinfo, COL_INFO, " Error %d", error_code);
-       }
-       proto_tree_add_uint(tree, hf_mysql_error_code, tvb,
-                           offset, 2, error_code);
-       offset+= 2;
+               { &hf_mysql_cap_compress,
+               { "Can use compression protocol","mysql.caps.cp",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_CP,
+               NULL, HFILL }},
 
-       if (tvb_get_guint8(tvb, offset) == '#')
-       {
-               offset+= 1;
-               proto_tree_add_item(tree, hf_mysql_sqlstate, tvb, offset, 5, FALSE);
-               offset+= 5;
-       }
+               { &hf_mysql_cap_odbc,
+               { "ODBC Client","mysql.caps.ob",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_OB,
+               NULL, HFILL }},
 
-       proto_tree_add_item(tree, hf_mysql_error_string, tvb, offset, -1, FALSE);
-       offset+= tvb_reported_length_remaining(tvb, offset);
+               { &hf_mysql_cap_local_files,
+               { "Can Use LOAD DATA LOCAL","mysql.caps.li",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_LI,
+               NULL, HFILL }},
 
-       return offset;
-}
+               { &hf_mysql_cap_ignore_space,
+               { "Ignore Spaces before '('","mysql.caps.is",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_IS,
+               NULL, HFILL }},
 
+               { &hf_mysql_cap_change_user,
+               { "Speaks 4.1 protocol (new flag)","mysql.caps.cu",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_CU,
+               NULL, HFILL }},
 
-static int
-mysql_dissect_ok_packet(tvbuff_t *tvb, packet_info *pinfo, int offset,
-                       proto_tree *tree, mysql_conn_data_t *conn_data)
-{
-       gint strlen;
-       guint64 affected_rows;
-       guint64 insert_id;
-       int fle;
+               { &hf_mysql_cap_interactive,
+               { "Interactive Client","mysql.caps.ia",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_IA,
+               NULL, HFILL }},
 
-       col_append_str(pinfo->cinfo, COL_INFO, " OK" );
+               { &hf_mysql_cap_ssl,
+               { "Switch to SSL after handshake","mysql.caps.sl",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_SL,
+               NULL, HFILL }},
 
-       fle= tvb_get_fle(tvb, offset, &affected_rows, NULL);
-       proto_tree_add_uint64(tree, hf_mysql_affected_rows,
-                             tvb, offset, fle, affected_rows);
-       offset+= fle;
+               { &hf_mysql_cap_ignore_sigpipe,
+               { "Ignore sigpipes","mysql.caps.ii",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_II,
+               NULL, HFILL }},
 
-       fle= tvb_get_fle(tvb, offset, &insert_id, NULL);
-       if (tree && insert_id) {
-               proto_tree_add_uint64(tree, hf_mysql_insert_id,
-                                     tvb, offset, fle, insert_id);
-       }
-       offset+= fle;
+               { &hf_mysql_cap_transactions,
+               { "Knows about transactions","mysql.caps.ta",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_TA,
+               NULL, HFILL }},
 
-       if ((strlen= tvb_reported_length_remaining(tvb, offset))) {
-               offset= mysql_dissect_server_status(tvb, offset, tree);
+               { &hf_mysql_cap_reserved,
+               { "Speaks 4.1 protocol (old flag)","mysql.caps.rs",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_RS,
+               NULL, HFILL }},
 
-               /* 4.1+ protocol only: 2 bytes number of warnings */
-               if (conn_data->clnt_caps & conn_data->srv_caps & MYSQL_CAPS_CU) {
-                       proto_tree_add_item(tree, hf_mysql_num_warn, tvb,
-                                           offset, 2, FALSE);
-               offset+= 2;
-               }
-       }
+               { &hf_mysql_cap_secure_connect,
+               { "Can do 4.1 authentication","mysql.caps.sc",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_SC,
+               NULL, HFILL }},
 
-       /* optional: message string */
-       if ((strlen= tvb_reported_length_remaining(tvb, offset))) {
-               proto_tree_add_item(tree, hf_mysql_message, tvb,
-                                   offset, strlen, FALSE);
-               offset+= strlen;
-       }
+               { &hf_mysql_extcaps_client,
+               { "Extended Client Capabilities", "mysql.extcaps.client",
+               FT_UINT16, BASE_HEX, NULL, 0x0,
+               "MySQL Extended Capabilities", HFILL }},
 
-       conn_data->state= REQUEST;
-       return offset;
-}
+               { &hf_mysql_cap_multi_statements,
+               { "Supports multiple statements","mysql.caps.ms",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_MS,
+               NULL, HFILL }},
 
+               { &hf_mysql_cap_multi_results,
+               { "Supports multiple results","mysql.caps.mr",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_MR,
+               NULL, HFILL }},
 
-static int
-mysql_dissect_server_status(tvbuff_t *tvb, int offset, proto_tree *tree)
-{
-       guint16 status;
-       proto_item *tf;
-       proto_item *stat_tree;
+               { &hf_mysql_login_request,
+               { "Login Request", "mysql.login_request",
+               FT_NONE, BASE_NONE, NULL,  0x0,
+               NULL, HFILL }},
 
-       status= tvb_get_letohs(tvb, offset);
-       if (tree) {
-               tf= proto_tree_add_uint_format(tree, hf_mysql_status, tvb, offset, 2, status, "Server Status: 0x%04X ", status);
-               stat_tree= proto_item_add_subtree(tf, ett_stat);
-               proto_tree_add_boolean(stat_tree, hf_mysql_stat_it, tvb, offset, 2, status);
-               proto_tree_add_boolean(stat_tree, hf_mysql_stat_ac, tvb, offset, 2, status);
-               proto_tree_add_boolean(stat_tree, hf_mysql_stat_mr, tvb, offset, 2, status);
-               proto_tree_add_boolean(stat_tree, hf_mysql_stat_mu, tvb, offset, 2, status);
-               proto_tree_add_boolean(stat_tree, hf_mysql_stat_bi, tvb, offset, 2, status);
-               proto_tree_add_boolean(stat_tree, hf_mysql_stat_ni, tvb, offset, 2, status);
-               proto_tree_add_boolean(stat_tree, hf_mysql_stat_cr, tvb, offset, 2, status);
-               proto_tree_add_boolean(stat_tree, hf_mysql_stat_lr, tvb, offset, 2, status);
-               proto_tree_add_boolean(stat_tree, hf_mysql_stat_dr, tvb, offset, 2, status);
-               proto_tree_add_boolean(stat_tree, hf_mysql_stat_bs, tvb, offset, 2, status);
-       }
-       offset+= 2;
+               { &hf_mysql_max_packet,
+               { "MAX Packet", "mysql.max_packet",
+               FT_UINT24, BASE_DEC, NULL,  0x0,
+               "MySQL Max packet", HFILL }},
 
-       return offset;
-}
+               { &hf_mysql_charset,
+               { "Charset", "mysql.charset",
+               FT_UINT8, BASE_DEC, VALS(mysql_collation_vals),  0x0,
+               "MySQL Charset", HFILL }},
 
+               { &hf_mysql_table_name,
+               { "Table Name", "mysql.table_name",
+               FT_STRINGZ, BASE_NONE, NULL, 0x0,
+               NULL, HFILL }},
 
-static void
-mysql_dissect_collation(tvbuff_t *tvb, int offset, proto_tree *tree, guint16 caps, gint charset, int field)
-{
-       proto_tree_add_uint_format(tree, field, tvb, offset, 1,
-                                  charset, "Charset: %s (%u)",
-                                  val_to_str(charset,
-                                             caps & MYSQL_CAPS_CU
-                                             ? mysql_collation_vals
-                                             : mysql_charset_vals,
-                                             "Unknown (%u)"), charset);
-}
+               { &hf_mysql_user,
+               { "Username", "mysql.user",
+               FT_STRINGZ, BASE_NONE, NULL, 0x0,
+               "Login Username", HFILL }},
 
+               { &hf_mysql_schema,
+               { "Schema", "mysql.schema",
+               FT_STRING, BASE_NONE, NULL, 0x0,
+               "Login Schema", HFILL }},
 
-static int
-mysql_dissect_caps(tvbuff_t *tvb, int offset, proto_tree *tree,
-                  guint16 *caps, const char* whom)
-{
-       *caps= tvb_get_letohs(tvb, offset);
-       if (tree) {
-               proto_item *tf= proto_tree_add_uint_format(tree, hf_mysql_caps, tvb, offset, 2, *caps,
-                                                          "%s Capabilities: 0x%04X ", whom, *caps);
-               proto_item *cap_tree= proto_item_add_subtree(tf, ett_caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_long_password, tvb, offset, 2, *caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_found_rows, tvb, offset, 2, *caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_long_flag, tvb, offset, 2, *caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_connect_with_db, tvb, offset, 2, *caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_no_schema, tvb, offset, 2, *caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_compress, tvb, offset, 2, *caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_odbc, tvb, offset, 2, *caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_local_files, tvb, offset, 2, *caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_ignore_space, tvb, offset, 2, *caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_change_user, tvb, offset, 2, *caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_interactive, tvb, offset, 2, *caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_ssl, tvb, offset, 2, *caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_ignore_sigpipe, tvb, offset, 2, *caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_transactions, tvb, offset, 2, *caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_reserved, tvb, offset, 2, *caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_secure_connect, tvb, offset, 2, *caps);
-       }
+               { &hf_mysql_salt,
+               { "Salt", "mysql.salt",
+               FT_STRINGZ, BASE_NONE, NULL, 0x0,
+               NULL, HFILL }},
 
-       offset+= 2;
-       return offset;
-}
+               { &hf_mysql_salt2,
+               { "Salt", "mysql.salt2",
+               FT_STRINGZ, BASE_NONE, NULL, 0x0,
+               NULL, HFILL }},
 
+               { &hf_mysql_thread_id,
+               { "Thread ID", "mysql.thread_id",
+               FT_UINT32, BASE_DEC, NULL,  0x0,
+               "MySQL Thread ID", HFILL }},
 
-static int
-mysql_dissect_ext_caps(tvbuff_t *tvb, int offset, proto_tree *tree,
-                      guint16 *caps, const char* whom)
-{
-       proto_item *extcap_tree;
-       *caps= tvb_get_letohs(tvb, offset);
-       if (tree) {
-               proto_item *tf= proto_tree_add_uint_format(tree, hf_mysql_extcaps, tvb, offset, 2, *caps,
-                                                          "Extended %s Capabilities: 0x%04X ", whom, *caps);
-               extcap_tree= proto_item_add_subtree(tf, ett_extcaps);
-               proto_tree_add_boolean(extcap_tree, hf_mysql_cap_multi_statements, tvb, offset, 2, *caps);
-               proto_tree_add_boolean(extcap_tree, hf_mysql_cap_multi_results, tvb, offset, 2, *caps);
-       }
+               { &hf_mysql_server_language,
+               { "Server Language", "mysql.server_language",
+               FT_UINT8, BASE_DEC, VALS(mysql_collation_vals),  0x0,
+               "MySQL Charset", HFILL }},
 
-       offset+= 2;
-       return offset;
-}
+               { &hf_mysql_server_status,
+               { "Server Status", "mysql.server_status",
+               FT_UINT16, BASE_HEX, NULL,  0x0,
+               "MySQL Status", HFILL }},
 
+               { &hf_mysql_stat_it,
+               { "In transaction", "mysql.stat.it",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_IT,
+               NULL, HFILL }},
 
-static int
-mysql_dissect_result_header(tvbuff_t *tvb, packet_info *pinfo, int offset,
-                           proto_tree *tree, mysql_conn_data_t *conn_data)
-{
-       gint fle;
-       guint64 num_fields, extra;
+               { &hf_mysql_stat_ac,
+               { "AUTO_COMMIT", "mysql.stat.ac",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_AC,
+               NULL, HFILL }},
 
-       col_append_str(pinfo->cinfo, COL_INFO, " TABULAR" );
+               { &hf_mysql_stat_mr,
+               { "More results", "mysql.stat.mr",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_MR,
+               NULL, HFILL }},
 
-       fle= tvb_get_fle(tvb, offset, &num_fields, NULL);
-       proto_tree_add_uint64(tree, hf_mysql_num_fields,
-                             tvb, offset, fle, num_fields);
-       offset+= fle;
+               { &hf_mysql_stat_mu,
+               { "Multi query - more resultsets", "mysql.stat.mu",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_MU,
+               NULL, HFILL }},
 
-       if (tvb_reported_length_remaining(tvb, offset)) {
-               fle= tvb_get_fle(tvb, offset, &extra, NULL);
-               proto_tree_add_uint64(tree, hf_mysql_extra,
-                                     tvb, offset, fle, extra);
-               offset+= fle;
-       }
+               { &hf_mysql_stat_bi,
+               { "Bad index used", "mysql.stat.bi",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_BI,
+               NULL, HFILL }},
 
-       if (num_fields) {
-               conn_data->state= FIELD_PACKET;
-       } else {
-               conn_data->state= ROW_PACKET;
-       }
+               { &hf_mysql_stat_ni,
+               { "No index used", "mysql.stat.ni",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_NI,
+               NULL, HFILL }},
 
-       return offset;
-}
+               { &hf_mysql_stat_cr,
+               { "Cursor exists", "mysql.stat.cr",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_CR,
+               NULL, HFILL }},
 
+               { &hf_mysql_stat_lr,
+               { "Last row sebd", "mysql.stat.lr",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_LR,
+               NULL, HFILL }},
 
-/*
- * Add length encoded string to tree
- */
-static int
-mysql_field_add_lestring(tvbuff_t *tvb, int offset, proto_tree *tree, int field)
-{
-       guint64 lelen;
-       guint8 is_null;
+               { &hf_mysql_stat_dr,
+               { "database dropped", "mysql.stat.dr",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_DR,
+               NULL, HFILL }},
 
-       offset += tvb_get_fle(tvb, offset, &lelen, &is_null);
-       if(is_null)
-               proto_tree_add_string(tree, field, tvb, offset, 4, "NULL");
-       else
-       {
-               proto_tree_add_item(tree, field, tvb, offset,
-                                   (int)lelen, FALSE);
-               offset += (int)lelen;
-       }
-       return offset;
-}
+               { &hf_mysql_stat_bs,
+               { "No backslash escapes", "mysql.stat.bs",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_BS,
+               NULL, HFILL }},
 
+               { &hf_mysql_refresh,
+               { "Refresh Option", "mysql.refresh",
+               FT_UINT8, BASE_HEX, NULL,  0x0,
+               NULL, HFILL }},
 
-static int
-mysql_dissect_field_packet(tvbuff_t *tvb, int offset, proto_tree *tree, mysql_conn_data_t *conn_data)
-{
-       guint16 flags;
-       proto_item *tf;
-       proto_item *flags_tree;
+               { &hf_mysql_rfsh_grants,
+               { "reload permissions", "mysql.rfsh.grants",
+               FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_GRANT,
+               NULL, HFILL }},
 
-       offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_catalog);
-       offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_db);
-       offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_table);
-       offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_org_table);
-       offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_name);
-       offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_org_name);
-       offset++; /* filler */
-       mysql_dissect_collation(tvb, offset, tree, conn_data->srv_caps,
-                               tvb_get_letohs(tvb, offset), hf_mysql_fld_charsetnr);
-       offset += 2; /* charset */
-       proto_tree_add_item(tree, hf_mysql_fld_length, tvb, offset, 4, TRUE);
-       offset += 4; /* length */
-       proto_tree_add_item(tree, hf_mysql_fld_type, tvb, offset, 1, FALSE);
-       offset++; /* type */
+               { &hf_mysql_rfsh_log,
+               { "flush logfiles", "mysql.rfsh.log",
+               FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_LOG,
+               NULL, HFILL }},
 
-       flags = tvb_get_letohs(tvb, offset);
-       tf = proto_tree_add_uint_format(tree, hf_mysql_fld_flags, tvb, offset,
-                                       2, flags, "Field flags: 0x%04X", flags);
-       flags_tree = proto_item_add_subtree(tf, ett_field_flags);
-       proto_tree_add_boolean(flags_tree, hf_mysql_fld_not_null, tvb, offset, 2, flags);
-       proto_tree_add_boolean(flags_tree, hf_mysql_fld_primary_key, tvb, offset, 2, flags);
-       proto_tree_add_boolean(flags_tree, hf_mysql_fld_unique_key, tvb, offset, 2, flags);
-       proto_tree_add_boolean(flags_tree, hf_mysql_fld_multiple_key, tvb, offset, 2, flags);
-       proto_tree_add_boolean(flags_tree, hf_mysql_fld_blob, tvb, offset, 2, flags);
-       proto_tree_add_boolean(flags_tree, hf_mysql_fld_unsigned, tvb, offset, 2, flags);
-       proto_tree_add_boolean(flags_tree, hf_mysql_fld_zero_fill, tvb, offset, 2, flags);
-       proto_tree_add_boolean(flags_tree, hf_mysql_fld_binary, tvb, offset, 2, flags);
-       proto_tree_add_boolean(flags_tree, hf_mysql_fld_enum, tvb, offset, 2, flags);
-       proto_tree_add_boolean(flags_tree, hf_mysql_fld_auto_increment, tvb, offset, 2, flags);
-       proto_tree_add_boolean(flags_tree, hf_mysql_fld_timestamp, tvb, offset, 2, flags);
-       proto_tree_add_boolean(flags_tree, hf_mysql_fld_set, tvb, offset, 2, flags);
-       offset += 2; /* flags */
+               { &hf_mysql_rfsh_tables,
+               { "flush tables", "mysql.rfsh.tables",
+               FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_TABLES,
+               NULL, HFILL }},
 
-       proto_tree_add_item(tree, hf_mysql_fld_decimals, tvb, offset, 1, FALSE);
-       offset++; /* decimals */
+               { &hf_mysql_rfsh_hosts,
+               { "flush hosts", "mysql.rfsh.hosts",
+               FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_HOSTS,
+               NULL, HFILL }},
 
-       offset += 2; /* filler */
+               { &hf_mysql_rfsh_status,
+               { "reset statistics", "mysql.rfsh.status",
+               FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_STATUS,
+               NULL, HFILL }},
 
-       /* default (Only use for show fields) */
-       if (tree && tvb_reported_length_remaining(tvb, offset) > 0) {
-               offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_default);
-       }
-       return offset;
-}
+               { &hf_mysql_rfsh_threads,
+               { "empty thread cache", "mysql.rfsh.threads",
+               FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_THREADS,
+               NULL, HFILL }},
 
+               { &hf_mysql_rfsh_slave,
+               { "flush slave status", "mysql.rfsh.slave",
+               FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_SLAVE,
+               NULL, HFILL }},
 
-static int
-mysql_dissect_row_packet(tvbuff_t *tvb, int offset, proto_tree *tree)
-{
-       while (tvb_reported_length_remaining(tvb, offset) > 0)  {
-               offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_row_text);
-       }
+               { &hf_mysql_rfsh_master,
+               { "flush master status", "mysql.rfsh.master",
+               FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_MASTER,
+               NULL, HFILL }},
 
-       return offset;
-}
+               { &hf_mysql_unused,
+               { "Unused", "mysql.unused",
+               FT_STRING, BASE_NONE, NULL, 0x0,
+               NULL, HFILL }},
 
+               { &hf_mysql_passwd,
+               { "Password", "mysql.passwd",
+               FT_BYTES, BASE_NONE, NULL, 0x0,
+               NULL, HFILL }},
 
-static int
-mysql_dissect_response_prepare(tvbuff_t *tvb, int offset, proto_tree *tree)
-{
-       proto_tree_add_text(tree, tvb, offset, -1, "FIXME: write mysql_dissect_response_prepare()");
-       return offset + tvb_reported_length_remaining(tvb, offset);
-}
+               { &hf_mysql_payload,
+               { "Payload", "mysql.payload",
+               FT_BYTES, BASE_NONE, NULL, 0x0,
+               "Additional Payload", HFILL }},
 
+               { &hf_mysql_affected_rows,
+               { "Affected Rows", "mysql.affected_rows",
+               FT_UINT64, BASE_DEC, NULL, 0x0,
+               NULL, HFILL }},
 
-static int
-mysql_dissect_param_packet(tvbuff_t *tvb, int offset, proto_tree *tree)
-{
-       proto_tree_add_text(tree, tvb, offset, -1, "FIXME: write mysql_dissect_param_packet()");
-       return offset + tvb_reported_length_remaining(tvb, offset);
-}
+               { &hf_mysql_insert_id,
+               { "Last INSERT ID", "mysql.insert_id",
+               FT_UINT64, BASE_DEC, NULL, 0x0,
+               NULL, HFILL }},
 
+               { &hf_mysql_num_warn,
+               { "Warnings", "mysql.warnings",
+               FT_UINT16, BASE_DEC, NULL, 0x0,
+               NULL, HFILL }},
 
+               { &hf_mysql_thd_id,
+               { "Thread ID", "mysql.thd_id",
+               FT_UINT32, BASE_DEC, NULL, 0x0,
+               NULL, HFILL }},
 
-/*
- get length of string in packet buffer
+               { &hf_mysql_stmt_id,
+               { "Statement ID", "mysql.stmt_id",
+               FT_UINT32, BASE_DEC, NULL, 0x0,
+               NULL, HFILL }},
 
- SYNOPSIS
-   my_tvb_strsize()
-     tvb      packet buffer
-     offset   current offset
+               { &hf_mysql_query,
+               { "Statement", "mysql.query",
+               FT_STRING, BASE_NONE, NULL, 0x0,
+               NULL, HFILL }},
 
- DESCRIPTION
-   deliver length of string, delimited by either \0 or end of buffer
+               { &hf_mysql_shutdown,
+               { "Shutdown Level", "mysql.shutdown",
+               FT_UINT8, BASE_DEC, VALS(mysql_shutdown_vals), 0x0,
+               NULL, HFILL }},
 
- RETURN VALUE
-   length of string found, including \0 (if present)
+               { &hf_mysql_option,
+               { "Option", "mysql.option",
+               FT_UINT16, BASE_DEC, VALS(mysql_option_vals), 0x0,
+               NULL, HFILL }},
 
-*/
-static gint
-my_tvb_strsize(tvbuff_t *tvb, int offset)
-{
-       gint len = tvb_strnlen(tvb, offset, -1);
-       if (len == -1) {
-               len = tvb_reported_length_remaining(tvb, offset);
-       } else {
-               len++; /* the trailing \0 */
-       }
-       return len;
-}
+               { &hf_mysql_param,
+               { "Parameter", "mysql.param",
+               FT_UINT16, BASE_DEC, NULL, 0x0,
+               NULL, HFILL }},
 
+               { &hf_mysql_num_params,
+               { "Number of parameter", "mysql.num_params",
+               FT_UINT16, BASE_DEC, NULL, 0x0,
+               NULL, HFILL }},
 
-/*
- read "field length encoded" value from packet buffer
+               { &hf_mysql_num_rows,
+               { "Rows to fetch", "mysql.num_rows",
+               FT_UINT32, BASE_DEC, NULL, 0x0,
+               NULL, HFILL }},
 
- SYNOPSIS
-   tvb_get_fle()
-     tvb     in    packet buffer
-     offset  in    offset in buffer
-     res     out   where to store FLE value, may be NULL
-     is_null out   where to store ISNULL flag, may be NULL
+               { &hf_mysql_exec_flags4,
+               { "Flags (unused)", "mysql.exec_flags",
+               FT_UINT8, BASE_DEC, NULL, 0x0,
+               NULL, HFILL }},
 
- DESCRIPTION
-   read FLE from packet buffer and store its value and ISNULL flag
-   in caller provided variables
+               { &hf_mysql_exec_flags5,
+               { "Flags", "mysql.exec_flags",
+               FT_UINT8, BASE_DEC, VALS(mysql_exec_flags_vals), 0x0,
+               NULL, HFILL }},
 
- RETURN VALUE
-   length of FLE
-*/
-static int
-tvb_get_fle(tvbuff_t *tvb, int offset, guint64 *res, guint8 *is_null)
-{
-       guint8 prefix= tvb_get_guint8(tvb, offset);
+               { &hf_mysql_exec_iter,
+               { "Iterations (unused)", "mysql.exec_iter",
+               FT_UINT32, BASE_DEC, NULL, 0x0,
+               NULL, HFILL }},
 
-       if (is_null)
-               *is_null= 0;
+               { &hf_mysql_binlog_position,
+               { "Binlog Position", "mysql.binlog.position",
+               FT_UINT32, BASE_DEC, NULL, 0x0,
+               "Position to start at", HFILL }},
 
-       switch (prefix) {
-       case 251:
-               if (res)
-                       *res= 0;
-               if (is_null)
-                       *is_null= 1;
-               break;
-       case 252:
-               if (res)
-                       *res= tvb_get_letohs(tvb, offset+1);
-               return 3;
-       case 253:
-               if (res)
-                       *res= tvb_get_letohl(tvb, offset+1);
-               return 5;
-       case 254:
-               if (res)
-                       *res= tvb_get_letoh64(tvb, offset+1);
-               return 9;
-       default:
-               if (res)
-                       *res= prefix;
-       }
+               { &hf_mysql_binlog_flags,
+               { "Binlog Flags", "mysql.binlog.flags",
+               FT_UINT16, BASE_HEX, NULL, 0x0,
+               "(currently not used; always 0)", HFILL }},
 
-       return 1;
+               { &hf_mysql_binlog_server_id,
+               { "Binlog server id", "mysql.binlog.server_id",
+               FT_UINT16, BASE_HEX, NULL, 0x0,
+               "server_id of the slave", HFILL }},
+
+               { &hf_mysql_binlog_file_name,
+               { "Binlog file name", "mysql.binlog.file_name",
+               FT_STRINGZ, BASE_NONE, NULL, 0x0,
+               NULL, HFILL }},
+
+               { &hf_mysql_eof,
+               { "EOF marker", "mysql.eof",
+               FT_UINT8, BASE_DEC, NULL,  0x0,
+               NULL, HFILL }},
+
+               { &hf_mysql_num_fields,
+               { "Number of fields", "mysql.num_fields",
+               FT_UINT64, BASE_DEC, NULL,  0x0,
+               NULL, HFILL }},
+
+               { &hf_mysql_extra,
+               { "Extra data", "mysql.extra",
+               FT_UINT64, BASE_DEC, NULL,  0x0,
+               NULL, HFILL }},
+
+               { &hf_mysql_fld_catalog,
+               { "Catalog", "mysql.field.catalog",
+               FT_STRING, BASE_NONE, NULL, 0x0,
+               "Field: catalog", HFILL }},
+
+               { &hf_mysql_fld_db,
+               { "Database", "mysql.field.db",
+               FT_STRING, BASE_NONE, NULL, 0x0,
+               "Field: database", HFILL }},
+
+               { &hf_mysql_fld_table,
+               { "Table", "mysql.field.table",
+               FT_STRING, BASE_NONE, NULL, 0x0,
+               "Field: table", HFILL }},
+
+               { &hf_mysql_fld_org_table,
+               { "Original table", "mysql.field.org_table",
+               FT_STRING, BASE_NONE, NULL, 0x0,
+               "Field: original table", HFILL }},
+
+               { &hf_mysql_fld_name,
+               { "Name", "mysql.field.name",
+               FT_STRING, BASE_NONE, NULL, 0x0,
+               "Field: name", HFILL }},
+
+               { &hf_mysql_fld_org_name,
+               { "Original name", "mysql.field.org_name",
+               FT_STRING, BASE_NONE, NULL, 0x0,
+               "Field: original name", HFILL }},
+
+               { &hf_mysql_fld_charsetnr,
+               { "Charset number", "mysql.field.charsetnr",
+               FT_UINT16, BASE_DEC, VALS(mysql_collation_vals), 0x0,
+               "Field: charset number", HFILL }},
+
+               { &hf_mysql_fld_length,
+               { "Length", "mysql.field.length",
+               FT_UINT32, BASE_DEC, NULL, 0x0,
+               "Field: length", HFILL }},
+
+               { &hf_mysql_fld_type,
+               { "Type", "mysql.field.type",
+               FT_UINT8, BASE_DEC, VALS(type_constants), 0x0,
+               "Field: type", HFILL }},
+
+               { &hf_mysql_fld_flags,
+               { "Flags", "mysql.field.flags",
+               FT_UINT16, BASE_HEX, NULL, 0x0,
+               "Field: flags", HFILL }},
+
+               { &hf_mysql_fld_not_null,
+               { "Not null", "mysql.field.flags.not_null",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_NOT_NULL_FLAG,
+               "Field: flag not null", HFILL }},
+
+               { &hf_mysql_fld_primary_key,
+               { "Primary key", "mysql.field.flags.primary_key",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_PRI_KEY_FLAG,
+               "Field: flag primary key", HFILL }},
+
+               { &hf_mysql_fld_unique_key,
+               { "Unique key", "mysql.field.flags.unique_key",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_UNIQUE_KEY_FLAG,
+               "Field: flag unique key", HFILL }},
+
+               { &hf_mysql_fld_multiple_key,
+               { "Multiple key", "mysql.field.flags.multiple_key",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_MULTIPLE_KEY_FLAG,
+               "Field: flag multiple key", HFILL }},
+
+               { &hf_mysql_fld_blob,
+               { "Blob", "mysql.field.flags.blob",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_BLOB_FLAG,
+               "Field: flag blob", HFILL }},
+
+               { &hf_mysql_fld_unsigned,
+               { "Unsigned", "mysql.field.flags.unsigned",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_UNSIGNED_FLAG,
+               "Field: flag unsigned", HFILL }},
+
+               { &hf_mysql_fld_zero_fill,
+               { "Zero fill", "mysql.field.flags.zero_fill",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_ZEROFILL_FLAG,
+               "Field: flag zero fill", HFILL }},
+
+               { &hf_mysql_fld_binary,
+               { "Binary", "mysql.field.flags.binary",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_BINARY_FLAG,
+               "Field: flag binary", HFILL }},
+
+               { &hf_mysql_fld_enum,
+               { "Enum", "mysql.field.flags.enum",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_ENUM_FLAG,
+               "Field: flag enum", HFILL }},
+
+               { &hf_mysql_fld_auto_increment,
+               { "Auto increment", "mysql.field.flags.auto_increment",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_AUTO_INCREMENT_FLAG,
+               "Field: flag auto increment", HFILL }},
+
+               { &hf_mysql_fld_timestamp,
+               { "Timestamp", "mysql.field.flags.timestamp",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_TIMESTAMP_FLAG,
+               "Field: flag timestamp", HFILL }},
+
+               { &hf_mysql_fld_set,
+               { "Set", "mysql.field.flags.set",
+               FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_SET_FLAG,
+               "Field: flag set", HFILL }},
+
+               { &hf_mysql_fld_decimals,
+               { "Decimals", "mysql.field.decimals",
+               FT_UINT8, BASE_DEC, NULL, 0x0,
+               "Field: decimals", HFILL }},
+
+               { &hf_mysql_fld_default,
+               { "Default", "mysql.field.default",
+               FT_STRING, BASE_NONE, NULL, 0x0,
+               "Field: default", HFILL }},
+
+               { &hf_mysql_row_text,
+               { "text", "mysql.row.text",
+               FT_STRING, BASE_NONE, NULL, 0x0,
+               "Field: row packet text", HFILL }},
+       };
+
+       static gint *ett[]=
+       {
+               &ett_mysql,
+               &ett_server_greeting,
+               &ett_login_request,
+               &ett_caps,
+               &ett_extcaps,
+               &ett_stat,
+               &ett_request,
+               &ett_refresh,
+               &ett_field_flags
+       };
+
+       module_t *mysql_module;
+
+       proto_mysql = proto_register_protocol("MySQL Protocol", "MySQL", "mysql");
+       proto_register_field_array(proto_mysql, hf, array_length(hf));
+       proto_register_subtree_array(ett, array_length(ett));
+
+       mysql_module = prefs_register_protocol(proto_mysql, NULL);
+       prefs_register_bool_preference(mysql_module, "desegment_buffers",
+                                      "Reassemble MySQL buffers spanning multiple TCP segments",
+                                      "Whether the MySQL dissector should reassemble MySQL buffers spanning multiple TCP segments."
+                                      " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
+                                      &mysql_desegment);
+       prefs_register_bool_preference(mysql_module, "show_sql_query",
+                                      "Show SQL Query string in INFO column",
+                                      "Whether the MySQL dissector should display the SQL query string in the INFO column.",
+                                      &mysql_showquery);
+
+        register_dissector("mysql", dissect_mysql_pdu, proto_mysql);
+}
+
+/* dissector registration */
+void proto_reg_handoff_mysql(void)
+{
+       dissector_handle_t mysql_handle;
+       mysql_handle = create_dissector_handle(dissect_mysql, proto_mysql);
+       dissector_add_uint("tcp.port", TCP_PORT_MySQL, mysql_handle);
 }
+