Add HP Switch Protocol SAP value
[obnox/wireshark/wip.git] / epan / dissectors / packet-mount.c
1 /* packet-mount.c
2  * Routines for mount dissection
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * Copied from packet-smb.c
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 #include <string.h>
33
34 #include "packet-rpc.h"
35 #include "packet-mount.h"
36 #include "packet-nfs.h"
37
38 #include <epan/emem.h>
39
40
41 static int proto_mount = -1;
42 static int proto_sgi_mount = -1;
43 static int hf_mount_procedure_v1 = -1;
44 static int hf_mount_procedure_v2 = -1;
45 static int hf_mount_procedure_v3 = -1;
46 static int hf_sgi_mount_procedure_v1 = -1;
47 static int hf_mount_path = -1;
48 static int hf_mount3_status = -1;
49 static int hf_mount_mountlist_hostname = -1;
50 static int hf_mount_mountlist_directory = -1;
51 static int hf_mount_mountlist = -1;
52 static int hf_mount_groups_group = -1;
53 static int hf_mount_groups = -1;
54 static int hf_mount_exportlist_directory = -1;
55 static int hf_mount_exportlist = -1;
56 static int hf_mount_has_options = -1;
57 static int hf_mount_options = -1;
58 static int hf_mount_pathconf_link_max = -1;
59 static int hf_mount_pathconf_max_canon = -1;
60 static int hf_mount_pathconf_max_input = -1;
61 static int hf_mount_pathconf_name_max = -1;
62 static int hf_mount_pathconf_path_max = -1;
63 static int hf_mount_pathconf_pipe_buf = -1;
64 static int hf_mount_pathconf_vdisable = -1;
65 static int hf_mount_pathconf_mask = -1;
66 static int hf_mount_pathconf_error_all = -1;
67 static int hf_mount_pathconf_error_link_max = -1;
68 static int hf_mount_pathconf_error_max_canon = -1;
69 static int hf_mount_pathconf_error_max_input = -1;
70 static int hf_mount_pathconf_error_name_max = -1;
71 static int hf_mount_pathconf_error_path_max = -1;
72 static int hf_mount_pathconf_error_pipe_buf = -1;
73 static int hf_mount_pathconf_chown_restricted = -1;
74 static int hf_mount_pathconf_no_trunc = -1;
75 static int hf_mount_pathconf_error_vdisable = -1;
76 static int hf_mount_statvfs_bsize = -1;
77 static int hf_mount_statvfs_frsize = -1;
78 static int hf_mount_statvfs_blocks = -1;
79 static int hf_mount_statvfs_bfree = -1;
80 static int hf_mount_statvfs_bavail = -1;
81 static int hf_mount_statvfs_files = -1;
82 static int hf_mount_statvfs_ffree = -1;
83 static int hf_mount_statvfs_favail = -1;
84 static int hf_mount_statvfs_fsid = -1;
85 static int hf_mount_statvfs_basetype = -1;
86 static int hf_mount_statvfs_flag = -1;
87 static int hf_mount_statvfs_flag_rdonly = -1;
88 static int hf_mount_statvfs_flag_nosuid = -1;
89 static int hf_mount_statvfs_flag_notrunc = -1;
90 static int hf_mount_statvfs_flag_nodev = -1;
91 static int hf_mount_statvfs_flag_grpid = -1;
92 static int hf_mount_statvfs_flag_local = -1;
93 static int hf_mount_statvfs_namemax = -1;
94 static int hf_mount_statvfs_fstr = -1;
95 static int hf_mount_flavors = -1;
96 static int hf_mount_flavor = -1;
97
98 static gint ett_mount = -1;
99 static gint ett_mount_mountlist = -1;
100 static gint ett_mount_groups = -1;
101 static gint ett_mount_exportlist = -1;
102 static gint ett_mount_pathconf_mask = -1;
103 static gint ett_mount_statvfs_flag = -1;
104
105 #define MAX_GROUP_NAME_LIST 128
106 static char group_name_list[MAX_GROUP_NAME_LIST];
107 static int  group_names_len;
108
109 /* RFC 1813, Page 107 */
110 static const value_string mount3_mountstat3[] =
111 {
112         {       0,      "OK" },
113         {       1,      "ERR_PERM" },
114         {       2,      "ERR_NOENT" },
115         {       5,      "ERR_IO" },
116         {       13,     "ERR_ACCESS" },
117         {       20,     "ERR_NOTDIR" },
118         {       22,     "ERR_INVAL" },
119         {       63,     "ERR_NAMETOOLONG" },
120         {       10004,  "ERR_NOTSUPP" },
121         {       10006,  "ERR_SERVERFAULT" },
122         {       0,      NULL }
123 };
124
125
126 /* RFC 1094, Page 24 */
127 /* This function dissects fhstatus for v1 and v2 of the mount protocol.
128  * Formally, hf_mount3_status only define the status codes returned by version
129  * 3 of the protocol.
130  * Though not formally defined in the standard, we use the same
131  * value-to-string mappings as version 3 since we belive that this mapping
132  * is consistant with most v1 and v2 implementations.
133  */
134 static int
135 dissect_fhstatus(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
136 {
137         gint32 status;
138
139         status=tvb_get_ntohl(tvb,offset);
140         offset = dissect_rpc_uint32(tvb,tree,hf_mount3_status,offset);
141
142         switch (status) {
143                 case 0:
144                         offset = dissect_fhandle(tvb,offset,pinfo,tree,"fhandle", NULL);
145                 break;
146                 default:
147                         /* void */
148                         if (check_col(pinfo->cinfo, COL_INFO)) {
149                                 col_append_fstr(
150                                         pinfo->cinfo, COL_INFO, " Error:%s",
151                                         val_to_str(status, mount3_mountstat3,
152                                             "Unknown (0x%08X)"));
153                         }
154                 break;
155         }
156
157         return offset;
158 }
159
160
161 static int
162 dissect_mount_dirpath_call(tvbuff_t *tvb, int offset, packet_info *pinfo,
163                 proto_tree *tree)
164 {
165         char *mountpoint=NULL;
166
167         if((!pinfo->fd->flags.visited) && nfs_file_name_snooping){
168                 rpc_call_info_value *civ=pinfo->private_data;
169
170                 if(civ->request && (civ->proc==1)){
171                         unsigned char *host, *name;
172                         unsigned const char *dir;
173                         int len;
174
175                         host=ip_to_str(pinfo->dst.data);
176                         len=tvb_get_ntohl(tvb, offset);
177                         if (len >= ITEM_LABEL_LENGTH)
178                                 THROW(ReportedBoundsError);
179
180                         dir=tvb_get_ptr(tvb, offset+4, len);
181                         if(dir){
182                                 unsigned char *ptr;
183                                 name=g_malloc(strlen(host)+1+len+1+200);
184                                 ptr=name;
185                                 memcpy(ptr, host, strlen(host));
186                                 ptr+=strlen(host);
187                                 *ptr++=':';
188                                 memcpy(ptr, dir, len);
189                                 ptr+=len;
190                                 *ptr=0;
191
192                                 nfs_name_snoop_add_name(civ->xid, tvb, -1, strlen(name), 0, 0, name);
193                         }
194                 }
195         }
196
197         offset = dissect_rpc_string(tvb,tree,hf_mount_path,offset,&mountpoint);
198         if (check_col(pinfo->cinfo, COL_INFO)) {
199                 col_append_fstr(pinfo->cinfo, COL_INFO," %s", mountpoint);
200         }
201
202
203         return offset;
204 }
205
206
207 /* RFC 1094, Page 25,26 */
208 static int
209 dissect_mount1_mnt_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
210 {
211         offset = dissect_fhstatus(tvb,offset,pinfo,tree);
212
213         return offset;
214 }
215
216
217
218 /* RFC 1094, Page 26 */
219 /* RFC 1813, Page 110 */
220 static int
221 dissect_mountlist(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
222 {
223         proto_item* lock_item = NULL;
224         proto_tree* lock_tree = NULL;
225         int old_offset = offset;
226         char* hostname;
227         char* directory;
228
229         if (tree) {
230                 lock_item = proto_tree_add_item(tree, hf_mount_mountlist, tvb,
231                                         offset, -1, FALSE);
232                 if (lock_item)
233                         lock_tree = proto_item_add_subtree(lock_item, ett_mount_mountlist);
234         }
235
236         offset = dissect_rpc_string(tvb, lock_tree,
237                         hf_mount_mountlist_hostname, offset, &hostname);
238         offset = dissect_rpc_string(tvb, lock_tree,
239                         hf_mount_mountlist_directory, offset, &directory);
240
241         if (lock_item) {
242                 /* now we have a nicer string */
243                 proto_item_set_text(lock_item, "Mount List Entry: %s:%s", hostname, directory);
244                 /* now we know, that mountlist is shorter */
245                 proto_item_set_len(lock_item, offset - old_offset);
246         }
247
248         return offset;
249 }
250
251
252 /* RFC 1094, Page 26 */
253 /* RFC 1813, Page 110 */
254 static int
255 dissect_mount_dump_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
256 {
257         offset = dissect_rpc_list(tvb, pinfo, tree, offset, dissect_mountlist);
258
259         return offset;
260 }
261
262
263
264 /* RFC 1094, Page 26 */
265 /* RFC 1813, Page 110 */
266 static int
267 dissect_group(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
268 {
269         int len,str_len;
270         len=tvb_get_ntohl(tvb,offset);
271         if (group_names_len < MAX_GROUP_NAME_LIST - 5) {
272                 str_len=tvb_get_nstringz(tvb,offset+4,
273                         MAX_GROUP_NAME_LIST-5-group_names_len,
274                         group_name_list+group_names_len);
275                 if((group_names_len>=(MAX_GROUP_NAME_LIST-5))||(str_len<0)){
276                         g_snprintf(group_name_list+(MAX_GROUP_NAME_LIST-5), 5, "...");
277                         group_names_len=MAX_GROUP_NAME_LIST;
278                 } else {
279                         group_names_len+=str_len;
280                         group_name_list[group_names_len++]=' ';
281                 }
282                 group_name_list[group_names_len]=0;
283         }
284
285         offset = dissect_rpc_string(tvb, tree,
286                         hf_mount_groups_group, offset, NULL);
287
288         return offset;
289 }
290
291
292 /* RFC 1094, Page 26 */
293 /* RFC 1813, Page 113 */
294 static int
295 dissect_exportlist(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
296 {
297         proto_item* exportlist_item = NULL;
298         proto_tree* exportlist_tree = NULL;
299         int old_offset = offset;
300         int groups_offset;
301         proto_item* groups_item = NULL;
302         proto_item* groups_tree = NULL;
303         char* directory;
304
305         group_name_list[0]=0;
306         group_names_len=0;
307         if (tree) {
308                 exportlist_item = proto_tree_add_item(tree, hf_mount_exportlist, tvb,
309                                         offset, -1, FALSE);
310                 if (exportlist_item)
311                         exportlist_tree = proto_item_add_subtree(exportlist_item, ett_mount_exportlist);
312         }
313
314         offset = dissect_rpc_string(tvb, exportlist_tree,
315                         hf_mount_exportlist_directory, offset, &directory);
316         groups_offset = offset;
317
318         if (tree) {
319                 groups_item = proto_tree_add_item(exportlist_tree, hf_mount_groups, tvb,
320                                         offset, -1, FALSE);
321                 if (groups_item)
322                         groups_tree = proto_item_add_subtree(groups_item, ett_mount_groups);
323         }
324
325         offset = dissect_rpc_list(tvb, pinfo, groups_tree, offset, dissect_group);
326         if (groups_item) {
327                 /* mark empty lists */
328                 if (offset - groups_offset == 4) {
329                         proto_item_set_text(groups_item, "Groups: empty");
330                 }
331
332                 /* now we know, that groups is shorter */
333                 proto_item_set_len(groups_item, offset - groups_offset);
334         }
335
336         if (exportlist_item) {
337                 /* now we have a nicer string */
338                 proto_item_set_text(exportlist_item, "Export List Entry: %s -> %s", directory,group_name_list);
339                 /* now we know, that exportlist is shorter */
340                 proto_item_set_len(exportlist_item, offset - old_offset);
341         }
342
343         return offset;
344 }
345
346
347 /* RFC 1094, Page 26 */
348 /* RFC 1813, Page 113 */
349 static int
350 dissect_mount_export_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
351 {
352         offset = dissect_rpc_list(tvb, pinfo, tree, offset, dissect_exportlist);
353
354         return offset;
355 }
356
357
358 #define OFFS_MASK       32      /* offset of the "pc_mask" field */
359
360 #define PC_ERROR_ALL            0x0001
361 #define PC_ERROR_LINK_MAX       0x0002
362 #define PC_ERROR_MAX_CANON      0x0004
363 #define PC_ERROR_MAX_INPUT      0x0008
364 #define PC_ERROR_NAME_MAX       0x0010
365 #define PC_ERROR_PATH_MAX       0x0020
366 #define PC_ERROR_PIPE_BUF       0x0040
367 #define PC_CHOWN_RESTRICTED     0x0080
368 #define PC_NO_TRUNC             0x0100
369 #define PC_ERROR_VDISABLE       0x0200
370
371 static const true_false_string tos_error_all = {
372   "All info invalid",
373   "Some or all info valid"
374 };
375
376 static const true_false_string tos_error_link_max = {
377   "LINK_MAX invalid",
378   "LINK_MAX valid"
379 };
380
381 static const true_false_string tos_error_max_canon = {
382   "MAX_CANON invalid",
383   "MAX_CANON valid"
384 };
385
386 static const true_false_string tos_error_max_input = {
387   "MAX_INPUT invalid",
388   "MAX_INPUT valid"
389 };
390
391 static const true_false_string tos_error_name_max = {
392   "NAME_MAX invalid",
393   "NAME_MAX valid"
394 };
395
396 static const true_false_string tos_error_path_max = {
397   "PATH_MAX invalid",
398   "PATH_MAX valid"
399 };
400
401 static const true_false_string tos_error_pipe_buf = {
402   "PIPE_BUF invalid",
403   "PIPE_BUF valid"
404 };
405
406 static const true_false_string tos_chown_restricted = {
407   "Only a privileged user can change the ownership of a file",
408   "Users may give away their own files"
409 };
410
411 static const true_false_string tos_no_trunc = {
412   "File names that are too long will get an error",
413   "File names that are too long will be truncated"
414 };
415
416 static const true_false_string tos_error_vdisable = {
417   "VDISABLE invalid",
418   "VDISABLE valid"
419 };
420
421
422 static int
423 dissect_mount_pathconf_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
424 {
425         int saved_offset;
426         guint32 pc_mask;
427         proto_item *lock_item;
428         proto_tree *lock_tree;
429
430         saved_offset=offset;
431         /*
432          * Extract the mask first, so we know which other fields the
433          * server was able to return to us.
434          */
435         pc_mask = tvb_get_ntohl(tvb, offset+OFFS_MASK) & 0xffff;
436         if (!(pc_mask & (PC_ERROR_LINK_MAX|PC_ERROR_ALL))) {
437                 if (tree) {
438                         dissect_rpc_uint32(tvb,tree,hf_mount_pathconf_link_max,offset);
439                 }
440         }
441         offset += 4;
442
443         if (!(pc_mask & (PC_ERROR_MAX_CANON|PC_ERROR_ALL))) {
444                 if (tree) {
445                         proto_tree_add_item(tree,
446                                 hf_mount_pathconf_max_canon,tvb,offset+2,2,
447                                 tvb_get_ntohs(tvb,offset)&0xffff);
448                 }
449         }
450         offset += 4;
451
452         if (!(pc_mask & (PC_ERROR_MAX_INPUT|PC_ERROR_ALL))) {
453                 if (tree) {
454                         proto_tree_add_item(tree,
455                                 hf_mount_pathconf_max_input,tvb,offset+2,2,
456                                 tvb_get_ntohs(tvb,offset)&0xffff);
457                 }
458         }
459         offset += 4;
460
461         if (!(pc_mask & (PC_ERROR_NAME_MAX|PC_ERROR_ALL))) {
462                 if (tree) {
463                         proto_tree_add_item(tree,
464                                 hf_mount_pathconf_name_max,tvb,offset+2,2,
465                                 tvb_get_ntohs(tvb,offset)&0xffff);
466                 }
467         }
468         offset += 4;
469
470         if (!(pc_mask & (PC_ERROR_PATH_MAX|PC_ERROR_ALL))) {
471                 if (tree) {
472                         proto_tree_add_item(tree,
473                                 hf_mount_pathconf_path_max,tvb,offset+2,2,
474                                 tvb_get_ntohs(tvb,offset)&0xffff);
475                 }
476         }
477         offset += 4;
478
479         if (!(pc_mask & (PC_ERROR_PIPE_BUF|PC_ERROR_ALL))) {
480                 if (tree) {
481                         proto_tree_add_item(tree,
482                                 hf_mount_pathconf_pipe_buf,tvb,offset+2,2,
483                                 tvb_get_ntohs(tvb,offset)&0xffff);
484                 }
485         }
486         offset += 4;
487
488         offset += 4;    /* skip "pc_xxx" pad field */
489
490         if (!(pc_mask & (PC_ERROR_VDISABLE|PC_ERROR_ALL))) {
491                 if (tree) {
492                         proto_tree_add_item(tree,
493                                 hf_mount_pathconf_vdisable,tvb,offset+3,1,
494                                 tvb_get_ntohs(tvb,offset)&0xffff);
495                 }
496         }
497         offset += 4;
498
499
500         if (tree) {
501                 lock_item = proto_tree_add_item(tree, hf_mount_pathconf_mask, tvb,
502                                         offset+2, 2, FALSE);
503
504                 lock_tree = proto_item_add_subtree(lock_item, ett_mount_pathconf_mask);
505                 proto_tree_add_boolean(lock_tree, hf_mount_pathconf_error_all, tvb,
506                     offset + 2, 2, pc_mask);
507
508                 proto_tree_add_boolean(lock_tree, hf_mount_pathconf_error_link_max, tvb,
509                     offset + 2, 2, pc_mask);
510                 proto_tree_add_boolean(lock_tree, hf_mount_pathconf_error_max_canon, tvb,
511                     offset + 2, 2, pc_mask);
512                 proto_tree_add_boolean(lock_tree, hf_mount_pathconf_error_max_input, tvb,
513                     offset + 2, 2, pc_mask);
514                 proto_tree_add_boolean(lock_tree, hf_mount_pathconf_error_name_max, tvb,
515                     offset + 2, 2, pc_mask);
516                 proto_tree_add_boolean(lock_tree, hf_mount_pathconf_error_path_max, tvb,
517                     offset + 2, 2, pc_mask);
518                 proto_tree_add_boolean(lock_tree, hf_mount_pathconf_error_pipe_buf, tvb,
519                     offset + 2, 2, pc_mask);
520                 proto_tree_add_boolean(lock_tree, hf_mount_pathconf_chown_restricted, tvb,
521                     offset + 2, 2, pc_mask);
522                 proto_tree_add_boolean(lock_tree, hf_mount_pathconf_no_trunc, tvb,
523                     offset + 2, 2, pc_mask);
524                 proto_tree_add_boolean(lock_tree, hf_mount_pathconf_error_vdisable, tvb,
525                     offset + 2, 2, pc_mask);
526         }
527
528         offset += 8;
529         return offset;
530 }
531
532
533 /* RFC 1813, Page 107 */
534 static int
535 dissect_mountstat3(packet_info *pinfo, tvbuff_t *tvb, proto_tree *tree, int offset, int hfindex, guint32 *status)
536 {
537         guint32 mountstat3;
538
539         mountstat3 = tvb_get_ntohl(tvb, offset);
540         if(mountstat3){
541                 if (check_col(pinfo->cinfo, COL_INFO)) {
542                         col_append_fstr(
543                                 pinfo->cinfo, COL_INFO, " Error:%s",
544                                 val_to_str(mountstat3, mount3_mountstat3,
545                                     "Unknown (0x%08X)"));
546                 }
547         }
548
549         offset = dissect_rpc_uint32(tvb,tree,hfindex,offset);
550         *status = mountstat3;
551         return offset;
552 }
553
554 /* RFC 1831, Page 109 */
555 static int
556 dissect_mount3_mnt_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
557 {
558         guint32 status;
559         guint32 auth_flavors;
560         guint32 auth_flavor;
561         guint32 auth_flavor_i;
562
563         offset = dissect_mountstat3(pinfo,tvb,tree,offset,hf_mount3_status,&status);
564
565         switch (status) {
566                 case 0:
567                         offset = dissect_nfs_fh3(tvb,offset,pinfo,tree,"fhandle",NULL);
568
569                         auth_flavors = tvb_get_ntohl(tvb, offset);
570                         proto_tree_add_uint(tree,hf_mount_flavors, tvb,
571                                 offset, 4, auth_flavors);
572                         offset += 4;
573                         for (auth_flavor_i = 0 ; auth_flavor_i < auth_flavors ; auth_flavor_i++) {
574                                 auth_flavor = tvb_get_ntohl(tvb, offset);
575                                 proto_tree_add_uint(tree,hf_mount_flavor, tvb,
576                                         offset, 4, auth_flavor);
577                                 offset += 4;
578                         }
579                 break;
580                 default:
581                         /* void */
582                 break;
583         }
584
585         return offset;
586 }
587
588 static int
589 dissect_sgi_exportlist(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
590 {
591         proto_item* exportlist_item = NULL;
592         proto_tree* exportlist_tree = NULL;
593         int old_offset = offset;
594         int options_offset;
595         char* directory, *options;
596
597         if (tree) {
598                 exportlist_item = proto_tree_add_item(tree, hf_mount_exportlist,
599                                         tvb, offset, -1, FALSE);
600                 if (exportlist_item)
601                         exportlist_tree = proto_item_add_subtree(exportlist_item,
602                                                 ett_mount_exportlist);
603         }
604
605         offset = dissect_rpc_string(tvb, exportlist_tree,
606                         hf_mount_exportlist_directory, offset, &directory);
607
608         offset = dissect_rpc_bool(tvb, exportlist_tree,
609                         hf_mount_has_options, offset);
610         options_offset = offset;
611
612         offset = dissect_rpc_string(tvb, exportlist_tree, hf_mount_options,
613                          offset, &options);
614
615         if (exportlist_item) {
616                 /* now we have a nicer string */
617                 proto_item_set_text(exportlist_item,
618                         "Export List Entry: %s %s", directory,
619                         options);
620                 /* now we know, that exportlist is shorter */
621                 proto_item_set_len(exportlist_item, offset - old_offset);
622         }
623
624         return offset;
625 }
626
627 static int
628 dissect_mount_exportlist_reply(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
629 {
630         offset = dissect_rpc_list(tvb, pinfo, tree, offset, dissect_sgi_exportlist);
631
632         return offset;
633 }
634
635 #define ST_RDONLY       0x00000001
636 #define ST_NOSUID       0x00000002
637 #define ST_NOTRUNC      0x00000004
638 #define ST_NODEV        0x20000000
639 #define ST_GRPID        0x40000000
640 #define ST_LOCAL        0x80000000
641
642 static const true_false_string tos_st_rdonly = {
643         "Read-only file system",
644         "Read/Write file system"
645 };
646
647 static const true_false_string tos_st_nosuid = {
648         "Does not support setuid/setgid semantics",
649         "Supports setuid/setgid semantics"
650 };
651
652 static const true_false_string tos_st_notrunc = {
653         "Does not trunctate filenames longer than NAME_MAX",
654         "Truncates filenames longer than NAME_MAX"
655 };
656
657 static const true_false_string tos_st_nodev = {
658         "Disallows opening of device files",
659         "Allows opening of device files"
660 };
661
662 static const true_false_string tos_st_grpid = {
663         "Group ID assigned from directory",
664         "Group ID not assigned from directory"
665 };
666
667 static const true_false_string tos_st_local = {
668         "File system is local",
669         "File system is not local"
670 };
671
672 static int
673 dissect_mount_statvfs_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
674 {
675         proto_item *flag_item;
676         proto_tree *flag_tree;
677         guint32 statvfs_flags;
678
679         statvfs_flags = tvb_get_ntohl(tvb, offset+52);
680         if (tree) {
681                 dissect_rpc_uint32(tvb, tree, hf_mount_statvfs_bsize, offset);
682         }
683         offset += 4;
684         if (tree) {
685                 dissect_rpc_uint32(tvb, tree, hf_mount_statvfs_frsize, offset);
686         }
687         offset += 4;
688         if (tree) {
689                 dissect_rpc_uint32(tvb, tree, hf_mount_statvfs_blocks, offset);
690         }
691         offset += 4;
692         if (tree) {
693                 dissect_rpc_uint32(tvb, tree, hf_mount_statvfs_bfree, offset);
694         }
695         offset += 4;
696         if (tree) {
697                 dissect_rpc_uint32(tvb, tree, hf_mount_statvfs_bavail, offset);
698         }
699         offset += 4;
700         if (tree) {
701                 dissect_rpc_uint32(tvb, tree, hf_mount_statvfs_files, offset);
702         }
703         offset += 4;
704         if (tree) {
705                 dissect_rpc_uint32(tvb, tree, hf_mount_statvfs_ffree, offset);
706         }
707         offset += 4;
708         if (tree) {
709                 dissect_rpc_uint32(tvb, tree, hf_mount_statvfs_favail, offset);
710         }
711         offset += 4;
712         if (tree) {
713                 dissect_rpc_bytes(tvb, tree, hf_mount_statvfs_basetype, offset,
714                         16, TRUE, NULL);
715         }
716         offset += 16;
717         if (tree) {
718                 dissect_rpc_bytes(tvb, tree, hf_mount_statvfs_fstr, offset,
719                         32, FALSE, NULL);
720         }
721         offset += 32;
722         if (tree) {
723                 dissect_rpc_uint32(tvb, tree, hf_mount_statvfs_fsid, offset);
724         }
725         offset += 4;
726
727         if (tree) {
728                 flag_item = proto_tree_add_item(tree, hf_mount_statvfs_flag,
729                                 tvb, offset, 4, FALSE);
730                 if (flag_item) {
731                         flag_tree = proto_item_add_subtree(flag_item,
732                                         ett_mount_statvfs_flag);
733                         proto_tree_add_boolean(flag_tree,
734                                 hf_mount_statvfs_flag_rdonly, tvb, offset, 4,
735                                 statvfs_flags);
736                         proto_tree_add_boolean(flag_tree,
737                                 hf_mount_statvfs_flag_nosuid, tvb, offset, 4,
738                                 statvfs_flags);
739                         proto_tree_add_boolean(flag_tree,
740                                 hf_mount_statvfs_flag_notrunc, tvb, offset, 4,
741                                 statvfs_flags);
742                         proto_tree_add_boolean(flag_tree,
743                                 hf_mount_statvfs_flag_nodev, tvb, offset, 4,
744                                 statvfs_flags);
745                         proto_tree_add_boolean(flag_tree,
746                                 hf_mount_statvfs_flag_grpid, tvb, offset, 4,
747                                 statvfs_flags);
748                         proto_tree_add_boolean(flag_tree,
749                                 hf_mount_statvfs_flag_local, tvb, offset, 4,
750                                 statvfs_flags);
751                 }
752         }
753
754         offset += 4;
755         if (tree) {
756                 dissect_rpc_uint32(tvb, tree, hf_mount_statvfs_namemax, offset);
757         }
758         offset += 4;
759
760         return offset;
761 }
762
763 /* proc number, "proc name", dissect_request, dissect_reply */
764 /* NULL as function pointer means: type of arguments is "void". */
765
766 /* Mount protocol version 1, RFC 1094 */
767 static const vsff mount1_proc[] = {
768     { 0, "NULL", NULL, NULL },
769     { MOUNTPROC_MNT,        "MNT",
770                 dissect_mount_dirpath_call, dissect_mount1_mnt_reply },
771     { MOUNTPROC_DUMP,       "DUMP",
772                 NULL, dissect_mount_dump_reply },
773     { MOUNTPROC_UMNT,      "UMNT",
774                 dissect_mount_dirpath_call, NULL },
775     { MOUNTPROC_UMNTALL,   "UMNTALL",
776                 NULL, NULL },
777     { MOUNTPROC_EXPORT,    "EXPORT",
778                 NULL, dissect_mount_export_reply },
779     { MOUNTPROC_EXPORTALL, "EXPORTALL",
780                 NULL, dissect_mount_export_reply },
781     { 0, NULL, NULL, NULL }
782 };
783 static const value_string mount1_proc_vals[] = {
784     { 0, "NULL" },
785     { MOUNTPROC_MNT,       "MNT" },
786     { MOUNTPROC_DUMP,      "DUMP" },
787     { MOUNTPROC_UMNT,      "UMNT" },
788     { MOUNTPROC_UMNTALL,   "UMNTALL" },
789     { MOUNTPROC_EXPORT,    "EXPORT" },
790     { MOUNTPROC_EXPORTALL, "EXPORTALL" },
791     { 0, NULL }
792 };
793 /* end of mount version 1 */
794
795
796 /* Mount protocol version 2, private communication from somebody at Sun;
797    mount V2 is V1 plus MOUNTPROC_PATHCONF to fetch information for the
798    POSIX "pathconf()" call. */
799 static const vsff mount2_proc[] = {
800     { 0, "NULL", NULL, NULL },
801     { MOUNTPROC_MNT,        "MNT",
802                 dissect_mount_dirpath_call, dissect_mount1_mnt_reply },
803     { MOUNTPROC_DUMP,       "DUMP",
804                 NULL, dissect_mount_dump_reply },
805     { MOUNTPROC_UMNT,      "UMNT",
806                 dissect_mount_dirpath_call, NULL },
807     { MOUNTPROC_UMNTALL,   "UMNTALL",
808                 NULL, NULL },
809     { MOUNTPROC_EXPORT,    "EXPORT",
810                 NULL, dissect_mount_export_reply },
811     { MOUNTPROC_EXPORTALL, "EXPORTALL",
812                 NULL, dissect_mount_export_reply },
813     { MOUNTPROC_PATHCONF,  "PATHCONF",
814                 dissect_mount_dirpath_call, dissect_mount_pathconf_reply },
815     { 0, NULL, NULL, NULL }
816 };
817 static const value_string mount2_proc_vals[] = {
818     { 0, "NULL" },
819     { MOUNTPROC_MNT,       "MNT" },
820     { MOUNTPROC_DUMP,      "DUMP" },
821     { MOUNTPROC_UMNT,      "UMNT" },
822     { MOUNTPROC_UMNTALL,   "UMNTALL" },
823     { MOUNTPROC_EXPORT,    "EXPORT" },
824     { MOUNTPROC_EXPORTALL, "EXPORTALL" },
825     { MOUNTPROC_PATHCONF,  "PATHCONF" },
826     { 0, NULL }
827 };
828 /* end of mount version 2 */
829
830
831 /* Mount protocol version 3, RFC 1813 */
832 static const vsff mount3_proc[] = {
833         { 0, "NULL", NULL, NULL },
834         { MOUNTPROC_MNT, "MNT",
835                 dissect_mount_dirpath_call, dissect_mount3_mnt_reply },
836         { MOUNTPROC_DUMP, "DUMP",
837                 NULL, dissect_mount_dump_reply },
838         { MOUNTPROC_UMNT, "UMNT",
839                 dissect_mount_dirpath_call, NULL },
840         { MOUNTPROC_UMNTALL, "UMNTALL",
841                 NULL, NULL },
842         { MOUNTPROC_EXPORT, "EXPORT",
843                 NULL, dissect_mount_export_reply },
844         { 0, NULL, NULL, NULL }
845 };
846 static const value_string mount3_proc_vals[] = {
847         { 0, "NULL" },
848         { MOUNTPROC_MNT, "MNT" },
849         { MOUNTPROC_DUMP, "DUMP" },
850         { MOUNTPROC_UMNT, "UMNT" },
851         { MOUNTPROC_UMNTALL, "UMNTALL" },
852         { MOUNTPROC_EXPORT, "EXPORT" },
853         { 0, NULL }
854 };
855 /* end of Mount protocol version 3 */
856
857 /* SGI mount protocol version 1; actually the same as v1 plus
858    MOUNTPROC_EXPORTLIST and MOUNTPROC_STATVFS */
859
860 static const vsff sgi_mount1_proc[] = {
861     { 0, "NULL", NULL, NULL },
862     { MOUNTPROC_MNT,        "MNT",
863                 dissect_mount_dirpath_call, dissect_mount1_mnt_reply },
864     { MOUNTPROC_DUMP,       "DUMP",
865                 NULL, dissect_mount_dump_reply },
866     { MOUNTPROC_UMNT,      "UMNT",
867                 dissect_mount_dirpath_call, NULL },
868     { MOUNTPROC_UMNTALL,   "UMNTALL",
869                 NULL, NULL },
870     { MOUNTPROC_EXPORT,    "EXPORT",
871                 NULL, dissect_mount_export_reply },
872     { MOUNTPROC_EXPORTALL, "EXPORTALL",
873                 NULL, dissect_mount_export_reply },
874     { MOUNTPROC_EXPORTLIST,"EXPORTLIST",
875                 NULL, dissect_mount_exportlist_reply },
876     { MOUNTPROC_STATVFS,   "STATVFS",
877                 dissect_mount_dirpath_call, dissect_mount_statvfs_reply },
878     { 0, NULL, NULL, NULL }
879 };
880 static const value_string sgi_mount1_proc_vals[] = {
881     { 0, "NULL" },
882     { MOUNTPROC_MNT,        "MNT" },
883     { MOUNTPROC_DUMP,       "DUMP" },
884     { MOUNTPROC_UMNT,       "UMNT" },
885     { MOUNTPROC_UMNTALL,    "UMNTALL" },
886     { MOUNTPROC_EXPORT,     "EXPORT" },
887     { MOUNTPROC_EXPORTALL,  "EXPORTALL" },
888     { MOUNTPROC_EXPORTLIST, "EXPORTLIST" },
889     { MOUNTPROC_STATVFS,    "STATVFS" },
890     { 0, NULL }
891 };
892 /* end of SGI mount protocol version 1 */
893
894 void
895 proto_register_mount(void)
896 {
897         static hf_register_info hf[] = {
898                 { &hf_mount_procedure_v1, {
899                         "V1 Procedure", "mount.procedure_v1", FT_UINT32, BASE_DEC,
900                         VALS(mount1_proc_vals), 0, "V1 Procedure", HFILL }},
901                 { &hf_mount_procedure_v2, {
902                         "V2 Procedure", "mount.procedure_v2", FT_UINT32, BASE_DEC,
903                         VALS(mount2_proc_vals), 0, "V2 Procedure", HFILL }},
904                 { &hf_mount_procedure_v3, {
905                         "V3 Procedure", "mount.procedure_v3", FT_UINT32, BASE_DEC,
906                         VALS(mount3_proc_vals), 0, "V3 Procedure", HFILL }},
907                 { &hf_sgi_mount_procedure_v1, {
908                         "SGI V1 procedure", "mount.procedure_sgi_v1", FT_UINT32, BASE_DEC,
909                         VALS(sgi_mount1_proc_vals), 0, "SGI V1 Procedure", HFILL }},
910                 { &hf_mount_path, {
911                         "Path", "mount.path", FT_STRING, BASE_DEC,
912                         NULL, 0, "Path", HFILL }},
913                 { &hf_mount3_status, {
914                         "Status", "mount.status", FT_UINT32, BASE_DEC,
915                         VALS(mount3_mountstat3), 0, "Status", HFILL }},
916                 { &hf_mount_mountlist_hostname, {
917                         "Hostname", "mount.dump.hostname", FT_STRING, BASE_DEC,
918                         NULL, 0, "Hostname", HFILL }},
919                 { &hf_mount_mountlist_directory, {
920                         "Directory", "mount.dump.directory", FT_STRING, BASE_DEC,
921                         NULL, 0, "Directory", HFILL }},
922                 { &hf_mount_mountlist, {
923                         "Mount List Entry", "mount.dump.entry", FT_NONE, 0,
924                         NULL, 0, "Mount List Entry", HFILL }},
925                 { &hf_mount_groups_group, {
926                         "Group", "mount.export.group", FT_STRING, BASE_DEC,
927                         NULL, 0, "Group", HFILL }},
928                 { &hf_mount_groups, {
929                         "Groups", "mount.export.groups", FT_NONE, 0,
930                         NULL, 0, "Groups", HFILL }},
931                 { &hf_mount_has_options, {
932                         "Has options", "mount.export.has_options", FT_UINT32,
933                          BASE_DEC, NULL, 0, "Has options", HFILL }},
934                 { &hf_mount_options, {
935                         "Options", "mount.export.options", FT_STRING, BASE_DEC,
936                         NULL, 0, "Options", HFILL }},
937                 { &hf_mount_exportlist_directory, {
938                         "Directory", "mount.export.directory", FT_STRING, BASE_DEC,
939                         NULL, 0, "Directory", HFILL }},
940                 { &hf_mount_exportlist, {
941                         "Export List Entry", "mount.export.entry", FT_NONE, 0,
942                         NULL, 0, "Export List Entry", HFILL }},
943                 { &hf_mount_pathconf_link_max, {
944                         "Maximum number of links to a file", "mount.pathconf.link_max",
945                         FT_UINT32, BASE_DEC,
946                         NULL, 0, "Maximum number of links allowed to a file", HFILL }},
947                 { &hf_mount_pathconf_max_canon, {
948                         "Maximum terminal input line length", "mount.pathconf.max_canon",
949                         FT_UINT16, BASE_DEC,
950                         NULL, 0, "Max tty input line length", HFILL }},
951                 { &hf_mount_pathconf_max_input, {
952                         "Terminal input buffer size", "mount.pathconf.max_input",
953                         FT_UINT16, BASE_DEC,
954                         NULL, 0, "Terminal input buffer size", HFILL }},
955                 { &hf_mount_pathconf_name_max, {
956                         "Maximum file name length", "mount.pathconf.name_max",
957                         FT_UINT16, BASE_DEC,
958                         NULL, 0, "Maximum file name length", HFILL }},
959                 { &hf_mount_pathconf_path_max, {
960                         "Maximum path name length", "mount.pathconf.path_max",
961                         FT_UINT16, BASE_DEC,
962                         NULL, 0, "Maximum path name length", HFILL }},
963                 { &hf_mount_pathconf_pipe_buf, {
964                         "Pipe buffer size", "mount.pathconf.pipe_buf",
965                         FT_UINT16, BASE_DEC,
966                         NULL, 0, "Maximum amount of data that can be written atomically to a pipe", HFILL }},
967                 { &hf_mount_pathconf_vdisable, {
968                         "VDISABLE character", "mount.pathconf.vdisable_char",
969                         FT_UINT8, BASE_HEX,
970                         NULL, 0, "Character value to disable a terminal special character", HFILL }},
971                 { &hf_mount_pathconf_mask, {
972                         "Reply error/status bits", "mount.pathconf.mask",
973                         FT_UINT16, BASE_HEX,
974                         NULL, 0, "Bit mask with error and status bits", HFILL }},
975                 { &hf_mount_pathconf_error_all, {
976                         "ERROR_ALL",    "mount.pathconf.mask.error_all",
977                         FT_BOOLEAN, 16, TFS(&tos_error_all),
978                         PC_ERROR_ALL, "", HFILL }},
979                 { &hf_mount_pathconf_error_link_max, {
980                         "ERROR_LINK_MAX", "mount.pathconf.mask.error_link_max",
981                         FT_BOOLEAN, 16, TFS(&tos_error_link_max),
982                         PC_ERROR_LINK_MAX, "", HFILL }},
983                 { &hf_mount_pathconf_error_max_canon, {
984                         "ERROR_MAX_CANON", "mount.pathconf.mask.error_max_canon",
985                         FT_BOOLEAN, 16, TFS(&tos_error_max_canon),
986                         PC_ERROR_MAX_CANON, "", HFILL }},
987                 { &hf_mount_pathconf_error_max_input, {
988                         "ERROR_MAX_INPUT", "mount.pathconf.mask.error_max_input",
989                         FT_BOOLEAN, 16, TFS(&tos_error_max_input),
990                         PC_ERROR_MAX_INPUT, "", HFILL }},
991                 { &hf_mount_pathconf_error_name_max, {
992                         "ERROR_NAME_MAX", "mount.pathconf.mask.error_name_max",
993                         FT_BOOLEAN, 16, TFS(&tos_error_name_max),
994                         PC_ERROR_NAME_MAX, "", HFILL }},
995                 { &hf_mount_pathconf_error_path_max, {
996                         "ERROR_PATH_MAX", "mount.pathconf.mask.error_path_max",
997                         FT_BOOLEAN, 16, TFS(&tos_error_path_max),
998                         PC_ERROR_PATH_MAX, "", HFILL }},
999                 { &hf_mount_pathconf_error_pipe_buf, {
1000                         "ERROR_PIPE_BUF", "mount.pathconf.mask.error_pipe_buf",
1001                         FT_BOOLEAN, 16, TFS(&tos_error_pipe_buf),
1002                         PC_ERROR_PIPE_BUF, "", HFILL }},
1003                 { &hf_mount_pathconf_chown_restricted, {
1004                         "CHOWN_RESTRICTED", "mount.pathconf.mask.chown_restricted",
1005                         FT_BOOLEAN, 16, TFS(&tos_chown_restricted),
1006                         PC_CHOWN_RESTRICTED, "", HFILL }},
1007                 { &hf_mount_pathconf_no_trunc, {
1008                         "NO_TRUNC", "mount.pathconf.mask.no_trunc",
1009                         FT_BOOLEAN, 16, TFS(&tos_no_trunc),
1010                         PC_NO_TRUNC, "", HFILL }},
1011                 { &hf_mount_pathconf_error_vdisable, {
1012                         "ERROR_VDISABLE", "mount.pathconf.mask.error_vdisable",
1013                         FT_BOOLEAN, 16, TFS(&tos_error_vdisable),
1014                         PC_ERROR_VDISABLE, "", HFILL }},
1015                 { &hf_mount_statvfs_bsize, {
1016                         "Block size", "mount.statvfs.f_bsize",
1017                         FT_UINT32, BASE_DEC, NULL, 0,
1018                         "File system block size", HFILL }},
1019                 { &hf_mount_statvfs_frsize, {
1020                         "Fragment size", "mount.statvfs.f_frsize",
1021                         FT_UINT32, BASE_DEC, NULL, 0,
1022                         "File system fragment size", HFILL }},
1023                 { &hf_mount_statvfs_blocks, {
1024                         "Blocks", "mount.statvfs.f_blocks",
1025                         FT_UINT32, BASE_DEC, NULL, 0,
1026                         "Total fragment sized blocks", HFILL }},
1027                 { &hf_mount_statvfs_bfree, {
1028                         "Blocks Free", "mount.statvfs.f_bfree",
1029                         FT_UINT32, BASE_DEC, NULL, 0,
1030                         "Free fragment sized blocks", HFILL }},
1031                 { &hf_mount_statvfs_bavail, {
1032                         "Blocks Available", "mount.statvfs.f_bavail",
1033                         FT_UINT32, BASE_DEC, NULL, 0,
1034                         "Available fragment sized blocks", HFILL }},
1035                 { &hf_mount_statvfs_files, {
1036                         "Files", "mount.statvfs.f_files",
1037                         FT_UINT32, BASE_DEC, NULL, 0,
1038                         "Total files/inodes", HFILL }},
1039                 { &hf_mount_statvfs_ffree, {
1040                         "Files Free", "mount.statvfs.f_ffree",
1041                         FT_UINT32, BASE_DEC, NULL, 0,
1042                         "Free files/inodes", HFILL }},
1043                 { &hf_mount_statvfs_favail, {
1044                         "Files Available", "mount.statvfs.f_favail",
1045                         FT_UINT32, BASE_DEC, NULL, 0,
1046                         "Available files/inodes",  HFILL }},
1047                 { &hf_mount_statvfs_fsid, {
1048                         "File system ID", "mount.statvfs.f_fsid",
1049                         FT_UINT32, BASE_DEC, NULL, 0,
1050                         "File system identifier", HFILL }},
1051                 { &hf_mount_statvfs_basetype, {
1052                         "Type", "mount.statvfs.f_basetype",
1053                         FT_STRING, BASE_DEC, NULL, 0,
1054                         "File system type", HFILL }},
1055                 { &hf_mount_statvfs_flag, {
1056                         "Flags", "mount.statvfs.f_flag",
1057                         FT_UINT32, BASE_HEX, NULL, 0,
1058                         "Flags bit-mask", HFILL }},
1059                 { &hf_mount_statvfs_flag_rdonly, {
1060                         "ST_RDONLY", "mount.statvfs.f_flag.st_rdonly",
1061                         FT_BOOLEAN, 32, TFS(&tos_st_rdonly), ST_RDONLY,
1062                         "", HFILL }},
1063                 { &hf_mount_statvfs_flag_nosuid, {
1064                         "ST_NOSUID", "mount.statvfs.f_flag.st_nosuid",
1065                         FT_BOOLEAN, 32, TFS(&tos_st_nosuid), ST_NOSUID,
1066                         "", HFILL }},
1067                 { &hf_mount_statvfs_flag_notrunc, {
1068                         "ST_NOTRUNC", "mount.statvfs.f_flag.st_notrunc",
1069                         FT_BOOLEAN, 32, TFS(&tos_st_notrunc), ST_NOTRUNC,
1070                         "", HFILL }},
1071                 { &hf_mount_statvfs_flag_nodev, {
1072                         "ST_NODEV", "mount.statvfs.f_flag.st_nodev",
1073                          FT_BOOLEAN, 32, TFS(&tos_st_nodev), ST_NODEV,
1074                         "", HFILL }},
1075                 { &hf_mount_statvfs_flag_grpid, {
1076                         "ST_GRPID", "mount.statvfs.f_flag.st_grpid",
1077                         FT_BOOLEAN, 32, TFS(&tos_st_grpid), ST_GRPID,
1078                         "", HFILL }},
1079                 { &hf_mount_statvfs_flag_local, {
1080                         "ST_LOCAL", "mount.statvfs.f_flag.st_local",
1081                         FT_BOOLEAN, 32, TFS(&tos_st_local), ST_LOCAL,
1082                         "", HFILL }},
1083                 { &hf_mount_statvfs_namemax, {
1084                         "Maximum file name length", "mount.statvfs.f_namemax",
1085                         FT_UINT32, BASE_DEC, NULL, 0,
1086                         "Maximum file name length", HFILL }},
1087                 { &hf_mount_statvfs_fstr, {
1088                         "File system specific string", "mount.statvfs.f_fstr",
1089                         FT_BYTES, BASE_HEX, NULL, 0,
1090                         "File system specific string", HFILL }},
1091                 { &hf_mount_flavors, {
1092                         "Flavors", "mount.flavors", FT_UINT32, BASE_DEC,
1093                         NULL, 0, "Flavors", HFILL }},
1094                 { &hf_mount_flavor, {
1095                         "Flavor", "mount.flavor", FT_UINT32, BASE_DEC,
1096                         VALS(rpc_auth_flavor), 0, "Flavor", HFILL }},
1097         };
1098         static gint *ett[] = {
1099                 &ett_mount,
1100                 &ett_mount_mountlist,
1101                 &ett_mount_groups,
1102                 &ett_mount_exportlist,
1103                 &ett_mount_pathconf_mask,
1104                 &ett_mount_statvfs_flag,
1105         };
1106
1107         proto_mount = proto_register_protocol("Mount Service", "MOUNT",
1108             "mount");
1109         proto_sgi_mount = proto_register_protocol("SGI Mount Service",
1110             "SGI MOUNT", "sgimount");
1111         proto_register_field_array(proto_mount, hf, array_length(hf));
1112         proto_register_subtree_array(ett, array_length(ett));
1113 }
1114
1115 void
1116 proto_reg_handoff_mount(void)
1117 {
1118         /* Register the protocol as RPC */
1119         rpc_init_prog(proto_mount, MOUNT_PROGRAM, ett_mount);
1120         rpc_init_prog(proto_sgi_mount, SGI_MOUNT_PROGRAM, ett_mount);
1121         /* Register the procedure tables */
1122         rpc_init_proc_table(MOUNT_PROGRAM, 1, mount1_proc, hf_mount_procedure_v1);
1123         rpc_init_proc_table(MOUNT_PROGRAM, 2, mount2_proc, hf_mount_procedure_v2);
1124         rpc_init_proc_table(MOUNT_PROGRAM, 3, mount3_proc, hf_mount_procedure_v3);
1125         rpc_init_proc_table(SGI_MOUNT_PROGRAM, 1, sgi_mount1_proc, hf_sgi_mount_procedure_v1);
1126 }