Allow a length of -1 to be specified when adding FT_NONE and FT_PROTOCOL
[obnox/wireshark/wip.git] / packet-mount.c
1 /* packet-mount.c
2  * Routines for mount dissection
3  *
4  * $Id: packet-mount.c,v 1.29 2002/01/20 22:12:26 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
8  * Copyright 1998 Gerald Combs
9  *
10  * Copied from packet-smb.c
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31
32 #ifdef HAVE_SYS_TYPES_H
33 #include <sys/types.h>
34 #endif
35
36 #include <string.h>
37
38 #include "packet-rpc.h"
39 #include "packet-mount.h"
40 #include "packet-nfs.h"
41
42
43 static int proto_mount = -1;
44 static int hf_mount_path = -1;
45 static int hf_mount3_status = -1;
46 static int hf_mount_mountlist_hostname = -1;
47 static int hf_mount_mountlist_directory = -1;
48 static int hf_mount_mountlist = -1;
49 static int hf_mount_groups_group = -1;
50 static int hf_mount_groups = -1;
51 static int hf_mount_exportlist_directory = -1;
52 static int hf_mount_exportlist = -1;
53 static int hf_mount_pathconf_link_max = -1;
54 static int hf_mount_pathconf_max_canon = -1;
55 static int hf_mount_pathconf_max_input = -1;
56 static int hf_mount_pathconf_name_max = -1;
57 static int hf_mount_pathconf_path_max = -1;
58 static int hf_mount_pathconf_pipe_buf = -1;
59 static int hf_mount_pathconf_vdisable = -1;
60 static int hf_mount_pathconf_mask = -1;
61 static int hf_mount_pathconf_error_all = -1;
62 static int hf_mount_pathconf_error_link_max = -1;
63 static int hf_mount_pathconf_error_max_canon = -1;
64 static int hf_mount_pathconf_error_max_input = -1;
65 static int hf_mount_pathconf_error_name_max = -1;
66 static int hf_mount_pathconf_error_path_max = -1;
67 static int hf_mount_pathconf_error_pipe_buf = -1;
68 static int hf_mount_pathconf_chown_restricted = -1;
69 static int hf_mount_pathconf_no_trunc = -1;
70 static int hf_mount_pathconf_error_vdisable = -1;
71 static int hf_mount_flavors = -1;
72 static int hf_mount_flavor = -1;
73
74 static gint ett_mount = -1;
75 static gint ett_mount_mountlist = -1;
76 static gint ett_mount_groups = -1;
77 static gint ett_mount_exportlist = -1;
78 static gint ett_mount_pathconf_mask = -1;
79
80 #define MAX_GROUP_NAME_LIST 128
81 static char group_name_list[MAX_GROUP_NAME_LIST];
82 static int  group_names_len;
83
84 /* RFC 1094, Page 24 */
85 /* This function dissects fhstatus for v1 and v2 of the mount protocol.
86  * Formally, hf_mount3_status only define the status codes returned by version
87  * 3 of the protocol. 
88  * Though not formally defined in the standard, we use the same 
89  * value-to-string mappings as version 3 since we belive that this mapping 
90  * is consistant with most v1 and v2 implementations.
91  */
92 static int
93 dissect_fhstatus(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
94 {
95         gint32 status;
96
97         status=tvb_get_ntohl(tvb,offset);
98         offset = dissect_rpc_uint32(tvb,pinfo,tree,hf_mount3_status,offset);
99
100         switch (status) {
101                 case 0:
102                         offset = dissect_fhandle(tvb,offset,pinfo,tree,"fhandle");
103                 break;
104                 default:
105                         /* void */
106                 break;
107         }
108
109         return offset;
110 }
111
112
113 static int
114 dissect_mount_dirpath_call(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
115 {
116         if((!pinfo->fd->flags.visited) && nfs_file_name_snooping){
117                 rpc_call_info_value *civ=pinfo->private_data;
118
119                 if(civ->request && (civ->proc==1)){
120                         unsigned char *host, *name;
121                         int len;
122
123                         host=ip_to_str(pinfo->dst.data);
124                         len=tvb_get_ntohl(tvb, offset);
125                 
126                         name=g_malloc(strlen(host)+1+len+1);
127                         sprintf(name,"%s:%*s", host, len, tvb_get_ptr(tvb, offset+4, len));
128
129                         nfs_name_snoop_add_name(civ->xid, tvb, -1, strlen(name), 0, 0, name);
130                 }
131         }
132
133
134         if ( tree )
135         {
136                 offset = dissect_rpc_string(tvb,pinfo,tree,hf_mount_path,offset,NULL);
137         }
138         
139         return offset;
140 }
141
142
143 /* RFC 1094, Page 25,26 */
144 static int
145 dissect_mount1_mnt_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
146 {
147         offset = dissect_fhstatus(tvb,offset,pinfo,tree);
148
149         return offset;
150 }
151
152
153
154 /* RFC 1094, Page 26 */
155 /* RFC 1813, Page 110 */
156 static int
157 dissect_mountlist(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
158 {
159         proto_item* lock_item = NULL;
160         proto_tree* lock_tree = NULL;
161         int old_offset = offset;
162         char* hostname;
163         char* directory;
164
165         if (tree) {
166                 lock_item = proto_tree_add_item(tree, hf_mount_mountlist, tvb,
167                                         offset, -1, FALSE);
168                 if (lock_item)
169                         lock_tree = proto_item_add_subtree(lock_item, ett_mount_mountlist);
170         }
171
172         offset = dissect_rpc_string(tvb, pinfo, lock_tree, 
173                         hf_mount_mountlist_hostname, offset, &hostname);
174         offset = dissect_rpc_string(tvb, pinfo, lock_tree,
175                         hf_mount_mountlist_directory, offset, &directory);
176
177         if (lock_item) {
178                 /* now we have a nicer string */
179                 proto_item_set_text(lock_item, "Mount List Entry: %s:%s", hostname, directory);
180                 /* now we know, that mountlist is shorter */
181                 proto_item_set_len(lock_item, offset - old_offset);
182         }
183         g_free(hostname);
184         g_free(directory);
185
186         return offset;
187 }
188
189
190 /* RFC 1094, Page 26 */
191 /* RFC 1813, Page 110 */
192 static int
193 dissect_mount_dump_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
194 {
195         offset = dissect_rpc_list(tvb, pinfo, tree, offset, dissect_mountlist);
196
197         return offset;
198 }
199
200
201
202 /* RFC 1094, Page 26 */
203 /* RFC 1813, Page 110 */
204 static int
205 dissect_group(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
206 {
207         int len,str_len;
208         len=tvb_get_ntohl(tvb,offset);
209         str_len=tvb_get_nstringz(tvb,offset+4,
210                 MAX_GROUP_NAME_LIST-5-group_names_len,
211                 group_name_list+group_names_len);
212         if((group_names_len>=(MAX_GROUP_NAME_LIST-5))||(str_len<0)){
213                 strcpy(group_name_list+(MAX_GROUP_NAME_LIST-5),"...");
214                 group_names_len=MAX_GROUP_NAME_LIST-1;
215         } else {
216                 group_names_len+=str_len;
217                 group_name_list[group_names_len++]=' ';
218         }
219         group_name_list[group_names_len]=0;
220
221         offset = dissect_rpc_string(tvb, pinfo, tree, 
222                         hf_mount_groups_group, offset, NULL);
223
224         return offset;
225 }
226
227
228 /* RFC 1094, Page 26 */
229 /* RFC 1813, Page 113 */
230 static int
231 dissect_exportlist(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
232 {
233         proto_item* exportlist_item = NULL;
234         proto_tree* exportlist_tree = NULL;
235         int old_offset = offset;
236         int groups_offset;
237         proto_item* groups_item = NULL;
238         proto_item* groups_tree = NULL;
239         char* directory;
240
241         group_name_list[0]=0;
242         group_names_len=0;
243         if (tree) {
244                 exportlist_item = proto_tree_add_item(tree, hf_mount_exportlist, tvb,
245                                         offset, -1, FALSE);
246                 if (exportlist_item)
247                         exportlist_tree = proto_item_add_subtree(exportlist_item, ett_mount_exportlist);
248         }
249
250         offset = dissect_rpc_string(tvb, pinfo, exportlist_tree,
251                         hf_mount_exportlist_directory, offset, &directory);
252         groups_offset = offset;
253
254         if (tree) {
255                 groups_item = proto_tree_add_item(exportlist_tree, hf_mount_groups, tvb,
256                                         offset, -1, FALSE);
257                 if (groups_item)
258                         groups_tree = proto_item_add_subtree(groups_item, ett_mount_groups);
259         }
260
261         offset = dissect_rpc_list(tvb, pinfo, groups_tree, offset, dissect_group);
262         if (groups_item) {
263                 /* mark empty lists */
264                 if (offset - groups_offset == 4) {
265                         proto_item_set_text(groups_item, "Groups: empty");
266                 }
267
268                 /* now we know, that groups is shorter */
269                 proto_item_set_len(groups_item, offset - groups_offset);
270         }
271
272         if (exportlist_item) {
273                 /* now we have a nicer string */
274                 proto_item_set_text(exportlist_item, "Export List Entry: %s -> %s", directory,group_name_list);
275                 /* now we know, that exportlist is shorter */
276                 proto_item_set_len(exportlist_item, offset - old_offset);
277         }
278         g_free(directory);
279
280         return offset;
281 }
282
283
284 /* RFC 1094, Page 26 */
285 /* RFC 1813, Page 113 */
286 static int
287 dissect_mount_export_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
288 {
289         offset = dissect_rpc_list(tvb, pinfo, tree, offset, dissect_exportlist);
290
291         return offset;
292 }
293
294
295 #define OFFS_MASK       32      /* offset of the "pc_mask" field */
296
297 #define PC_ERROR_ALL            0x0001
298 #define PC_ERROR_LINK_MAX       0x0002
299 #define PC_ERROR_MAX_CANON      0x0004
300 #define PC_ERROR_MAX_INPUT      0x0008
301 #define PC_ERROR_NAME_MAX       0x0010
302 #define PC_ERROR_PATH_MAX       0x0020
303 #define PC_ERROR_PIPE_BUF       0x0040
304 #define PC_CHOWN_RESTRICTED     0x0080
305 #define PC_NO_TRUNC             0x0100
306 #define PC_ERROR_VDISABLE       0x0200
307
308 static const true_false_string tos_error_all = {
309   "All info invalid",
310   "Some or all info valid"
311 };
312
313 static const true_false_string tos_error_link_max = {
314   "LINK_MAX invalid",
315   "LINK_MAX valid"
316 };
317
318 static const true_false_string tos_error_max_canon = {
319   "MAX_CANON invalid",
320   "MAX_CANON valid"
321 };
322
323 static const true_false_string tos_error_max_input = {
324   "MAX_INPUT invalid",
325   "MAX_INPUT valid"
326 };
327
328 static const true_false_string tos_error_name_max = {
329   "NAME_MAX invalid",
330   "NAME_MAX valid"
331 };
332
333 static const true_false_string tos_error_path_max = {
334   "PATH_MAX invalid",
335   "PATH_MAX valid"
336 };
337
338 static const true_false_string tos_error_pipe_buf = {
339   "PIPE_BUF invalid",
340   "PIPE_BUF valid"
341 };
342
343 static const true_false_string tos_chown_restricted = {
344   "Only a privileged user can change the ownership of a file",
345   "Users may give away their own files"
346 };
347
348 static const true_false_string tos_no_trunc = {
349   "File names that are too long will get an error",
350   "File names that are too long will be truncated"
351 };
352
353 static const true_false_string tos_error_vdisable = {
354   "VDISABLE invalid",
355   "VDISABLE valid"
356 };
357
358
359 static int
360 dissect_mount_pathconf_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
361 {
362         int saved_offset;
363         guint32 pc_mask;
364         proto_item *lock_item;
365         proto_tree *lock_tree;
366
367         saved_offset=offset;
368         /*
369          * Extract the mask first, so we know which other fields the
370          * server was able to return to us.
371          */
372         pc_mask = tvb_get_ntohl(tvb, offset+OFFS_MASK) & 0xffff;
373         if (!(pc_mask & (PC_ERROR_LINK_MAX|PC_ERROR_ALL))) {
374                 if (tree) {
375                         dissect_rpc_uint32(tvb,pinfo,tree,hf_mount_pathconf_link_max,offset);
376                 }
377         }
378         offset += 4;
379
380         if (!(pc_mask & (PC_ERROR_MAX_CANON|PC_ERROR_ALL))) {
381                 if (tree) {
382                         proto_tree_add_item(tree, 
383                                 hf_mount_pathconf_max_canon,tvb,offset+2,2,
384                                 tvb_get_ntohs(tvb,offset)&0xffff);
385                 }
386         }
387         offset += 4;
388
389         if (!(pc_mask & (PC_ERROR_MAX_INPUT|PC_ERROR_ALL))) {
390                 if (tree) {
391                         proto_tree_add_item(tree, 
392                                 hf_mount_pathconf_max_input,tvb,offset+2,2,
393                                 tvb_get_ntohs(tvb,offset)&0xffff);
394                 }
395         }
396         offset += 4;
397
398         if (!(pc_mask & (PC_ERROR_NAME_MAX|PC_ERROR_ALL))) {
399                 if (tree) {
400                         proto_tree_add_item(tree, 
401                                 hf_mount_pathconf_name_max,tvb,offset+2,2,
402                                 tvb_get_ntohs(tvb,offset)&0xffff);
403                 }
404         }
405         offset += 4;
406
407         if (!(pc_mask & (PC_ERROR_PATH_MAX|PC_ERROR_ALL))) {
408                 if (tree) {
409                         proto_tree_add_item(tree, 
410                                 hf_mount_pathconf_path_max,tvb,offset+2,2,
411                                 tvb_get_ntohs(tvb,offset)&0xffff);
412                 }
413         }
414         offset += 4;
415
416         if (!(pc_mask & (PC_ERROR_PIPE_BUF|PC_ERROR_ALL))) {
417                 if (tree) {
418                         proto_tree_add_item(tree, 
419                                 hf_mount_pathconf_pipe_buf,tvb,offset+2,2,
420                                 tvb_get_ntohs(tvb,offset)&0xffff);
421                 }
422         }
423         offset += 4;
424
425         offset += 4;    /* skip "pc_xxx" pad field */
426
427         if (!(pc_mask & (PC_ERROR_VDISABLE|PC_ERROR_ALL))) {
428                 if (tree) {
429                         proto_tree_add_item(tree, 
430                                 hf_mount_pathconf_vdisable,tvb,offset+3,1,
431                                 tvb_get_ntohs(tvb,offset)&0xffff);
432                 }
433         }
434         offset += 4;
435
436
437         if (tree) {
438                 lock_item = proto_tree_add_item(tree, hf_mount_pathconf_mask, tvb,
439                                         offset+2, 2, FALSE);
440
441                 lock_tree = proto_item_add_subtree(lock_item, ett_mount_pathconf_mask);
442                 proto_tree_add_boolean(lock_tree, hf_mount_pathconf_error_all, tvb,
443                     offset + 2, 2, pc_mask);
444
445                 proto_tree_add_boolean(lock_tree, hf_mount_pathconf_error_link_max, tvb,
446                     offset + 2, 2, pc_mask);
447                 proto_tree_add_boolean(lock_tree, hf_mount_pathconf_error_max_canon, tvb,
448                     offset + 2, 2, pc_mask);
449                 proto_tree_add_boolean(lock_tree, hf_mount_pathconf_error_max_input, tvb,
450                     offset + 2, 2, pc_mask);
451                 proto_tree_add_boolean(lock_tree, hf_mount_pathconf_error_name_max, tvb,
452                     offset + 2, 2, pc_mask);
453                 proto_tree_add_boolean(lock_tree, hf_mount_pathconf_error_path_max, tvb,
454                     offset + 2, 2, pc_mask);
455                 proto_tree_add_boolean(lock_tree, hf_mount_pathconf_error_pipe_buf, tvb,
456                     offset + 2, 2, pc_mask);
457                 proto_tree_add_boolean(lock_tree, hf_mount_pathconf_chown_restricted, tvb,
458                     offset + 2, 2, pc_mask);
459                 proto_tree_add_boolean(lock_tree, hf_mount_pathconf_no_trunc, tvb,
460                     offset + 2, 2, pc_mask);
461                 proto_tree_add_boolean(lock_tree, hf_mount_pathconf_error_vdisable, tvb,
462                     offset + 2, 2, pc_mask);
463         }
464
465         offset += 8;
466         return offset;
467 }
468
469 /* RFC 1813, Page 107 */
470 static const value_string mount3_mountstat3[] = 
471 {
472         {       0,      "OK" },
473         {       1,      "ERR_PERM" },
474         {       2,      "ERR_NOENT" },
475         {       5,      "ERR_IO" },
476         {       13,     "ERR_ACCESS" },
477         {       20,     "ERR_NOTDIR" },
478         {       22,     "ERR_INVAL" },
479         {       63,     "ERR_NAMETOOLONG" },
480         {       10004,  "ERR_NOTSUPP" },
481         {       10006,  "ERR_SERVERFAULT" },
482         {       0,      NULL }
483 };
484
485
486 /* RFC 1813, Page 107 */
487 static int
488 dissect_mountstat3(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, int hfindex, guint32 *status)
489 {
490         guint32 mountstat3;
491
492         mountstat3 = tvb_get_ntohl(tvb, offset);
493
494         offset = dissect_rpc_uint32(tvb,pinfo,tree,hfindex,offset);
495         *status = mountstat3;
496         return offset;
497 }
498
499 /* RFC 1831, Page 109 */
500 static int
501 dissect_mount3_mnt_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
502 {
503         guint32 status;
504         guint32 auth_flavors;
505         guint32 auth_flavor;
506         guint32 auth_flavor_i;
507         
508         offset = dissect_mountstat3(tvb,pinfo,tree,offset,hf_mount3_status,&status);
509
510         switch (status) {
511                 case 0:
512                         offset = dissect_nfs_fh3(tvb,offset,pinfo,tree,"fhandle");
513
514                         auth_flavors = tvb_get_ntohl(tvb, offset);
515                         proto_tree_add_uint(tree,hf_mount_flavors, tvb,
516                                 offset, 4, auth_flavors);
517                         offset += 4;
518                         for (auth_flavor_i = 0 ; auth_flavor_i < auth_flavors ; auth_flavor_i++) {
519                                 auth_flavor = tvb_get_ntohl(tvb, offset);
520                                 proto_tree_add_uint(tree,hf_mount_flavor, tvb,
521                                         offset, 4, auth_flavor);
522                                 offset += 4;
523                         }
524                 break;
525                 default:
526                         /* void */
527                 break;
528         }
529         
530         return offset;
531 }
532
533
534 /* proc number, "proc name", dissect_request, dissect_reply */
535 /* NULL as function pointer means: type of arguments is "void". */
536
537 /* Mount protocol version 1, RFC 1094 */
538 static const vsff mount1_proc[] = {
539     { 0, "NULL", NULL, NULL },
540     { MOUNTPROC_MNT,        "MNT",      
541                 dissect_mount_dirpath_call, dissect_mount1_mnt_reply },
542     { MOUNTPROC_DUMP,       "DUMP",
543                 NULL, dissect_mount_dump_reply },
544     { MOUNTPROC_UMNT,      "UMNT",        
545                 dissect_mount_dirpath_call, NULL },
546     { MOUNTPROC_UMNTALL,   "UMNTALL",
547                 NULL, NULL },
548     { MOUNTPROC_EXPORT,    "EXPORT",
549                 NULL, dissect_mount_export_reply },
550     { MOUNTPROC_EXPORTALL, "EXPORTALL",
551                 NULL, dissect_mount_export_reply },
552     { 0, NULL, NULL, NULL }
553 };
554 /* end of mount version 1 */
555
556
557 /* Mount protocol version 2, private communication from somebody at Sun;
558    mount V2 is V1 plus MOUNTPROC_PATHCONF to fetch information for the
559    POSIX "pathconf()" call. */
560 static const vsff mount2_proc[] = {
561     { 0, "NULL", NULL, NULL },
562     { MOUNTPROC_MNT,        "MNT",      
563                 dissect_mount_dirpath_call, dissect_mount1_mnt_reply },
564     { MOUNTPROC_DUMP,       "DUMP",
565                 NULL, dissect_mount_dump_reply },
566     { MOUNTPROC_UMNT,      "UMNT",        
567                 dissect_mount_dirpath_call, NULL },
568     { MOUNTPROC_UMNTALL,   "UMNTALL",
569                 NULL, NULL },
570     { MOUNTPROC_EXPORT,    "EXPORT",
571                 NULL, dissect_mount_export_reply },
572     { MOUNTPROC_EXPORTALL, "EXPORTALL",
573                 NULL, dissect_mount_export_reply },
574     { MOUNTPROC_PATHCONF,  "PATHCONF",
575                 dissect_mount_dirpath_call, dissect_mount_pathconf_reply },
576     { 0, NULL, NULL, NULL }
577 };
578 /* end of mount version 2 */
579
580
581 /* Mount protocol version 3, RFC 1813 */
582 static const vsff mount3_proc[] = {
583         { 0, "NULL", NULL, NULL },
584         { MOUNTPROC_MNT, "MNT",
585                 dissect_mount_dirpath_call, dissect_mount3_mnt_reply },
586         { MOUNTPROC_DUMP, "DUMP",
587                 NULL, dissect_mount_dump_reply },
588         { MOUNTPROC_UMNT, "UMNT",
589                 dissect_mount_dirpath_call, NULL },
590         { MOUNTPROC_UMNTALL, "UMNTALL",
591                 NULL, NULL },
592         { MOUNTPROC_EXPORT, "EXPORT",
593                 NULL, dissect_mount_export_reply },
594         { 0, NULL, NULL, NULL }
595 };
596 /* end of Mount protocol version 3 */
597
598
599 void
600 proto_register_mount(void)
601 {
602         static hf_register_info hf[] = {
603                 { &hf_mount_path, {
604                         "Path", "mount.path", FT_STRING, BASE_DEC,
605                         NULL, 0, "Path", HFILL }},
606                 { &hf_mount3_status, {
607                         "Status", "mount.status", FT_UINT32, BASE_DEC,
608                         VALS(mount3_mountstat3), 0, "Status", HFILL }},
609                 { &hf_mount_mountlist_hostname, {
610                         "Hostname", "mount.dump.hostname", FT_STRING, BASE_DEC,
611                         NULL, 0, "Hostname", HFILL }},
612                 { &hf_mount_mountlist_directory, {
613                         "Directory", "mount.dump.directory", FT_STRING, BASE_DEC,
614                         NULL, 0, "Directory", HFILL }},
615                 { &hf_mount_mountlist, {
616                         "Mount List Entry", "mount.dump.entry", FT_NONE, 0,
617                         NULL, 0, "Mount List Entry", HFILL }},
618                 { &hf_mount_groups_group, {
619                         "Group", "mount.export.group", FT_STRING, BASE_DEC,
620                         NULL, 0, "Group", HFILL }},
621                 { &hf_mount_groups, {
622                         "Groups", "mount.export.groups", FT_NONE, 0,
623                         NULL, 0, "Groups", HFILL }},
624                 { &hf_mount_exportlist_directory, {
625                         "Directory", "mount.export.directory", FT_STRING, BASE_DEC,
626                         NULL, 0, "Directory", HFILL }},
627                 { &hf_mount_exportlist, {
628                         "Export List Entry", "mount.export.entry", FT_NONE, 0,
629                         NULL, 0, "Export List Entry", HFILL }},
630                 { &hf_mount_pathconf_link_max, {
631                         "Maximum number of links to a file", "mount.pathconf.link_max",
632                         FT_UINT32, BASE_DEC,
633                         NULL, 0, "Maximum number of links allowed to a file", HFILL }},
634                 { &hf_mount_pathconf_max_canon, {
635                         "Maximum terminal input line length", "mount.pathconf.max_canon",
636                         FT_UINT16, BASE_DEC,
637                         NULL, 0, "Max tty input line length", HFILL }},
638                 { &hf_mount_pathconf_max_input, {
639                         "Terminal input buffer size", "mount.pathconf.max_input",
640                         FT_UINT16, BASE_DEC,
641                         NULL, 0, "Terminal input buffer size", HFILL }},
642                 { &hf_mount_pathconf_name_max, {
643                         "Maximum file name length", "mount.pathconf.name_max",
644                         FT_UINT16, BASE_DEC,
645                         NULL, 0, "Maximum file name length", HFILL }},
646                 { &hf_mount_pathconf_path_max, {
647                         "Maximum path name length", "mount.pathconf.path_max",
648                         FT_UINT16, BASE_DEC,
649                         NULL, 0, "Maximum path name length", HFILL }},
650                 { &hf_mount_pathconf_pipe_buf, {
651                         "Pipe buffer size", "mount.pathconf.pipe_buf",
652                         FT_UINT16, BASE_DEC,
653                         NULL, 0, "Maximum amount of data that can be written atomically to a pipe", HFILL }},
654                 { &hf_mount_pathconf_vdisable, {
655                         "VDISABLE character", "mount.pathconf.vdisable_char",
656                         FT_UINT8, BASE_HEX,
657                         NULL, 0, "Character value to disable a terminal special character", HFILL }},
658                 { &hf_mount_pathconf_mask, {
659                         "Reply error/status bits", "mount.pathconf.mask",
660                         FT_UINT16, BASE_HEX,
661                         NULL, 0, "Bit mask with error and status bits", HFILL }},
662                 { &hf_mount_pathconf_error_all, {
663                         "ERROR_ALL",    "mount.pathconf.mask.error_all",
664                         FT_BOOLEAN, 16, TFS(&tos_error_all),
665                         PC_ERROR_ALL, "", HFILL }},
666                 { &hf_mount_pathconf_error_link_max, {
667                         "ERROR_LINK_MAX", "mount.pathconf.mask.error_link_max",
668                         FT_BOOLEAN, 16, TFS(&tos_error_link_max),
669                         PC_ERROR_LINK_MAX, "", HFILL }},
670                 { &hf_mount_pathconf_error_max_canon, {
671                         "ERROR_MAX_CANON", "mount.pathconf.mask.error_max_canon",
672                         FT_BOOLEAN, 16, TFS(&tos_error_max_canon),
673                         PC_ERROR_MAX_CANON, "", HFILL }},
674                 { &hf_mount_pathconf_error_max_input, {
675                         "ERROR_MAX_INPUT", "mount.pathconf.mask.error_max_input",
676                         FT_BOOLEAN, 16, TFS(&tos_error_max_input),
677                         PC_ERROR_MAX_INPUT, "", HFILL }},
678                 { &hf_mount_pathconf_error_name_max, {
679                         "ERROR_NAME_MAX", "mount.pathconf.mask.error_name_max",
680                         FT_BOOLEAN, 16, TFS(&tos_error_name_max),
681                         PC_ERROR_NAME_MAX, "", HFILL }},
682                 { &hf_mount_pathconf_error_path_max, {
683                         "ERROR_PATH_MAX", "mount.pathconf.mask.error_path_max",
684                         FT_BOOLEAN, 16, TFS(&tos_error_path_max),
685                         PC_ERROR_PATH_MAX, "", HFILL }},
686                 { &hf_mount_pathconf_error_pipe_buf, {
687                         "ERROR_PIPE_BUF", "mount.pathconf.mask.error_pipe_buf",
688                         FT_BOOLEAN, 16, TFS(&tos_error_pipe_buf),
689                         PC_ERROR_PIPE_BUF, "", HFILL }},
690                 { &hf_mount_pathconf_chown_restricted, {
691                         "CHOWN_RESTRICTED", "mount.pathconf.mask.chown_restricted",
692                         FT_BOOLEAN, 16, TFS(&tos_chown_restricted),
693                         PC_CHOWN_RESTRICTED, "", HFILL }},
694                 { &hf_mount_pathconf_no_trunc, {
695                         "NO_TRUNC", "mount.pathconf.mask.no_trunc",
696                         FT_BOOLEAN, 16, TFS(&tos_no_trunc),
697                         PC_NO_TRUNC, "", HFILL }},
698                 { &hf_mount_pathconf_error_vdisable, {
699                         "ERROR_VDISABLE", "mount.pathconf.mask.error_vdisable",
700                         FT_BOOLEAN, 16, TFS(&tos_error_vdisable),
701                         PC_ERROR_VDISABLE, "", HFILL }},
702                 { &hf_mount_flavors, {
703                         "Flavors", "mount.flavors", FT_UINT32, BASE_DEC,
704                         NULL, 0, "Flavors", HFILL }},
705                 { &hf_mount_flavor, {
706                         "Flavor", "mount.flavor", FT_UINT32, BASE_DEC,
707                         VALS(rpc_auth_flavor), 0, "Flavor", HFILL }},
708         };
709         static gint *ett[] = {
710                 &ett_mount,
711                 &ett_mount_mountlist,
712                 &ett_mount_groups,
713                 &ett_mount_exportlist,
714                 &ett_mount_pathconf_mask,
715         };
716
717         proto_mount = proto_register_protocol("Mount Service", "MOUNT", "mount");
718         proto_register_field_array(proto_mount, hf, array_length(hf));
719         proto_register_subtree_array(ett, array_length(ett));
720 }
721
722 void
723 proto_reg_handoff_mount(void)
724 {
725         /* Register the protocol as RPC */
726         rpc_init_prog(proto_mount, MOUNT_PROGRAM, ett_mount);
727         /* Register the procedure tables */
728         rpc_init_proc_table(MOUNT_PROGRAM, 1, mount1_proc);
729         rpc_init_proc_table(MOUNT_PROGRAM, 2, mount2_proc);
730         rpc_init_proc_table(MOUNT_PROGRAM, 3, mount3_proc);
731 }