Document the new Copy Profile button.
[obnox/wireshark/wip.git] / epan / dissectors / packet-ctdb.c
1 /* packet-ctdb.c
2  * Routines for CTDB (Cluster TDB) dissection
3  * Copyright 2007, Ronnie Sahlberg
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include <glib.h>
35
36 #include <epan/packet.h>
37 #include <epan/value_string.h>
38 #include <epan/emem.h>
39
40 /* Initialize the protocol and registered fields */
41 static int proto_ctdb = -1;
42 static int hf_ctdb_length = -1;
43 static int hf_ctdb_opcode = -1;
44 static int hf_ctdb_magic = -1;
45 static int hf_ctdb_version = -1;
46 static int hf_ctdb_dst = -1;
47 static int hf_ctdb_src = -1;
48 static int hf_ctdb_id = -1;
49 static int hf_ctdb_flags_immediate = -1;
50 static int hf_ctdb_dbid = -1;
51 static int hf_ctdb_callid = -1;
52 static int hf_ctdb_status = -1;
53 static int hf_ctdb_keylen = -1;
54 static int hf_ctdb_datalen = -1;
55 static int hf_ctdb_errorlen = -1;
56 static int hf_ctdb_key = -1;
57 static int hf_ctdb_keyhash = -1;
58 static int hf_ctdb_data = -1;
59 static int hf_ctdb_error = -1;
60 static int hf_ctdb_dmaster = -1;
61 static int hf_ctdb_request_in = -1;
62 static int hf_ctdb_response_in = -1;
63 static int hf_ctdb_time = -1;
64 static int hf_ctdb_generation = -1;
65 static int hf_ctdb_hopcount = -1;
66 static int hf_ctdb_rsn = -1;
67 static int hf_ctdb_ctrl_opcode = -1;
68 static int hf_ctdb_srvid = -1;
69 static int hf_ctdb_clientid = -1;
70 static int hf_ctdb_ctrl_flags = -1;
71 static int hf_ctdb_recmaster = -1;
72 static int hf_ctdb_recmode = -1;
73 static int hf_ctdb_num_nodes = -1;
74 static int hf_ctdb_vnn = -1;
75 static int hf_ctdb_node_flags = -1;
76 static int hf_ctdb_node_ip = -1;
77 static int hf_ctdb_pid = -1;
78 static int hf_ctdb_process_exists = -1;
79
80 /* Initialize the subtree pointers */
81 static gint ett_ctdb = -1;
82 static gint ett_ctdb_key = -1;
83
84 /* this tree keeps track of caller/reqid for ctdb transactions */
85 emem_tree_t *ctdb_transactions=NULL;
86 typedef struct _ctdb_trans_t {
87         guint32 key_hash;
88         guint32 request_in;
89         guint32 response_in;
90         nstime_t req_time;
91 } ctdb_trans_t;
92
93 /* this tree keeps track of CONTROL request/responses */
94 emem_tree_t *ctdb_controls=NULL;
95 typedef struct _ctdb_control_t {
96         guint32 opcode;
97         guint32 request_in;
98         guint32 response_in;
99         nstime_t req_time;
100 } ctdb_control_t;
101
102 #define CTDB_REQ_CALL                   0
103 #define CTDB_REPLY_CALL                 1
104 #define CTDB_REQ_DMASTER                2
105 #define CTDB_REPLY_DMASTER              3
106 #define CTDB_REPLY_ERROR                4
107 #define CTDB_REQ_MESSAGE                5
108 #define CTDB_REQ_CONTROL                7
109 #define CTDB_REPLY_CONTROL              8
110 #define CTDB_REQ_KEEPALIVE              9
111 static const value_string ctdb_opcodes[] = {
112         {CTDB_REQ_CALL,                 "REQ_CALL"},
113         {CTDB_REPLY_CALL,               "REPLY_CALL"},
114         {CTDB_REQ_DMASTER,              "REQ_DMASTER"},
115         {CTDB_REPLY_DMASTER,            "REPLY_DMASTER"},
116         {CTDB_REPLY_ERROR,              "REPLY_ERROR"},
117         {CTDB_REQ_MESSAGE,              "REQ_MESSAGE"},
118         {CTDB_REQ_CONTROL,              "REQ_CONTROL"},
119         {CTDB_REPLY_CONTROL,            "REPLY_CONTROL"},
120         {CTDB_REQ_KEEPALIVE,            "REQ_KEEPALIVE"},
121         {0,NULL}
122 };
123
124
125 #define CTDB_CONTROL_PROCESS_EXISTS             0
126 #define CTDB_CONTROL_STATISTICS                 1
127 #define CTDB_CONTROL_CONFIG                     2
128 #define CTDB_CONTROL_PING                       3
129 #define CTDB_CONTROL_GETDBPATH                  4
130 #define CTDB_CONTROL_GETVNNMAP                  5
131 #define CTDB_CONTROL_SETVNNMAP                  6
132 #define CTDB_CONTROL_GET_DEBUG                  7
133 #define CTDB_CONTROL_SET_DEBUG                  8
134 #define CTDB_CONTROL_GET_DBMAP                  9
135 #define CTDB_CONTROL_GET_NODEMAP                10
136 #define CTDB_CONTROL_SET_DMASTER                11
137 #define CTDB_CONTROL_CLEAR_DB                   12
138 #define CTDB_CONTROL_PULL_DB                    13
139 #define CTDB_CONTROL_PUSH_DB                    14
140 #define CTDB_CONTROL_GET_RECMODE                15
141 #define CTDB_CONTROL_SET_RECMODE                16
142 #define CTDB_CONTROL_STATISTICS_RESET           17
143 #define CTDB_CONTROL_DB_ATTACH                  18
144 #define CTDB_CONTROL_SET_CALL                   19
145 #define CTDB_CONTROL_TRAVERSE_START             20
146 #define CTDB_CONTROL_TRAVERSE_ALL               21
147 #define CTDB_CONTROL_TRAVERSE_DATA              22
148 #define CTDB_CONTROL_REGISTER_SRVID             23
149 #define CTDB_CONTROL_DEREGISTER_SRVID           24
150 #define CTDB_CONTROL_GET_DBNAME                 25
151 #define CTDB_CONTROL_ENABLE_SEQNUM              26
152 #define CTDB_CONTROL_UPDATE_SEQNUM              27
153 #define CTDB_CONTROL_SET_SEQNUM_FREQUENCY       28
154 #define CTDB_CONTROL_DUMP_MEMORY                29
155 #define CTDB_CONTROL_GET_PID                    30
156 #define CTDB_CONTROL_GET_RECMASTER              31
157 #define CTDB_CONTROL_SET_RECMASTER              32
158 #define CTDB_CONTROL_FREEZE                     33
159 #define CTDB_CONTROL_THAW                       34
160 #define CTDB_CONTROL_GET_VNN                    35
161 #define CTDB_CONTROL_SHUTDOWN                   36
162 #define CTDB_CONTROL_GET_MONMODE                37
163 #define CTDB_CONTROL_SET_MONMODE                38
164 #define CTDB_CONTROL_MAX_RSN                    39
165 #define CTDB_CONTROL_SET_RSN_NONEMPTY           40
166 #define CTDB_CONTROL_DELETE_LOW_RSN             41
167 #define CTDB_CONTROL_TAKEOVER_IP                42
168 #define CTDB_CONTROL_RELEASE_IP                 43
169 #define CTDB_CONTROL_TCP_CLIENT                 44
170 #define CTDB_CONTROL_TCP_ADD                    45
171 #define CTDB_CONTROL_TCP_REMOVE                 46
172 #define CTDB_CONTROL_STARTUP                    47
173 #define CTDB_CONTROL_SET_TUNABLE                48
174 #define CTDB_CONTROL_GET_TUNABLE                49
175 #define CTDB_CONTROL_LIST_TUNABLES              50
176 #define CTDB_CONTROL_GET_PUBLIC_IPS             51
177 #define CTDB_CONTROL_MODIFY_FLAGS               52
178 #define CTDB_CONTROL_GET_ALL_TUNABLES           53
179 #define CTDB_CONTROL_KILL_TCP                   54
180 #define CTDB_CONTROL_GET_TCP_TICKLE_LIST        55
181 #define CTDB_CONTROL_SET_TCP_TICKLE_LIST        56
182 #define CTDB_CONTROL_REGISTER_SERVER_ID         57
183 #define CTDB_CONTROL_UNREGISTER_SERVER_ID       58
184 #define CTDB_CONTROL_CHECK_SERVER_ID            59
185 #define CTDB_CONTROL_GET_SERVER_ID_LIST         60
186 #define CTDB_CONTROL_DB_ATTACH_PERSISTENT       61
187 #define CTDB_CONTROL_PERSISTENT_STORE           62
188 #define CTDB_CONTROL_UPDATE_RECORD              63
189
190 static const value_string ctrl_opcode_vals[] = {
191         {CTDB_CONTROL_PROCESS_EXISTS,   "PROCESS_EXISTS"},
192         {CTDB_CONTROL_STATISTICS,       "STATISTICS"},
193         {CTDB_CONTROL_CONFIG,           "CONFIG"},
194         {CTDB_CONTROL_PING,             "PING"},
195         {CTDB_CONTROL_GETDBPATH,        "GETDBPATH"},
196         {CTDB_CONTROL_GETVNNMAP,        "GETVNNMAP"},
197         {CTDB_CONTROL_SETVNNMAP,        "SETVNNMAP"},
198         {CTDB_CONTROL_GET_DEBUG,        "GET_DEBUG"},
199         {CTDB_CONTROL_SET_DEBUG,        "SET_DEBUG"},
200         {CTDB_CONTROL_GET_DBMAP,        "GET_DBMAP"},
201         {CTDB_CONTROL_GET_NODEMAP,      "GET_NODEMAP"},
202         {CTDB_CONTROL_SET_DMASTER,      "SET_DMASTER"},
203         {CTDB_CONTROL_CLEAR_DB,         "CLEAR_DB"},
204         {CTDB_CONTROL_PULL_DB,          "PULL_DB"},
205         {CTDB_CONTROL_PUSH_DB,          "PUSH_DB"},
206         {CTDB_CONTROL_GET_RECMODE,      "GET_RECMODE"},
207         {CTDB_CONTROL_SET_RECMODE,      "SET_RECMODE"},
208         {CTDB_CONTROL_STATISTICS_RESET, "STATISTICS_RESET"},
209         {CTDB_CONTROL_DB_ATTACH,        "DB_ATTACH"},
210         {CTDB_CONTROL_SET_CALL,         "SET_CALL"},
211         {CTDB_CONTROL_TRAVERSE_START,   "TRAVERSE_START"},
212         {CTDB_CONTROL_TRAVERSE_ALL,     "TRAVERSE_ALL"},
213         {CTDB_CONTROL_TRAVERSE_DATA,    "TRAVERSE_DATA"},
214         {CTDB_CONTROL_REGISTER_SRVID,   "REGISTER_SRVID"},
215         {CTDB_CONTROL_DEREGISTER_SRVID, "DEREGISTER_SRVID"},
216         {CTDB_CONTROL_GET_DBNAME,       "GET_DBNAME"},
217         {CTDB_CONTROL_ENABLE_SEQNUM,    "ENABLE_SEQNUM"},
218         {CTDB_CONTROL_UPDATE_SEQNUM,    "UPDATE_SEQNUM"},
219         {CTDB_CONTROL_SET_SEQNUM_FREQUENCY,     "SET_SEQNUM_FREQUENCY"},
220         {CTDB_CONTROL_DUMP_MEMORY,      "DUMP_MEMORY"},
221         {CTDB_CONTROL_GET_PID,          "GET_PID"},
222         {CTDB_CONTROL_GET_RECMASTER,    "GET_RECMASTER"},
223         {CTDB_CONTROL_SET_RECMASTER,    "SET_RECMASTER"},
224         {CTDB_CONTROL_FREEZE,           "FREEZE"},
225         {CTDB_CONTROL_THAW,             "THAW"},
226         {CTDB_CONTROL_GET_VNN,          "GET_VNN"},
227         {CTDB_CONTROL_SHUTDOWN,         "SHUTDOWN"},
228         {CTDB_CONTROL_GET_MONMODE,      "GET_MONMODE"},
229         {CTDB_CONTROL_SET_MONMODE,      "SET_MONMODE"},
230         {CTDB_CONTROL_MAX_RSN,          "MAX_RSN"},
231         {CTDB_CONTROL_SET_RSN_NONEMPTY, "SET_RSN_NONEMPTY"},
232         {CTDB_CONTROL_DELETE_LOW_RSN,   "DELETE_LOW_RSN"},
233         {CTDB_CONTROL_TAKEOVER_IP,      "TAKEOVER_IP"},
234         {CTDB_CONTROL_RELEASE_IP,       "RELEASE_IP"},
235         {CTDB_CONTROL_TCP_CLIENT,       "TCP_CLIENT"},
236         {CTDB_CONTROL_TCP_ADD,          "TCP_ADD"},
237         {CTDB_CONTROL_TCP_REMOVE,       "TCP_REMOVE"},
238         {CTDB_CONTROL_STARTUP,          "STARTUP"},
239         {CTDB_CONTROL_SET_TUNABLE,      "SET_TUNABLE"},
240         {CTDB_CONTROL_GET_TUNABLE,      "GET_TUNABLE"},
241         {CTDB_CONTROL_LIST_TUNABLES,    "LIST_TUNABLES"},
242         {CTDB_CONTROL_GET_PUBLIC_IPS,   "GET_PUBLIC_IPS"},
243         {CTDB_CONTROL_MODIFY_FLAGS,     "MODIFY_FLAGS"},
244         {CTDB_CONTROL_GET_ALL_TUNABLES, "GET_ALL_TUNABLES"},
245         {CTDB_CONTROL_KILL_TCP,         "KILL_TCP"},
246         {CTDB_CONTROL_GET_TCP_TICKLE_LIST,      "GET_TCP_TICKLE_LIST"},
247         {CTDB_CONTROL_SET_TCP_TICKLE_LIST,      "SET_TCP_TICKLE_LIST"},
248         {CTDB_CONTROL_REGISTER_SERVER_ID,       "REGISTER_SERVER_ID"},
249         {CTDB_CONTROL_UNREGISTER_SERVER_ID,     "UNREGISTER_SERVER_ID"},
250         {CTDB_CONTROL_CHECK_SERVER_ID,          "CHECK_SERVER_ID"},
251         {CTDB_CONTROL_GET_SERVER_ID_LIST,       "GET_SERVER_ID_LIST"},
252         {CTDB_CONTROL_DB_ATTACH_PERSISTENT,     "DB_ATTACH_PERSISTENT"},
253         {CTDB_CONTROL_PERSISTENT_STORE,         "PERSISTENT_STORE"},
254         {CTDB_CONTROL_UPDATE_RECORD,            "UPDATE_RECORD"},
255         {0, NULL}
256 };
257
258
259
260 static int dissect_control_get_recmaster_reply(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, guint32 status, int endianess _U_)
261 {
262         proto_tree_add_uint(tree, hf_ctdb_recmaster, tvb, 0, 0, status);
263
264         if(check_col(pinfo->cinfo, COL_INFO)){
265                 col_append_fstr(pinfo->cinfo, COL_INFO, " RecMaster:%d", status);
266         }
267
268         return offset;
269 }
270
271 static const value_string recmode_vals[] = {
272         {0,"NORMAL"},
273         {1,"RECOVERY ACTIVE"},
274         {0,NULL}
275 };
276
277 static int dissect_control_get_recmode_reply(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, guint32 status, int endianess _U_)
278 {
279         proto_tree_add_uint(tree, hf_ctdb_recmode, tvb, 0, 0, status);
280
281         if(check_col(pinfo->cinfo, COL_INFO)){
282                 col_append_fstr(pinfo->cinfo, COL_INFO, " RecMode:%s",
283                         val_to_str(status, recmode_vals, "Unknown:%d"));
284         }
285
286         return offset;
287 }
288
289 static int dissect_control_get_nodemap_reply(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, int offset, guint32 status _U_, int endianess)
290 {
291         guint32 num_nodes;
292
293         /* num nodes */
294         proto_tree_add_item(tree, hf_ctdb_num_nodes, tvb, offset, 4, endianess);
295         if(endianess){
296                 num_nodes=tvb_get_letohl(tvb, offset);
297         } else {
298                 num_nodes=tvb_get_ntohl(tvb, offset);
299         }
300         offset+=4;
301
302         while(num_nodes--){
303                 /* vnn */
304                 proto_tree_add_item(tree, hf_ctdb_vnn, tvb, offset, 4, endianess);
305                 offset+=4;
306
307                 /* node flags */
308                 proto_tree_add_item(tree, hf_ctdb_node_flags, tvb, offset, 4, endianess);
309                 offset+=4;
310
311                 /* here comes a sockaddr_in but we only store ipv4 addresses in it */
312                 proto_tree_add_item(tree, hf_ctdb_node_ip, tvb, offset+4, 4, FALSE);
313                 offset+=16;
314         }
315
316         return offset;
317 }
318
319 static int dissect_control_process_exist_request(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, guint32 status _U_, int endianess)
320 {
321         guint32 pid;
322
323         /* pid */
324         proto_tree_add_item(tree, hf_ctdb_pid, tvb, offset, 4, endianess);
325         if(endianess){
326                 pid=tvb_get_letohl(tvb, offset);
327         } else {
328                 pid=tvb_get_ntohl(tvb, offset);
329         }
330         offset+=4;
331
332         if(check_col(pinfo->cinfo, COL_INFO)){
333                 col_append_fstr(pinfo->cinfo, COL_INFO, " pid:%d", pid);
334         }
335
336         return offset;
337 }
338
339 static const true_false_string process_exists_tfs = {
340   "Process does NOT exist",
341   "Process Exists"
342 };
343
344 static int dissect_control_process_exist_reply(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, int offset, guint32 status, int endianess _U_)
345 {
346         proto_tree_add_boolean(tree, hf_ctdb_process_exists, tvb, offset, 4, status);
347         return offset;
348 }
349
350 /* This defines the array of dissectors for request/reply controls */
351 typedef int (*control_dissector)(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, guint32 status, int endianess);
352
353 typedef struct _control_dissector_array_t {
354         guint32 opcode;
355         control_dissector request_dissector;
356         control_dissector reply_dissector;
357 } control_dissector_array_t;
358
359 static control_dissector_array_t control_dissectors[] = {
360         {CTDB_CONTROL_GET_RECMASTER,
361                 NULL,
362                 dissect_control_get_recmaster_reply},
363         {CTDB_CONTROL_GET_RECMODE,
364                 NULL,
365                 dissect_control_get_recmode_reply},
366         {CTDB_CONTROL_GET_NODEMAP,
367                 NULL,
368                 dissect_control_get_nodemap_reply},
369         {CTDB_CONTROL_FREEZE,
370                 NULL,
371                 NULL},
372         {CTDB_CONTROL_THAW,
373                 NULL,
374                 NULL},
375         {CTDB_CONTROL_PROCESS_EXISTS,
376                 dissect_control_process_exist_request,
377                 dissect_control_process_exist_reply},
378
379 /*CTDB_CONTROL_STATISTICS*/
380 /*CTDB_CONTROL_CONFIG*/
381 /*CTDB_CONTROL_PING*/
382 /*CTDB_CONTROL_GETDBPATH*/
383 /*CTDB_CONTROL_GETVNNMAP*/
384 /*CTDB_CONTROL_SETVNNMAP*/
385 /*CTDB_CONTROL_GET_DEBUG*/
386 /*CTDB_CONTROL_SET_DEBUG*/
387 /*CTDB_CONTROL_GET_DBMAP*/
388 /*CTDB_CONTROL_SET_DMASTER*/
389 /*CTDB_CONTROL_CLEAR_DB*/
390 /*CTDB_CONTROL_PULL_DB*/
391 /*CTDB_CONTROL_PUSH_DB*/
392 /*CTDB_CONTROL_SET_RECMODE*/
393 /*CTDB_CONTROL_STATISTICS_RESET*/
394 /*CTDB_CONTROL_DB_ATTACH*/
395 /*CTDB_CONTROL_SET_CALL*/
396 /*CTDB_CONTROL_TRAVERSE_START*/
397 /*CTDB_CONTROL_TRAVERSE_ALL*/
398 /*CTDB_CONTROL_TRAVERSE_DATA*/
399 /*CTDB_CONTROL_REGISTER_SRVID*/
400 /*CTDB_CONTROL_DEREGISTER_SRVID*/
401 /*CTDB_CONTROL_GET_DBNAME*/
402 /*CTDB_CONTROL_ENABLE_SEQNUM*/
403 /*CTDB_CONTROL_UPDATE_SEQNUM*/
404 /*CTDB_CONTROL_SET_SEQNUM_FREQUENCY*/
405 /*CTDB_CONTROL_DUMP_MEMORY*/
406 /*CTDB_CONTROL_GET_PID*/
407 /*CTDB_CONTROL_SET_RECMASTER*/
408 /*CTDB_CONTROL_GET_VNN*/
409 /*CTDB_CONTROL_SHUTDOWN*/
410 /*CTDB_CONTROL_GET_MONMODE*/
411 /*CTDB_CONTROL_SET_MONMODE*/
412 /*CTDB_CONTROL_MAX_RSN*/
413 /*CTDB_CONTROL_SET_RSN_NONEMPTY*/
414 /*CTDB_CONTROL_DELETE_LOW_RSN*/
415 /*CTDB_CONTROL_TAKEOVER_IP*/
416 /*CTDB_CONTROL_RELEASE_IP*/
417 /*CTDB_CONTROL_TCP_CLIENT*/
418 /*CTDB_CONTROL_TCP_ADD*/
419 /*CTDB_CONTROL_TCP_REMOVE*/
420 /*CTDB_CONTROL_STARTUP*/
421 /*CTDB_CONTROL_SET_TUNABLE*/
422 /*CTDB_CONTROL_GET_TUNABLE*/
423 /*CTDB_CONTROL_LIST_TUNABLES*/
424 /*CTDB_CONTROL_GET_PUBLIC_IPS*/
425 /*CTDB_CONTROL_MODIFY_FLAGS*/
426 /*CTDB_CONTROL_GET_ALL_TUNABLES*/
427 /*CTDB_CONTROL_KILL_TCP*/
428 /*CTDB_CONTROL_GET_TCP_TICKLE_LIST*/
429 /*CTDB_CONTROL_SET_TCP_TICKLE_LIST*/
430         {0, NULL, NULL}
431 };
432
433 static control_dissector find_control_dissector(guint32 opcode, gboolean is_request)
434 {
435         control_dissector_array_t *cd=control_dissectors;
436
437         while(cd){
438                 if((!cd->opcode)&&(!cd->request_dissector)&&(!cd->reply_dissector)){
439                         break;
440                 }
441                 if(opcode==cd->opcode){
442                         if(is_request){
443                                 return cd->request_dissector;
444                         } else {
445                                 return cd->reply_dissector;
446                         }
447                 }
448                 cd++;
449         }
450         return NULL;
451 }
452
453 static const value_string ctdb_dbid_vals[] = {
454         {0x435d3410,            "notify.tdb"},
455         {0x42fe72c5,            "locking.tdb"},
456         {0x1421fb78,            "brlock.tdb"},
457         {0x17055d90,            "connections.tdb"},
458         {0xc0bdde6a,            "sessionid.tdb"},
459         {0, NULL}
460 };
461
462 static void
463 ctdb_display_trans(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, ctdb_trans_t *ctdb_trans)
464 {
465         proto_item *item;
466
467         if(ctdb_trans->request_in!=pinfo->fd->num){
468                 item=proto_tree_add_uint(tree, hf_ctdb_request_in, tvb, 0, 0, ctdb_trans->request_in);
469                 PROTO_ITEM_SET_GENERATED(item);
470         }
471
472         if( (ctdb_trans->response_in!=0)
473           &&(ctdb_trans->response_in!=pinfo->fd->num) ){
474                 item=proto_tree_add_uint(tree, hf_ctdb_response_in, tvb, 0, 0, ctdb_trans->response_in);
475                 PROTO_ITEM_SET_GENERATED(item);
476         }
477
478         if(pinfo->fd->num==ctdb_trans->response_in){
479                 nstime_t ns;
480
481                 nstime_delta(&ns, &pinfo->fd->abs_ts, &ctdb_trans->req_time);
482                 item=proto_tree_add_time(tree, hf_ctdb_time, tvb, 0, 0, &ns);
483                 PROTO_ITEM_SET_GENERATED(item);
484         }
485 }
486
487 static void
488 ctdb_display_control(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, ctdb_control_t *ctdb_control)
489 {
490         proto_item *item;
491
492         if(ctdb_control->request_in!=pinfo->fd->num){
493                 item=proto_tree_add_uint(tree, hf_ctdb_request_in, tvb, 0, 0, ctdb_control->request_in);
494                 PROTO_ITEM_SET_GENERATED(item);
495         }
496
497         if( (ctdb_control->response_in!=0)
498           &&(ctdb_control->response_in!=pinfo->fd->num) ){
499                 item=proto_tree_add_uint(tree, hf_ctdb_response_in, tvb, 0, 0, ctdb_control->response_in);
500                 PROTO_ITEM_SET_GENERATED(item);
501         }
502
503         if(pinfo->fd->num==ctdb_control->response_in){
504                 nstime_t ns;
505
506                 nstime_delta(&ns, &pinfo->fd->abs_ts, &ctdb_control->req_time);
507                 item=proto_tree_add_time(tree, hf_ctdb_time, tvb, 0, 0, &ns);
508                 PROTO_ITEM_SET_GENERATED(item);
509         }
510 }
511
512 static guint32
513 ctdb_hash(tvbuff_t *tvb, int offset, guint32 len)
514 {
515         guint32 value;
516         guint32 i;
517
518         for(value=0x238F13AF*len, i=0; i < len; i++)
519                 value=(value+(tvb_get_guint8(tvb, offset+i) << (i*5 % 24)));
520
521         return (1103515243 * value + 12345);  
522 }
523
524 static int
525 dissect_ctdb_key(proto_tree *tree, tvbuff_t *tvb, int offset, guint32 keylen, guint32 *key_hash, int endianess)
526 {
527         guint32 keyhash;
528         proto_item *key_item=NULL;
529         proto_item *key_tree=NULL;
530
531         if(tree){
532                 key_item=proto_tree_add_item(tree, hf_ctdb_key, tvb, offset, keylen, endianess);
533                 key_tree=proto_item_add_subtree(key_item, ett_ctdb_key);
534
535         }
536
537         keyhash=ctdb_hash(tvb, offset, keylen);
538         proto_item_append_text(key_item, " (Hash:0x%08x)", keyhash);
539         key_item=proto_tree_add_uint(key_tree, hf_ctdb_keyhash, tvb, 0, 0, keyhash);
540         PROTO_ITEM_SET_GENERATED(key_item);
541
542         offset+=keylen;
543
544         if(key_hash){
545                 *key_hash=keyhash;
546         }
547
548         return offset;
549 }
550
551 static int
552 dissect_ctdb_reply_call(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int endianess)
553 {
554         guint32 datalen;
555
556         /* status */
557         proto_tree_add_item(tree, hf_ctdb_status, tvb, offset, 4, endianess);
558         offset+=4;
559
560         /* datalen */
561         proto_tree_add_item(tree, hf_ctdb_datalen, tvb, offset, 4, endianess);
562         if(endianess){
563                 datalen=tvb_get_letohl(tvb, offset);
564         } else {
565                 datalen=tvb_get_ntohl(tvb, offset);
566         }
567         offset+=4;
568
569         /* data */
570         proto_tree_add_item(tree, hf_ctdb_data, tvb, offset, datalen, endianess);
571         offset+=datalen;
572         
573
574         return offset;
575 }
576
577 static int
578 dissect_ctdb_reply_dmaster(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, guint32 reqid, guint32 dst, int endianess)
579 {
580         guint32 datalen, keylen;
581         emem_tree_key_t tkey[3];
582         ctdb_trans_t *ctdb_trans;
583
584         /* dbid */
585         proto_tree_add_item(tree, hf_ctdb_dbid, tvb, offset, 4, endianess);
586         offset+=4;
587
588
589         /* rsn */
590         offset=(offset+7)&0xfffff8; /* fixup alignment*/
591         proto_tree_add_item(tree, hf_ctdb_rsn, tvb, offset, 8, endianess);
592         offset+=8;
593
594         /* keylen */
595         proto_tree_add_item(tree, hf_ctdb_keylen, tvb, offset, 4, endianess);
596         if(endianess){
597                 keylen=tvb_get_letohl(tvb, offset);
598         } else {
599                 keylen=tvb_get_ntohl(tvb, offset);
600         }
601         offset+=4;
602
603         /* datalen */
604         proto_tree_add_item(tree, hf_ctdb_datalen, tvb, offset, 4, endianess);
605         if(endianess){
606                 datalen=tvb_get_letohl(tvb, offset);
607         } else {
608                 datalen=tvb_get_ntohl(tvb, offset);
609         }
610         offset+=4;
611
612         /* key */
613         offset=dissect_ctdb_key(tree, tvb, offset, keylen, NULL, endianess);
614
615         /* data */
616         proto_tree_add_item(tree, hf_ctdb_data, tvb, offset, datalen, endianess);
617         offset+=datalen;
618         
619         tkey[0].length=1;
620         tkey[0].key=&reqid;
621         tkey[1].length=1;
622         tkey[1].key=&dst;
623         tkey[2].length=0;
624         ctdb_trans=se_tree_lookup32_array(ctdb_transactions, &tkey[0]);
625
626         if(ctdb_trans){
627                 ctdb_trans->response_in=pinfo->fd->num;
628                 ctdb_display_trans(pinfo, tree, tvb, ctdb_trans);
629         }
630
631         return offset;
632 }
633
634 static int
635 dissect_ctdb_req_dmaster(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, guint32 reqid, int endianess)
636 {
637         guint32 keylen, datalen, dmaster;
638         emem_tree_key_t tkey[3];
639         ctdb_trans_t *ctdb_trans;
640
641         /* dbid */
642         proto_tree_add_item(tree, hf_ctdb_dbid, tvb, offset, 4, endianess);
643         offset+=4;
644
645         /* rsn */
646         offset=(offset+7)&0xfffff8; /* fixup alignment*/
647         proto_tree_add_item(tree, hf_ctdb_rsn, tvb, offset, 8, endianess);
648         offset+=8;
649
650         /* dmaster */
651         proto_tree_add_item(tree, hf_ctdb_dmaster, tvb, offset, 4, endianess);
652         if(endianess){
653                 dmaster=tvb_get_letohl(tvb, offset);
654         } else {
655                 dmaster=tvb_get_ntohl(tvb, offset);
656         }
657         offset += 4;
658
659         /* keylen */
660         proto_tree_add_item(tree, hf_ctdb_keylen, tvb, offset, 4, endianess);
661         if(endianess){
662                 keylen=tvb_get_letohl(tvb, offset);
663         } else {
664                 keylen=tvb_get_ntohl(tvb, offset);
665         }
666         offset+=4;
667
668         /* datalen */
669         proto_tree_add_item(tree, hf_ctdb_datalen, tvb, offset, 4, endianess);
670         if(endianess){
671                 datalen=tvb_get_letohl(tvb, offset);
672         } else {
673                 datalen=tvb_get_ntohl(tvb, offset);
674         }
675         offset+=4;
676
677         /* key */
678         offset=dissect_ctdb_key(tree, tvb, offset, keylen, NULL, endianess);
679
680         /* data */
681         proto_tree_add_item(tree, hf_ctdb_data, tvb, offset, datalen, endianess);
682         offset+=datalen;
683
684
685         tkey[0].length=1;
686         tkey[0].key=&reqid;
687         tkey[1].length=1;
688         tkey[1].key=&dmaster;
689         tkey[2].length=0;
690         ctdb_trans=se_tree_lookup32_array(ctdb_transactions, &tkey[0]);
691
692         if(ctdb_trans){
693                 ctdb_display_trans(pinfo, tree, tvb, ctdb_trans);
694         }
695
696         return offset;
697 }
698
699
700
701 static int
702 dissect_ctdb_req_control(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, guint32 reqid, guint32 src, guint32 dst, int endianess)
703 {
704         guint32 datalen;
705         guint32 opcode;
706         ctdb_control_t *ctdb_control;
707         control_dissector cd;
708         int data_offset;
709
710         /* ctrl opcode */
711         proto_tree_add_item(tree, hf_ctdb_ctrl_opcode, tvb, offset, 4, endianess);
712         if(endianess){
713                 opcode=tvb_get_letohl(tvb, offset);
714         } else {
715                 opcode=tvb_get_ntohl(tvb, offset);
716         }
717         offset+=4;
718
719         if(check_col(pinfo->cinfo, COL_INFO)){
720                 col_add_fstr(pinfo->cinfo, COL_INFO, "%s Request %d->%d",
721                         val_to_str(opcode, ctrl_opcode_vals, "Unknown:%d"),
722                         src, dst);
723         }
724
725         /* srvid */
726         offset=(offset+7)&0xfffff8; /* fixup alignment*/
727         proto_tree_add_item(tree, hf_ctdb_srvid, tvb, offset, 8, endianess);
728         offset+=8;
729
730         /* client id */
731         proto_tree_add_item(tree, hf_ctdb_clientid, tvb, offset, 4, endianess);
732         offset+=4;
733
734         /* ctrl flags */
735         proto_tree_add_item(tree, hf_ctdb_ctrl_flags, tvb, offset, 4, endianess);
736         offset+=4;
737
738         /* datalen */
739         proto_tree_add_item(tree, hf_ctdb_datalen, tvb, offset, 4, endianess);
740         if(endianess){
741                 datalen=tvb_get_letohl(tvb, offset);
742         } else {
743                 datalen=tvb_get_ntohl(tvb, offset);
744         }
745         offset+=4;
746
747         /* data */
748         data_offset=offset;
749         if (datalen) {
750                 proto_tree_add_item(tree, hf_ctdb_data, tvb, offset, datalen, endianess);
751                 offset+=datalen;
752         }
753
754         /* setup request/response matching */
755         if(!pinfo->fd->flags.visited){
756                 emem_tree_key_t tkey[4];
757
758                 ctdb_control=se_alloc(sizeof(ctdb_control_t));
759                 ctdb_control->opcode=opcode;
760                 ctdb_control->request_in=pinfo->fd->num;
761                 ctdb_control->response_in=0;
762                 ctdb_control->req_time=pinfo->fd->abs_ts;
763                 tkey[0].length=1;
764                 tkey[0].key=&reqid;
765                 tkey[1].length=1;
766                 tkey[1].key=&src;
767                 tkey[2].length=1;
768                 tkey[2].key=&dst;
769                 tkey[3].length=0;
770
771                 se_tree_insert32_array(ctdb_controls, &tkey[0], ctdb_control);
772         } else {
773                 emem_tree_key_t tkey[4];
774
775                 tkey[0].length=1;
776                 tkey[0].key=&reqid;
777                 tkey[1].length=1;
778                 tkey[1].key=&src;
779                 tkey[2].length=1;
780                 tkey[2].key=&dst;
781                 tkey[3].length=0;
782                 ctdb_control=se_tree_lookup32_array(ctdb_controls, &tkey[0]);
783         }
784
785
786         cd=find_control_dissector(ctdb_control->opcode, TRUE);
787         if (cd) {
788                 cd(pinfo, tree, tvb, data_offset, 0, endianess);
789         }
790
791         ctdb_display_control(pinfo, tree, tvb, ctdb_control);
792         
793         return offset;
794 }
795
796 static int
797 dissect_ctdb_reply_control(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, guint32 reqid, guint32 src, guint32 dst, int endianess)
798 {
799         ctdb_control_t *ctdb_control;
800         emem_tree_key_t tkey[4];
801         proto_item *item;
802         guint32 datalen, errorlen, status;
803         int data_offset;
804         control_dissector cd;
805
806         tkey[0].length=1;
807         tkey[0].key=&reqid;
808         tkey[1].length=1;
809         tkey[1].key=&dst;
810         tkey[2].length=1;
811         tkey[2].key=&src;
812         tkey[3].length=0;
813         ctdb_control=se_tree_lookup32_array(ctdb_controls, &tkey[0]);
814
815         if(!ctdb_control){
816                 return offset;
817         }
818
819         if(!pinfo->fd->flags.visited){
820                 ctdb_control->response_in = pinfo->fd->num;
821         }
822
823         /* ctrl opcode */
824         item=proto_tree_add_uint(tree, hf_ctdb_ctrl_opcode, tvb, 0, 0, ctdb_control->opcode);
825         PROTO_ITEM_SET_GENERATED(item);
826
827         if(check_col(pinfo->cinfo, COL_INFO)){
828                 col_add_fstr(pinfo->cinfo, COL_INFO, "%s Reply %d->%d",
829                         val_to_str(ctdb_control->opcode, ctrl_opcode_vals, "Unknown:%d"),
830                         src, dst);
831         }
832
833
834         /* status */
835         proto_tree_add_item(tree, hf_ctdb_status, tvb, offset, 4, endianess);
836         if(endianess){
837                 status=tvb_get_letohl(tvb, offset);
838         } else {
839                 status=tvb_get_ntohl(tvb, offset);
840         }
841         offset+=4;
842
843         /* datalen */
844         proto_tree_add_item(tree, hf_ctdb_datalen, tvb, offset, 4, endianess);
845         if(endianess){
846                 datalen=tvb_get_letohl(tvb, offset);
847         } else {
848                 datalen=tvb_get_ntohl(tvb, offset);
849         }
850         offset+=4;
851
852         /* errorlen */
853         proto_tree_add_item(tree, hf_ctdb_errorlen, tvb, offset, 4, endianess);
854         if(endianess){
855                 errorlen=tvb_get_letohl(tvb, offset);
856         } else {
857                 errorlen=tvb_get_ntohl(tvb, offset);
858         }
859         offset+=4;
860
861         /* data */
862         data_offset=offset;
863         if (datalen) {
864                 proto_tree_add_item(tree, hf_ctdb_data, tvb, offset, datalen, endianess);
865                 offset+=datalen;
866         }
867
868
869         /* error */
870         if (errorlen) {
871                 proto_tree_add_item(tree, hf_ctdb_error, tvb, offset, errorlen, endianess);
872                 offset+=datalen;
873         }
874         
875
876         cd=find_control_dissector(ctdb_control->opcode, FALSE);
877         if (cd) {
878                 cd(pinfo, tree, tvb, data_offset, status, endianess);
879         }
880
881         ctdb_display_control(pinfo, tree, tvb, ctdb_control);
882         return offset;
883 }
884
885 static const true_false_string flags_immediate_tfs={
886         "DMASTER for the record must IMMEDIATELY be migrated to the caller",
887         "Dmaster migration is not required"
888 };
889
890 static int
891 dissect_ctdb_req_call(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint32 reqid, guint32 caller, int endianess)
892 {
893         guint32 flags, keyhash;
894         guint32 keylen, datalen;
895         ctdb_trans_t *ctdb_trans=NULL;
896
897         /* flags */
898         proto_tree_add_item(tree, hf_ctdb_flags_immediate, tvb, offset, 4, endianess);
899         if(endianess){
900                 flags=tvb_get_letohl(tvb, offset);
901         } else {
902                 flags=tvb_get_ntohl(tvb, offset);
903         }
904         if(flags&0x00000001){
905                 col_append_str(pinfo->cinfo, COL_INFO, " IMMEDIATE");
906         }       
907         offset+=4;
908
909         /* dbid */
910         proto_tree_add_item(tree, hf_ctdb_dbid, tvb, offset, 4, endianess);
911         offset+=4;
912
913         /* callid */
914         proto_tree_add_item(tree, hf_ctdb_callid, tvb, offset, 4, endianess);
915         offset+=4;
916
917         /* hopcount */
918         proto_tree_add_item(tree, hf_ctdb_hopcount, tvb, offset, 4, endianess);
919         offset+=4;
920
921         /* keylen */
922         proto_tree_add_item(tree, hf_ctdb_keylen, tvb, offset, 4, endianess);
923         if(endianess){
924                 keylen=tvb_get_letohl(tvb, offset);
925         } else {
926                 keylen=tvb_get_ntohl(tvb, offset);
927         }
928         offset+=4;
929
930         /* datalen */
931         proto_tree_add_item(tree, hf_ctdb_datalen, tvb, offset, 4, endianess);
932         if(endianess){
933                 datalen=tvb_get_letohl(tvb, offset);
934         } else {
935                 datalen=tvb_get_ntohl(tvb, offset);
936         }
937         offset+=4;
938
939         /* key */
940         offset=dissect_ctdb_key(tree, tvb, offset, keylen, &keyhash, endianess);
941
942         /* data */
943         proto_tree_add_item(tree, hf_ctdb_data, tvb, offset, datalen, endianess);
944         offset+=datalen;
945
946         /* setup request/response matching */
947         if(!pinfo->fd->flags.visited){
948                 emem_tree_key_t tkey[3];
949
950                 ctdb_trans=se_alloc(sizeof(ctdb_trans_t));
951                 ctdb_trans->key_hash=keyhash;
952                 ctdb_trans->request_in=pinfo->fd->num;
953                 ctdb_trans->response_in=0;
954                 ctdb_trans->req_time=pinfo->fd->abs_ts;
955                 tkey[0].length=1;
956                 tkey[0].key=&reqid;
957                 tkey[1].length=1;
958                 tkey[1].key=&caller;
959                 tkey[2].length=0;
960
961                 se_tree_insert32_array(ctdb_transactions, &tkey[0], ctdb_trans);
962         } else {
963                 emem_tree_key_t tkey[3];
964
965                 tkey[0].length=1;
966                 tkey[0].key=&reqid;
967                 tkey[1].length=1;
968                 tkey[1].key=&caller;
969                 tkey[2].length=0;
970                 ctdb_trans=se_tree_lookup32_array(ctdb_transactions, &tkey[0]);
971         }
972
973         if(ctdb_trans){
974                 ctdb_display_trans(pinfo, tree, tvb, ctdb_trans);
975         }
976
977         return offset;
978 }
979
980 static gboolean
981 dissect_ctdb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
982 {
983         proto_tree *tree=NULL;
984         proto_item *item=NULL;
985         int offset=0;
986         guint32 opcode, src, dst, reqid;
987         int endianess;
988
989         /* does this look like CTDB? */
990         if(tvb_length_remaining(tvb, offset)<8){
991                 return FALSE;
992         }
993         switch(tvb_get_letohl(tvb, offset+4)){
994         case 0x42445443:
995                 endianess=FALSE;
996                 break;
997         case 0x43544442:
998                 endianess=TRUE;
999                 break;
1000         default:
1001                 return FALSE;
1002         }
1003         
1004
1005         col_set_str(pinfo->cinfo, COL_PROTOCOL, "CTDB");
1006         col_clear(pinfo->cinfo, COL_INFO);
1007
1008         if(parent_tree){
1009                 item=proto_tree_add_item(parent_tree, proto_ctdb, tvb, offset,
1010                         -1, endianess);
1011                 tree=proto_item_add_subtree(item, ett_ctdb);
1012         }
1013
1014         /* header*/
1015         /* length */
1016         proto_tree_add_item(tree, hf_ctdb_length, tvb, offset, 4, endianess);
1017         offset+=4;
1018
1019         /* magic */
1020         proto_tree_add_item(tree, hf_ctdb_magic, tvb, offset, 4, endianess);
1021         offset+=4;
1022
1023         /* version */
1024         proto_tree_add_item(tree, hf_ctdb_version, tvb, offset, 4, endianess);
1025         offset+=4;
1026
1027         /* generation */
1028         proto_tree_add_item(tree, hf_ctdb_generation, tvb, offset, 4, endianess);
1029         offset+=4;
1030
1031         /* opcode */
1032         proto_tree_add_item(tree, hf_ctdb_opcode, tvb, offset, 4, endianess);
1033         if(endianess){
1034                 opcode=tvb_get_letohl(tvb, offset);
1035         } else {
1036                 opcode=tvb_get_ntohl(tvb, offset);
1037         }
1038         offset+=4;
1039
1040         /* dst */
1041         proto_tree_add_item(tree, hf_ctdb_dst, tvb, offset, 4, endianess);
1042         if(endianess){
1043                 dst=tvb_get_letohl(tvb, offset);
1044         } else {
1045                 dst=tvb_get_ntohl(tvb, offset);
1046         }
1047         offset+=4;
1048
1049         /* src */
1050         proto_tree_add_item(tree, hf_ctdb_src, tvb, offset, 4, endianess);
1051         if(endianess){
1052                 src=tvb_get_letohl(tvb, offset);
1053         } else {
1054                 src=tvb_get_ntohl(tvb, offset);
1055         }
1056         offset+=4;
1057
1058         /* id */
1059         proto_tree_add_item(tree, hf_ctdb_id, tvb, offset, 4, endianess);
1060         if(endianess){
1061                 reqid=tvb_get_letohl(tvb, offset);
1062         } else {
1063                 reqid=tvb_get_ntohl(tvb, offset);
1064         }
1065         offset+=4;
1066
1067         if(check_col(pinfo->cinfo, COL_INFO)){
1068                 col_append_fstr(pinfo->cinfo, COL_INFO, "%s %d->%d",
1069                         val_to_str(opcode, ctdb_opcodes, "Unknown:%d"),
1070                         src, dst);
1071         }
1072
1073         switch(opcode){
1074         case CTDB_REQ_CALL:
1075                 offset=dissect_ctdb_req_call(tvb, offset, pinfo, tree, reqid, src, endianess);
1076                 break;
1077         case CTDB_REPLY_CALL:
1078                 offset=dissect_ctdb_reply_call(tvb, offset, pinfo, tree, endianess);
1079                 break;
1080         case CTDB_REPLY_DMASTER:
1081                 offset=dissect_ctdb_reply_dmaster(tvb, offset, pinfo, tree, reqid, dst, endianess);
1082                 break;
1083         case CTDB_REQ_DMASTER:
1084                 offset=dissect_ctdb_req_dmaster(tvb, offset, pinfo, tree, reqid, endianess);
1085                 break;
1086         case CTDB_REPLY_ERROR:
1087                 break;
1088         case CTDB_REQ_MESSAGE:
1089                 break;
1090         case CTDB_REQ_CONTROL:
1091                 offset=dissect_ctdb_req_control(tvb, offset, pinfo, tree, reqid, src, dst, endianess);
1092                 break;
1093         case CTDB_REPLY_CONTROL:
1094                 offset=dissect_ctdb_reply_control(tvb, offset, pinfo, tree, reqid, src, dst, endianess);
1095                 break;
1096         };
1097
1098         return TRUE;
1099 }
1100
1101
1102 /*
1103  * Register the protocol with Wireshark
1104  */
1105 void
1106 proto_register_ctdb(void)
1107 {
1108         static hf_register_info hf[] = {
1109         { &hf_ctdb_length, { 
1110           "Length", "ctdb.len", FT_UINT32, BASE_DEC, 
1111           NULL, 0x0, "Size of CTDB PDU", HFILL }},
1112         { &hf_ctdb_dst, { 
1113           "Destination", "ctdb.dst", FT_UINT32, BASE_DEC, 
1114           NULL, 0x0, NULL, HFILL }},
1115         { &hf_ctdb_src, { 
1116           "Source", "ctdb.src", FT_UINT32, BASE_DEC, 
1117           NULL, 0x0, NULL, HFILL }},
1118         { &hf_ctdb_id, { 
1119           "Id", "ctdb.id", FT_UINT32, BASE_DEC, 
1120           NULL, 0x0, "Transaction ID", HFILL }},
1121         { &hf_ctdb_opcode, { 
1122           "Opcode", "ctdb.opcode", FT_UINT32, BASE_DEC, 
1123           VALS(ctdb_opcodes), 0x0, "CTDB command opcode", HFILL }},
1124         { &hf_ctdb_flags_immediate, { 
1125           "Immediate", "ctdb.immediate", FT_BOOLEAN, 32, 
1126           TFS(&flags_immediate_tfs), 0x00000001, "Force migration of DMASTER?", HFILL }},
1127         { &hf_ctdb_dbid, { 
1128           "DB Id", "ctdb.dbid", FT_UINT32, BASE_HEX, 
1129           VALS(ctdb_dbid_vals), 0x0, "Database ID", HFILL }},
1130         { &hf_ctdb_callid, { 
1131           "Call Id", "ctdb.callid", FT_UINT32, BASE_DEC, 
1132           NULL, 0x0, "Call ID", HFILL }},
1133         { &hf_ctdb_status, { 
1134           "Status", "ctdb.status", FT_UINT32, BASE_DEC, 
1135           NULL, 0x0, NULL, HFILL }},
1136         { &hf_ctdb_datalen, { 
1137           "Data Length", "ctdb.datalen", FT_UINT32, BASE_DEC, 
1138           NULL, 0x0, NULL, HFILL }},
1139         { &hf_ctdb_errorlen, { 
1140           "Error Length", "ctdb.errorlen", FT_UINT32, BASE_DEC, 
1141           NULL, 0x0, NULL, HFILL }},
1142         { &hf_ctdb_keylen, { 
1143           "Key Length", "ctdb.keylen", FT_UINT32, BASE_DEC, 
1144           NULL, 0x0, NULL, HFILL }},
1145         { &hf_ctdb_magic, { 
1146           "Magic", "ctdb.magic", FT_UINT32, BASE_HEX, 
1147           NULL, 0x0, NULL, HFILL }},
1148         { &hf_ctdb_version, { 
1149           "Version", "ctdb.version", FT_UINT32, BASE_DEC, 
1150           NULL, 0x0, NULL, HFILL }},
1151         { &hf_ctdb_dmaster, { 
1152           "Dmaster", "ctdb.dmaster", FT_UINT32, BASE_DEC, 
1153           NULL, 0x0, NULL, HFILL }},
1154         { &hf_ctdb_generation, { 
1155           "Generation", "ctdb.generation", FT_UINT32, BASE_DEC, 
1156           NULL, 0x0, NULL, HFILL }},
1157         { &hf_ctdb_key, { 
1158           "Key", "ctdb.key", FT_BYTES, BASE_NONE, 
1159           NULL, 0x0, NULL, HFILL }},
1160         { &hf_ctdb_keyhash, { 
1161           "KeyHash", "ctdb.keyhash", FT_UINT32, BASE_HEX, 
1162           NULL, 0x0, NULL, HFILL }},
1163         { &hf_ctdb_data, { 
1164           "Data", "ctdb.data", FT_BYTES, BASE_NONE, 
1165           NULL, 0x0, NULL, HFILL }},
1166         { &hf_ctdb_error, { 
1167           "Error", "ctdb.error", FT_BYTES, BASE_NONE, 
1168           NULL, 0x0, NULL, HFILL }},
1169         { &hf_ctdb_request_in, { 
1170           "Request In", "ctdb.request_in", FT_FRAMENUM, BASE_NONE, 
1171           NULL, 0x0, NULL, HFILL }},
1172         { &hf_ctdb_response_in, { 
1173           "Response In", "ctdb.response_in", FT_FRAMENUM, BASE_NONE, 
1174           NULL, 0x0, NULL, HFILL }},
1175         { &hf_ctdb_time, { 
1176           "Time since request", "ctdb.time", FT_RELATIVE_TIME, BASE_NONE, 
1177           NULL, 0x0, NULL, HFILL }},
1178         { &hf_ctdb_hopcount, { 
1179           "Hopcount", "ctdb.hopcount", FT_UINT32, BASE_DEC, 
1180           NULL, 0x0, NULL, HFILL }},
1181         { &hf_ctdb_rsn, { 
1182           "RSN", "ctdb.rsn", FT_UINT64, BASE_HEX, 
1183           NULL, 0x0, NULL, HFILL }},
1184         { &hf_ctdb_ctrl_opcode, { 
1185           "CTRL Opcode", "ctdb.ctrl_opcode", FT_UINT32, BASE_DEC, 
1186           VALS(ctrl_opcode_vals), 0x0, NULL, HFILL }},
1187         { &hf_ctdb_srvid, { 
1188           "SrvId", "ctdb.srvid", FT_UINT64, BASE_HEX, 
1189           NULL, 0x0, NULL, HFILL }},
1190         { &hf_ctdb_clientid, { 
1191           "ClientId", "ctdb.clientid", FT_UINT32, BASE_HEX, 
1192           NULL, 0x0, NULL, HFILL }},
1193         { &hf_ctdb_ctrl_flags, { 
1194           "CTRL Flags", "ctdb.ctrl_flags", FT_UINT32, BASE_HEX, 
1195           NULL, 0x0, NULL, HFILL }},
1196         { &hf_ctdb_recmaster, { 
1197           "Recovery Master", "ctdb.recmaster", FT_UINT32, BASE_DEC, 
1198           NULL, 0x0, NULL, HFILL }},
1199         { &hf_ctdb_recmode, { 
1200           "Recovery Mode", "ctdb.recmode", FT_UINT32, BASE_DEC, 
1201           VALS(recmode_vals), 0x0, NULL, HFILL }},
1202         { &hf_ctdb_num_nodes, { 
1203           "Num Nodes", "ctdb.num_nodes", FT_UINT32, BASE_DEC, 
1204           NULL, 0x0, NULL, HFILL }},
1205         { &hf_ctdb_vnn, { 
1206           "VNN", "ctdb.vnn", FT_UINT32, BASE_DEC, 
1207           NULL, 0x0, NULL, HFILL }},
1208         { &hf_ctdb_node_flags, { 
1209           "Node Flags", "ctdb.node_flags", FT_UINT32, BASE_HEX, 
1210           NULL, 0x0, NULL, HFILL }},
1211         { &hf_ctdb_node_ip, { 
1212           "Node IP", "ctdb.node_ip", FT_IPv4, BASE_NONE, 
1213           NULL, 0x0, NULL, HFILL }},
1214         { &hf_ctdb_pid, { 
1215           "PID", "ctdb.pid", FT_UINT32, BASE_DEC, 
1216           NULL, 0x0, NULL, HFILL }},
1217         { &hf_ctdb_process_exists, { 
1218           "Process Exists", "ctdb.process_exists", FT_BOOLEAN, 32, 
1219           TFS(&process_exists_tfs), 0x01, NULL, HFILL }},
1220         };
1221
1222         /* Setup protocol subtree array */
1223         static gint *ett[] = {
1224                 &ett_ctdb,
1225                 &ett_ctdb_key,
1226         };
1227
1228         /* Register the protocol name and description */
1229         proto_ctdb = proto_register_protocol("Cluster TDB", "CTDB", "ctdb");
1230
1231         /* Required function calls to register the header fields and subtrees used */
1232         proto_register_field_array(proto_ctdb, hf, array_length(hf));
1233         proto_register_subtree_array(ett, array_length(ett));
1234 }
1235
1236
1237 void
1238 proto_reg_handoff_ctdb(void)
1239 {
1240         dissector_handle_t ctdb_handle;
1241
1242         ctdb_handle = new_create_dissector_handle(dissect_ctdb, proto_ctdb);
1243         dissector_add_handle("tcp.port", ctdb_handle);
1244
1245         heur_dissector_add("tcp", dissect_ctdb, proto_ctdb);
1246
1247         ctdb_transactions=se_tree_create(EMEM_TREE_TYPE_RED_BLACK, "CTDB transactions tree");
1248         ctdb_controls=se_tree_create(EMEM_TREE_TYPE_RED_BLACK, "CTDB controls tree");
1249 }