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