Try to squeeze some bytes out of the frame_data structure.
[gd/wireshark/.git] / epan / dissectors / packet-mysql.c
1 /* packet-mysql.c
2  * Routines for mysql packet dissection
3  *
4  * Huagang XIE <huagang@intruvert.com>
5  *
6  * MySQL 4.1+ protocol by Axel Schwenke <axel@mysql.com>
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * Copied from packet-tftp.c
13  *
14  * SPDX-License-Identifier: GPL-2.0-or-later
15  *
16  *
17  * the protocol spec at
18  *  https://dev.mysql.com/doc/internals/en/client-server-protocol.html
19  * and MySQL source code
20  */
21
22 /* create extra output for conversation tracking */
23 /* #define CTDEBUG 1 */
24
25 #include "config.h"
26
27 #include <epan/packet.h>
28 #include <epan/prefs.h>
29 #include <epan/expert.h>
30 #include <epan/strutil.h>
31 #include <epan/proto_data.h>
32 #include "packet-tcp.h"
33 #include "packet-tls-utils.h"
34
35 void proto_register_mysql(void);
36 void proto_reg_handoff_mysql(void);
37
38 /* port for protocol registration */
39 #define TCP_PORT_MySQL   3306
40
41 /* client/server capabilities
42  * Source: http://dev.mysql.com/doc/internals/en/capability-flags.html
43  * Source: mysql_com.h
44  */
45 #define MYSQL_CAPS_LP 0x0001 /* CLIENT_LONG_PASSWORD */
46 #define MYSQL_CAPS_FR 0x0002 /* CLIENT_FOUND_ROWS */
47 #define MYSQL_CAPS_LF 0x0004 /* CLIENT_LONG_FLAG */
48 #define MYSQL_CAPS_CD 0x0008 /* CLIENT_CONNECT_WITH_DB */
49 #define MYSQL_CAPS_NS 0x0010 /* CLIENT_NO_SCHEMA */
50 #define MYSQL_CAPS_CP 0x0020 /* CLIENT_COMPRESS */
51 #define MYSQL_CAPS_OB 0x0040 /* CLIENT_ODBC */
52 #define MYSQL_CAPS_LI 0x0080 /* CLIENT_LOCAL_FILES */
53 #define MYSQL_CAPS_IS 0x0100 /* CLIENT_IGNORE_SPACE */
54 #define MYSQL_CAPS_CU 0x0200 /* CLIENT_PROTOCOL_41 */
55 #define MYSQL_CAPS_IA 0x0400 /* CLIENT_INTERACTIVE */
56 #define MYSQL_CAPS_SL 0x0800 /* CLIENT_SSL */
57 #define MYSQL_CAPS_II 0x1000 /* CLIENT_IGNORE_SPACE */
58 #define MYSQL_CAPS_TA 0x2000 /* CLIENT_TRANSACTIONS */
59 #define MYSQL_CAPS_RS 0x4000 /* CLIENT_RESERVED */
60 #define MYSQL_CAPS_SC 0x8000 /* CLIENT_SECURE_CONNECTION */
61
62
63 /* field flags */
64 #define MYSQL_FLD_NOT_NULL_FLAG       0x0001
65 #define MYSQL_FLD_PRI_KEY_FLAG        0x0002
66 #define MYSQL_FLD_UNIQUE_KEY_FLAG     0x0004
67 #define MYSQL_FLD_MULTIPLE_KEY_FLAG   0x0008
68 #define MYSQL_FLD_BLOB_FLAG           0x0010
69 #define MYSQL_FLD_UNSIGNED_FLAG       0x0020
70 #define MYSQL_FLD_ZEROFILL_FLAG       0x0040
71 #define MYSQL_FLD_BINARY_FLAG         0x0080
72 #define MYSQL_FLD_ENUM_FLAG           0x0100
73 #define MYSQL_FLD_AUTO_INCREMENT_FLAG 0x0200
74 #define MYSQL_FLD_TIMESTAMP_FLAG      0x0400
75 #define MYSQL_FLD_SET_FLAG            0x0800
76
77 /* extended capabilities: 4.1+ client only
78  *
79  * These are libmysqlclient flags and NOT present
80  * in the protocol:
81  * CLIENT_SSL_VERIFY_SERVER_CERT (1UL << 30)
82  * CLIENT_REMEMBER_OPTIONS (1UL << 31)
83  */
84 #define MYSQL_CAPS_MS 0x0001 /* CLIENT_MULTI_STATMENTS */
85 #define MYSQL_CAPS_MR 0x0002 /* CLIENT_MULTI_RESULTS */
86 #define MYSQL_CAPS_PM 0x0004 /* CLIENT_PS_MULTI_RESULTS */
87 #define MYSQL_CAPS_PA 0x0008 /* CLIENT_PLUGIN_AUTH */
88 #define MYSQL_CAPS_CA 0x0010 /* CLIENT_CONNECT_ATTRS */
89 #define MYSQL_CAPS_AL 0x0020 /* CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA */
90 #define MYSQL_CAPS_EP 0x0040 /* CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS */
91 #define MYSQL_CAPS_ST 0x0080 /* CLIENT_SESSION_TRACK */
92 #define MYSQL_CAPS_DE 0x0100 /* CLIENT_DEPRECATE_EOF */
93 #define MYSQL_CAPS_UNUSED 0xFE00
94
95 /* status bitfield */
96 #define MYSQL_STAT_IT 0x0001
97 #define MYSQL_STAT_AC 0x0002
98 #define MYSQL_STAT_MU 0x0004
99 #define MYSQL_STAT_MR 0x0008
100 #define MYSQL_STAT_BI 0x0010
101 #define MYSQL_STAT_NI 0x0020
102 #define MYSQL_STAT_CR 0x0040
103 #define MYSQL_STAT_LR 0x0080
104 #define MYSQL_STAT_DR 0x0100
105 #define MYSQL_STAT_BS 0x0200
106 #define MYSQL_STAT_MC 0x0400
107 #define MYSQL_STAT_QUERY_WAS_SLOW 0x0800
108 #define MYSQL_STAT_PS_OUT_PARAMS 0x1000
109 #define MYSQL_STAT_TRANS_READONLY 0x2000
110 #define MYSQL_STAT_SESSION_STATE_CHANGED 0x4000
111
112 /* bitfield for MYSQL_REFRESH */
113 #define MYSQL_RFSH_GRANT   1   /* Refresh grant tables */
114 #define MYSQL_RFSH_LOG     2   /* Start on new log file */
115 #define MYSQL_RFSH_TABLES  4   /* close all tables */
116 #define MYSQL_RFSH_HOSTS   8   /* Flush host cache */
117 #define MYSQL_RFSH_STATUS  16  /* Flush status variables */
118 #define MYSQL_RFSH_THREADS 32  /* Flush thread cache */
119 #define MYSQL_RFSH_SLAVE   64  /* Reset master info and restart slave thread */
120 #define MYSQL_RFSH_MASTER  128 /* Remove all bin logs in the index and truncate the index */
121
122 /* MySQL command codes (enum_server_command in mysql-server.git:include/my_command.h) */
123 #define MYSQL_SLEEP               0  /* not from client */
124 #define MYSQL_QUIT                1
125 #define MYSQL_INIT_DB             2
126 #define MYSQL_QUERY               3
127 #define MYSQL_FIELD_LIST          4
128 #define MYSQL_CREATE_DB           5
129 #define MYSQL_DROP_DB             6
130 #define MYSQL_REFRESH             7
131 #define MYSQL_SHUTDOWN            8
132 #define MYSQL_STATISTICS          9
133 #define MYSQL_PROCESS_INFO        10
134 #define MYSQL_CONNECT             11 /* not from client */
135 #define MYSQL_PROCESS_KILL        12
136 #define MYSQL_DEBUG               13
137 #define MYSQL_PING                14
138 #define MYSQL_TIME                15 /* not from client */
139 #define MYSQL_DELAY_INSERT        16 /* not from client */
140 #define MYSQL_CHANGE_USER         17
141 #define MYSQL_BINLOG_DUMP         18 /* replication */
142 #define MYSQL_TABLE_DUMP          19 /* replication */
143 #define MYSQL_CONNECT_OUT         20 /* replication */
144 #define MYSQL_REGISTER_SLAVE      21 /* replication */
145 #define MYSQL_STMT_PREPARE        22
146 #define MYSQL_STMT_EXECUTE        23
147 #define MYSQL_STMT_SEND_LONG_DATA 24
148 #define MYSQL_STMT_CLOSE          25
149 #define MYSQL_STMT_RESET          26
150 #define MYSQL_SET_OPTION          27
151 #define MYSQL_STMT_FETCH          28
152 #define MYSQL_DAEMON              29
153 #define MYSQL_BINLOG_DUMP_GTID    30 /* replication */
154 #define MYSQL_RESET_CONNECTION    31
155
156
157 /* MySQL cursor types */
158
159 #define MYSQL_CURSOR_TYPE_NO_CURSOR  0
160 #define MYSQL_CURSOR_TYPE_READ_ONLY  1
161 #define MYSQL_CURSOR_TYPE_FOR_UPDATE 2
162 #define MYSQL_CURSOR_TYPE_SCROLLABLE 4
163
164 /* MySQL parameter flags -- used internally by the dissector */
165
166 #define MYSQL_PARAM_FLAG_STREAMED 0x01
167
168 /* Compression states, internal to the dissector */
169 #define MYSQL_COMPRESS_NONE   0
170 #define MYSQL_COMPRESS_INIT   1
171 #define MYSQL_COMPRESS_ACTIVE 2
172
173 /* Generic Response Codes */
174 #define MYSQL_RESPONSE_OK   0x00
175 #define MYSQL_RESPONSE_ERR  0xFF
176 #define MYSQL_RESPONSE_EOF  0xFE
177
178 /* decoding table: command */
179 static const value_string mysql_command_vals[] = {
180         {MYSQL_SLEEP,   "SLEEP"},
181         {MYSQL_QUIT,   "Quit"},
182         {MYSQL_INIT_DB,  "Use Database"},
183         {MYSQL_QUERY,   "Query"},
184         {MYSQL_FIELD_LIST, "Show Fields"},
185         {MYSQL_CREATE_DB,  "Create Database"},
186         {MYSQL_DROP_DB , "Drop Database"},
187         {MYSQL_REFRESH , "Refresh"},
188         {MYSQL_SHUTDOWN , "Shutdown"},
189         {MYSQL_STATISTICS , "Statistics"},
190         {MYSQL_PROCESS_INFO , "Process List"},
191         {MYSQL_CONNECT , "Connect"},
192         {MYSQL_PROCESS_KILL , "Kill Server Thread"},
193         {MYSQL_DEBUG , "Dump Debuginfo"},
194         {MYSQL_PING , "Ping"},
195         {MYSQL_TIME , "Time"},
196         {MYSQL_DELAY_INSERT , "Insert Delayed"},
197         {MYSQL_CHANGE_USER , "Change User"},
198         {MYSQL_BINLOG_DUMP , "Send Binlog"},
199         {MYSQL_TABLE_DUMP, "Send Table"},
200         {MYSQL_CONNECT_OUT, "Slave Connect"},
201         {MYSQL_REGISTER_SLAVE, "Register Slave"},
202         {MYSQL_STMT_PREPARE, "Prepare Statement"},
203         {MYSQL_STMT_EXECUTE, "Execute Statement"},
204         {MYSQL_STMT_SEND_LONG_DATA, "Send BLOB"},
205         {MYSQL_STMT_CLOSE, "Close Statement"},
206         {MYSQL_STMT_RESET, "Reset Statement"},
207         {MYSQL_SET_OPTION, "Set Option"},
208         {MYSQL_STMT_FETCH, "Fetch Data"},
209         {MYSQL_BINLOG_DUMP_GTID, "Send Binlog GTID"},
210         {0, NULL}
211 };
212 static value_string_ext mysql_command_vals_ext = VALUE_STRING_EXT_INIT(mysql_command_vals);
213
214 /* decoding table: exec_flags */
215 static const value_string mysql_exec_flags_vals[] = {
216         {MYSQL_CURSOR_TYPE_NO_CURSOR, "Defaults"},
217         {MYSQL_CURSOR_TYPE_READ_ONLY, "Read-only cursor"},
218         {MYSQL_CURSOR_TYPE_FOR_UPDATE, "Cursor for update"},
219         {MYSQL_CURSOR_TYPE_SCROLLABLE, "Scrollable cursor"},
220         {0, NULL}
221 };
222
223 /* decoding table: new_parameter_bound_flag */
224 static const value_string mysql_new_parameter_bound_flag_vals[] = {
225         {0, "Subsequent call"},
226         {1, "First call or rebound"},
227         {0, NULL}
228 };
229
230 /* decoding table: exec_time_sign */
231 static const value_string mysql_exec_time_sign_vals[] = {
232         {0, "Positive"},
233         {1, "Negative"},
234         {0, NULL}
235 };
236
237 #if 0
238 /* charset: pre-4.1 used the term 'charset', later changed to 'collation' */
239 static const value_string mysql_charset_vals[] = {
240         {1,  "big5"},
241         {2,  "czech"},
242         {3,  "dec8"},
243         {4,  "dos" },
244         {5,  "german1"},
245         {6,  "hp8"},
246         {7,  "koi8_ru"},
247         {8,  "latin1"},
248         {9,  "latin2"},
249         {9,  "swe7 "},
250         {10, "usa7"},
251         {11, "ujis"},
252         {12, "sjis"},
253         {13, "cp1251"},
254         {14, "danish"},
255         {15, "hebrew"},
256         {16, "win1251"},
257         {17, "tis620"},
258         {18, "euc_kr"},
259         {19, "estonia"},
260         {20, "hungarian"},
261         {21, "koi8_ukr"},
262         {22, "win1251ukr"},
263         {23, "gb2312"},
264         {24, "greek"},
265         {25, "win1250"},
266         {26, "croat"},
267         {27, "gbk"},
268         {28, "cp1257"},
269         {29, "latin5"},
270         {0, NULL}
271 };
272 #endif
273
274
275 /* collation codes may change over time, recreate with the following SQL
276
277 SELECT CONCAT('  {', ID, ',"', CHARACTER_SET_NAME, ' COLLATE ', COLLATION_NAME, '"},')
278 FROM INFORMATION_SCHEMA.COLLATIONS
279 ORDER BY ID
280 INTO OUTFILE '/tmp/mysql-collations';
281
282 */
283 static const value_string mysql_collation_vals[] = {
284         {3,   "dec8 COLLATE dec8_swedish_ci"},
285         {4,   "cp850 COLLATE cp850_general_ci"},
286         {5,   "latin1 COLLATE latin1_german1_ci"},
287         {6,   "hp8 COLLATE hp8_english_ci"},
288         {7,   "koi8r COLLATE koi8r_general_ci"},
289         {8,   "latin1 COLLATE latin1_swedish_ci"},
290         {9,   "latin2 COLLATE latin2_general_ci"},
291         {10,  "swe7 COLLATE swe7_swedish_ci"},
292         {11,  "ascii COLLATE ascii_general_ci"},
293         {14,  "cp1251 COLLATE cp1251_bulgarian_ci"},
294         {15,  "latin1 COLLATE latin1_danish_ci"},
295         {16,  "hebrew COLLATE hebrew_general_ci"},
296         {20,  "latin7 COLLATE latin7_estonian_cs"},
297         {21,  "latin2 COLLATE latin2_hungarian_ci"},
298         {22,  "koi8u COLLATE koi8u_general_ci"},
299         {23,  "cp1251 COLLATE cp1251_ukrainian_ci"},
300         {25,  "greek COLLATE greek_general_ci"},
301         {26,  "cp1250 COLLATE cp1250_general_ci"},
302         {27,  "latin2 COLLATE latin2_croatian_ci"},
303         {29,  "cp1257 COLLATE cp1257_lithuanian_ci"},
304         {30,  "latin5 COLLATE latin5_turkish_ci"},
305         {31,  "latin1 COLLATE latin1_german2_ci"},
306         {32,  "armscii8 COLLATE armscii8_general_ci"},
307         {33,  "utf8 COLLATE utf8_general_ci"},
308         {36,  "cp866 COLLATE cp866_general_ci"},
309         {37,  "keybcs2 COLLATE keybcs2_general_ci"},
310         {38,  "macce COLLATE macce_general_ci"},
311         {39,  "macroman COLLATE macroman_general_ci"},
312         {40,  "cp852 COLLATE cp852_general_ci"},
313         {41,  "latin7 COLLATE latin7_general_ci"},
314         {42,  "latin7 COLLATE latin7_general_cs"},
315         {43,  "macce COLLATE macce_bin"},
316         {44,  "cp1250 COLLATE cp1250_croatian_ci"},
317         {45,  "utf8mb4 COLLATE utf8mb4_general_ci"},
318         {46,  "utf8mb4 COLLATE utf8mb4_bin"},
319         {47,  "latin1 COLLATE latin1_bin"},
320         {48,  "latin1 COLLATE latin1_general_ci"},
321         {49,  "latin1 COLLATE latin1_general_cs"},
322         {50,  "cp1251 COLLATE cp1251_bin"},
323         {51,  "cp1251 COLLATE cp1251_general_ci"},
324         {52,  "cp1251 COLLATE cp1251_general_cs"},
325         {53,  "macroman COLLATE macroman_bin"},
326         {57,  "cp1256 COLLATE cp1256_general_ci"},
327         {58,  "cp1257 COLLATE cp1257_bin"},
328         {59,  "cp1257 COLLATE cp1257_general_ci"},
329         {63,  "binary COLLATE binary"},
330         {64,  "armscii8 COLLATE armscii8_bin"},
331         {65,  "ascii COLLATE ascii_bin"},
332         {66,  "cp1250 COLLATE cp1250_bin"},
333         {67,  "cp1256 COLLATE cp1256_bin"},
334         {68,  "cp866 COLLATE cp866_bin"},
335         {69,  "dec8 COLLATE dec8_bin"},
336         {70,  "greek COLLATE greek_bin"},
337         {71,  "hebrew COLLATE hebrew_bin"},
338         {72,  "hp8 COLLATE hp8_bin"},
339         {73,  "keybcs2 COLLATE keybcs2_bin"},
340         {74,  "koi8r COLLATE koi8r_bin"},
341         {75,  "koi8u COLLATE koi8u_bin"},
342         {77,  "latin2 COLLATE latin2_bin"},
343         {78,  "latin5 COLLATE latin5_bin"},
344         {79,  "latin7 COLLATE latin7_bin"},
345         {80,  "cp850 COLLATE cp850_bin"},
346         {81,  "cp852 COLLATE cp852_bin"},
347         {82,  "swe7 COLLATE swe7_bin"},
348         {83,  "utf8 COLLATE utf8_bin"},
349         {92,  "geostd8 COLLATE geostd8_general_ci"},
350         {93,  "geostd8 COLLATE geostd8_bin"},
351         {94,  "latin1 COLLATE latin1_spanish_ci"},
352         {99,  "cp1250 COLLATE cp1250_polish_ci"},
353         {192, "utf8 COLLATE utf8_unicode_ci"},
354         {193, "utf8 COLLATE utf8_icelandic_ci"},
355         {194, "utf8 COLLATE utf8_latvian_ci"},
356         {195, "utf8 COLLATE utf8_romanian_ci"},
357         {196, "utf8 COLLATE utf8_slovenian_ci"},
358         {197, "utf8 COLLATE utf8_polish_ci"},
359         {198, "utf8 COLLATE utf8_estonian_ci"},
360         {199, "utf8 COLLATE utf8_spanish_ci"},
361         {200, "utf8 COLLATE utf8_swedish_ci"},
362         {201, "utf8 COLLATE utf8_turkish_ci"},
363         {202, "utf8 COLLATE utf8_czech_ci"},
364         {203, "utf8 COLLATE utf8_danish_ci"},
365         {204, "utf8 COLLATE utf8_lithuanian_ci"},
366         {205, "utf8 COLLATE utf8_slovak_ci"},
367         {206, "utf8 COLLATE utf8_spanish2_ci"},
368         {207, "utf8 COLLATE utf8_roman_ci"},
369         {208, "utf8 COLLATE utf8_persian_ci"},
370         {209, "utf8 COLLATE utf8_esperanto_ci"},
371         {210, "utf8 COLLATE utf8_hungarian_ci"},
372         {211, "utf8 COLLATE utf8_sinhala_ci"},
373         {212, "utf8 COLLATE utf8_german2_ci"},
374         {213, "utf8 COLLATE utf8_croatian_ci"},
375         {214, "utf8 COLLATE utf8_unicode_520_ci"},
376         {215, "utf8 COLLATE utf8_vietnamese_ci"},
377         {223, "utf8 COLLATE utf8_general_mysql500_ci"},
378         {224, "utf8mb4 COLLATE utf8mb4_unicode_ci"},
379         {225, "utf8mb4 COLLATE utf8mb4_icelandic_ci"},
380         {226, "utf8mb4 COLLATE utf8mb4_latvian_ci"},
381         {227, "utf8mb4 COLLATE utf8mb4_romanian_ci"},
382         {228, "utf8mb4 COLLATE utf8mb4_slovenian_ci"},
383         {229, "utf8mb4 COLLATE utf8mb4_polish_ci"},
384         {230, "utf8mb4 COLLATE utf8mb4_estonian_ci"},
385         {231, "utf8mb4 COLLATE utf8mb4_spanish_ci"},
386         {232, "utf8mb4 COLLATE utf8mb4_swedish_ci"},
387         {233, "utf8mb4 COLLATE utf8mb4_turkish_ci"},
388         {234, "utf8mb4 COLLATE utf8mb4_czech_ci"},
389         {235, "utf8mb4 COLLATE utf8mb4_danish_ci"},
390         {236, "utf8mb4 COLLATE utf8mb4_lithuanian_ci"},
391         {237, "utf8mb4 COLLATE utf8mb4_slovak_ci"},
392         {238, "utf8mb4 COLLATE utf8mb4_spanish2_ci"},
393         {239, "utf8mb4 COLLATE utf8mb4_roman_ci"},
394         {240, "utf8mb4 COLLATE utf8mb4_persian_ci"},
395         {241, "utf8mb4 COLLATE utf8mb4_esperanto_ci"},
396         {242, "utf8mb4 COLLATE utf8mb4_hungarian_ci"},
397         {243, "utf8mb4 COLLATE utf8mb4_sinhala_ci"},
398         {244, "utf8mb4 COLLATE utf8mb4_german2_ci"},
399         {245, "utf8mb4 COLLATE utf8mb4_croatian_ci"},
400         {246, "utf8mb4 COLLATE utf8mb4_unicode_520_ci"},
401         {247, "utf8mb4 COLLATE utf8mb4_vietnamese_ci"},
402         {0, NULL}
403 };
404 static value_string_ext mysql_collation_vals_ext = VALUE_STRING_EXT_INIT(mysql_collation_vals);
405
406
407 /* allowed MYSQL_SHUTDOWN levels */
408 static const value_string mysql_shutdown_vals[] = {
409         {0,   "default"},
410         {1,   "wait for connections to finish"},
411         {2,   "wait for transactions to finish"},
412         {8,   "wait for updates to finish"},
413         {16,  "wait flush all buffers"},
414         {17,  "wait flush critical buffers"},
415         {254, "kill running queries"},
416         {255, "kill connections"},
417         {0, NULL}
418 };
419
420
421 /* allowed MYSQL_SET_OPTION values */
422 static const value_string mysql_option_vals[] = {
423         {0, "multi statements on"},
424         {1, "multi statements off"},
425         {0, NULL}
426 };
427
428 static const value_string mysql_session_track_type_vals[] = {
429         {0, "SESSION_SYSVARS_TRACKER"},
430         {1, "CURRENT_SCHEMA_TRACKER"},
431         {2, "SESSION_STATE_CHANGE_TRACKER"},
432         {0, NULL}
433 };
434
435 static const value_string mysql_response_code_vals[] = {
436     { MYSQL_RESPONSE_OK,    "OK Packet" },
437     { MYSQL_RESPONSE_ERR,   "ERR Packet" },
438     { MYSQL_RESPONSE_EOF,   "EOF Packet" },
439     { 0, NULL }
440 };
441
442 /* protocol id */
443 static int proto_mysql = -1;
444
445 /* dissector configuration */
446 static gboolean mysql_desegment = TRUE;
447 static gboolean mysql_showquery = FALSE;
448
449 /* expand-the-tree flags */
450 static gint ett_mysql = -1;
451 static gint ett_server_greeting = -1;
452 static gint ett_login_request = -1;
453 static gint ett_caps = -1;
454 static gint ett_extcaps = -1;
455 static gint ett_stat = -1;
456 static gint ett_request = -1;
457 static gint ett_refresh = -1;
458 static gint ett_field_flags = -1;
459 static gint ett_exec_param = -1;
460 static gint ett_session_track = -1;
461 static gint ett_session_track_data = -1;
462 static gint ett_connattrs = -1;
463 static gint ett_connattrs_attr = -1;
464
465 /* protocol fields */
466 static int hf_mysql_caps_server = -1;
467 static int hf_mysql_caps_client = -1;
468 static int hf_mysql_cap_long_password = -1;
469 static int hf_mysql_cap_found_rows = -1;
470 static int hf_mysql_cap_long_flag = -1;
471 static int hf_mysql_cap_connect_with_db = -1;
472 static int hf_mysql_cap_no_schema = -1;
473 static int hf_mysql_cap_compress = -1;
474 static int hf_mysql_cap_odbc = -1;
475 static int hf_mysql_cap_local_files = -1;
476 static int hf_mysql_cap_ignore_space = -1;
477 static int hf_mysql_cap_change_user = -1;
478 static int hf_mysql_cap_interactive = -1;
479 static int hf_mysql_cap_ssl = -1;
480 static int hf_mysql_cap_ignore_sigpipe = -1;
481 static int hf_mysql_cap_transactions = -1;
482 static int hf_mysql_cap_reserved = -1;
483 static int hf_mysql_cap_secure_connect = -1;
484 static int hf_mysql_extcaps_server = -1;
485 static int hf_mysql_extcaps_client = -1;
486 static int hf_mysql_cap_multi_statements = -1;
487 static int hf_mysql_cap_multi_results = -1;
488 static int hf_mysql_cap_ps_multi_results = -1;
489 static int hf_mysql_cap_plugin_auth = -1;
490 static int hf_mysql_cap_connect_attrs = -1;
491 static int hf_mysql_cap_plugin_auth_lenenc_client_data = -1;
492 static int hf_mysql_cap_client_can_handle_expired_passwords = -1;
493 static int hf_mysql_cap_session_track = -1;
494 static int hf_mysql_cap_deprecate_eof = -1;
495 static int hf_mysql_cap_unused = -1;
496 static int hf_mysql_server_language = -1;
497 static int hf_mysql_server_status = -1;
498 static int hf_mysql_stat_it = -1;
499 static int hf_mysql_stat_ac = -1;
500 static int hf_mysql_stat_mr = -1;
501 static int hf_mysql_stat_mu = -1;
502 static int hf_mysql_stat_bi = -1;
503 static int hf_mysql_stat_ni = -1;
504 static int hf_mysql_stat_cr = -1;
505 static int hf_mysql_stat_lr = -1;
506 static int hf_mysql_stat_dr = -1;
507 static int hf_mysql_stat_bs = -1;
508 static int hf_mysql_stat_mc = -1;
509 static int hf_mysql_stat_session_state_changed = -1;
510 static int hf_mysql_stat_query_was_slow = -1;
511 static int hf_mysql_stat_ps_out_params = -1;
512 static int hf_mysql_stat_trans_readonly = -1;
513 static int hf_mysql_refresh = -1;
514 static int hf_mysql_rfsh_grants = -1;
515 static int hf_mysql_rfsh_log = -1;
516 static int hf_mysql_rfsh_tables = -1;
517 static int hf_mysql_rfsh_hosts = -1;
518 static int hf_mysql_rfsh_status = -1;
519 static int hf_mysql_rfsh_threads = -1;
520 static int hf_mysql_rfsh_slave = -1;
521 static int hf_mysql_rfsh_master = -1;
522 static int hf_mysql_packet_length = -1;
523 static int hf_mysql_packet_number = -1;
524 static int hf_mysql_request = -1;
525 static int hf_mysql_command = -1;
526 static int hf_mysql_response_code = -1;
527 static int hf_mysql_error_code = -1;
528 static int hf_mysql_error_string = -1;
529 static int hf_mysql_sqlstate = -1;
530 static int hf_mysql_message = -1;
531 static int hf_mysql_payload = -1;
532 static int hf_mysql_server_greeting = -1;
533 static int hf_mysql_session_track = -1;
534 static int hf_mysql_session_track_type = -1;
535 static int hf_mysql_session_track_length = -1;
536 static int hf_mysql_session_track_data = -1;
537 static int hf_mysql_session_track_data_length = -1;
538 static int hf_mysql_session_track_sysvar_length = -1;
539 static int hf_mysql_session_track_sysvar_name = -1;
540 static int hf_mysql_session_track_sysvar_value = -1;
541 static int hf_mysql_session_track_schema = -1;
542 static int hf_mysql_session_track_schema_length = -1;
543 static int hf_mysql_session_state_change = -1;
544 static int hf_mysql_protocol = -1;
545 static int hf_mysql_version  = -1;
546 static int hf_mysql_login_request = -1;
547 static int hf_mysql_max_packet = -1;
548 static int hf_mysql_user = -1;
549 static int hf_mysql_table_name = -1;
550 static int hf_mysql_schema = -1;
551 static int hf_mysql_client_auth_plugin = -1;
552 static int hf_mysql_connattrs = -1;
553 static int hf_mysql_connattrs_length = -1;
554 static int hf_mysql_connattrs_attr = -1;
555 static int hf_mysql_connattrs_name_length = -1;
556 static int hf_mysql_connattrs_name = -1;
557 static int hf_mysql_connattrs_value_length = -1;
558 static int hf_mysql_connattrs_value = -1;
559 static int hf_mysql_thread_id  = -1;
560 static int hf_mysql_salt = -1;
561 static int hf_mysql_salt2 = -1;
562 static int hf_mysql_auth_plugin_length = -1;
563 static int hf_mysql_auth_plugin = -1;
564 static int hf_mysql_charset = -1;
565 static int hf_mysql_passwd = -1;
566 static int hf_mysql_unused = -1;
567 static int hf_mysql_affected_rows = -1;
568 static int hf_mysql_insert_id = -1;
569 static int hf_mysql_num_warn = -1;
570 static int hf_mysql_thd_id = -1;
571 static int hf_mysql_stmt_id = -1;
572 static int hf_mysql_query = -1;
573 static int hf_mysql_shutdown = -1;
574 static int hf_mysql_option = -1;
575 static int hf_mysql_num_rows = -1;
576 static int hf_mysql_param = -1;
577 static int hf_mysql_num_params = -1;
578 static int hf_mysql_exec_flags4 = -1;
579 static int hf_mysql_exec_flags5 = -1;
580 static int hf_mysql_exec_iter = -1;
581 static int hf_mysql_binlog_position = -1;
582 static int hf_mysql_binlog_flags = -1;
583 static int hf_mysql_binlog_server_id = -1;
584 static int hf_mysql_binlog_file_name = -1;
585 static int hf_mysql_eof = -1;
586 static int hf_mysql_num_fields = -1;
587 static int hf_mysql_extra = -1;
588 static int hf_mysql_fld_catalog  = -1;
589 static int hf_mysql_fld_db = -1;
590 static int hf_mysql_fld_table = -1;
591 static int hf_mysql_fld_org_table = -1;
592 static int hf_mysql_fld_name = -1;
593 static int hf_mysql_fld_org_name = -1;
594 static int hf_mysql_fld_charsetnr = -1;
595 static int hf_mysql_fld_length = -1;
596 static int hf_mysql_fld_type = -1;
597 static int hf_mysql_fld_flags = -1;
598 static int hf_mysql_fld_not_null = -1;
599 static int hf_mysql_fld_primary_key = -1;
600 static int hf_mysql_fld_unique_key = -1;
601 static int hf_mysql_fld_multiple_key = -1;
602 static int hf_mysql_fld_blob = -1;
603 static int hf_mysql_fld_unsigned = -1;
604 static int hf_mysql_fld_zero_fill = -1;
605 static int hf_mysql_fld_binary = -1;
606 static int hf_mysql_fld_enum = -1;
607 static int hf_mysql_fld_auto_increment = -1;
608 static int hf_mysql_fld_timestamp = -1;
609 static int hf_mysql_fld_set = -1;
610 static int hf_mysql_fld_decimals = -1;
611 static int hf_mysql_fld_default = -1;
612 static int hf_mysql_row_text = -1;
613 static int hf_mysql_new_parameter_bound_flag = -1;
614 static int hf_mysql_exec_param = -1;
615 static int hf_mysql_exec_unsigned = -1;
616 static int hf_mysql_exec_field_longlong = -1;
617 static int hf_mysql_exec_field_string = -1;
618 static int hf_mysql_exec_field_double = -1;
619 static int hf_mysql_exec_field_datetime_length = -1;
620 static int hf_mysql_exec_field_year = -1;
621 static int hf_mysql_exec_field_month = -1;
622 static int hf_mysql_exec_field_day = -1;
623 static int hf_mysql_exec_field_hour = -1;
624 static int hf_mysql_exec_field_minute = -1;
625 static int hf_mysql_exec_field_second = -1;
626 static int hf_mysql_exec_field_second_b = -1;
627 static int hf_mysql_exec_field_long = -1;
628 static int hf_mysql_exec_field_tiny = -1;
629 static int hf_mysql_exec_field_short = -1;
630 static int hf_mysql_exec_field_float = -1;
631 static int hf_mysql_exec_field_time_length = -1;
632 static int hf_mysql_exec_field_time_sign = -1;
633 static int hf_mysql_exec_field_time_days = -1;
634 static int hf_mysql_auth_switch_request_status = -1;
635 static int hf_mysql_auth_switch_request_name = -1;
636 static int hf_mysql_auth_switch_request_data = -1;
637 static int hf_mysql_auth_switch_response_data = -1;
638 static int hf_mysql_compressed_packet_length = -1;
639 static int hf_mysql_compressed_packet_length_uncompressed = -1;
640 static int hf_mysql_compressed_packet_number = -1;
641
642 static dissector_handle_t mysql_handle;
643 static dissector_handle_t tls_handle;
644
645 static expert_field ei_mysql_eof = EI_INIT;
646 static expert_field ei_mysql_dissector_incomplete = EI_INIT;
647 static expert_field ei_mysql_streamed_param = EI_INIT;
648 static expert_field ei_mysql_prepare_response_needed = EI_INIT;
649 static expert_field ei_mysql_unknown_response = EI_INIT;
650 static expert_field ei_mysql_command = EI_INIT;
651
652 /* type constants */
653 static const value_string type_constants[] = {
654         {0x00, "FIELD_TYPE_DECIMAL"    },
655         {0x01, "FIELD_TYPE_TINY"       },
656         {0x02, "FIELD_TYPE_SHORT"      },
657         {0x03, "FIELD_TYPE_LONG"       },
658         {0x04, "FIELD_TYPE_FLOAT"      },
659         {0x05, "FIELD_TYPE_DOUBLE"     },
660         {0x06, "FIELD_TYPE_NULL"       },
661         {0x07, "FIELD_TYPE_TIMESTAMP"  },
662         {0x08, "FIELD_TYPE_LONGLONG"   },
663         {0x09, "FIELD_TYPE_INT24"      },
664         {0x0a, "FIELD_TYPE_DATE"       },
665         {0x0b, "FIELD_TYPE_TIME"       },
666         {0x0c, "FIELD_TYPE_DATETIME"   },
667         {0x0d, "FIELD_TYPE_YEAR"       },
668         {0x0e, "FIELD_TYPE_NEWDATE"    },
669         {0x0f, "FIELD_TYPE_VARCHAR"    },
670         {0x10, "FIELD_TYPE_BIT"        },
671         {0xf6, "FIELD_TYPE_NEWDECIMAL" },
672         {0xf7, "FIELD_TYPE_ENUM"       },
673         {0xf8, "FIELD_TYPE_SET"        },
674         {0xf9, "FIELD_TYPE_TINY_BLOB"  },
675         {0xfa, "FIELD_TYPE_MEDIUM_BLOB"},
676         {0xfb, "FIELD_TYPE_LONG_BLOB"  },
677         {0xfc, "FIELD_TYPE_BLOB"       },
678         {0xfd, "FIELD_TYPE_VAR_STRING" },
679         {0xfe, "FIELD_TYPE_STRING"     },
680         {0xff, "FIELD_TYPE_GEOMETRY"   },
681         {0, NULL}
682 };
683
684 typedef enum mysql_state {
685         UNDEFINED,
686         LOGIN,
687         REQUEST,
688         RESPONSE_OK,
689         RESPONSE_MESSAGE,
690         RESPONSE_TABULAR,
691         RESPONSE_SHOW_FIELDS,
692         FIELD_PACKET,
693         ROW_PACKET,
694         RESPONSE_PREPARE,
695         PREPARED_PARAMETERS,
696         PREPARED_FIELDS,
697         AUTH_SWITCH_REQUEST,
698         AUTH_SWITCH_RESPONSE
699 } mysql_state_t;
700
701 #ifdef CTDEBUG
702 static const value_string state_vals[] = {
703         {UNDEFINED,            "undefined"},
704         {LOGIN,                "login"},
705         {REQUEST,              "request"},
706         {RESPONSE_OK,          "response OK"},
707         {RESPONSE_MESSAGE,     "response message"},
708         {RESPONSE_TABULAR,     "tabular response"},
709         {RESPONSE_SHOW_FIELDS, "response to SHOW FIELDS"},
710         {FIELD_PACKET,         "field packet"},
711         {ROW_PACKET,           "row packet"},
712         {RESPONSE_PREPARE,     "response to PREPARE"},
713         {PREPARED_PARAMETERS,  "parameters in response to PREPARE"},
714         {PREPARED_FIELDS,      "fields in response to PREPARE"},
715         {AUTH_SWITCH_REQUEST,  "authentication switch request"},
716         {AUTH_SWITCH_RESPONSE, "authentication switch response"},
717         {0, NULL}
718 };
719 #endif
720
721 typedef struct mysql_conn_data {
722         guint16 srv_caps;
723         guint16 srv_caps_ext;
724         guint16 clnt_caps;
725         guint16 clnt_caps_ext;
726         mysql_state_t state;
727         guint16 stmt_num_params;
728         guint16 stmt_num_fields;
729         wmem_tree_t* stmts;
730 #ifdef CTDEBUG
731         guint32 generation;
732 #endif
733         guint8 major_version;
734         guint32 frame_start_ssl;
735         guint32 frame_start_compressed;
736         guint8 compressed_state;
737 } mysql_conn_data_t;
738
739 struct mysql_frame_data {
740         mysql_state_t state;
741 };
742
743 typedef struct my_stmt_data {
744         guint16 nparam;
745         guint8* param_flags;
746 } my_stmt_data_t;
747
748 typedef struct mysql_exec_dissector {
749         guint8 type;
750         guint8 unsigned_flag;
751         void (*dissector)(tvbuff_t *tvb, int *param_offset, proto_item *field_tree);
752 } mysql_exec_dissector_t;
753
754 /* function prototypes */
755 static int mysql_dissect_error_packet(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree);
756 static int mysql_dissect_ok_packet(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data);
757 static int mysql_dissect_server_status(tvbuff_t *tvb, int offset, proto_tree *tree, guint16 *server_status);
758 static int mysql_dissect_caps(tvbuff_t *tvb, int offset, proto_tree *tree, int mysql_caps, guint16 *caps);
759 static int mysql_dissect_extcaps(tvbuff_t *tvb, int offset, proto_tree *tree, int mysql_extcaps, guint16 *caps);
760 static int mysql_dissect_result_header(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data);
761 static int mysql_dissect_field_packet(tvbuff_t *tvb, int offset, proto_tree *tree, mysql_conn_data_t *conn_data);
762 static int mysql_dissect_row_packet(tvbuff_t *tvb, int offset, proto_tree *tree);
763 static int mysql_dissect_response_prepare(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data);
764 static int mysql_dissect_auth_switch_request(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data);
765 static int mysql_dissect_auth_switch_response(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data);
766 static void mysql_dissect_exec_string(tvbuff_t *tvb, int *param_offset, proto_item *field_tree);
767 static void mysql_dissect_exec_datetime(tvbuff_t *tvb, int *param_offset, proto_item *field_tree);
768 static void mysql_dissect_exec_tiny(tvbuff_t *tvb, int *param_offset, proto_item *field_tree);
769 static void mysql_dissect_exec_short(tvbuff_t *tvb, int *param_offset, proto_item *field_tree);
770 static void mysql_dissect_exec_long(tvbuff_t *tvb, int *param_offset, proto_item *field_tree);
771 static void mysql_dissect_exec_float(tvbuff_t *tvb, int *param_offset, proto_item *field_tree);
772 static void mysql_dissect_exec_double(tvbuff_t *tvb, int *param_offset, proto_item *field_tree);
773 static void mysql_dissect_exec_longlong(tvbuff_t *tvb, int *param_offset, proto_item *field_tree);
774 static void mysql_dissect_exec_null(tvbuff_t *tvb, int *param_offset, proto_item *field_tree);
775 static char mysql_dissect_exec_param(proto_item *req_tree, tvbuff_t *tvb, int *offset,
776                 int *param_offset, guint8 param_flags, packet_info *pinfo);
777 static void mysql_dissect_exec_primitive(tvbuff_t *tvb, int *param_offset,
778                 proto_item *field_tree, const int hfindex, const int offset);
779 static void mysql_dissect_exec_time(tvbuff_t *tvb, int *param_offset, proto_item *field_tree);
780
781 static gint my_tvb_strsize(tvbuff_t *tvb, int offset);
782 static int tvb_get_fle(tvbuff_t *tvb, int offset, guint64 *res, guint8 *is_null);
783
784 static const mysql_exec_dissector_t mysql_exec_dissectors[] = {
785         { 0x01, 0, mysql_dissect_exec_tiny },
786         { 0x02, 0, mysql_dissect_exec_short },
787         { 0x03, 0, mysql_dissect_exec_long },
788         { 0x04, 0, mysql_dissect_exec_float },
789         { 0x05, 0, mysql_dissect_exec_double },
790         { 0x06, 0, mysql_dissect_exec_null },
791         { 0x07, 0, mysql_dissect_exec_datetime },
792         { 0x08, 0, mysql_dissect_exec_longlong },
793         { 0x0a, 0, mysql_dissect_exec_datetime },
794         { 0x0b, 0, mysql_dissect_exec_time },
795         { 0x0c, 0, mysql_dissect_exec_datetime },
796         { 0xf6, 0, mysql_dissect_exec_string },
797         { 0xfc, 0, mysql_dissect_exec_string },
798         { 0xfd, 0, mysql_dissect_exec_string },
799         { 0xfe, 0, mysql_dissect_exec_string },
800         { 0x00, 0, NULL },
801 };
802
803 static const int *mysql_rfsh_flags[] = {
804         &hf_mysql_rfsh_grants,
805         &hf_mysql_rfsh_log,
806         &hf_mysql_rfsh_tables,
807         &hf_mysql_rfsh_hosts,
808         &hf_mysql_rfsh_status,
809         &hf_mysql_rfsh_threads,
810         &hf_mysql_rfsh_slave,
811         &hf_mysql_rfsh_master,
812         NULL
813 };
814
815 static const int *mysql_stat_flags[] = {
816         &hf_mysql_stat_it,
817         &hf_mysql_stat_ac,
818         &hf_mysql_stat_mu,
819         &hf_mysql_stat_mr,
820         &hf_mysql_stat_bi,
821         &hf_mysql_stat_ni,
822         &hf_mysql_stat_cr,
823         &hf_mysql_stat_lr,
824         &hf_mysql_stat_dr,
825         &hf_mysql_stat_bs,
826         &hf_mysql_stat_mc,
827         &hf_mysql_stat_query_was_slow,
828         &hf_mysql_stat_ps_out_params,
829         &hf_mysql_stat_trans_readonly,
830         &hf_mysql_stat_session_state_changed,
831         NULL
832 };
833
834 static const int *mysql_caps_flags[] = {
835         &hf_mysql_cap_long_password,
836         &hf_mysql_cap_found_rows,
837         &hf_mysql_cap_long_flag,
838         &hf_mysql_cap_connect_with_db,
839         &hf_mysql_cap_no_schema,
840         &hf_mysql_cap_compress,
841         &hf_mysql_cap_odbc,
842         &hf_mysql_cap_local_files,
843         &hf_mysql_cap_ignore_space,
844         &hf_mysql_cap_change_user,
845         &hf_mysql_cap_interactive,
846         &hf_mysql_cap_ssl,
847         &hf_mysql_cap_ignore_sigpipe,
848         &hf_mysql_cap_transactions,
849         &hf_mysql_cap_reserved,
850         &hf_mysql_cap_secure_connect,
851         NULL
852 };
853
854 static const int * mysql_extcaps_flags[] = {
855         &hf_mysql_cap_multi_statements,
856         &hf_mysql_cap_multi_results,
857         &hf_mysql_cap_ps_multi_results,
858         &hf_mysql_cap_plugin_auth,
859         &hf_mysql_cap_connect_attrs,
860         &hf_mysql_cap_plugin_auth_lenenc_client_data,
861         &hf_mysql_cap_client_can_handle_expired_passwords,
862         &hf_mysql_cap_session_track,
863         &hf_mysql_cap_deprecate_eof,
864         &hf_mysql_cap_unused,
865         NULL
866 };
867
868 static const int * mysql_fld_flags[] = {
869         &hf_mysql_fld_not_null,
870         &hf_mysql_fld_primary_key,
871         &hf_mysql_fld_unique_key,
872         &hf_mysql_fld_multiple_key,
873         &hf_mysql_fld_blob,
874         &hf_mysql_fld_unsigned,
875         &hf_mysql_fld_zero_fill,
876         &hf_mysql_fld_binary,
877         &hf_mysql_fld_enum,
878         &hf_mysql_fld_auto_increment,
879         &hf_mysql_fld_timestamp,
880         &hf_mysql_fld_set,
881         NULL
882 };
883
884 /* Helper function to only set state on first pass */
885 static void mysql_set_conn_state(packet_info *pinfo, mysql_conn_data_t *conn_data, mysql_state_t state)
886 {
887         if (!pinfo->fd->visited)
888         {
889                 conn_data->state = state;
890         }
891 }
892
893 static int
894 mysql_dissect_greeting(tvbuff_t *tvb, packet_info *pinfo, int offset,
895                        proto_tree *tree, mysql_conn_data_t *conn_data)
896 {
897         gint protocol;
898         gint lenstr;
899         int ver_offset;
900
901         proto_item *tf;
902         proto_item *greeting_tree;
903
904         protocol= tvb_get_guint8(tvb, offset);
905
906         if (protocol == 0xff) {
907                 return mysql_dissect_error_packet(tvb, pinfo, offset+1, tree);
908         }
909
910         mysql_set_conn_state(pinfo, conn_data, LOGIN);
911
912         tf = proto_tree_add_item(tree, hf_mysql_server_greeting, tvb, offset, -1, ENC_NA);
913         greeting_tree = proto_item_add_subtree(tf, ett_server_greeting);
914
915         col_append_fstr(pinfo->cinfo, COL_INFO, " proto=%d", protocol) ;
916
917         proto_tree_add_item(greeting_tree, hf_mysql_protocol, tvb, offset, 1, ENC_NA);
918
919         offset += 1;
920
921         /* version string */
922         lenstr = tvb_strsize(tvb,offset);
923         col_append_fstr(pinfo->cinfo, COL_INFO, " version=%s",
924                         tvb_format_text(tvb, offset, lenstr-1));
925
926         proto_tree_add_item(greeting_tree, hf_mysql_version, tvb, offset, lenstr, ENC_ASCII|ENC_NA);
927         conn_data->major_version = 0;
928         for (ver_offset = 0; ver_offset < lenstr; ver_offset++) {
929                 guint8 ver_char = tvb_get_guint8(tvb, offset + ver_offset);
930                 if (ver_char == '.') break;
931                 conn_data->major_version = conn_data->major_version * 10 + ver_char - '0';
932         }
933         offset += lenstr;
934
935         /* 4 bytes little endian thread_id */
936         proto_tree_add_item(greeting_tree, hf_mysql_thread_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
937         offset += 4;
938
939         /* salt string */
940         lenstr = tvb_strsize(tvb,offset);
941         proto_tree_add_item(greeting_tree, hf_mysql_salt, tvb, offset, lenstr, ENC_ASCII|ENC_NA);
942         offset += lenstr;
943
944         /* rest is optional */
945         if (!tvb_reported_length_remaining(tvb, offset)) return offset;
946
947         /* 2 bytes CAPS */
948         offset = mysql_dissect_caps(tvb, offset, greeting_tree, hf_mysql_caps_server, &conn_data->srv_caps);
949
950         /* rest is optional */
951         if (!tvb_reported_length_remaining(tvb, offset)) return offset;
952
953         proto_tree_add_item(greeting_tree, hf_mysql_server_language, tvb, offset, 1, ENC_NA);
954         offset += 1; /* for charset */
955
956         offset = mysql_dissect_server_status(tvb, offset, greeting_tree, NULL);
957
958         /* 2 bytes ExtCAPS */
959         offset = mysql_dissect_extcaps(tvb, offset, greeting_tree, hf_mysql_extcaps_server, &conn_data->srv_caps_ext);
960
961         /* 1 byte Auth Plugin Length */
962         proto_tree_add_item(greeting_tree, hf_mysql_auth_plugin_length, tvb, offset, 1, ENC_NA);
963         offset += 1;
964
965         /* 10 bytes unused */
966         proto_tree_add_item(greeting_tree, hf_mysql_unused, tvb, offset, 10, ENC_NA);
967         offset += 10;
968
969         /* 4.1+ server: rest of salt */
970         if (tvb_reported_length_remaining(tvb, offset)) {
971                 lenstr = tvb_strsize(tvb,offset);
972                 proto_tree_add_item(greeting_tree, hf_mysql_salt2, tvb, offset, lenstr, ENC_ASCII|ENC_NA);
973                 offset += lenstr;
974         }
975
976         /* 5.x server: auth plugin */
977         if (tvb_reported_length_remaining(tvb, offset)) {
978                 lenstr = tvb_strsize(tvb,offset);
979                 proto_tree_add_item(greeting_tree, hf_mysql_auth_plugin, tvb, offset, lenstr, ENC_ASCII|ENC_NA);
980                 offset += lenstr;
981         }
982
983         return offset;
984 }
985
986
987 /*
988   Add a connect attributs entry to the connattrs subtree
989
990   return bytes read
991 */
992 static int
993 add_connattrs_entry_to_tree(tvbuff_t *tvb, packet_info *pinfo _U_, proto_item *tree, int offset) {
994         guint64 lenstr;
995         int orig_offset = offset, lenfle;
996         proto_item *ti;
997         proto_tree *connattrs_tree;
998         const guint8 *str;
999
1000         ti = proto_tree_add_item(tree, hf_mysql_connattrs_attr, tvb, offset, 1, ENC_NA);
1001         connattrs_tree = proto_item_add_subtree(ti, ett_connattrs_attr);
1002
1003         lenfle = tvb_get_fle(tvb, offset, &lenstr, NULL);
1004         proto_tree_add_uint64(connattrs_tree, hf_mysql_connattrs_name_length, tvb, offset, lenfle, lenstr);
1005         offset += lenfle;
1006
1007         proto_tree_add_item_ret_string(connattrs_tree, hf_mysql_connattrs_name, tvb, offset, (gint)lenstr, ENC_ASCII|ENC_NA, wmem_packet_scope(), &str);
1008         proto_item_append_text(ti, " - %s", str);
1009         offset += (int)lenstr;
1010
1011         lenfle = tvb_get_fle(tvb, offset, &lenstr, NULL);
1012         proto_tree_add_uint64(connattrs_tree, hf_mysql_connattrs_value_length, tvb, offset, lenfle, lenstr);
1013         offset += lenfle;
1014
1015         proto_tree_add_item_ret_string(connattrs_tree, hf_mysql_connattrs_value, tvb, offset, (gint)lenstr, ENC_ASCII|ENC_NA, wmem_packet_scope(), &str);
1016         proto_item_append_text(ti, ": %s", str);
1017         offset += (int)lenstr;
1018
1019         proto_item_set_len(ti, offset - orig_offset);
1020
1021         return (offset - orig_offset);
1022 }
1023
1024 static int
1025 mysql_dissect_login(tvbuff_t *tvb, packet_info *pinfo, int offset,
1026                     proto_tree *tree, mysql_conn_data_t *conn_data)
1027 {
1028         gint lenstr;
1029
1030         proto_item *tf;
1031         proto_item *login_tree;
1032
1033         /* after login there can be OK or DENIED */
1034         mysql_set_conn_state(pinfo, conn_data, RESPONSE_OK);
1035
1036         tf = proto_tree_add_item(tree, hf_mysql_login_request, tvb, offset, -1, ENC_NA);
1037         login_tree = proto_item_add_subtree(tf, ett_login_request);
1038
1039         offset = mysql_dissect_caps(tvb, offset, login_tree, hf_mysql_caps_client, &conn_data->clnt_caps);
1040
1041         if (!(conn_data->frame_start_ssl) && conn_data->clnt_caps & MYSQL_CAPS_SL) /* Next packet will be use SSL */
1042         {
1043                 col_set_str(pinfo->cinfo, COL_INFO, "Response: SSL Handshake");
1044                 conn_data->frame_start_ssl = pinfo->num;
1045                 ssl_starttls_ack(tls_handle, pinfo, mysql_handle);
1046         }
1047         if (conn_data->clnt_caps & MYSQL_CAPS_CU) /* 4.1 protocol */
1048         {
1049                 offset = mysql_dissect_extcaps(tvb, offset, login_tree, hf_mysql_extcaps_client, &conn_data->clnt_caps_ext);
1050
1051                 proto_tree_add_item(login_tree, hf_mysql_max_packet, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1052                 offset += 4;
1053
1054                 proto_tree_add_item(login_tree, hf_mysql_charset, tvb, offset, 1, ENC_NA);
1055                 offset += 1; /* for charset */
1056
1057                 offset += 23; /* filler bytes */
1058
1059         } else { /* pre-4.1 */
1060                 proto_tree_add_item(login_tree, hf_mysql_max_packet, tvb, offset, 3, ENC_LITTLE_ENDIAN);
1061                 offset += 3;
1062         }
1063
1064         /* User name */
1065         lenstr = my_tvb_strsize(tvb, offset);
1066         col_append_fstr(pinfo->cinfo, COL_INFO, " user=%s",
1067                         tvb_format_text(tvb, offset, lenstr-1));
1068         proto_tree_add_item(login_tree, hf_mysql_user, tvb, offset, lenstr, ENC_ASCII|ENC_NA);
1069         offset += lenstr;
1070
1071         /* rest is optional */
1072         if (!tvb_reported_length_remaining(tvb, offset)) return offset;
1073
1074         /* password: asciiz or length+ascii */
1075         if (conn_data->clnt_caps & MYSQL_CAPS_SC) {
1076                 lenstr = tvb_get_guint8(tvb, offset);
1077                 offset += 1;
1078         } else {
1079                 lenstr = my_tvb_strsize(tvb, offset);
1080         }
1081         if (tree && lenstr > 1) {
1082                 proto_tree_add_item(login_tree, hf_mysql_passwd, tvb, offset, lenstr, ENC_NA);
1083         }
1084         offset += lenstr;
1085
1086         /* optional: initial schema */
1087         if (conn_data->clnt_caps & MYSQL_CAPS_CD)
1088         {
1089                 lenstr= my_tvb_strsize(tvb,offset);
1090                 if(lenstr<0){
1091                         return offset;
1092                 }
1093
1094                 col_append_fstr(pinfo->cinfo, COL_INFO, " db=%s",
1095                         tvb_format_text(tvb, offset, lenstr-1));
1096
1097                 proto_tree_add_item(login_tree, hf_mysql_schema, tvb, offset, lenstr, ENC_ASCII|ENC_NA);
1098                 offset += lenstr;
1099         }
1100
1101         /* optional: authentication plugin */
1102         if (conn_data->clnt_caps_ext & MYSQL_CAPS_PA)
1103         {
1104                 mysql_set_conn_state(pinfo, conn_data, AUTH_SWITCH_REQUEST);
1105                 lenstr= my_tvb_strsize(tvb,offset);
1106                 proto_tree_add_item(login_tree, hf_mysql_client_auth_plugin, tvb, offset, lenstr, ENC_ASCII|ENC_NA);
1107                 offset += lenstr;
1108         }
1109
1110         /* optional: connection attributes */
1111         if (conn_data->clnt_caps_ext & MYSQL_CAPS_CA && tvb_reported_length_remaining(tvb, offset))
1112         {
1113                 proto_tree *connattrs_tree;
1114                 int lenfle;
1115                 guint64 connattrs_length;
1116                 int length;
1117
1118                 lenfle = tvb_get_fle(tvb, offset, &connattrs_length, NULL);
1119                 tf = proto_tree_add_item(login_tree, hf_mysql_connattrs, tvb, offset, (guint32)connattrs_length, ENC_NA);
1120                 connattrs_tree = proto_item_add_subtree(tf, ett_connattrs);
1121                 proto_tree_add_uint64(connattrs_tree, hf_mysql_connattrs_length, tvb, offset, lenfle, connattrs_length);
1122                 offset += lenfle;
1123
1124                 while (connattrs_length > 0) {
1125                         length = add_connattrs_entry_to_tree(tvb, pinfo, connattrs_tree, offset);
1126                         offset += length;
1127                         connattrs_length -= length;
1128                 }
1129         }
1130
1131         return offset;
1132 }
1133
1134
1135 static void
1136 mysql_dissect_exec_string(tvbuff_t *tvb, int *param_offset, proto_item *field_tree)
1137 {
1138         guint32 param_len32;
1139         guint8 param_len;
1140
1141         param_len = tvb_get_guint8(tvb, *param_offset);
1142
1143         switch (param_len) {
1144                 case 0xfc: /* 252 - 64k chars */
1145                         *param_offset += 1;
1146                         param_len32 = tvb_get_letohs(tvb, *param_offset);
1147                         proto_tree_add_item(field_tree, hf_mysql_exec_field_string,
1148                                             tvb, *param_offset, 2, ENC_ASCII | ENC_LITTLE_ENDIAN);
1149                         *param_offset += param_len32 + 2;
1150                         break;
1151                 case 0xfd: /* 64k - 16M chars */
1152                         *param_offset += 1;
1153                         param_len32 = tvb_get_letoh24(tvb, *param_offset);
1154                         proto_tree_add_item(field_tree, hf_mysql_exec_field_string,
1155                                             tvb, *param_offset, 3, ENC_ASCII | ENC_LITTLE_ENDIAN);
1156                         *param_offset += param_len32 + 3;
1157                         break;
1158                 default: /* < 252 chars */
1159                         proto_tree_add_item(field_tree, hf_mysql_exec_field_string,
1160                                             tvb, *param_offset, 1, ENC_ASCII | ENC_NA);
1161                         *param_offset += param_len + 1;
1162                         break;
1163         }
1164 }
1165
1166 static void
1167 mysql_dissect_exec_time(tvbuff_t *tvb, int *param_offset, proto_item *field_tree)
1168 {
1169         guint8 param_len;
1170
1171         param_len = tvb_get_guint8(tvb, *param_offset);
1172         proto_tree_add_item(field_tree, hf_mysql_exec_field_time_length,
1173                             tvb, *param_offset, 1, ENC_NA);
1174         *param_offset += 1;
1175         if (param_len >= 1) {
1176                 proto_tree_add_item(field_tree, hf_mysql_exec_field_time_sign,
1177                                     tvb, *param_offset, 1, ENC_NA);
1178         }
1179         if (param_len >= 5) {
1180                 proto_tree_add_item(field_tree, hf_mysql_exec_field_time_days,
1181                                     tvb, *param_offset + 1, 4, ENC_LITTLE_ENDIAN);
1182         }
1183         if (param_len >= 8) {
1184                 proto_tree_add_item(field_tree, hf_mysql_exec_field_hour,
1185                                     tvb, *param_offset + 5, 1, ENC_NA);
1186                 proto_tree_add_item(field_tree, hf_mysql_exec_field_minute,
1187                                     tvb, *param_offset + 6, 1, ENC_NA);
1188                 proto_tree_add_item(field_tree, hf_mysql_exec_field_second,
1189                                     tvb, *param_offset + 7, 1, ENC_NA);
1190         }
1191         if (param_len >= 12) {
1192                 proto_tree_add_item(field_tree, hf_mysql_exec_field_second_b,
1193                                     tvb, *param_offset + 8, 4, ENC_LITTLE_ENDIAN);
1194         }
1195         *param_offset += param_len;
1196 }
1197
1198 static void
1199 mysql_dissect_exec_datetime(tvbuff_t *tvb, int *param_offset, proto_item *field_tree)
1200 {
1201         guint8 param_len;
1202
1203         param_len = tvb_get_guint8(tvb, *param_offset);
1204         proto_tree_add_item(field_tree, hf_mysql_exec_field_datetime_length,
1205                             tvb, *param_offset, 1, ENC_NA);
1206         *param_offset += 1;
1207         if (param_len >= 2) {
1208                 proto_tree_add_item(field_tree, hf_mysql_exec_field_year,
1209                                     tvb, *param_offset, 2, ENC_LITTLE_ENDIAN);
1210         }
1211         if (param_len >= 4) {
1212                 proto_tree_add_item(field_tree, hf_mysql_exec_field_month,
1213                                     tvb, *param_offset + 2, 1, ENC_NA);
1214                 proto_tree_add_item(field_tree, hf_mysql_exec_field_day,
1215                                     tvb, *param_offset + 3, 1, ENC_NA);
1216         }
1217         if (param_len >= 7) {
1218                 proto_tree_add_item(field_tree, hf_mysql_exec_field_hour,
1219                                     tvb, *param_offset + 4, 1, ENC_NA);
1220                 proto_tree_add_item(field_tree, hf_mysql_exec_field_minute,
1221                                     tvb, *param_offset + 5, 1, ENC_NA);
1222                 proto_tree_add_item(field_tree, hf_mysql_exec_field_second,
1223                                     tvb, *param_offset + 6, 1, ENC_NA);
1224         }
1225         if (param_len >= 11) {
1226                 proto_tree_add_item(field_tree, hf_mysql_exec_field_second_b,
1227                                     tvb, *param_offset + 7, 4, ENC_LITTLE_ENDIAN);
1228         }
1229         *param_offset += param_len;
1230 }
1231
1232 static void
1233 mysql_dissect_exec_primitive(tvbuff_t *tvb, int *param_offset,
1234                              proto_item *field_tree, const int hfindex,
1235                              const int offset)
1236 {
1237         proto_tree_add_item(field_tree, hfindex, tvb,
1238                             *param_offset, offset, ENC_LITTLE_ENDIAN);
1239         *param_offset += offset;
1240 }
1241
1242 static void
1243 mysql_dissect_exec_tiny(tvbuff_t *tvb, int *param_offset, proto_item *field_tree)
1244 {
1245         mysql_dissect_exec_primitive(tvb, param_offset, field_tree, hf_mysql_exec_field_tiny, 1);
1246 }
1247
1248 static void
1249 mysql_dissect_exec_short(tvbuff_t *tvb, int *param_offset, proto_item *field_tree)
1250 {
1251         mysql_dissect_exec_primitive(tvb, param_offset, field_tree, hf_mysql_exec_field_short, 2);
1252 }
1253
1254 static void
1255 mysql_dissect_exec_long(tvbuff_t *tvb, int *param_offset, proto_item *field_tree)
1256 {
1257         mysql_dissect_exec_primitive(tvb, param_offset, field_tree, hf_mysql_exec_field_long, 4);
1258 }
1259
1260 static void
1261 mysql_dissect_exec_float(tvbuff_t *tvb, int *param_offset, proto_item *field_tree)
1262 {
1263         mysql_dissect_exec_primitive(tvb, param_offset, field_tree, hf_mysql_exec_field_float, 4);
1264 }
1265
1266 static void
1267 mysql_dissect_exec_double(tvbuff_t *tvb, int *param_offset, proto_item *field_tree)
1268 {
1269         mysql_dissect_exec_primitive(tvb, param_offset, field_tree, hf_mysql_exec_field_double, 8);
1270 }
1271
1272 static void
1273 mysql_dissect_exec_longlong(tvbuff_t *tvb, int *param_offset, proto_item *field_tree)
1274 {
1275         mysql_dissect_exec_primitive(tvb, param_offset, field_tree, hf_mysql_exec_field_longlong, 8);
1276 }
1277
1278 static void
1279 mysql_dissect_exec_null(tvbuff_t *tvb _U_, int *param_offset _U_, proto_item *field_tree _U_)
1280 {}
1281
1282 static char
1283 mysql_dissect_exec_param(proto_item *req_tree, tvbuff_t *tvb, int *offset,
1284                          int *param_offset, guint8 param_flags,
1285                          packet_info *pinfo)
1286 {
1287         guint8 param_type, param_unsigned;
1288         proto_item *tf;
1289         proto_item *field_tree;
1290         int dissector_index = 0;
1291
1292         tf = proto_tree_add_item(req_tree, hf_mysql_exec_param, tvb, *offset, 2, ENC_NA);
1293         field_tree = proto_item_add_subtree(tf, ett_stat);
1294         proto_tree_add_item(field_tree, hf_mysql_fld_type, tvb, *offset, 1, ENC_NA);
1295         param_type = tvb_get_guint8(tvb, *offset);
1296         *offset += 1; /* type */
1297         proto_tree_add_item(field_tree, hf_mysql_exec_unsigned, tvb, *offset, 1, ENC_NA);
1298         param_unsigned = tvb_get_guint8(tvb, *offset);
1299         *offset += 1; /* signedness */
1300         if ((param_flags & MYSQL_PARAM_FLAG_STREAMED) == MYSQL_PARAM_FLAG_STREAMED) {
1301                 expert_add_info(pinfo, field_tree, &ei_mysql_streamed_param);
1302                 return 1;
1303         }
1304         while (mysql_exec_dissectors[dissector_index].dissector != NULL) {
1305                 if (mysql_exec_dissectors[dissector_index].type == param_type &&
1306                     mysql_exec_dissectors[dissector_index].unsigned_flag == param_unsigned) {
1307                         mysql_exec_dissectors[dissector_index].dissector(tvb, param_offset, field_tree);
1308                         return 1;
1309                 }
1310                 dissector_index++;
1311         }
1312         return 0;
1313 }
1314
1315 static int
1316 mysql_dissect_request(tvbuff_t *tvb,packet_info *pinfo, int offset,
1317                       proto_tree *tree, mysql_conn_data_t *conn_data, mysql_state_t current_state)
1318 {
1319         gint opcode;
1320         gint lenstr;
1321         proto_item *request_item, *tf = NULL, *ti;
1322         proto_item *req_tree;
1323         guint32 stmt_id;
1324         my_stmt_data_t *stmt_data;
1325         int stmt_pos, param_offset;
1326
1327         if(current_state == AUTH_SWITCH_RESPONSE){
1328                 return mysql_dissect_auth_switch_response(tvb, pinfo, offset, tree, conn_data);
1329         }
1330
1331         request_item = proto_tree_add_item(tree, hf_mysql_request, tvb, offset, -1, ENC_NA);
1332         req_tree = proto_item_add_subtree(request_item, ett_request);
1333
1334         opcode = tvb_get_guint8(tvb, offset);
1335         col_append_fstr(pinfo->cinfo, COL_INFO, " %s", val_to_str_ext(opcode, &mysql_command_vals_ext, "Unknown (%u)"));
1336
1337         proto_tree_add_item(req_tree, hf_mysql_command, tvb, offset, 1, ENC_NA);
1338         proto_item_append_text(request_item, " %s", val_to_str_ext(opcode, &mysql_command_vals_ext, "Unknown (%u)"));
1339         offset += 1;
1340
1341
1342         switch (opcode) {
1343
1344         case MYSQL_QUIT:
1345                 break;
1346
1347         case MYSQL_PROCESS_INFO:
1348                 mysql_set_conn_state(pinfo, conn_data, RESPONSE_TABULAR);
1349                 break;
1350
1351         case MYSQL_DEBUG:
1352         case MYSQL_PING:
1353                 mysql_set_conn_state(pinfo, conn_data, RESPONSE_OK);
1354                 break;
1355
1356         case MYSQL_STATISTICS:
1357                 mysql_set_conn_state(pinfo, conn_data, RESPONSE_MESSAGE);
1358                 break;
1359
1360         case MYSQL_INIT_DB:
1361         case MYSQL_CREATE_DB:
1362         case MYSQL_DROP_DB:
1363                 lenstr = my_tvb_strsize(tvb, offset);
1364                 proto_tree_add_item(req_tree, hf_mysql_schema, tvb, offset, lenstr, ENC_ASCII|ENC_NA);
1365                 offset += lenstr;
1366                 mysql_set_conn_state(pinfo, conn_data, RESPONSE_OK);
1367                 break;
1368
1369         case MYSQL_QUERY:
1370                 lenstr = my_tvb_strsize(tvb, offset);
1371                 proto_tree_add_item(req_tree, hf_mysql_query, tvb, offset, lenstr, ENC_ASCII|ENC_NA);
1372                 if (mysql_showquery) {
1373                         col_append_fstr(pinfo->cinfo, COL_INFO, " { %s } ",
1374                                         tvb_format_text(tvb, offset, lenstr));
1375                 }
1376                 offset += lenstr;
1377                 mysql_set_conn_state(pinfo, conn_data, RESPONSE_TABULAR);
1378                 break;
1379
1380         case MYSQL_STMT_PREPARE:
1381                 lenstr = my_tvb_strsize(tvb, offset);
1382                 proto_tree_add_item(req_tree, hf_mysql_query, tvb, offset, lenstr, ENC_ASCII|ENC_NA);
1383                 offset += lenstr;
1384                 mysql_set_conn_state(pinfo, conn_data, RESPONSE_PREPARE);
1385                 break;
1386
1387         case MYSQL_STMT_CLOSE:
1388                 proto_tree_add_item(req_tree, hf_mysql_stmt_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1389                 offset += 4;
1390                 mysql_set_conn_state(pinfo, conn_data, REQUEST);
1391                 break;
1392
1393         case MYSQL_STMT_RESET:
1394                 proto_tree_add_item(req_tree, hf_mysql_stmt_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1395                 offset += 4;
1396                 mysql_set_conn_state(pinfo, conn_data, RESPONSE_OK);
1397                 break;
1398
1399         case MYSQL_FIELD_LIST:
1400                 lenstr = my_tvb_strsize(tvb, offset);
1401                 proto_tree_add_item(req_tree, hf_mysql_table_name, tvb,  offset, lenstr, ENC_ASCII|ENC_NA);
1402                 offset += lenstr;
1403                 mysql_set_conn_state(pinfo, conn_data, RESPONSE_SHOW_FIELDS);
1404                 break;
1405
1406         case MYSQL_PROCESS_KILL:
1407                 proto_tree_add_item(req_tree, hf_mysql_thd_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1408                 offset += 4;
1409                 mysql_set_conn_state(pinfo, conn_data, RESPONSE_OK);
1410                 break;
1411
1412         case MYSQL_CHANGE_USER:
1413                 lenstr = tvb_strsize(tvb, offset);
1414                 proto_tree_add_item(req_tree, hf_mysql_user, tvb,  offset, lenstr, ENC_ASCII|ENC_NA);
1415                 offset += lenstr;
1416
1417                 if (conn_data->clnt_caps & MYSQL_CAPS_SC) {
1418                         lenstr = tvb_get_guint8(tvb, offset);
1419                         offset += 1;
1420                 } else {
1421                         lenstr = tvb_strsize(tvb, offset);
1422                 }
1423                 proto_tree_add_item(req_tree, hf_mysql_passwd, tvb, offset, lenstr, ENC_NA);
1424                 offset += lenstr;
1425
1426                 lenstr = my_tvb_strsize(tvb, offset);
1427                 proto_tree_add_item(req_tree, hf_mysql_schema, tvb, offset, lenstr, ENC_ASCII|ENC_NA);
1428                 offset += lenstr;
1429
1430                 if (tvb_reported_length_remaining(tvb, offset) > 0) {
1431                         proto_tree_add_item(req_tree, hf_mysql_charset, tvb, offset, 1, ENC_NA);
1432                         offset += 2; /* for charset */
1433                 }
1434                 mysql_set_conn_state(pinfo, conn_data, RESPONSE_OK);
1435
1436                 /* optional: authentication plugin */
1437                 if (conn_data->clnt_caps_ext & MYSQL_CAPS_PA)
1438                 {
1439                         mysql_set_conn_state(pinfo, conn_data, AUTH_SWITCH_REQUEST);
1440                         lenstr= my_tvb_strsize(tvb,offset);
1441                         proto_tree_add_item(req_tree, hf_mysql_client_auth_plugin, tvb, offset, lenstr, ENC_ASCII|ENC_NA);
1442                         offset += lenstr;
1443                 }
1444
1445                 /* optional: connection attributes */
1446                 if (conn_data->clnt_caps_ext & MYSQL_CAPS_CA)
1447                 {
1448                         proto_tree *connattrs_tree;
1449                         int lenfle;
1450                         guint64 connattrs_length;
1451                         int length;
1452
1453                         lenfle = tvb_get_fle(tvb, offset, &connattrs_length, NULL);
1454                         tf = proto_tree_add_item(req_tree, hf_mysql_connattrs, tvb, offset, (guint32)connattrs_length, ENC_NA);
1455                         connattrs_tree = proto_item_add_subtree(tf, ett_connattrs);
1456                         proto_tree_add_uint64(connattrs_tree, hf_mysql_connattrs_length, tvb, offset, lenfle, connattrs_length);
1457                         offset += lenfle;
1458
1459                         while (connattrs_length > 0) {
1460                                 length = add_connattrs_entry_to_tree(tvb, pinfo, connattrs_tree, offset);
1461                                 offset += length;
1462                                 connattrs_length -= length;
1463                         }
1464                 }
1465                 break;
1466
1467         case MYSQL_REFRESH:
1468                 proto_tree_add_bitmask_with_flags(req_tree, tvb, offset,
1469                     hf_mysql_refresh, ett_refresh, mysql_rfsh_flags,
1470                     ENC_BIG_ENDIAN, BMT_NO_APPEND);
1471                 offset += 1;
1472                 mysql_set_conn_state(pinfo, conn_data, RESPONSE_OK);
1473                 break;
1474
1475         case MYSQL_SHUTDOWN:
1476                 proto_tree_add_item(req_tree, hf_mysql_shutdown, tvb, offset, 1, ENC_NA);
1477                 offset += 1;
1478                 mysql_set_conn_state(pinfo, conn_data, RESPONSE_OK);
1479                 break;
1480
1481         case MYSQL_SET_OPTION:
1482                 proto_tree_add_item(req_tree, hf_mysql_option, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1483                 offset += 2;
1484                 mysql_set_conn_state(pinfo, conn_data, RESPONSE_OK);
1485                 break;
1486
1487         case MYSQL_STMT_FETCH:
1488                 proto_tree_add_item(req_tree, hf_mysql_stmt_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1489                 offset += 4;
1490
1491                 proto_tree_add_item(req_tree, hf_mysql_num_rows, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1492                 offset += 4;
1493                 mysql_set_conn_state(pinfo, conn_data, RESPONSE_TABULAR);
1494                 break;
1495
1496         case MYSQL_STMT_SEND_LONG_DATA:
1497                 proto_tree_add_item(req_tree, hf_mysql_stmt_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1498                 stmt_id = tvb_get_letohl(tvb, offset);
1499                 offset += 4;
1500
1501                 stmt_data = (my_stmt_data_t *)wmem_tree_lookup32(conn_data->stmts, stmt_id);
1502                 if (stmt_data != NULL) {
1503                         guint16 data_param = tvb_get_letohs(tvb, offset);
1504                         if (stmt_data->nparam > data_param) {
1505                                 stmt_data->param_flags[data_param] |= MYSQL_PARAM_FLAG_STREAMED;
1506                         }
1507                 }
1508
1509                 proto_tree_add_item(req_tree, hf_mysql_param, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1510                 offset += 2;
1511
1512                 /* rest is data */
1513                 lenstr = tvb_reported_length_remaining(tvb, offset);
1514                 if (tree &&  lenstr > 0) {
1515                         proto_tree_add_item(req_tree, hf_mysql_payload, tvb, offset, lenstr, ENC_NA);
1516                 }
1517                 offset += lenstr;
1518                 mysql_set_conn_state(pinfo, conn_data, REQUEST);
1519                 break;
1520
1521         case MYSQL_STMT_EXECUTE:
1522                 proto_tree_add_item(req_tree, hf_mysql_stmt_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1523                 stmt_id = tvb_get_letohl(tvb, offset);
1524                 offset += 4;
1525
1526                 if (conn_data->major_version >= 5) {
1527                         proto_tree_add_item(req_tree, hf_mysql_exec_flags5, tvb, offset, 1, ENC_NA);
1528                 } else {
1529                         proto_tree_add_item(req_tree, hf_mysql_exec_flags4, tvb, offset, 1, ENC_NA);
1530                 }
1531                 offset += 1;
1532
1533                 proto_tree_add_item(req_tree, hf_mysql_exec_iter, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1534                 offset += 4;
1535
1536                 stmt_data = (my_stmt_data_t *)wmem_tree_lookup32(conn_data->stmts, stmt_id);
1537                 if (stmt_data != NULL) {
1538                         if (stmt_data->nparam != 0) {
1539                                 guint8 stmt_bound;
1540                                 offset += (stmt_data->nparam + 7) / 8; /* NULL bitmap */
1541                                 proto_tree_add_item(req_tree, hf_mysql_new_parameter_bound_flag, tvb, offset, 1, ENC_NA);
1542                                 stmt_bound = tvb_get_guint8(tvb, offset);
1543                                 offset += 1;
1544                                 if (stmt_bound == 1) {
1545                                         param_offset = offset + stmt_data->nparam * 2;
1546                                         for (stmt_pos = 0; stmt_pos < stmt_data->nparam; stmt_pos++) {
1547                                                 if (!mysql_dissect_exec_param(req_tree, tvb, &offset, &param_offset,
1548                                                                               stmt_data->param_flags[stmt_pos], pinfo))
1549                                                         break;
1550                                         }
1551                                         offset = param_offset;
1552                                 }
1553                         }
1554                 } else {
1555                         lenstr = tvb_reported_length_remaining(tvb, offset);
1556                         if (tree &&  lenstr > 0) {
1557                                 ti = proto_tree_add_item(req_tree, hf_mysql_payload, tvb, offset, lenstr, ENC_NA);
1558                                 expert_add_info(pinfo, ti, &ei_mysql_prepare_response_needed);
1559                         }
1560                         offset += lenstr;
1561                 }
1562 #if 0
1563 /* FIXME: rest needs metadata about statement */
1564 #else
1565                 lenstr = tvb_reported_length_remaining(tvb, offset);
1566                 if (tree &&  lenstr > 0) {
1567                         ti = proto_tree_add_item(req_tree, hf_mysql_payload, tvb, offset, lenstr, ENC_NA);
1568                         expert_add_info_format(pinfo, ti, &ei_mysql_dissector_incomplete, "FIXME: execute dissector incomplete");
1569                 }
1570                 offset += lenstr;
1571 #endif
1572                 mysql_set_conn_state(pinfo, conn_data, RESPONSE_TABULAR);
1573                 break;
1574
1575         case MYSQL_BINLOG_DUMP_GTID:
1576         case MYSQL_BINLOG_DUMP:
1577                 proto_tree_add_item(req_tree, hf_mysql_binlog_position, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1578                 offset += 4;
1579
1580                 proto_tree_add_item(req_tree, hf_mysql_binlog_flags, tvb, offset, 2, ENC_BIG_ENDIAN);
1581                 offset += 2;
1582
1583                 proto_tree_add_item(req_tree, hf_mysql_binlog_server_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1584                 offset += 4;
1585
1586                 /* binlog file name ? */
1587                 lenstr = tvb_reported_length_remaining(tvb, offset);
1588                 if (tree &&  lenstr > 0) {
1589                         proto_tree_add_item(req_tree, hf_mysql_binlog_file_name, tvb, offset, lenstr, ENC_ASCII|ENC_NA);
1590                 }
1591                 offset += lenstr;
1592
1593                 mysql_set_conn_state(pinfo, conn_data, REQUEST);
1594                 break;
1595 /* FIXME: implement replication packets */
1596         case MYSQL_TABLE_DUMP:
1597         case MYSQL_CONNECT_OUT:
1598         case MYSQL_REGISTER_SLAVE:
1599                 ti = proto_tree_add_item(req_tree, hf_mysql_payload, tvb, offset, -1, ENC_NA);
1600                 expert_add_info_format(pinfo, ti, &ei_mysql_dissector_incomplete, "FIXME: implement replication packets");
1601                 offset += tvb_reported_length_remaining(tvb, offset);
1602                 mysql_set_conn_state(pinfo, conn_data, REQUEST);
1603                 break;
1604
1605         default:
1606                 ti = proto_tree_add_item(req_tree, hf_mysql_payload, tvb, offset, -1, ENC_NA);
1607                 expert_add_info(pinfo, ti, &ei_mysql_command);
1608                 offset += tvb_reported_length_remaining(tvb, offset);
1609                 mysql_set_conn_state(pinfo, conn_data, UNDEFINED);
1610         }
1611
1612         proto_item_set_end(request_item, tvb, offset);
1613         return offset;
1614 }
1615
1616 /*
1617  * Decode the header of a compressed packet
1618  * https://dev.mysql.com/doc/internals/en/compressed-packet-header.html
1619  */
1620 static int
1621 mysql_dissect_compressed_header(tvbuff_t *tvb, int offset, proto_tree *mysql_tree)
1622 {
1623         proto_tree_add_item(mysql_tree, hf_mysql_compressed_packet_length, tvb, offset, 3, ENC_LITTLE_ENDIAN);
1624         offset += 3;
1625
1626         proto_tree_add_item(mysql_tree, hf_mysql_compressed_packet_number, tvb, offset, 1, ENC_NA);
1627         offset += 1;
1628
1629         proto_tree_add_item(mysql_tree, hf_mysql_compressed_packet_length_uncompressed, tvb, offset, 3, ENC_LITTLE_ENDIAN);
1630         offset += 3;
1631
1632         return offset;
1633 }
1634
1635 static int
1636 mysql_dissect_response(tvbuff_t *tvb, packet_info *pinfo, int offset,
1637                        proto_tree *tree, mysql_conn_data_t *conn_data, mysql_state_t current_state)
1638 {
1639         gint response_code;
1640         gint lenstr;
1641         proto_item *ti;
1642         guint16 server_status = 0;
1643
1644         response_code = tvb_get_guint8(tvb, offset);
1645
1646         if (response_code == 0xff ) {
1647                 proto_tree_add_item(tree, hf_mysql_response_code, tvb, offset, 1, ENC_NA);
1648                 offset = mysql_dissect_error_packet(tvb, pinfo, offset+1, tree);
1649                 mysql_set_conn_state(pinfo, conn_data, REQUEST);
1650         }
1651
1652         else if (response_code == 0xfe && tvb_reported_length_remaining(tvb, offset) < 9) {
1653
1654                 proto_tree_add_item(tree, hf_mysql_response_code, tvb, offset, 1, ENC_NA);
1655                 ti = proto_tree_add_item(tree, hf_mysql_eof, tvb, offset, 1, ENC_NA);
1656
1657                 offset += 1;
1658
1659                 /* pre-4.1 packet ends here */
1660                 if (tvb_reported_length_remaining(tvb, offset)) {
1661                         proto_tree_add_item(tree, hf_mysql_num_warn, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1662                         offset = mysql_dissect_server_status(tvb, offset+2, tree, &server_status);
1663                 }
1664
1665                 switch (current_state) {
1666                 case FIELD_PACKET:
1667                         mysql_set_conn_state(pinfo, conn_data, ROW_PACKET);
1668                         break;
1669                 case ROW_PACKET:
1670                         if (server_status & MYSQL_STAT_MU) {
1671                                 mysql_set_conn_state(pinfo, conn_data, RESPONSE_TABULAR);
1672                         } else {
1673                                 mysql_set_conn_state(pinfo, conn_data, REQUEST);
1674                         }
1675                         break;
1676                 case PREPARED_PARAMETERS:
1677                         if (conn_data->stmt_num_fields > 0) {
1678                                 mysql_set_conn_state(pinfo, conn_data, PREPARED_FIELDS);
1679                         } else {
1680                                 mysql_set_conn_state(pinfo, conn_data, REQUEST);
1681                         }
1682                         break;
1683                 case PREPARED_FIELDS:
1684                         mysql_set_conn_state(pinfo, conn_data, REQUEST);
1685                         break;
1686                 default:
1687                         /* This should be an unreachable case */
1688                         mysql_set_conn_state(pinfo, conn_data, REQUEST);
1689                         expert_add_info(pinfo, ti, &ei_mysql_eof);
1690                 }
1691         }
1692
1693         else if (response_code == 0) {
1694                 proto_tree_add_item(tree, hf_mysql_response_code, tvb, offset, 1, ENC_NA);
1695                 if (current_state == RESPONSE_PREPARE) {
1696                         offset = mysql_dissect_response_prepare(tvb, pinfo, offset, tree, conn_data);
1697                 } else if (tvb_reported_length_remaining(tvb, offset+1)  > tvb_get_fle(tvb, offset+1, NULL, NULL)) {
1698                         offset = mysql_dissect_ok_packet(tvb, pinfo, offset+1, tree, conn_data);
1699                         if (conn_data->compressed_state == MYSQL_COMPRESS_INIT) {
1700                                 /* This is the OK packet which follows the compressed protocol setup */
1701                                 conn_data->compressed_state = MYSQL_COMPRESS_ACTIVE;
1702                         }
1703                 } else {
1704                         offset = mysql_dissect_result_header(tvb, pinfo, offset, tree, conn_data);
1705                 }
1706         }
1707
1708         else {
1709                 switch (current_state) {
1710                 case RESPONSE_MESSAGE:
1711                         if ((lenstr = tvb_reported_length_remaining(tvb, offset))) {
1712                                 proto_tree_add_item(tree, hf_mysql_message, tvb, offset, lenstr, ENC_ASCII|ENC_NA);
1713                                 offset += lenstr;
1714                         }
1715                         mysql_set_conn_state(pinfo, conn_data, REQUEST);
1716                         break;
1717
1718                 case RESPONSE_TABULAR:
1719                 case REQUEST: /* That shouldn't be the case; maybe two requests in a row (s. bug 15074) */
1720                         offset = mysql_dissect_result_header(tvb, pinfo, offset, tree, conn_data);
1721                         break;
1722
1723                 case FIELD_PACKET:
1724                 case RESPONSE_SHOW_FIELDS:
1725                 case RESPONSE_PREPARE:
1726                 case PREPARED_PARAMETERS:
1727                         offset = mysql_dissect_field_packet(tvb, offset, tree, conn_data);
1728                         break;
1729
1730                 case ROW_PACKET:
1731                         offset = mysql_dissect_row_packet(tvb, offset, tree);
1732                         break;
1733
1734                 case PREPARED_FIELDS:
1735                         offset = mysql_dissect_field_packet(tvb, offset, tree, conn_data);
1736                         break;
1737
1738                 case AUTH_SWITCH_REQUEST:
1739                         offset = mysql_dissect_auth_switch_request(tvb, pinfo, offset, tree, conn_data);
1740                         break;
1741
1742
1743                 default:
1744                         ti = proto_tree_add_item(tree, hf_mysql_payload, tvb, offset, -1, ENC_NA);
1745                         expert_add_info(pinfo, ti, &ei_mysql_unknown_response);
1746                         offset += tvb_reported_length_remaining(tvb, offset);
1747                         mysql_set_conn_state(pinfo, conn_data, UNDEFINED);
1748                 }
1749         }
1750
1751         return offset;
1752 }
1753
1754
1755 static int
1756 mysql_dissect_error_packet(tvbuff_t *tvb, packet_info *pinfo,
1757                            int offset, proto_tree *tree)
1758 {
1759         col_append_fstr(pinfo->cinfo, COL_INFO, " Error %d", tvb_get_letohs(tvb, offset));
1760
1761         proto_tree_add_item(tree, hf_mysql_error_code, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1762         offset += 2;
1763
1764         if (tvb_get_guint8(tvb, offset) == '#')
1765         {
1766                 offset += 1;
1767                 proto_tree_add_item(tree, hf_mysql_sqlstate, tvb, offset, 5, ENC_ASCII|ENC_NA);
1768                 offset += 5;
1769         }
1770
1771         proto_tree_add_item(tree, hf_mysql_error_string, tvb, offset, -1, ENC_ASCII|ENC_NA);
1772         offset += tvb_reported_length_remaining(tvb, offset);
1773
1774         return offset;
1775 }
1776
1777 /*
1778   Add a session track entry to the session tracking subtree
1779
1780   return bytes read
1781 */
1782 static int
1783 add_session_tracker_entry_to_tree(tvbuff_t *tvb, packet_info *pinfo, proto_item *tree, int offset) {
1784         guint8 data_type; /* session tracker type */
1785         guint64 length; /* complete length of session tracking entry */
1786         guint64 lenstr;
1787         int orig_offset = offset, lenfle;
1788         proto_item *item, *ti;
1789         proto_tree *session_track_tree;
1790
1791         ti = proto_tree_add_item(tree, hf_mysql_session_track, tvb, offset, 1, ENC_NA);
1792         session_track_tree = proto_item_add_subtree(ti, ett_session_track);
1793
1794         proto_tree_add_item(session_track_tree, hf_mysql_session_track_type, tvb, offset, 1, ENC_BIG_ENDIAN);
1795         data_type = tvb_get_guint8(tvb, offset);
1796         offset += 1;
1797
1798         lenfle = tvb_get_fle(tvb, offset, &length, NULL);
1799         proto_tree_add_uint64(session_track_tree, hf_mysql_session_track_length, tvb, offset, lenfle, length);
1800         offset += lenfle;
1801
1802         switch (data_type) {
1803         case 0: /* SESSION_SYSVARS_TRACKER */
1804                 lenfle = tvb_get_fle(tvb, offset, &lenstr, NULL);
1805                 proto_tree_add_uint64(session_track_tree, hf_mysql_session_track_sysvar_length, tvb, offset, lenfle, lenstr);
1806                 offset += lenfle;
1807
1808                 proto_tree_add_item(session_track_tree, hf_mysql_session_track_sysvar_name, tvb, offset, (gint)lenstr, ENC_ASCII|ENC_NA);
1809                 offset += (int)lenstr;
1810
1811                 lenfle = tvb_get_fle(tvb, offset, &lenstr, NULL);
1812                 proto_tree_add_uint64(session_track_tree, hf_mysql_session_track_sysvar_length, tvb, offset, lenfle, lenstr);
1813                 offset += lenfle;
1814
1815                 proto_tree_add_item(session_track_tree, hf_mysql_session_track_sysvar_value, tvb, offset, (gint)lenstr, ENC_ASCII|ENC_NA);
1816                 offset += (int)lenstr;
1817                 break;
1818         case 1: /* CURRENT_SCHEMA_TRACKER */
1819                 lenfle = tvb_get_fle(tvb, offset, &lenstr, NULL);
1820                 proto_tree_add_uint64(session_track_tree, hf_mysql_session_track_schema_length, tvb, offset, lenfle, lenstr);
1821                 offset += lenfle;
1822
1823                 proto_tree_add_item(session_track_tree, hf_mysql_session_track_schema, tvb, offset, (gint)lenstr, ENC_ASCII|ENC_NA);
1824                 offset += (int)lenstr;
1825                 break;
1826         case 2: /* SESSION_STATE_CHANGE_TRACKER */
1827                 proto_tree_add_item(session_track_tree, hf_mysql_session_state_change, tvb, offset, 1, ENC_ASCII|ENC_NA);
1828                 offset++;
1829                 break;
1830         default: /* unsupported types skipped */
1831                 item = proto_tree_add_item(session_track_tree, hf_mysql_payload, tvb, offset, (gint)length, ENC_NA);
1832                 expert_add_info_format(pinfo, item, &ei_mysql_dissector_incomplete, "FIXME: unrecognized session tracker data");
1833                 offset += (int)length;
1834         }
1835         proto_item_set_len(ti, offset - orig_offset);
1836
1837         return (offset - orig_offset);
1838 }
1839
1840 static int
1841 mysql_dissect_ok_packet(tvbuff_t *tvb, packet_info *pinfo, int offset,
1842                         proto_tree *tree, mysql_conn_data_t *conn_data)
1843 {
1844         guint64 lenstr;
1845         guint64 affected_rows;
1846         guint64 insert_id;
1847         int fle;
1848         guint16 server_status = 0;
1849
1850         col_append_str(pinfo->cinfo, COL_INFO, " OK" );
1851
1852         fle = tvb_get_fle(tvb, offset, &affected_rows, NULL);
1853         proto_tree_add_uint64(tree, hf_mysql_affected_rows, tvb, offset, fle, affected_rows);
1854         offset += fle;
1855
1856         fle= tvb_get_fle(tvb, offset, &insert_id, NULL);
1857         if (tree && insert_id) {
1858                 proto_tree_add_uint64(tree, hf_mysql_insert_id, tvb, offset, fle, insert_id);
1859         }
1860         offset += fle;
1861
1862         if (tvb_reported_length_remaining(tvb, offset) > 0) {
1863                 offset = mysql_dissect_server_status(tvb, offset, tree, &server_status);
1864
1865                 /* 4.1+ protocol only: 2 bytes number of warnings */
1866                 if (conn_data->clnt_caps & conn_data->srv_caps & MYSQL_CAPS_CU) {
1867                         proto_tree_add_item(tree, hf_mysql_num_warn, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1868                 offset += 2;
1869                 }
1870         }
1871
1872         if (conn_data->clnt_caps_ext & MYSQL_CAPS_ST) {
1873                 if (tvb_reported_length_remaining(tvb, offset) > 0) {
1874                         guint64 session_track_length;
1875                         proto_item *tf;
1876                         proto_item *session_track_tree = NULL;
1877                         int length;
1878
1879                         offset += tvb_get_fle(tvb, offset, &lenstr, NULL);
1880                         /* first read the optional message */
1881                         if (lenstr) {
1882                                 proto_tree_add_item(tree, hf_mysql_message, tvb, offset, (gint)lenstr, ENC_ASCII|ENC_NA);
1883                                 offset += (int)lenstr;
1884                         }
1885
1886                         /* session state tracking */
1887                         if (server_status & MYSQL_STAT_SESSION_STATE_CHANGED) {
1888                                 fle = tvb_get_fle(tvb, offset, &session_track_length, NULL);
1889                                 tf = proto_tree_add_item(tree, hf_mysql_session_track_data, tvb, offset, -1, ENC_NA);
1890                                 session_track_tree = proto_item_add_subtree(tf, ett_session_track_data);
1891                                 proto_tree_add_uint64(tf, hf_mysql_session_track_data_length, tvb, offset, fle, session_track_length);
1892                                 offset += fle;
1893
1894                                 while (session_track_length > 0) {
1895                                         length = add_session_tracker_entry_to_tree(tvb, pinfo, session_track_tree, offset);
1896                                         offset += length;
1897                                         session_track_length -= length;
1898                                 }
1899                         }
1900                 }
1901         } else {
1902                 /* optional: message string */
1903                 if (tvb_reported_length_remaining(tvb, offset) > 0) {
1904                         lenstr = tvb_reported_length_remaining(tvb, offset);
1905                         proto_tree_add_item(tree, hf_mysql_message, tvb, offset, (gint)lenstr, ENC_ASCII|ENC_NA);
1906                         offset += (int)lenstr;
1907                 }
1908         }
1909
1910         mysql_set_conn_state(pinfo, conn_data, REQUEST);
1911         return offset;
1912 }
1913
1914
1915 static int
1916 mysql_dissect_server_status(tvbuff_t *tvb, int offset, proto_tree *tree, guint16 *server_status)
1917 {
1918
1919         if (server_status) {
1920                 *server_status = tvb_get_letohs(tvb, offset);
1921         }
1922         proto_tree_add_bitmask_with_flags(tree, tvb, offset, hf_mysql_server_status, ett_stat, mysql_stat_flags, ENC_LITTLE_ENDIAN, BMT_NO_APPEND);
1923
1924         offset += 2;
1925
1926         return offset;
1927 }
1928
1929
1930 static int
1931 mysql_dissect_caps(tvbuff_t *tvb, int offset, proto_tree *tree, int mysql_caps, guint16 *caps)
1932 {
1933
1934         *caps= tvb_get_letohs(tvb, offset);
1935
1936         proto_tree_add_bitmask_with_flags(tree, tvb, offset, mysql_caps, ett_caps, mysql_caps_flags, ENC_LITTLE_ENDIAN, BMT_NO_APPEND);
1937
1938         offset += 2;
1939         return offset;
1940 }
1941
1942 static int
1943 mysql_dissect_extcaps(tvbuff_t *tvb, int offset, proto_tree *tree, int mysql_extcaps, guint16 *ext_caps)
1944 {
1945
1946         *ext_caps= tvb_get_letohs(tvb, offset);
1947
1948         proto_tree_add_bitmask_with_flags(tree, tvb, offset, mysql_extcaps, ett_extcaps, mysql_extcaps_flags, ENC_LITTLE_ENDIAN, BMT_NO_APPEND);
1949
1950         offset += 2;
1951         return offset;
1952 }
1953
1954
1955 static int
1956 mysql_dissect_result_header(tvbuff_t *tvb, packet_info *pinfo, int offset,
1957                             proto_tree *tree, mysql_conn_data_t *conn_data)
1958 {
1959         gint fle;
1960         guint64 num_fields, extra;
1961
1962         col_append_str(pinfo->cinfo, COL_INFO, " TABULAR" );
1963
1964         fle = tvb_get_fle(tvb, offset, &num_fields, NULL);
1965         proto_tree_add_uint64(tree, hf_mysql_num_fields, tvb, offset, fle, num_fields);
1966         offset += fle;
1967
1968         if (tvb_reported_length_remaining(tvb, offset)) {
1969                 fle = tvb_get_fle(tvb, offset, &extra, NULL);
1970                 proto_tree_add_uint64(tree, hf_mysql_extra, tvb, offset, fle, extra);
1971                 offset += fle;
1972         }
1973
1974         if (num_fields) {
1975                 mysql_set_conn_state(pinfo, conn_data, FIELD_PACKET);
1976         } else {
1977                 mysql_set_conn_state(pinfo, conn_data, ROW_PACKET);
1978         }
1979
1980         return offset;
1981 }
1982
1983
1984 /*
1985  * Add length encoded string to tree
1986  */
1987 static int
1988 mysql_field_add_lestring(tvbuff_t *tvb, int offset, proto_tree *tree, int field)
1989 {
1990         guint64 lelen;
1991         guint8 is_null;
1992
1993         offset += tvb_get_fle(tvb, offset, &lelen, &is_null);
1994         if(is_null)
1995                 proto_tree_add_string(tree, field, tvb, offset, 0, "NULL");
1996         else
1997         {
1998                 proto_tree_add_item(tree, field, tvb, offset, (int)lelen, ENC_NA);
1999                 /* Prevent infinite loop due to overflow */
2000                 if (offset + (int)lelen < offset) {
2001                         offset = tvb_reported_length(tvb);
2002                 }
2003                 else {
2004                         offset += (int)lelen;
2005                 }
2006         }
2007         return offset;
2008 }
2009
2010
2011 static int
2012 mysql_dissect_field_packet(tvbuff_t *tvb, int offset, proto_tree *tree, mysql_conn_data_t *conn_data _U_)
2013 {
2014
2015         offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_catalog);
2016         offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_db);
2017         offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_table);
2018         offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_org_table);
2019         offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_name);
2020         offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_org_name);
2021         offset +=1; /* filler */
2022
2023         proto_tree_add_item(tree, hf_mysql_fld_charsetnr, tvb, offset, 2, ENC_LITTLE_ENDIAN);
2024         offset += 2; /* charset */
2025
2026         proto_tree_add_item(tree, hf_mysql_fld_length, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2027         offset += 4; /* length */
2028
2029         proto_tree_add_item(tree, hf_mysql_fld_type, tvb, offset, 1, ENC_NA);
2030         offset += 1; /* type */
2031
2032         proto_tree_add_bitmask_with_flags(tree, tvb, offset, hf_mysql_fld_flags, ett_field_flags, mysql_fld_flags, ENC_LITTLE_ENDIAN, BMT_NO_APPEND);
2033         offset += 2; /* flags */
2034
2035         proto_tree_add_item(tree, hf_mysql_fld_decimals, tvb, offset, 1, ENC_NA);
2036         offset += 1; /* decimals */
2037
2038         offset += 2; /* filler */
2039
2040         /* default (Only use for show fields) */
2041         if (tree && tvb_reported_length_remaining(tvb, offset) > 0) {
2042                 offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_default);
2043         }
2044         return offset;
2045 }
2046
2047
2048 static int
2049 mysql_dissect_row_packet(tvbuff_t *tvb, int offset, proto_tree *tree)
2050 {
2051         while (tvb_reported_length_remaining(tvb, offset) > 0) {
2052                 offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_row_text);
2053         }
2054
2055         return offset;
2056 }
2057
2058
2059 static int
2060 mysql_dissect_response_prepare(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data)
2061 {
2062         my_stmt_data_t *stmt_data;
2063         guint32 stmt_id;
2064         int flagsize;
2065
2066         /* 0, marker for OK packet */
2067         offset += 1;
2068         proto_tree_add_item(tree, hf_mysql_stmt_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
2069         stmt_id = tvb_get_letohl(tvb, offset);
2070         offset += 4;
2071         proto_tree_add_item(tree, hf_mysql_num_fields, tvb, offset, 2, ENC_LITTLE_ENDIAN);
2072         conn_data->stmt_num_fields = tvb_get_letohs(tvb, offset);
2073         offset += 2;
2074         proto_tree_add_item(tree, hf_mysql_num_params, tvb, offset, 2, ENC_LITTLE_ENDIAN);
2075         conn_data->stmt_num_params = tvb_get_letohs(tvb, offset);
2076         stmt_data = wmem_new(wmem_file_scope(), struct my_stmt_data);
2077         stmt_data->nparam = conn_data->stmt_num_params;
2078         flagsize = (int)(sizeof(guint8) * stmt_data->nparam);
2079         stmt_data->param_flags = (guint8 *)wmem_alloc(wmem_file_scope(), flagsize);
2080         memset(stmt_data->param_flags, 0, flagsize);
2081         wmem_tree_insert32(conn_data->stmts, stmt_id, stmt_data);
2082         offset += 2;
2083         /* Filler */
2084         offset += 1;
2085         proto_tree_add_item(tree, hf_mysql_num_warn, tvb, offset, 2, ENC_LITTLE_ENDIAN);
2086
2087         if (conn_data->stmt_num_params > 0)
2088                 mysql_set_conn_state(pinfo, conn_data, PREPARED_PARAMETERS);
2089         else if (conn_data->stmt_num_fields > 0)
2090                 mysql_set_conn_state(pinfo, conn_data, PREPARED_FIELDS);
2091         else
2092                 mysql_set_conn_state(pinfo, conn_data, REQUEST);
2093
2094         return offset + tvb_reported_length_remaining(tvb, offset);
2095 }
2096
2097
2098 static int
2099 mysql_dissect_auth_switch_request(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data _U_)
2100 {
2101         gint lenstr;
2102
2103         col_set_str(pinfo->cinfo, COL_INFO, "Auth Switch Request" );
2104         mysql_set_conn_state(pinfo, conn_data, AUTH_SWITCH_RESPONSE);
2105
2106         /* Status (Always 0xfe) */
2107         proto_tree_add_item(tree, hf_mysql_auth_switch_request_status, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2108         offset += 1;
2109
2110         /* name */
2111         lenstr = my_tvb_strsize(tvb, offset);
2112         proto_tree_add_item(tree, hf_mysql_auth_switch_request_name, tvb, offset, lenstr, ENC_ASCII|ENC_NA);
2113         offset += lenstr;
2114
2115         /* Data */
2116         lenstr = my_tvb_strsize(tvb, offset);
2117         proto_tree_add_item(tree, hf_mysql_auth_switch_request_data, tvb, offset, lenstr, ENC_NA);
2118         offset += lenstr;
2119
2120         return offset + tvb_reported_length_remaining(tvb, offset);
2121
2122 }
2123 static int
2124 mysql_dissect_auth_switch_response(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data _U_)
2125 {
2126         gint lenstr;
2127
2128         col_set_str(pinfo->cinfo, COL_INFO, "Auth Switch Response" );
2129
2130         /* Data */
2131         lenstr = my_tvb_strsize(tvb, offset);
2132         proto_tree_add_item(tree, hf_mysql_auth_switch_response_data, tvb, offset, lenstr, ENC_NA);
2133         offset += lenstr;
2134
2135         return offset + tvb_reported_length_remaining(tvb, offset);
2136
2137 }
2138 /*
2139  get length of string in packet buffer
2140
2141  SYNOPSIS
2142    my_tvb_strsize()
2143      tvb      packet buffer
2144      offset   current offset
2145
2146  DESCRIPTION
2147    deliver length of string, delimited by either \0 or end of buffer
2148
2149  RETURN VALUE
2150    length of string found, including \0 (if present)
2151
2152 */
2153 static gint
2154 my_tvb_strsize(tvbuff_t *tvb, int offset)
2155 {
2156         gint len = tvb_strnlen(tvb, offset, -1);
2157         if (len == -1) {
2158                 len = tvb_reported_length_remaining(tvb, offset);
2159         } else {
2160                 len++; /* the trailing \0 */
2161         }
2162         return len;
2163 }
2164
2165 /*
2166  read "field length encoded" value from packet buffer
2167
2168  SYNOPSIS
2169    tvb_get_fle()
2170      tvb     in    packet buffer
2171      offset  in    offset in buffer
2172      res     out   where to store FLE value, may be NULL
2173      is_null out   where to store ISNULL flag, may be NULL
2174
2175  DESCRIPTION
2176    read FLE from packet buffer and store its value and ISNULL flag
2177    in caller provided variables
2178
2179  RETURN VALUE
2180    length of FLE
2181 */
2182 static int
2183 tvb_get_fle(tvbuff_t *tvb, int offset, guint64 *res, guint8 *is_null)
2184 {
2185         guint8 prefix;
2186
2187         prefix = tvb_get_guint8(tvb, offset);
2188
2189         if (is_null)
2190                 *is_null = 0;
2191
2192         switch (prefix) {
2193         case 251:
2194                 if (res)
2195                         *res = 0;
2196                 if (is_null)
2197                         *is_null = 1;
2198                 break;
2199         case 252:
2200                 if (res)
2201                         *res = tvb_get_letohs(tvb, offset+1);
2202                 return 3;
2203         case 253:
2204                 if (res)
2205                         *res = tvb_get_letohl(tvb, offset+1);
2206                 return 5;
2207         case 254:
2208                 if (res)
2209                         *res = tvb_get_letoh64(tvb, offset+1);
2210                 return 9;
2211         default:
2212                 if (res)
2213                         *res = prefix;
2214         }
2215
2216         return 1;
2217 }
2218
2219 /* dissector helper: length of PDU */
2220 static guint
2221 get_mysql_pdu_len(packet_info *pinfo, tvbuff_t *tvb, int offset, void *data _U_)
2222 {
2223         /* Regular packet header: length (3) + sequence number (1) */
2224         conversation_t     *conversation;
2225         mysql_conn_data_t  *conn_data;
2226         guint               len = 4 + tvb_get_letoh24(tvb, offset);
2227
2228         conversation = find_conversation_pinfo(pinfo, 0);
2229         if (conversation) {
2230                 conn_data = (mysql_conn_data_t *)conversation_get_proto_data(conversation, proto_mysql);
2231                 if (conn_data && conn_data->compressed_state == MYSQL_COMPRESS_ACTIVE &&
2232                         pinfo->num > conn_data->frame_start_compressed) {
2233                         /* Compressed packet header includes uncompressed packet length (3) */
2234                         len += 3;
2235                 }
2236         }
2237
2238         return len;
2239 }
2240
2241 /* dissector main function: handle one PDU */
2242 static int
2243 dissect_mysql_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
2244 {
2245         proto_tree      *mysql_tree= NULL;
2246         proto_item      *ti;
2247         conversation_t  *conversation;
2248         int             offset = 0;
2249         guint           packet_number;
2250         gboolean        is_response, is_tls = FALSE;
2251         mysql_conn_data_t  *conn_data;
2252 #ifdef CTDEBUG
2253         mysql_state_t conn_state_in, conn_state_out, frame_state;
2254         guint64         generation;
2255         proto_item *pi;
2256 #endif
2257         struct mysql_frame_data  *mysql_frame_data_p;
2258
2259         /* get conversation, create if necessary*/
2260         conversation= find_or_create_conversation(pinfo);
2261
2262         /* get associated state information, create if necessary */
2263         conn_data= (mysql_conn_data_t *)conversation_get_proto_data(conversation, proto_mysql);
2264         if (!conn_data) {
2265                 conn_data= wmem_new(wmem_file_scope(), mysql_conn_data_t);
2266                 conn_data->srv_caps= 0;
2267                 conn_data->clnt_caps= 0;
2268                 conn_data->clnt_caps_ext= 0;
2269                 conn_data->state= UNDEFINED;
2270                 conn_data->stmts= wmem_tree_new(wmem_file_scope());
2271 #ifdef CTDEBUG
2272                 conn_data->generation= 0;
2273 #endif
2274                 conn_data->major_version= 0;
2275                 conn_data->frame_start_ssl= 0;
2276                 conn_data->frame_start_compressed= 0;
2277                 conn_data->compressed_state= MYSQL_COMPRESS_NONE;
2278                 conversation_add_proto_data(conversation, proto_mysql, conn_data);
2279         }
2280
2281         /* Using tvb_raw_offset(tvb) allows storage of multiple "proto data" in a single frame
2282          * (when there are multiple MySQL pdus in a single frame) */
2283         mysql_frame_data_p = (struct mysql_frame_data *)p_get_proto_data(wmem_file_scope(), pinfo, proto_mysql, tvb_raw_offset(tvb));
2284         if (!mysql_frame_data_p) {
2285                 /*  We haven't seen this frame before.  Store the state of the
2286                  *  conversation now so if/when we dissect the frame again
2287                  *  we'll start with the same state.
2288                  */
2289                 mysql_frame_data_p = wmem_new(wmem_file_scope(), struct mysql_frame_data);
2290                 mysql_frame_data_p->state = conn_data->state;
2291                 p_add_proto_data(wmem_file_scope(), pinfo, proto_mysql, tvb_raw_offset(tvb), mysql_frame_data_p);
2292         }
2293
2294         if ((conn_data->frame_start_compressed) && (pinfo->num > conn_data->frame_start_compressed)) {
2295                 if (conn_data->compressed_state == MYSQL_COMPRESS_ACTIVE) {
2296                         offset = mysql_dissect_compressed_header(tvb, offset, tree);
2297                 }
2298         }
2299
2300         ti = proto_tree_add_item(tree, proto_mysql, tvb, offset, -1, ENC_NA);
2301         mysql_tree = proto_item_add_subtree(ti, ett_mysql);
2302         proto_tree_add_item(mysql_tree, hf_mysql_packet_length, tvb, offset, 3, ENC_LITTLE_ENDIAN);
2303         offset+= 3;
2304
2305         col_set_str(pinfo->cinfo, COL_PROTOCOL, "MySQL");
2306
2307         if (pinfo->destport == pinfo->match_uint) {
2308                 is_response= FALSE;
2309         } else {
2310                 is_response= TRUE;
2311         }
2312
2313         packet_number = tvb_get_guint8(tvb, offset);
2314         proto_tree_add_item(mysql_tree, hf_mysql_packet_number, tvb, offset, 1, ENC_NA);
2315         offset += 1;
2316
2317 #ifdef CTDEBUG
2318         conn_state_in= conn_data->state;
2319         frame_state = mysql_frame_data_p->state;
2320         generation= conn_data->generation;
2321         if (tree) {
2322                 pi = proto_tree_add_debug_text(mysql_tree, "conversation: %p", conversation);
2323                 PROTO_ITEM_SET_GENERATED(pi);
2324                 pi = proto_tree_add_debug_text(mysql_tree, "generation: %" G_GINT64_MODIFIER "d", generation);
2325                 PROTO_ITEM_SET_GENERATED(pi);
2326                 pi = proto_tree_add_debug_text(mysql_tree, "conn state: %s (%u)",
2327                                     val_to_str(conn_state_in, state_vals, "Unknown (%u)"),
2328                                     conn_state_in);
2329                 PROTO_ITEM_SET_GENERATED(pi);
2330                 pi = proto_tree_add_debug_text(mysql_tree, "frame state: %s (%u)",
2331                                     val_to_str(frame_state, state_vals, "Unknown (%u)"),
2332                                     frame_state);
2333                 PROTO_ITEM_SET_GENERATED(pi);
2334         }
2335 #endif
2336
2337         is_tls = proto_is_frame_protocol(pinfo->layers, "tls");
2338
2339         if (is_response) {
2340                 if (packet_number == 0 && mysql_frame_data_p->state == UNDEFINED) {
2341                         col_set_str(pinfo->cinfo, COL_INFO, "Server Greeting");
2342                         offset = mysql_dissect_greeting(tvb, pinfo, offset, mysql_tree, conn_data);
2343                 } else {
2344                         col_set_str(pinfo->cinfo, COL_INFO, "Response");
2345                         offset = mysql_dissect_response(tvb, pinfo, offset, mysql_tree, conn_data, mysql_frame_data_p->state);
2346                 }
2347         } else {
2348                 if (mysql_frame_data_p->state == LOGIN && (packet_number == 1 || (packet_number == 2 && is_tls))) {
2349                         col_set_str(pinfo->cinfo, COL_INFO, "Login Request");
2350                         offset = mysql_dissect_login(tvb, pinfo, offset, mysql_tree, conn_data);
2351                         if (conn_data->srv_caps & MYSQL_CAPS_CP) {
2352                                 if (conn_data->clnt_caps & MYSQL_CAPS_CP) {
2353                                         conn_data->frame_start_compressed = pinfo->num;
2354                                         conn_data->compressed_state = MYSQL_COMPRESS_INIT;
2355                                 }
2356                         }
2357                 } else {
2358                         col_set_str(pinfo->cinfo, COL_INFO, "Request");
2359                         offset = mysql_dissect_request(tvb, pinfo, offset, mysql_tree, conn_data, mysql_frame_data_p->state);
2360                 }
2361         }
2362
2363 #ifdef CTDEBUG
2364         conn_state_out= conn_data->state;
2365         ++(conn_data->generation);
2366         pi = proto_tree_add_debug_text(mysql_tree, "next proto state: %s (%u)",
2367                             val_to_str(conn_state_out, state_vals, "Unknown (%u)"),
2368                             conn_state_out);
2369         PROTO_ITEM_SET_GENERATED(pi);
2370 #endif
2371
2372         /* remaining payload indicates an error */
2373         if (tvb_reported_length_remaining(tvb, offset) > 0) {
2374                 ti = proto_tree_add_item(mysql_tree, hf_mysql_payload, tvb, offset, -1, ENC_NA);
2375                 expert_add_info(pinfo, ti, &ei_mysql_dissector_incomplete);
2376         }
2377
2378         return tvb_reported_length(tvb);
2379 }
2380
2381 /* dissector entrypoint, handles TCP-desegmentation */
2382 static int
2383 dissect_mysql(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
2384 {
2385         tcp_dissect_pdus(tvb, pinfo, tree, mysql_desegment, 3,
2386                          get_mysql_pdu_len, dissect_mysql_pdu, data);
2387
2388         return tvb_reported_length(tvb);
2389 }
2390
2391 /* protocol registration */
2392 void proto_register_mysql(void)
2393 {
2394         static hf_register_info hf[]=
2395         {
2396                 { &hf_mysql_packet_length,
2397                 { "Packet Length", "mysql.packet_length",
2398                 FT_UINT24, BASE_DEC, NULL,  0x0,
2399                 NULL, HFILL }},
2400
2401                 { &hf_mysql_packet_number,
2402                 { "Packet Number", "mysql.packet_number",
2403                 FT_UINT8, BASE_DEC, NULL, 0x0,
2404                 "Packet Number (now called: Sequence ID)", HFILL }},
2405
2406                 { &hf_mysql_request,
2407                 { "Request Command", "mysql.request",
2408                 FT_NONE, BASE_NONE, NULL, 0x0,
2409                 NULL, HFILL }},
2410
2411                 { &hf_mysql_command,
2412                 { "Command", "mysql.command",
2413                 FT_UINT8, BASE_DEC|BASE_EXT_STRING, &mysql_command_vals_ext, 0x0,
2414                 NULL, HFILL }},
2415
2416                 { &hf_mysql_response_code,
2417                 { "Response Code", "mysql.response_code",
2418                 FT_UINT8, BASE_HEX, VALS(mysql_response_code_vals), 0x0,
2419                 NULL, HFILL }},
2420
2421                 { &hf_mysql_error_code,
2422                 { "Error Code", "mysql.error_code",
2423                 FT_UINT16, BASE_DEC, NULL, 0x0,
2424                 NULL, HFILL }},
2425
2426                 { &hf_mysql_error_string,
2427                 { "Error message", "mysql.error.message",
2428                 FT_STRING, BASE_NONE, NULL, 0x0,
2429                 "Error string in case of MySQL error message", HFILL }},
2430
2431                 { &hf_mysql_sqlstate,
2432                 { "SQL state", "mysql.sqlstate",
2433                 FT_STRING, BASE_NONE, NULL, 0x0,
2434                 NULL, HFILL }},
2435
2436                 { &hf_mysql_message,
2437                 { "Message", "mysql.message",
2438                 FT_STRINGZ, BASE_NONE, NULL, 0x0,
2439                 NULL, HFILL }},
2440
2441                 { &hf_mysql_server_greeting,
2442                 { "Server Greeting", "mysql.server_greeting",
2443                 FT_NONE, BASE_NONE, NULL, 0x0,
2444                 NULL, HFILL }},
2445
2446                 { &hf_mysql_protocol,
2447                 { "Protocol", "mysql.protocol",
2448                 FT_UINT8, BASE_DEC, NULL, 0x0,
2449                 "Protocol Version", HFILL }},
2450
2451                 { &hf_mysql_version,
2452                 { "Version", "mysql.version",
2453                 FT_STRINGZ, BASE_NONE, NULL, 0x0,
2454                 "MySQL Version", HFILL }},
2455
2456                 { &hf_mysql_session_track,
2457                 { "Session Track", "mysql.session_track",
2458                   FT_NONE, BASE_NONE, NULL, 0x0,
2459                   NULL, HFILL }},
2460
2461                 { &hf_mysql_session_track_type,
2462                 { "Session tracking type", "mysql.session_track.type",
2463                   FT_UINT8, BASE_DEC, VALS(mysql_session_track_type_vals), 0x0,
2464                   NULL, HFILL }},
2465
2466                 { &hf_mysql_session_track_length,
2467                 { "Session tracking length", "mysql.session_track.length",
2468                   FT_UINT64, BASE_DEC, NULL, 0x0,
2469                   NULL, HFILL }},
2470
2471                 { &hf_mysql_session_track_data,
2472                 { "Session tracking data", "mysql.session_track.data",
2473                   FT_NONE, BASE_NONE, NULL, 0x0,
2474                   NULL, HFILL }},
2475
2476                 { &hf_mysql_session_track_data_length,
2477                 { "Session tracking data length", "mysql.session_track.data.length",
2478                   FT_UINT64, BASE_DEC, NULL, 0x0,
2479                   NULL, HFILL }},
2480
2481                 { &hf_mysql_session_track_sysvar_length,
2482                 { "System variable change Length", "mysql.session_track.sysvar.length",
2483                   FT_UINT64, BASE_DEC, NULL, 0x0,
2484                   NULL, HFILL }},
2485
2486                 { &hf_mysql_session_track_sysvar_name,
2487                 { "System variable change Name", "mysql.session_track.sysvar.name",
2488                   FT_STRINGZ, BASE_NONE, NULL, 0x0,
2489                   NULL, HFILL }},
2490
2491                 { &hf_mysql_session_track_sysvar_value,
2492                 { "System variable change Value", "mysql.session_track.sysvar.value",
2493                   FT_STRINGZ, BASE_NONE, NULL, 0x0,
2494                   NULL, HFILL }},
2495
2496                 { &hf_mysql_session_track_schema_length,
2497                 { "Schema change length", "mysql.session_track.schema.length",
2498                   FT_UINT64, BASE_DEC, NULL, 0x0,
2499                   NULL, HFILL }},
2500
2501                 { &hf_mysql_session_track_schema,
2502                 { "Schema change", "mysql.session_track.schema",
2503                   FT_STRINGZ, BASE_NONE, NULL, 0x0,
2504                   NULL, HFILL }},
2505
2506                 { &hf_mysql_session_state_change,
2507                 { "State change", "mysql.session_track.state_change",
2508                   FT_STRINGZ, BASE_NONE, NULL, 0x0,
2509                   NULL, HFILL }},
2510
2511                 { &hf_mysql_caps_server,
2512                 { "Server Capabilities", "mysql.caps.server",
2513                 FT_UINT16, BASE_HEX, NULL, 0x0,
2514                 "MySQL Capabilities", HFILL }},
2515
2516                 { &hf_mysql_caps_client,
2517                 { "Client Capabilities", "mysql.caps.client",
2518                 FT_UINT16, BASE_HEX, NULL, 0x0,
2519                 "MySQL Capabilities", HFILL }},
2520
2521                 { &hf_mysql_cap_long_password,
2522                 { "Long Password","mysql.caps.lp",
2523                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_LP,
2524                 NULL, HFILL }},
2525
2526                 { &hf_mysql_cap_found_rows,
2527                 { "Found Rows","mysql.caps.fr",
2528                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_FR,
2529                 NULL, HFILL }},
2530
2531                 { &hf_mysql_cap_long_flag,
2532                 { "Long Column Flags","mysql.caps.lf",
2533                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_LF,
2534                 NULL, HFILL }},
2535
2536                 { &hf_mysql_cap_connect_with_db,
2537                 { "Connect With Database","mysql.caps.cd",
2538                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_CD,
2539                 NULL, HFILL }},
2540
2541                 { &hf_mysql_cap_no_schema,
2542                 { "Don't Allow database.table.column","mysql.caps.ns",
2543                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_NS,
2544                 NULL, HFILL }},
2545
2546                 { &hf_mysql_cap_compress,
2547                 { "Can use compression protocol","mysql.caps.cp",
2548                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_CP,
2549                 NULL, HFILL }},
2550
2551                 { &hf_mysql_cap_odbc,
2552                 { "ODBC Client","mysql.caps.ob",
2553                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_OB,
2554                 NULL, HFILL }},
2555
2556                 { &hf_mysql_cap_local_files,
2557                 { "Can Use LOAD DATA LOCAL","mysql.caps.li",
2558                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_LI,
2559                 NULL, HFILL }},
2560
2561                 { &hf_mysql_cap_ignore_space,
2562                 { "Ignore Spaces before '('","mysql.caps.is",
2563                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_IS,
2564                 NULL, HFILL }},
2565
2566                 { &hf_mysql_cap_change_user,
2567                 { "Speaks 4.1 protocol (new flag)","mysql.caps.cu",
2568                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_CU,
2569                 NULL, HFILL }},
2570
2571                 { &hf_mysql_cap_interactive,
2572                 { "Interactive Client","mysql.caps.ia",
2573                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_IA,
2574                 NULL, HFILL }},
2575
2576                 { &hf_mysql_cap_ssl,
2577                 { "Switch to SSL after handshake","mysql.caps.sl",
2578                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_SL,
2579                 NULL, HFILL }},
2580
2581                 { &hf_mysql_cap_ignore_sigpipe,
2582                 { "Ignore sigpipes","mysql.caps.ii",
2583                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_II,
2584                 NULL, HFILL }},
2585
2586                 { &hf_mysql_cap_transactions,
2587                 { "Knows about transactions","mysql.caps.ta",
2588                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_TA,
2589                 NULL, HFILL }},
2590
2591                 { &hf_mysql_cap_reserved,
2592                 { "Speaks 4.1 protocol (old flag)","mysql.caps.rs",
2593                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_RS,
2594                 NULL, HFILL }},
2595
2596                 { &hf_mysql_cap_secure_connect,
2597                 { "Can do 4.1 authentication","mysql.caps.sc",
2598                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_SC,
2599                 NULL, HFILL }},
2600
2601                 { &hf_mysql_extcaps_server,
2602                 { "Extended Server Capabilities", "mysql.extcaps.server",
2603                 FT_UINT16, BASE_HEX, NULL, 0x0,
2604                 "MySQL Extended Capabilities", HFILL }},
2605
2606                 { &hf_mysql_extcaps_client,
2607                 { "Extended Client Capabilities", "mysql.extcaps.client",
2608                 FT_UINT16, BASE_HEX, NULL, 0x0,
2609                 "MySQL Extended Capabilities", HFILL }},
2610
2611                 { &hf_mysql_cap_multi_statements,
2612                 { "Multiple statements","mysql.caps.ms",
2613                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_MS,
2614                 NULL, HFILL }},
2615
2616                 { &hf_mysql_cap_multi_results,
2617                 { "Multiple results","mysql.caps.mr",
2618                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_MR,
2619                 NULL, HFILL }},
2620
2621                 { &hf_mysql_cap_ps_multi_results,
2622                 { "PS Multiple results","mysql.caps.pm",
2623                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_PM,
2624                 NULL, HFILL }},
2625
2626                 { &hf_mysql_cap_plugin_auth,
2627                 { "Plugin Auth","mysql.caps.pa",
2628                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_PA,
2629                 NULL, HFILL }},
2630
2631                 { &hf_mysql_cap_connect_attrs,
2632                 { "Connect attrs","mysql.caps.ca",
2633                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_CA,
2634                 NULL, HFILL }},
2635
2636                 { &hf_mysql_cap_plugin_auth_lenenc_client_data,
2637                 { "Plugin Auth LENENC Client Data","mysql.caps.pm",
2638                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_AL,
2639                 NULL, HFILL }},
2640
2641                 { &hf_mysql_cap_client_can_handle_expired_passwords,
2642                 { "Client can handle expired passwords","mysql.caps.ep",
2643                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_EP,
2644                 NULL, HFILL }},
2645
2646                 { &hf_mysql_cap_session_track,
2647                 { "Session variable tracking","mysql.caps.session_track",
2648                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_ST,
2649                 NULL, HFILL }},
2650
2651                 { &hf_mysql_cap_deprecate_eof,
2652                 { "Deprecate EOF","mysql.caps.deprecate_eof",
2653                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_DE,
2654                 NULL, HFILL }},
2655
2656                 { &hf_mysql_cap_unused,
2657                 { "Unused","mysql.caps.unused",
2658                 FT_UINT16, BASE_HEX, NULL, MYSQL_CAPS_UNUSED,
2659                 NULL, HFILL }},
2660
2661                 { &hf_mysql_login_request,
2662                 { "Login Request", "mysql.login_request",
2663                 FT_NONE, BASE_NONE, NULL, 0x0,
2664                 NULL, HFILL }},
2665
2666                 { &hf_mysql_max_packet,
2667                 { "MAX Packet", "mysql.max_packet",
2668                 FT_UINT24, BASE_DEC, NULL, 0x0,
2669                 "MySQL Max packet", HFILL }},
2670
2671                 { &hf_mysql_charset,
2672                 { "Charset", "mysql.charset",
2673                 FT_UINT8, BASE_DEC|BASE_EXT_STRING, &mysql_collation_vals_ext, 0x0,
2674                 "MySQL Charset", HFILL }},
2675
2676                 { &hf_mysql_table_name,
2677                 { "Table Name", "mysql.table_name",
2678                 FT_STRINGZ, BASE_NONE, NULL, 0x0,
2679                 NULL, HFILL }},
2680
2681                 { &hf_mysql_user,
2682                 { "Username", "mysql.user",
2683                 FT_STRINGZ, BASE_NONE, NULL, 0x0,
2684                 "Login Username", HFILL }},
2685
2686                 { &hf_mysql_schema,
2687                 { "Schema", "mysql.schema",
2688                 FT_STRING, BASE_NONE, NULL, 0x0,
2689                 "Login Schema", HFILL }},
2690
2691                 { &hf_mysql_client_auth_plugin,
2692                 { "Client Auth Plugin", "mysql.client_auth_plugin",
2693                 FT_STRING, BASE_NONE, NULL, 0x0,
2694                 NULL, HFILL }},
2695
2696                 { &hf_mysql_connattrs,
2697                 { "Connection Attributes", "mysql.connattrs",
2698                 FT_NONE, BASE_NONE, NULL, 0x0,
2699                 NULL, HFILL }},
2700
2701                 { &hf_mysql_connattrs_length,
2702                 { "Connection Attributes length", "mysql.connattrs.length",
2703                   FT_UINT64, BASE_DEC, NULL, 0x0,
2704                   NULL, HFILL }},
2705
2706                 { &hf_mysql_connattrs_attr,
2707                 { "Connection Attribute", "mysql.connattrs.attr",
2708                   FT_NONE, BASE_NONE, NULL, 0x0,
2709                   NULL, HFILL }},
2710
2711                 { &hf_mysql_connattrs_name_length,
2712                 { "Connection Attribute Name Length", "mysql.connattrs.name.length",
2713                   FT_UINT64, BASE_DEC, NULL, 0x0,
2714                   NULL, HFILL }},
2715
2716                 { &hf_mysql_connattrs_name,
2717                 { "Connection Attribute Name", "mysql.connattrs.name",
2718                   FT_STRINGZ, BASE_NONE, NULL, 0x0,
2719                   NULL, HFILL }},
2720
2721                 { &hf_mysql_connattrs_value_length,
2722                 { "Connection Attribute Name Length", "mysql.connattrs.name.length",
2723                   FT_UINT64, BASE_DEC, NULL, 0x0,
2724                   NULL, HFILL }},
2725
2726                 { &hf_mysql_connattrs_value,
2727                 { "Connection Attribute Value", "mysql.connattrs.value",
2728                   FT_STRINGZ, BASE_NONE, NULL, 0x0,
2729                   NULL, HFILL }},
2730
2731                 { &hf_mysql_salt,
2732                 { "Salt", "mysql.salt",
2733                 FT_STRINGZ, BASE_NONE, NULL, 0x0,
2734                 NULL, HFILL }},
2735
2736                 { &hf_mysql_salt2,
2737                 { "Salt", "mysql.salt2",
2738                 FT_STRINGZ, BASE_NONE, NULL, 0x0,
2739                 NULL, HFILL }},
2740
2741                 { &hf_mysql_auth_plugin_length,
2742                 { "Authentication Plugin Length", "mysql.auth_plugin.length",
2743                 FT_UINT8, BASE_DEC, NULL, 0x0,
2744                 NULL, HFILL }},
2745
2746                 { &hf_mysql_auth_plugin,
2747                 { "Authentication Plugin", "mysql.auth_plugin",
2748                 FT_STRINGZ, BASE_NONE, NULL, 0x0,
2749                 NULL, HFILL }},
2750
2751                 { &hf_mysql_thread_id,
2752                 { "Thread ID", "mysql.thread_id",
2753                 FT_UINT32, BASE_DEC, NULL, 0x0,
2754                 "MySQL Thread ID", HFILL }},
2755
2756                 { &hf_mysql_server_language,
2757                 { "Server Language", "mysql.server_language",
2758                 FT_UINT8, BASE_DEC|BASE_EXT_STRING, &mysql_collation_vals_ext, 0x0,
2759                 "MySQL Charset", HFILL }},
2760
2761                 { &hf_mysql_server_status,
2762                 { "Server Status", "mysql.server_status",
2763                 FT_UINT16, BASE_HEX, NULL, 0x0,
2764                 "MySQL Status", HFILL }},
2765
2766                 { &hf_mysql_stat_it,
2767                 { "In transaction", "mysql.stat.it",
2768                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_IT,
2769                 NULL, HFILL }},
2770
2771                 { &hf_mysql_stat_ac,
2772                 { "AUTO_COMMIT", "mysql.stat.ac",
2773                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_AC,
2774                 NULL, HFILL }},
2775
2776                 { &hf_mysql_stat_mr,
2777                 { "More results", "mysql.stat.mr",
2778                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_MR,
2779                 NULL, HFILL }},
2780
2781                 { &hf_mysql_stat_mu,
2782                 { "Multi query / Unused", "mysql.stat.mu",
2783                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_MU,
2784                 "Multi query / Unused with MySQL >= 5.6", HFILL }},
2785
2786                 { &hf_mysql_stat_bi,
2787                 { "Bad index used", "mysql.stat.bi",
2788                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_BI,
2789                 NULL, HFILL }},
2790
2791                 { &hf_mysql_stat_ni,
2792                 { "No index used", "mysql.stat.ni",
2793                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_NI,
2794                 NULL, HFILL }},
2795
2796                 { &hf_mysql_stat_cr,
2797                 { "Cursor exists", "mysql.stat.cr",
2798                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_CR,
2799                 NULL, HFILL }},
2800
2801                 { &hf_mysql_stat_lr,
2802                 { "Last row sent", "mysql.stat.lr",
2803                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_LR,
2804                 NULL, HFILL }},
2805
2806                 { &hf_mysql_stat_dr,
2807                 { "Database dropped", "mysql.stat.dr",
2808                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_DR,
2809                 NULL, HFILL }},
2810
2811                 { &hf_mysql_stat_bs,
2812                 { "No backslash escapes", "mysql.stat.bs",
2813                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_BS,
2814                 NULL, HFILL }},
2815
2816                 { &hf_mysql_stat_mc,
2817                 { "Metadata changed", "mysql.stat.mc",
2818                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_MC,
2819                 NULL, HFILL }},
2820
2821                 { &hf_mysql_stat_session_state_changed,
2822                 { "Session state changed", "mysql.stat.session_state_changed",
2823                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_SESSION_STATE_CHANGED,
2824                 NULL, HFILL }},
2825
2826                 { &hf_mysql_stat_query_was_slow,
2827                 { "Query was slow", "mysql.stat.query_was_slow",
2828                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_QUERY_WAS_SLOW,
2829                 NULL, HFILL }},
2830
2831                 { &hf_mysql_stat_ps_out_params,
2832                 { "PS Out Params", "mysql.stat.ps_out_params",
2833                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_PS_OUT_PARAMS,
2834                 NULL, HFILL }},
2835
2836                 { &hf_mysql_stat_trans_readonly,
2837                 { "In Trans Readonly", "mysql.stat.trans_readonly",
2838                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_TRANS_READONLY,
2839                 NULL, HFILL }},
2840
2841                 { &hf_mysql_refresh,
2842                 { "Refresh Option", "mysql.refresh",
2843                 FT_UINT8, BASE_HEX, NULL, 0x0,
2844                 NULL, HFILL }},
2845
2846                 { &hf_mysql_rfsh_grants,
2847                 { "reload permissions", "mysql.rfsh.grants",
2848                 FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_GRANT,
2849                 NULL, HFILL }},
2850
2851                 { &hf_mysql_rfsh_log,
2852                 { "flush logfiles", "mysql.rfsh.log",
2853                 FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_LOG,
2854                 NULL, HFILL }},
2855
2856                 { &hf_mysql_rfsh_tables,
2857                 { "flush tables", "mysql.rfsh.tables",
2858                 FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_TABLES,
2859                 NULL, HFILL }},
2860
2861                 { &hf_mysql_rfsh_hosts,
2862                 { "flush hosts", "mysql.rfsh.hosts",
2863                 FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_HOSTS,
2864                 NULL, HFILL }},
2865
2866                 { &hf_mysql_rfsh_status,
2867                 { "reset statistics", "mysql.rfsh.status",
2868                 FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_STATUS,
2869                 NULL, HFILL }},
2870
2871                 { &hf_mysql_rfsh_threads,
2872                 { "empty thread cache", "mysql.rfsh.threads",
2873                 FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_THREADS,
2874                 NULL, HFILL }},
2875
2876                 { &hf_mysql_rfsh_slave,
2877                 { "flush slave status", "mysql.rfsh.slave",
2878                 FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_SLAVE,
2879                 NULL, HFILL }},
2880
2881                 { &hf_mysql_rfsh_master,
2882                 { "flush master status", "mysql.rfsh.master",
2883                 FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_MASTER,
2884                 NULL, HFILL }},
2885
2886                 { &hf_mysql_unused,
2887                 { "Unused", "mysql.unused",
2888                 FT_BYTES, BASE_NONE, NULL, 0x0,
2889                 NULL, HFILL }},
2890
2891                 { &hf_mysql_passwd,
2892                 { "Password", "mysql.passwd",
2893                 FT_BYTES, BASE_NONE, NULL, 0x0,
2894                 NULL, HFILL }},
2895
2896                 { &hf_mysql_payload,
2897                 { "Payload", "mysql.payload",
2898                 FT_BYTES, BASE_NONE, NULL, 0x0,
2899                 "Additional Payload", HFILL }},
2900
2901                 { &hf_mysql_affected_rows,
2902                 { "Affected Rows", "mysql.affected_rows",
2903                 FT_UINT64, BASE_DEC, NULL, 0x0,
2904                 NULL, HFILL }},
2905
2906                 { &hf_mysql_insert_id,
2907                 { "Last INSERT ID", "mysql.insert_id",
2908                 FT_UINT64, BASE_DEC, NULL, 0x0,
2909                 NULL, HFILL }},
2910
2911                 { &hf_mysql_num_warn,
2912                 { "Warnings", "mysql.warnings",
2913                 FT_UINT16, BASE_DEC, NULL, 0x0,
2914                 NULL, HFILL }},
2915
2916                 { &hf_mysql_thd_id,
2917                 { "Thread ID", "mysql.thd_id",
2918                 FT_UINT32, BASE_DEC, NULL, 0x0,
2919                 NULL, HFILL }},
2920
2921                 { &hf_mysql_stmt_id,
2922                 { "Statement ID", "mysql.stmt_id",
2923                 FT_UINT32, BASE_DEC, NULL, 0x0,
2924                 NULL, HFILL }},
2925
2926                 { &hf_mysql_query,
2927                 { "Statement", "mysql.query",
2928                 FT_STRING, BASE_NONE, NULL, 0x0,
2929                 NULL, HFILL }},
2930
2931                 { &hf_mysql_shutdown,
2932                 { "Shutdown Level", "mysql.shutdown",
2933                 FT_UINT8, BASE_DEC, VALS(mysql_shutdown_vals), 0x0,
2934                 NULL, HFILL }},
2935
2936                 { &hf_mysql_option,
2937                 { "Option", "mysql.option",
2938                 FT_UINT16, BASE_DEC, VALS(mysql_option_vals), 0x0,
2939                 NULL, HFILL }},
2940
2941                 { &hf_mysql_param,
2942                 { "Parameter", "mysql.param",
2943                 FT_UINT16, BASE_DEC, NULL, 0x0,
2944                 NULL, HFILL }},
2945
2946                 { &hf_mysql_num_params,
2947                 { "Number of parameter", "mysql.num_params",
2948                 FT_UINT16, BASE_DEC, NULL, 0x0,
2949                 NULL, HFILL }},
2950
2951                 { &hf_mysql_num_rows,
2952                 { "Rows to fetch", "mysql.num_rows",
2953                 FT_UINT32, BASE_DEC, NULL, 0x0,
2954                 NULL, HFILL }},
2955
2956                 { &hf_mysql_exec_flags4,
2957                 { "Flags (unused)", "mysql.exec_flags",
2958                 FT_UINT8, BASE_DEC, NULL, 0x0,
2959                 NULL, HFILL }},
2960
2961                 { &hf_mysql_exec_flags5,
2962                 { "Flags", "mysql.exec_flags",
2963                 FT_UINT8, BASE_DEC, VALS(mysql_exec_flags_vals), 0x0,
2964                 NULL, HFILL }},
2965
2966                 { &hf_mysql_new_parameter_bound_flag,
2967                 { "New parameter bound flag", "mysql.new_parameter_bound_flag",
2968                 FT_UINT8, BASE_DEC, VALS(mysql_new_parameter_bound_flag_vals), 0x0,
2969                 NULL, HFILL }},
2970
2971                 { &hf_mysql_exec_iter,
2972                 { "Iterations (unused)", "mysql.exec_iter",
2973                 FT_UINT32, BASE_DEC, NULL, 0x0,
2974                 NULL, HFILL }},
2975
2976                 { &hf_mysql_binlog_position,
2977                 { "Binlog Position", "mysql.binlog.position",
2978                 FT_UINT32, BASE_DEC, NULL, 0x0,
2979                 "Position to start at", HFILL }},
2980
2981                 { &hf_mysql_binlog_flags,
2982                 { "Binlog Flags", "mysql.binlog.flags",
2983                 FT_UINT16, BASE_HEX, NULL, 0x0,
2984                 "(currently not used; always 0)", HFILL }},
2985
2986                 { &hf_mysql_binlog_server_id,
2987                 { "Binlog server id", "mysql.binlog.server_id",
2988                 FT_UINT16, BASE_HEX, NULL, 0x0,
2989                 "server_id of the slave", HFILL }},
2990
2991                 { &hf_mysql_binlog_file_name,
2992                 { "Binlog file name", "mysql.binlog.file_name",
2993                 FT_STRINGZ, BASE_NONE, NULL, 0x0,
2994                 NULL, HFILL }},
2995
2996                 { &hf_mysql_eof,
2997                 { "EOF marker", "mysql.eof",
2998                 FT_UINT8, BASE_DEC, NULL, 0x0,
2999                 NULL, HFILL }},
3000
3001                 { &hf_mysql_num_fields,
3002                 { "Number of fields", "mysql.num_fields",
3003                 FT_UINT64, BASE_DEC, NULL, 0x0,
3004                 NULL, HFILL }},
3005
3006                 { &hf_mysql_extra,
3007                 { "Extra data", "mysql.extra",
3008                 FT_UINT64, BASE_DEC, NULL, 0x0,
3009                 NULL, HFILL }},
3010
3011                 { &hf_mysql_fld_catalog,
3012                 { "Catalog", "mysql.field.catalog",
3013                 FT_STRING, BASE_NONE, NULL, 0x0,
3014                 "Field: catalog", HFILL }},
3015
3016                 { &hf_mysql_fld_db,
3017                 { "Database", "mysql.field.db",
3018                 FT_STRING, BASE_NONE, NULL, 0x0,
3019                 "Field: database", HFILL }},
3020
3021                 { &hf_mysql_fld_table,
3022                 { "Table", "mysql.field.table",
3023                 FT_STRING, BASE_NONE, NULL, 0x0,
3024                 "Field: table", HFILL }},
3025
3026                 { &hf_mysql_fld_org_table,
3027                 { "Original table", "mysql.field.org_table",
3028                 FT_STRING, BASE_NONE, NULL, 0x0,
3029                 "Field: original table", HFILL }},
3030
3031                 { &hf_mysql_fld_name,
3032                 { "Name", "mysql.field.name",
3033                 FT_STRING, BASE_NONE, NULL, 0x0,
3034                 "Field: name", HFILL }},
3035
3036                 { &hf_mysql_fld_org_name,
3037                 { "Original name", "mysql.field.org_name",
3038                 FT_STRING, BASE_NONE, NULL, 0x0,
3039                 "Field: original name", HFILL }},
3040
3041                 { &hf_mysql_fld_charsetnr,
3042                 { "Charset number", "mysql.field.charsetnr",
3043                 FT_UINT16, BASE_DEC|BASE_EXT_STRING, &mysql_collation_vals_ext, 0x0,
3044                 "Field: charset number", HFILL }},
3045
3046                 { &hf_mysql_fld_length,
3047                 { "Length", "mysql.field.length",
3048                 FT_UINT32, BASE_DEC, NULL, 0x0,
3049                 "Field: length", HFILL }},
3050
3051                 { &hf_mysql_fld_type,
3052                 { "Type", "mysql.field.type",
3053                 FT_UINT8, BASE_DEC, VALS(type_constants), 0x0,
3054                 "Field: type", HFILL }},
3055
3056                 { &hf_mysql_fld_flags,
3057                 { "Flags", "mysql.field.flags",
3058                 FT_UINT16, BASE_HEX, NULL, 0x0,
3059                 "Field: flags", HFILL }},
3060
3061                 { &hf_mysql_fld_not_null,
3062                 { "Not null", "mysql.field.flags.not_null",
3063                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_NOT_NULL_FLAG,
3064                 "Field: flag not null", HFILL }},
3065
3066                 { &hf_mysql_fld_primary_key,
3067                 { "Primary key", "mysql.field.flags.primary_key",
3068                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_PRI_KEY_FLAG,
3069                 "Field: flag primary key", HFILL }},
3070
3071                 { &hf_mysql_fld_unique_key,
3072                 { "Unique key", "mysql.field.flags.unique_key",
3073                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_UNIQUE_KEY_FLAG,
3074                 "Field: flag unique key", HFILL }},
3075
3076                 { &hf_mysql_fld_multiple_key,
3077                 { "Multiple key", "mysql.field.flags.multiple_key",
3078                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_MULTIPLE_KEY_FLAG,
3079                 "Field: flag multiple key", HFILL }},
3080
3081                 { &hf_mysql_fld_blob,
3082                 { "Blob", "mysql.field.flags.blob",
3083                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_BLOB_FLAG,
3084                 "Field: flag blob", HFILL }},
3085
3086                 { &hf_mysql_fld_unsigned,
3087                 { "Unsigned", "mysql.field.flags.unsigned",
3088                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_UNSIGNED_FLAG,
3089                 "Field: flag unsigned", HFILL }},
3090
3091                 { &hf_mysql_fld_zero_fill,
3092                 { "Zero fill", "mysql.field.flags.zero_fill",
3093                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_ZEROFILL_FLAG,
3094                 "Field: flag zero fill", HFILL }},
3095
3096                 { &hf_mysql_fld_binary,
3097                 { "Binary", "mysql.field.flags.binary",
3098                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_BINARY_FLAG,
3099                 "Field: flag binary", HFILL }},
3100
3101                 { &hf_mysql_fld_enum,
3102                 { "Enum", "mysql.field.flags.enum",
3103                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_ENUM_FLAG,
3104                 "Field: flag enum", HFILL }},
3105
3106                 { &hf_mysql_fld_auto_increment,
3107                 { "Auto increment", "mysql.field.flags.auto_increment",
3108                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_AUTO_INCREMENT_FLAG,
3109                 "Field: flag auto increment", HFILL }},
3110
3111                 { &hf_mysql_fld_timestamp,
3112                 { "Timestamp", "mysql.field.flags.timestamp",
3113                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_TIMESTAMP_FLAG,
3114                 "Field: flag timestamp", HFILL }},
3115
3116                 { &hf_mysql_fld_set,
3117                 { "Set", "mysql.field.flags.set",
3118                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_SET_FLAG,
3119                 "Field: flag set", HFILL }},
3120
3121                 { &hf_mysql_fld_decimals,
3122                 { "Decimals", "mysql.field.decimals",
3123                 FT_UINT8, BASE_DEC, NULL, 0x0,
3124                 "Field: decimals", HFILL }},
3125
3126                 { &hf_mysql_fld_default,
3127                 { "Default", "mysql.field.default",
3128                 FT_STRING, BASE_NONE, NULL, 0x0,
3129                 "Field: default", HFILL }},
3130
3131                 { &hf_mysql_row_text,
3132                 { "text", "mysql.row.text",
3133                 FT_STRING, BASE_NONE, NULL, 0x0,
3134                 "Field: row packet text", HFILL }},
3135
3136                 { &hf_mysql_exec_param,
3137                 { "Parameter", "mysql.exec_param",
3138                 FT_NONE, BASE_NONE, NULL, 0x0,
3139                 NULL, HFILL }},
3140
3141                 { &hf_mysql_exec_unsigned,
3142                 { "Unsigned", "mysql.exec.unsigned",
3143                 FT_UINT8, BASE_DEC, NULL, 0x0,
3144                 NULL, HFILL }},
3145
3146                 { &hf_mysql_exec_field_longlong,
3147                 { "Value", "mysql.exec.field.longlong",
3148                 FT_INT64, BASE_DEC, NULL, 0x0,
3149                 NULL, HFILL }},
3150
3151                 { &hf_mysql_exec_field_string,
3152                 { "Value", "mysql.exec.field.string",
3153                 FT_UINT_STRING, BASE_NONE, NULL, 0x0,
3154                 NULL, HFILL }},
3155
3156                 { &hf_mysql_exec_field_double,
3157                 { "Value", "mysql.exec.field.double",
3158                 FT_DOUBLE, BASE_NONE, NULL, 0x0,
3159                 NULL, HFILL }},
3160
3161                 { &hf_mysql_exec_field_datetime_length,
3162                 { "Length", "mysql.exec.field.datetime.length",
3163                 FT_INT8, BASE_DEC, NULL, 0x0,
3164                 NULL, HFILL }},
3165
3166                 { &hf_mysql_exec_field_year,
3167                 { "Year", "mysql.exec.field.year",
3168                 FT_INT16, BASE_DEC, NULL, 0x0,
3169                 NULL, HFILL }},
3170
3171                 { &hf_mysql_exec_field_month,
3172                 { "Month", "mysql.exec.field.month",
3173                 FT_INT8, BASE_DEC, NULL, 0x0,
3174                 NULL, HFILL }},
3175
3176                 { &hf_mysql_exec_field_day,
3177                 { "Day", "mysql.exec.field.day",
3178                 FT_INT8, BASE_DEC, NULL, 0x0,
3179                 NULL, HFILL }},
3180
3181                 { &hf_mysql_exec_field_hour,
3182                 { "Hour", "mysql.exec.field.hour",
3183                 FT_INT8, BASE_DEC, NULL, 0x0,
3184                 NULL, HFILL }},
3185
3186                 { &hf_mysql_exec_field_minute,
3187                 { "Minute", "mysql.exec.field.minute",
3188                 FT_INT8, BASE_DEC, NULL, 0x0,
3189                 NULL, HFILL }},
3190
3191                 { &hf_mysql_exec_field_second,
3192                 { "Second", "mysql.exec.field.second",
3193                 FT_INT8, BASE_DEC, NULL, 0x0,
3194                 NULL, HFILL }},
3195
3196                 { &hf_mysql_exec_field_second_b,
3197                 { "Billionth of a second", "mysql.exec.field.secondb",
3198                 FT_INT32, BASE_DEC, NULL, 0x0,
3199                 NULL, HFILL }},
3200
3201                 { &hf_mysql_exec_field_long,
3202                 { "Value", "mysql.exec.field.long",
3203                 FT_INT32, BASE_DEC, NULL, 0x0,
3204                 NULL, HFILL }},
3205
3206                 { &hf_mysql_exec_field_tiny,
3207                 { "Value", "mysql.exec.field.tiny",
3208                 FT_INT8, BASE_DEC, NULL, 0x0,
3209                 NULL, HFILL }},
3210
3211                 { &hf_mysql_exec_field_short,
3212                 { "Value", "mysql.exec.field.short",
3213                 FT_INT16, BASE_DEC, NULL, 0x0,
3214                 NULL, HFILL }},
3215
3216                 { &hf_mysql_exec_field_float,
3217                 { "Value", "mysql.exec.field.float",
3218                 FT_FLOAT, BASE_NONE, NULL, 0x0,
3219                 NULL, HFILL }},
3220
3221                 { &hf_mysql_exec_field_time_length,
3222                 { "Length", "mysql.exec.field.time.length",
3223                 FT_INT8, BASE_DEC, NULL, 0x0,
3224                 NULL, HFILL }},
3225
3226                 { &hf_mysql_exec_field_time_sign,
3227                 { "Flags", "mysql.exec.field.time.sign",
3228                 FT_UINT8, BASE_DEC, VALS(mysql_exec_time_sign_vals), 0x0,
3229                 NULL, HFILL }},
3230
3231                 { &hf_mysql_exec_field_time_days,
3232                 { "Days", "mysql.exec.field.time.days",
3233                 FT_INT32, BASE_DEC, NULL, 0x0,
3234                 NULL, HFILL }},
3235
3236                 { &hf_mysql_auth_switch_request_status,
3237                 { "Status", "mysql.auth_switch_request.status",
3238                 FT_UINT8, BASE_HEX, NULL, 0x0,
3239                 NULL, HFILL }},
3240
3241                 { &hf_mysql_auth_switch_request_name,
3242                 { "Auth Method Name", "mysql.auth_switch_request.name",
3243                 FT_STRING, BASE_NONE, NULL, 0x0,
3244                 NULL, HFILL }},
3245
3246                 { &hf_mysql_auth_switch_request_data,
3247                 { "Auth Method Data", "mysql.auth_switch_request.data",
3248                 FT_BYTES, BASE_NONE, NULL, 0x0,
3249                 NULL, HFILL }},
3250
3251                 { &hf_mysql_auth_switch_response_data,
3252                 { "Auth Method Data", "mysql.auth_switch_response.data",
3253                 FT_BYTES, BASE_NONE, NULL, 0x0,
3254                 NULL, HFILL }},
3255
3256                 { &hf_mysql_compressed_packet_length,
3257                 { "Compressed Packet Length", "mysql.compressed_packet_length",
3258                 FT_UINT24, BASE_DEC, NULL,  0x0,
3259                 NULL, HFILL }},
3260
3261                 { &hf_mysql_compressed_packet_number,
3262                 { "Compressed Packet Number", "mysql.compressed_packet_number",
3263                 FT_UINT24, BASE_DEC, NULL,  0x0,
3264                 NULL, HFILL }},
3265
3266                 { &hf_mysql_compressed_packet_length_uncompressed,
3267                 { "Uncompressed Packet Length", "mysql.compressed_packet_length_uncompressed",
3268                 FT_UINT24, BASE_DEC, NULL,  0x0,
3269                 NULL, HFILL }},
3270         };
3271
3272         static gint *ett[]=
3273         {
3274                 &ett_mysql,
3275                 &ett_server_greeting,
3276                 &ett_login_request,
3277                 &ett_caps,
3278                 &ett_extcaps,
3279                 &ett_stat,
3280                 &ett_request,
3281                 &ett_refresh,
3282                 &ett_field_flags,
3283                 &ett_exec_param,
3284                 &ett_session_track,
3285                 &ett_session_track_data,
3286                 &ett_connattrs,
3287                 &ett_connattrs_attr
3288         };
3289
3290         static ei_register_info ei[] = {
3291                 { &ei_mysql_dissector_incomplete, { "mysql.dissector_incomplete", PI_UNDECODED, PI_WARN, "FIXME - dissector is incomplete", EXPFILL }},
3292                 { &ei_mysql_streamed_param, { "mysql.streamed_param", PI_SEQUENCE, PI_CHAT, "This parameter was streamed, its value can be found in Send BLOB packets", EXPFILL }},
3293                 { &ei_mysql_prepare_response_needed, { "mysql.prepare_response_needed", PI_UNDECODED, PI_WARN, "PREPARE Response packet is needed to dissect the payload", EXPFILL }},
3294                 { &ei_mysql_command, { "mysql.command.invalid", PI_PROTOCOL, PI_WARN, "Unknown/invalid command code", EXPFILL }},
3295                 { &ei_mysql_eof, { "mysql.eof.wrong_state", PI_PROTOCOL, PI_WARN, "EOF Marker found while connection in wrong state.", EXPFILL }},
3296                 { &ei_mysql_unknown_response, { "mysql.unknown_response", PI_UNDECODED, PI_WARN, "unknown/invalid response", EXPFILL }},
3297         };
3298
3299         module_t *mysql_module;
3300         expert_module_t* expert_mysql;
3301
3302         proto_mysql = proto_register_protocol("MySQL Protocol", "MySQL", "mysql");
3303         proto_register_field_array(proto_mysql, hf, array_length(hf));
3304         proto_register_subtree_array(ett, array_length(ett));
3305         expert_mysql = expert_register_protocol(proto_mysql);
3306         expert_register_field_array(expert_mysql, ei, array_length(ei));
3307
3308         mysql_module = prefs_register_protocol(proto_mysql, NULL);
3309         prefs_register_bool_preference(mysql_module, "desegment_buffers",
3310                                        "Reassemble MySQL buffers spanning multiple TCP segments",
3311                                        "Whether the MySQL dissector should reassemble MySQL buffers spanning multiple TCP segments."
3312                                        " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
3313                                        &mysql_desegment);
3314         prefs_register_bool_preference(mysql_module, "show_sql_query",
3315                                        "Show SQL Query string in INFO column",
3316                                        "Whether the MySQL dissector should display the SQL query string in the INFO column.",
3317                                        &mysql_showquery);
3318
3319         mysql_handle = register_dissector("mysql", dissect_mysql, proto_mysql);
3320 }
3321
3322 /* dissector registration */
3323 void proto_reg_handoff_mysql(void)
3324 {
3325         tls_handle = find_dissector("tls");
3326         dissector_add_uint_with_preference("tcp.port", TCP_PORT_MySQL, mysql_handle);
3327 }
3328
3329 /*
3330  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
3331  *
3332  * Local variables:
3333  * c-basic-offset: 8
3334  * tab-width: 8
3335  * indent-tabs-mode: t
3336  * End:
3337  *
3338  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
3339  * :indentSize=8:tabSize=8:noTabs=false:
3340  */