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