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