From András Veres-Szentkirályi: Added cursor type decoding to MySQL dissector
[obnox/wireshark/wip.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  * $Id$
9  *
10  * Wireshark - Network traffic analyzer
11  * By Gerald Combs <gerald@wireshark.org>
12  * Copyright 1998 Gerald Combs
13  *
14  * Copied from packet-tftp.c
15  *
16  * This program is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU General Public License
18  * as published by the Free Software Foundation; either version 2
19  * of the License, or (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
29  *
30  *
31  * the protocol spec at
32  *  http://public.logicacmg.com/~redferni/mysql/MySQL-Protocol.html
33  *  http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol
34  * and MySQL source code
35  */
36
37 /* create extra output for conversation tracking */
38 /* #define CTDEBUG 1 */
39
40 #ifdef HAVE_CONFIG_H
41 # include "config.h"
42 #endif
43
44 #include <glib.h>
45 #include <epan/packet.h>
46 #include <epan/conversation.h>
47 #include <epan/emem.h>
48
49 #include <epan/dissectors/packet-tcp.h>
50 #include <epan/prefs.h>
51 #include <epan/expert.h>
52
53 /* port for protocol registration */
54 #define TCP_PORT_MySQL   3306
55
56 /* client/server capabilities */
57 #define MYSQL_CAPS_LP 0x0001
58 #define MYSQL_CAPS_FR 0x0002
59 #define MYSQL_CAPS_LF 0x0004
60 #define MYSQL_CAPS_CD 0x0008
61 #define MYSQL_CAPS_NS 0x0010
62 #define MYSQL_CAPS_CP 0x0020
63 #define MYSQL_CAPS_OB 0x0040
64 #define MYSQL_CAPS_LI 0x0080
65 #define MYSQL_CAPS_IS 0x0100
66 #define MYSQL_CAPS_CU 0x0200
67 #define MYSQL_CAPS_IA 0x0400
68 #define MYSQL_CAPS_SL 0x0800
69 #define MYSQL_CAPS_II 0x1000
70 #define MYSQL_CAPS_TA 0x2000
71 #define MYSQL_CAPS_RS 0x4000
72 #define MYSQL_CAPS_SC 0x8000
73
74 /* field flags */
75 #define MYSQL_FLD_NOT_NULL_FLAG       0x0001
76 #define MYSQL_FLD_PRI_KEY_FLAG        0x0002
77 #define MYSQL_FLD_UNIQUE_KEY_FLAG     0x0004
78 #define MYSQL_FLD_MULTIPLE_KEY_FLAG   0x0008
79 #define MYSQL_FLD_BLOB_FLAG           0x0010
80 #define MYSQL_FLD_UNSIGNED_FLAG       0x0020
81 #define MYSQL_FLD_ZEROFILL_FLAG       0x0040
82 #define MYSQL_FLD_BINARY_FLAG         0x0080
83 #define MYSQL_FLD_ENUM_FLAG           0x0100
84 #define MYSQL_FLD_AUTO_INCREMENT_FLAG 0x0200
85 #define MYSQL_FLD_TIMESTAMP_FLAG      0x0400
86 #define MYSQL_FLD_SET_FLAG            0x0800
87
88 /* extended capabilities: 4.1+ client only */
89 #define MYSQL_CAPS_MS 0x0001
90 #define MYSQL_CAPS_MR 0x0002
91
92 /* status bitfield */
93 #define MYSQL_STAT_IT 0x0001
94 #define MYSQL_STAT_AC 0x0002
95 #define MYSQL_STAT_MR 0x0004
96 #define MYSQL_STAT_MU 0x0008
97 #define MYSQL_STAT_BI 0x0010
98 #define MYSQL_STAT_NI 0x0020
99 #define MYSQL_STAT_CR 0x0040
100 #define MYSQL_STAT_LR 0x0080
101 #define MYSQL_STAT_DR 0x0100
102 #define MYSQL_STAT_BS 0x0200
103
104 /* bitfield for MYSQL_REFRESH */
105 #define MYSQL_RFSH_GRANT   1   /* Refresh grant tables */
106 #define MYSQL_RFSH_LOG     2   /* Start on new log file */
107 #define MYSQL_RFSH_TABLES  4   /* close all tables */
108 #define MYSQL_RFSH_HOSTS   8   /* Flush host cache */
109 #define MYSQL_RFSH_STATUS  16  /* Flush status variables */
110 #define MYSQL_RFSH_THREADS 32  /* Flush thread cache */
111 #define MYSQL_RFSH_SLAVE   64  /* Reset master info and restart slave thread */
112 #define MYSQL_RFSH_MASTER  128 /* Remove all bin logs in the index and truncate the index */
113
114 /* MySQL command codes */
115 #define MYSQL_SLEEP               0  /* not from client */
116 #define MYSQL_QUIT                1
117 #define MYSQL_INIT_DB             2
118 #define MYSQL_QUERY               3
119 #define MYSQL_FIELD_LIST          4
120 #define MYSQL_CREATE_DB           5
121 #define MYSQL_DROP_DB             6
122 #define MYSQL_REFRESH             7
123 #define MYSQL_SHUTDOWN            8
124 #define MYSQL_STATISTICS          9
125 #define MYSQL_PROCESS_INFO        10
126 #define MYSQL_CONNECT             11 /* not from client */
127 #define MYSQL_PROCESS_KILL        12
128 #define MYSQL_DEBUG               13
129 #define MYSQL_PING                14
130 #define MYSQL_TIME                15 /* not from client */
131 #define MYSQL_DELAY_INSERT        16 /* not from client */
132 #define MYSQL_CHANGE_USER         17
133 #define MYSQL_BINLOG_DUMP         18 /* replication */
134 #define MYSQL_TABLE_DUMP          19 /* replication */
135 #define MYSQL_CONNECT_OUT         20 /* replication */
136 #define MYSQL_REGISTER_SLAVE      21 /* replication */
137 #define MYSQL_STMT_PREPARE        22
138 #define MYSQL_STMT_EXECUTE        23
139 #define MYSQL_STMT_SEND_LONG_DATA 24
140 #define MYSQL_STMT_CLOSE          25
141 #define MYSQL_STMT_RESET          26
142 #define MYSQL_SET_OPTION          27
143 #define MYSQL_STMT_FETCH          28
144
145 /* MySQL cursor types */
146
147 #define MYSQL_CURSOR_TYPE_NO_CURSOR  0
148 #define MYSQL_CURSOR_TYPE_READ_ONLY  1
149 #define MYSQL_CURSOR_TYPE_FOR_UPDATE 2
150 #define MYSQL_CURSOR_TYPE_SCROLLABLE 4
151
152
153 /* decoding table: command */
154 static const value_string mysql_command_vals[] = {
155         {MYSQL_SLEEP,   "SLEEP"},
156         {MYSQL_QUIT,   "Quit"},
157         {MYSQL_INIT_DB,  "Use Database"},
158         {MYSQL_QUERY,   "Query"},
159         {MYSQL_FIELD_LIST, "Show Fields"},
160         {MYSQL_CREATE_DB,  "Create Database"},
161         {MYSQL_DROP_DB , "Drop Database"},
162         {MYSQL_REFRESH , "Refresh"},
163         {MYSQL_SHUTDOWN , "Shutdown"},
164         {MYSQL_STATISTICS , "Statistics"},
165         {MYSQL_PROCESS_INFO , "Process List"},
166         {MYSQL_CONNECT , "Connect"},
167         {MYSQL_PROCESS_KILL , "Kill Server Thread"},
168         {MYSQL_DEBUG , "Dump Debuginfo"},
169         {MYSQL_PING , "Ping"},
170         {MYSQL_TIME , "Time"},
171         {MYSQL_DELAY_INSERT , "Insert Delayed"},
172         {MYSQL_CHANGE_USER , "Change User"},
173         {MYSQL_BINLOG_DUMP , "Send Binlog"},
174         {MYSQL_TABLE_DUMP, "Send Table"},
175         {MYSQL_CONNECT_OUT, "Slave Connect"},
176         {MYSQL_REGISTER_SLAVE, "Register Slave"},
177         {MYSQL_STMT_PREPARE, "Prepare Statement"},
178         {MYSQL_STMT_EXECUTE, "Execute Statement"},
179         {MYSQL_STMT_SEND_LONG_DATA, "Send BLOB"},
180         {MYSQL_STMT_CLOSE, "Close Statement"},
181         {MYSQL_STMT_RESET, "Reset Statement"},
182         {MYSQL_SET_OPTION, "Set Option"},
183         {MYSQL_STMT_FETCH, "Fetch Data"},
184         {0, NULL}
185 };
186
187 /* decoding table: exec_flags */
188 static const value_string mysql_exec_flags_vals[] = {
189         {MYSQL_CURSOR_TYPE_NO_CURSOR, "Defaults"},
190         {MYSQL_CURSOR_TYPE_READ_ONLY, "Read-only cursor"},
191         {MYSQL_CURSOR_TYPE_FOR_UPDATE, "Cursor for update"},
192         {MYSQL_CURSOR_TYPE_SCROLLABLE, "Scrollable cursor"},
193         {0, NULL}
194 };
195
196 /* charset: pre-4.1 used the term 'charset', later changed to 'collation' */
197 static const value_string mysql_charset_vals[] = {
198         {1,  "big5"},
199         {2,  "czech"},
200         {3,  "dec8"},
201         {4,  "dos" },
202         {5,  "german1"},
203         {6,  "hp8"},
204         {7,  "koi8_ru"},
205         {8,  "latin1"},
206         {9,  "latin2"},
207         {9,  "swe7 "},
208         {10, "usa7"},
209         {11, "ujis"},
210         {12, "sjis"},
211         {13, "cp1251"},
212         {14, "danish"},
213         {15, "hebrew"},
214         {16, "win1251"},
215         {17, "tis620"},
216         {18, "euc_kr"},
217         {19, "estonia"},
218         {20, "hungarian"},
219         {21, "koi8_ukr"},
220         {22, "win1251ukr"},
221         {23, "gb2312"},
222         {24, "greek"},
223         {25, "win1250"},
224         {26, "croat"},
225         {27, "gbk"},
226         {28, "cp1257"},
227         {29, "latin5"},
228         {0, NULL}
229 };
230
231
232 /* collation codes may change over time, recreate with the following SQL
233
234 SELECT CONCAT('  {', ID, ',"', CHARACTER_SET_NAME, ' COLLATE ', COLLATION_NAME, '"},')
235 FROM INFORMATION_SCHEMA.COLLATIONS
236 ORDER BY ID
237 INTO OUTFILE '/tmp/mysql-collations';
238
239 */
240 static const value_string mysql_collation_vals[] = {
241         {3,   "dec8 COLLATE dec8_swedish_ci"},
242         {4,   "cp850 COLLATE cp850_general_ci"},
243         {5,   "latin1 COLLATE latin1_german1_ci"},
244         {6,   "hp8 COLLATE hp8_english_ci"},
245         {7,   "koi8r COLLATE koi8r_general_ci"},
246         {8,   "latin1 COLLATE latin1_swedish_ci"},
247         {9,   "latin2 COLLATE latin2_general_ci"},
248         {10,  "swe7 COLLATE swe7_swedish_ci"},
249         {11,  "ascii COLLATE ascii_general_ci"},
250         {14,  "cp1251 COLLATE cp1251_bulgarian_ci"},
251         {15,  "latin1 COLLATE latin1_danish_ci"},
252         {16,  "hebrew COLLATE hebrew_general_ci"},
253         {20,  "latin7 COLLATE latin7_estonian_cs"},
254         {21,  "latin2 COLLATE latin2_hungarian_ci"},
255         {22,  "koi8u COLLATE koi8u_general_ci"},
256         {23,  "cp1251 COLLATE cp1251_ukrainian_ci"},
257         {25,  "greek COLLATE greek_general_ci"},
258         {26,  "cp1250 COLLATE cp1250_general_ci"},
259         {27,  "latin2 COLLATE latin2_croatian_ci"},
260         {29,  "cp1257 COLLATE cp1257_lithuanian_ci"},
261         {30,  "latin5 COLLATE latin5_turkish_ci"},
262         {31,  "latin1 COLLATE latin1_german2_ci"},
263         {32,  "armscii8 COLLATE armscii8_general_ci"},
264         {33,  "utf8 COLLATE utf8_general_ci"},
265         {36,  "cp866 COLLATE cp866_general_ci"},
266         {37,  "keybcs2 COLLATE keybcs2_general_ci"},
267         {38,  "macce COLLATE macce_general_ci"},
268         {39,  "macroman COLLATE macroman_general_ci"},
269         {40,  "cp852 COLLATE cp852_general_ci"},
270         {41,  "latin7 COLLATE latin7_general_ci"},
271         {42,  "latin7 COLLATE latin7_general_cs"},
272         {43,  "macce COLLATE macce_bin"},
273         {44,  "cp1250 COLLATE cp1250_croatian_ci"},
274         {47,  "latin1 COLLATE latin1_bin"},
275         {48,  "latin1 COLLATE latin1_general_ci"},
276         {49,  "latin1 COLLATE latin1_general_cs"},
277         {50,  "cp1251 COLLATE cp1251_bin"},
278         {51,  "cp1251 COLLATE cp1251_general_ci"},
279         {52,  "cp1251 COLLATE cp1251_general_cs"},
280         {53,  "macroman COLLATE macroman_bin"},
281         {57,  "cp1256 COLLATE cp1256_general_ci"},
282         {58,  "cp1257 COLLATE cp1257_bin"},
283         {59,  "cp1257 COLLATE cp1257_general_ci"},
284         {63,  "binary COLLATE binary"},
285         {64,  "armscii8 COLLATE armscii8_bin"},
286         {65,  "ascii COLLATE ascii_bin"},
287         {66,  "cp1250 COLLATE cp1250_bin"},
288         {67,  "cp1256 COLLATE cp1256_bin"},
289         {68,  "cp866 COLLATE cp866_bin"},
290         {69,  "dec8 COLLATE dec8_bin"},
291         {70,  "greek COLLATE greek_bin"},
292         {71,  "hebrew COLLATE hebrew_bin"},
293         {72,  "hp8 COLLATE hp8_bin"},
294         {73,  "keybcs2 COLLATE keybcs2_bin"},
295         {74,  "koi8r COLLATE koi8r_bin"},
296         {75,  "koi8u COLLATE koi8u_bin"},
297         {77,  "latin2 COLLATE latin2_bin"},
298         {78,  "latin5 COLLATE latin5_bin"},
299         {79,  "latin7 COLLATE latin7_bin"},
300         {80,  "cp850 COLLATE cp850_bin"},
301         {81,  "cp852 COLLATE cp852_bin"},
302         {82,  "swe7 COLLATE swe7_bin"},
303         {83,  "utf8 COLLATE utf8_bin"},
304         {92,  "geostd8 COLLATE geostd8_general_ci"},
305         {93,  "geostd8 COLLATE geostd8_bin"},
306         {94,  "latin1 COLLATE latin1_spanish_ci"},
307         {99,  "cp1250 COLLATE cp1250_polish_ci"},
308         {192, "utf8 COLLATE utf8_unicode_ci"},
309         {193, "utf8 COLLATE utf8_icelandic_ci"},
310         {194, "utf8 COLLATE utf8_latvian_ci"},
311         {195, "utf8 COLLATE utf8_romanian_ci"},
312         {196, "utf8 COLLATE utf8_slovenian_ci"},
313         {197, "utf8 COLLATE utf8_polish_ci"},
314         {198, "utf8 COLLATE utf8_estonian_ci"},
315         {199, "utf8 COLLATE utf8_spanish_ci"},
316         {200, "utf8 COLLATE utf8_swedish_ci"},
317         {201, "utf8 COLLATE utf8_turkish_ci"},
318         {202, "utf8 COLLATE utf8_czech_ci"},
319         {203, "utf8 COLLATE utf8_danish_ci"},
320         {204, "utf8 COLLATE utf8_lithuanian_ci"},
321         {205, "utf8 COLLATE utf8_slovak_ci"},
322         {206, "utf8 COLLATE utf8_spanish2_ci"},
323         {207, "utf8 COLLATE utf8_roman_ci"},
324         {208, "utf8 COLLATE utf8_persian_ci"},
325         {209, "utf8 COLLATE utf8_esperanto_ci"},
326         {210, "utf8 COLLATE utf8_hungarian_ci"},
327         {0, NULL}
328 };
329
330
331 /* allowed MYSQL_SHUTDOWN levels */
332 static const value_string mysql_shutdown_vals[] = {
333         {0,   "default"},
334         {1,   "wait for connections to finish"},
335         {2,   "wait for transactions to finish"},
336         {8,   "wait for updates to finish"},
337         {16,  "wait flush all buffers"},
338         {17,  "wait flush critical buffers"},
339         {254, "kill running queries"},
340         {255, "kill connections"},
341         {0, NULL}
342 };
343
344
345 /* allowed MYSQL_SET_OPTION values */
346 static const value_string mysql_option_vals[] = {
347         {0, "multi statements on"},
348         {1, "multi statements off"},
349         {0, NULL}
350 };
351
352 /* protocol id */
353 static int proto_mysql = -1;
354
355 /* dissector configuration */
356 static gboolean mysql_desegment = TRUE;
357 static gboolean mysql_showquery = FALSE;
358
359 /* expand-the-tree flags */
360 static gint ett_mysql = -1;
361 static gint ett_server_greeting = -1;
362 static gint ett_login_request = -1;
363 static gint ett_caps = -1;
364 static gint ett_extcaps = -1;
365 static gint ett_stat = -1;
366 static gint ett_request = -1;
367 static gint ett_refresh = -1;
368 static gint ett_field_flags = -1;
369
370 /* protocol fields */
371 static int hf_mysql_caps_server = -1;
372 static int hf_mysql_caps_client = -1;
373 static int hf_mysql_cap_long_password = -1;
374 static int hf_mysql_cap_found_rows = -1;
375 static int hf_mysql_cap_long_flag = -1;
376 static int hf_mysql_cap_connect_with_db = -1;
377 static int hf_mysql_cap_no_schema = -1;
378 static int hf_mysql_cap_compress = -1;
379 static int hf_mysql_cap_odbc = -1;
380 static int hf_mysql_cap_local_files = -1;
381 static int hf_mysql_cap_ignore_space = -1;
382 static int hf_mysql_cap_change_user = -1;
383 static int hf_mysql_cap_interactive = -1;
384 static int hf_mysql_cap_ssl = -1;
385 static int hf_mysql_cap_ignore_sigpipe = -1;
386 static int hf_mysql_cap_transactions = -1;
387 static int hf_mysql_cap_reserved = -1;
388 static int hf_mysql_cap_secure_connect = -1;
389 static int hf_mysql_extcaps_client = -1;
390 static int hf_mysql_cap_multi_statements = -1;
391 static int hf_mysql_cap_multi_results = -1;
392 static int hf_mysql_server_language = -1;
393 static int hf_mysql_server_status = -1;
394 static int hf_mysql_stat_it = -1;
395 static int hf_mysql_stat_ac = -1;
396 static int hf_mysql_stat_mr = -1;
397 static int hf_mysql_stat_mu = -1;
398 static int hf_mysql_stat_bi = -1;
399 static int hf_mysql_stat_ni = -1;
400 static int hf_mysql_stat_cr = -1;
401 static int hf_mysql_stat_lr = -1;
402 static int hf_mysql_stat_dr = -1;
403 static int hf_mysql_stat_bs = -1;
404 static int hf_mysql_refresh = -1;
405 static int hf_mysql_rfsh_grants = -1;
406 static int hf_mysql_rfsh_log = -1;
407 static int hf_mysql_rfsh_tables = -1;
408 static int hf_mysql_rfsh_hosts = -1;
409 static int hf_mysql_rfsh_status = -1;
410 static int hf_mysql_rfsh_threads = -1;
411 static int hf_mysql_rfsh_slave = -1;
412 static int hf_mysql_rfsh_master = -1;
413 static int hf_mysql_packet_length = -1;
414 static int hf_mysql_packet_number = -1;
415 static int hf_mysql_request = -1;
416 static int hf_mysql_command = -1;
417 static int hf_mysql_error_code = -1;
418 static int hf_mysql_error_string = -1;
419 static int hf_mysql_sqlstate = -1;
420 static int hf_mysql_message = -1;
421 static int hf_mysql_payload = -1;
422 static int hf_mysql_server_greeting = -1;
423 static int hf_mysql_protocol = -1;
424 static int hf_mysql_version  = -1;
425 static int hf_mysql_login_request = -1;
426 static int hf_mysql_max_packet = -1;
427 static int hf_mysql_user = -1;
428 static int hf_mysql_table_name = -1;
429 static int hf_mysql_schema = -1;
430 static int hf_mysql_thread_id  = -1;
431 static int hf_mysql_salt = -1;
432 static int hf_mysql_salt2 = -1;
433 static int hf_mysql_charset = -1;
434 static int hf_mysql_passwd = -1;
435 static int hf_mysql_unused = -1;
436 static int hf_mysql_affected_rows = -1;
437 static int hf_mysql_insert_id = -1;
438 static int hf_mysql_num_warn = -1;
439 static int hf_mysql_thd_id = -1;
440 static int hf_mysql_stmt_id = -1;
441 static int hf_mysql_query = -1;
442 static int hf_mysql_shutdown = -1;
443 static int hf_mysql_option = -1;
444 static int hf_mysql_num_rows = -1;
445 static int hf_mysql_param = -1;
446 static int hf_mysql_num_params = -1;
447 static int hf_mysql_exec_flags4 = -1;
448 static int hf_mysql_exec_flags5 = -1;
449 static int hf_mysql_exec_iter = -1;
450 static int hf_mysql_binlog_position = -1;
451 static int hf_mysql_binlog_flags = -1;
452 static int hf_mysql_binlog_server_id = -1;
453 static int hf_mysql_binlog_file_name = -1;
454 static int hf_mysql_eof = -1;
455 static int hf_mysql_num_fields = -1;
456 static int hf_mysql_extra = -1;
457 static int hf_mysql_fld_catalog  = -1;
458 static int hf_mysql_fld_db = -1;
459 static int hf_mysql_fld_table = -1;
460 static int hf_mysql_fld_org_table = -1;
461 static int hf_mysql_fld_name = -1;
462 static int hf_mysql_fld_org_name = -1;
463 static int hf_mysql_fld_charsetnr = -1;
464 static int hf_mysql_fld_length = -1;
465 static int hf_mysql_fld_type = -1;
466 static int hf_mysql_fld_flags = -1;
467 static int hf_mysql_fld_not_null = -1;
468 static int hf_mysql_fld_primary_key = -1;
469 static int hf_mysql_fld_unique_key = -1;
470 static int hf_mysql_fld_multiple_key = -1;
471 static int hf_mysql_fld_blob = -1;
472 static int hf_mysql_fld_unsigned = -1;
473 static int hf_mysql_fld_zero_fill = -1;
474 static int hf_mysql_fld_binary = -1;
475 static int hf_mysql_fld_enum = -1;
476 static int hf_mysql_fld_auto_increment = -1;
477 static int hf_mysql_fld_timestamp = -1;
478 static int hf_mysql_fld_set = -1;
479 static int hf_mysql_fld_decimals = -1;
480 static int hf_mysql_fld_default = -1;
481 static int hf_mysql_row_text = -1;
482
483 /* type constants */
484 static const value_string type_constants[] =
485 {
486         {0x00, "FIELD_TYPE_DECIMAL"    },
487         {0x01, "FIELD_TYPE_TINY"       },
488         {0x02, "FIELD_TYPE_SHORT"      },
489         {0x03, "FIELD_TYPE_LONG"       },
490         {0x04, "FIELD_TYPE_FLOAT"      },
491         {0x05, "FIELD_TYPE_DOUBLE"     },
492         {0x06, "FIELD_TYPE_NULL"       },
493         {0x07, "FIELD_TYPE_TIMESTAMP"  },
494         {0x08, "FIELD_TYPE_LONGLONG"   },
495         {0x09, "FIELD_TYPE_INT24"      },
496         {0x0a, "FIELD_TYPE_DATE"       },
497         {0x0b, "FIELD_TYPE_TIME"       },
498         {0x0c, "FIELD_TYPE_DATETIME"   },
499         {0x0d, "FIELD_TYPE_YEAR"       },
500         {0x0e, "FIELD_TYPE_NEWDATE"    },
501         {0x0f, "FIELD_TYPE_VARCHAR"    },
502         {0x10, "FIELD_TYPE_BIT"        },
503         {0xf6, "FIELD_TYPE_NEWDECIMAL" },
504         {0xf7, "FIELD_TYPE_ENUM"       },
505         {0xf8, "FIELD_TYPE_SET"        },
506         {0xf9, "FIELD_TYPE_TINY_BLOB"  },
507         {0xfa, "FIELD_TYPE_MEDIUM_BLOB"},
508         {0xfb, "FIELD_TYPE_LONG_BLOB"  },
509         {0xfc, "FIELD_TYPE_BLOB"       },
510         {0xfd, "FIELD_TYPE_VAR_STRING" },
511         {0xfe, "FIELD_TYPE_STRING"     },
512         {0xff, "FIELD_TYPE_GEOMETRY"   },
513         {0, NULL}
514 };
515
516 typedef enum mysql_state
517 {
518         UNDEFINED,
519         LOGIN,
520         REQUEST,
521         RESPONSE_OK,
522         RESPONSE_MESSAGE,
523         RESPONSE_TABULAR,
524         RESPONSE_SHOW_FIELDS,
525         FIELD_PACKET,
526         ROW_PACKET,
527         RESPONSE_PREPARE,
528     PREPARED_PARAMETERS,
529     PREPARED_FIELDS
530 } mysql_state_t;
531
532 #ifdef CTDEBUG
533 static const value_string state_vals[] = {
534         {UNDEFINED,            "undefined"},
535         {LOGIN,                "login"},
536         {REQUEST,              "request"},
537         {RESPONSE_OK,          "response OK"},
538         {RESPONSE_MESSAGE,     "response message"},
539         {RESPONSE_TABULAR,     "tabular response"},
540         {RESPONSE_SHOW_FIELDS, "response to SHOW FIELDS"},
541         {FIELD_PACKET,         "field packet"},
542         {ROW_PACKET,           "row packet"},
543         {RESPONSE_PREPARE,     "response to PREPARE"},
544         {RESPONSE_PARAMETERS,  "parameters in response to PREPARE"},
545         {RESPONSE_FIELDS,      "fields in response to PREPARE"},
546         {0, NULL}
547 };
548 #endif
549
550 typedef struct mysql_conn_data
551 {
552         guint16 srv_caps;
553         guint16 clnt_caps;
554         guint16 clnt_caps_ext;
555         mysql_state_t state;
556         guint16 stmt_num_params;
557         guint16 stmt_num_fields;
558         GHashTable* stmts;
559 #ifdef CTDEBUG
560         guint32 generation;
561 #endif
562         guint8 major_version;
563 } mysql_conn_data_t;
564
565 struct mysql_frame_data {
566         mysql_state_t   state;
567 };
568
569 typedef struct my_stmt_data
570 {
571         guint16 nparam;
572 } my_stmt_data_t;
573
574
575 /* function prototypes */
576 static void dissect_mysql(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
577 static guint get_mysql_pdu_len(packet_info *pinfo, tvbuff_t *tvb, int offset);
578 static void dissect_mysql_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
579 static int mysql_dissect_login(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data);
580 static int mysql_dissect_greeting(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data);
581 static int mysql_dissect_request(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data);
582 static int mysql_dissect_response(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data);
583 static int mysql_dissect_error_packet(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree);
584 static int mysql_dissect_ok_packet(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data);
585 static int mysql_dissect_server_status(tvbuff_t *tvb, int offset, proto_tree *tree);
586 static int mysql_dissect_caps_server(tvbuff_t *tvb, int offset, proto_tree *tree, guint16 *caps);
587 static int mysql_dissect_caps_client(tvbuff_t *tvb, int offset, proto_tree *tree, guint16 *caps);
588 static int mysql_dissect_ext_caps_client(tvbuff_t *tvb, int offset, proto_tree *tree, guint16 *caps);
589 static int mysql_dissect_result_header(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data);
590 static int mysql_dissect_field_packet(tvbuff_t *tvb, int offset, proto_tree *tree, mysql_conn_data_t *conn_data);
591 static int mysql_dissect_row_packet(tvbuff_t *tvb, int offset, proto_tree *tree);
592 static int mysql_dissect_response_prepare(tvbuff_t *tvb, int offset, proto_tree *tree, mysql_conn_data_t *conn_data);
593 static gint my_tvb_strsize(tvbuff_t *tvb, int offset);
594 static int tvb_get_fle(tvbuff_t *tvb, int offset, guint64 *res, guint8 *is_null);
595
596 /* dissector entrypoint, handles TCP-desegmentation */
597 static void
598 dissect_mysql(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
599 {
600         tcp_dissect_pdus(tvb, pinfo, tree, mysql_desegment, 3,
601                          get_mysql_pdu_len, dissect_mysql_pdu);
602 }
603
604
605 /* dissector helper: length of PDU */
606 static guint
607 get_mysql_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
608 {
609         guint plen= tvb_get_letoh24(tvb, offset);
610         return plen + 4; /* add length field + packet number */
611 }
612
613 /* dissector main function: handle one PDU */
614 static void
615 dissect_mysql_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
616 {
617         proto_tree      *mysql_tree= NULL;
618         proto_item      *ti;
619         conversation_t  *conversation;
620         int             offset = 0;
621         guint           packet_number;
622         gboolean        is_response;
623         mysql_conn_data_t  *conn_data;
624 #ifdef CTDEBUG
625         mysql_state_t conn_state_in, conn_state_out, frame_state;
626         guint64         generation;
627         proto_item *pi;
628 #endif
629         struct mysql_frame_data  *mysql_frame_data_p;
630
631         /* get conversation, create if neccessary*/
632         conversation= find_or_create_conversation(pinfo);
633
634         /* get associated state information, create if neccessary */
635         conn_data= conversation_get_proto_data(conversation, proto_mysql);
636         if (!conn_data) {
637                 conn_data= se_alloc(sizeof(mysql_conn_data_t));
638                 conn_data->srv_caps= 0;
639                 conn_data->clnt_caps= 0;
640                 conn_data->clnt_caps_ext= 0;
641                 conn_data->state= UNDEFINED;
642                 conn_data->stmts= g_hash_table_new(g_int_hash, g_int_equal);
643 #ifdef CTDEBUG
644                 conn_data->generation= 0;
645 #endif
646                 conn_data->major_version= 0;
647                 conversation_add_proto_data(conversation, proto_mysql, conn_data);
648         }
649
650         mysql_frame_data_p = p_get_proto_data(pinfo->fd, proto_mysql);
651         if (!mysql_frame_data_p) {
652                 /*  We haven't seen this frame before.  Store the state of the
653                  *  conversation now so if/when we dissect the frame again
654                  *  we'll start with the same state.
655                  */
656                 mysql_frame_data_p = se_alloc(sizeof(struct mysql_frame_data));
657                 mysql_frame_data_p->state = conn_data->state;
658                 p_add_proto_data(pinfo->fd, proto_mysql, mysql_frame_data_p);
659
660         } else if (conn_data->state != FIELD_PACKET  && conn_data->state != ROW_PACKET ) {
661                 /*  We have seen this frame before.  Set the connection state
662                  *  to whatever state it had the first time we saw this frame
663                  *  (e.g., based on whatever frames came before it).
664                  *  The state may change as we dissect this packet.
665                  *  XXX: I think the logic of the above else if test is as follows:
666                  *       During the first (sequential) dissection pass thru the capture
667                  *       file the conversation connection state as of the beginning of each frame
668                  *       is saved in the connection_state for that frame.
669                  *       Any state changes *within* a mysql "message" (ie: query/response/etc)
670                  *       while processing mysql PDUS (aka "packets") in that message must be preserved.
671                  *       It appears that FIELD_PACKET & ROW_PACKET are the only two
672                  *       state changes which can occur within a mysql message which affect
673                  *       subsequent processing within the message.
674                  *       Question: Does this logic work OK for a reassembled message ?
675                  */
676                  conn_data->state= mysql_frame_data_p->state;
677         }
678
679         if (tree) {
680                 ti = proto_tree_add_item(tree, proto_mysql, tvb, offset, -1, ENC_NA);
681                 mysql_tree = proto_item_add_subtree(ti, ett_mysql);
682                 proto_tree_add_item(mysql_tree, hf_mysql_packet_length, tvb, offset, 3, ENC_LITTLE_ENDIAN);
683         }
684         offset+= 3;
685
686         col_set_str(pinfo->cinfo, COL_PROTOCOL, "MySQL");
687
688         if (pinfo->destport == pinfo->match_uint) {
689                 is_response= FALSE;
690         } else {
691                 is_response= TRUE;
692         }
693
694         packet_number = tvb_get_guint8(tvb, offset);
695         proto_tree_add_item(mysql_tree, hf_mysql_packet_number, tvb, offset, 1, ENC_NA);
696         offset += 1;
697
698 #ifdef CTDEBUG
699         conn_state_in= conn_data->state;
700         frame_state = mysql_frame_data_p->state;
701         generation= conn_data->generation;
702         if (tree) {
703                 pi= proto_tree_add_text(mysql_tree, tvb, offset, 0, "conversation: %p", conversation);
704                 PROTO_ITEM_SET_GENERATED(pi);
705                 pi= proto_tree_add_text(mysql_tree, tvb, offset, 0, "generation: %" G_GINT64_MODIFIER "d", generation);
706                 PROTO_ITEM_SET_GENERATED(pi);
707                 pi= proto_tree_add_text(mysql_tree, tvb, offset, 0, "conn state: %s (%u)",
708                                     val_to_str(conn_state_in, state_vals, "Unknown (%u)"),
709                                     conn_state_in);
710                 PROTO_ITEM_SET_GENERATED(pi);
711                 pi= proto_tree_add_text(mysql_tree, tvb, offset, 0, "frame state: %s (%u)",
712                                     val_to_str(frame_state, state_vals, "Unknown (%u)"),
713                                     frame_state);
714                 PROTO_ITEM_SET_GENERATED(pi);
715         }
716 #endif
717
718         if (is_response) {
719                 if (packet_number == 0) {
720                         col_set_str(pinfo->cinfo, COL_INFO, "Server Greeting");
721                         offset = mysql_dissect_greeting(tvb, pinfo, offset, mysql_tree, conn_data);
722                 } else {
723                         col_set_str(pinfo->cinfo, COL_INFO, "Response");
724                         offset = mysql_dissect_response(tvb, pinfo, offset, mysql_tree, conn_data);
725                 }
726         } else {
727                 if (packet_number == 1) {
728                         col_set_str(pinfo->cinfo, COL_INFO, "Login Request");
729                         offset = mysql_dissect_login(tvb, pinfo, offset, mysql_tree, conn_data);
730                 } else {
731                         col_set_str(pinfo->cinfo, COL_INFO, "Request");
732                         offset = mysql_dissect_request(tvb, pinfo, offset, mysql_tree, conn_data);
733                 }
734         }
735
736 #ifdef CTDEBUG
737         conn_state_out= conn_data->state;
738         ++(conn_data->generation);
739         pi= proto_tree_add_text(mysql_tree, tvb, offset, 0, "next proto state: %s (%u)",
740                             val_to_str(conn_state_out, state_vals, "Unknown (%u)"),
741                             conn_state_out);
742         PROTO_ITEM_SET_GENERATED(pi);
743 #endif
744
745         /* remaining payload indicates an error */
746         if (tree && tvb_reported_length_remaining(tvb, offset) > 0) {
747                 ti = proto_tree_add_item(mysql_tree, hf_mysql_payload, tvb, offset, -1, ENC_NA);
748                 expert_add_info_format(pinfo, ti, PI_UNDECODED, PI_WARN, "FIXME - dissector is incomplete");
749         }
750 }
751
752
753 static int
754 mysql_dissect_greeting(tvbuff_t *tvb, packet_info *pinfo, int offset,
755                        proto_tree *tree, mysql_conn_data_t *conn_data)
756 {
757         gint protocol;
758         gint strlen;
759         int ver_offset;
760
761         proto_item *tf;
762         proto_item *greeting_tree= NULL;
763
764         protocol= tvb_get_guint8(tvb, offset);
765
766         if (protocol == 0xff) {
767                 return mysql_dissect_error_packet(tvb, pinfo, offset+1, tree);
768         }
769
770         conn_data->state= LOGIN;
771
772         if (tree) {
773                 tf = proto_tree_add_item(tree, hf_mysql_server_greeting, tvb, offset, -1, ENC_NA);
774                 greeting_tree = proto_item_add_subtree(tf, ett_server_greeting);
775         }
776
777         if (check_col(pinfo->cinfo, COL_INFO)) {
778                 col_append_fstr(pinfo->cinfo, COL_INFO, " proto=%d", protocol) ;
779         }
780         proto_tree_add_item(greeting_tree, hf_mysql_protocol, tvb, offset, 1, ENC_NA);
781
782         offset += 1;
783
784         /* version string */
785         strlen = tvb_strsize(tvb,offset);
786         if (check_col(pinfo->cinfo, COL_INFO)) {
787                 col_append_fstr(pinfo->cinfo, COL_INFO, " version=%s", tvb_get_ephemeral_string(tvb, offset, strlen));
788         }
789         proto_tree_add_item(greeting_tree, hf_mysql_version, tvb, offset, strlen, ENC_NA);
790         conn_data->major_version = 0;
791         for (ver_offset = 0; ver_offset < strlen; ver_offset++) {
792                 guint8 ver_char = tvb_get_guint8(tvb, offset + ver_offset);
793                 if (ver_char == '.') break;
794                 conn_data->major_version = conn_data->major_version * 10 + ver_char - '0';
795         }
796         offset += strlen;
797
798         /* 4 bytes little endian thread_id */
799         proto_tree_add_item(greeting_tree, hf_mysql_thread_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
800         offset += 4;
801
802         /* salt string */
803         strlen = tvb_strsize(tvb,offset);
804         proto_tree_add_item(greeting_tree, hf_mysql_salt, tvb, offset, strlen, ENC_NA);
805         offset += strlen;
806
807         /* rest is optional */
808         if (!tvb_reported_length_remaining(tvb, offset)) return offset;
809
810         /* 2 bytes CAPS */
811         offset = mysql_dissect_caps_server(tvb, offset, greeting_tree, &conn_data->srv_caps);
812
813         /* rest is optional */
814         if (!tvb_reported_length_remaining(tvb, offset)) return offset;
815
816         proto_tree_add_item(greeting_tree, hf_mysql_server_language, tvb, offset, 1, ENC_NA);
817         offset += 1; /* for charset */
818
819         offset = mysql_dissect_server_status(tvb, offset, greeting_tree);
820
821         /* 13 bytes unused */
822         proto_tree_add_item(greeting_tree, hf_mysql_unused, tvb, offset, 13, ENC_NA);
823         offset += 13;
824
825         /* 4.1+ server: rest of salt */
826         if (tvb_reported_length_remaining(tvb, offset)) {
827                 strlen = tvb_strsize(tvb,offset);
828                 proto_tree_add_item(greeting_tree, hf_mysql_salt2, tvb, offset, strlen, ENC_NA);
829                 offset += strlen;
830         }
831
832         return offset;
833 }
834
835
836 static int
837 mysql_dissect_login(tvbuff_t *tvb, packet_info *pinfo, int offset,
838                     proto_tree *tree, mysql_conn_data_t *conn_data)
839 {
840         gint strlen;
841
842         proto_item *tf;
843         proto_item *login_tree= NULL;
844
845         /* after login there can be OK or DENIED */
846         conn_data->state = RESPONSE_OK;
847
848         if (tree) {
849                 tf = proto_tree_add_item(tree, hf_mysql_login_request, tvb, offset, -1, ENC_NA);
850                 login_tree = proto_item_add_subtree(tf, ett_login_request);
851         }
852
853         offset = mysql_dissect_caps_client(tvb, offset, login_tree, &conn_data->clnt_caps);
854
855         if (conn_data->clnt_caps & MYSQL_CAPS_CU) /* 4.1 protocol */
856         {
857                 offset = mysql_dissect_ext_caps_client(tvb, offset, login_tree, &conn_data->clnt_caps_ext);
858
859                 proto_tree_add_item(login_tree, hf_mysql_max_packet, tvb, offset, 4, ENC_LITTLE_ENDIAN);
860                 offset += 4;
861
862                 proto_tree_add_item(login_tree, hf_mysql_charset, tvb, offset, 1, ENC_NA);
863                 offset += 1; /* for charset */
864
865                 offset += 23; /* filler bytes */
866
867         } else { /* pre-4.1 */
868                 proto_tree_add_item(login_tree, hf_mysql_max_packet, tvb, offset, 3, ENC_LITTLE_ENDIAN);
869                 offset += 3;
870         }
871
872         /* User name */
873         strlen = my_tvb_strsize(tvb, offset);
874         if (check_col(pinfo->cinfo, COL_INFO)) {
875                 col_append_fstr(pinfo->cinfo, COL_INFO, " user=%s", tvb_get_ephemeral_string(tvb, offset, strlen));
876         }
877         proto_tree_add_item(login_tree, hf_mysql_user, tvb, offset, strlen, ENC_NA);
878         offset += strlen;
879
880         /* rest is optional */
881         if (!tvb_reported_length_remaining(tvb, offset)) return offset;
882
883         /* password: asciiz or length+ascii */
884         if (conn_data->clnt_caps & MYSQL_CAPS_SC) {
885                 strlen = tvb_get_guint8(tvb, offset);
886                 offset += 1;
887         } else {
888                 strlen = my_tvb_strsize(tvb, offset);
889         }
890         if (tree && strlen > 1) {
891                 proto_tree_add_item(login_tree, hf_mysql_passwd, tvb, offset, strlen, ENC_NA);
892         }
893         offset += strlen;
894
895         /* optional: initial schema */
896         if (conn_data->clnt_caps & MYSQL_CAPS_CD)
897         {
898                 strlen= my_tvb_strsize(tvb,offset);
899                 if(strlen<0){
900                         return offset;
901                 }
902
903                 if (check_col(pinfo->cinfo, COL_INFO)) {
904                         col_append_fstr(pinfo->cinfo, COL_INFO, " db=%s", tvb_get_ephemeral_string(tvb, offset, strlen));
905                 }
906                 proto_tree_add_item(login_tree, hf_mysql_schema, tvb, offset, strlen, ENC_NA);
907                 offset += strlen;
908         }
909
910         return offset;
911 }
912
913
914 static int
915 mysql_dissect_request(tvbuff_t *tvb,packet_info *pinfo, int offset,
916                       proto_tree *tree, mysql_conn_data_t *conn_data)
917 {
918         gint opcode;
919         gint strlen;
920         proto_item *tf = NULL, *ti;
921         proto_item *req_tree = NULL;
922
923         if (tree) {
924                 tf = proto_tree_add_item(tree, hf_mysql_request, tvb, offset, 1, ENC_NA);
925                 req_tree = proto_item_add_subtree(tf, ett_request);
926         }
927
928         opcode = tvb_get_guint8(tvb, offset);
929         if (check_col(pinfo->cinfo, COL_INFO)) {
930                 col_append_fstr(pinfo->cinfo, COL_INFO, " %s", val_to_str(opcode, mysql_command_vals, "Unknown (%u)"));
931         }
932         proto_tree_add_item(req_tree, hf_mysql_command, tvb, offset, 1, ENC_NA);
933         proto_item_append_text(tf, " %s", val_to_str(opcode, mysql_command_vals, "Unknown (%u)"));
934         offset += 1;
935
936
937         switch (opcode) {
938
939         case MYSQL_QUIT:
940                 if (conn_data->stmts) {
941                         g_hash_table_destroy(conn_data->stmts);
942                         conn_data->stmts = NULL;
943                 }
944                 break;
945
946         case MYSQL_PROCESS_INFO:
947                 conn_data->state = RESPONSE_TABULAR;
948                 break;
949
950         case MYSQL_DEBUG:
951         case MYSQL_PING:
952                 conn_data->state = RESPONSE_OK;
953                 break;
954
955         case MYSQL_STATISTICS:
956                 conn_data->state = RESPONSE_MESSAGE;
957                 break;
958
959         case MYSQL_INIT_DB:
960         case MYSQL_CREATE_DB:
961         case MYSQL_DROP_DB:
962                 strlen = my_tvb_strsize(tvb, offset);
963                 proto_tree_add_item(req_tree, hf_mysql_schema, tvb, offset, strlen, ENC_NA);
964                 offset += strlen;
965                 conn_data->state = RESPONSE_OK;
966                 break;
967
968         case MYSQL_QUERY:
969                 strlen = my_tvb_strsize(tvb, offset);
970                 proto_tree_add_item(req_tree, hf_mysql_query, tvb, offset, strlen, ENC_NA);
971                 if (mysql_showquery) {
972                         if (check_col(pinfo->cinfo, COL_INFO))
973                                 col_append_fstr(pinfo->cinfo, COL_INFO, " { %s } ", tvb_get_ephemeral_string(tvb, offset, strlen));
974                 }
975                 offset += strlen;
976                 conn_data->state = RESPONSE_TABULAR;
977                 break;
978
979         case MYSQL_STMT_PREPARE:
980                 strlen = my_tvb_strsize(tvb, offset);
981                 proto_tree_add_item(req_tree, hf_mysql_query, tvb, offset, strlen, ENC_NA);
982                 offset += strlen;
983                 conn_data->state = RESPONSE_PREPARE;
984                 break;
985
986         case MYSQL_STMT_CLOSE:
987                 if (conn_data->stmts) {
988                         gint stmt = tvb_get_letohl(tvb, offset);
989                         g_hash_table_remove(conn_data->stmts, &stmt);
990                 }
991                 proto_tree_add_item(req_tree, hf_mysql_stmt_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
992                 offset += 4;
993                 conn_data->state = REQUEST;
994                 break;
995
996         case MYSQL_STMT_RESET:
997                 proto_tree_add_item(req_tree, hf_mysql_stmt_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
998                 offset += 4;
999                 conn_data->state = RESPONSE_OK;
1000                 break;
1001
1002         case MYSQL_FIELD_LIST:
1003                 strlen = my_tvb_strsize(tvb, offset);
1004                 proto_tree_add_item(req_tree, hf_mysql_table_name, tvb,  offset, strlen, ENC_NA);
1005                 offset += strlen;
1006                 conn_data->state = RESPONSE_SHOW_FIELDS;
1007                 break;
1008
1009         case MYSQL_PROCESS_KILL:
1010                 proto_tree_add_item(req_tree, hf_mysql_thd_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1011                 offset += 4;
1012                 conn_data->state = RESPONSE_OK;
1013                 break;
1014
1015         case MYSQL_CHANGE_USER:
1016                 strlen = tvb_strsize(tvb, offset);
1017                 proto_tree_add_item(req_tree, hf_mysql_user, tvb,  offset, strlen, ENC_NA);
1018                 offset += strlen;
1019
1020                 strlen = tvb_strsize(tvb, offset);
1021                 proto_tree_add_item(req_tree, hf_mysql_passwd, tvb, offset, strlen, ENC_NA);
1022                 offset += strlen;
1023
1024                 strlen = my_tvb_strsize(tvb, offset);
1025                 proto_tree_add_item(req_tree, hf_mysql_schema, tvb, offset, strlen, ENC_NA);
1026                 offset += strlen;
1027
1028                 conn_data->state= RESPONSE_OK;
1029                 break;
1030
1031         case MYSQL_REFRESH:
1032                 {
1033                         proto_item *tff;
1034                         proto_item *rfsh_tree;
1035
1036                         tff = proto_tree_add_item(req_tree, hf_mysql_refresh, tvb, offset, 1, ENC_NA);
1037                         rfsh_tree = proto_item_add_subtree(tff, ett_refresh);
1038                         proto_tree_add_item(rfsh_tree, hf_mysql_rfsh_grants, tvb, offset, 1, ENC_NA);
1039                         proto_tree_add_item(rfsh_tree, hf_mysql_rfsh_log, tvb, offset, 1, ENC_NA);
1040                         proto_tree_add_item(rfsh_tree, hf_mysql_rfsh_tables, tvb, offset, 1, ENC_NA);
1041                         proto_tree_add_item(rfsh_tree, hf_mysql_rfsh_hosts, tvb, offset, 1, ENC_NA);
1042                         proto_tree_add_item(rfsh_tree, hf_mysql_rfsh_status, tvb, offset, 1, ENC_NA);
1043                         proto_tree_add_item(rfsh_tree, hf_mysql_rfsh_threads, tvb, offset, 1, ENC_NA);
1044                         proto_tree_add_item(rfsh_tree, hf_mysql_rfsh_slave, tvb, offset, 1, ENC_NA);
1045                         proto_tree_add_item(rfsh_tree, hf_mysql_rfsh_master, tvb, offset, 1, ENC_NA);
1046
1047                 }
1048                 offset += 1;
1049                 conn_data->state= RESPONSE_OK;
1050                 break;
1051
1052         case MYSQL_SHUTDOWN:
1053                 proto_tree_add_item(req_tree, hf_mysql_shutdown, tvb, offset, 1, ENC_NA);
1054                 offset += 1;
1055                 conn_data->state = RESPONSE_OK;
1056                 break;
1057
1058         case MYSQL_SET_OPTION:
1059                 proto_tree_add_item(req_tree, hf_mysql_option, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1060                 offset += 2;
1061                 conn_data->state = RESPONSE_OK;
1062                 break;
1063
1064         case MYSQL_STMT_FETCH:
1065                 proto_tree_add_item(req_tree, hf_mysql_stmt_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1066                 offset += 4;
1067
1068                 proto_tree_add_item(req_tree, hf_mysql_num_rows, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1069                 offset += 4;
1070                 conn_data->state = RESPONSE_TABULAR;
1071                 break;
1072
1073         case MYSQL_STMT_SEND_LONG_DATA:
1074                 proto_tree_add_item(req_tree, hf_mysql_stmt_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1075                 offset += 4;
1076
1077                 proto_tree_add_item(req_tree, hf_mysql_param, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1078                 offset += 2;
1079
1080                 /* rest is data */
1081                 strlen = tvb_reported_length_remaining(tvb, offset);
1082                 if (tree &&  strlen > 0) {
1083                         proto_tree_add_item(req_tree, hf_mysql_payload, tvb, offset, strlen, ENC_NA);
1084                 }
1085                 offset += strlen;
1086                 conn_data->state = REQUEST;
1087                 break;
1088
1089         case MYSQL_STMT_EXECUTE:
1090                 proto_tree_add_item(req_tree, hf_mysql_stmt_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1091                 offset += 4;
1092
1093                 if (conn_data->major_version >= 5) {
1094                         proto_tree_add_item(req_tree, hf_mysql_exec_flags5, tvb, offset, 1, ENC_NA);
1095                 } else {
1096                         proto_tree_add_item(req_tree, hf_mysql_exec_flags4, tvb, offset, 1, ENC_NA);
1097                 }
1098                 offset += 1;
1099
1100                 proto_tree_add_item(req_tree, hf_mysql_exec_iter, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1101                 offset += 4;
1102
1103 #if 0
1104 /* FIXME: rest needs metadata about statement */
1105 #else
1106                 strlen = tvb_reported_length_remaining(tvb, offset);
1107                 if (tree &&  strlen > 0) {
1108                         ti = proto_tree_add_item(req_tree, hf_mysql_payload, tvb, offset, strlen, ENC_NA);
1109                         expert_add_info_format(pinfo, ti, PI_UNDECODED, PI_WARN, "FIXME: execute dissector incomplete");
1110                 }
1111                 offset += strlen;
1112 #endif
1113                 conn_data->state= RESPONSE_TABULAR;
1114                 break;
1115
1116         case MYSQL_BINLOG_DUMP:
1117                 proto_tree_add_item(req_tree, hf_mysql_binlog_position, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1118                 offset += 4;
1119
1120                 proto_tree_add_item(req_tree, hf_mysql_binlog_flags, tvb, offset, 2, ENC_NA);
1121                 offset += 2;
1122
1123                 proto_tree_add_item(req_tree, hf_mysql_binlog_server_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1124                 offset += 4;
1125
1126                 /* binlog file name ? */
1127                 strlen = tvb_reported_length_remaining(tvb, offset);
1128                 if (tree &&  strlen > 0) {
1129                         proto_tree_add_item(req_tree, hf_mysql_binlog_file_name, tvb, offset, strlen, ENC_NA);
1130                 }
1131                 offset += strlen;
1132
1133                 conn_data->state = REQUEST;
1134                 break;
1135 /* FIXME: implement replication packets */
1136         case MYSQL_TABLE_DUMP:
1137         case MYSQL_CONNECT_OUT:
1138         case MYSQL_REGISTER_SLAVE:
1139                 ti = proto_tree_add_item(req_tree, hf_mysql_payload, tvb, offset, -1, ENC_NA);
1140                 expert_add_info_format(pinfo, ti, PI_UNDECODED, PI_WARN, "FIXME: implement replication packets");
1141                 offset += tvb_reported_length_remaining(tvb, offset);
1142                 conn_data->state = REQUEST;
1143                 break;
1144
1145         default:
1146                 ti = proto_tree_add_item(req_tree, hf_mysql_payload, tvb, offset, -1, ENC_NA);
1147                 expert_add_info_format(pinfo, ti, PI_PROTOCOL, PI_WARN, "Unknown/invalid command code");
1148                 offset += tvb_reported_length_remaining(tvb, offset);
1149                 conn_data->state = UNDEFINED;
1150         }
1151
1152         return offset;
1153 }
1154
1155
1156 static int
1157 mysql_dissect_response(tvbuff_t *tvb, packet_info *pinfo, int offset,
1158                        proto_tree *tree, mysql_conn_data_t *conn_data)
1159 {
1160         gint response_code;
1161         gint strlen;
1162     gint server_status = 0;
1163
1164         response_code = tvb_get_guint8(tvb, offset);
1165
1166         if (response_code == 0xff ) {
1167                 offset = mysql_dissect_error_packet(tvb, pinfo, offset+1, tree);
1168                 conn_data->state= REQUEST;
1169         }
1170
1171         else if (response_code == 0xfe && tvb_reported_length_remaining(tvb, offset) < 9) {
1172
1173                 proto_tree_add_item(tree, hf_mysql_eof, tvb, offset, 1, ENC_NA);
1174
1175                 offset += 1;
1176
1177                 /* pre-4.1 packet ends here */
1178                 if (tvb_reported_length_remaining(tvb, offset)) {
1179                         proto_tree_add_item(tree, hf_mysql_num_warn, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1180                         server_status = tvb_get_letohs(tvb, offset+2);
1181                         offset = mysql_dissect_server_status(tvb, offset+2, tree);
1182                 }
1183
1184                 if (conn_data->state == FIELD_PACKET) {
1185                         conn_data->state= ROW_PACKET;
1186                 } else if (conn_data->state == ROW_PACKET) {
1187                         if (server_status & MYSQL_STAT_MU) {
1188                                 conn_data->state= RESPONSE_TABULAR;
1189                         } else {
1190                                 conn_data->state= REQUEST;
1191                         }
1192                 } else if (conn_data->state == PREPARED_PARAMETERS) {
1193                         if (conn_data->stmt_num_fields > 0) {
1194                                 conn_data->state= PREPARED_FIELDS;
1195                         } else {
1196                                 conn_data->state= REQUEST;
1197                         }
1198                 } else if (conn_data->state == PREPARED_FIELDS) {
1199                         conn_data->state= REQUEST;
1200                 } else {
1201                         /* This should be an unreachable case */
1202                         conn_data->state= REQUEST;
1203                 }
1204         }
1205
1206         else if (response_code == 0) {
1207                 if (conn_data->state == RESPONSE_PREPARE) {
1208                         offset = mysql_dissect_response_prepare(tvb, offset, tree, conn_data);
1209                 } else if (tvb_reported_length_remaining(tvb, offset+1)  > tvb_get_fle(tvb, offset+1, NULL, NULL)) {
1210                         offset = mysql_dissect_ok_packet(tvb, pinfo, offset+1, tree, conn_data);
1211                 } else {
1212                         offset = mysql_dissect_result_header(tvb, pinfo, offset, tree, conn_data);
1213                 }
1214         }
1215
1216         else {
1217                 switch (conn_data->state) {
1218                 case RESPONSE_MESSAGE:
1219                         if ((strlen = tvb_reported_length_remaining(tvb, offset))) {
1220                                 proto_tree_add_item(tree, hf_mysql_message, tvb, offset, strlen, ENC_NA);
1221                                 offset += strlen;
1222                         }
1223                         conn_data->state = REQUEST;
1224                         break;
1225
1226                 case RESPONSE_TABULAR:
1227                         offset = mysql_dissect_result_header(tvb, pinfo, offset, tree, conn_data);
1228                         break;
1229
1230                 case FIELD_PACKET:
1231                 case RESPONSE_SHOW_FIELDS:
1232                 case RESPONSE_PREPARE:
1233                 case PREPARED_PARAMETERS:
1234                         offset = mysql_dissect_field_packet(tvb, offset, tree, conn_data);
1235                         break;
1236
1237                 case ROW_PACKET:
1238                         offset = mysql_dissect_row_packet(tvb, offset, tree);
1239                         break;
1240
1241                 case PREPARED_FIELDS:
1242                         offset = mysql_dissect_field_packet(tvb, offset, tree, conn_data);
1243                         break;
1244
1245                 default:
1246                         proto_tree_add_string(tree, hf_mysql_payload, tvb, offset, -1,
1247                                               "unknown/invalid response");
1248                         offset += tvb_reported_length_remaining(tvb, offset);
1249                         conn_data->state = UNDEFINED;
1250                 }
1251         }
1252
1253         return offset;
1254 }
1255
1256
1257 static int
1258 mysql_dissect_error_packet(tvbuff_t *tvb, packet_info *pinfo,
1259                            int offset, proto_tree *tree)
1260 {
1261         if (check_col(pinfo->cinfo, COL_INFO)) {
1262                 col_append_fstr(pinfo->cinfo, COL_INFO, " Error %d", tvb_get_letohs(tvb, offset));
1263         }
1264         proto_tree_add_item(tree, hf_mysql_error_code, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1265         offset += 2;
1266
1267         if (tvb_get_guint8(tvb, offset) == '#')
1268         {
1269                 offset += 1;
1270                 proto_tree_add_item(tree, hf_mysql_sqlstate, tvb, offset, 5, ENC_NA);
1271                 offset += 5;
1272         }
1273
1274         proto_tree_add_item(tree, hf_mysql_error_string, tvb, offset, -1, ENC_NA);
1275         offset += tvb_reported_length_remaining(tvb, offset);
1276
1277         return offset;
1278 }
1279
1280
1281 static int
1282 mysql_dissect_ok_packet(tvbuff_t *tvb, packet_info *pinfo, int offset,
1283                         proto_tree *tree, mysql_conn_data_t *conn_data)
1284 {
1285         gint strlen;
1286         guint64 affected_rows;
1287         guint64 insert_id;
1288         int fle;
1289
1290         col_append_str(pinfo->cinfo, COL_INFO, " OK" );
1291
1292         fle = tvb_get_fle(tvb, offset, &affected_rows, NULL);
1293         proto_tree_add_uint64(tree, hf_mysql_affected_rows, tvb, offset, fle, affected_rows);
1294         offset += fle;
1295
1296         fle= tvb_get_fle(tvb, offset, &insert_id, NULL);
1297         if (tree && insert_id) {
1298                 proto_tree_add_uint64(tree, hf_mysql_insert_id, tvb, offset, fle, insert_id);
1299         }
1300         offset += fle;
1301
1302         if (tvb_reported_length_remaining(tvb, offset) > 0) {
1303                 offset = mysql_dissect_server_status(tvb, offset, tree);
1304
1305                 /* 4.1+ protocol only: 2 bytes number of warnings */
1306                 if (conn_data->clnt_caps & conn_data->srv_caps & MYSQL_CAPS_CU) {
1307                         proto_tree_add_item(tree, hf_mysql_num_warn, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1308                 offset += 2;
1309                 }
1310         }
1311
1312         /* optional: message string */
1313         if (tvb_reported_length_remaining(tvb, offset) > 0) {
1314                 strlen = tvb_reported_length_remaining(tvb, offset);
1315                 proto_tree_add_item(tree, hf_mysql_message, tvb, offset, strlen, ENC_NA);
1316                 offset += strlen;
1317         }
1318
1319         conn_data->state = REQUEST;
1320         return offset;
1321 }
1322
1323
1324 static int
1325 mysql_dissect_server_status(tvbuff_t *tvb, int offset, proto_tree *tree)
1326 {
1327         proto_item *tf;
1328         proto_item *stat_tree;
1329
1330         if (tree) {
1331                 tf= proto_tree_add_item(tree, hf_mysql_server_status, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1332                 stat_tree= proto_item_add_subtree(tf, ett_stat);
1333                 proto_tree_add_item(stat_tree, hf_mysql_stat_it, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1334                 proto_tree_add_item(stat_tree, hf_mysql_stat_ac, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1335                 proto_tree_add_item(stat_tree, hf_mysql_stat_mr, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1336                 proto_tree_add_item(stat_tree, hf_mysql_stat_mu, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1337                 proto_tree_add_item(stat_tree, hf_mysql_stat_bi, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1338                 proto_tree_add_item(stat_tree, hf_mysql_stat_ni, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1339                 proto_tree_add_item(stat_tree, hf_mysql_stat_cr, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1340                 proto_tree_add_item(stat_tree, hf_mysql_stat_lr, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1341                 proto_tree_add_item(stat_tree, hf_mysql_stat_dr, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1342                 proto_tree_add_item(stat_tree, hf_mysql_stat_bs, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1343         }
1344         offset += 2;
1345
1346         return offset;
1347 }
1348
1349
1350 static int
1351 mysql_dissect_caps_server(tvbuff_t *tvb, int offset, proto_tree *tree, guint16 *caps)
1352 {
1353         proto_item *tf;
1354         proto_item *cap_tree;
1355
1356         *caps= tvb_get_letohs(tvb, offset);
1357
1358         if (tree) {
1359                 tf = proto_tree_add_item(tree, hf_mysql_caps_server, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1360                 cap_tree= proto_item_add_subtree(tf, ett_caps);
1361                 proto_tree_add_item(cap_tree, hf_mysql_cap_long_password, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1362                 proto_tree_add_item(cap_tree, hf_mysql_cap_found_rows, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1363                 proto_tree_add_item(cap_tree, hf_mysql_cap_long_flag, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1364                 proto_tree_add_item(cap_tree, hf_mysql_cap_connect_with_db, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1365                 proto_tree_add_item(cap_tree, hf_mysql_cap_no_schema, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1366                 proto_tree_add_item(cap_tree, hf_mysql_cap_compress, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1367                 proto_tree_add_item(cap_tree, hf_mysql_cap_odbc, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1368                 proto_tree_add_item(cap_tree, hf_mysql_cap_local_files, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1369                 proto_tree_add_item(cap_tree, hf_mysql_cap_ignore_space, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1370                 proto_tree_add_item(cap_tree, hf_mysql_cap_change_user, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1371                 proto_tree_add_item(cap_tree, hf_mysql_cap_interactive, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1372                 proto_tree_add_item(cap_tree, hf_mysql_cap_ssl, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1373                 proto_tree_add_item(cap_tree, hf_mysql_cap_ignore_sigpipe, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1374                 proto_tree_add_item(cap_tree, hf_mysql_cap_transactions, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1375                 proto_tree_add_item(cap_tree, hf_mysql_cap_reserved, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1376                 proto_tree_add_item(cap_tree, hf_mysql_cap_secure_connect, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1377         }
1378
1379         offset += 2;
1380         return offset;
1381 }
1382
1383 static int
1384 mysql_dissect_caps_client(tvbuff_t *tvb, int offset, proto_tree *tree, guint16 *caps)
1385 {
1386         proto_item *tf;
1387         proto_item *cap_tree;
1388
1389         *caps= tvb_get_letohs(tvb, offset);
1390
1391         if (tree) {
1392                 tf = proto_tree_add_item(tree, hf_mysql_caps_client, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1393                 cap_tree= proto_item_add_subtree(tf, ett_caps);
1394                 proto_tree_add_item(cap_tree, hf_mysql_cap_long_password, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1395                 proto_tree_add_item(cap_tree, hf_mysql_cap_found_rows, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1396                 proto_tree_add_item(cap_tree, hf_mysql_cap_long_flag, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1397                 proto_tree_add_item(cap_tree, hf_mysql_cap_connect_with_db, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1398                 proto_tree_add_item(cap_tree, hf_mysql_cap_no_schema, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1399                 proto_tree_add_item(cap_tree, hf_mysql_cap_compress, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1400                 proto_tree_add_item(cap_tree, hf_mysql_cap_odbc, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1401                 proto_tree_add_item(cap_tree, hf_mysql_cap_local_files, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1402                 proto_tree_add_item(cap_tree, hf_mysql_cap_ignore_space, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1403                 proto_tree_add_item(cap_tree, hf_mysql_cap_change_user, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1404                 proto_tree_add_item(cap_tree, hf_mysql_cap_interactive, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1405                 proto_tree_add_item(cap_tree, hf_mysql_cap_ssl, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1406                 proto_tree_add_item(cap_tree, hf_mysql_cap_ignore_sigpipe, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1407                 proto_tree_add_item(cap_tree, hf_mysql_cap_transactions, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1408                 proto_tree_add_item(cap_tree, hf_mysql_cap_reserved, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1409                 proto_tree_add_item(cap_tree, hf_mysql_cap_secure_connect, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1410         }
1411
1412         offset += 2;
1413         return offset;
1414 }
1415 static int
1416 mysql_dissect_ext_caps_client(tvbuff_t *tvb, int offset, proto_tree *tree, guint16 *ext_caps)
1417 {
1418         proto_item *tf;
1419         proto_item *extcap_tree;
1420         *ext_caps= tvb_get_letohs(tvb, offset);
1421         if (tree) {
1422                 tf = proto_tree_add_item(tree, hf_mysql_extcaps_client, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1423                 extcap_tree = proto_item_add_subtree(tf, ett_extcaps);
1424                 proto_tree_add_item(extcap_tree, hf_mysql_cap_multi_statements, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1425                 proto_tree_add_item(extcap_tree, hf_mysql_cap_multi_results, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1426         }
1427
1428         offset += 2;
1429         return offset;
1430 }
1431
1432
1433 static int
1434 mysql_dissect_result_header(tvbuff_t *tvb, packet_info *pinfo, int offset,
1435                             proto_tree *tree, mysql_conn_data_t *conn_data)
1436 {
1437         gint fle;
1438         guint64 num_fields, extra;
1439
1440         col_append_str(pinfo->cinfo, COL_INFO, " TABULAR" );
1441
1442         fle = tvb_get_fle(tvb, offset, &num_fields, NULL);
1443         proto_tree_add_uint64(tree, hf_mysql_num_fields, tvb, offset, fle, num_fields);
1444         offset += fle;
1445
1446         if (tvb_reported_length_remaining(tvb, offset)) {
1447                 fle = tvb_get_fle(tvb, offset, &extra, NULL);
1448                 proto_tree_add_uint64(tree, hf_mysql_extra, tvb, offset, fle, extra);
1449                 offset += fle;
1450         }
1451
1452         if (num_fields) {
1453                 conn_data->state = FIELD_PACKET;
1454         } else {
1455                 conn_data->state = ROW_PACKET;
1456         }
1457
1458         return offset;
1459 }
1460
1461
1462 /*
1463  * Add length encoded string to tree
1464  */
1465 static int
1466 mysql_field_add_lestring(tvbuff_t *tvb, int offset, proto_tree *tree, int field)
1467 {
1468         guint64 lelen;
1469         guint8 is_null;
1470
1471         offset += tvb_get_fle(tvb, offset, &lelen, &is_null);
1472         if(is_null)
1473                 proto_tree_add_string(tree, field, tvb, offset, 4, "NULL");
1474         else
1475         {
1476                 proto_tree_add_item(tree, field, tvb, offset, (int)lelen, ENC_NA);
1477                 offset += (int)lelen;
1478         }
1479         return offset;
1480 }
1481
1482
1483 static int
1484 mysql_dissect_field_packet(tvbuff_t *tvb, int offset, proto_tree *tree, mysql_conn_data_t *conn_data _U_)
1485 {
1486         proto_item *tf;
1487         proto_item *flags_tree;
1488
1489         offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_catalog);
1490         offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_db);
1491         offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_table);
1492         offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_org_table);
1493         offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_name);
1494         offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_org_name);
1495         offset +=1; /* filler */
1496
1497         proto_tree_add_item(tree, hf_mysql_fld_charsetnr, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1498         offset += 2; /* charset */
1499
1500         proto_tree_add_item(tree, hf_mysql_fld_length, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1501         offset += 4; /* length */
1502
1503         proto_tree_add_item(tree, hf_mysql_fld_type, tvb, offset, 1, ENC_NA);
1504         offset += 1; /* type */
1505
1506         tf = proto_tree_add_item(tree, hf_mysql_fld_flags, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1507         flags_tree = proto_item_add_subtree(tf, ett_field_flags);
1508         proto_tree_add_item(flags_tree, hf_mysql_fld_not_null, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1509         proto_tree_add_item(flags_tree, hf_mysql_fld_primary_key, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1510         proto_tree_add_item(flags_tree, hf_mysql_fld_unique_key, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1511         proto_tree_add_item(flags_tree, hf_mysql_fld_multiple_key, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1512         proto_tree_add_item(flags_tree, hf_mysql_fld_blob, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1513         proto_tree_add_item(flags_tree, hf_mysql_fld_unsigned, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1514         proto_tree_add_item(flags_tree, hf_mysql_fld_zero_fill, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1515         proto_tree_add_item(flags_tree, hf_mysql_fld_binary, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1516         proto_tree_add_item(flags_tree, hf_mysql_fld_enum, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1517         proto_tree_add_item(flags_tree, hf_mysql_fld_auto_increment, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1518         proto_tree_add_item(flags_tree, hf_mysql_fld_timestamp, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1519         proto_tree_add_item(flags_tree, hf_mysql_fld_set, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1520         offset += 2; /* flags */
1521
1522         proto_tree_add_item(tree, hf_mysql_fld_decimals, tvb, offset, 1, ENC_NA);
1523         offset += 1; /* decimals */
1524
1525         offset += 2; /* filler */
1526
1527         /* default (Only use for show fields) */
1528         if (tree && tvb_reported_length_remaining(tvb, offset) > 0) {
1529                 offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_default);
1530         }
1531         return offset;
1532 }
1533
1534
1535 static int
1536 mysql_dissect_row_packet(tvbuff_t *tvb, int offset, proto_tree *tree)
1537 {
1538         while (tvb_reported_length_remaining(tvb, offset) > 0)  {
1539                 offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_row_text);
1540         }
1541
1542         return offset;
1543 }
1544
1545
1546 static int
1547 mysql_dissect_response_prepare(tvbuff_t *tvb, int offset, proto_tree *tree, mysql_conn_data_t *conn_data)
1548 {
1549     /* 0, marker for OK packet */
1550     offset += 1;
1551     proto_tree_add_item(tree, hf_mysql_stmt_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1552     offset += 4;
1553     proto_tree_add_item(tree, hf_mysql_num_fields, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1554     conn_data->stmt_num_fields = tvb_get_letohs(tvb, offset);
1555     offset += 2;
1556     proto_tree_add_item(tree, hf_mysql_num_params, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1557     conn_data->stmt_num_params = tvb_get_letohs(tvb, offset);
1558     offset += 2;
1559     /* Filler */
1560     offset += 1;
1561     proto_tree_add_item(tree, hf_mysql_num_warn, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1562
1563     if (conn_data->stmt_num_params > 0)
1564         conn_data->state = PREPARED_PARAMETERS;
1565     else if (conn_data->stmt_num_fields > 0)
1566         conn_data->state = PREPARED_FIELDS;
1567     else
1568         conn_data->state = REQUEST;
1569
1570         return offset + tvb_reported_length_remaining(tvb, offset);
1571 }
1572
1573
1574
1575 /*
1576  get length of string in packet buffer
1577
1578  SYNOPSIS
1579    my_tvb_strsize()
1580      tvb      packet buffer
1581      offset   current offset
1582
1583  DESCRIPTION
1584    deliver length of string, delimited by either \0 or end of buffer
1585
1586  RETURN VALUE
1587    length of string found, including \0 (if present)
1588
1589 */
1590 static gint
1591 my_tvb_strsize(tvbuff_t *tvb, int offset)
1592 {
1593         gint len = tvb_strnlen(tvb, offset, -1);
1594         if (len == -1) {
1595                 len = tvb_reported_length_remaining(tvb, offset);
1596         } else {
1597                 len++; /* the trailing \0 */
1598         }
1599         return len;
1600 }
1601
1602
1603 /*
1604  read "field length encoded" value from packet buffer
1605
1606  SYNOPSIS
1607    tvb_get_fle()
1608      tvb     in    packet buffer
1609      offset  in    offset in buffer
1610      res     out   where to store FLE value, may be NULL
1611      is_null out   where to store ISNULL flag, may be NULL
1612
1613  DESCRIPTION
1614    read FLE from packet buffer and store its value and ISNULL flag
1615    in caller provided variables
1616
1617  RETURN VALUE
1618    length of FLE
1619 */
1620 static int
1621 tvb_get_fle(tvbuff_t *tvb, int offset, guint64 *res, guint8 *is_null)
1622 {
1623         guint8 prefix;
1624
1625         prefix = tvb_get_guint8(tvb, offset);
1626
1627         if (is_null)
1628                 *is_null = 0;
1629
1630         switch (prefix) {
1631         case 251:
1632                 if (res)
1633                         *res = 0;
1634                 if (is_null)
1635                         *is_null = 1;
1636                 break;
1637         case 252:
1638                 if (res)
1639                         *res = tvb_get_letohs(tvb, offset+1);
1640                 return 3;
1641         case 253:
1642                 if (res)
1643                         *res = tvb_get_letohl(tvb, offset+1);
1644                 return 5;
1645         case 254:
1646                 if (res)
1647                         *res = tvb_get_letoh64(tvb, offset+1);
1648                 return 9;
1649         default:
1650                 if (res)
1651                         *res = prefix;
1652         }
1653
1654         return 1;
1655 }
1656
1657 /* protocol registration */
1658 void proto_register_mysql(void)
1659 {
1660         static hf_register_info hf[]=
1661         {
1662                 { &hf_mysql_packet_length,
1663                 { "Packet Length", "mysql.packet_length",
1664                 FT_UINT24, BASE_DEC, NULL,  0x0,
1665                 NULL, HFILL }},
1666
1667                 { &hf_mysql_packet_number,
1668                 { "Packet Number", "mysql.packet_number",
1669                 FT_UINT8, BASE_DEC, NULL, 0x0,
1670                 NULL, HFILL }},
1671
1672                 { &hf_mysql_request,
1673                 { "Request Command", "mysql.request",
1674                 FT_NONE, BASE_NONE, NULL, 0x0,
1675                 NULL, HFILL }},
1676
1677                 { &hf_mysql_command,
1678                 { "Command", "mysql.command",
1679                 FT_UINT8, BASE_DEC, VALS(mysql_command_vals), 0x0,
1680                 NULL, HFILL }},
1681
1682                 { &hf_mysql_error_code,
1683                 { "Error Code", "mysql.error_code",
1684                 FT_UINT16, BASE_DEC, NULL, 0x0,
1685                 NULL, HFILL }},
1686
1687                 { &hf_mysql_error_string,
1688                 { "Error message", "mysql.error.message",
1689                 FT_STRING, BASE_NONE, NULL, 0x0,
1690                 "Error string in case of MySQL error message", HFILL }},
1691
1692                 { &hf_mysql_sqlstate,
1693                 { "SQL state", "mysql.sqlstate",
1694                 FT_STRING, BASE_NONE, NULL, 0x0,
1695                 NULL, HFILL }},
1696
1697                 { &hf_mysql_message,
1698                 { "Message", "mysql.message",
1699                 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1700                 NULL, HFILL }},
1701
1702                 { &hf_mysql_server_greeting,
1703                 { "Server Greeting", "mysql.server_greeting",
1704                 FT_NONE, BASE_NONE, NULL, 0x0,
1705                 NULL, HFILL }},
1706
1707                 { &hf_mysql_protocol,
1708                 { "Protocol", "mysql.protocol",
1709                 FT_UINT8, BASE_DEC, NULL, 0x0,
1710                 "Protocol Version", HFILL }},
1711
1712                 { &hf_mysql_version,
1713                 { "Version", "mysql.version",
1714                 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1715                 "MySQL Version", HFILL }},
1716
1717                 { &hf_mysql_caps_server,
1718                 { "Server Capabilities", "mysql.caps.server",
1719                 FT_UINT16, BASE_HEX, NULL, 0x0,
1720                 "MySQL Capabilities", HFILL }},
1721
1722                 { &hf_mysql_caps_client,
1723                 { "Client Capabilities", "mysql.caps.client",
1724                 FT_UINT16, BASE_HEX, NULL, 0x0,
1725                 "MySQL Capabilities", HFILL }},
1726
1727                 { &hf_mysql_cap_long_password,
1728                 { "Long Password","mysql.caps.lp",
1729                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_LP,
1730                 NULL, HFILL }},
1731
1732                 { &hf_mysql_cap_found_rows,
1733                 { "Found Rows","mysql.caps.fr",
1734                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_FR,
1735                 NULL, HFILL }},
1736
1737                 { &hf_mysql_cap_long_flag,
1738                 { "Long Column Flags","mysql.caps.lf",
1739                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_LF,
1740                 NULL, HFILL }},
1741
1742                 { &hf_mysql_cap_connect_with_db,
1743                 { "Connect With Database","mysql.caps.cd",
1744                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_CD,
1745                 NULL, HFILL }},
1746
1747                 { &hf_mysql_cap_no_schema,
1748                 { "Don't Allow database.table.column","mysql.caps.ns",
1749                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_NS,
1750                 NULL, HFILL }},
1751
1752                 { &hf_mysql_cap_compress,
1753                 { "Can use compression protocol","mysql.caps.cp",
1754                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_CP,
1755                 NULL, HFILL }},
1756
1757                 { &hf_mysql_cap_odbc,
1758                 { "ODBC Client","mysql.caps.ob",
1759                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_OB,
1760                 NULL, HFILL }},
1761
1762                 { &hf_mysql_cap_local_files,
1763                 { "Can Use LOAD DATA LOCAL","mysql.caps.li",
1764                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_LI,
1765                 NULL, HFILL }},
1766
1767                 { &hf_mysql_cap_ignore_space,
1768                 { "Ignore Spaces before '('","mysql.caps.is",
1769                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_IS,
1770                 NULL, HFILL }},
1771
1772                 { &hf_mysql_cap_change_user,
1773                 { "Speaks 4.1 protocol (new flag)","mysql.caps.cu",
1774                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_CU,
1775                 NULL, HFILL }},
1776
1777                 { &hf_mysql_cap_interactive,
1778                 { "Interactive Client","mysql.caps.ia",
1779                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_IA,
1780                 NULL, HFILL }},
1781
1782                 { &hf_mysql_cap_ssl,
1783                 { "Switch to SSL after handshake","mysql.caps.sl",
1784                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_SL,
1785                 NULL, HFILL }},
1786
1787                 { &hf_mysql_cap_ignore_sigpipe,
1788                 { "Ignore sigpipes","mysql.caps.ii",
1789                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_II,
1790                 NULL, HFILL }},
1791
1792                 { &hf_mysql_cap_transactions,
1793                 { "Knows about transactions","mysql.caps.ta",
1794                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_TA,
1795                 NULL, HFILL }},
1796
1797                 { &hf_mysql_cap_reserved,
1798                 { "Speaks 4.1 protocol (old flag)","mysql.caps.rs",
1799                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_RS,
1800                 NULL, HFILL }},
1801
1802                 { &hf_mysql_cap_secure_connect,
1803                 { "Can do 4.1 authentication","mysql.caps.sc",
1804                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_SC,
1805                 NULL, HFILL }},
1806
1807                 { &hf_mysql_extcaps_client,
1808                 { "Extended Client Capabilities", "mysql.extcaps.client",
1809                 FT_UINT16, BASE_HEX, NULL, 0x0,
1810                 "MySQL Extended Capabilities", HFILL }},
1811
1812                 { &hf_mysql_cap_multi_statements,
1813                 { "Supports multiple statements","mysql.caps.ms",
1814                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_MS,
1815                 NULL, HFILL }},
1816
1817                 { &hf_mysql_cap_multi_results,
1818                 { "Supports multiple results","mysql.caps.mr",
1819                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_MR,
1820                 NULL, HFILL }},
1821
1822                 { &hf_mysql_login_request,
1823                 { "Login Request", "mysql.login_request",
1824                 FT_NONE, BASE_NONE, NULL,  0x0,
1825                 NULL, HFILL }},
1826
1827                 { &hf_mysql_max_packet,
1828                 { "MAX Packet", "mysql.max_packet",
1829                 FT_UINT24, BASE_DEC, NULL,  0x0,
1830                 "MySQL Max packet", HFILL }},
1831
1832                 { &hf_mysql_charset,
1833                 { "Charset", "mysql.charset",
1834                 FT_UINT8, BASE_DEC, VALS(mysql_collation_vals),  0x0,
1835                 "MySQL Charset", HFILL }},
1836
1837                 { &hf_mysql_table_name,
1838                 { "Table Name", "mysql.table_name",
1839                 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1840                 NULL, HFILL }},
1841
1842                 { &hf_mysql_user,
1843                 { "Username", "mysql.user",
1844                 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1845                 "Login Username", HFILL }},
1846
1847                 { &hf_mysql_schema,
1848                 { "Schema", "mysql.schema",
1849                 FT_STRING, BASE_NONE, NULL, 0x0,
1850                 "Login Schema", HFILL }},
1851
1852                 { &hf_mysql_salt,
1853                 { "Salt", "mysql.salt",
1854                 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1855                 NULL, HFILL }},
1856
1857                 { &hf_mysql_salt2,
1858                 { "Salt", "mysql.salt2",
1859                 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1860                 NULL, HFILL }},
1861
1862                 { &hf_mysql_thread_id,
1863                 { "Thread ID", "mysql.thread_id",
1864                 FT_UINT32, BASE_DEC, NULL,  0x0,
1865                 "MySQL Thread ID", HFILL }},
1866
1867                 { &hf_mysql_server_language,
1868                 { "Server Language", "mysql.server_language",
1869                 FT_UINT8, BASE_DEC, VALS(mysql_collation_vals),  0x0,
1870                 "MySQL Charset", HFILL }},
1871
1872                 { &hf_mysql_server_status,
1873                 { "Server Status", "mysql.server_status",
1874                 FT_UINT16, BASE_HEX, NULL,  0x0,
1875                 "MySQL Status", HFILL }},
1876
1877                 { &hf_mysql_stat_it,
1878                 { "In transaction", "mysql.stat.it",
1879                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_IT,
1880                 NULL, HFILL }},
1881
1882                 { &hf_mysql_stat_ac,
1883                 { "AUTO_COMMIT", "mysql.stat.ac",
1884                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_AC,
1885                 NULL, HFILL }},
1886
1887                 { &hf_mysql_stat_mr,
1888                 { "More results", "mysql.stat.mr",
1889                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_MR,
1890                 NULL, HFILL }},
1891
1892                 { &hf_mysql_stat_mu,
1893                 { "Multi query - more resultsets", "mysql.stat.mu",
1894                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_MU,
1895                 NULL, HFILL }},
1896
1897                 { &hf_mysql_stat_bi,
1898                 { "Bad index used", "mysql.stat.bi",
1899                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_BI,
1900                 NULL, HFILL }},
1901
1902                 { &hf_mysql_stat_ni,
1903                 { "No index used", "mysql.stat.ni",
1904                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_NI,
1905                 NULL, HFILL }},
1906
1907                 { &hf_mysql_stat_cr,
1908                 { "Cursor exists", "mysql.stat.cr",
1909                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_CR,
1910                 NULL, HFILL }},
1911
1912                 { &hf_mysql_stat_lr,
1913                 { "Last row sebd", "mysql.stat.lr",
1914                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_LR,
1915                 NULL, HFILL }},
1916
1917                 { &hf_mysql_stat_dr,
1918                 { "database dropped", "mysql.stat.dr",
1919                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_DR,
1920                 NULL, HFILL }},
1921
1922                 { &hf_mysql_stat_bs,
1923                 { "No backslash escapes", "mysql.stat.bs",
1924                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_BS,
1925                 NULL, HFILL }},
1926
1927                 { &hf_mysql_refresh,
1928                 { "Refresh Option", "mysql.refresh",
1929                 FT_UINT8, BASE_HEX, NULL,  0x0,
1930                 NULL, HFILL }},
1931
1932                 { &hf_mysql_rfsh_grants,
1933                 { "reload permissions", "mysql.rfsh.grants",
1934                 FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_GRANT,
1935                 NULL, HFILL }},
1936
1937                 { &hf_mysql_rfsh_log,
1938                 { "flush logfiles", "mysql.rfsh.log",
1939                 FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_LOG,
1940                 NULL, HFILL }},
1941
1942                 { &hf_mysql_rfsh_tables,
1943                 { "flush tables", "mysql.rfsh.tables",
1944                 FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_TABLES,
1945                 NULL, HFILL }},
1946
1947                 { &hf_mysql_rfsh_hosts,
1948                 { "flush hosts", "mysql.rfsh.hosts",
1949                 FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_HOSTS,
1950                 NULL, HFILL }},
1951
1952                 { &hf_mysql_rfsh_status,
1953                 { "reset statistics", "mysql.rfsh.status",
1954                 FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_STATUS,
1955                 NULL, HFILL }},
1956
1957                 { &hf_mysql_rfsh_threads,
1958                 { "empty thread cache", "mysql.rfsh.threads",
1959                 FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_THREADS,
1960                 NULL, HFILL }},
1961
1962                 { &hf_mysql_rfsh_slave,
1963                 { "flush slave status", "mysql.rfsh.slave",
1964                 FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_SLAVE,
1965                 NULL, HFILL }},
1966
1967                 { &hf_mysql_rfsh_master,
1968                 { "flush master status", "mysql.rfsh.master",
1969                 FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_MASTER,
1970                 NULL, HFILL }},
1971
1972                 { &hf_mysql_unused,
1973                 { "Unused", "mysql.unused",
1974                 FT_STRING, BASE_NONE, NULL, 0x0,
1975                 NULL, HFILL }},
1976
1977                 { &hf_mysql_passwd,
1978                 { "Password", "mysql.passwd",
1979                 FT_BYTES, BASE_NONE, NULL, 0x0,
1980                 NULL, HFILL }},
1981
1982                 { &hf_mysql_payload,
1983                 { "Payload", "mysql.payload",
1984                 FT_BYTES, BASE_NONE, NULL, 0x0,
1985                 "Additional Payload", HFILL }},
1986
1987                 { &hf_mysql_affected_rows,
1988                 { "Affected Rows", "mysql.affected_rows",
1989                 FT_UINT64, BASE_DEC, NULL, 0x0,
1990                 NULL, HFILL }},
1991
1992                 { &hf_mysql_insert_id,
1993                 { "Last INSERT ID", "mysql.insert_id",
1994                 FT_UINT64, BASE_DEC, NULL, 0x0,
1995                 NULL, HFILL }},
1996
1997                 { &hf_mysql_num_warn,
1998                 { "Warnings", "mysql.warnings",
1999                 FT_UINT16, BASE_DEC, NULL, 0x0,
2000                 NULL, HFILL }},
2001
2002                 { &hf_mysql_thd_id,
2003                 { "Thread ID", "mysql.thd_id",
2004                 FT_UINT32, BASE_DEC, NULL, 0x0,
2005                 NULL, HFILL }},
2006
2007                 { &hf_mysql_stmt_id,
2008                 { "Statement ID", "mysql.stmt_id",
2009                 FT_UINT32, BASE_DEC, NULL, 0x0,
2010                 NULL, HFILL }},
2011
2012                 { &hf_mysql_query,
2013                 { "Statement", "mysql.query",
2014                 FT_STRING, BASE_NONE, NULL, 0x0,
2015                 NULL, HFILL }},
2016
2017                 { &hf_mysql_shutdown,
2018                 { "Shutdown Level", "mysql.shutdown",
2019                 FT_UINT8, BASE_DEC, VALS(mysql_shutdown_vals), 0x0,
2020                 NULL, HFILL }},
2021
2022                 { &hf_mysql_option,
2023                 { "Option", "mysql.option",
2024                 FT_UINT16, BASE_DEC, VALS(mysql_option_vals), 0x0,
2025                 NULL, HFILL }},
2026
2027                 { &hf_mysql_param,
2028                 { "Parameter", "mysql.param",
2029                 FT_UINT16, BASE_DEC, NULL, 0x0,
2030                 NULL, HFILL }},
2031
2032                 { &hf_mysql_num_params,
2033                 { "Number of parameter", "mysql.num_params",
2034                 FT_UINT16, BASE_DEC, NULL, 0x0,
2035                 NULL, HFILL }},
2036
2037                 { &hf_mysql_num_rows,
2038                 { "Rows to fetch", "mysql.num_rows",
2039                 FT_UINT32, BASE_DEC, NULL, 0x0,
2040                 NULL, HFILL }},
2041
2042                 { &hf_mysql_exec_flags4,
2043                 { "Flags (unused)", "mysql.exec_flags",
2044                 FT_UINT8, BASE_DEC, NULL, 0x0,
2045                 NULL, HFILL }},
2046
2047                 { &hf_mysql_exec_flags5,
2048                 { "Flags", "mysql.exec_flags",
2049                 FT_UINT8, BASE_DEC, VALS(mysql_exec_flags_vals), 0x0,
2050                 NULL, HFILL }},
2051
2052                 { &hf_mysql_exec_iter,
2053                 { "Iterations (unused)", "mysql.exec_iter",
2054                 FT_UINT32, BASE_DEC, NULL, 0x0,
2055                 NULL, HFILL }},
2056
2057                 { &hf_mysql_binlog_position,
2058                 { "Binlog Position", "mysql.binlog.position",
2059                 FT_UINT32, BASE_DEC, NULL, 0x0,
2060                 "Position to start at", HFILL }},
2061
2062                 { &hf_mysql_binlog_flags,
2063                 { "Binlog Flags", "mysql.binlog.flags",
2064                 FT_UINT16, BASE_HEX, NULL, 0x0,
2065                 "(currently not used; always 0)", HFILL }},
2066
2067                 { &hf_mysql_binlog_server_id,
2068                 { "Binlog server id", "mysql.binlog.server_id",
2069                 FT_UINT16, BASE_HEX, NULL, 0x0,
2070                 "server_id of the slave", HFILL }},
2071
2072                 { &hf_mysql_binlog_file_name,
2073                 { "Binlog file name", "mysql.binlog.file_name",
2074                 FT_STRINGZ, BASE_NONE, NULL, 0x0,
2075                 NULL, HFILL }},
2076
2077                 { &hf_mysql_eof,
2078                 { "EOF marker", "mysql.eof",
2079                 FT_UINT8, BASE_DEC, NULL,  0x0,
2080                 NULL, HFILL }},
2081
2082                 { &hf_mysql_num_fields,
2083                 { "Number of fields", "mysql.num_fields",
2084                 FT_UINT64, BASE_DEC, NULL,  0x0,
2085                 NULL, HFILL }},
2086
2087                 { &hf_mysql_extra,
2088                 { "Extra data", "mysql.extra",
2089                 FT_UINT64, BASE_DEC, NULL,  0x0,
2090                 NULL, HFILL }},
2091
2092                 { &hf_mysql_fld_catalog,
2093                 { "Catalog", "mysql.field.catalog",
2094                 FT_STRING, BASE_NONE, NULL, 0x0,
2095                 "Field: catalog", HFILL }},
2096
2097                 { &hf_mysql_fld_db,
2098                 { "Database", "mysql.field.db",
2099                 FT_STRING, BASE_NONE, NULL, 0x0,
2100                 "Field: database", HFILL }},
2101
2102                 { &hf_mysql_fld_table,
2103                 { "Table", "mysql.field.table",
2104                 FT_STRING, BASE_NONE, NULL, 0x0,
2105                 "Field: table", HFILL }},
2106
2107                 { &hf_mysql_fld_org_table,
2108                 { "Original table", "mysql.field.org_table",
2109                 FT_STRING, BASE_NONE, NULL, 0x0,
2110                 "Field: original table", HFILL }},
2111
2112                 { &hf_mysql_fld_name,
2113                 { "Name", "mysql.field.name",
2114                 FT_STRING, BASE_NONE, NULL, 0x0,
2115                 "Field: name", HFILL }},
2116
2117                 { &hf_mysql_fld_org_name,
2118                 { "Original name", "mysql.field.org_name",
2119                 FT_STRING, BASE_NONE, NULL, 0x0,
2120                 "Field: original name", HFILL }},
2121
2122                 { &hf_mysql_fld_charsetnr,
2123                 { "Charset number", "mysql.field.charsetnr",
2124                 FT_UINT16, BASE_DEC, VALS(mysql_collation_vals), 0x0,
2125                 "Field: charset number", HFILL }},
2126
2127                 { &hf_mysql_fld_length,
2128                 { "Length", "mysql.field.length",
2129                 FT_UINT32, BASE_DEC, NULL, 0x0,
2130                 "Field: length", HFILL }},
2131
2132                 { &hf_mysql_fld_type,
2133                 { "Type", "mysql.field.type",
2134                 FT_UINT8, BASE_DEC, VALS(type_constants), 0x0,
2135                 "Field: type", HFILL }},
2136
2137                 { &hf_mysql_fld_flags,
2138                 { "Flags", "mysql.field.flags",
2139                 FT_UINT16, BASE_HEX, NULL, 0x0,
2140                 "Field: flags", HFILL }},
2141
2142                 { &hf_mysql_fld_not_null,
2143                 { "Not null", "mysql.field.flags.not_null",
2144                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_NOT_NULL_FLAG,
2145                 "Field: flag not null", HFILL }},
2146
2147                 { &hf_mysql_fld_primary_key,
2148                 { "Primary key", "mysql.field.flags.primary_key",
2149                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_PRI_KEY_FLAG,
2150                 "Field: flag primary key", HFILL }},
2151
2152                 { &hf_mysql_fld_unique_key,
2153                 { "Unique key", "mysql.field.flags.unique_key",
2154                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_UNIQUE_KEY_FLAG,
2155                 "Field: flag unique key", HFILL }},
2156
2157                 { &hf_mysql_fld_multiple_key,
2158                 { "Multiple key", "mysql.field.flags.multiple_key",
2159                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_MULTIPLE_KEY_FLAG,
2160                 "Field: flag multiple key", HFILL }},
2161
2162                 { &hf_mysql_fld_blob,
2163                 { "Blob", "mysql.field.flags.blob",
2164                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_BLOB_FLAG,
2165                 "Field: flag blob", HFILL }},
2166
2167                 { &hf_mysql_fld_unsigned,
2168                 { "Unsigned", "mysql.field.flags.unsigned",
2169                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_UNSIGNED_FLAG,
2170                 "Field: flag unsigned", HFILL }},
2171
2172                 { &hf_mysql_fld_zero_fill,
2173                 { "Zero fill", "mysql.field.flags.zero_fill",
2174                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_ZEROFILL_FLAG,
2175                 "Field: flag zero fill", HFILL }},
2176
2177                 { &hf_mysql_fld_binary,
2178                 { "Binary", "mysql.field.flags.binary",
2179                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_BINARY_FLAG,
2180                 "Field: flag binary", HFILL }},
2181
2182                 { &hf_mysql_fld_enum,
2183                 { "Enum", "mysql.field.flags.enum",
2184                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_ENUM_FLAG,
2185                 "Field: flag enum", HFILL }},
2186
2187                 { &hf_mysql_fld_auto_increment,
2188                 { "Auto increment", "mysql.field.flags.auto_increment",
2189                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_AUTO_INCREMENT_FLAG,
2190                 "Field: flag auto increment", HFILL }},
2191
2192                 { &hf_mysql_fld_timestamp,
2193                 { "Timestamp", "mysql.field.flags.timestamp",
2194                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_TIMESTAMP_FLAG,
2195                 "Field: flag timestamp", HFILL }},
2196
2197                 { &hf_mysql_fld_set,
2198                 { "Set", "mysql.field.flags.set",
2199                 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_SET_FLAG,
2200                 "Field: flag set", HFILL }},
2201
2202                 { &hf_mysql_fld_decimals,
2203                 { "Decimals", "mysql.field.decimals",
2204                 FT_UINT8, BASE_DEC, NULL, 0x0,
2205                 "Field: decimals", HFILL }},
2206
2207                 { &hf_mysql_fld_default,
2208                 { "Default", "mysql.field.default",
2209                 FT_STRING, BASE_NONE, NULL, 0x0,
2210                 "Field: default", HFILL }},
2211
2212                 { &hf_mysql_row_text,
2213                 { "text", "mysql.row.text",
2214                 FT_STRING, BASE_NONE, NULL, 0x0,
2215                 "Field: row packet text", HFILL }},
2216         };
2217
2218         static gint *ett[]=
2219         {
2220                 &ett_mysql,
2221                 &ett_server_greeting,
2222                 &ett_login_request,
2223                 &ett_caps,
2224                 &ett_extcaps,
2225                 &ett_stat,
2226                 &ett_request,
2227                 &ett_refresh,
2228                 &ett_field_flags
2229         };
2230
2231         module_t *mysql_module;
2232
2233         proto_mysql = proto_register_protocol("MySQL Protocol", "MySQL", "mysql");
2234         proto_register_field_array(proto_mysql, hf, array_length(hf));
2235         proto_register_subtree_array(ett, array_length(ett));
2236
2237         mysql_module = prefs_register_protocol(proto_mysql, NULL);
2238         prefs_register_bool_preference(mysql_module, "desegment_buffers",
2239                                        "Reassemble MySQL buffers spanning multiple TCP segments",
2240                                        "Whether the MySQL dissector should reassemble MySQL buffers spanning multiple TCP segments."
2241                                        " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
2242                                        &mysql_desegment);
2243         prefs_register_bool_preference(mysql_module, "show_sql_query",
2244                                        "Show SQL Query string in INFO column",
2245                                        "Whether the MySQL dissector should display the SQL query string in the INFO column.",
2246                                        &mysql_showquery);
2247
2248          register_dissector("mysql", dissect_mysql_pdu, proto_mysql);
2249 }
2250
2251 /* dissector registration */
2252 void proto_reg_handoff_mysql(void)
2253 {
2254         dissector_handle_t mysql_handle;
2255         mysql_handle = create_dissector_handle(dissect_mysql, proto_mysql);
2256         dissector_add_uint("tcp.port", TCP_PORT_MySQL, mysql_handle);
2257 }
2258