From Axel Schwenke:
authoretxrab <etxrab@f5534014-38df-0310-8fa8-9805f1628bb7>
Tue, 16 May 2006 19:07:48 +0000 (19:07 +0000)
committeretxrab <etxrab@f5534014-38df-0310-8fa8-9805f1628bb7>
Tue, 16 May 2006 19:07:48 +0000 (19:07 +0000)
- complete dissector for greeting/login packets
- nearly complete dissector for requests, except:
  + parameters for COM_EXECUTE
  + requests from replication slave
- added some features to response dissectors

git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@18174 f5534014-38df-0310-8fa8-9805f1628bb7

epan/dissectors/packet-mysql.c

index 386f4e2cbe4c54261239d33c5b96a091951b8ed6..f54a7a71ef841b55e03a0fb3d072407dda713bb4 100644 (file)
@@ -3,6 +3,8 @@
  *
  * Huagang XIE <huagang@intruvert.com>
  *
+ * MySQL 4.1+ protocol by Axel Schwenke <axel@mysql.com>
+ *
  * $Id$
  *
  * Ethereal - Network traffic analyzer
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  *
  *
- * the protocol spec at 
- *     http://public.logicacmg.com/~redferni/mysql/MySQL-Protocol.html
- * and MySQL source code  
+ * the protocol spec at
+ *  http://public.logicacmg.com/~redferni/mysql/MySQL-Protocol.html
+ * and MySQL source code
  */
 
+/* create extra output for conversation tracking */
+/* #define CTDEBUG 1 */
+
 #ifdef HAVE_CONFIG_H
 # include "config.h"
 #endif
 #include <epan/conversation.h>
 #include <epan/emem.h>
 
-#include "packet-tcp.h"
+#include <epan/dissectors/packet-tcp.h>
 #include <epan/reassemble.h>
 #include <epan/prefs.h>
 
-/* Capabilities */
+/* Define version if we are not building ethereal statically */
+#ifndef ENABLE_STATIC
+#include <gmodule.h>
+G_MODULE_EXPORT const gchar version[] = "0.1";
+#endif
+
+
+/* port for protocol registration */
+#define TCP_PORT_MySQL   3306
+
+/* client/server capabilities */
 #define MYSQL_CAPS_LP 0x0001
 #define MYSQL_CAPS_FR 0x0002
 #define MYSQL_CAPS_LF 0x0004
 #define MYSQL_CAPS_SL 0x0800
 #define MYSQL_CAPS_II 0x1000
 #define MYSQL_CAPS_TA 0x2000
+#define MYSQL_CAPS_RS 0x4000
+#define MYSQL_CAPS_SC 0x8000
+
+/* extended capabilities: 4.1+ client only */
+#define MYSQL_CAPS_MS 0x0001
+#define MYSQL_CAPS_MR 0x0002
+
+/* status bitfield */
+#define MYSQL_STAT_IT 0x0001
+#define MYSQL_STAT_AC 0x0002
+#define MYSQL_STAT_MR 0x0004
+#define MYSQL_STAT_MU 0x0008
+#define MYSQL_STAT_BI 0x0010
+#define MYSQL_STAT_NI 0x0020
+#define MYSQL_STAT_CR 0x0040
+#define MYSQL_STAT_LR 0x0080
+#define MYSQL_STAT_DR 0x0100
+#define MYSQL_STAT_BS 0x0200
+
+/* bitfield for MYSQL_REFRESH */
+#define MYSQL_RFSH_GRANT   1   /* Refresh grant tables */
+#define MYSQL_RFSH_LOG     2   /* Start on new log file */
+#define MYSQL_RFSH_TABLES  4   /* close all tables */
+#define MYSQL_RFSH_HOSTS   8   /* Flush host cache */
+#define MYSQL_RFSH_STATUS  16  /* Flush status variables */
+#define MYSQL_RFSH_THREADS 32  /* Flush thread cache */
+#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 */
+#define MYSQL_SLEEP               0  /* not from client */
+#define MYSQL_QUIT                1
+#define MYSQL_INIT_DB             2
+#define MYSQL_QUERY               3
+#define MYSQL_FIELD_LIST          4
+#define MYSQL_CREATE_DB           5
+#define MYSQL_DROP_DB             6
+#define MYSQL_REFRESH             7
+#define MYSQL_SHUTDOWN            8
+#define MYSQL_STATISTICS          9
+#define MYSQL_PROCESS_INFO        10
+#define MYSQL_CONNECT             11 /* not from client */
+#define MYSQL_PROCESS_KILL        12
+#define MYSQL_DEBUG               13
+#define MYSQL_PING                14
+#define MYSQL_TIME                15 /* not from client */
+#define MYSQL_DELAY_INSERT        16 /* not from client */
+#define MYSQL_CHANGE_USER         17
+#define MYSQL_BINLOG_DUMP         18 /* replication */
+#define MYSQL_TABLE_DUMP          19 /* replication */
+#define MYSQL_CONNECT_OUT         20 /* replication */
+#define MYSQL_REGISTER_SLAVE      21 /* replication */
+#define MYSQL_STMT_PREPARE        22
+#define MYSQL_STMT_EXECUTE        23
+#define MYSQL_STMT_SEND_LONG_DATA 24
+#define MYSQL_STMT_CLOSE          25
+#define MYSQL_STMT_RESET          26
+#define MYSQL_SET_OPTION          27
+#define MYSQL_STMT_FETCH          28
+
+
+/* decoding table: opcodes */
+static const value_string mysql_opcode_vals[] = {
+       {MYSQL_SLEEP,   "SLEEP"},
+       {MYSQL_QUIT,   "Quit"},
+       {MYSQL_INIT_DB,  "Use Database"},
+       {MYSQL_QUERY,   "Query"},
+       {MYSQL_FIELD_LIST, "Show Fields"},
+       {MYSQL_CREATE_DB,  "Create Database"},
+       {MYSQL_DROP_DB , "Drop Database"},
+       {MYSQL_REFRESH , "Refresh"},
+       {MYSQL_SHUTDOWN , "Shutdown"},
+       {MYSQL_STATISTICS , "Statistics"},
+       {MYSQL_PROCESS_INFO , "Process List"},
+       {MYSQL_CONNECT , "Connect"},
+       {MYSQL_PROCESS_KILL , "Kill Server Thread"},
+       {MYSQL_DEBUG , "Dump Debuginfo"},
+       {MYSQL_PING , "Ping"},
+       {MYSQL_TIME , "Time"},
+       {MYSQL_DELAY_INSERT , "Insert Delayed"},
+       {MYSQL_CHANGE_USER , "Change User"},
+       {MYSQL_BINLOG_DUMP , "Send Binlog"},
+       {MYSQL_TABLE_DUMP, "Send Table"},
+       {MYSQL_CONNECT_OUT, "Slave Connect"},
+       {MYSQL_REGISTER_SLAVE, "Register Slave"},
+       {MYSQL_STMT_PREPARE, "Prepare Statement"},
+       {MYSQL_STMT_EXECUTE, "Execute Statement"},
+       {MYSQL_STMT_SEND_LONG_DATA, "Send BLOB"},
+       {MYSQL_STMT_CLOSE, "Close Statement"},
+       {MYSQL_STMT_RESET, "Reset Statement"},
+       {MYSQL_SET_OPTION, "Set Option"},
+       {MYSQL_STMT_FETCH, "Fetch Data"},
+       {0, NULL}
+};
+
+
+/* charset: pre-4.1 used ther term 'charset', later changed to 'collation' */
+static const value_string mysql_charset_vals[] = {
+       {1,  "big5"},
+       {2,  "czech"},
+       {3,  "dec8"},
+       {4,  "dos" },
+       {5,  "german1"},
+       {6,  "hp8"},
+       {7,  "koi8_ru"},
+       {8,  "latin1"},
+       {9,  "latin2"},
+       {9,  "swe7 "},
+       {10, "usa7"},
+       {11, "ujis"},
+       {12, "sjis"},
+       {13, "cp1251"},
+       {14, "danish"},
+       {15, "hebrew"},
+       {16, "win1251"},
+       {17, "tis620"},
+       {18, "euc_kr"},
+       {19, "estonia"},
+       {20, "hungarian"},
+       {21, "koi8_ukr"},
+       {22, "win1251ukr"},
+       {23, "gb2312"},
+       {24, "greek"},
+       {25, "win1250"},
+       {26, "croat"},
+       {27, "gbk"},
+       {28, "cp1257"},
+       {29, "latin5"},
+       {0, NULL}
+};
+
+
+/* collation codes may change over time, recreate with the following SQL
+
+SELECT CONCAT('  {', ID, ',"', CHARACTER_SET_NAME,
+              ' COLLATE ', COLLATION_NAME, '"},')
+FROM INFORMATION_SCHEMA.COLLATIONS
+ORDER BY ID
+INTO OUTFILE '/tmp/mysql-collations';
+
+*/
+static const value_string mysql_collation_vals[] = {
+       {3,   "dec8 COLLATE dec8_swedish_ci"},
+       {4,   "cp850 COLLATE cp850_general_ci"},
+       {5,   "latin1 COLLATE latin1_german1_ci"},
+       {6,   "hp8 COLLATE hp8_english_ci"},
+       {7,   "koi8r COLLATE koi8r_general_ci"},
+       {8,   "latin1 COLLATE latin1_swedish_ci"},
+       {9,   "latin2 COLLATE latin2_general_ci"},
+       {10,  "swe7 COLLATE swe7_swedish_ci"},
+       {11,  "ascii COLLATE ascii_general_ci"},
+       {14,  "cp1251 COLLATE cp1251_bulgarian_ci"},
+       {15,  "latin1 COLLATE latin1_danish_ci"},
+       {16,  "hebrew COLLATE hebrew_general_ci"},
+       {20,  "latin7 COLLATE latin7_estonian_cs"},
+       {21,  "latin2 COLLATE latin2_hungarian_ci"},
+       {22,  "koi8u COLLATE koi8u_general_ci"},
+       {23,  "cp1251 COLLATE cp1251_ukrainian_ci"},
+       {25,  "greek COLLATE greek_general_ci"},
+       {26,  "cp1250 COLLATE cp1250_general_ci"},
+       {27,  "latin2 COLLATE latin2_croatian_ci"},
+       {29,  "cp1257 COLLATE cp1257_lithuanian_ci"},
+       {30,  "latin5 COLLATE latin5_turkish_ci"},
+       {31,  "latin1 COLLATE latin1_german2_ci"},
+       {32,  "armscii8 COLLATE armscii8_general_ci"},
+       {33,  "utf8 COLLATE utf8_general_ci"},
+       {36,  "cp866 COLLATE cp866_general_ci"},
+       {37,  "keybcs2 COLLATE keybcs2_general_ci"},
+       {38,  "macce COLLATE macce_general_ci"},
+       {39,  "macroman COLLATE macroman_general_ci"},
+       {40,  "cp852 COLLATE cp852_general_ci"},
+       {41,  "latin7 COLLATE latin7_general_ci"},
+       {42,  "latin7 COLLATE latin7_general_cs"},
+       {43,  "macce COLLATE macce_bin"},
+       {44,  "cp1250 COLLATE cp1250_croatian_ci"},
+       {47,  "latin1 COLLATE latin1_bin"},
+       {48,  "latin1 COLLATE latin1_general_ci"},
+       {49,  "latin1 COLLATE latin1_general_cs"},
+       {50,  "cp1251 COLLATE cp1251_bin"},
+       {51,  "cp1251 COLLATE cp1251_general_ci"},
+       {52,  "cp1251 COLLATE cp1251_general_cs"},
+       {53,  "macroman COLLATE macroman_bin"},
+       {57,  "cp1256 COLLATE cp1256_general_ci"},
+       {58,  "cp1257 COLLATE cp1257_bin"},
+       {59,  "cp1257 COLLATE cp1257_general_ci"},
+       {63,  "binary COLLATE binary"},
+       {64,  "armscii8 COLLATE armscii8_bin"},
+       {65,  "ascii COLLATE ascii_bin"},
+       {66,  "cp1250 COLLATE cp1250_bin"},
+       {67,  "cp1256 COLLATE cp1256_bin"},
+       {68,  "cp866 COLLATE cp866_bin"},
+       {69,  "dec8 COLLATE dec8_bin"},
+       {70,  "greek COLLATE greek_bin"},
+       {71,  "hebrew COLLATE hebrew_bin"},
+       {72,  "hp8 COLLATE hp8_bin"},
+       {73,  "keybcs2 COLLATE keybcs2_bin"},
+       {74,  "koi8r COLLATE koi8r_bin"},
+       {75,  "koi8u COLLATE koi8u_bin"},
+       {77,  "latin2 COLLATE latin2_bin"},
+       {78,  "latin5 COLLATE latin5_bin"},
+       {79,  "latin7 COLLATE latin7_bin"},
+       {80,  "cp850 COLLATE cp850_bin"},
+       {81,  "cp852 COLLATE cp852_bin"},
+       {82,  "swe7 COLLATE swe7_bin"},
+       {83,  "utf8 COLLATE utf8_bin"},
+       {92,  "geostd8 COLLATE geostd8_general_ci"},
+       {93,  "geostd8 COLLATE geostd8_bin"},
+       {94,  "latin1 COLLATE latin1_spanish_ci"},
+       {99,  "cp1250 COLLATE cp1250_polish_ci"},
+       {192, "utf8 COLLATE utf8_unicode_ci"},
+       {193, "utf8 COLLATE utf8_icelandic_ci"},
+       {194, "utf8 COLLATE utf8_latvian_ci"},
+       {195, "utf8 COLLATE utf8_romanian_ci"},
+       {196, "utf8 COLLATE utf8_slovenian_ci"},
+       {197, "utf8 COLLATE utf8_polish_ci"},
+       {198, "utf8 COLLATE utf8_estonian_ci"},
+       {199, "utf8 COLLATE utf8_spanish_ci"},
+       {200, "utf8 COLLATE utf8_swedish_ci"},
+       {201, "utf8 COLLATE utf8_turkish_ci"},
+       {202, "utf8 COLLATE utf8_czech_ci"},
+       {203, "utf8 COLLATE utf8_danish_ci"},
+       {204, "utf8 COLLATE utf8_lithuanian_ci"},
+       {205, "utf8 COLLATE utf8_slovak_ci"},
+       {206, "utf8 COLLATE utf8_spanish2_ci"},
+       {207, "utf8 COLLATE utf8_roman_ci"},
+       {208, "utf8 COLLATE utf8_persian_ci"},
+       {209, "utf8 COLLATE utf8_esperanto_ci"},
+       {210, "utf8 COLLATE utf8_hungarian_ci"},
+       {0, NULL}
+};
+
+
+/* allowed MYSQL_SHUTDOWN levels */
+static const value_string mysql_shutdown_vals[] = {
+       {0,   "default"},
+       {1,   "wait for connections to finish"},
+       {2,   "wait for transactions to finish"},
+       {8,   "wait for updates to finish"},
+       {16,  "wait flush all buffers"},
+       {17,  "wait flush critical buffers"},
+       {254, "kill running queries"},
+       {255, "kill connections"},
+       {0, NULL}
+};
+
+
+/* allowed MYSQL_SET_OPTION values */
+static const value_string mysql_option_vals[] = {
+       {0, "multi statements on"},
+       {1, "multi statements off"},
+       {0, NULL}
+};
 
+
+
+/* protocol id */
 static int proto_mysql = -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_payload= -1;
-static int hf_mysql_protocol= -1;
+
+/* dissector configuration */
+static gboolean mysql_desegment = TRUE;
+
+/* expand-the-tree flags */
+static gint ett_mysql = -1;
+static gint ett_server_greeting = -1;
+static gint ett_caps = -1;
+static gint ett_extcaps = -1;
+static gint ett_stat = -1;
+static gint ett_request = -1;
+static gint ett_refresh = -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;
@@ -82,771 +360,1618 @@ 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_password= -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_status= -1;
+static int hf_mysql_passwd= -1;
 static int hf_mysql_unused= -1;
 static int hf_mysql_parameter= -1;
-static int hf_mysql_error_code= -1;
-static int hf_mysql_error_string= -1;
-static int hf_mysql_sqlstate= -1;
-
-static gint ett_mysql = -1;
-static gint ett_server_greeting = -1;
-static gint ett_caps = -1;
-static gint ett_request = -1;
-
-static gboolean mysql_desegment = TRUE;
-
-#define TCP_PORT_MySQL   3306 
-
-#define        MySQL_SLEEP             0
-#define        MySQL_QUIT              1
-#define        MySQL_INIT_DB           2
-#define        MySQL_QUERY             3
-#define        MySQL_FIELD_LIST        4
-#define        MySQL_CREATE_DB         5
-#define        MySQL_DROP_DB           6
-#define MySQL_REFRESH          7
-#define MySQL_SHUTDOWN         8
-#define MySQL_STATISTICS       9
-#define MySQL_PROCESS_INFO     10
-#define MySQL_CONNECT          11
-#define MySQL_PROCESS_KILL     12
-#define MySQL_DEBUG            13
-#define MySQL_PING             14
-#define MySQL_TIME             15
-#define MySQL_DELAY_INSERT     16
-#define MySQL_CHANGE_USER      17
-#define MySQL_BINLOG_DUMP      18
-#define MySQL_TABLE_DUMP       19
-#define MySQL_CONNECT_OUT      20
-
-
-static const value_string mysql_opcode_vals[] = {
-  { MySQL_SLEEP,   "SLEEP" },
-  { MySQL_QUIT,   "Quit" },
-  { MySQL_INIT_DB,  "Init Database" },
-  { MySQL_QUERY,   "Query" },
-  { MySQL_FIELD_LIST, "Field List" },
-  { MySQL_CREATE_DB,  "Create Database" },
-  { MySQL_DROP_DB , "Drop Database" },
-  { MySQL_REFRESH , "Refresh" },
-  { MySQL_SHUTDOWN , "Shutdown" },
-  { MySQL_STATISTICS , "Statistics" },
-  { MySQL_PROCESS_INFO , "Process Info" },
-  { MySQL_CONNECT , "Connect" },
-  { MySQL_PROCESS_KILL , "Process Kill" },
-  { MySQL_DEBUG , "Debug" },
-  { MySQL_PING , "Ping" },
-  { MySQL_TIME , "Time" },
-  { MySQL_DELAY_INSERT , "Delay Insert" },
-  { MySQL_CHANGE_USER , "Change User" },
-  { MySQL_BINLOG_DUMP , "Binlog Dump" },
-  { MySQL_TABLE_DUMP, "Table Dump" },
-  { MySQL_CONNECT_OUT, "Table Connect Out" },
-  { 0,          NULL }
-};
-
-static const value_string mysql_status_vals[] = {
-       {1, "IN_TRANS" },
-       {2, "AUTOCOMMIT"},
-       { 0, NULL }
-};
-static const value_string mysql_charset_vals[] = {
-       {1, "big5"}, 
-       {2, "czech"},  
-       {3,"dec8"},
-       {4, "dos" },  
-       {5,"german1"}, 
-       {6,"hp8"},  
-       {7,"koi8_ru"},
-       {8,"latin1"},  
-       {9,"latin2"}, 
-       {9,"swe7 "},
-       {10,"usa7"},
-       {11,"ujis"},
-       {12,"sjis"},
-       {13,"cp1251"},
-       {14,"danish"},
-       {15,"hebrew"},
-       {16,"win1251"},
-       {17,"tis620"},
-       {18,"euc_kr"},
-       {19,"estonia"},
-       {20,"hungarian"},
-       {21,"koi8_ukr"},
-       {22,"win1251ukr"},
-       {23,"gb2312"},
-       {24,"greek"},
-       {25,"win1250"},
-       {26,"croat"},
-       {27,"gbk"},
-       {28,"cp1257"},
-       {29,"latin5"},
-       {0,NULL}
-};
-#if 0
-static const value_string mysql_error_code_vals[] = {
-  { 0, "Not defined" },
-  { 1, "File not found" },
-  { 2, "Access violation" },
-  { 3, "Disk full or allocation exceeded" },
-  { 4, "Illegal MySQL Operation" },
-  { 5, "Unknown transfer ID" },
-  { 6, "File already exists" },
-  { 7, "No such user" },
-  { 8, "Option negotiation failed" },
-  { 0, NULL }
+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;
+
+typedef enum my_proto_state
+{
+       UNDEFINED,
+       LOGIN,
+       REQUEST,
+       RESPONSE_OK,
+       RESPONSE_MESSAGE,
+       RESPONSE_TABULAR,
+       FIELD_PACKET,
+       ROW_PACKET,
+       RESPONSE_PREPARE,
+       PARAM_PACKET
+} my_proto_state_t;
+
+#ifdef CTDEBUG
+static const value_string state_vals[] = {
+       {UNDEFINED,        "undefined"},
+       {LOGIN,            "login"},
+       {REQUEST,          "request"},
+       {RESPONSE_OK,      "response OK"},
+       {RESPONSE_MESSAGE, "response message"},
+       {RESPONSE_TABULAR, "tabular response"},
+       {FIELD_PACKET,     "field packet"},
+       {ROW_PACKET,       "row packet"},
+       {RESPONSE_PREPARE, "response to PREPARE"},
+       {PARAM_PACKET,     "parameter packet"},
+       {0, NULL}
 };
 #endif
 
-static guint get_mysql_pdu_len(tvbuff_t *tvb, int offset);
-static void dissect_mysql_pdu(tvbuff_t *tvb, packet_info *pinfo,
-               proto_tree *tree);
-static int mysql_dissect_server_greeting(tvbuff_t *tvb, packet_info *pinfo, 
-               int offset, proto_tree *tree);
-static int mysql_dissect_authentication(tvbuff_t *tvb, packet_info *pinfo,
-               int offset, proto_tree *tree);
-static int mysql_dissect_request(tvbuff_t *tvb, packet_info *pinfo,
-               int offset, proto_tree *tree);
-static int mysql_dissect_response(tvbuff_t *tvb, packet_info *pinfo,
-               int offset, proto_tree *tree);
-static int mysql_dissect_error_packet(tvbuff_t *tvb, packet_info *pinfo,
-               int offset, proto_tree *tree);
-
-static void
-dissect_mysql(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+typedef struct my_conn_data
 {
-       tcp_dissect_pdus(tvb, pinfo, tree, mysql_desegment, 3,
-           get_mysql_pdu_len, dissect_mysql_pdu);
-}
+       guint16 srv_caps;
+       guint16 clnt_caps;
+       guint16 clnt_caps_ext;
+       my_proto_state_t state;
+       GHashTable* stmts;
+#ifdef CTDEBUG
+       guint32 generation;
+#endif
+} my_conn_data_t;
 
-static guint
-get_mysql_pdu_len(tvbuff_t *tvb, int offset)
-{
-       guint plen;
-
-       /*
-        * Get the length of the MySQL packet.
-        */
-       plen = tvb_get_letoh24(tvb, offset);
-
-       /*
-        * That length doesn't include the length field or the packet
-        * number itself; add them in.
-        */
-       return plen + 4;
-}
 
-static void
-dissect_mysql_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+typedef struct my_stmt_data
 {
-       proto_tree      *mysql_tree = NULL;
-       proto_item      *ti;
-       conversation_t  *conversation;
-
-       int             offset = 0;
-       guint           packet_number;
-
-       gboolean        is_response;
-
-       conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
-               pinfo->srcport, pinfo->destport, 0);
-
-       if (!conversation) {
-               /* create a new conversation */
-               conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
-                               pinfo->srcport, pinfo->destport, 0);
-       }
-
-
-       if (check_col(pinfo->cinfo, COL_PROTOCOL))
-               col_set_str(pinfo->cinfo, COL_PROTOCOL, "MySQL");
-
-       if (pinfo->destport == pinfo->match_port) {
-               is_response=FALSE;
-       }else {
-               is_response=TRUE;
-       }
-
-       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;
-/* packet number */
-       packet_number= tvb_get_guint8(tvb, offset);
-       if (tree) {
-                 proto_tree_add_uint(mysql_tree, hf_mysql_packet_number, tvb,
-                   offset, 1, packet_number);
-       }
-       offset += 1;
+       guint16 nparam;
+} my_stmt_data_t;
 
-       /*      
-        *      packet == 0 && response --> server greeting
-        *      packet == 1 && request --> login request
-        */ 
-       if(is_response ) {
-               if( packet_number == 0 ) {
-                       if (check_col(pinfo->cinfo, COL_INFO)) {
-                               col_add_str(pinfo->cinfo, COL_INFO, "Server Greeting" ) ; 
-                       }
-                       offset = mysql_dissect_server_greeting(tvb,pinfo,offset,mysql_tree);
-               }else {
-                       if (check_col(pinfo->cinfo, COL_INFO)) {
-                               col_add_str(pinfo->cinfo, COL_INFO, "Response" ) ; 
-                       }
-                       offset = mysql_dissect_response(tvb,pinfo,offset,mysql_tree);
-               }
-       } else {
-               if( packet_number == 1 ) {
-                       if (check_col(pinfo->cinfo, COL_INFO)) {
-                               col_add_str(pinfo->cinfo, COL_INFO, "Login Request") ; 
-                       }
-                       offset = mysql_dissect_authentication(tvb,pinfo,offset,mysql_tree);
-               }else {
-                       if (check_col(pinfo->cinfo, COL_INFO)) {
-                               col_add_str(pinfo->cinfo, COL_INFO, "Request") ; 
-                       }
-                       offset = mysql_dissect_request(tvb,pinfo,offset,mysql_tree);
-               }
-       }
 
-/* payload */
-       if (tree && tvb_reported_length_remaining(tvb, offset) > 0) {
-               proto_tree_add_item(mysql_tree, hf_mysql_payload,
-                   tvb, offset, -1, FALSE);
-       }
-}
-static int 
-mysql_dissect_response(tvbuff_t *tvb, packet_info *pinfo,
-               int offset, proto_tree *tree)
+/* function prototypes */
+void proto_reg_handoff_mysql(void);
+void proto_register_mysql(void);
+static void dissect_mysql(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
+static guint get_mysql_pdu_len(tvbuff_t *tvb, int offset);
+static void dissect_mysql_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
+static int mysql_dissect_login(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, my_conn_data_t *conn_data);
+static int mysql_dissect_greeting(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, my_conn_data_t *conn_data);
+static int mysql_dissect_request(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, my_conn_data_t *conn_data);
+static int mysql_dissect_response(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, my_conn_data_t *conn_data);
+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, my_conn_data_t *conn_data);
+static int mysql_dissect_server_status(tvbuff_t *tvb, int offset, proto_tree *tree);
+static int mysql_dissect_collation(tvbuff_t *tvb, int offset, proto_tree *tree, guint16 caps);
+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_result_header(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, my_conn_data_t *conn_data);
+static int mysql_dissect_field_packet(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, my_conn_data_t *conn_data);
+static int mysql_dissect_row_packet(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, my_conn_data_t *conn_data);
+static int mysql_dissect_response_prepare(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, my_conn_data_t *conn_data);
+static int mysql_dissect_param_packet(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, my_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);
+
+
+
+/* plugin registration (if compiled as plugin) */
+#ifndef ENABLE_STATIC
+G_MODULE_EXPORT void plugin_register(void)
 {
-       gint response_code;
-
-       /* response code */
-       response_code= tvb_get_guint8(tvb, offset);
-       if (tree) {
-               proto_tree_add_uint(tree, hf_mysql_response_code, tvb,
-               offset, 1, response_code);
+       if (proto_mysql == -1) { /* only once */
+               proto_register_mysql();
        }
-       offset +=1;
-               
-       if(response_code== 0xff ) {
-               offset = mysql_dissect_error_packet(tvb, pinfo, offset, tree);
-       } else {
-               if (check_col(pinfo->cinfo, COL_INFO)) {
-                       col_append_str(pinfo->cinfo, COL_INFO, " OK" ); 
-               }
-       }
-       return offset;
 }
 
-static int
-mysql_dissect_request(tvbuff_t *tvb,packet_info *pinfo,
-               int offset, proto_tree *tree)
-{
-       gint opcode;
-       gint strlen;
-       proto_item *tf;
-       proto_item *req_tree=NULL;
-
-       if(tree) {
-               tf=proto_tree_add_text(tree,tvb,offset,-1,"Command");
-               req_tree = proto_item_add_subtree(tf ,ett_request);
-       }
-
-       opcode = tvb_get_guint8(tvb, offset);
-       
-       if (check_col(pinfo->cinfo, COL_INFO)) {
-               col_append_fstr(pinfo->cinfo, COL_INFO, " Command: %s", 
-                       val_to_str(opcode, mysql_opcode_vals, "Unknown (%u)"));
-       }
-
-       if (req_tree) {
-               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);
-       }
-       /* command parameter */
-
-       offset += 1;
-       if ( (strlen = tvb_length_remaining(tvb,offset)) > 0 ) {
-               
-               if (check_col(pinfo->cinfo, COL_INFO)) {
-                       col_append_fstr(pinfo->cinfo, COL_INFO, " : %s",
-                                       tvb_format_text(tvb,offset,strlen));
-               }
-               
-               if (tree) {
-                       proto_tree_add_item(req_tree, hf_mysql_parameter, tvb,
-                               offset, strlen, FALSE );
-               }
-               offset +=strlen;
-       }
-
-       return offset;
+G_MODULE_EXPORT void plugin_reg_handoff(void){
+       proto_reg_handoff_mysql();
 }
+#endif
 
 
-static int
-mysql_dissect_authentication(tvbuff_t *tvb, packet_info *pinfo,
-               int offset, proto_tree *tree)
+/* dissector registration */
+void proto_reg_handoff_mysql(void)
 {
-       gint16  client_caps;
-       gint32  max_packet;
-       gint    strlen;
-
-       proto_item *tf;
-       proto_item *cap_tree;
-       proto_item *login_tree=NULL;
-
-       if(tree) {
-               tf=proto_tree_add_text(tree,tvb,offset,-1,"Login Packet");
-               login_tree = proto_item_add_subtree(tf ,ett_server_greeting);
-       }
-
-       client_caps= tvb_get_letohs(tvb, offset);
-
-       if (check_col(pinfo->cinfo, COL_INFO)) {
-               col_append_fstr(pinfo->cinfo, COL_INFO, " Caps: 0x%x",client_caps) ; 
-       }
-       if(tree) {
-               tf = proto_tree_add_uint_format(login_tree, hf_mysql_caps, tvb, offset , 1, client_caps, "Caps: 0x%04x ", client_caps );
-               cap_tree = proto_item_add_subtree(tf, ett_caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_long_password, tvb, offset, 2, client_caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_found_rows, tvb, offset, 2, client_caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_long_flag, tvb, offset, 2, client_caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_connect_with_db, tvb, offset, 2, client_caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_no_schema, tvb, offset, 2, client_caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_compress, tvb, offset, 2, client_caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_odbc, tvb, offset, 2, client_caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_local_files, tvb, offset, 2, client_caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_ignore_space, tvb, offset, 2, client_caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_change_user, tvb, offset, 2, client_caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_interactive, tvb, offset, 2, client_caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_ssl, tvb, offset, 2, client_caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_ignore_sigpipe, tvb, offset, 2, client_caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_transactions, tvb, offset, 2, client_caps);
-       }
-
-/*     proto_tree_add_uint(tree, hf_mysql_client_caps, tvb,
-               offset, 2, client_caps);
-*/
-       offset +=2;
-       /* 3 bytes max packet, 16777216 - x */
-       max_packet = 0xffffff - tvb_get_letoh24(tvb, offset);
-       if(tree) {
-               proto_tree_add_uint(login_tree, hf_mysql_max_packet, tvb,
-                       offset, 3, max_packet);
-       }
-       offset +=3;
-       /* User name */
-       strlen = 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 (tree) {
-               proto_tree_add_item(login_tree, hf_mysql_user, tvb,
-                       offset, strlen, FALSE );
-       }
-       offset +=strlen;
-       
-       /* Password */
-       strlen = tvb_length_remaining(tvb,offset);
-
-       if (check_col(pinfo->cinfo, COL_INFO)) {
-               col_append_fstr(pinfo->cinfo, COL_INFO, " ,password:  %s",
-                               tvb_get_ptr(tvb,offset,strlen));
-       }
-       if (tree) {
-               proto_tree_add_item(login_tree, hf_mysql_password, tvb,
-                       offset, strlen, FALSE );
-       }
-       offset +=strlen;
-       
-               
-       return offset;
+       dissector_handle_t mysql_handle;
+       mysql_handle = create_dissector_handle(dissect_mysql, proto_mysql);
+       dissector_add("tcp.port", TCP_PORT_MySQL, mysql_handle);
 }
 
 
-static int 
-mysql_dissect_server_greeting(tvbuff_t *tvb, packet_info *pinfo,
-               int offset, proto_tree *tree)
-{
-       gint protocol;
-       gint strlen;
-       gint32 thread_id;
-       gint16 server_caps;
-       gint charset;
-       gint16 status;
-       
-       proto_item *tf;
-       proto_item *greeting_tree=NULL;
-       proto_item *cap_tree;
-
-       protocol= tvb_get_guint8(tvb, offset);
-
-       if (protocol == 0xff) {
-               offset += 1;
-               return mysql_dissect_error_packet(tvb, pinfo, offset, 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, " Protocol : %d",protocol) ; 
-       }
-       if (tree) {
-               proto_tree_add_uint(greeting_tree, hf_mysql_protocol, tvb,
-                       offset, 1, protocol);
-       }
-       offset +=1;
-       /* 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_ptr(tvb,offset,strlen));
-       }
-       if (tree) {
-               proto_tree_add_item(greeting_tree, hf_mysql_version, tvb,
-                       offset, strlen, FALSE );
-       }
-       offset +=strlen;
-               
-       /* 4 bytes little endian thread_id */
-       thread_id = tvb_get_letohl(tvb, offset);
-       if(tree) {
-               proto_tree_add_uint(greeting_tree, hf_mysql_thread_id, tvb,
-                       offset, 4, thread_id);
-       }
-       offset +=4;
-       /* salt string */
-       strlen = tvb_strsize(tvb,offset);
-       if (tree) {
-               proto_tree_add_item(greeting_tree, hf_mysql_salt, tvb,
-                       offset, strlen, FALSE );
-       }
-       offset +=strlen;
-       /* 2 bytes CAPS */
-       server_caps= tvb_get_letohs(tvb, offset);
-
-       if (check_col(pinfo->cinfo, COL_INFO)) {
-               col_append_fstr(pinfo->cinfo, COL_INFO, " Caps: 0x%x",server_caps) ; 
-       }
-       if(tree) {
-               tf = proto_tree_add_uint_format(greeting_tree, hf_mysql_caps, tvb, offset , 1, server_caps, "Caps: 0x%04x ", server_caps );
-               cap_tree = proto_item_add_subtree(tf, ett_caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_long_password, tvb, offset, 2, server_caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_found_rows, tvb, offset, 2, server_caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_long_flag, tvb, offset, 2, server_caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_connect_with_db, tvb, offset, 2, server_caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_no_schema, tvb, offset, 2, server_caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_compress, tvb, offset, 2, server_caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_odbc, tvb, offset, 2, server_caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_local_files, tvb, offset, 2, server_caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_ignore_space, tvb, offset, 2, server_caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_change_user, tvb, offset, 2, server_caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_interactive, tvb, offset, 2, server_caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_ssl, tvb, offset, 2, server_caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_ignore_sigpipe, tvb, offset, 2, server_caps);
-               proto_tree_add_boolean(cap_tree, hf_mysql_cap_transactions, tvb, offset, 2, server_caps);
-       }
-       offset+=2;
-       /* 1 byte charset */
-       charset = tvb_get_guint8(tvb, offset);
-       if (tree) {
-               proto_tree_add_uint_format(greeting_tree, hf_mysql_charset, tvb,
-                       offset, 1, charset, "Charset: %s (%u)", 
-                       val_to_str(charset, mysql_charset_vals, "Unknown (%u)"), charset);
-       }
-       offset +=1;
-       /* 2 byte status */
-       status = tvb_get_letohs(tvb, offset);
-       if (tree) {
-               proto_tree_add_uint_format(greeting_tree, hf_mysql_status, tvb,
-                       offset, 2, status, "Status: %s (%u)",
-                       val_to_str(status, mysql_status_vals, "Unknown (%u)"), status); 
-       }
-       offset +=2;
-       /* other unused */
-       strlen = tvb_length_remaining(tvb,offset);
-
-       if (tree) {
-               proto_tree_add_item(greeting_tree, hf_mysql_unused, tvb,
-                       offset, strlen, FALSE );
-       }
-       offset +=strlen;
-       
-       return offset;
-}
-
-static int
-mysql_dissect_error_packet(tvbuff_t *tvb, packet_info *pinfo,
-               int offset, proto_tree *tree)
+/* protocol registration */
+void proto_register_mysql(void)
 {
-       gint error_code;
+       static hf_register_info hf[]=
+       {
+               { &hf_mysql_packet_length,
+               { "Packet Length", "mysql.packet_length",
+               FT_UINT24, BASE_DEC, NULL,  0x0,
+               "Packet Length", HFILL }},
+
+               { &hf_mysql_packet_number,
+               { "Packet Number", "mysql.packet_number",
+               FT_UINT8, BASE_DEC, NULL, 0x0,
+               "Packet Number", HFILL }},
+
+               { &hf_mysql_opcode,
+               { "Command", "mysql.opcode",
+               FT_UINT8, BASE_DEC, NULL, 0x0,
+               "Command", HFILL }},
+
+               { &hf_mysql_response_code,
+               { "Response Code", "mysql.response_code",
+               FT_UINT8, BASE_DEC, NULL, 0x0,
+               "Response Code", HFILL }},
+
+               { &hf_mysql_error_code,
+               { "Error Code", "mysql.error_code",
+               FT_UINT16, BASE_DEC, NULL, 0x0,
+               "Error Code", HFILL }},
+
+               { &hf_mysql_error_string,
+               { "Error message", "mysql.error.message",
+               FT_STRING, BASE_DEC, NULL, 0x0,
+               "Error string in case of MySQL error message", HFILL }},
+
+               { &hf_mysql_sqlstate,
+               { "SQL state", "mysql.sqlstate",
+               FT_STRING, BASE_NONE, NULL, 0x0,
+               "", HFILL }},
 
-       /* error code */
-       error_code = tvb_get_letohs(tvb, offset);
-       if (check_col(pinfo->cinfo, COL_INFO)) {
-               col_append_fstr(pinfo->cinfo, COL_INFO, " Error Code: %u", error_code); 
-       }
-       if (tree) {
-               proto_tree_add_uint(tree, hf_mysql_error_code, tvb,
-               offset, 2, error_code);
-       }
-       offset += 2;
+               { &hf_mysql_message,
+               { "Message", "mysql.message",
+               FT_STRINGZ, BASE_DEC, NULL, 0x0,
+               "Message", 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_protocol,
+               { "Protocol", "mysql.protocol",
+               FT_UINT8, BASE_DEC, NULL, 0x0,
+               "Protocol Version", HFILL }},
 
-       proto_tree_add_item(tree, hf_mysql_error_string, tvb, offset, -1, FALSE);
+               { &hf_mysql_version,
+               { "Version", "mysql.version",
+               FT_STRINGZ, BASE_DEC, NULL, 0x0,
+               "MySQL Version", HFILL }},
 
-        return offset + tvb_reported_length_remaining(tvb, offset);
-}
+               { &hf_mysql_caps,
+               { "Caps", "mysql.caps",
+               FT_UINT16, BASE_DEC, NULL, 0x0,
+               "MySQL Capabilities", HFILL }},
 
-void
-proto_register_mysql(void)
-{
-  static hf_register_info hf[] = {
-    { &hf_mysql_packet_length,
-      { "Packet Length",             "mysql.packet_length",
-       FT_UINT24, BASE_DEC, NULL,  0x0,
-       "MySQL packet length", HFILL }},
-
-    { &hf_mysql_packet_number,
-      { "Packet Number",         "mysql.packet_number",
-       FT_UINT8, BASE_DEC, NULL, 0x0,
-       "MySQL Packet Number", HFILL }},
-
-    { &hf_mysql_opcode,
-      { "Command",       "mysql.opcode",
-       FT_UINT8, BASE_DEC, NULL, 0x0,
-       "MySQL OPCODE", HFILL }},
-
-    { &hf_mysql_response_code,
-      { "Response Code",         "mysql.response_code",
-       FT_UINT8, BASE_DEC, NULL, 0x0,
-       "MySQL Respone Code", HFILL }},
-#if 0
-    { &hf_mysql_error_code,
-      { "Error Code",    "mysql.error_code",
-       FT_UINT16, BASE_DEC, NULL, 0x0,
-       "MySQL Error CODE", HFILL }},
-#endif
-    { &hf_mysql_protocol,
-      { "Protocol",      "mysql.protocol",
-       FT_UINT8, BASE_DEC, NULL, 0x0,
-       "MySQL Protocol", HFILL }},
-
-    { &hf_mysql_version,
-      { "Version",   "mysql.version",
-       FT_STRINGZ, BASE_DEC, NULL, 0x0,
-       "MySQL Version", HFILL }},
-
-    { &hf_mysql_caps,
-      { "Caps",          "mysql.caps",
-       FT_UINT16, BASE_DEC, NULL, 0x0,
-       "MySQL Capabilities", HFILL }},
-
-     { &hf_mysql_cap_long_password,
-       { "Long Password","mysql.caps.lp", 
+               { &hf_mysql_cap_long_password,
+               { "Long Password","mysql.caps.lp",
                FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_LP,
                "", HFILL }},
-               
-     { &hf_mysql_cap_found_rows,
-       { "Found Rows","mysql.caps.fr", 
+
+               { &hf_mysql_cap_found_rows,
+               { "Found Rows","mysql.caps.fr",
                FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_FR,
                "", HFILL }},
 
-               
-     { &hf_mysql_cap_long_flag,
-       { "Long Flag","mysql.caps.lf", 
+               { &hf_mysql_cap_long_flag,
+               { "Long Column Flags","mysql.caps.lf",
                FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_LF,
                "", HFILL }},
-               
-     { &hf_mysql_cap_connect_with_db,
-       { "Connect With Database","mysql.caps.cd", 
+
+               { &hf_mysql_cap_connect_with_db,
+               { "Connect With Database","mysql.caps.cd",
                FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_CD,
                "", HFILL }},
 
-               
-     { &hf_mysql_cap_no_schema,
-       { "Dont Allow database.table.column","mysql.caps.ns", 
+               { &hf_mysql_cap_no_schema,
+               { "Dont Allow database.table.column","mysql.caps.ns",
                FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_NS,
                "", HFILL }},
 
-     { &hf_mysql_cap_compress,
-       { "Can use compression protocol","mysql.caps.CP", 
+               { &hf_mysql_cap_compress,
+               { "Can use compression protocol","mysql.caps.cp",
                FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_CP,
                "", HFILL }},
-               
-     { &hf_mysql_cap_odbc,
-       { "ODBC Client","mysql.caps.ob", 
+
+               { &hf_mysql_cap_odbc,
+               { "ODBC Client","mysql.caps.ob",
                FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_OB,
                "", HFILL }},
 
-               
-     { &hf_mysql_cap_local_files,
-       { "Can Use LOAD DATA LOCAL","mysql.caps.li", 
+               { &hf_mysql_cap_local_files,
+               { "Can Use LOAD DATA LOCAL","mysql.caps.li",
                FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_LI,
                "", HFILL }},
-               
-     { &hf_mysql_cap_ignore_space,
-       { "Ignore Spaces before (","mysql.caps.is", 
+
+               { &hf_mysql_cap_ignore_space,
+               { "Ignore Spaces before '('","mysql.caps.is",
                FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_IS,
                "", HFILL }},
 
-               
-     { &hf_mysql_cap_change_user,
-       { "Support the mysql_change_user()","mysql.caps.cu", 
+               { &hf_mysql_cap_change_user,
+               { "Speaks 4.1 protocol (new flag)","mysql.caps.cu",
                FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_CU,
                "", HFILL }},
 
-               
-     { &hf_mysql_cap_interactive,
-       { "an Interactive Client","mysql.caps.ia", 
+               { &hf_mysql_cap_interactive,
+               { "Interactive Client","mysql.caps.ia",
                FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_IA,
                "", HFILL }},
 
-               
-     { &hf_mysql_cap_ssl,
-       { "Switch to SSL after handshake","mysql.caps.sl", 
+               { &hf_mysql_cap_ssl,
+               { "Switch to SSL after handshake","mysql.caps.sl",
                FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_SL,
                "", HFILL }},
 
-     { &hf_mysql_cap_ignore_sigpipe,
-       { "Ignore sigpipes","mysql.caps.ii", 
+               { &hf_mysql_cap_ignore_sigpipe,
+               { "Ignore sigpipes","mysql.caps.ii",
                FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_II,
                "", HFILL }},
-               
-     { &hf_mysql_cap_transactions,
-       { "Client knows about transactions","mysql.caps.ta", 
+
+               { &hf_mysql_cap_transactions,
+               { "Knows about transactions","mysql.caps.ta",
                FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_TA,
                "", HFILL }},
 
-    { &hf_mysql_max_packet,
-      { "MAX Packet",        "mysql.max_packet",
-       FT_UINT24, BASE_DEC, NULL,  0x0,
-       "MySQL Max packet", HFILL }},
-               
-    { &hf_mysql_user,
-      { "Username",          "mysql.user",
-       FT_STRINGZ, BASE_DEC, NULL, 0x0,
-       "Login Username", HFILL }}, 
-
-    { &hf_mysql_password,
-      { "Password",          "mysql.password",
-       FT_STRING, BASE_DEC, NULL, 0x0,
-       "Login Password", HFILL }}, 
-
-    { &hf_mysql_salt,
-      { "Salt",              "mysql.salt",
-       FT_STRINGZ, BASE_DEC, NULL, 0x0,
-       "Salt", HFILL }}, 
-
-    { &hf_mysql_thread_id,
-      { "Thread ID",         "mysql.thread_id",
-       FT_UINT32, BASE_DEC, NULL,  0x0,
-       "MySQL Thread ID", HFILL }},
-       
-    { &hf_mysql_charset,
-      { "Charset",           "mysql.charset",
-       FT_UINT8, BASE_DEC, NULL,  0x0,
-       "MySQL Charset", HFILL }},
-       
-    { &hf_mysql_status,
-      { "Status",            "mysql.status",
-       FT_UINT16, BASE_DEC, NULL,  0x0,
-       "MySQL Status", HFILL }},
-
-    { &hf_mysql_unused,
-      { "Unused",            "mysql.unused",
-       FT_STRING, BASE_DEC, NULL, 0x0,
-       "Unused", HFILL }},
-
-    { &hf_mysql_parameter,
-      { "Parameter",         "mysql.parameter",
-       FT_STRING, BASE_DEC, NULL, 0x0,
-       "Parameter", HFILL }},
-    { &hf_mysql_payload,
-      { "Payload",           "mysql.payload",
-       FT_STRING, BASE_DEC, NULL, 0x0,
-       "MySQL Payload", HFILL }},
-#if 0
-    { &hf_mysql_destination_file,
-      { "DESTINATION File",   "mysql.destination_file",
-       FT_STRINGZ, BASE_DEC, NULL, 0x0,
-       "MySQL source file name", HFILL }},
-
-    { &hf_mysql_blocknum,
-      { "Block",              "mysql.block",
-       FT_UINT16, BASE_DEC, NULL, 0x0,
-       "Block number", HFILL }},
-#endif
-    { &hf_mysql_error_code,
-      { "Error code",         "mysql.error.code",
-       FT_UINT16, BASE_DEC, NULL, 0x0,
-       "Error code in case of MySQL error message", HFILL }},
-
-    { &hf_mysql_error_string,
-      { "Error message",      "mysql.error.message",
-       FT_STRING, BASE_DEC, NULL, 0x0,
-       "Error string in case of MySQL error message", HFILL }},
-
-    { &hf_mysql_sqlstate,
-      { "SQL state",      "mysql.sqlstate",
-       FT_STRING, BASE_NONE, NULL, 0x0,
-       "", HFILL }}
-  };
-       static gint *ett[] = {
-               &ett_mysql,
-               &ett_server_greeting,
-               &ett_caps,
-               &ett_request,
-       };
-       module_t *mysql_module;
+               { &hf_mysql_cap_reserved,
+               { "Speaks 4.1 protocol (old flag)","mysql.caps.rs",
+               FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_RS,
+               "", HFILL }},
 
-       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));
+               { &hf_mysql_cap_secure_connect,
+               { "Can do 4.1 authentication","mysql.caps.sc",
+               FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_SC,
+               "", HFILL }},
 
-       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);
-}
+               { &hf_mysql_extcaps,
+               { "Ext. Caps", "mysql.extcaps",
+               FT_UINT16, BASE_DEC, NULL, 0x0,
+               "MySQL Extended Capabilities", HFILL }},
 
-void
-proto_reg_handoff_mysql(void)
-{
-       dissector_handle_t mysql_handle;
+               { &hf_mysql_cap_multi_statements,
+               { "Supports multiple statements","mysql.caps.ms",
+               FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_MS,
+               "", HFILL }},
 
-       mysql_handle = create_dissector_handle(dissect_mysql, proto_mysql);
-  
-       dissector_add("tcp.port", TCP_PORT_MySQL, mysql_handle);
+               { &hf_mysql_cap_multi_results,
+               { "Supports multiple results","mysql.caps.mr",
+               FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_MR,
+               "", HFILL }},
+
+               { &hf_mysql_max_packet,
+               { "MAX Packet", "mysql.max_packet",
+               FT_UINT24, BASE_DEC, NULL,  0x0,
+               "MySQL Max packet", HFILL }},
+
+               { &hf_mysql_user,
+               { "Username", "mysql.user",
+               FT_STRINGZ, BASE_DEC, NULL, 0x0,
+               "Login Username", HFILL }},
+
+               { &hf_mysql_schema,
+               { "Schema", "mysql.schema",
+               FT_STRING, BASE_DEC, NULL, 0x0,
+               "Login Schema", HFILL }},
+
+               { &hf_mysql_salt,
+               { "Salt", "mysql.salt",
+               FT_STRINGZ, BASE_DEC, NULL, 0x0,
+               "Salt", HFILL }},
+
+               { &hf_mysql_salt2,
+               { "Salt", "mysql.salt2",
+               FT_STRINGZ, BASE_DEC, NULL, 0x0,
+               "Salt", HFILL }},
+
+               { &hf_mysql_thread_id,
+               { "Thread ID", "mysql.thread_id",
+               FT_UINT32, BASE_DEC, NULL,  0x0,
+               "MySQL Thread ID", HFILL }},
+
+               { &hf_mysql_charset,
+               { "Charset", "mysql.charset",
+               FT_UINT8, BASE_DEC, NULL,  0x0,
+               "MySQL Charset", HFILL }},
+
+               { &hf_mysql_status,
+               { "Status", "mysql.status",
+               FT_UINT16, BASE_DEC, NULL,  0x0,
+               "MySQL Status", HFILL }},
+
+               { &hf_mysql_stat_it,
+               { "In transaction", "mysql.stat.it",
+               FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_STAT_IT,
+               "", HFILL }},
+
+               { &hf_mysql_stat_ac,
+               { "AUTO_COMMIT", "mysql.stat.ac",
+               FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_STAT_AC,
+               "", HFILL }},
+
+               { &hf_mysql_stat_mr,
+               { "More results", "mysql.stat.mr",
+               FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_STAT_MR,
+               "", HFILL }},
+
+               { &hf_mysql_stat_mu,
+               { "Multi query - more resultsets", "mysql.stat.mu",
+               FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_STAT_MU,
+               "", HFILL }},
+
+               { &hf_mysql_stat_bi,
+               { "Bad index used", "mysql.stat.bi",
+               FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_STAT_BI,
+               "", HFILL }},
+
+               { &hf_mysql_stat_ni,
+               { "No index used", "mysql.stat.ni",
+               FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_STAT_NI,
+               "", HFILL }},
+
+               { &hf_mysql_stat_cr,
+               { "Cursor exists", "mysql.stat.cr",
+               FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_STAT_CR,
+               "", HFILL }},
+
+               { &hf_mysql_stat_lr,
+               { "Last row sebd", "mysql.stat.lr",
+               FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_STAT_LR,
+               "", HFILL }},
+
+               { &hf_mysql_stat_dr,
+               { "database dropped", "mysql.stat.dr",
+               FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_STAT_DR,
+               "", HFILL }},
+
+               { &hf_mysql_stat_bs,
+               { "No backslash escapes", "mysql.stat.bs",
+               FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_STAT_BS,
+               "", HFILL }},
+
+               { &hf_mysql_refresh,
+               { "Refresh Option", "mysql.refresh",
+               FT_UINT8, BASE_DEC, NULL,  0x0,
+               "Refresh Option", HFILL }},
+
+               { &hf_mysql_rfsh_grants,
+               { "reload permissions", "mysql.rfsh.grants",
+               FT_BOOLEAN, 8, TFS(&flags_set_truth), MYSQL_RFSH_GRANT,
+               "", HFILL }},
+
+               { &hf_mysql_rfsh_log,
+               { "flush logfiles", "mysql.rfsh.log",
+               FT_BOOLEAN, 8, TFS(&flags_set_truth), MYSQL_RFSH_LOG,
+               "", HFILL }},
+
+               { &hf_mysql_rfsh_tables,
+               { "flush tables", "mysql.rfsh.tables",
+               FT_BOOLEAN, 8, TFS(&flags_set_truth), MYSQL_RFSH_TABLES,
+               "", HFILL }},
+
+               { &hf_mysql_rfsh_hosts,
+               { "flush hosts", "mysql.rfsh.hosts",
+               FT_BOOLEAN, 8, TFS(&flags_set_truth), MYSQL_RFSH_HOSTS,
+               "", HFILL }},
+
+               { &hf_mysql_rfsh_status,
+               { "reset statistics", "mysql.rfsh.status",
+               FT_BOOLEAN, 8, TFS(&flags_set_truth), MYSQL_RFSH_STATUS,
+               "", HFILL }},
+
+               { &hf_mysql_rfsh_threads,
+               { "empty thread cache", "mysql.rfsh.threads",
+               FT_BOOLEAN, 8, TFS(&flags_set_truth), MYSQL_RFSH_THREADS,
+               "", HFILL }},
+
+               { &hf_mysql_rfsh_slave,
+               { "flush slave status", "mysql.rfsh.slave",
+               FT_BOOLEAN, 8, TFS(&flags_set_truth), MYSQL_RFSH_SLAVE,
+               "", HFILL }},
+
+               { &hf_mysql_rfsh_master,
+               { "flush master status", "mysql.rfsh.master",
+               FT_BOOLEAN, 8, TFS(&flags_set_truth), MYSQL_RFSH_MASTER,
+               "", HFILL }},
+
+               { &hf_mysql_unused,
+               { "Unused", "mysql.unused",
+               FT_STRING, BASE_DEC, NULL, 0x0,
+               "Unused", HFILL }},
+
+               { &hf_mysql_passwd,
+               { "Password", "mysql.passwd",
+               FT_STRING, BASE_DEC, NULL, 0x0,
+               "Password", HFILL }},
+
+               { &hf_mysql_parameter,
+               { "Parameter", "mysql.parameter",
+               FT_STRING, BASE_DEC, NULL, 0x0,
+               "Parameter", HFILL }},
+
+               { &hf_mysql_payload,
+               { "Payload", "mysql.payload",
+               FT_STRING, BASE_DEC, NULL, 0x0,
+               "Additional Payload", HFILL }},
+
+               { &hf_mysql_affected_rows,
+               { "Affected Rows", "mysql.affected_rows",
+               FT_UINT64, BASE_DEC, NULL, 0x0,
+               "Affected Rows", HFILL }},
+
+               { &hf_mysql_insert_id,
+               { "Last INSERT ID", "mysql.insert_id",
+               FT_UINT64, BASE_DEC, NULL, 0x0,
+               "Last INSERT ID", HFILL }},
+
+               { &hf_mysql_num_warn,
+               { "Warnings", "mysql.warnings",
+               FT_UINT16, BASE_DEC, NULL, 0x0,
+               "Warnings", HFILL }},
+
+               { &hf_mysql_thd_id,
+               { "Thread ID", "mysql.thd_id",
+               FT_UINT32, BASE_DEC, NULL, 0x0,
+               "Thread ID", HFILL }},
+
+               { &hf_mysql_stmt_id,
+               { "Statement ID", "mysql.stmt_id",
+               FT_UINT32, BASE_DEC, NULL, 0x0,
+               "Statement ID", HFILL }},
+
+               { &hf_mysql_query,
+               { "Statement", "mysql.query",
+               FT_STRING, BASE_DEC, NULL, 0x0,
+               "Statement", HFILL }},
+
+               { &hf_mysql_option,
+               { "Option", "mysql.option",
+               FT_UINT16, BASE_DEC, NULL, 0x0,
+               "Option", HFILL }},
+
+               { &hf_mysql_param,
+               { "Parameter", "mysql.param",
+               FT_UINT16, BASE_DEC, NULL, 0x0,
+               "Parameter", HFILL }},
+
+               { &hf_mysql_num_rows,
+               { "Rows to fetch", "mysql.num_rows",
+               FT_UINT32, BASE_DEC, NULL, 0x0,
+               "Rows to fetch", HFILL }},
+
+               { &hf_mysql_exec_flags,
+               { "Flags (unused)", "mysql.exec_flags",
+               FT_UINT8, BASE_DEC, NULL, 0x0,
+               "Flags (unused)", HFILL }},
+
+               { &hf_mysql_exec_iter,
+               { "Iterations (unused)", "mysql.exec_iter",
+               FT_UINT32, BASE_DEC, NULL, 0x0,
+               "Iterations (unused)", HFILL }},
+
+               { &hf_mysql_eof,
+               { "EOF", "mysql.eof",
+               FT_UINT8, BASE_DEC, NULL,  0x0,
+               "EOF", HFILL }},
+
+               { &hf_mysql_num_fields,
+               { "Number of fields", "mysql.num_fields",
+               FT_UINT64, BASE_DEC, NULL,  0x0,
+               "Number of fields", HFILL }},
+
+               { &hf_mysql_extra,
+               { "Extra data", "mysql.extra",
+               FT_UINT64, BASE_DEC, NULL,  0x0,
+               "Extra data", HFILL }}
+       };
+
+       static gint *ett[]=
+       {
+               &ett_mysql,
+               &ett_server_greeting,
+               &ett_caps,
+               &ett_extcaps,
+               &ett_stat,
+               &ett_request,
+               &ett_refresh,
+       };
+
+       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);
 }
+
+
+/* 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 helper: length of PDU */
+static guint get_mysql_pdu_len(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)
+{
+       proto_tree      *mysql_tree= NULL;
+       proto_item      *ti;
+       conversation_t  *conversation;
+       int             offset = 0;
+       guint           packet_number;
+       gboolean        is_response;
+       my_conn_data_t  *conn_data;
+#ifdef CTDEBUG
+       my_proto_state_t state_in, state_out;
+       guint64         generation;
+#endif
+
+       /* get conversation, create if neccessary*/
+       conversation= find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
+                                       pinfo->ptype, pinfo->srcport,
+                                       pinfo->destport, 0);
+
+       if (!conversation) {
+               conversation= conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst,
+                                              pinfo->ptype, pinfo->srcport,
+                                              pinfo->destport, 0);
+       }
+
+       /* get associated state information, create if neccessary */
+       conn_data= conversation_get_proto_data(conversation, proto_mysql);
+       if (!conn_data) {
+               conn_data= se_alloc(sizeof(my_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 (check_col(pinfo->cinfo, COL_PROTOCOL)) {
+               col_set_str(pinfo->cinfo, COL_PROTOCOL, "MySQL");
+       }
+
+       if (pinfo->destport == pinfo->match_port) {
+               is_response= FALSE;
+       } else {
+               is_response= TRUE;
+       }
+
+       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;
+
+       packet_number= tvb_get_guint8(tvb, offset);
+       if (tree) {
+               proto_tree_add_uint(mysql_tree, hf_mysql_packet_number, tvb,
+                                   offset, 1, packet_number);
+       }
+       offset+= 1;
+
+#ifdef CTDEBUG
+       state_in= conn_data->state;
+       generation= conn_data->generation;
+       if (tree) {
+               proto_tree_add_text(mysql_tree, tvb, offset, 0, "conversation: %p", conversation);
+               proto_tree_add_text(mysql_tree, tvb, offset, 0, "generation: %lld", generation);
+               proto_tree_add_text(mysql_tree, tvb, offset, 0, "proto state: %s (%u)",
+                                   val_to_str(state_in, state_vals, "Unknown (%u)"),
+                                   state_in);
+       }
+#endif
+
+       if (is_response ) {
+               if (packet_number == 0) {
+                       if (check_col(pinfo->cinfo, COL_INFO)) {
+                               col_add_str(pinfo->cinfo, COL_INFO, "Server Greeting" );
+                       }
+                       offset= mysql_dissect_greeting(tvb, pinfo, offset,
+                                                      mysql_tree, conn_data);
+               } else {
+                       if (check_col(pinfo->cinfo, COL_INFO)) {
+                               col_add_str(pinfo->cinfo, COL_INFO, "Response" );
+                       }
+                       offset= mysql_dissect_response(tvb, pinfo, offset,
+                                                      mysql_tree, conn_data);
+               }
+       } else {
+               if (packet_number == 1) {
+                       if (check_col(pinfo->cinfo, COL_INFO)) {
+                               col_add_str(pinfo->cinfo, COL_INFO, "Login Request");
+                       }
+                       offset= mysql_dissect_login(tvb, pinfo, offset,
+                                                   mysql_tree, conn_data);
+               } else {
+                       if (check_col(pinfo->cinfo, COL_INFO)) {
+                               col_add_str(pinfo->cinfo, COL_INFO, "Request");
+                       }
+                       offset= mysql_dissect_request(tvb, pinfo, offset,
+                                                     mysql_tree, conn_data);
+               }
+       }
+
+#ifdef CTDEBUG
+       state_out= conn_data->state;
+       ++(conn_data->generation);
+       if (tree) {
+               proto_tree_add_text(mysql_tree, tvb, offset, 0, "next proto state: %s (%u)",
+                                   val_to_str(state_out, state_vals, "Unknown (%u)"),
+                                   state_out);
+       }
+#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");
+       }
+}
+
+
+static int mysql_dissect_greeting(tvbuff_t *tvb, packet_info *pinfo, int offset,
+                                 proto_tree *tree, my_conn_data_t *conn_data)
+{
+       gint protocol;
+       gint strlen;
+       gint32 thread_id;
+       guint16 server_caps;
+
+       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;
+
+       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) ;
+       }
+       if (tree) {
+               proto_tree_add_uint(greeting_tree, hf_mysql_protocol, tvb,
+                                   offset, 1, protocol);
+       }
+       offset+= 1;
+
+       /* 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_ptr(tvb, offset, strlen));
+       }
+       if (tree) {
+               proto_tree_add_item(greeting_tree, hf_mysql_version, tvb,
+                                   offset, strlen, FALSE );
+       }
+       offset+= strlen;
+
+       /* 4 bytes little endian thread_id */
+       thread_id= tvb_get_letohl(tvb, offset);
+       if (tree) {
+               proto_tree_add_uint(greeting_tree, hf_mysql_thread_id, tvb,
+                                   offset, 4, thread_id);
+       }
+       offset+= 4;
+
+       /* salt string */
+       strlen= tvb_strsize(tvb,offset);
+       if (tree) {
+               proto_tree_add_item(greeting_tree, hf_mysql_salt, tvb,
+                                   offset, strlen, FALSE );
+       }
+       offset+=strlen;
+
+       /* rest is optional */
+       if (!tvb_length_remaining(tvb, offset)) return offset;
+
+       /* 2 bytes CAPS */
+       offset= mysql_dissect_caps(tvb, offset, greeting_tree, &server_caps, "Server");
+       conn_data->srv_caps= server_caps;
+
+       /* rest is optional */
+       if (!tvb_length_remaining(tvb, offset)) return offset;
+
+       offset= mysql_dissect_collation(tvb, offset, greeting_tree, server_caps);
+       offset= mysql_dissect_server_status(tvb, offset, greeting_tree);
+
+       /* 13 bytes unused */
+       if (tree) {
+               proto_tree_add_item(greeting_tree, hf_mysql_unused, tvb,
+                                   offset, 13, FALSE );
+       }
+       offset+= 13;
+
+       /* 4.1+ server: rest of salt */
+       if (tvb_length_remaining(tvb, offset)) {
+               strlen= tvb_strsize(tvb,offset);
+               if (tree) {
+                       proto_tree_add_item(greeting_tree, hf_mysql_salt2, tvb,
+                                           offset, strlen, FALSE );
+               }
+               offset+= strlen;
+       }
+
+       return offset;
+}
+
+
+static int mysql_dissect_login(tvbuff_t *tvb, packet_info *pinfo, int offset,
+                              proto_tree *tree, my_conn_data_t *conn_data)
+{
+       guint16  client_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;
+
+       if (tree) {
+               tf= proto_tree_add_text(tree, tvb, offset, -1, "Login Request");
+               login_tree= proto_item_add_subtree(tf, ett_server_greeting);
+       }
+
+       offset= mysql_dissect_caps(tvb, offset, login_tree, &client_caps, "Client");
+       conn_data->clnt_caps= client_caps;
+
+       if (client_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);
+               if(tree) {
+                       proto_tree_add_uint(login_tree, hf_mysql_max_packet, tvb,
+                                           offset, 4, max_packet);
+               }
+               offset+= 4;
+
+               offset= mysql_dissect_collation(tvb, offset, login_tree, client_caps);
+
+               offset+= 23; /* filler bytes */
+
+       } else { /* pre-4.1 */
+               max_packet= 0xffffff - tvb_get_letoh24(tvb, offset);
+               if (tree) {
+                       proto_tree_add_uint(login_tree, hf_mysql_max_packet, tvb,
+                                           offset, 3, max_packet);
+               }
+               offset+= 3;
+       }
+
+       /* 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 (tree) {
+               proto_tree_add_item(login_tree, hf_mysql_user, tvb,
+                                   offset, strlen, FALSE );
+       }
+       offset+= strlen;
+
+       /* rest is optional */
+       if (!tvb_length_remaining(tvb, offset)) return offset;
+
+       /* password: asciiz or length+ascii */
+       if (client_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 (client_caps & MYSQL_CAPS_CD)
+       {
+               strlen= my_tvb_strsize(tvb,offset);
+
+               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);
+               }
+               if (tree) {
+                       proto_tree_add_item(login_tree, hf_mysql_schema, tvb,
+                                           offset, strlen, FALSE );
+               }
+               offset+= strlen;
+       }
+
+       return offset;
+}
+
+
+static int mysql_dissect_request(tvbuff_t *tvb,packet_info *pinfo, int offset,
+                                proto_tree *tree, my_conn_data_t *conn_data)
+{
+       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);
+       }
+
+       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)"));
+       }
+       if (req_tree) {
+               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;
+
+
+       switch (opcode) {
+
+       case MYSQL_QUIT:
+               if (conn_data->stmts) {
+                       g_hash_table_destroy(conn_data->stmts);
+                       conn_data->stmts= NULL;
+               }
+               break;
+
+       case MYSQL_PROCESS_INFO:
+               conn_data->state= RESPONSE_TABULAR;
+               break;
+
+       case MYSQL_DEBUG:
+       case MYSQL_PING:
+               conn_data->state= RESPONSE_OK;
+               break;
+
+       case MYSQL_STATISTICS:
+               conn_data->state= RESPONSE_MESSAGE;
+               break;
+
+       case MYSQL_INIT_DB:
+       case MYSQL_CREATE_DB:
+       case MYSQL_DROP_DB:
+               strlen= my_tvb_strsize(tvb, offset);
+               if (req_tree) {
+                       proto_tree_add_item(req_tree, hf_mysql_schema, tvb,
+                                           offset, strlen, FALSE);
+               }
+               offset+= strlen;
+               conn_data->state= RESPONSE_OK;
+               break;
+
+       case MYSQL_QUERY:
+               strlen= my_tvb_strsize(tvb, offset);
+               if (req_tree) {
+                       proto_tree_add_item(req_tree, hf_mysql_query, tvb,
+                                           offset, strlen, FALSE);
+               }
+               offset+= strlen;
+               conn_data->state= RESPONSE_TABULAR;
+               break;
+
+       case MYSQL_STMT_PREPARE:
+               strlen= my_tvb_strsize(tvb, offset);
+               if (req_tree) {
+                       proto_tree_add_item(req_tree, hf_mysql_query, tvb,
+                                           offset, strlen, FALSE);
+               }
+               offset+= strlen;
+               conn_data->state= RESPONSE_PREPARE;
+               break;
+
+       case MYSQL_STMT_CLOSE:
+               if (conn_data->stmts) {
+                       gint stmt= tvb_get_letohl(tvb, offset);
+                       g_hash_table_remove(conn_data->stmts, &stmt);
+               }
+               if (req_tree) {
+                       proto_tree_add_item(req_tree, hf_mysql_stmt_id,
+                                           tvb, offset, 4, TRUE);
+               }
+               offset+= 4;
+               conn_data->state= REQUEST;
+               break;
+
+       case MYSQL_STMT_RESET:
+               if (req_tree) {
+                       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);
+               if (req_tree) {
+                       proto_tree_add_text(req_tree, tvb, offset, strlen, "Table name: %s",
+                                           tvb_get_string(tvb, offset, strlen));
+               }
+               offset+= strlen;
+               conn_data->state= RESPONSE_TABULAR;
+               break;
+
+       case MYSQL_PROCESS_KILL:
+               if (req_tree) {
+                       proto_tree_add_item(req_tree, hf_mysql_thd_id,
+                                           tvb, offset, 4, TRUE);
+               }
+               offset+= 4;
+               conn_data->state= RESPONSE_OK;
+               break;
+
+       case MYSQL_CHANGE_USER:
+               strlen= tvb_strsize(tvb, offset);
+               if (req_tree) {
+                       proto_tree_add_item(req_tree, hf_mysql_user, tvb,
+                                           offset, strlen, FALSE);
+               }
+               offset+= strlen;
+
+               strlen= tvb_strsize(tvb, offset);
+               if (req_tree) {
+                       proto_tree_add_item(req_tree, hf_mysql_passwd, tvb,
+                                           offset, strlen, FALSE);
+               }
+               offset+= strlen;
+
+               strlen= my_tvb_strsize(tvb, offset);
+               if (req_tree) {
+                       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 *tf;
+                       proto_item *rfsh_tree;
+                       gint refresh= tvb_get_guint8(tvb, offset);
+
+                       if (req_tree) {
+                               tf= 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(tf, 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);
+               if (req_tree) {
+                       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;
+
+       case MYSQL_SET_OPTION:
+               option= tvb_get_letohs(tvb, offset);
+               if (req_tree) {
+                       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;
+
+       case MYSQL_STMT_FETCH:
+               if (req_tree) {
+                       proto_tree_add_item(req_tree, hf_mysql_stmt_id,
+                                           tvb, offset, 4, TRUE);
+               }
+               offset+= 4;
+
+               if (req_tree) {
+                       proto_tree_add_item(req_tree, hf_mysql_num_rows,
+                                           tvb, offset, 4, TRUE);
+               }
+               offset+= 4;
+               conn_data->state= RESPONSE_TABULAR;
+               break;
+
+       case MYSQL_STMT_SEND_LONG_DATA:
+               if (req_tree) {
+                       proto_tree_add_item(req_tree, hf_mysql_stmt_id,
+                                           tvb, offset, 4, TRUE);
+               }
+               offset+= 4;
+
+               if (req_tree) {
+                       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;
+
+       case MYSQL_STMT_EXECUTE:
+               if (req_tree) {
+                       proto_tree_add_item(req_tree, hf_mysql_stmt_id,
+                                           tvb, offset, 4, TRUE);
+               }
+               offset+= 4;
+
+               if (req_tree) {
+                       proto_tree_add_item(req_tree, hf_mysql_exec_flags,
+                                           tvb, offset, 1, TRUE);
+               }
+               offset+= 1;
+
+               if (req_tree) {
+                       proto_tree_add_item(req_tree, hf_mysql_exec_iter,
+                                           tvb, offset, 4, TRUE);
+               }
+               offset+= 4;
+
+#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;
+
+/* FIXME: implement replication packets */
+       case MYSQL_BINLOG_DUMP:
+       case MYSQL_TABLE_DUMP:
+       case MYSQL_CONNECT_OUT:
+       case MYSQL_REGISTER_SLAVE:
+               if (req_tree) {
+                       proto_tree_add_string(req_tree, hf_mysql_payload, tvb, offset, -1,
+                                             "FIXME: implement replication packets");
+               }
+               offset+= tvb_length_remaining(tvb, offset);
+               conn_data->state= REQUEST;
+               break;
+
+       default:
+               if (req_tree) {
+                       proto_tree_add_string(req_tree, hf_mysql_payload, tvb, offset, -1,
+                                             "unknown/invalid command code");
+               }
+               offset+= tvb_length_remaining(tvb, offset);
+               conn_data->state= UNDEFINED;
+       }
+
+       return offset;
+}
+
+
+static int mysql_dissect_response(tvbuff_t *tvb, packet_info *pinfo, int offset,
+                                 proto_tree *tree, my_conn_data_t *conn_data)
+{
+       gint response_code;
+        gint strlen;
+
+       response_code= tvb_get_guint8(tvb, offset);
+
+       if (response_code == 0xff ) {
+               offset= mysql_dissect_error_packet(tvb, pinfo, offset+1, tree);
+               conn_data->state= REQUEST;
+       }
+
+        else if (response_code == 0xfe && tvb_length_remaining(tvb, offset) < 9) {
+
+               if (tree) {
+                       proto_tree_add_uint_format(tree, hf_mysql_eof, tvb, offset, 1,
+                                                  response_code, "EOF marker (%u)",
+                                                  response_code);
+               }
+               offset+= 1;
+
+               /* pre-4.1 packet ends here */
+               if (tvb_length_remaining(tvb, offset)) {
+                       if (tree) {
+                               proto_tree_add_item(tree, hf_mysql_num_warn,
+                                                   tvb, offset, 2, FALSE);
+                       }
+                       offset= mysql_dissect_server_status(tvb, offset+2, tree);
+               }
+
+               if (conn_data->state == FIELD_PACKET) {
+                       conn_data->state= ROW_PACKET;
+               } else {
+                       conn_data->state= REQUEST;
+               }
+       }
+
+       else if (response_code == 0) {
+               if (tvb_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);
+               }
+       }
+
+       else {
+               switch (conn_data->state) {
+               case RESPONSE_MESSAGE:
+                       if ((strlen= tvb_length_remaining(tvb, offset))) {
+                               if (tree) {
+                                       proto_tree_add_item(tree, hf_mysql_message, tvb,
+                                                           offset, strlen, FALSE);
+                               }
+                               offset+= strlen;
+                       }
+                       conn_data->state= REQUEST;
+                       break;
+
+               case RESPONSE_TABULAR:
+                       offset= mysql_dissect_result_header(tvb, pinfo, offset,
+                                                           tree, conn_data);
+                       break;
+
+               case FIELD_PACKET:
+                       offset= mysql_dissect_field_packet(tvb, pinfo, offset,
+                                                          tree, conn_data);
+                       break;
+
+               case ROW_PACKET:
+                       offset= mysql_dissect_row_packet(tvb, pinfo, offset,
+                                                        tree, conn_data);
+                       break;
+
+               case RESPONSE_PREPARE:
+                       offset= mysql_dissect_response_prepare(tvb, pinfo, offset,
+                                                              tree, conn_data);
+                       break;
+
+               case PARAM_PACKET:
+                       offset= mysql_dissect_param_packet(tvb, pinfo, offset,
+                                                          tree, conn_data);
+                       break;
+
+               default:
+                       if (tree) {
+                               proto_tree_add_string(tree, hf_mysql_payload, tvb, offset, -1,
+                                                     "unknown/invalid response");
+                       }
+                       offset+= tvb_length_remaining(tvb, offset);
+                       conn_data->state= UNDEFINED;
+               }
+       }
+
+       return offset;
+}
+
+
+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);
+
+       if (check_col(pinfo->cinfo, COL_INFO)) {
+               col_append_fstr(pinfo->cinfo, COL_INFO, " Error %d", error_code);
+       }
+       if (tree) {
+               proto_tree_add_uint(tree, hf_mysql_error_code, tvb,
+                                   offset, 2, error_code);
+       }
+       offset+= 2;
+
+       if (tvb_get_guint8(tvb, offset) == '#')
+       {
+               offset+= 1;
+               proto_tree_add_item(tree, hf_mysql_sqlstate, tvb, offset, 5, FALSE);
+               offset+= 5;
+       }
+
+       proto_tree_add_item(tree, hf_mysql_error_string, tvb, offset, -1, FALSE);
+       offset+= tvb_reported_length_remaining(tvb, offset);
+
+       return offset;
+}
+
+
+static int mysql_dissect_ok_packet(tvbuff_t *tvb, packet_info *pinfo, int offset,
+                                  proto_tree *tree, my_conn_data_t *conn_data)
+{
+       gint strlen;
+       guint64 affected_rows;
+       guint64 insert_id;
+       int fle;
+
+       if (check_col(pinfo->cinfo, COL_INFO)) {
+               col_append_str(pinfo->cinfo, COL_INFO, " OK" );
+       }
+
+       fle= tvb_get_fle(tvb, offset, &affected_rows, NULL);
+       if (tree) {
+               proto_tree_add_uint64(tree, hf_mysql_affected_rows,
+                                     tvb, offset, fle, affected_rows);
+       }
+       offset+= fle;
+
+       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;
+
+       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) {
+               if (tree) {
+                       proto_tree_add_item(tree, hf_mysql_num_warn, tvb,
+                                           offset, 2, FALSE);
+               }
+               offset+= 2;
+       }
+
+       /* optional: message string */
+       if ((strlen= tvb_length_remaining(tvb, offset))) {
+               if (tree) {
+                       proto_tree_add_item(tree, hf_mysql_message, tvb,
+                                           offset, strlen, FALSE);
+               }
+               offset+= strlen;
+       }
+
+       conn_data->state= REQUEST;
+       return offset;
+}
+
+
+static int mysql_dissect_server_status(tvbuff_t *tvb, int offset, proto_tree *tree)
+{
+       guint16 status;
+       proto_item *tf;
+       proto_item *stat_tree;
+
+       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;
+
+       return offset;
+}
+
+
+static int mysql_dissect_collation(tvbuff_t *tvb, int offset, proto_tree *tree, guint16 caps)
+{
+       gint charset= tvb_get_guint8(tvb, offset);
+       if (tree) {
+               proto_tree_add_uint_format(tree, hf_mysql_charset, tvb, offset, 1,
+                                          charset, "Charset: %s (%u)",
+                                          val_to_str(charset,
+                                                     caps & MYSQL_CAPS_CU
+                                                     ? mysql_collation_vals
+                                                     : mysql_charset_vals,
+                                                     "Unknown (%u)"), charset);
+       }
+       offset+= 1;
+       return offset;
+}
+
+
+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);
+       }
+
+       offset+= 2;
+       return offset;
+}
+
+
+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);
+       }
+
+       offset+= 2;
+       return offset;
+}
+
+
+static int mysql_dissect_result_header(tvbuff_t *tvb, packet_info *pinfo, int offset,
+                                      proto_tree *tree, my_conn_data_t *conn_data)
+{
+       gint fle;
+       guint64 num_fields, extra;
+
+       if (check_col(pinfo->cinfo, COL_INFO)) {
+               col_append_str(pinfo->cinfo, COL_INFO, " TABULAR" );
+       }
+
+       fle= tvb_get_fle(tvb, offset, &num_fields, NULL);
+       if (tree) {
+               proto_tree_add_uint64(tree, hf_mysql_num_fields,
+                                     tvb, offset, fle, num_fields);
+       }
+       offset+= fle;
+
+       if (tvb_length_remaining(tvb, offset)) {
+               fle= tvb_get_fle(tvb, offset, &extra, NULL);
+               if (tree) {
+                       proto_tree_add_uint64(tree, hf_mysql_extra,
+                                             tvb, offset, fle, extra);
+               }
+               offset+= fle;
+       }
+
+       if (num_fields) {
+               conn_data->state= FIELD_PACKET;
+       } else {
+               conn_data->state= ROW_PACKET;
+       }
+
+       return offset;
+}
+
+
+static int mysql_dissect_field_packet(tvbuff_t *tvb, packet_info *pinfo, int offset,
+                                     proto_tree *tree, my_conn_data_t *conn_data)
+{
+       proto_tree_add_text(tree, tvb, offset, -1, "FIXME: write mysql_dissect_field_packet()");
+       return offset + tvb_length_remaining(tvb, offset);
+}
+
+
+static int mysql_dissect_row_packet(tvbuff_t *tvb, packet_info *pinfo, int offset,
+                                   proto_tree *tree, my_conn_data_t *conn_data)
+{
+       proto_tree_add_text(tree, tvb, offset, -1, "FIXME: write mysql_dissect_row_packet()");
+       return offset + tvb_length_remaining(tvb, offset);
+}
+
+
+static int mysql_dissect_response_prepare(tvbuff_t *tvb, packet_info *pinfo, int offset,
+                                         proto_tree *tree, my_conn_data_t *conn_data)
+{
+       proto_tree_add_text(tree, tvb, offset, -1, "FIXME: write mysql_dissect_response_prepare()");
+       return offset + tvb_length_remaining(tvb, offset);
+}
+
+
+static int mysql_dissect_param_packet(tvbuff_t *tvb, packet_info *pinfo, int offset,
+                                     proto_tree *tree, my_conn_data_t *conn_data)
+{
+       proto_tree_add_text(tree, tvb, offset, -1, "FIXME: write mysql_dissect_param_packet()");
+       return offset + tvb_length_remaining(tvb, offset);
+}
+
+
+
+/*
+ get length of string in packet buffer
+
+ SYNOPSIS
+   my_tvb_strsize()
+     tvb      packet buffer
+     offset   current offset
+
+ DESCRIPTION
+   deliver length of string, delimited by either \0 or end of buffer
+
+ RETURN VALUE
+   length of string found, including \0 (if present)
+
+*/
+static gint my_tvb_strsize(tvbuff_t *tvb, int offset)
+{
+       gint len = tvb_strnlen(tvb, offset, -1);
+       if (len == -1) {
+               len = tvb_length_remaining(tvb, offset);
+       } else {
+               len++; /* the trailing \0 */
+       }
+       return len;
+}
+
+
+/*
+ read "field length encoded" value from packet buffer
+
+ 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
+
+ DESCRIPTION
+   read FLE from packet buffer and store its value and ISNULL flag
+   in caller provided variables
+
+ 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);
+
+       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:
+               if (res)
+                       *res= prefix;
+       }
+
+       return 1;
+}
+
+