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