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