For proto_tree_add_item(..., proto_xxx, ...)use ENC_NA as the encoding arg.
[obnox/wireshark/wip.git] / epan / dissectors / packet-pvfs2.c
1 /* packet-pvfs.c
2  * Routines for pvfs2 packet dissection
3  * By Mike Frisch <mfrisch@platform.com>
4  * Joint and Several Copyright 2005, Mike Frisch and Platform Computing Inc.
5  *
6  * $Id$
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * Copied from packet-smb.c and others
13  *
14  * TODO
15  *
16  *    - Add filename snooping (match file handles with file names),
17  *      similar to how packet-rpc.c/packet-nfs.c implements it
18  *
19  * This program is free software; you can redistribute it and/or
20  * modify it under the terms of the GNU General Public License
21  * as published by the Free Software Foundation; either version 2
22  * of the License, or (at your option) any later version.
23  *
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27  * GNU General Public License for more details.
28  *
29  * You should have received a copy of the GNU General Public License
30  * along with this program; if not, write to the Free Software
31  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
32  */
33
34 #ifdef HAVE_CONFIG_H
35 # include "config.h"
36 #endif
37
38 #include <stdlib.h>
39 #include <string.h>
40 #include <ctype.h>
41
42 #include <glib.h>
43
44 #include <epan/packet.h>
45 #include <epan/prefs.h>
46 #include <epan/emem.h>
47 #include <epan/strutil.h>
48 #include "packet-tcp.h"
49
50 #define TCP_PORT_PVFS2 3334
51
52 #define PVFS2_FH_LENGTH 8
53
54 /* Header incl. magic number, mode, tag, size */
55 #define BMI_HEADER_SIZE 24
56
57 /* desegmentation of PVFS over TCP */
58 static gboolean pvfs_desegment = TRUE;
59
60 /* Forward declaration we need below */
61 void proto_reg_handoff_pvfs(void);
62
63 /* Initialize the protocol and registered fields */
64 static int proto_pvfs = -1;
65 static int hf_pvfs_magic_nr = -1;
66 static int hf_pvfs_mode = -1;
67 static int hf_pvfs_tag = -1;
68 static int hf_pvfs_size = -1;
69 static int hf_pvfs_release_number = -1;
70 static int hf_pvfs_encoding = -1;
71 static int hf_pvfs_server_op = -1;
72 static int hf_pvfs_handle = -1;
73 static int hf_pvfs_fs_id = -1;
74 static int hf_pvfs_attrmask = -1;
75 static int hf_pvfs_attr = -1;
76 static int hf_pvfs_ds_type = -1;
77 static int hf_pvfs_error = -1;
78 static int hf_pvfs_atime = -1;
79 static int hf_pvfs_atime_sec = -1;
80 static int hf_pvfs_atime_nsec = -1;
81 static int hf_pvfs_mtime = -1;
82 static int hf_pvfs_mtime_sec = -1;
83 static int hf_pvfs_mtime_nsec = -1;
84 static int hf_pvfs_ctime = -1;
85 static int hf_pvfs_ctime_sec = -1;
86 static int hf_pvfs_ctime_nsec = -1;
87 static int hf_pvfs_parent_atime = -1;
88 static int hf_pvfs_parent_atime_sec = -1;
89 static int hf_pvfs_parent_atime_nsec = -1;
90 static int hf_pvfs_parent_mtime = -1;
91 static int hf_pvfs_parent_mtime_sec = -1;
92 static int hf_pvfs_parent_mtime_nsec = -1;
93 static int hf_pvfs_parent_ctime = -1;
94 static int hf_pvfs_parent_ctime_sec = -1;
95 static int hf_pvfs_parent_ctime_nsec = -1;
96 static int hf_pvfs_dirent_count = -1;
97 static int hf_pvfs_directory_version = -1;
98 static int hf_pvfs_path = -1;
99 static int hf_pvfs_total_completed = -1;
100 static int hf_pvfs_io_dist = -1;
101 static int hf_pvfs_aggregate_size = -1;
102 static int hf_pvfs_io_type = -1;
103 static int hf_pvfs_flowproto_type = -1;
104 static int hf_pvfs_server_param = -1;
105 static int hf_pvfs_prev_value = -1;
106 static int hf_pvfs_ram_free_bytes = -1;
107 static int hf_pvfs_bytes_available = -1;
108 static int hf_pvfs_bytes_total = -1;
109 static int hf_pvfs_ram_bytes_total = -1;
110 static int hf_pvfs_ram_bytes_free = -1;
111 static int hf_pvfs_load_average_1s = -1;
112 static int hf_pvfs_load_average_5s = -1;
113 static int hf_pvfs_load_average_15s = -1;
114 static int hf_pvfs_uptime_seconds = -1;
115 static int hf_pvfs_handles_available = -1;
116 static int hf_pvfs_handles_total = -1;
117 static int hf_pvfs_unused = -1;
118 static int hf_pvfs_context_id = -1;
119 static int hf_pvfs_offset = -1;
120 static int hf_pvfs_stride = -1;
121 static int hf_pvfs_lb = -1;
122 static int hf_pvfs_ub = -1;
123 static int hf_pvfs_end_time_ms = -1;
124 static int hf_pvfs_cur_time_ms = -1;
125 static int hf_pvfs_start_time_ms = -1;
126 static int hf_pvfs_bytes_written = -1;
127 static int hf_pvfs_bytes_read = -1;
128 static int hf_pvfs_metadata_write = -1;
129 static int hf_pvfs_metadata_read = -1;
130 static int hf_pvfs_b_size = -1;
131 static int hf_pvfs_k_size = -1;
132 static int hf_pvfs_id_gen_t = -1;
133 static int hf_pvfs_attribute_key = -1;
134 static int hf_pvfs_attribute_value = -1;
135 static int hf_pvfs_strip_size = -1;
136 static int hf_pvfs_ereg = -1;
137 static int hf_pvfs_sreg = -1;
138 static int hf_pvfs_num_eregs = -1;
139 static int hf_pvfs_num_blocks = -1;
140 static int hf_pvfs_num_contig_chunks = -1;
141 static int hf_pvfs_server_nr = -1;
142 static int hf_pvfs_server_count = -1;
143 static int hf_pvfs_fh_length = -1;
144 static int hf_pvfs_fh_hash = -1;
145
146 /* Initialize the subtree pointers */
147 static gint ett_pvfs = -1;
148 static gint ett_pvfs_hdr = -1;
149 static gint ett_pvfs_credentials = -1;
150 static gint ett_pvfs_server_config = -1;
151 static gint ett_pvfs_server_config_branch = -1;
152 static gint ett_pvfs_attrmask = -1;
153 static gint ett_pvfs_time = -1;
154 static gint ett_pvfs_extent_array_tree = -1;
155 static gint ett_pvfs_extent_item = -1;
156 static gint ett_pvfs_string = -1;
157 static gint ett_pvfs_attr_tree = -1;
158 static gint ett_pvfs_distribution = -1;
159 static gint ett_pvfs_mgmt_perf_stat = -1;
160 static gint ett_pvfs_mgmt_dspace_info = -1;
161 static gint ett_pvfs_attr = -1;
162 static gint ett_pvfs_fh = -1;
163
164 #define BMI_MAGIC_NR 51903
165
166 static const value_string names_pvfs_mode[] =
167 {
168 #define TCP_MODE_IMMED 1
169         { TCP_MODE_IMMED, "TCP_MODE_IMMED" },
170 #define TCP_MODE_UNEXP 2
171         { TCP_MODE_UNEXP, "TCP_MODE_UNEXP" },
172 #define TCP_MODE_EAGER 4
173         { TCP_MODE_EAGER, "TCP_MODE_EAGER" },
174 #define TCP_MODE_REND 8
175         { TCP_MODE_REND,  "TCP_MODE_REND" },
176         { 0, NULL }
177 };
178
179 static const value_string names_pvfs_encoding[] =
180 {
181 #define PVFS_ENCODING_DIRECT 1
182         { PVFS_ENCODING_DIRECT, "ENCODING_DIRECT" },
183 #define PVFS_ENCODING_LE_BFIELD 2
184         { PVFS_ENCODING_LE_BFIELD, "ENCODING_LE_BFIELD" },
185 #define PVFS_ENCODING_XDR 3
186         { PVFS_ENCODING_XDR, "ENCODING_XDR" },
187         { 0, NULL }
188 };
189
190 static const value_string names_pvfs_io_type[] =
191 {
192 #define PVFS_IO_READ 1
193         { PVFS_IO_READ, "PVFS_IO_READ" },
194 #define PVFS_IO_WRITE 2
195         { PVFS_IO_WRITE, "PVFS_IO_WRITE" },
196         { 0, NULL }
197 };
198
199 static const value_string names_pvfs_flowproto_type[] =
200 {
201 #define FLOWPROTO_DUMP_OFFSETS 1
202         { FLOWPROTO_DUMP_OFFSETS, "FLOWPROTO_DUMP_OFFSETS" },
203 #define FLOWPROTO_BMI_CACHE 2
204         { FLOWPROTO_BMI_CACHE, "FLOWPROTO_BMI_CACHE" },
205 #define FLOWPROTO_MULTIQUEUE 3
206         { FLOWPROTO_MULTIQUEUE, "FLOWPROTO_MULTIQUEUE" },
207         { 0, NULL }
208 };
209
210 static const value_string names_pvfs_server_param[] =
211 {
212 #define PVFS_SERV_PARAM_INVALID 0
213         { PVFS_SERV_PARAM_INVALID, "PVFS_SERV_PARAM_INVALID" },
214 #define PVFS_SERV_PARAM_GOSSIP_MASK 1
215         { PVFS_SERV_PARAM_GOSSIP_MASK, "PVFS_SERV_PARAM_GOSSIP_MASK" },
216 #define PVFS_SERV_PARAM_FSID_CHECK 2
217         { PVFS_SERV_PARAM_FSID_CHECK, "PVFS_SERV_PARAM_FSID_CHECK" },
218 #define PVFS_SERV_PARAM_ROOT_CHECK 3
219         { PVFS_SERV_PARAM_ROOT_CHECK, "PVFS_SERV_PARAM_ROOT_CHECK" },
220 #define PVFS_SERV_PARAM_MODE 4
221         { PVFS_SERV_PARAM_MODE, "PVFS_SERV_PARAM_MODE" },
222 #define PVFS_SERV_PARAM_EVENT_ON 5
223         { PVFS_SERV_PARAM_EVENT_ON, "PVFS_SERV_PARAM_EVENT_ON" },
224 #define PVFS_SERV_PARAM_EVENT_MASKS 6
225         { PVFS_SERV_PARAM_EVENT_MASKS, "PVFS_SERV_PARAM_EVENT_MASKS" },
226         { 0, NULL }
227 };
228
229 static const value_string names_pvfs_server_mode[] =
230 {
231 #define PVFS_SERVER_NORMAL_MODE 1
232         { PVFS_SERVER_NORMAL_MODE, "PVFS_SERVER_NORMAL_MODE" },
233 #define PVFS_SERVER_ADMIN_MODE 2
234         { PVFS_SERVER_ADMIN_MODE, "PVFS_SERVER_ADMIN_MODE" },
235         { 0, NULL }
236 };
237
238 /* Forward declaration */
239 static gboolean
240 dissect_pvfs_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
241                 gboolean dissect_other_as_continuation);
242
243
244 static void dissect_pvfs_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
245 {
246         dissect_pvfs_common(tvb, pinfo, tree, FALSE);
247
248 }
249
250 static guint get_pvfs_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
251 {
252   guint32 plen;
253
254   /*
255    * Get the length of the PVFS-over-TCP packet. Ignore top 32 bits
256    */
257   plen = tvb_get_letohl(tvb, offset + 16);
258
259   return plen+24;
260 }
261
262 static int
263 dissect_pvfs_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
264 {
265         guint32 magic_nr, mode;
266         guint64 size;
267
268         /* verify that this is indeed PVFS and that it looks sane */
269         if(tvb_length(tvb)<24){
270                 /* too few bytes remaining to verify the header */
271                 return 0;
272         }
273
274         /* validate the magic number */
275         magic_nr = tvb_get_letohl(tvb, 0);
276         if(magic_nr!=BMI_MAGIC_NR){
277                 return 0;
278         }
279
280         /* Validate the TCP message mode (32-bit) */
281         mode = tvb_get_letohl(tvb, 4);
282         switch(mode){
283         case TCP_MODE_IMMED:
284         case TCP_MODE_UNEXP:
285         case TCP_MODE_EAGER:
286         case TCP_MODE_REND:
287                 break;
288         default:
289                 /* invalid mode, not a PVFS packet */
290                 return 0;
291         }
292
293         /* validate the size : assume size must be >0 and less than 1000000 */
294         size=tvb_get_letohl(tvb, 20);
295         size<<=32;
296         size|=tvb_get_letohl(tvb, 16);
297         if((size>1000000)||(size==0)){
298                 return 0;
299         }
300
301         tcp_dissect_pdus(tvb, pinfo, tree, pvfs_desegment, 24, get_pvfs_pdu_len,
302                 dissect_pvfs_pdu);
303
304         return tvb_length(tvb);
305 }
306
307 static const value_string names_pvfs_server_op[] =
308 {
309 #define PVFS_SERV_INVALID 0
310         { PVFS_SERV_INVALID, "PVFS_SERV_INVALID" },
311 #define PVFS_SERV_CREATE 1
312         { PVFS_SERV_CREATE, "PVFS_SERV_CREATE" },
313 #define PVFS_SERV_REMOVE 2
314         { PVFS_SERV_REMOVE, "PVFS_SERV_REMOVE" },
315 #define PVFS_SERV_IO 3
316         { PVFS_SERV_IO, "PVFS_SERV_IO" },
317 #define PVFS_SERV_GETATTR 4
318         { PVFS_SERV_GETATTR, "PVFS_SERV_GETATTR" },
319 #define PVFS_SERV_SETATTR 5
320         { PVFS_SERV_SETATTR, "PVFS_SERV_SETATTR" },
321 #define PVFS_SERV_LOOKUP_PATH 6
322         { PVFS_SERV_LOOKUP_PATH, "PVFS_SERV_LOOKUP_PATH" },
323 #define PVFS_SERV_CRDIRENT 7
324         { PVFS_SERV_CRDIRENT, "PVFS_SERV_CRDIRENT" },
325 #define PVFS_SERV_RMDIRENT 8
326         { PVFS_SERV_RMDIRENT, "PVFS_SERV_RMDIRENT" },
327 #define PVFS_SERV_CHDIRENT 9
328         { PVFS_SERV_CHDIRENT, "PVFS_SERV_CHDIRENT" },
329 #define PVFS_SERV_TRUNCATE 10
330         { PVFS_SERV_TRUNCATE, "PVFS_SERV_TRUNCATE" },
331 #define PVFS_SERV_MKDIR 11
332         { PVFS_SERV_MKDIR, "PVFS_SERV_MKDIR" },
333 #define PVFS_SERV_READDIR 12
334         { PVFS_SERV_READDIR, "PVFS_SERV_READDIR" },
335 #define PVFS_SERV_GETCONFIG 13
336         { PVFS_SERV_GETCONFIG, "PVFS_SERV_GETCONFIG" },
337 #define PVFS_SERV_WRITE_COMPLETION 14
338         { PVFS_SERV_WRITE_COMPLETION, "PVFS_SERV_WRITE_COMPLETION" },
339 #define PVFS_SERV_FLUSH 15
340         { PVFS_SERV_FLUSH, "PVFS_SERV_FLUSH" },
341 #define PVFS_SERV_MGMT_SETPARAM 16
342         { PVFS_SERV_MGMT_SETPARAM, "PVFS_SERV_MGMT_SETPARAM" },
343 #define PVFS_SERV_MGMT_NOOP 17
344         { PVFS_SERV_MGMT_NOOP, "PVFS_SERV_MGMT_NOOP" },
345 #define PVFS_SERV_STATFS 18
346         { PVFS_SERV_STATFS, "PVFS_SERV_STATFS" },
347 #define PVFS_SERV_PERF_UPDATE 19  /* not a real protocol request */
348         { PVFS_SERV_PERF_UPDATE, "PVFS_SERV_PERF_UPDATE" },
349 #define PVFS_SERV_MGMT_PERF_MON 20
350         { PVFS_SERV_MGMT_PERF_MON, "PVFS_SERV_MGMT_PERF_MON" },
351 #define PVFS_SERV_MGMT_ITERATE_HANDLES 21
352         { PVFS_SERV_MGMT_ITERATE_HANDLES, "PVFS_SERV_MGMT_ITERATE_HANDLES" },
353 #define PVFS_SERV_MGMT_DSPACE_INFO_LIST 22
354         { PVFS_SERV_MGMT_DSPACE_INFO_LIST, "PVFS_SERV_MGMT_DSPACE_INFO_LIST" },
355 #define PVFS_SERV_MGMT_EVENT_MON 23
356         { PVFS_SERV_MGMT_EVENT_MON, "PVFS_SERV_MGMT_EVENT_MON" },
357 #define PVFS_SERV_MGMT_REMOVE_OBJECT 24
358         { PVFS_SERV_MGMT_REMOVE_OBJECT, "PVFS_SERV_MGMT_REMOVE_OBJECT" },
359 #define PVFS_SERV_MGMT_REMOVE_DIRENT 25
360         { PVFS_SERV_MGMT_REMOVE_DIRENT, "PVFS_SERV_MGMT_REMOVE_DIRENT" },
361 #define PVFS_SERV_MGMT_GET_DIRDATA_HANDLE 26
362         { PVFS_SERV_MGMT_GET_DIRDATA_HANDLE, "PVFS_SERV_MGMT_GET_DIRDATA_HANDLE" },
363 #define PVFS_SERV_JOB_TIMER 27    /* not a real protocol request */
364         { PVFS_SERV_JOB_TIMER, "PVFS_SERV_JOB_TIMER" },
365 #define PVFS_SERV_PROTO_ERROR 28
366         { PVFS_SERV_PROTO_ERROR, "PVFS_SERV_PROTO_ERROR" },
367 #define PVFS_SERV_GETEATTR 29
368         { PVFS_SERV_GETEATTR, "PVFS_SERV_GETEATTR" },
369 #define PVFS_SERV_SETEATTR 30
370         { PVFS_SERV_SETEATTR, "PVFS_SERV_SETEATTR" },
371 #define PVFS_SERV_DELEATTR 31
372         { PVFS_SERV_DELEATTR, "PVFS_SERV_DELEATTR" },
373         { 0, NULL }
374 };
375
376 /* special bits used to differentiate PVFS error codes from system
377  *  * errno values
378  *   */
379 #define PVFS_ERROR_BIT           (1 << 30)
380
381 /* a shorthand to make the error code definitions more readable */
382 #define E(num) (num|PVFS_ERROR_BIT)
383
384 static const value_string names_pvfs_error[] = {
385         { 0, "Success" },
386 #define PVFS_EPERM            E(1) /* Operation not permitted */
387         { PVFS_EPERM, "PVFS_EPERM" },
388 #define PVFS_ENOENT           E(2) /* No such file or directory */
389         { PVFS_ENOENT, "PVFS_ENOENT" },
390 #define PVFS_EINTR            E(3) /* Interrupted system call */
391         { PVFS_EINTR, "PVFS_EINTR" },
392 #define PVFS_EIO              E(4) /* I/O error */
393         { PVFS_EIO, "PVFS_EIO" },
394 #define PVFS_ENXIO            E(5) /* No such device or address */
395         { PVFS_ENXIO, "PVFS_ENXIO" },
396 #define PVFS_EBADF            E(6) /* Bad file number */
397         { PVFS_EBADF, "PVFS_EBADF" },
398 #define PVFS_EAGAIN           E(7) /* Try again */
399         { PVFS_EAGAIN, "PVFS_EAGAIN" },
400 #define PVFS_ENOMEM           E(8) /* Out of memory */
401         { PVFS_ENOMEM, "PVFS_ENOMEM" },
402 #define PVFS_EFAULT           E(9) /* Bad address */
403         { PVFS_EFAULT, "PVFS_EFAULT" },
404 #define PVFS_EBUSY           E(10) /* Device or resource busy */
405         { PVFS_EBUSY, "PVFS_EBUSY" },
406 #define PVFS_EEXIST          E(11) /* File exists */
407         { PVFS_EEXIST, "PVFS_EEXIST" },
408 #define PVFS_ENODEV          E(12) /* No such device */
409         { PVFS_ENODEV, "PVFS_ENODEV" },
410 #define PVFS_ENOTDIR         E(13) /* Not a directory */
411         { PVFS_ENOTDIR, "PVFS_ENOTDIR" },
412 #define PVFS_EISDIR          E(14) /* Is a directory */
413         { PVFS_EISDIR, "PVFS_EISDIR" },
414 #define PVFS_EINVAL          E(15) /* Invalid argument */
415         { PVFS_EINVAL, "PVFS_EINVAL" },
416 #define PVFS_EMFILE          E(16) /* Too many open files */
417         { PVFS_EMFILE, "PVFS_EMFILE" },
418 #define PVFS_EFBIG           E(17) /* File too large */
419         { PVFS_EFBIG, "PVFS_EFBIG" },
420 #define PVFS_ENOSPC          E(18) /* No space left on device */
421         { PVFS_ENOSPC, "PVFS_ENOSPC" },
422 #define PVFS_EROFS           E(19) /* Read-only file system */
423         { PVFS_EROFS, "PVFS_EROFS" },
424 #define PVFS_EMLINK          E(20) /* Too many links */
425         { PVFS_EMLINK, "PVFS_EMLINK" },
426 #define PVFS_EPIPE           E(21) /* Broken pipe */
427         { PVFS_EPIPE, "PVFS_EPIPE" },
428 #define PVFS_EDEADLK         E(22) /* Resource deadlock would occur */
429         { PVFS_EDEADLK, "PVFS_EDEADLK" },
430 #define PVFS_ENAMETOOLONG    E(23) /* File name too long */
431         { PVFS_ENAMETOOLONG, "PVFS_ENAMETOOLONG" },
432 #define PVFS_ENOLCK          E(24) /* No record locks available */
433         { PVFS_ENOLCK, "PVFS_ENOLCK" },
434 #define PVFS_ENOSYS          E(25) /* Function not implemented */
435         { PVFS_ENOSYS, "PVFS_ENOSYS" },
436 #define PVFS_ENOTEMPTY       E(26) /* Directory not empty */
437         { PVFS_ENOTEMPTY, "PVFS_ENOTEMPTY" },
438 #define PVFS_ELOOP           E(27) /* Too many symbolic links encountered */
439         { PVFS_ELOOP, "PVFS_ELOOP" },
440 #define PVFS_EWOULDBLOCK     E(28) /* Operation would block */
441         { PVFS_EWOULDBLOCK, "PVFS_EWOULDBLOCK" },
442 #define PVFS_ENOMSG          E(29) /* No message of desired type */
443         { PVFS_ENOMSG, "PVFS_ENOMSG" },
444 #define PVFS_EUNATCH         E(30) /* Protocol driver not attached */
445         { PVFS_EUNATCH, "PVFS_EUNATCH" },
446 #define PVFS_EBADR           E(31) /* Invalid request descriptor */
447         { PVFS_EBADR, "PVFS_EBADR" },
448 #define PVFS_EDEADLOCK       E(32)
449         { PVFS_EDEADLOCK, "PVFS_EDEADLOCK" },
450 #define PVFS_ENODATA         E(33) /* No data available */
451         { PVFS_ENODATA, "PVFS_ENODATA" },
452 #define PVFS_ETIME           E(34) /* Timer expired */
453         { PVFS_ETIME, "PVFS_ETIME" },
454 #define PVFS_ENONET          E(35) /* Machine is not on the network */
455         { PVFS_ENONET, "PVFS_ENONET" },
456 #define PVFS_EREMOTE         E(36) /* Object is remote */
457         { PVFS_EREMOTE, "PVFS_EREMOTE" },
458 #define PVFS_ECOMM           E(37) /* Communication error on send */
459         { PVFS_ECOMM, "PVFS_ECOMM" },
460 #define PVFS_EPROTO          E(38) /* Protocol error */
461         { PVFS_EPROTO, "PVFS_EPROTO" },
462 #define PVFS_EBADMSG         E(39) /* Not a data message */
463         { PVFS_EBADMSG, "PVFS_EBADMSG" },
464 #define PVFS_EOVERFLOW       E(40) /* Value too large for defined data type */
465         { PVFS_EOVERFLOW, "PVFS_EOVERFLOW" },
466 #define PVFS_ERESTART        E(41) /* Interrupted system call should be restarted */
467         { PVFS_ERESTART, "PVFS_ERESTART" },
468 #define PVFS_EMSGSIZE        E(42) /* Message too long */
469         { PVFS_EMSGSIZE, "PVFS_EMSGSIZE" },
470 #define PVFS_EPROTOTYPE      E(43) /* Protocol wrong type for socket */
471         { PVFS_EPROTOTYPE, "PVFS_EPROTOTYPE" },
472 #define PVFS_ENOPROTOOPT     E(44) /* Protocol not available */
473         { PVFS_ENOPROTOOPT, "PVFS_ENOPROTOOPT" },
474 #define PVFS_EPROTONOSUPPORT E(45) /* Protocol not supported */
475         { PVFS_EPROTONOSUPPORT, "PVFS_EPROTONOSUPPORT" },
476 #define PVFS_EOPNOTSUPP      E(46) /* Operation not supported on transport endpoint */
477         { PVFS_EOPNOTSUPP, "PVFS_EOPNOTSUPP" },
478 #define PVFS_EADDRINUSE      E(47) /* Address already in use */
479         { PVFS_EADDRINUSE, "PVFS_EADDRINUSE" },
480 #define PVFS_EADDRNOTAVAIL   E(48) /* Cannot assign requested address */
481         { PVFS_EADDRNOTAVAIL, "PVFS_EADDRNOTAVAIL" },
482 #define PVFS_ENETDOWN        E(49) /* Network is down */
483         { PVFS_ENETDOWN, "PVFS_ENETDOWN" },
484 #define PVFS_ENETUNREACH     E(50) /* Network is unreachable */
485         { PVFS_ENETUNREACH, "PVFS_ENETUNREACH" },
486 #define PVFS_ENETRESET       E(51) /* Network dropped connection because of reset */
487         { PVFS_ENETRESET, "PVFS_ENETRESET" },
488 #define PVFS_ENOBUFS         E(52) /* No buffer space available */
489         { PVFS_ENOBUFS, "PVFS_ENOBUFS" },
490 #define PVFS_ETIMEDOUT       E(53) /* Connection timed out */
491         { PVFS_ETIMEDOUT, "PVFS_ETIMEDOUT" },
492 #define PVFS_ECONNREFUSED    E(54) /* Connection refused */
493         { PVFS_ECONNREFUSED, "PVFS_ECONNREFUSED" },
494 #define PVFS_EHOSTDOWN       E(55) /* Host is down */
495         { PVFS_EHOSTDOWN, "PVFS_EHOSTDOWN" },
496 #define PVFS_EHOSTUNREACH    E(56) /* No route to host */
497         { PVFS_EHOSTUNREACH, "PVFS_EHOSTUNREACH" },
498 #define PVFS_EALREADY        E(57) /* Operation already in progress */
499         { PVFS_EALREADY, "PVFS_EALREADY" },
500 #define PVFS_EACCES          E(58) /* Operation already in progress */
501         { PVFS_EACCES, "PVFS_EACCES" },
502         { 0, NULL }
503 };
504
505 static int
506 dissect_pvfs2_error(tvbuff_t *tvb, proto_tree *tree, int offset,
507                 packet_info *pinfo)
508 {
509         gint32 err;
510         const char *errmsg = NULL;
511
512         err = tvb_get_letohl(tvb, offset);
513         proto_tree_add_uint(tree, hf_pvfs_error, tvb, offset, 4, -err);
514         offset += 4;
515
516         if ((err != 0) && check_col(pinfo->cinfo, COL_INFO))
517         {
518                 errmsg = val_to_str(-err, names_pvfs_error, "Unknown error: %u");
519                 col_append_fstr(pinfo->cinfo, COL_INFO, " Error: %s", errmsg);
520         }
521
522         return offset;
523 }
524
525 static int
526 dissect_pvfs_credentials(tvbuff_t *tvb, proto_tree *parent_tree,
527                 int offset)
528 {
529         proto_item *item = NULL;
530         proto_tree *hcred_tree = NULL;
531         guint32 uid = 0, gid = 0;
532
533         uid = tvb_get_letohl(tvb, offset);
534         gid = tvb_get_letohl(tvb, offset + 4);
535
536         if (parent_tree)
537         {
538                 item = proto_tree_add_text(parent_tree, tvb, offset, 8,
539                                 "Credentials (UID: %d, GID: %d)", uid, gid);
540
541                 if (item)
542                         hcred_tree = proto_item_add_subtree(item, ett_pvfs_credentials);
543         }
544
545         /* UID */
546         proto_tree_add_text(hcred_tree, tvb, offset, 4, "UID: %d", uid);
547         offset += 4;
548
549         /* GID */
550         proto_tree_add_text(hcred_tree, tvb, offset, 4, "GID: %d", gid);
551         offset += 4;
552
553         return offset;
554 }
555
556 static const value_string names_pvfs_attr[] =
557 {
558 #define PVFS_ATTR_COMMON_UID   (1 << 0)
559 #define PVFS_ATTR_BIT_COMMON_UID 0
560         { PVFS_ATTR_BIT_COMMON_UID, "PVFS_ATTR_COMMON_UID" },
561
562 #define PVFS_ATTR_COMMON_GID   (1 << 1)
563 #define PVFS_ATTR_BIT_COMMON_GID 1
564         { PVFS_ATTR_BIT_COMMON_GID, "PVFS_ATTR_COMMON_GID" },
565
566 #define PVFS_ATTR_COMMON_PERM  (1 << 2)
567 #define PVFS_ATTR_BIT_COMMON_PERM 2
568         { PVFS_ATTR_BIT_COMMON_PERM, "PVFS_ATTR_COMMON_PERM" },
569
570 #define PVFS_ATTR_COMMON_ATIME (1 << 3)
571 #define PVFS_ATTR_BIT_COMMON_ATIME 3
572         { PVFS_ATTR_BIT_COMMON_ATIME, "PVFS_ATTR_COMMON_ATIME" },
573
574 #define PVFS_ATTR_COMMON_CTIME (1 << 4)
575 #define PVFS_ATTR_BIT_COMMON_CTIME 4
576         { PVFS_ATTR_BIT_COMMON_CTIME, "PVFS_ATTR_COMMON_CTIME" },
577
578 #define PVFS_ATTR_COMMON_MTIME (1 << 5)
579 #define PVFS_ATTR_BIT_COMMON_MTIME 5
580         { PVFS_ATTR_BIT_COMMON_MTIME, "PVFS_ATTR_COMMON_MTIME" },
581
582 #define PVFS_ATTR_COMMON_TYPE  (1 << 6)
583 #define PVFS_ATTR_BIT_COMMON_TYPE 6
584         { PVFS_ATTR_BIT_COMMON_TYPE, "PVFS_ATTR_COMMON_TYPE" },
585
586 #if 0
587 #define PVFS_ATTR_COMMON_ALL                       \
588         (PVFS_ATTR_COMMON_UID   | PVFS_ATTR_COMMON_GID   | \
589           PVFS_ATTR_COMMON_PERM  | PVFS_ATTR_COMMON_ATIME | \
590           PVFS_ATTR_COMMON_CTIME | PVFS_ATTR_COMMON_MTIME | \
591           PVFS_ATTR_COMMON_TYPE)
592 #endif
593
594 /* internal attribute masks for metadata objects */
595 #define PVFS_ATTR_META_DIST    (1 << 10)
596 #define PVFS_ATTR_BIT_META_DIST 10
597         { PVFS_ATTR_BIT_META_DIST, "PVFS_ATTR_META_DIST" },
598
599 #define PVFS_ATTR_META_DFILES  (1 << 11)
600 #define PVFS_ATTR_BIT_META_DFILES 11
601         { PVFS_ATTR_BIT_META_DFILES, "PVFS_ATTR_META_DFILES" },
602
603 #if 0
604 #define PVFS_ATTR_META_ALL \
605         (PVFS_ATTR_META_DIST | PVFS_ATTR_META_DFILES)
606 #endif
607
608 /* internal attribute masks for datafile objects */
609 #define PVFS_ATTR_DATA_SIZE            (1 << 15)
610 #define PVFS_ATTR_BIT_DATA_SIZE 15
611         { PVFS_ATTR_BIT_DATA_SIZE, "PVFS_ATTR_DATA_SIZE" },
612
613 #if 0
614 #define PVFS_ATTR_DATA_ALL   PVFS_ATTR_DATA_SIZE
615 #endif
616
617 /* internal attribute masks for symlink objects */
618 #define PVFS_ATTR_SYMLNK_TARGET            (1 << 18)
619 #define PVFS_ATTR_BIT_SYMLINK_TARGET 18
620         { PVFS_ATTR_BIT_SYMLINK_TARGET, "PVFS_ATTR_SYMLNK_TARGET" },
621
622 #if 0
623 #define PVFS_ATTR_SYMLNK_ALL PVFS_ATTR_SYMLNK_TARGET
624 #endif
625
626 /* internal attribute masks for directory objects */
627 #define PVFS_ATTR_DIR_DIRENT_COUNT         (1 << 19)
628 #define PVFS_ATTR_BIT_DIR_DIRENT_COUNT 19
629         { PVFS_ATTR_BIT_DIR_DIRENT_COUNT, "PVFS_ATTR_DIR_DIRENT_COUNT" },
630
631 #if 0
632 #define PVFS_ATTR_DIR_ALL PVFS_ATTR_DIR_DIRENT_COUNT
633 #endif
634
635 /* attribute masks used by system interface callers */
636 #define PVFS_ATTR_SYS_SIZE                  (1 << 20)
637 #define PVFS_ATTR_BIT_SYS_SIZE 20
638         { PVFS_ATTR_BIT_SYS_SIZE, "PVFS_ATTR_SYS_SIZE" },
639
640 #define PVFS_ATTR_SYS_LNK_TARGET            (1 << 24)
641 #define PVFS_ATTR_BIT_SYS_LNK_TARGET 24
642         { PVFS_ATTR_BIT_SYS_LNK_TARGET, "PVFS_ATTR_SYS_LNK_TARGET" },
643
644 #define PVFS_ATTR_SYS_DFILE_COUNT           (1 << 25)
645 #define PVFS_ATTR_BIT_SYS_DFILE_COUNT 25
646         { PVFS_ATTR_BIT_SYS_DFILE_COUNT, "PVFS_ATTR_SYS_DFILE_COUNT" },
647
648 #define PVFS_ATTR_SYS_DIRENT_COUNT          (1 << 26)
649 #define PVFS_ATTR_BIT_SYS_DIRENT_COUNT 26
650         { PVFS_ATTR_BIT_SYS_DIRENT_COUNT, "PVFS_ATTR_SYS_DIRENT_COUNT" },
651
652 #if 0
653 #define PVFS_ATTR_SYS_UID        PVFS_ATTR_COMMON_UID
654 #define PVFS_ATTR_SYS_GID        PVFS_ATTR_COMMON_GID
655 #define PVFS_ATTR_SYS_PERM       PVFS_ATTR_COMMON_PERM
656 #define PVFS_ATTR_SYS_ATIME      PVFS_ATTR_COMMON_ATIME
657 #define PVFS_ATTR_SYS_CTIME      PVFS_ATTR_COMMON_CTIME
658 #define PVFS_ATTR_SYS_MTIME      PVFS_ATTR_COMMON_MTIME
659 #define PVFS_ATTR_SYS_TYPE       PVFS_ATTR_COMMON_TYPE
660 #endif
661         { 0, NULL }
662 };
663
664 #if 0
665 #define PVFS_ATTR_SYS_ALL                    \
666         (PVFS_ATTR_COMMON_ALL | PVFS_ATTR_SYS_SIZE | \
667           PVFS_ATTR_SYS_LNK_TARGET | PVFS_ATTR_SYS_DFILE_COUNT | \
668           PVFS_ATTR_SYS_DIRENT_COUNT)
669
670 #define PVFS_ATTR_SYS_ALL_NOSIZE                   \
671         (PVFS_ATTR_COMMON_ALL | PVFS_ATTR_SYS_LNK_TARGET | \
672           PVFS_ATTR_SYS_DFILE_COUNT | PVFS_ATTR_SYS_DIRENT_COUNT)
673
674 #define PVFS_ATTR_SYS_ALL_SETABLE \
675         (PVFS_ATTR_COMMON_ALL-PVFS_ATTR_COMMON_TYPE)
676 #endif
677
678
679 static int
680 dissect_pvfs2_attrmask(tvbuff_t *tvb, proto_tree *tree, int offset,
681                 guint32 *pattrmask)
682 {
683         guint32 attrmask = 0, i = 0;
684         proto_item *attritem = NULL;
685         proto_tree *attrtree = NULL;
686
687         attrmask = tvb_get_letohl(tvb, offset);
688
689         attritem = proto_tree_add_text(tree, tvb, offset, 4,
690                         "Attribute Mask: %d", attrmask);
691
692         if (attritem)
693                 attrtree = proto_item_add_subtree(attritem, ett_pvfs_attrmask);
694
695         for (i = 0; i < 32; i++)
696         {
697                 if (attrmask & (1 << i))
698                         proto_tree_add_uint(attrtree, hf_pvfs_attr, tvb, offset, 4, i);
699         }
700
701         offset += 4;
702
703         if (pattrmask)
704                 *pattrmask = attrmask;
705
706         return offset;
707 }
708
709 static const value_string names_pvfs_ds_type[] = {
710 #define PVFS_TYPE_NONE 0
711         { PVFS_TYPE_NONE, "PVFS_TYPE_NONE" },
712 #define PVFS_TYPE_METAFILE (1 << 0)
713         { PVFS_TYPE_METAFILE, "PVFS_TYPE_METAFILE" },
714 #define PVFS_TYPE_DATAFILE (1 << 1)
715         { PVFS_TYPE_DATAFILE, "PVFS_TYPE_DATAFILE" },
716 #define PVFS_TYPE_DIRECTORY (1 << 2)
717         { PVFS_TYPE_DIRECTORY, "PVFS_TYPE_DIRECTORY" },
718 #define PVFS_TYPE_SYMLINK (1 << 3)
719         { PVFS_TYPE_SYMLINK, "PVFS_TYPE_SYMLINK" },
720 #define PVFS_TYPE_DIRDATA (1 << 4)
721         { PVFS_TYPE_DIRDATA, "PVFS_TYPE_DIRDATA" },
722         { 0, NULL }
723 };
724
725 static int
726 dissect_pvfs2_ds_type(tvbuff_t *tvb, proto_tree *tree, int offset,
727                 int *pds_type)
728 {
729         guint32 ds_type = 0;
730
731         ds_type = tvb_get_letohl(tvb, offset);
732
733         if (tree)
734                 proto_tree_add_uint(tree, hf_pvfs_ds_type, tvb, offset, 4, ds_type);
735
736         offset += 4;
737
738         if (pds_type)
739                 *pds_type = ds_type;
740
741         return offset;
742 }
743
744 #define roundup4(x) (((x) + 3) & ~3)
745 #define roundup8(x) (((x) + 7) & ~7)
746
747 static int
748 dissect_pvfs_opaque_data(tvbuff_t *tvb, int offset,
749     proto_tree *tree,
750     packet_info *pinfo _U_,
751     int hfindex,
752     gboolean fixed_length, guint32 length,
753     gboolean string_data, char const **string_buffer_ret)
754 {
755         int data_offset;
756         proto_item *string_item = NULL;
757         proto_tree *string_tree = NULL;
758
759         guint32 string_length;
760         guint32 string_length_full;
761         guint32 string_length_packet;
762         guint32 string_length_captured;
763         guint32 string_length_copy;
764
765         int fill_truncated;
766         guint32 fill_length;
767         guint32 fill_length_packet;
768         guint32 fill_length_captured;
769         guint32 fill_length_copy;
770
771         int exception = 0;
772
773         char *string_buffer = NULL;
774         const char *string_buffer_print = NULL;
775
776         if (fixed_length) {
777                 string_length = length;
778                 data_offset = offset;
779         } else {
780                 string_length = tvb_get_letohl(tvb,offset+0);
781                 data_offset = offset + 4;
782
783                 /*
784                  * Variable-length strings include NULL terminator on-the-wire but
785                  * NULL terminator is not included in string length.
786                  */
787
788                 if (string_data)
789                         string_length += 1;
790         }
791
792         string_length_captured = tvb_length_remaining(tvb, data_offset);
793         string_length_packet = tvb_reported_length_remaining(tvb, data_offset);
794
795         /*
796          * Strangeness...  the protocol basically says that the length plus
797          * the string must be padded out to an 8-byte boundary.
798          */
799
800         if (!string_data)
801                 string_length_full = roundup4(string_length);
802         else
803                 string_length_full = roundup8(4 + string_length);
804
805         if (string_length_captured < string_length) {
806                 /* truncated string */
807                 string_length_copy = string_length_captured;
808                 fill_truncated = 2;
809                 fill_length = 0;
810                 fill_length_copy = 0;
811
812                 if (string_length_packet < string_length)
813                         exception = ReportedBoundsError;
814                 else
815                         exception = BoundsError;
816         }
817         else {
818                 /* full string data */
819                 string_length_copy = string_length;
820
821                 if (!string_data)
822                         fill_length = string_length_full - string_length;
823                 else
824                         fill_length = string_length_full - string_length - 4;
825
826                 fill_length_captured = tvb_length_remaining(tvb,
827                     data_offset + string_length);
828                 fill_length_packet = tvb_reported_length_remaining(tvb,
829                     data_offset + string_length);
830
831                 if (fill_length_captured < fill_length) {
832                         /* truncated fill bytes */
833                         fill_length_copy = fill_length_packet;
834                         fill_truncated = 1;
835                         if (fill_length_packet < fill_length)
836                                 exception = ReportedBoundsError;
837                         else
838                                 exception = BoundsError;
839                 }
840                 else {
841                         /* full fill bytes */
842                         fill_length_copy = fill_length;
843                         fill_truncated = 0;
844                 }
845         }
846
847         if (string_data) {
848                 char *tmpstr;
849
850                 tmpstr = (char *) tvb_get_ephemeral_string(tvb, data_offset,
851                                 string_length_copy);
852
853                 string_buffer = memcpy(ep_alloc(string_length_copy+1), tmpstr, string_length_copy);
854         } else {
855                 string_buffer = (char *) tvb_memcpy(tvb,
856                                 ep_alloc(string_length_copy+1), data_offset, string_length_copy);
857         }
858
859         string_buffer[string_length_copy] = '\0';
860
861         /* calculate a nice printable string */
862         if (string_length) {
863                 if (string_length != string_length_copy) {
864                         if (string_data) {
865                                 char *formatted;
866                                 guint16 string_buffer_size = 0;
867
868                                 formatted = format_text((guint8 *)string_buffer,
869                                                 (int)strlen(string_buffer));
870
871                                 string_buffer_size = (guint16)strlen(formatted) + 12 + 1;
872
873                                 /* alloc maximum data area */
874                                 string_buffer_print = (char*) ep_alloc(string_buffer_size);
875                                 /* copy over the data */
876                                 g_snprintf((char *)string_buffer_print, string_buffer_size,
877                                                 "%s<TRUNCATED>", formatted);
878                                 /* append <TRUNCATED> */
879                                 /* This way, we get the TRUNCATED even
880                                    in the case of totally wrong packets,
881                                    where \0 are inside the string.
882                                    TRUNCATED will appear at the
883                                    first \0 or at the end (where we
884                                    put the securing \0).
885                                 */
886                         } else {
887                                 string_buffer_print="<DATA><TRUNCATED>";
888                         }
889                 } else {
890                         if (string_data) {
891                                 string_buffer_print =
892                                     ep_strdup(format_text((guint8 *) string_buffer,
893                                                                  (int)strlen(string_buffer)));
894                         } else {
895                                 string_buffer_print="<DATA>";
896                         }
897                 }
898         } else {
899                 string_buffer_print="<EMPTY>";
900         }
901
902         if (tree) {
903                 string_item = proto_tree_add_text(tree, tvb,offset+0, -1,
904                     "%s: %s", proto_registrar_get_name(hfindex),
905                     string_buffer_print);
906
907                 if (string_item)
908                         string_tree = proto_item_add_subtree(string_item,
909                         ett_pvfs_string);
910         }
911         if (!fixed_length) {
912                 if (string_tree)
913                         proto_tree_add_text(string_tree, tvb,offset+0,4,
914                                 "length: %u (excl. NULL terminator)", string_length - 1);
915                 offset += 4;
916         }
917
918         if (string_tree) {
919                 if (string_data) {
920                         proto_tree_add_string_format(string_tree,
921                             hfindex, tvb, offset, string_length_copy,
922                             string_buffer,
923                             "contents: %s", string_buffer_print);
924                 } else {
925                         proto_tree_add_bytes_format(string_tree,
926                             hfindex, tvb, offset, string_length_copy,
927                             (guint8 *) string_buffer,
928                             "contents: %s", string_buffer_print);
929                 }
930         }
931
932         offset += string_length_copy;
933
934         if (fill_length) {
935                 if (string_tree) {
936                         if (fill_truncated) {
937                                 proto_tree_add_text(string_tree, tvb,
938                                 offset,fill_length_copy,
939                                 "fill bytes: opaque data<TRUNCATED>");
940                         }
941                         else {
942                                 proto_tree_add_text(string_tree, tvb,
943                                 offset,fill_length_copy,
944                                 "fill bytes: opaque data");
945                         }
946                 }
947                 offset += fill_length_copy;
948         }
949
950         if (string_item)
951                 proto_item_set_end(string_item, tvb, offset);
952
953         if (string_buffer_ret != NULL)
954                 *string_buffer_ret = string_buffer_print;
955
956         /*
957          * If the data was truncated, throw the appropriate exception,
958          * so that dissection stops and the frame is properly marked.
959          */
960         if (exception != 0)
961                 THROW(exception);
962
963         return offset;
964 }
965
966 static int
967 dissect_pvfs_string(tvbuff_t *tvb, proto_tree *tree, int hfindex,
968                 int offset, const char **string_buffer_ret)
969 {
970         return dissect_pvfs_opaque_data(tvb, offset, tree, NULL, hfindex,
971                         FALSE, 0, TRUE, string_buffer_ret);
972 }
973
974 static void
975 dissect_fhandle_data_unknown(tvbuff_t *tvb, int offset, proto_tree *tree)
976 {
977         guint sublen;
978         guint bytes_left;
979         gboolean first_line;
980
981         bytes_left = PVFS2_FH_LENGTH;
982         first_line = TRUE;
983         while (bytes_left != 0) {
984                 sublen = 16;
985                 if (sublen > bytes_left)
986                         sublen = bytes_left;
987                 proto_tree_add_text(tree, tvb, offset, sublen,
988                                         "%s%s",
989                                         first_line ? "data: " :
990                                                      "      ",
991                                         tvb_bytes_to_str(tvb,offset,sublen));
992                 bytes_left -= sublen;
993                 offset += sublen;
994                 first_line = FALSE;
995         }
996 }
997
998 static void
999 dissect_fhandle_data(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1000     proto_tree *tree, guint32 *hash)
1001 {
1002         guint32 fhhash;
1003         guint32 i;
1004
1005         /* Not all bytes there. Any attempt to deduce the type would be
1006                 senseless. */
1007         if (!tvb_bytes_exist(tvb, offset, PVFS2_FH_LENGTH))
1008                 goto type_ready;
1009
1010         /* create a semiunique hash value for the filehandle */
1011         for(fhhash=0,i=0;i<(PVFS2_FH_LENGTH-3);i+=4){
1012                 guint32 val;
1013                 val = tvb_get_ntohl(tvb, offset+i);
1014                 fhhash ^= val;
1015                 fhhash += val;
1016         }
1017
1018         proto_tree_add_uint(tree, hf_pvfs_fh_hash, tvb, offset, PVFS2_FH_LENGTH,
1019                         fhhash);
1020
1021         if (hash)
1022                 *hash = fhhash;
1023
1024         /* TODO: add file name snooping code here */
1025
1026 type_ready:
1027         dissect_fhandle_data_unknown(tvb, offset, tree);
1028 }
1029
1030 static int
1031 dissect_pvfs_fh(tvbuff_t *tvb, int offset, packet_info *pinfo,
1032                 proto_tree *tree, const char *name, guint32 *hash)
1033 {
1034         proto_item* fitem = NULL;
1035         proto_tree* ftree = NULL;
1036
1037         if (tree)
1038         {
1039                 fitem = proto_tree_add_text(tree, tvb, offset, PVFS2_FH_LENGTH,
1040                                 "%s", name);
1041
1042                 if (fitem)
1043                         ftree = proto_item_add_subtree(fitem, ett_pvfs_fh);
1044         }
1045
1046         /* TODO: add fh to file name snooping code here */
1047
1048         proto_tree_add_uint(ftree, hf_pvfs_fh_length, tvb, offset, 0,
1049                         PVFS2_FH_LENGTH);
1050
1051         dissect_fhandle_data(tvb, offset, pinfo, ftree, hash);
1052
1053         offset += PVFS2_FH_LENGTH;
1054
1055         return offset;
1056 }
1057
1058 static int
1059 dissect_pvfs_handle_extent(tvbuff_t *tvb, proto_tree *tree, int offset,
1060                 packet_info *pinfo, guint32 nCount)
1061 {
1062         proto_item *extent_item = NULL;
1063         proto_tree *extent_tree = NULL;
1064
1065         if (tree)
1066         {
1067                 extent_item = proto_tree_add_text(tree, tvb, offset, 8,
1068                                 "Item %d", nCount);
1069
1070                 if (extent_item)
1071                         extent_tree = proto_item_add_subtree(extent_item,
1072                                         ett_pvfs_extent_item);
1073         }
1074
1075         /* first handle */
1076         offset = dissect_pvfs_fh(tvb, offset, pinfo, extent_tree, "first handle",
1077                         NULL);
1078
1079         /* last handle */
1080         offset = dissect_pvfs_fh(tvb, offset, pinfo, extent_tree, "last handle",
1081                         NULL);
1082
1083         return offset;
1084 }
1085
1086 static int
1087 dissect_pvfs_handle_extent_array(tvbuff_t *tvb, proto_tree *tree, int offset,
1088                 packet_info *pinfo)
1089 {
1090         guint32 extent_count = 0;
1091         guint32 nCount;
1092         proto_item *extent_array_item = NULL;
1093         proto_tree *extent_array_tree = NULL;
1094
1095         /* extent count */
1096         extent_count = tvb_get_letohl(tvb, offset);
1097
1098         if (tree)
1099                 extent_array_item = proto_tree_add_text(tree, tvb, offset, 4,
1100                                         "Handle Extent Array (count = %d)", extent_count);
1101
1102         offset += 4;
1103
1104         if (extent_count > 0)
1105         {
1106                 if (extent_array_item)
1107                         extent_array_tree = proto_item_add_subtree(extent_array_item,
1108                                         ett_pvfs_extent_array_tree);
1109
1110                 /* Add extent array items */
1111                 for (nCount = 0; nCount < extent_count; nCount++)
1112                         offset = dissect_pvfs_handle_extent(tvb, extent_array_tree, offset,
1113                                         pinfo, nCount);
1114         }
1115
1116         return offset;
1117 }
1118
1119 static int
1120 dissect_pvfs_time(tvbuff_t *tvb, proto_tree *tree, int offset,
1121                 int hf_time, int hf_time_sec, int hf_time_nsec)
1122 {
1123         guint32 seconds;
1124         guint32 nseconds;
1125         nstime_t ts;
1126         proto_item *time_item = NULL;
1127         proto_tree *time_tree = NULL;
1128
1129         ts.secs = seconds = tvb_get_letohl(tvb, offset);
1130         ts.nsecs = nseconds = tvb_get_letohl(tvb, offset + 4);
1131
1132         if (tree)
1133         {
1134                 time_item = proto_tree_add_time(tree, hf_time, tvb, offset, 8, &ts);
1135
1136                 if (time_item)
1137                         time_tree = proto_item_add_subtree(time_item, ett_pvfs_time);
1138         }
1139
1140         if (time_tree)
1141         {
1142                 proto_tree_add_uint(time_tree, hf_time_sec, tvb, offset, 4, seconds);
1143                 proto_tree_add_uint(time_tree, hf_time_nsec, tvb, offset + 4, 4,
1144                                 nseconds);
1145         }
1146
1147         offset += 8;
1148         return offset;
1149 }
1150
1151 static
1152 int dissect_pvfs_uint64(tvbuff_t *tvb, proto_tree *tree, int offset,
1153                 int hfindex, guint64 *pvalue)
1154 {
1155         guint64 val;
1156
1157         val = ((guint64) tvb_get_letohl(tvb, offset + 4)) << 32 |
1158                 tvb_get_letohl(tvb, offset);
1159
1160         proto_tree_add_uint64(tree, hfindex, tvb, offset, 8, val);
1161
1162         if (pvalue)
1163                 *pvalue = val;
1164
1165         return offset + 8;
1166 }
1167
1168 /* Taken from pvfs2-dist-simple-stripe.h */
1169 #define PVFS_DIST_SIMPLE_STRIPE_NAME "simple_stripe"
1170 #define PVFS_DIST_SIMPLE_STRIPE_NAME_SIZE 14
1171
1172 static int
1173 dissect_pvfs_distribution(tvbuff_t *tvb, proto_tree *tree, int offset)
1174 {
1175         proto_item *dist_item = NULL;
1176         proto_tree *dist_tree = NULL;
1177         guint32 distlen = 0;
1178         char *tmpstr = NULL;
1179         guint8 issimplestripe = 0;
1180
1181         /* Get distribution name length */
1182         distlen = tvb_get_letohl(tvb, offset);
1183
1184         /* Get distribution name */
1185         tmpstr = (char *) tvb_get_ephemeral_string(tvb, offset + 4, distlen);
1186
1187         if (tree)
1188         {
1189                 guint32 total_len;
1190
1191                 /* 'distlen' does not include the NULL terminator */
1192                 total_len = roundup8(4 + distlen + 1);
1193
1194                 if (((distlen + 1) == PVFS_DIST_SIMPLE_STRIPE_NAME_SIZE) &&
1195                                 (g_ascii_strncasecmp(tmpstr, PVFS_DIST_SIMPLE_STRIPE_NAME,
1196                                                                  distlen) == 0))
1197                 {
1198                         /* Parameter for 'simple_stripe' is 8 bytes */
1199                         total_len += 8;
1200
1201                         issimplestripe = 1;
1202                 }
1203
1204                 dist_item = proto_tree_add_text(tree, tvb, offset, total_len + 8,
1205                                 "Distribution: %s", tmpstr);
1206
1207                 if (dist_item)
1208                         dist_tree = proto_item_add_subtree(dist_item, ett_pvfs_distribution);
1209         }
1210
1211         /* io_dist */
1212         offset = dissect_pvfs_string(tvb, dist_tree, hf_pvfs_io_dist, offset,
1213                         NULL);
1214
1215         /* TODO: only one distribution type is currently supported */
1216         if (issimplestripe)
1217                 offset = dissect_pvfs_uint64(tvb, dist_tree, offset,
1218                                 hf_pvfs_strip_size, NULL);
1219
1220         offset += 8;
1221
1222         return offset;
1223 }
1224
1225 static int
1226 dissect_pvfs_meta_attr_dfiles(tvbuff_t *tvb, proto_tree *tree, int offset,
1227                 packet_info *pinfo)
1228 {
1229         guint32 dfile_count, i;
1230
1231         /* dfile_count */
1232         dfile_count = tvb_get_letohl(tvb, offset);
1233         proto_tree_add_text(tree, tvb, offset, 4, "dfile_count: %d",
1234                         dfile_count);
1235         offset += 4;
1236
1237         for (i = 0; i < dfile_count; i++)
1238                 offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "handle", NULL);
1239
1240         return offset;
1241 }
1242
1243 static int
1244 dissect_pvfs_object_attr(tvbuff_t *tvb, proto_tree *tree, int offset,
1245                 packet_info *pinfo)
1246 {
1247         gint32 ds_type = 0;
1248         guint32 attrmask = 0;
1249         proto_item *attr_item = NULL;
1250         proto_tree *attr_tree = NULL;
1251
1252         if (tree)
1253         {
1254                 attr_item = proto_tree_add_text(tree, tvb, offset, -1, "Attributes");
1255
1256                 if (attr_item)
1257                         attr_tree = proto_item_add_subtree(attr_item, ett_pvfs_attr_tree);
1258         }
1259
1260         /* UID */
1261         proto_tree_add_text(attr_tree, tvb, offset, 4, "UID: %d",
1262                         tvb_get_letohl(tvb, offset));
1263         offset += 4;
1264
1265         /* GID */
1266         proto_tree_add_text(attr_tree, tvb, offset, 4, "GID: %d",
1267                         tvb_get_letohl(tvb, offset));
1268         offset += 4;
1269
1270         /* Permissions */
1271         proto_tree_add_text(attr_tree, tvb, offset, 4, "Permissions: %o",
1272                         tvb_get_letohl(tvb, offset));
1273         offset += 4;
1274
1275         offset += 4;
1276
1277         /* atime */
1278         offset = dissect_pvfs_time(tvb, attr_tree, offset, hf_pvfs_atime,
1279                         hf_pvfs_atime_sec, hf_pvfs_atime_nsec);
1280
1281         /* mtime */
1282         offset = dissect_pvfs_time(tvb, attr_tree, offset, hf_pvfs_mtime,
1283                         hf_pvfs_mtime_sec, hf_pvfs_mtime_nsec);
1284
1285         /* ctime */
1286         offset = dissect_pvfs_time(tvb, attr_tree, offset, hf_pvfs_ctime,
1287                         hf_pvfs_ctime_sec, hf_pvfs_ctime_nsec);
1288
1289         /* attrmask */
1290         offset = dissect_pvfs2_attrmask(tvb, attr_tree, offset, &attrmask);
1291
1292         /* objtype */
1293         offset = dissect_pvfs2_ds_type(tvb, attr_tree, offset, &ds_type);
1294
1295         if (attrmask & PVFS_ATTR_META_DIST)
1296         {
1297                 offset = dissect_pvfs_distribution(tvb, attr_tree, offset);
1298
1299                 offset = dissect_pvfs_meta_attr_dfiles(tvb, attr_tree, offset, pinfo);
1300         }
1301         else
1302         {
1303                 if (attrmask & PVFS_ATTR_META_DFILES)
1304                 {
1305                         offset = dissect_pvfs_meta_attr_dfiles(tvb, attr_tree, offset, pinfo);
1306                 }
1307                 else
1308                 {
1309                         if (attrmask & PVFS_ATTR_DATA_SIZE)
1310                         {
1311                                 offset = dissect_pvfs_uint64(tvb, attr_tree, offset, hf_pvfs_size,
1312                                                 NULL);
1313                         }
1314                         else
1315                         {
1316                                 if (attrmask & PVFS_ATTR_SYMLNK_TARGET)
1317                                 {
1318                                         /* target_path_len */
1319                                         proto_tree_add_text(attr_tree, tvb, offset, 4,
1320                                                         "target_path_len: %d", tvb_get_letohl(tvb, offset));
1321                                         offset += 4;
1322
1323                                         offset += 4;
1324
1325                                         /* target_path */
1326                                         offset = dissect_pvfs_string(tvb, attr_tree, hf_pvfs_path,
1327                                                         offset, NULL);
1328                                 }
1329                                 else
1330                                 {
1331                                         if (attrmask & PVFS_ATTR_DIR_DIRENT_COUNT)
1332                                         {
1333                                                 offset = dissect_pvfs_uint64(tvb, attr_tree, offset,
1334                                                                 hf_pvfs_size, NULL);
1335                                         }
1336                                 }
1337                         }
1338                 }
1339         }
1340
1341         return offset;
1342 }
1343
1344 static int
1345 dissect_pvfs_io_type(tvbuff_t *tvb, proto_tree *tree, int offset)
1346 {
1347         proto_tree_add_uint(tree, hf_pvfs_io_type, tvb, offset, 4,
1348                         tvb_get_letohl(tvb, offset));
1349         offset += 4;
1350
1351         return offset;
1352 }
1353
1354 static int
1355 dissect_pvfs_flowproto_type(tvbuff_t *tvb, proto_tree *tree, int offset)
1356 {
1357         proto_tree_add_uint(tree, hf_pvfs_flowproto_type, tvb, offset, 4,
1358                         tvb_get_letohl(tvb, offset));
1359         offset += 4;
1360
1361         return offset;
1362 }
1363
1364 static int
1365 dissect_pvfs_server_param(tvbuff_t *tvb, proto_tree *tree, int offset,
1366                 packet_info *pinfo)
1367 {
1368         guint32 server_param = 0;
1369         guint32 lowpart;
1370
1371         /* server_param */
1372         server_param = tvb_get_letohl(tvb, offset);
1373         proto_tree_add_uint(tree, hf_pvfs_server_param, tvb, offset, 4,
1374                         server_param);
1375         offset += 4;
1376
1377         switch (server_param)
1378         {
1379                 case PVFS_SERV_PARAM_MODE:
1380                         lowpart = tvb_get_letohl(tvb, offset);
1381
1382                         proto_tree_add_text(tree, tvb, offset, 8,
1383                                         "Server Mode: %s (%u)",
1384                                         val_to_str(lowpart, names_pvfs_server_mode, "%u"), lowpart);
1385                         break;
1386
1387                 case PVFS_SERV_PARAM_FSID_CHECK:
1388                         lowpart = tvb_get_letohl(tvb, offset);
1389                         proto_tree_add_uint(tree, hf_pvfs_fs_id, tvb, offset, 4, lowpart);
1390                         proto_tree_add_uint(tree, hf_pvfs_unused, tvb, offset + 4, 4,
1391                                         tvb_get_letohl(tvb, offset + 4));
1392                         break;
1393
1394                 case PVFS_SERV_PARAM_ROOT_CHECK:
1395                         offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "handle", NULL);
1396                         break;
1397         }
1398
1399         offset += 8;
1400
1401         return offset;
1402 }
1403
1404 static int
1405 dissect_pvfs_fs_id(tvbuff_t *tvb, proto_tree *tree, int offset)
1406 {
1407         if (tree)
1408                 proto_tree_add_uint(tree, hf_pvfs_fs_id, tvb, offset, 4,
1409                                 tvb_get_letohl(tvb, offset));
1410
1411         offset += 4;
1412
1413         return offset;
1414 }
1415
1416 /*
1417  * =======================================================================
1418  * Request handlers
1419  * =======================================================================
1420  */
1421
1422 static int
1423 dissect_pvfs2_create_request(tvbuff_t *tvb, proto_tree *tree, int offset,
1424                 packet_info *pinfo)
1425 {
1426         /* fs_id */
1427         offset = dissect_pvfs_fs_id(tvb, tree, offset);
1428
1429         /* type */
1430         offset = dissect_pvfs2_ds_type(tvb, tree, offset, NULL);
1431
1432         offset += 4;
1433
1434         offset = dissect_pvfs_handle_extent_array(tvb, tree, offset, pinfo);
1435
1436         return offset;
1437 }
1438
1439 static int
1440 dissect_pvfs2_remove_request(tvbuff_t *tvb, proto_tree *tree, int offset,
1441                 packet_info *pinfo)
1442 {
1443         /* handle */
1444         offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "handle", NULL);
1445
1446         /* fs_id */
1447         offset = dissect_pvfs_fs_id(tvb, tree, offset);
1448
1449         return offset;
1450 }
1451
1452 static int
1453 dissect_pvfs_pint_request(tvbuff_t *tvb, proto_tree *tree, int offset)
1454 {
1455         guint64 val = 0;
1456         gint32 ereg, sreg;
1457
1458         /* offset */
1459         val = ((guint64) tvb_get_letohl(tvb, offset + 4)) << 32 |
1460                 tvb_get_letohl(tvb, offset);
1461         proto_tree_add_uint64(tree, hf_pvfs_offset, tvb, offset, 8, val);
1462         offset += 8;
1463
1464         /* TODO: num_eregs */
1465         proto_tree_add_uint(tree, hf_pvfs_num_eregs, tvb, offset, 4,
1466                         tvb_get_letohl(tvb, offset));
1467         offset += 4;
1468
1469         /* TODO: num_blocks */
1470         proto_tree_add_uint(tree, hf_pvfs_num_blocks, tvb, offset, 4,
1471                         tvb_get_letohl(tvb, offset));
1472         offset += 4;
1473
1474         /* TODO: stride */
1475         val = ((guint64) tvb_get_letohl(tvb, offset + 4)) << 32 |
1476                 tvb_get_letohl(tvb, offset);
1477         proto_tree_add_uint64(tree, hf_pvfs_stride, tvb, offset, 8, val);
1478         offset += 8;
1479
1480         /* TODO: ub */
1481         val = ((guint64) tvb_get_letohl(tvb, offset + 4)) << 32 |
1482                 tvb_get_letohl(tvb, offset);
1483         proto_tree_add_uint64(tree, hf_pvfs_ub, tvb, offset, 8, val);
1484         offset += 8;
1485
1486         /* TODO: lb */
1487         val = ((guint64) tvb_get_letohl(tvb, offset + 4)) << 32 |
1488                 tvb_get_letohl(tvb, offset);
1489         proto_tree_add_uint64(tree, hf_pvfs_lb, tvb, offset, 8, val);
1490         offset += 8;
1491
1492         /* TODO: aggregate size */
1493         val = ((guint64) tvb_get_letohl(tvb, offset + 4)) << 32 |
1494                 tvb_get_letohl(tvb, offset);
1495         proto_tree_add_uint64(tree, hf_pvfs_aggregate_size, tvb, offset, 8, val);
1496         offset += 8;
1497
1498         /* num_contig_chunks */
1499         proto_tree_add_uint(tree, hf_pvfs_num_contig_chunks, tvb, offset, 4,
1500                         tvb_get_letohl(tvb, offset));
1501         offset += 4;
1502
1503         /* depth */
1504         proto_tree_add_text(tree, tvb, offset, 4, "depth: %d",
1505                         tvb_get_letohl(tvb, offset));
1506         offset += 4;
1507
1508         /* num_nested_req */
1509         proto_tree_add_text(tree, tvb, offset, 4, "num_nested_req: %d",
1510                         tvb_get_letohl(tvb, offset));
1511         offset += 4;
1512
1513         /* committed */
1514         proto_tree_add_text(tree, tvb, offset, 4, "committed: %d",
1515                         tvb_get_letohl(tvb, offset));
1516         offset += 4;
1517
1518         /* refcount */
1519         proto_tree_add_text(tree, tvb, offset, 4, "refcount: %d",
1520                         tvb_get_letohl(tvb, offset));
1521         offset += 4;
1522
1523         /* documented */
1524         offset += 4;
1525
1526         /* ereg */
1527         ereg = tvb_get_letohl(tvb, offset);
1528         proto_tree_add_int(tree, hf_pvfs_ereg, tvb, offset, 4, ereg);
1529         offset += 4;
1530
1531         /* sreg */
1532         sreg = tvb_get_letohl(tvb, offset);
1533         proto_tree_add_int(tree, hf_pvfs_sreg, tvb, offset, 4, sreg);
1534         offset += 4;
1535
1536         return offset;
1537 }
1538
1539 static int
1540 dissect_pvfs2_io_request(tvbuff_t *tvb, proto_tree *tree, int offset,
1541                 packet_info *pinfo)
1542 {
1543         guint64 val;
1544
1545         /* handle */
1546         offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "handle", NULL);
1547
1548         /* fs_id */
1549         offset = dissect_pvfs_fs_id(tvb, tree, offset);
1550
1551         /* skip4 as per source code */
1552         offset += 4;
1553
1554         /* io_type */
1555         offset = dissect_pvfs_io_type(tvb, tree, offset);
1556
1557         /* flow_type */
1558         offset = dissect_pvfs_flowproto_type(tvb, tree, offset);
1559
1560         /* server_nr */
1561         proto_tree_add_uint(tree, hf_pvfs_server_nr, tvb, offset, 4,
1562                         tvb_get_letohl(tvb, offset));
1563         offset += 4;
1564
1565         /* server_ct */
1566         proto_tree_add_uint(tree, hf_pvfs_server_count, tvb, offset, 4,
1567                         tvb_get_letohl(tvb, offset));
1568         offset += 4;
1569
1570         /* Distribution */
1571         offset = dissect_pvfs_distribution(tvb, tree, offset);
1572
1573         proto_tree_add_text(tree, tvb, offset, 4, "numreq: %d",
1574                         tvb_get_letohl(tvb, offset));
1575         offset += 4;
1576
1577         /* */
1578         offset += 4;
1579
1580         offset = dissect_pvfs_pint_request(tvb, tree, offset);
1581
1582         /* TODO: remove this!!! */
1583         offset = tvb_length(tvb) - 16;
1584
1585         /* offset */
1586         val = ((guint64) tvb_get_letohl(tvb, offset + 4)) << 32 |
1587                 tvb_get_letohl(tvb, offset);
1588         proto_tree_add_uint64(tree, hf_pvfs_offset, tvb, offset, 8, val);
1589         offset += 8;
1590
1591         /* size */
1592         val = ((guint64) tvb_get_letohl(tvb, offset + 4)) << 32 |
1593                 tvb_get_letohl(tvb, offset);
1594         proto_tree_add_uint64(tree, hf_pvfs_size, tvb, offset, 8, val);
1595         offset += 8;
1596
1597         return offset;
1598 }
1599
1600 static int
1601 dissect_pvfs2_getattr_request(tvbuff_t *tvb, proto_tree *tree, int offset,
1602                 packet_info *pinfo)
1603 {
1604         /* handle */
1605         offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "handle", NULL);
1606
1607         /* fs_id */
1608         offset = dissect_pvfs_fs_id(tvb, tree, offset);
1609
1610         /* attrmask */
1611         offset = dissect_pvfs2_attrmask(tvb, tree, offset, NULL);
1612
1613         return offset;
1614 }
1615
1616 static int
1617 dissect_pvfs2_setattr_request(tvbuff_t *tvb, proto_tree *tree, int offset,
1618                 packet_info *pinfo)
1619 {
1620         /* handle */
1621         offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "handle", NULL);
1622
1623         /* parent_ref: fs_id */
1624         offset = dissect_pvfs_fs_id(tvb, tree, offset);
1625
1626         offset += 4;
1627
1628         offset = dissect_pvfs_object_attr(tvb, tree, offset, pinfo);
1629
1630         return offset;
1631 }
1632
1633 /* As per pvfs2-1.2.0/src/proto/pvfs2-req-proto.h */
1634 static int
1635 dissect_pvfs2_lookup_path_request(tvbuff_t *tvb, proto_tree *tree,
1636                 int offset, packet_info *pinfo)
1637 {
1638         /* Path */
1639         offset = dissect_pvfs_string(tvb, tree, hf_pvfs_path, offset, NULL);
1640
1641         /* fs_id */
1642         offset = dissect_pvfs_fs_id(tvb, tree, offset);
1643
1644         offset += 4;
1645
1646         /* starting_handle */
1647         offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "handle", NULL);
1648
1649         /* attribute mask */
1650         offset = dissect_pvfs2_attrmask(tvb, tree, offset, NULL);
1651
1652         return offset;
1653 }
1654
1655 static int
1656 dissect_pvfs2_crdirent_request(tvbuff_t *tvb, proto_tree *tree, int offset,
1657                 packet_info *pinfo)
1658 {
1659         /* Filename */
1660         offset = dissect_pvfs_string(tvb, tree, hf_pvfs_path, offset, NULL);
1661
1662         offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "file handle", NULL);
1663
1664         /* parent_handle */
1665         offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "parent handle", NULL);
1666
1667         /* fs_id */
1668         offset = dissect_pvfs_fs_id(tvb, tree, offset);
1669
1670         offset += 4;
1671
1672         /* atime */
1673         offset = dissect_pvfs_time(tvb, tree, offset, hf_pvfs_atime,
1674                         hf_pvfs_atime_sec, hf_pvfs_atime_nsec);
1675
1676         /* mtime */
1677         offset = dissect_pvfs_time(tvb, tree, offset, hf_pvfs_mtime,
1678                         hf_pvfs_mtime_sec, hf_pvfs_mtime_nsec);
1679
1680         /* ctime */
1681         offset = dissect_pvfs_time(tvb, tree, offset, hf_pvfs_ctime,
1682                         hf_pvfs_ctime_sec, hf_pvfs_ctime_nsec);
1683
1684         return offset;
1685 }
1686
1687 /* TODO: incomplete */
1688 static int
1689 dissect_pvfs2_rmdirent_request(tvbuff_t *tvb, proto_tree *tree, int offset,
1690                 packet_info *pinfo)
1691 {
1692         /* path */
1693         offset = dissect_pvfs_string(tvb, tree, hf_pvfs_path, offset, NULL);
1694
1695         /* handle */
1696         offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "handle", NULL);
1697
1698         /* fs_id */
1699         offset = dissect_pvfs_fs_id(tvb, tree, offset);
1700
1701         offset += 4;
1702
1703         /* atime */
1704         offset = dissect_pvfs_time(tvb, tree, offset, hf_pvfs_atime,
1705                         hf_pvfs_atime_sec, hf_pvfs_atime_nsec);
1706
1707         /* mtime */
1708         offset = dissect_pvfs_time(tvb, tree, offset, hf_pvfs_mtime,
1709                         hf_pvfs_mtime_sec, hf_pvfs_mtime_nsec);
1710
1711         /* ctime */
1712         offset = dissect_pvfs_time(tvb, tree, offset, hf_pvfs_ctime,
1713                         hf_pvfs_ctime_sec, hf_pvfs_ctime_nsec);
1714
1715         return offset;
1716 }
1717
1718 static int
1719 dissect_pvfs2_chdirent_request(tvbuff_t *tvb, proto_tree *tree, int offset,
1720                 packet_info *pinfo)
1721 {
1722         /* path */
1723         offset = dissect_pvfs_string(tvb, tree, hf_pvfs_path, offset, NULL);
1724
1725         /* New directory entry handle */
1726         offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "new directory handle",
1727                         NULL);
1728
1729         /* Parent handle */
1730         offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "parent handle", NULL);
1731
1732         /* fs_id */
1733         offset = dissect_pvfs_fs_id(tvb, tree, offset);
1734
1735         /* Parent atime */
1736         offset = dissect_pvfs_time(tvb, tree, offset, hf_pvfs_parent_atime,
1737                         hf_pvfs_parent_atime_sec, hf_pvfs_parent_atime_nsec);
1738
1739         /* Parent mtime */
1740         offset = dissect_pvfs_time(tvb, tree, offset, hf_pvfs_parent_mtime,
1741                         hf_pvfs_parent_mtime_sec, hf_pvfs_parent_mtime_nsec);
1742
1743         /* Parent ctime */
1744         offset = dissect_pvfs_time(tvb, tree, offset, hf_pvfs_parent_ctime,
1745                         hf_pvfs_parent_ctime_sec, hf_pvfs_parent_ctime_nsec);
1746
1747         return offset;
1748 }
1749
1750 static int
1751 dissect_pvfs2_truncate_request(tvbuff_t *tvb, proto_tree *tree, int offset,
1752                 packet_info *pinfo)
1753 {
1754         guint64 val;
1755
1756         /* handle */
1757         offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "handle", NULL);
1758
1759         /* fs_id */
1760         offset = dissect_pvfs_fs_id(tvb, tree, offset);
1761
1762         offset += 4;
1763
1764         /* size */
1765         val = ((guint64) tvb_get_letohl(tvb, offset + 4)) << 32 |
1766                 tvb_get_letohl(tvb, offset);
1767         proto_tree_add_uint64(tree, hf_pvfs_size, tvb, offset, 8, val);
1768         offset += 8;
1769
1770         /* TODO: flags */
1771         proto_tree_add_text(tree, tvb, offset, 4, "flags: %u",
1772                         tvb_get_letohl(tvb, offset));
1773         offset += 4;
1774
1775         return offset;
1776 }
1777
1778 static int
1779 dissect_pvfs2_mkdir_request(tvbuff_t *tvb, proto_tree *tree, int offset,
1780                 packet_info *pinfo)
1781 {
1782         guint count, i;
1783
1784         /* fs_id */
1785         offset = dissect_pvfs_fs_id(tvb, tree, offset);
1786
1787         offset += 4;
1788
1789         /* attr */
1790         offset = dissect_pvfs_object_attr(tvb, tree, offset, pinfo);
1791
1792         /* handle_extent_array */
1793         count = tvb_get_letohl(tvb, offset);
1794         offset += 4;
1795
1796         for (i = 0; i < count; i++)
1797                 offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "handle", NULL);
1798
1799         return offset;
1800 }
1801
1802 static int
1803 dissect_pvfs2_readdir_request(tvbuff_t *tvb, proto_tree *tree, int offset,
1804                 packet_info *pinfo)
1805 {
1806         /* object_ref: handle */
1807         offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "handle", NULL);
1808
1809         /* object_ref: fs_id */
1810         offset = dissect_pvfs_fs_id(tvb, tree, offset);
1811
1812         /* ds_position */
1813         proto_tree_add_text(tree, tvb, offset, 4, "ds_position: %d",
1814                         tvb_get_letohl(tvb, offset));
1815         offset += 4;
1816
1817         /* dirent_limit */
1818         proto_tree_add_text(tree, tvb, offset, 4, "dirent_limit: %d",
1819                         tvb_get_letohl(tvb, offset));
1820         offset += 4;
1821
1822         return offset;
1823 }
1824
1825 static int
1826 dissect_pvfs2_flush_request(tvbuff_t *tvb, proto_tree *tree,
1827                 int offset, packet_info *pinfo)
1828 {
1829         /* handle */
1830         offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "handle", NULL);
1831
1832         /* fs_id */
1833         offset = dissect_pvfs_fs_id(tvb, tree, offset);
1834
1835         /* flags */
1836         proto_tree_add_text(tree, tvb, offset, 4, "flags: %d",
1837                         tvb_get_letohl(tvb, offset));
1838         offset += 4;
1839
1840         return offset;
1841 }
1842
1843 static int
1844 dissect_pvfs2_mgmt_setparam_request(tvbuff_t *tvb, proto_tree *tree,
1845                 int offset, packet_info *pinfo)
1846 {
1847         /* fs_id */
1848         offset = dissect_pvfs_fs_id(tvb, tree, offset);
1849
1850         /* server_param */
1851         offset = dissect_pvfs_server_param(tvb, tree, offset, pinfo);
1852
1853         return offset;
1854 }
1855
1856 static int
1857 dissect_pvfs2_statfs_request(tvbuff_t *tvb, proto_tree *tree, int offset,
1858                 packet_info *pinfo _U_)
1859 {
1860         /* fs_id */
1861         offset = dissect_pvfs_fs_id(tvb, tree, offset);
1862
1863         return offset;
1864 }
1865
1866 static int
1867 dissect_pvfs2_mgmt_perf_mon_request(tvbuff_t *tvb _U_, proto_tree *tree _U_,
1868                 int offset, packet_info *pinfo _U_)
1869 {
1870         /* TODO: next_id */
1871         proto_tree_add_text(tree, tvb, offset, 4, "next_id: %d",
1872                         tvb_get_letohl(tvb, offset));
1873         offset += 4;
1874
1875         /* TODO: count */
1876         proto_tree_add_text(tree, tvb, offset, 4, "count: %d",
1877                         tvb_get_letohl(tvb, offset));
1878         offset += 4;
1879
1880         return offset;
1881 }
1882
1883 static int
1884 dissect_pvfs2_mgmt_iterate_handles_request(tvbuff_t *tvb, proto_tree *tree,
1885                 int offset, packet_info *pinfo)
1886 {
1887         /* fs_id */
1888         offset = dissect_pvfs_fs_id(tvb, tree, offset);
1889
1890         /* handle */
1891         offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "handle", NULL);
1892
1893         return offset;
1894 }
1895
1896 static int
1897 dissect_pvfs2_mgmt_dspace_info_list_request(tvbuff_t *tvb,
1898                 proto_tree *tree, int offset, packet_info *pinfo)
1899 {
1900         guint32 handle_count, i;
1901
1902         /* fs_id */
1903         offset = dissect_pvfs_fs_id(tvb, tree, offset);
1904
1905         /* handle count */
1906         handle_count = tvb_get_letohl(tvb, offset);
1907         offset += 4;
1908
1909         for (i = 0; i < handle_count; i++)
1910         {
1911                 /* handle */
1912                 offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "handle", NULL);
1913         }
1914
1915         return offset;
1916 }
1917
1918 static int
1919 dissect_pvfs2_mgmt_event_mon_request(tvbuff_t *tvb, proto_tree *tree,
1920                 int offset, packet_info *pinfo _U_)
1921 {
1922         /* event_count */
1923         proto_tree_add_text(tree, tvb, offset, 4, "Event count: %d",
1924                         tvb_get_letohl(tvb, offset));
1925         offset += 4;
1926
1927         return offset;
1928 }
1929
1930 static int
1931 dissect_pvfs2_mgmt_remove_object_request(tvbuff_t *tvb, proto_tree *tree,
1932                 int offset, packet_info *pinfo)
1933 {
1934         /* Handle */
1935         offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "handle", NULL);
1936
1937         /* fs_id */
1938         offset = dissect_pvfs_fs_id(tvb, tree, offset);
1939
1940         return offset;
1941 }
1942
1943 static int
1944 dissect_pvfs2_mgmt_remove_dirent_request(tvbuff_t *tvb,
1945                 proto_tree *tree, int offset, packet_info *pinfo)
1946 {
1947         /* Handle */
1948         offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "handle", NULL);
1949
1950         /* fs_id */
1951         offset = dissect_pvfs_fs_id(tvb, tree, offset);
1952
1953         /* */
1954         offset += 4;
1955
1956         /* entry */
1957         offset = dissect_pvfs_string(tvb, tree, hf_pvfs_path, offset, NULL);
1958
1959         return offset;
1960 }
1961
1962 static int
1963 dissect_pvfs2_mgmt_get_dirdata_handle_request(tvbuff_t *tvb,
1964                 proto_tree *tree, int offset, packet_info *pinfo)
1965 {
1966         /* Handle */
1967         offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "handle", NULL);
1968
1969         /* fs_id */
1970         offset = dissect_pvfs_fs_id(tvb, tree, offset);
1971
1972         return offset;
1973 }
1974
1975 /* TODO: untested/incomplete */
1976 static int
1977 dissect_pvfs_ds_keyval(tvbuff_t *tvb, proto_tree *tree, int offset)
1978 {
1979         /* attribute key */
1980         offset = dissect_pvfs_string(tvb, tree, hf_pvfs_attribute_key, offset,
1981                         NULL);
1982
1983         /* attribute value */
1984         offset = dissect_pvfs_string(tvb, tree, hf_pvfs_attribute_value, offset,
1985                         NULL);
1986
1987         return offset;
1988 }
1989
1990 /* TODO: incomplete/untested */
1991 static int
1992 dissect_ds_keyval_array(tvbuff_t *tvb, proto_tree *tree, int offset)
1993 {
1994         guint32 nKey, i;
1995
1996         /* number of keys and vals */
1997         nKey = tvb_get_letohl(tvb, offset);
1998         offset += 4;
1999
2000         for (i = 0; i < nKey; i++)
2001                 offset = dissect_pvfs_ds_keyval(tvb, tree, offset);
2002
2003         return offset;
2004 }
2005
2006 /* TODO: incomplete/untested */
2007 static int
2008 dissect_pvfs2_geteattr_request(tvbuff_t *tvb, proto_tree *tree,
2009                 int offset, packet_info *pinfo)
2010 {
2011         /* handle */
2012         offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "handle", NULL);
2013
2014         /* fs_id */
2015         offset = dissect_pvfs_fs_id(tvb, tree, offset);
2016
2017         offset += 4;
2018
2019         offset = dissect_ds_keyval_array(tvb, tree, offset);
2020
2021         return offset;
2022 }
2023
2024 /* TODO: incomplete/untested */
2025 static int
2026 dissect_pvfs2_seteattr_request(tvbuff_t *tvb, proto_tree *tree,
2027                 int offset, packet_info *pinfo)
2028 {
2029         /* handle */
2030         offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "handle", NULL);
2031
2032         /* fs_id */
2033         offset = dissect_pvfs_fs_id(tvb, tree, offset);
2034
2035         offset += 4;
2036
2037         offset = dissect_ds_keyval_array(tvb, tree, offset);
2038
2039         return offset;
2040 }
2041
2042 /* TODO: untested */
2043 static int
2044 dissect_pvfs2_deleattr_request(tvbuff_t *tvb, proto_tree *tree,
2045                 int offset, packet_info *pinfo)
2046 {
2047         /* handle */
2048         offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "handle", NULL);
2049
2050         /* fs_id */
2051         offset = dissect_pvfs_fs_id(tvb, tree, offset);
2052
2053         /* key */
2054         offset = dissect_pvfs_ds_keyval(tvb, tree, offset);
2055
2056         return offset;
2057 }
2058
2059 static int
2060 dissect_pvfs2_release_number(tvbuff_t *tvb, proto_tree *tree, int offset)
2061 {
2062         guint32 release_nr = tvb_get_letohl(tvb, offset);
2063
2064         proto_tree_add_text(tree, tvb, offset, 4,
2065                         "PVFS2 Release Number: %d (%d.%d.%d)",
2066                         release_nr,
2067                         release_nr / 10000,
2068                         (release_nr % 10000) / 100,
2069                         (release_nr % 10000) % 100);
2070         offset += 4;
2071
2072         return offset;
2073 }
2074
2075 static int
2076 dissect_pvfs2_common_header(tvbuff_t *tvb, proto_tree *tree, int offset)
2077 {
2078         /* PVFS release number */
2079         offset = dissect_pvfs2_release_number(tvb, tree, offset);
2080
2081         /* wire encoding type */
2082         proto_tree_add_uint(tree, hf_pvfs_encoding, tvb, offset,
2083                         4, tvb_get_letohl(tvb, offset));
2084         offset += 4;
2085
2086         /* server op */
2087         proto_tree_add_uint(tree, hf_pvfs_server_op, tvb, offset, 4,
2088                 tvb_get_letohl(tvb, offset));
2089         offset += 4;
2090
2091         return offset;
2092 }
2093
2094 static int
2095 dissect_pvfs2_request(tvbuff_t *tvb, proto_tree *tree, int offset,
2096                 packet_info *pinfo, guint32 server_op)
2097 {
2098         /* context_id */
2099         proto_tree_add_uint(tree, hf_pvfs_context_id, tvb, offset,
2100                         4, tvb_get_letohl(tvb, offset));
2101         offset += 4;
2102
2103         /* credentials */
2104         offset = dissect_pvfs_credentials(tvb, tree, offset);
2105
2106         switch (server_op)
2107         {
2108                 case  PVFS_SERV_CREATE:
2109                         offset = dissect_pvfs2_create_request(tvb, tree, offset, pinfo);
2110                         break;
2111
2112                 case  PVFS_SERV_REMOVE:
2113                         offset = dissect_pvfs2_remove_request(tvb, tree, offset, pinfo);
2114                         break;
2115
2116                 case  PVFS_SERV_IO:
2117                         offset = dissect_pvfs2_io_request(tvb, tree, offset, pinfo);
2118                         break;
2119
2120                 case PVFS_SERV_GETATTR:
2121                         offset = dissect_pvfs2_getattr_request(tvb, tree, offset, pinfo);
2122                         break;
2123
2124                 case PVFS_SERV_SETATTR:
2125                         offset = dissect_pvfs2_setattr_request(tvb, tree, offset, pinfo);
2126                         break;
2127
2128                 case PVFS_SERV_LOOKUP_PATH:
2129                         offset = dissect_pvfs2_lookup_path_request(tvb, tree, offset, pinfo);
2130                         break;
2131
2132                 case PVFS_SERV_CRDIRENT:
2133                         offset = dissect_pvfs2_crdirent_request(tvb, tree, offset, pinfo);
2134                         break;
2135
2136                 case PVFS_SERV_RMDIRENT:
2137                         offset = dissect_pvfs2_rmdirent_request(tvb, tree, offset, pinfo);
2138                         break;
2139
2140                 case  PVFS_SERV_CHDIRENT:
2141                         offset = dissect_pvfs2_chdirent_request(tvb, tree, offset, pinfo);
2142                         break;
2143
2144                 case  PVFS_SERV_TRUNCATE:
2145                         offset = dissect_pvfs2_truncate_request(tvb, tree, offset, pinfo);
2146                         break;
2147
2148                 case  PVFS_SERV_MKDIR:
2149                         offset = dissect_pvfs2_mkdir_request(tvb, tree, offset, pinfo);
2150                         break;
2151
2152                 case  PVFS_SERV_READDIR:
2153                         offset = dissect_pvfs2_readdir_request(tvb, tree, offset, pinfo);
2154                         break;
2155
2156 #if 0
2157                 case PVFS_SERV_GETCONFIG:
2158                         /* No parameters in request */
2159                         break;
2160 #endif
2161
2162 #if 0
2163                 case  PVFS_SERV_WRITE_COMPLETION:
2164                         /* No parameters in request */
2165                         break;
2166 #endif
2167
2168                 case  PVFS_SERV_FLUSH:
2169                         offset = dissect_pvfs2_flush_request(tvb, tree, offset, pinfo);
2170                         break;
2171
2172                 case  PVFS_SERV_MGMT_SETPARAM:
2173                         offset = dissect_pvfs2_mgmt_setparam_request(tvb, tree, offset,
2174                                         pinfo);
2175                         break;
2176
2177 #if 0
2178                 case  PVFS_SERV_MGMT_NOOP:
2179                         /* No parameters in request */
2180                         break;
2181 #endif
2182
2183                 case  PVFS_SERV_STATFS:
2184                         offset = dissect_pvfs2_statfs_request(tvb, tree, offset, pinfo);
2185                         break;
2186
2187 #if 0
2188                 case  PVFS_SERV_PERF_UPDATE:
2189                         /* No parameters in request */
2190                         break;
2191 #endif
2192
2193                 case  PVFS_SERV_MGMT_PERF_MON:
2194                         offset = dissect_pvfs2_mgmt_perf_mon_request(tvb, tree, offset,
2195                                         pinfo);
2196                         break;
2197
2198                 case  PVFS_SERV_MGMT_ITERATE_HANDLES:
2199                         offset = dissect_pvfs2_mgmt_iterate_handles_request(tvb, tree,
2200                                         offset, pinfo);
2201                         break;
2202
2203                 case  PVFS_SERV_MGMT_DSPACE_INFO_LIST:
2204                         offset = dissect_pvfs2_mgmt_dspace_info_list_request(tvb, tree,
2205                                         offset, pinfo);
2206                         break;
2207
2208                 case  PVFS_SERV_MGMT_EVENT_MON:
2209                         offset = dissect_pvfs2_mgmt_event_mon_request(tvb, tree, offset,
2210                                         pinfo);
2211                         break;
2212
2213                 case  PVFS_SERV_MGMT_REMOVE_OBJECT:
2214                         offset = dissect_pvfs2_mgmt_remove_object_request(tvb, tree, offset,
2215                                         pinfo);
2216                         break;
2217
2218                 case  PVFS_SERV_MGMT_REMOVE_DIRENT:
2219                         offset = dissect_pvfs2_mgmt_remove_dirent_request(tvb, tree, offset,
2220                                         pinfo);
2221                         break;
2222
2223                 case  PVFS_SERV_MGMT_GET_DIRDATA_HANDLE:
2224                         offset = dissect_pvfs2_mgmt_get_dirdata_handle_request(tvb, tree,
2225                                         offset, pinfo);
2226                         break;
2227
2228 #if 0
2229                 case  PVFS_SERV_JOB_TIMER:
2230                         /* No parameters in request */
2231                         break;
2232 #endif
2233
2234                 case  PVFS_SERV_PROTO_ERROR:
2235                         /* TODO: is this necessary? */
2236                         break;
2237
2238                 case  PVFS_SERV_GETEATTR:
2239                         offset = dissect_pvfs2_geteattr_request(tvb, tree, offset, pinfo);
2240                         break;
2241
2242                 case  PVFS_SERV_SETEATTR:
2243                         offset = dissect_pvfs2_seteattr_request(tvb, tree, offset, pinfo);
2244                         break;
2245
2246                 case  PVFS_SERV_DELEATTR:
2247                         offset = dissect_pvfs2_deleattr_request(tvb, tree, offset, pinfo);
2248                         break;
2249
2250                 default:
2251                         /* TODO: what should we do here? */
2252                         break;
2253         }
2254
2255         return offset;
2256 }
2257
2258 /*
2259  * =======================================================================
2260  * Response handlers
2261  * =======================================================================
2262  */
2263
2264 static int
2265 dissect_pvfs2_create_response(tvbuff_t *tvb, proto_tree *tree, int offset,
2266                 packet_info *pinfo)
2267 {
2268         /* Handle */
2269         return dissect_pvfs_fh(tvb, offset, pinfo, tree, "handle", NULL);
2270 }
2271
2272 static int
2273 dissect_pvfs2_io_response(tvbuff_t *tvb, proto_tree *tree, int offset)
2274 {
2275         return dissect_pvfs_uint64(tvb, tree, offset, hf_pvfs_size, NULL);
2276 }
2277
2278 static int
2279 dissect_pvfs2_getattr_response(tvbuff_t *tvb, proto_tree *tree,
2280                 int offset, packet_info *pinfo)
2281 {
2282         offset = dissect_pvfs_object_attr(tvb, tree, offset, pinfo);
2283
2284         return offset;
2285 }
2286
2287 static int
2288 dissect_pvfs2_lookup_path_response(tvbuff_t *tvb, proto_tree *tree,
2289                 int offset, packet_info *pinfo)
2290 {
2291         guint32 nCount = 0;
2292         guint32 handle_count = 0;
2293         guint32 attr_count = 0;
2294         proto_item *attr_item = NULL;
2295         proto_tree *attr_tree = NULL;
2296
2297         offset += 4;
2298
2299         /* handle_count */
2300         handle_count = tvb_get_letohl(tvb, offset);
2301         proto_tree_add_text(tree, tvb, offset, 4, "Handle Count: %d",
2302                         handle_count);
2303         offset += 4;
2304
2305         /* TODO: add bounds checking */
2306         for (nCount = 0; nCount < handle_count; nCount++)
2307                 offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "handle", NULL);
2308
2309         offset += 4;
2310
2311         /* array of attributes */
2312         attr_count = tvb_get_letohl(tvb, offset);
2313
2314         if (tree)
2315         {
2316                 attr_item = proto_tree_add_text(tree, tvb, offset, 4,
2317                                 "Attribute array (total items: %d)", attr_count);
2318
2319                 if (attr_item)
2320                         attr_tree = proto_item_add_subtree(attr_item, ett_pvfs_attr);
2321         }
2322
2323         offset += 4;
2324
2325         /* Array of attributes */
2326         for (nCount = 0; nCount < attr_count; nCount++)
2327                 offset = dissect_pvfs_object_attr(tvb, attr_tree, offset, pinfo);
2328
2329         return offset;
2330 }
2331
2332 static int
2333 dissect_pvfs2_rmdirent_response(tvbuff_t *tvb, proto_tree *tree, int offset,
2334                 packet_info *pinfo)
2335 {
2336         /* Handle */
2337         offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "handle", NULL);
2338
2339         return offset;
2340 }
2341
2342 static int
2343 dissect_pvfs2_chdirent_response(tvbuff_t *tvb, proto_tree *tree, int offset,
2344                 packet_info *pinfo)
2345 {
2346         /* Handle */
2347         offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "handle", NULL);
2348
2349         return offset;
2350 }
2351
2352 static int
2353 dissect_pvfs2_mkdir_response(tvbuff_t *tvb, proto_tree *tree, int offset,
2354                 packet_info *pinfo)
2355 {
2356         /* Handle */
2357         offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "handle", NULL);
2358
2359         return offset;
2360 }
2361
2362 static int
2363 dissect_pvfs2_readdir_response(tvbuff_t *tvb, proto_tree *tree, int offset,
2364                 packet_info *pinfo)
2365 {
2366         guint64 val;
2367         guint32 dirent_count = 0;
2368         guint32 nCount = 0;
2369
2370         /* ds_position */
2371         proto_tree_add_text(tree, tvb, offset, 4, "ds_position: %d",
2372                         tvb_get_letohl(tvb, offset));
2373         offset += 4;
2374
2375         offset += 4;
2376
2377         /* directory_version */
2378         val = ((guint64) tvb_get_letohl(tvb, offset + 4)) << 32 |
2379                 tvb_get_letohl(tvb, offset);
2380         proto_tree_add_uint64(tree, hf_pvfs_directory_version, tvb, offset, 8,
2381                         val);
2382         offset += 8;
2383
2384         offset += 4;
2385
2386         /* dirent_count */
2387         dirent_count = tvb_get_letohl(tvb, offset);
2388         proto_tree_add_text(tree, tvb, offset, 4, "dirent_count: %d",
2389                         dirent_count);
2390         offset += 4;
2391
2392         for (nCount = 0; nCount < dirent_count; nCount++)
2393         {
2394                 offset = dissect_pvfs_string(tvb, tree, hf_pvfs_path, offset, NULL);
2395                 offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "handle", NULL);
2396         }
2397
2398         return offset;
2399 }
2400
2401 /*
2402  * TODO: this code needs work!  Not finished yet!
2403  */
2404 static int
2405 dissect_pvfs2_getconfig_response(tvbuff_t *tvb, proto_tree *parent_tree,
2406                 int offset)
2407 {
2408         guint32 i;
2409         guint32 total_bytes = 0, total_config_bytes = 0, total_lines = 0;
2410         guint32 bytes_processed = 0;
2411         guint32 length_remaining = 0;
2412         char *ptr = NULL;
2413         proto_item *item = NULL, *config_item = NULL;
2414         proto_tree *tree = NULL, *config_tree = NULL;
2415         /*guint8 truncated = 0;*/
2416
2417         if (parent_tree)
2418         {
2419                 item = proto_tree_add_text(parent_tree, tvb, offset, 12,
2420                                 "Server Config");
2421
2422                 if (item)
2423                         tree = proto_item_add_subtree(item, ett_pvfs_server_config);
2424         }
2425
2426         /* Total number of bytes in server config (incl. entry count) */
2427         total_bytes = tvb_get_letohl(tvb, offset);
2428         proto_tree_add_text(tree, tvb, offset, 4, "Total Bytes: %d",
2429                         total_bytes);
2430         offset += 4;
2431
2432         /* There must be at least 4 bytes of data returned to determine the
2433          * size of the server config data
2434          */
2435         if (total_bytes < 4)
2436         {
2437                 /* Server config not returned, bail out */
2438                 return offset;
2439         }
2440
2441         /* Number of entries in server config */
2442         total_lines = tvb_get_letohl(tvb, offset);
2443         proto_tree_add_text(tree, tvb, offset, 4, "Lines: %d", total_lines);
2444         offset += 4;
2445
2446         /* Number of bytes in server config */
2447         total_config_bytes = tvb_get_letohl(tvb, offset);
2448         proto_tree_add_text(tree, tvb, offset, 4, "Config Bytes: %d",
2449                         total_config_bytes);
2450         offset += 4;
2451
2452         /* Get pointer to server config data */
2453         ptr = (char *) tvb_get_ptr(tvb, offset, total_config_bytes);
2454
2455         /* Check if all data is available */
2456         length_remaining = tvb_length_remaining(tvb, offset);
2457
2458         if (length_remaining < total_config_bytes)
2459         {
2460                 total_config_bytes = length_remaining;
2461
2462                 /*truncated = 1;*/
2463         }
2464
2465         bytes_processed = 0;
2466
2467         for (i = 0; i < total_lines; i++)
2468         {
2469                 guint8 entry[256], *pentry = entry, *tmp_entry = NULL;
2470                 guint32 entry_length = 0, tmp_entry_length = 0;
2471                 guint32 bufsiz = sizeof(entry);
2472
2473                 while ((*ptr != '\n') && (*ptr != '\0') &&
2474                                 (bytes_processed < total_config_bytes) &&
2475                                 (entry_length < bufsiz))
2476                 {
2477                         *pentry++ = *ptr++;
2478
2479                         bytes_processed++;
2480                         entry_length++;
2481                 }
2482
2483                 if ((entry_length == bufsiz) &&
2484                                 ((entry[entry_length - 1] != '\n') &&
2485                                  (entry[entry_length - 1] != '\0')))
2486                 {
2487                         /*
2488                          * Single line of config data doesn't fit into provided buffer,
2489                          * config data is malformed.
2490                          */
2491
2492                         break;
2493                 }
2494
2495                 if (bytes_processed == total_config_bytes)
2496                 {
2497                         /* Oops...  ran out of data before we could complete the entry */
2498                         break;
2499                 }
2500
2501                 *pentry= '\0';
2502
2503                 tmp_entry = entry;
2504                 tmp_entry_length = entry_length;
2505
2506                 /* Remove all whitespace from front of entry */
2507                 while ((tmp_entry_length > 0) && (!isalnum(*tmp_entry)) &&
2508                                 (*tmp_entry != '<'))
2509                 {
2510                         tmp_entry++;
2511                         tmp_entry_length--;
2512                 }
2513
2514                 if (tmp_entry[0] == '<')
2515                 {
2516                         if (tmp_entry[tmp_entry_length - 1] == '>')
2517                         {
2518                                 /* Token */
2519                                 if (tmp_entry[1] != '/')
2520                                 {
2521                                         /* Opening token, create new tree root */
2522                                         config_item = proto_tree_add_text(tree, tvb, offset,
2523                                                         tmp_entry_length, "%s", tmp_entry);
2524
2525                                         if (config_item)
2526                                                 config_tree = proto_item_add_subtree(config_item,
2527                                                                 ett_pvfs_server_config_branch);
2528                                 }
2529                                 else
2530                                 {
2531                                         /* Closing token */
2532                                         config_item = NULL;
2533                                         config_tree = NULL;
2534                                 }
2535                         }
2536                         else
2537                         {
2538                                 /* Malformed token */
2539                                 break;
2540                         }
2541                 }
2542                 else
2543                 {
2544                         /* Insert items into the root config tree if there's no subtree
2545                          * defined.
2546                          */
2547                         if (config_tree == NULL)
2548                                 config_tree = tree;
2549
2550                         if (tmp_entry_length > 0)
2551                         {
2552                                 proto_tree_add_text(config_tree, tvb, offset, tmp_entry_length,
2553                                                 "%s", tmp_entry);
2554                         }
2555                 }
2556
2557                 offset += entry_length + 1;
2558
2559                 ptr++;
2560                 bytes_processed++;
2561         }
2562
2563         if (bytes_processed < total_config_bytes)
2564         {
2565                 /* We ran out of server config data */
2566                 proto_tree_add_text(config_tree, tvb, offset, -1,
2567                                 "<MALFORMED OR TRUNCATED DATA>");
2568         }
2569
2570         return offset;
2571 }
2572
2573 static int
2574 dissect_pvfs2_write_completion_response(tvbuff_t *tvb, proto_tree *tree,
2575                 int offset)
2576 {
2577         /* size */
2578         offset = dissect_pvfs_uint64(tvb, tree, offset, hf_pvfs_total_completed,
2579                         NULL);
2580
2581         return offset;
2582 }
2583
2584 static int
2585 dissect_pvfs2_mgmt_setparam_response(tvbuff_t *tvb, proto_tree *tree,
2586                 int offset)
2587 {
2588         guint64 val;
2589
2590         /* old_value */
2591         val = ((guint64) tvb_get_letohl(tvb, offset + 4)) << 32 |
2592                 tvb_get_letohl(tvb, offset);
2593
2594         proto_tree_add_uint64(tree, hf_pvfs_prev_value, tvb, offset, 8, val);
2595
2596         offset += 8;
2597
2598         return offset;
2599 }
2600
2601 static int
2602 dissect_pvfs2_statfs_response(tvbuff_t *tvb, proto_tree *tree, int offset)
2603 {
2604         offset += 4;
2605
2606         /* fs_id */
2607         offset = dissect_pvfs_fs_id(tvb, tree, offset);
2608
2609         /* bytes_available */
2610         offset = dissect_pvfs_uint64(tvb, tree, offset, hf_pvfs_bytes_available,
2611                         NULL);
2612
2613         /* bytes_total */
2614         offset = dissect_pvfs_uint64(tvb, tree, offset, hf_pvfs_bytes_total,
2615                         NULL);
2616
2617         /* RAM bytes total */
2618         offset = dissect_pvfs_uint64(tvb, tree, offset, hf_pvfs_ram_bytes_total,
2619                         NULL);
2620
2621         /* RAM bytes free */
2622         offset = dissect_pvfs_uint64(tvb, tree, offset, hf_pvfs_ram_bytes_free,
2623                         NULL);
2624
2625         /* load average (1s) */
2626         offset = dissect_pvfs_uint64(tvb, tree, offset, hf_pvfs_load_average_1s,
2627                         NULL);
2628
2629         /* load average (5s) */
2630         offset = dissect_pvfs_uint64(tvb, tree, offset, hf_pvfs_load_average_5s,
2631                         NULL);
2632
2633         /* load average (15s) */
2634         offset = dissect_pvfs_uint64(tvb, tree, offset, hf_pvfs_load_average_15s,
2635                         NULL);
2636
2637         /* uptime (seconds) */
2638         offset = dissect_pvfs_uint64(tvb, tree, offset, hf_pvfs_uptime_seconds,
2639                         NULL);
2640
2641         /* handles_available_count */
2642         offset = dissect_pvfs_uint64(tvb, tree, offset, hf_pvfs_handles_available,
2643                         NULL);
2644
2645         /* handles_total_count */
2646         offset = dissect_pvfs_uint64(tvb, tree, offset, hf_pvfs_handles_total,
2647                         NULL);
2648
2649         return offset;
2650 }
2651
2652 static int
2653 dissect_pvfs_mgmt_perf_stat(tvbuff_t *tvb, proto_tree *tree, int offset,
2654                 int nItem)
2655 {
2656         proto_item *stat_item = NULL;
2657         proto_tree *stat_tree = NULL;
2658
2659         if (tree)
2660         {
2661                 stat_item = proto_tree_add_text(tree, tvb, offset, 48,
2662                                 "Stat Array - Element %d", nItem);
2663
2664                 if (stat_item)
2665                         stat_tree = proto_item_add_subtree(stat_item,
2666                                         ett_pvfs_mgmt_perf_stat);
2667         }
2668
2669         /* TODO: valid_flag */
2670         proto_tree_add_text(stat_tree, tvb, offset, 4, "valid_flag: %d",
2671                         tvb_get_letohl(tvb, offset));
2672         offset += 4;
2673
2674         /* TODO: id */
2675         proto_tree_add_text(stat_tree, tvb, offset, 4, "id: %d",
2676                         tvb_get_letohl(tvb, offset));
2677         offset += 4;
2678
2679         offset = dissect_pvfs_uint64(tvb, stat_tree, offset, hf_pvfs_start_time_ms,
2680                         NULL);
2681         offset = dissect_pvfs_uint64(tvb, stat_tree, offset, hf_pvfs_bytes_written,
2682                         NULL);
2683         offset = dissect_pvfs_uint64(tvb, stat_tree, offset, hf_pvfs_bytes_read,
2684                         NULL);
2685         offset = dissect_pvfs_uint64(tvb, stat_tree, offset, hf_pvfs_metadata_write,
2686                         NULL);
2687         offset = dissect_pvfs_uint64(tvb, stat_tree, offset, hf_pvfs_metadata_read,
2688                         NULL);
2689
2690         return offset;
2691 }
2692
2693 static int
2694 dissect_pvfs2_mgmt_perf_mon_response(tvbuff_t *tvb, proto_tree *tree,
2695                 int offset)
2696 {
2697         guint32 perf_array_count, i;
2698
2699         /* TODO: suggested_next_id */
2700         proto_tree_add_text(tree, tvb, offset, 4, "suggested_next_id: %d",
2701                         tvb_get_letohl(tvb, offset));
2702         offset += 4;
2703
2704         offset += 4;
2705
2706         offset = dissect_pvfs_uint64(tvb, tree, offset, hf_pvfs_end_time_ms,
2707                         NULL);
2708         offset = dissect_pvfs_uint64(tvb, tree, offset, hf_pvfs_cur_time_ms,
2709                         NULL);
2710
2711         offset += 4;
2712
2713         /* TODO: perf_array_count */
2714         perf_array_count = tvb_get_letohl(tvb, offset);
2715         proto_tree_add_text(tree, tvb, offset, 4, "perf_array_count: %d",
2716                         perf_array_count);
2717         offset += 4;
2718
2719         for (i = 0; i < perf_array_count; i++)
2720                 offset = dissect_pvfs_mgmt_perf_stat(tvb, tree, offset, i);
2721
2722         return offset;
2723 }
2724
2725 static int
2726 dissect_pvfs2_mgmt_iterate_handles_response(tvbuff_t *tvb, proto_tree *tree,
2727                 int offset, packet_info *pinfo)
2728 {
2729         guint32 handle_count, i;
2730
2731         /* ds_position */
2732         proto_tree_add_text(tree, tvb, offset, 4, "ds_position: %d",
2733                         tvb_get_letohl(tvb, offset));
2734         offset += 4;
2735
2736         /* handle_count */
2737         handle_count = tvb_get_letohl(tvb, offset);
2738         proto_tree_add_text(tree, tvb, offset, 4, "handle_count: %d",
2739                         handle_count);
2740         offset += 4;
2741
2742         /* TODO: this could be improved */
2743         for (i = 0; i < handle_count; i++)
2744                 offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "handle", NULL);
2745
2746         return offset;
2747 }
2748
2749 static int
2750 dissect_pvfs2_mgmt_dspace_info(tvbuff_t *tvb, proto_tree *tree, int offset,
2751                 packet_info *pinfo)
2752 {
2753         offset = dissect_pvfs2_error(tvb, tree, offset, pinfo);
2754         offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "handle", NULL);
2755         offset = dissect_pvfs2_ds_type(tvb, tree, offset, NULL);
2756         offset = dissect_pvfs_uint64(tvb, tree, offset, hf_pvfs_b_size,
2757                         NULL);
2758         offset = dissect_pvfs_uint64(tvb, tree, offset, hf_pvfs_k_size,
2759                         NULL);
2760         offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "handle", NULL);
2761
2762         return offset;
2763 }
2764
2765 static int
2766 dissect_pvfs2_mgmt_dspace_info_list_response(tvbuff_t *tvb, proto_tree *tree,
2767                 int offset, packet_info *pinfo)
2768 {
2769         guint32 dspace_info_count, i;
2770         proto_item *arr_item = NULL;
2771         proto_tree *arr_tree = NULL;
2772
2773         offset += 4;
2774
2775         /* dspace_info_count */
2776         dspace_info_count = tvb_get_letohl(tvb, offset);
2777         proto_tree_add_text(tree, tvb, offset, 4, "dspace_info_count: %d",
2778                         dspace_info_count);
2779
2780         if ((dspace_info_count > 0) && (tree))
2781         {
2782                 arr_item = proto_tree_add_text(tree, tvb, offset,
2783                                 dspace_info_count * 40, "dspace_info Array (%d items)",
2784                                 dspace_info_count);
2785
2786                 if (arr_item)
2787                         arr_tree = proto_item_add_subtree(arr_item,
2788                                         ett_pvfs_mgmt_dspace_info);
2789         }
2790
2791         for (i = 0; i < dspace_info_count; i++)
2792                 offset = dissect_pvfs2_mgmt_dspace_info(tvb, arr_tree, offset, pinfo);
2793
2794         return offset;
2795 }
2796
2797 static int
2798 dissect_pvfs2_mgmt_event_mon_response(tvbuff_t *tvb, proto_tree *tree,
2799                 int offset)
2800 {
2801         /* api */
2802         proto_tree_add_text(tree, tvb, offset, 4, "api: %d",
2803                         tvb_get_letohl(tvb, offset));
2804         offset += 4;
2805
2806         /* operation */
2807         proto_tree_add_text(tree, tvb, offset, 4, "operation: %d",
2808                         tvb_get_letohl(tvb, offset));
2809         offset += 4;
2810
2811         /* value */
2812         proto_tree_add_text(tree, tvb, offset, 4, "value: %d",
2813                         tvb_get_letohl(tvb, offset));
2814         offset += 4;
2815
2816         /* id */
2817         offset = dissect_pvfs_uint64(tvb, tree, offset, hf_pvfs_id_gen_t,
2818                         NULL);
2819
2820         /* flags */
2821         proto_tree_add_text(tree, tvb, offset, 4, "flags: %d",
2822                         tvb_get_letohl(tvb, offset));
2823         offset += 4;
2824
2825         /* tv_sec */
2826         proto_tree_add_text(tree, tvb, offset, 4, "tv_sec: %d",
2827                         tvb_get_letohl(tvb, offset));
2828         offset += 4;
2829
2830         /* tv_usec */
2831         proto_tree_add_text(tree, tvb, offset, 4, "tv_usec: %d",
2832                         tvb_get_letohl(tvb, offset));
2833         offset += 4;
2834
2835         offset += 4;
2836
2837         return offset;
2838 }
2839
2840 static int
2841 dissect_pvfs2_mgmt_remove_object_response(tvbuff_t *tvb, proto_tree *tree,
2842                 int offset, packet_info *pinfo)
2843 {
2844         /* handle */
2845         offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "handle", NULL);
2846
2847         /* fs_id */
2848         offset = dissect_pvfs_fs_id(tvb, tree, offset);
2849
2850         return offset;
2851 }
2852
2853 static int
2854 dissect_pvfs2_mgmt_get_dirdata_handle_response(tvbuff_t *tvb,
2855                 proto_tree *tree, int offset, packet_info *pinfo)
2856 {
2857         /* handle */
2858         offset = dissect_pvfs_fh(tvb, offset, pinfo, tree, "handle", NULL);
2859
2860         return offset;
2861 }
2862
2863 /* TODO: untested */
2864 static int
2865 dissect_pvfs2_geteattr_response(tvbuff_t *tvb, proto_tree *tree, int offset,
2866                 packet_info *pinfo _U_)
2867 {
2868         offset += 4;
2869
2870         /* Dissect nKey & ds_keyval array */
2871         offset = dissect_ds_keyval_array(tvb, tree, offset);
2872
2873         return offset;
2874 }
2875
2876 static int
2877 dissect_pvfs2_response(tvbuff_t *tvb, proto_tree *tree, int offset,
2878                 packet_info *pinfo, guint32 server_op)
2879 {
2880         /* error code */
2881         offset = dissect_pvfs2_error(tvb, tree, offset, pinfo);
2882
2883         switch (server_op)
2884         {
2885                 case PVFS_SERV_CREATE:
2886                         offset = dissect_pvfs2_create_response(tvb, tree, offset, pinfo);
2887                         break;
2888
2889 #if 0
2890                 case PVFS_SERV_REMOVE:
2891                         /* No result data */
2892                         break;
2893 #endif
2894
2895                 case PVFS_SERV_IO:
2896                         offset = dissect_pvfs2_io_response(tvb, tree, offset);
2897                         break;
2898
2899                 case PVFS_SERV_GETATTR:
2900                         offset = dissect_pvfs2_getattr_response(tvb, tree, offset, pinfo);
2901                         break;
2902
2903                 case PVFS_SERV_SETATTR:
2904                         /* No result data */
2905                         break;
2906
2907                 case PVFS_SERV_LOOKUP_PATH:
2908                         offset = dissect_pvfs2_lookup_path_response(tvb, tree, offset, pinfo);
2909                         break;
2910
2911 #if 0
2912                 case PVFS_SERV_CRDIRENT:
2913                         /* No result data */
2914                         break;
2915 #endif
2916
2917                 case PVFS_SERV_RMDIRENT:
2918                         offset = dissect_pvfs2_rmdirent_response(tvb, tree, offset, pinfo);
2919                         break;
2920
2921                 case PVFS_SERV_CHDIRENT:
2922                         offset = dissect_pvfs2_chdirent_response(tvb, tree, offset, pinfo);
2923                         break;
2924
2925 #if 0
2926                 case PVFS_SERV_TRUNCATE:
2927                         /* No result data */
2928                         break;
2929 #endif
2930
2931                 case PVFS_SERV_MKDIR:
2932                         offset = dissect_pvfs2_mkdir_response(tvb, tree, offset, pinfo);
2933                         break;
2934
2935                 case PVFS_SERV_READDIR:
2936                         offset = dissect_pvfs2_readdir_response(tvb, tree, offset, pinfo);
2937                         break;
2938
2939                 case PVFS_SERV_GETCONFIG:
2940                         offset = dissect_pvfs2_getconfig_response(tvb, tree, offset);
2941                         break;
2942
2943                 case PVFS_SERV_WRITE_COMPLETION:
2944                         offset = dissect_pvfs2_write_completion_response(tvb, tree, offset);
2945                         break;
2946
2947 #if 0
2948                 case PVFS_SERV_FLUSH:
2949                         /* No result data */
2950                         break;
2951 #endif
2952
2953                 case PVFS_SERV_MGMT_SETPARAM:
2954                         offset = dissect_pvfs2_mgmt_setparam_response(tvb, tree, offset);
2955                         break;
2956
2957 #if 0
2958                 case PVFS_SERV_MGMT_NOOP:
2959                         /* No result data */
2960                         break;
2961 #endif
2962
2963                 case PVFS_SERV_STATFS:
2964                         offset = dissect_pvfs2_statfs_response(tvb, tree, offset);
2965                         break;
2966
2967 #if 0
2968                 case PVFS_SERV_PERF_UPDATE:
2969                         /* No result data */
2970                         break;
2971 #endif
2972
2973                 case PVFS_SERV_MGMT_PERF_MON:
2974                         offset = dissect_pvfs2_mgmt_perf_mon_response(tvb, tree, offset);
2975                         break;
2976
2977                 case PVFS_SERV_MGMT_ITERATE_HANDLES:
2978                         offset = dissect_pvfs2_mgmt_iterate_handles_response(tvb, tree,
2979                                         offset, pinfo);
2980                         break;
2981
2982                 case PVFS_SERV_MGMT_DSPACE_INFO_LIST:
2983                         offset = dissect_pvfs2_mgmt_dspace_info_list_response(tvb, tree,
2984                                         offset, pinfo);
2985                         break;
2986
2987                 case PVFS_SERV_MGMT_EVENT_MON:
2988                         offset = dissect_pvfs2_mgmt_event_mon_response(tvb, tree, offset);
2989                         break;
2990
2991                 case PVFS_SERV_MGMT_REMOVE_OBJECT:
2992                         offset = dissect_pvfs2_mgmt_remove_object_response(tvb, tree, offset,
2993                                         pinfo);
2994                         break;
2995
2996 #if 0
2997                 case PVFS_SERV_MGMT_REMOVE_DIRENT:
2998                         /* No result data */
2999                         break;
3000 #endif
3001
3002                 case PVFS_SERV_MGMT_GET_DIRDATA_HANDLE:
3003                         offset = dissect_pvfs2_mgmt_get_dirdata_handle_response(tvb, tree,
3004                                         offset, pinfo);
3005                         break;
3006
3007 #if 0
3008                 case PVFS_SERV_JOB_TIMER:
3009                         /* No result data */
3010                         break;
3011 #endif
3012
3013                 case PVFS_SERV_PROTO_ERROR:
3014                         /* No result data */
3015                         break;
3016
3017                         /* TODO: untested */
3018                 case PVFS_SERV_GETEATTR:
3019                         offset = dissect_pvfs2_geteattr_response(tvb, tree, offset, pinfo);
3020                         break;
3021
3022 #if 0
3023                 case PVFS_SERV_SETEATTR:
3024                         /* No result data */
3025                         break;
3026 #endif
3027
3028 #if 0
3029                 case PVFS_SERV_DELEATTR:
3030                         /* No result data */
3031                         break;
3032 #endif
3033
3034                 default:
3035                         /* TODO: what do we do here? */
3036                         break;
3037         }
3038
3039         return offset;
3040 }
3041
3042 static GHashTable *pvfs2_io_tracking_value_table = NULL;
3043
3044 typedef struct pvfs2_io_tracking_key
3045 {
3046         guint64 tag;
3047 } pvfs2_io_tracking_key_t;
3048
3049 typedef struct pvfs2_io_tracking_value
3050 {
3051         guint32 request_frame_num;
3052         guint32 response_frame_num;
3053         guint32 flow_frame_num;
3054
3055 } pvfs2_io_tracking_value_t;
3056
3057 static gint
3058 pvfs2_io_tracking_equal(gconstpointer k1, gconstpointer k2)
3059 {
3060         const pvfs2_io_tracking_key_t *key1 = (const pvfs2_io_tracking_key_t *) k1;
3061         const pvfs2_io_tracking_key_t *key2 = (const pvfs2_io_tracking_key_t *) k2;
3062
3063         return (key1->tag == key2->tag);
3064 }
3065
3066 static guint
3067 pvfs2_io_tracking_hash(gconstpointer k)
3068 {
3069         const pvfs2_io_tracking_key_t *key = (const pvfs2_io_tracking_key_t *) k;
3070
3071         return (guint) ((key->tag >> 32) ^ ((guint32) key->tag));
3072 }
3073
3074 static void
3075 pvfs2_io_tracking_init(void)
3076 {
3077         if (pvfs2_io_tracking_value_table != NULL)
3078                 g_hash_table_destroy(pvfs2_io_tracking_value_table);
3079
3080         pvfs2_io_tracking_value_table = g_hash_table_new(pvfs2_io_tracking_hash,
3081                         pvfs2_io_tracking_equal);
3082 }
3083
3084 static pvfs2_io_tracking_value_t *
3085 pvfs2_io_tracking_new_with_tag(guint64 tag, guint32 num)
3086 {
3087         pvfs2_io_tracking_value_t *value;
3088         pvfs2_io_tracking_key_t *newkey;
3089
3090         newkey = (pvfs2_io_tracking_key_t *) se_alloc0(sizeof(*newkey));
3091         newkey->tag = tag;
3092
3093         value = se_alloc0(sizeof(*value));
3094
3095         g_hash_table_insert(pvfs2_io_tracking_value_table, newkey, value);
3096
3097         value->request_frame_num = num;
3098
3099         return value;
3100 }
3101
3102 static gboolean
3103 dissect_pvfs_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree,
3104                 gboolean dissect_other_as_continuation _U_)
3105 {
3106         guint32 mode = 0;
3107         proto_item *item = NULL, *hitem = NULL;
3108         proto_tree *pvfs_tree = NULL, *pvfs_htree = NULL;
3109         int offset = 0;
3110         guint64 tag;
3111         guint32 server_op;
3112         pvfs2_io_tracking_value_t *val = NULL;
3113
3114         col_set_str(pinfo->cinfo, COL_PROTOCOL, "PVFS");
3115
3116         col_clear(pinfo->cinfo, COL_INFO);
3117
3118         if (parent_tree)
3119         {
3120                 item = proto_tree_add_item(parent_tree, proto_pvfs, tvb, 0, -1, ENC_NA);
3121
3122                 if (item)
3123                         pvfs_tree = proto_item_add_subtree(item, ett_pvfs);
3124         }
3125
3126         proto_tree_add_text(pvfs_tree, tvb, 0, -1, "Version: 2");
3127
3128         /* PVFS packet header is 24 bytes */
3129         hitem = proto_tree_add_text(pvfs_tree, tvb, 0, BMI_HEADER_SIZE,
3130                         "BMI Header");
3131         if (hitem)
3132                 pvfs_htree = proto_item_add_subtree(hitem, ett_pvfs_hdr);
3133
3134         /* Magic number */
3135         proto_tree_add_item(pvfs_htree, hf_pvfs_magic_nr, tvb, offset, 4, ENC_LITTLE_ENDIAN);
3136         offset += 4;
3137
3138         /* TCP message mode (32-bit) */
3139         mode = tvb_get_letohl(tvb, offset);
3140         proto_tree_add_uint(pvfs_htree, hf_pvfs_mode, tvb, offset, 4, mode);
3141         offset += 4;
3142
3143         /* tag (64-bit) */
3144         offset = dissect_pvfs_uint64(tvb, pvfs_htree, offset, hf_pvfs_tag, &tag);
3145
3146         /* size (64-bit) */
3147         offset = dissect_pvfs_uint64(tvb, pvfs_htree, offset, hf_pvfs_size, NULL);
3148
3149         /* Lookahead to get server_op (invalid if frame contains flow data) */
3150         server_op = tvb_get_letohl(tvb, offset + 8);
3151
3152         if (mode == TCP_MODE_UNEXP)
3153         {
3154                 /* Add entry to tracking table for PVFS_SERV_IO request */
3155                 if ((server_op == PVFS_SERV_IO) && !pinfo->fd->flags.visited)
3156                         val = pvfs2_io_tracking_new_with_tag(tag, pinfo->fd->num);
3157         }
3158         else
3159         {
3160                 pvfs2_io_tracking_key_t key;
3161
3162                 memset(&key, 0, sizeof(key));
3163                 key.tag = tag;
3164
3165                 val = g_hash_table_lookup(pvfs2_io_tracking_value_table, &key);
3166
3167                 /* If this frame contains a known PVFS_SERV_IO tag, track it */
3168                 if (val && !pinfo->fd->flags.visited)
3169                 {
3170                         /* If response HAS NOT been seen, mark this frame as response */
3171                         if (val->response_frame_num == 0)
3172                                 val->response_frame_num = pinfo->fd->num;
3173                         else
3174                         {
3175                                 /* If response HAS been seen, this frame is flow data */
3176                                 if (val->flow_frame_num == 0)
3177                                         val->flow_frame_num = pinfo->fd->num;
3178                         }
3179                 }
3180         }
3181
3182         if (val && (val->flow_frame_num == pinfo->fd->num))
3183         {
3184                 /* This frame is marked as being flow data */
3185                 col_set_str(pinfo->cinfo, COL_INFO, "PVFS flow data");
3186
3187                 proto_tree_add_text(pvfs_tree, tvb, offset, -1, "<data>");
3188
3189                 return TRUE;
3190         }
3191
3192         /* Extract common part of packet found in requests and responses */
3193         offset = dissect_pvfs2_common_header(tvb, pvfs_htree, offset);
3194
3195         /* Update column info display */
3196         if (check_col(pinfo->cinfo, COL_INFO))
3197         {
3198                 col_add_str(pinfo->cinfo, COL_INFO,
3199                                 val_to_str(server_op, names_pvfs_server_op, "%u (unknown)"));
3200
3201                 col_append_str(pinfo->cinfo, COL_INFO,
3202                                 (mode == TCP_MODE_UNEXP)? " (request)": " (response)");
3203         }
3204
3205         /* TODO: handle all modes */
3206         if (mode == TCP_MODE_UNEXP)
3207         {
3208                 /* Request */
3209                 offset = dissect_pvfs2_request(tvb, pvfs_tree, offset, pinfo, server_op);
3210         }
3211         else
3212         {
3213                 /* TODO: re-examine this! */
3214 #if 0
3215                 if (mode == TCP_MODE_REND)
3216                 {
3217                         /*
3218                          * TODO: move this code outside so it's common for requests and
3219                          * responses
3220                          */
3221
3222                         col_set_str(pinfo->cinfo, COL_INFO, "PVFS2 DATA (request)");
3223                 }
3224                 else
3225 #endif
3226                 {
3227                         /* Response */
3228                         offset = dissect_pvfs2_response(tvb, pvfs_tree, offset, pinfo,
3229                                         server_op);
3230                 }
3231         }
3232
3233         return TRUE;
3234 }
3235
3236 /* Register the protocol with Wireshark */
3237 void
3238 proto_register_pvfs(void)
3239 {
3240         static hf_register_info hf[] = {
3241                 { &hf_pvfs_magic_nr,
3242                         { "Magic Number", "pvfs.magic_nr", FT_UINT32, BASE_HEX,
3243                                 NULL, 0, NULL, HFILL }},
3244
3245                 { &hf_pvfs_mode,
3246                         { "Mode", "pvfs.mode", FT_UINT32, BASE_DEC,
3247                                 VALS(names_pvfs_mode), 0, NULL, HFILL }},
3248
3249                 { &hf_pvfs_tag,
3250                         { "Tag", "pvfs.tag", FT_UINT64, BASE_DEC,
3251                                 NULL, 0, NULL, HFILL }},
3252
3253                 { &hf_pvfs_size,
3254                         { "Size", "pvfs.size", FT_UINT64, BASE_DEC,
3255                                 NULL, 0, NULL, HFILL }},
3256
3257                 { &hf_pvfs_release_number,
3258                         { "Release Number", "pvfs.release_number", FT_UINT32, BASE_DEC,
3259                                 NULL, 0, NULL, HFILL }},
3260
3261                 { &hf_pvfs_encoding,
3262                         { "Encoding", "pvfs.encoding", FT_UINT32, BASE_DEC,
3263                                 VALS(names_pvfs_encoding), 0, NULL, HFILL }},
3264
3265                 { &hf_pvfs_server_op,
3266                         { "Server Operation", "pvfs.server_op", FT_UINT32, BASE_DEC,
3267                                 VALS(names_pvfs_server_op), 0, NULL, HFILL }},
3268
3269                 { &hf_pvfs_handle,
3270                         { "Handle", "pvfs.handle", FT_BYTES, BASE_NONE,
3271                                 NULL, 0, NULL, HFILL }},
3272
3273                 { &hf_pvfs_fs_id,
3274                         { "fs_id", "pvfs.fs_id", FT_UINT32, BASE_HEX,
3275                                 NULL, 0, "File System ID", HFILL }},
3276
3277                 { &hf_pvfs_attrmask,
3278                         { "attrmask", "pvfs.attrmask", FT_UINT32, BASE_HEX,
3279                                 NULL, 0, "Attribute Mask", HFILL }},
3280
3281                 { &hf_pvfs_attr,
3282                         { "attr", "pvfs.attribute", FT_UINT32, BASE_HEX,
3283                                 VALS(names_pvfs_attr), 0, "Attribute", HFILL }},
3284
3285                 { &hf_pvfs_ds_type,
3286                         { "ds_type", "pvfs.ds_type", FT_UINT32, BASE_HEX,
3287                                 VALS(names_pvfs_ds_type), 0, "Type", HFILL }},
3288
3289                 { &hf_pvfs_error,
3290                         { "Result", "pvfs.error", FT_UINT32, BASE_HEX,
3291                                 VALS(names_pvfs_error), 0, NULL, HFILL }},
3292
3293                 { &hf_pvfs_atime,
3294                         { "atime", "pvfs.atime", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
3295                                 NULL, 0, "Access Time", HFILL }},
3296
3297                 { &hf_pvfs_atime_sec,
3298                         { "seconds", "pvfs.atime.sec", FT_UINT32, BASE_DEC,
3299                                 NULL, 0, "Access Time (seconds)", HFILL }},
3300
3301                 { &hf_pvfs_atime_nsec,
3302                         { "microseconds", "pvfs.atime.usec", FT_UINT32, BASE_DEC,
3303                                 NULL, 0, "Access Time (microseconds)", HFILL }},
3304
3305                 { &hf_pvfs_mtime,
3306                         { "mtime", "pvfs.mtime", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
3307                                 NULL, 0, "Modify Time", HFILL }},
3308
3309                 { &hf_pvfs_mtime_sec,
3310                         { "seconds", "pvfs.mtime.sec", FT_UINT32, BASE_DEC,
3311                                 NULL, 0, "Modify Time (seconds)", HFILL }},
3312
3313                 { &hf_pvfs_mtime_nsec,
3314                         { "microseconds", "pvfs.mtime.usec", FT_UINT32, BASE_DEC,
3315                                 NULL, 0, "Modify Time (microseconds)", HFILL }},
3316
3317                 { &hf_pvfs_ctime,
3318                         { "ctime", "pvfs.ctime", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
3319                                 NULL, 0, "Creation Time", HFILL }},
3320
3321                 { &hf_pvfs_ctime_sec,
3322                         { "seconds", "pvfs.ctime.sec", FT_UINT32, BASE_DEC,
3323                                 NULL, 0, "Creation Time (seconds)", HFILL }},
3324
3325                 { &hf_pvfs_ctime_nsec,
3326                         { "microseconds", "pvfs.ctime.usec", FT_UINT32, BASE_DEC,
3327                                 NULL, 0, "Creation Time (microseconds)", HFILL }},
3328
3329                 { &hf_pvfs_parent_atime,
3330                         { "Parent atime", "pvfs.parent_atime", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
3331                                 NULL, 0, "Access Time", HFILL }},
3332
3333                 { &hf_pvfs_parent_atime_sec,
3334                         { "seconds", "pvfs.parent_atime.sec", FT_UINT32, BASE_DEC,
3335                                 NULL, 0, "Access Time (seconds)", HFILL }},
3336
3337                 { &hf_pvfs_parent_atime_nsec,
3338                         { "microseconds", "pvfs.parent_atime.usec", FT_UINT32, BASE_DEC,
3339                                 NULL, 0, "Access Time (microseconds)", HFILL }},
3340
3341                 { &hf_pvfs_parent_mtime,
3342                         { "Parent mtime", "pvfs.parent_mtime", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
3343                                 NULL, 0, "Modify Time", HFILL }},
3344
3345                 { &hf_pvfs_parent_mtime_sec,
3346                         { "seconds", "pvfs.parent_mtime.sec", FT_UINT32, BASE_DEC,
3347                                 NULL, 0, "Modify Time (seconds)", HFILL }},
3348
3349                 { &hf_pvfs_parent_mtime_nsec,
3350                         { "microseconds", "pvfs.parent_mtime.usec", FT_UINT32, BASE_DEC,
3351                                 NULL, 0, "Modify Time (microseconds)", HFILL }},
3352
3353                 { &hf_pvfs_parent_ctime,
3354                         { "Parent ctime", "pvfs.parent_ctime", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
3355                                 NULL, 0, "Creation Time", HFILL }},
3356
3357                 { &hf_pvfs_parent_ctime_sec,
3358                         { "seconds", "pvfs.parent_ctime.sec", FT_UINT32, BASE_DEC,
3359                                 NULL, 0, "Creation Time (seconds)", HFILL }},
3360
3361                 { &hf_pvfs_parent_ctime_nsec,
3362                         { "microseconds", "pvfs.parent_ctime.usec", FT_UINT32, BASE_DEC,
3363                                 NULL, 0, "Creation Time (microseconds)", HFILL }},
3364
3365                 { &hf_pvfs_dirent_count,
3366                         { "Dir Entry Count", "pvfs.dirent_count", FT_UINT64, BASE_DEC,
3367                                 NULL, 0, "Directory Entry Count", HFILL }},
3368
3369                 { &hf_pvfs_directory_version,
3370                         { "Directory Version", "pvfs.directory_version", FT_UINT64, BASE_HEX,
3371                                 NULL, 0, NULL, HFILL }},
3372
3373                 { &hf_pvfs_path,
3374                         { "Path", "pvfs.path", FT_STRING, BASE_NONE,
3375                                 NULL, 0, NULL, HFILL }},
3376
3377                 { &hf_pvfs_total_completed,
3378                         { "Bytes Completed", "pvfs.bytes_completed", FT_UINT64, BASE_DEC,
3379                                 NULL, 0, NULL, HFILL }},
3380
3381                 { &hf_pvfs_io_dist,
3382                          { "Name", "pvfs.distribution.name", FT_STRING, BASE_NONE,
3383                                  NULL, 0, "Distribution Name", HFILL }},
3384
3385                 { &hf_pvfs_aggregate_size,
3386                         { "Aggregate Size", "pvfs.aggregate_size", FT_UINT64, BASE_DEC,
3387                                 NULL, 0, NULL, HFILL }},
3388
3389                 { &hf_pvfs_io_type,
3390                         { "I/O Type", "pvfs.io_type", FT_UINT32, BASE_DEC,
3391                                 VALS(names_pvfs_io_type), 0, NULL, HFILL }},
3392
3393                 { &hf_pvfs_flowproto_type,
3394                         { "Flow Protocol Type", "pvfs.flowproto_type", FT_UINT32, BASE_DEC,
3395                                 VALS(names_pvfs_flowproto_type), 0, NULL, HFILL }},
3396
3397                 { &hf_pvfs_server_param,
3398                         { "Server Parameter", "pvfs.server_param", FT_UINT32, BASE_DEC,
3399                                 VALS(names_pvfs_server_param), 0, NULL, HFILL }},
3400
3401                 { &hf_pvfs_prev_value,
3402                         { "Previous Value", "pvfs.prev_value", FT_UINT64, BASE_DEC,
3403                                 NULL, 0, NULL, HFILL }},
3404
3405                 { &hf_pvfs_ram_free_bytes,
3406                         { "RAM Free Bytes", "pvfs.ram.free_bytes", FT_UINT64, BASE_DEC,
3407                                 NULL, 0, NULL, HFILL }},
3408
3409                 { &hf_pvfs_bytes_available,
3410                         { "Bytes Available", "pvfs.bytes_available", FT_UINT64, BASE_DEC,
3411                                 NULL, 0, NULL, HFILL }},
3412
3413                 { &hf_pvfs_bytes_total,
3414                         { "Bytes Total", "pvfs.bytes_total", FT_UINT64, BASE_DEC,
3415                                 NULL, 0, NULL, HFILL }},
3416
3417                 { &hf_pvfs_ram_bytes_total,
3418                         { "RAM Bytes Total", "pvfs.ram_bytes_total", FT_UINT64, BASE_DEC,
3419                                 NULL, 0, NULL, HFILL }},
3420
3421                 { &hf_pvfs_ram_bytes_free,
3422                         { "RAM Bytes Free", "pvfs.ram_bytes_free", FT_UINT64, BASE_DEC,
3423                                 NULL, 0, NULL, HFILL }},
3424
3425                 { &hf_pvfs_load_average_1s,
3426                         { "Load Average (1s)", "pvfs.load_average.1s", FT_UINT64, BASE_DEC,
3427                                 NULL, 0, NULL, HFILL }},
3428
3429                 { &hf_pvfs_load_average_5s,
3430                         { "Load Average (5s)", "pvfs.load_average.5s", FT_UINT64, BASE_DEC,
3431                                 NULL, 0, NULL, HFILL }},
3432
3433                 { &hf_pvfs_load_average_15s,
3434                         { "Load Average (15s)", "pvfs.load_average.15s", FT_UINT64, BASE_DEC,
3435                                 NULL, 0, NULL, HFILL }},
3436
3437                 { &hf_pvfs_uptime_seconds,
3438                         { "Uptime (seconds)", "pvfs.uptime", FT_UINT64, BASE_DEC,
3439                                 NULL, 0, NULL, HFILL }},
3440
3441                 { &hf_pvfs_handles_available,
3442                         { "Handles Available", "pvfs.handles_available", FT_UINT64, BASE_DEC,
3443                                 NULL, 0, NULL, HFILL }},
3444
3445                 { &hf_pvfs_handles_total,
3446                         { "Total Handles", "pvfs.total_handles", FT_UINT64, BASE_DEC,
3447                                 NULL, 0, NULL, HFILL }},
3448
3449                 /*
3450                  * This is used when the field returns 64-bits but we're only interested
3451                  * in the lower 32-bit bits.
3452                  */
3453                 { &hf_pvfs_unused,
3454                         { "Unused", "pvfs.unused", FT_UINT32, BASE_DEC,
3455                                 NULL, 0, NULL, HFILL }},
3456
3457                 { &hf_pvfs_context_id,
3458                         { "Context ID", "pvfs.context_id", FT_UINT32, BASE_DEC,
3459                                 NULL, 0, NULL, HFILL }},
3460
3461                 { &hf_pvfs_offset,
3462                         { "Offset", "pvfs.offset", FT_UINT64, BASE_DEC,
3463                                 NULL, 0, NULL, HFILL }},
3464
3465                 { &hf_pvfs_stride,
3466                         { "Stride", "pvfs.stride", FT_UINT64, BASE_DEC,
3467                                 NULL, 0, NULL, HFILL }},
3468
3469                 { &hf_pvfs_ub,
3470                         { "ub", "pvfs.ub", FT_UINT64, BASE_DEC,
3471                                 NULL, 0, NULL, HFILL }},
3472
3473                 { &hf_pvfs_lb,
3474                         { "lb", "pvfs.lb", FT_UINT64, BASE_DEC,
3475                                 NULL, 0, NULL, HFILL }},
3476
3477                 { &hf_pvfs_end_time_ms,
3478                         { "end_time_ms", "pvfs.end_time_ms", FT_UINT64, BASE_DEC,
3479                                 NULL, 0, NULL, HFILL }},
3480
3481                 { &hf_pvfs_cur_time_ms,
3482                         { "cur_time_ms", "pvfs.cur_time_ms", FT_UINT64, BASE_DEC,
3483                                 NULL, 0, NULL, HFILL }},
3484
3485                 { &hf_pvfs_start_time_ms,
3486                         { "start_time_ms", "pvfs.start_time_ms", FT_UINT64, BASE_DEC,
3487                                 NULL, 0, NULL, HFILL }},
3488
3489                 { &hf_pvfs_bytes_written,
3490                         { "bytes_written", "pvfs.bytes_written", FT_UINT64, BASE_DEC,
3491                                 NULL, 0, NULL, HFILL }},
3492
3493                 { &hf_pvfs_bytes_read,
3494                         { "bytes_read", "pvfs.bytes_read", FT_UINT64, BASE_DEC,
3495                                 NULL, 0, NULL, HFILL }},
3496
3497                 { &hf_pvfs_metadata_write,
3498                         { "metadata_write", "pvfs.metadata_write", FT_UINT64, BASE_DEC,
3499                                 NULL, 0, NULL, HFILL }},
3500
3501                 { &hf_pvfs_metadata_read,
3502                         { "metadata_read", "pvfs.metadata_read", FT_UINT64, BASE_DEC,
3503                                 NULL, 0, NULL, HFILL }},
3504
3505                 { &hf_pvfs_b_size,
3506                         { "Size of bstream (if applicable)", "pvfs.b_size", FT_UINT64,
3507                                 BASE_DEC, NULL, 0, "Size of bstream", HFILL }},
3508
3509                 { &hf_pvfs_k_size,
3510                         { "Number of keyvals (if applicable)", "pvfs.k_size", FT_UINT64,
3511                                 BASE_DEC, NULL, 0, "Number of keyvals", HFILL }},
3512
3513                 { &hf_pvfs_id_gen_t,
3514                         { "id_gen_t", "pvfs.id_gen_t", FT_UINT64, BASE_DEC,
3515                                 NULL, 0, NULL, HFILL }},
3516
3517                 { &hf_pvfs_attribute_key,
3518                         { "Attribute key", "pvfs.attribute.key", FT_STRING, BASE_NONE,
3519                                 NULL, 0, NULL, HFILL }},
3520
3521                 { &hf_pvfs_attribute_value,
3522                         { "Attribute value", "pvfs.attribute.value", FT_STRING, BASE_NONE,
3523                                 NULL, 0, NULL, HFILL }},
3524
3525                 { &hf_pvfs_strip_size,
3526                         { "Strip size", "pvfs.strip_size", FT_UINT64, BASE_DEC,
3527                                 NULL, 0, "Strip size (bytes)", HFILL }},
3528
3529                 /* TODO: need description */
3530                 { &hf_pvfs_ereg,
3531                         { "ereg", "pvfs.ereg", FT_INT32, BASE_DEC,
3532                                 NULL, 0, NULL, HFILL }},
3533
3534                 /* TODO: need description */
3535                 { &hf_pvfs_sreg,
3536                         { "sreg", "pvfs.sreg", FT_INT32, BASE_DEC,
3537                                 NULL, 0, NULL, HFILL }},
3538
3539                 { &hf_pvfs_num_eregs,
3540                         { "Number of eregs", "pvfs.num_eregs", FT_UINT32, BASE_DEC,
3541                                 NULL, 0, NULL, HFILL }},
3542
3543                 { &hf_pvfs_num_blocks,
3544                         { "Number of blocks", "pvfs.num_blocks", FT_UINT32, BASE_DEC,
3545                                 NULL, 0, NULL, HFILL }},
3546
3547                 { &hf_pvfs_num_contig_chunks,
3548                         { "Number of contig_chunks", "pvfs.num_contig_chunks", FT_UINT32,
3549                                 BASE_DEC, NULL, 0, NULL, HFILL }},
3550
3551                 { &hf_pvfs_server_nr,
3552                         { "Server #", "pvfs.server_nr", FT_UINT32, BASE_DEC,
3553                                 NULL, 0, NULL, HFILL }},
3554
3555                 { &hf_pvfs_server_count,
3556                         { "Number of servers", "pvfs.server_count", FT_UINT32, BASE_DEC,
3557                                 NULL, 0, NULL, HFILL }},
3558
3559                 { &hf_pvfs_fh_length,
3560                         { "length", "pvfs.fh.length", FT_UINT32, BASE_DEC,
3561                                 NULL, 0, "file handle length", HFILL }},
3562
3563                 { &hf_pvfs_fh_hash,
3564                         { "hash", "pvfs.fh.hash", FT_UINT32, BASE_HEX,
3565                                 NULL, 0, "file handle hash", HFILL }},
3566         };
3567
3568         /* Setup protocol subtree array */
3569         static gint *ett[] = {
3570                 &ett_pvfs,
3571                 &ett_pvfs_hdr,
3572                 &ett_pvfs_credentials,
3573                 &ett_pvfs_server_config,
3574                 &ett_pvfs_server_config_branch,
3575                 &ett_pvfs_attrmask,
3576                 &ett_pvfs_time,
3577                 &ett_pvfs_extent_array_tree,
3578                 &ett_pvfs_extent_item,
3579                 &ett_pvfs_string,
3580                 &ett_pvfs_attr_tree,
3581                 &ett_pvfs_distribution,
3582                 &ett_pvfs_mgmt_perf_stat,
3583                 &ett_pvfs_mgmt_dspace_info,
3584                 &ett_pvfs_attr,
3585                 &ett_pvfs_fh
3586         };
3587         module_t *pvfs_module;
3588
3589         /* Register the protocol name and description */
3590         proto_pvfs = proto_register_protocol("Parallel Virtual File System",
3591                         "PVFS", "pvfs");
3592
3593         /*
3594          * Required function calls to register the header fields and
3595          * subtrees used
3596          */
3597
3598         proto_register_field_array(proto_pvfs, hf, array_length(hf));
3599         proto_register_subtree_array(ett, array_length(ett));
3600
3601         register_init_routine(pvfs2_io_tracking_init);
3602
3603         pvfs_module = prefs_register_protocol(proto_pvfs, NULL);
3604         prefs_register_bool_preference(pvfs_module, "desegment",
3605             "Reassemble PVFS messages spanning multiple TCP segments",
3606             "Whether the PVFS dissector should reassemble messages spanning multiple TCP segments. "
3607             "To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
3608             &pvfs_desegment);
3609 }
3610
3611 void
3612 proto_reg_handoff_pvfs(void)
3613 {
3614         dissector_handle_t pvfs_handle;
3615
3616         pvfs_handle = new_create_dissector_handle(dissect_pvfs_heur, proto_pvfs);
3617         dissector_add_uint("tcp.port", TCP_PORT_PVFS2, pvfs_handle);
3618
3619         heur_dissector_add("tcp", dissect_pvfs_heur, proto_pvfs);
3620 }
3621