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