Add HP Switch Protocol SAP value
[obnox/wireshark/wip.git] / epan / dissectors / packet-9p.c
1 /* packet-9P.c
2  * Routines for 9P dissection
3  * Copyright 2005, Nils O. SelÃ¥sdal
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * File permission bits decoding taken from packet-nfs.c
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  * 
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  * 
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include <glib.h>
37
38 #include <epan/packet.h>
39 #include <epan/strutil.h>
40
41 #define NINEPORT 564
42
43 /*Message types for 9P */
44 /*See man 5 intro on Plan 9 - or;
45         http://www.cs.bell-labs.com/sys/man/5/INDEX.html
46 */
47 enum {
48         TVERSION        = 100,
49         RVERSION        = 101,
50         TAUTH           = 102,
51         RAUTH           = 103,
52         TATTACH         = 104,
53         RATTACH         = 105,
54         TERROR          = 106,  /* Not used */
55         RERROR          = 107,
56         TFLUSH          = 108,
57         RFLUSH          = 109,
58         TWALK           = 110,
59         RWALK           = 111,
60         TOPEN = 112,
61         ROPEN,
62         TCREATE = 114,
63         RCREATE,
64         TREAD = 116,
65         RREAD,
66         TWRITE = 118,
67         RWRITE,
68         TCLUNK = 120,
69         RCLUNK,
70         TREMOVE = 122,
71         RREMOVE,
72         TSTAT = 124,
73         RSTAT,
74         TWSTAT = 126,
75         RWSTAT
76 };
77 /* File open modes */
78 #define P9_OREAD           0x0 
79 #define P9_OWRITE          0x1 
80 #define P9_ORDWR           0x2 
81 #define P9_OEXEC           0x3
82 #define P9_MODEMASK        0x3 
83 #define P9_OTRUNC         0x10 
84 #define P9_ORCLOSE        0x40 
85
86 /* stat mode flags */
87 #define DMDIR           0x80000000 /* Directory */
88 #define DMAPPEND        0x40000000 /* Append only */
89 #define DMEXCL          0x20000000 /* Exclusive use */
90 #define DMMOUNT         0x10000000 /* Mounted channel */
91 #define DMAUTH          0x08000000 /* Authentication */
92 #define DMTMP           0x04000000 /* Temporary */
93
94 #define QTDIR           0x80    /* Directory */
95 #define QTAPPEND        0x40    /* Append only */
96 #define QTEXCL          0x20    /* Exclusive use */
97 #define QTMOUNT         0x10    /* Mounted channel */
98 #define QTAUTH          0x08    /* Authentication */
99 #define QTTMP           0x04    /* Temporary */
100 #define QTFILE          0x00    /* plain file ?? */
101
102 /* Initialize the protocol and registered fields */
103 static int proto_9P = -1;
104 static int hf_9P_msgsz = -1;
105 static int hf_9P_msgtype = -1;
106 static int hf_9P_tag = -1;
107 static int hf_9P_oldtag = -1;
108 static int hf_9P_parmsz = -1;
109 static int hf_9P_maxsize = -1;
110 static int hf_9P_fid = -1;
111 static int hf_9P_nqid = -1;
112 static int hf_9P_mode = -1;
113 static int hf_9P_mode_rwx = -1;
114 static int hf_9P_mode_t = -1;
115 static int hf_9P_mode_c = -1;
116 static int hf_9P_iounit = -1;
117 static int hf_9P_count = -1;
118 static int hf_9P_offset = -1;
119 static int hf_9P_perm = -1;
120 static int hf_9P_qidtype = -1;
121 static int hf_9P_qidvers = -1;
122 static int hf_9P_qidpath = -1;
123 static int hf_9P_stattype = -1;
124 static int hf_9P_statmode = -1;
125 static int hf_9P_atime = -1;
126 static int hf_9P_mtime = -1;
127 static int hf_9P_length = -1;
128 static int hf_9P_dev = -1;
129 static int hf_9P_wname = -1;
130 static int hf_9P_version = -1;
131 static int hf_9P_afid = -1;
132 static int hf_9P_uname = -1;
133 static int hf_9P_aname = -1;
134 static int hf_9P_ename = -1;
135 static int hf_9P_name = -1;
136 static int hf_9P_filename = -1;
137 static int hf_9P_sdlen = -1;
138 static int hf_9P_uid = -1;
139 static int hf_9P_gid = -1;
140 static int hf_9P_muid = -1;
141 static int hf_9P_nwalk = -1;
142 static int hf_9P_newfid = -1;
143
144 /*handle for dissecting data in 9P msgs*/
145 static dissector_handle_t data_handle;
146
147 /* subtree pointers */
148 static gint ett_9P = -1;
149 static gint ett_9P_omode = -1;
150 static gint ett_9P_dm = -1;
151 static gint ett_9P_wname = -1;
152 static gint ett_9P_aname = -1;
153 static gint ett_9P_ename = -1;
154 static gint ett_9P_uname = -1;
155 static gint ett_9P_uid = -1;
156 static gint ett_9P_gid = -1;
157 static gint ett_9P_muid = -1;
158 static gint ett_9P_filename = -1;
159 static gint ett_9P_version = -1;
160 static gint ett_9P_qid = -1;
161 static gint ett_9P_qidtype = -1;
162
163 /*9P Msg types to name mapping */
164 static const value_string ninep_msg_type[] = 
165 {       {TVERSION,      "Tversion"},
166         {RVERSION,      "Rversion"},
167         {TAUTH,         "Tauth"},
168         {RAUTH,         "Rauth"},
169         {TATTACH,       "Tattach"},
170         {RATTACH,       "Rattach"},
171         {RERROR,        "Rerror"},
172         {TFLUSH,        "Tflush"},
173         {RFLUSH,        "Rflush"},
174         {TWALK,         "Twalk"},
175         {RWALK,         "Rwalk"},
176         {TOPEN,         "Topen"},
177         {ROPEN,         "Ropen"},
178         {TCREATE,       "Tcreate"},
179         {RCREATE,       "Rcreate"},
180         {TREAD,         "Tread"},
181         {RREAD,         "Rread"},
182         {TWRITE,        "Twrite"},
183         {RWRITE,        "Rwrite"},
184         {TCLUNK,        "Tclunk"},
185         {RCLUNK,        "Rclunk"},
186         {TREMOVE,       "Tremove"},
187         {RREMOVE,       "Rremove"},
188         {TSTAT,         "Tstat"},
189         {RSTAT,         "Rstat"},
190         {TWSTAT,        "Twstat"},
191         {RWSTAT,        "Rwstat"},
192         {0,             NULL},
193 };
194 /* Open/Create modes */
195 static const value_string ninep_mode_vals[] = 
196 {
197         {P9_OREAD,      "Read Access"},
198         {P9_OWRITE,     "Write Access"},
199         {P9_ORDWR,      "Read/Write Access "},
200         {P9_OEXEC,      "Execute Access"},
201         {0,             NULL}
202 };
203
204 static void dissect_9P_mode(tvbuff_t * tvb,  proto_item * tree,int offset);
205 static void dissect_9P_dm(tvbuff_t * tvb,  proto_item * tree,int offset,int iscreate);
206 static void dissect_9P_qid(tvbuff_t * tvb,  proto_tree * tree,int offset);
207
208 /* Dissect 9P messages*/
209 static void dissect_9P(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
210 {
211         guint32 ninesz,tmp,i;
212         guint16 tmp16;
213         guint8 ninemsg;
214         guint offset = 0;
215         const char *mname;
216         gint len,reportedlen;
217         tvbuff_t *next_tvb;
218         proto_item *ti;
219         proto_tree *ninep_tree,*tmp_tree;
220         nstime_t tv;
221
222         if (check_col(pinfo->cinfo, COL_PROTOCOL))
223                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "9P");
224         if (check_col(pinfo->cinfo, COL_INFO)) 
225                 col_clear(pinfo->cinfo, COL_INFO);
226
227         ninesz = tvb_get_letohl(tvb, offset);
228         ninemsg = tvb_get_guint8(tvb, offset + 4);
229
230         mname = val_to_str(ninemsg, ninep_msg_type,"Unknown");
231         
232         if(strcmp(mname,"Unknown") == 0) {
233                 if (check_col(pinfo->cinfo, COL_INFO))
234                         col_add_fstr(pinfo->cinfo, COL_INFO, "9P Data Continuitation(?) (Tag %u)",(guint)ninemsg);
235
236                 return;
237         }
238
239         if (check_col(pinfo->cinfo, COL_INFO))
240                 col_append_fstr(pinfo->cinfo, COL_INFO, "%s Tag=%u",mname,(guint)tvb_get_letohs(tvb,offset+5));
241
242         if (!tree) /*not much more of one line summary interrest yet.. */
243                 return;
244
245         ti = proto_tree_add_item(tree, proto_9P, tvb, 0, -1, FALSE);
246         ninep_tree = proto_item_add_subtree(ti, ett_9P);
247         proto_tree_add_item(ninep_tree, hf_9P_msgsz, tvb, offset, 4, TRUE);
248         offset+=4;
249
250         proto_tree_add_item(ninep_tree, hf_9P_msgtype, tvb, offset, 1, TRUE);
251         ++offset;
252         proto_tree_add_item(ninep_tree, hf_9P_tag, tvb, offset, 2, TRUE);
253         offset += 2;
254
255         switch(ninemsg) {
256         case RVERSION:
257         case TVERSION:
258                 proto_tree_add_item(ninep_tree, hf_9P_maxsize, tvb, offset, 4, TRUE);
259                 offset +=4;
260
261                 tmp16 = tvb_get_letohs(tvb,offset);
262                 ti = proto_tree_add_item(ninep_tree, hf_9P_version, tvb, offset+2, tmp16, TRUE);
263                 tmp_tree = proto_item_add_subtree(ti,ett_9P_version);   
264                 proto_tree_add_item(tmp_tree, hf_9P_parmsz, tvb, offset, 2, TRUE);
265                 offset += 2;
266                 break;
267         case TAUTH:
268                 proto_tree_add_item(ninep_tree, hf_9P_afid, tvb, offset, 4, TRUE);
269                 offset +=4;
270
271                 tmp16 = tvb_get_letohs(tvb,offset);
272                 ti = proto_tree_add_item(ninep_tree, hf_9P_uname, tvb, offset+2, tmp16, TRUE);
273                 tmp_tree = proto_item_add_subtree(ti,ett_9P_uname);
274                 proto_tree_add_item(tmp_tree, hf_9P_parmsz, tvb, offset, 2, TRUE);
275                 offset += tmp16+2;
276
277                 tmp16 = tvb_get_letohs(tvb,offset);
278                 ti = proto_tree_add_item(ninep_tree, hf_9P_aname, tvb, offset+2, tmp16, TRUE);
279                 tmp_tree = proto_item_add_subtree(ti,ett_9P_aname);
280                 proto_tree_add_item(tmp_tree, hf_9P_parmsz, tvb, offset, 2, TRUE);
281                 offset +=2;
282                 break;
283         case RAUTH:
284                 dissect_9P_qid(tvb,ninep_tree,offset);
285                 offset += 13;
286                 break;
287         case RERROR:
288                 tmp16 = tvb_get_letohs(tvb,offset);
289                 ti = proto_tree_add_item(ninep_tree, hf_9P_ename, tvb, offset+2, tmp16, TRUE);
290                 tmp_tree = proto_item_add_subtree(ti,ett_9P_ename);
291                 proto_tree_add_item(tmp_tree, hf_9P_parmsz, tvb, offset, 2, TRUE);
292                 offset +=2;
293
294                 break;
295         case TFLUSH:
296                 proto_tree_add_item(ninep_tree, hf_9P_oldtag, tvb, offset, 2, TRUE);
297                 break;
298         case RFLUSH:
299                 break;
300         case TATTACH:
301                 proto_tree_add_item(ninep_tree, hf_9P_fid, tvb, offset, 4, TRUE);
302                 offset +=4;
303
304                 proto_tree_add_item(ninep_tree, hf_9P_afid, tvb, offset, 4, TRUE);
305                 offset +=4;
306
307                 tmp16 = tvb_get_letohs(tvb,offset);
308                 ti = proto_tree_add_item(ninep_tree, hf_9P_uname, tvb, offset+2, tmp16, TRUE);
309                 tmp_tree = proto_item_add_subtree(ti,ett_9P_uname);
310                 proto_tree_add_item(tmp_tree, hf_9P_parmsz, tvb, offset, 2, TRUE);
311                 offset += tmp16 + 2;
312
313                 tmp16 = tvb_get_letohs(tvb,offset);
314                 ti = proto_tree_add_item(ninep_tree, hf_9P_aname, tvb, offset+2, tmp16, TRUE);
315                 tmp_tree = proto_item_add_subtree(ti,ett_9P_aname);
316                 proto_tree_add_item(tmp_tree, hf_9P_parmsz, tvb, offset, 2, TRUE);
317                 offset += tmp16+2;
318                 break;
319         case RATTACH:
320                 dissect_9P_qid(tvb,ninep_tree,offset);
321                 offset += 13;
322                 break;
323         case TWALK:
324                 proto_tree_add_item(ninep_tree, hf_9P_fid, tvb, offset, 4, TRUE);
325                 offset +=4;
326
327                 proto_tree_add_item(ninep_tree, hf_9P_newfid, tvb, offset, 4, TRUE);
328                 offset +=4;
329                 
330                 tmp16 = tvb_get_letohs(tvb,offset);
331                 proto_tree_add_item(ninep_tree, hf_9P_nwalk, tvb, offset, 2, TRUE);
332                 offset +=2;
333                 /* I can't imagine anyone having a directory depth more than 25,
334                    Limit to 10 times that to be sure, 2^16 is too much */
335                 if(tmp16 > 250) {
336                         tmp16 = 250;
337                         tmp_tree = proto_tree_add_text(ninep_tree, tvb, 0, 0, "Only first 250 items shown");
338                         PROTO_ITEM_SET_GENERATED(tmp_tree);
339                 }
340
341                 for(i = 0 ; i < tmp16; i++) {
342                         guint16 tmplen;
343                         proto_item *wname;
344                         proto_tree *wname_tree;
345                         
346                         tmplen = tvb_get_letohs(tvb,offset);
347                         wname = proto_tree_add_item(ninep_tree, hf_9P_wname, tvb, offset+2, tmplen, TRUE);
348                         wname_tree = proto_item_add_subtree(wname,ett_9P_wname);
349                         proto_tree_add_item(wname_tree, hf_9P_parmsz, tvb, offset, 2, TRUE);
350
351                         offset += tmplen + 2;
352                 }
353
354                 break;
355         case RWALK:
356                 tmp16 = tvb_get_letohs(tvb,offset);
357                 proto_tree_add_item(ninep_tree, hf_9P_nqid, tvb, offset, 2, TRUE);
358                 offset +=2;
359                 /* I can't imagine anyone having a directory depth more than 25,
360                    Limit to 10 times that to be sure, 2^16 is too much */
361                 if(tmp16 > 250) {
362                         tmp16 = 250;
363                         tmp_tree = proto_tree_add_text(ninep_tree, tvb, 0, 0, "Only first 250 items shown");
364                         PROTO_ITEM_SET_GENERATED(tmp_tree);
365                 }
366
367                 for(i = 0; i < tmp16; i++) {
368                         dissect_9P_qid(tvb,ninep_tree,offset);
369                         offset += 13;
370                 }       
371                 break;  
372         case TOPEN:
373                 proto_tree_add_item(ninep_tree, hf_9P_fid, tvb, offset, 4, TRUE);
374                 offset +=4;
375                 ti = proto_tree_add_item(ninep_tree, hf_9P_mode, tvb, offset, 1, TRUE);
376                 dissect_9P_mode(tvb,ti,offset);
377                 break;
378         case ROPEN:
379                 dissect_9P_qid(tvb,ninep_tree,offset);
380                 offset += 13;
381                 proto_tree_add_item(ninep_tree, hf_9P_iounit, tvb, offset, 4, TRUE);
382                 break;
383         case TCREATE:
384                 proto_tree_add_item(ninep_tree, hf_9P_fid, tvb, offset, 4, TRUE);
385                 offset +=4;
386
387                 tmp16 = tvb_get_letohs(tvb,offset);
388                 ti = proto_tree_add_item(ninep_tree, hf_9P_name, tvb, offset+2, tmp16, TRUE);
389                 tmp_tree = proto_item_add_subtree(ti,ett_9P_filename);
390                 proto_tree_add_item(tmp_tree, hf_9P_parmsz, tvb, offset, 2, TRUE);
391                 offset += tmp16 + 2;
392
393                 ti = proto_tree_add_item(ninep_tree, hf_9P_perm, tvb, offset, 4, TRUE);
394                 dissect_9P_dm(tvb,ti,offset,1);
395                 offset +=4;
396
397                 ti = proto_tree_add_item(ninep_tree, hf_9P_mode, tvb, offset, 1, TRUE);
398                 dissect_9P_mode(tvb,ti,offset);
399
400                 break;
401         case RCREATE:
402                 dissect_9P_qid(tvb,ninep_tree,offset);
403                 offset += 13;
404                 proto_tree_add_item(ninep_tree, hf_9P_iounit, tvb, offset, 4, TRUE);
405                 break;
406         case TREAD:
407                 proto_tree_add_item(ninep_tree, hf_9P_fid, tvb, offset, 4, TRUE);
408                 offset +=4;
409
410                 proto_tree_add_item(ninep_tree, hf_9P_offset, tvb, offset, 8, TRUE);
411                 offset +=8;
412
413                 proto_tree_add_item(ninep_tree, hf_9P_count, tvb, offset, 4, TRUE);
414                 break;  
415         case RREAD:
416                 tmp = tvb_get_letohl(tvb,offset);
417                 proto_tree_add_item(ninep_tree, hf_9P_count, tvb, offset, 4, TRUE);
418                 offset += 4;
419
420                 len = tvb_reported_length_remaining(tvb, offset);
421                 reportedlen = ((gint)tmp&0xffff) > len ? len : (gint)tmp&0xffff;
422                 next_tvb = tvb_new_subset(tvb, offset, len, reportedlen);
423                 call_dissector(data_handle,next_tvb, pinfo, tree);
424                 break;
425         case TWRITE:
426                 proto_tree_add_item(ninep_tree, hf_9P_fid, tvb, offset, 4, TRUE);
427                 offset +=4;
428
429                 proto_tree_add_item(ninep_tree, hf_9P_offset, tvb, offset, 8, TRUE);
430                 offset +=8;
431
432                 tmp = tvb_get_letohl(tvb,offset);
433                 proto_tree_add_item(ninep_tree, hf_9P_count, tvb, offset, 4, TRUE);
434                 offset += 4;
435                 len = tvb_reported_length_remaining(tvb, offset);
436                 reportedlen = ((gint)tmp&0xffff) > len ? len : (gint)tmp&0xffff;
437                 next_tvb = tvb_new_subset(tvb, offset, len, reportedlen);
438                 call_dissector(data_handle,next_tvb, pinfo, tree);
439                 break;
440         case RWRITE:
441                 proto_tree_add_item(ninep_tree, hf_9P_count, tvb, offset, 4, TRUE);
442                 break;
443         case TCLUNK:
444                 proto_tree_add_item(ninep_tree, hf_9P_fid, tvb, offset, 4, TRUE);
445
446                 break;
447         case RCLUNK:
448                 break;
449         case TREMOVE:
450                 proto_tree_add_item(ninep_tree, hf_9P_fid, tvb, offset, 4, TRUE);
451
452                 break;
453         case RREMOVE:
454                 break;
455         case TSTAT:
456                 proto_tree_add_item(ninep_tree, hf_9P_fid, tvb, offset, 4, TRUE);
457                 break;
458         case RSTAT:
459                 proto_tree_add_item(ninep_tree, hf_9P_parmsz, tvb, offset, 2, TRUE);
460                 offset +=2;
461
462                 proto_tree_add_item(ninep_tree, hf_9P_sdlen, tvb, offset, 2, TRUE);
463                 offset +=2;
464
465                 proto_tree_add_item(ninep_tree, hf_9P_stattype, tvb, offset, 2, TRUE);
466                 offset +=2;
467
468                 proto_tree_add_item(ninep_tree, hf_9P_dev, tvb, offset, 4, TRUE);
469                 offset +=4;
470
471                 dissect_9P_qid(tvb,ninep_tree,offset);
472                 offset += 13;
473
474                 ti = proto_tree_add_item(ninep_tree, hf_9P_statmode, tvb, offset, 4, TRUE);
475                 dissect_9P_dm(tvb,ti,offset,0);
476                 offset +=4;
477
478                 tv.secs = tvb_get_letohl(tvb,offset);
479                 tv.nsecs = 0;
480                 proto_tree_add_time(ninep_tree, hf_9P_atime, tvb, offset, 4, &tv);
481                 offset +=4;
482
483                 tv.secs = tvb_get_letohl(tvb,offset);
484                 tv.nsecs = 0;
485                 proto_tree_add_time(ninep_tree, hf_9P_mtime, tvb, offset, 4, &tv);
486                 offset +=4;
487
488                 proto_tree_add_item(ninep_tree, hf_9P_length, tvb, offset, 8, TRUE);
489                 offset +=8;
490
491                 tmp16 = tvb_get_letohs(tvb,offset);
492                 ti = proto_tree_add_item(ninep_tree, hf_9P_filename, tvb, offset+2, tmp16, TRUE);
493                 tmp_tree = proto_item_add_subtree(ti,ett_9P_filename);
494                 proto_tree_add_item(tmp_tree, hf_9P_parmsz, tvb, offset, 2, TRUE);
495                 offset += tmp16+2;
496
497                 tmp16 = tvb_get_letohs(tvb,offset);
498                 ti = proto_tree_add_item(ninep_tree, hf_9P_uid, tvb, offset+2, tmp16, TRUE);
499                 tmp_tree = proto_item_add_subtree(ti,ett_9P_uid);
500                 proto_tree_add_item(tmp_tree, hf_9P_parmsz, tvb, offset, 2, TRUE);
501                 offset += tmp16+2;
502
503                 tmp16 = tvb_get_letohs(tvb,offset);
504                 ti = proto_tree_add_item(ninep_tree, hf_9P_gid, tvb, offset+2, tmp16, TRUE);
505                 tmp_tree = proto_item_add_subtree(ti,ett_9P_gid);
506                 proto_tree_add_item(tmp_tree, hf_9P_parmsz, tvb, offset, 2, TRUE);
507                 offset += tmp16+2;
508
509                 tmp16 = tvb_get_letohs(tvb,offset);
510                 ti = proto_tree_add_item(ninep_tree, hf_9P_muid, tvb, offset+2, tmp16, TRUE);
511                 tmp_tree = proto_item_add_subtree(ti,ett_9P_muid);
512                 proto_tree_add_item(tmp_tree, hf_9P_parmsz, tvb, offset, 2, TRUE);
513                 offset += tmp16+2;
514                 break;
515         case TWSTAT:
516                 proto_tree_add_item(ninep_tree, hf_9P_fid, tvb, offset, 4, TRUE);
517                 offset += 4;
518
519                 proto_tree_add_item(ninep_tree, hf_9P_parmsz, tvb, offset, 2, TRUE);
520                 offset +=2;
521
522                 proto_tree_add_item(ninep_tree, hf_9P_sdlen, tvb, offset, 2, TRUE);
523                 offset +=2;
524
525                 proto_tree_add_item(ninep_tree, hf_9P_stattype, tvb, offset, 2, TRUE);
526                 offset +=2;
527
528                 proto_tree_add_item(ninep_tree, hf_9P_dev, tvb, offset, 4, TRUE);
529                 offset +=4;
530
531                 dissect_9P_qid(tvb,ninep_tree,offset);
532                 offset += 13;
533
534                 ti = proto_tree_add_item(ninep_tree, hf_9P_statmode, tvb, offset, 4, TRUE);
535                 dissect_9P_dm(tvb,ti,offset,0);
536                 offset +=4;
537
538                 tv.secs = tvb_get_letohl(tvb,offset);
539                 tv.nsecs = 0;
540                 proto_tree_add_time(ninep_tree, hf_9P_atime, tvb, offset, 4, &tv);
541                 offset +=4;
542
543                 tv.secs = tvb_get_letohl(tvb,offset);
544                 tv.nsecs = 0;
545                 proto_tree_add_time(ninep_tree, hf_9P_mtime, tvb, offset, 4, &tv);
546                 offset +=4;
547
548                 proto_tree_add_item(ninep_tree, hf_9P_length, tvb, offset, 8, TRUE);
549                 offset +=8;
550
551                 tmp16 = tvb_get_letohs(tvb,offset);
552                 ti = proto_tree_add_item(ninep_tree, hf_9P_filename, tvb, offset+2, tmp16, TRUE);
553                 tmp_tree = proto_item_add_subtree(ti,ett_9P_filename);
554                 proto_tree_add_item(tmp_tree, hf_9P_parmsz, tvb, offset, 2, TRUE);
555                 offset += tmp16+2;
556
557                 tmp16 = tvb_get_letohs(tvb,offset);
558                 ti = proto_tree_add_item(ninep_tree, hf_9P_uid, tvb, offset+2, tmp16, TRUE);
559                 tmp_tree = proto_item_add_subtree(ti,ett_9P_uid);
560                 proto_tree_add_item(tmp_tree, hf_9P_parmsz, tvb, offset, 2, TRUE);
561                 offset += tmp16+2;
562
563                 tmp16 = tvb_get_letohs(tvb,offset);
564                 ti = proto_tree_add_item(ninep_tree, hf_9P_gid, tvb, offset+2, tmp16, TRUE);
565                 tmp_tree = proto_item_add_subtree(ti,ett_9P_gid);
566                 proto_tree_add_item(tmp_tree, hf_9P_parmsz, tvb, offset, 2, TRUE);
567                 offset += tmp16+2;
568
569                 tmp16 = tvb_get_letohs(tvb,offset);
570                 ti = proto_tree_add_item(ninep_tree, hf_9P_muid, tvb, offset+2, tmp16, TRUE);
571                 tmp_tree = proto_item_add_subtree(ti,ett_9P_muid);
572                 proto_tree_add_item(tmp_tree, hf_9P_parmsz, tvb, offset, 2, TRUE);
573                 offset += tmp16+2;
574                 break;
575         }
576 }
577 /* dissect 9P open mode flags */
578 static void dissect_9P_mode(tvbuff_t * tvb,  proto_item * item,int offset)
579 {
580         proto_item *mode_tree;
581         guint8 mode;
582
583         mode = tvb_get_guint8(tvb,offset);
584         mode_tree = proto_item_add_subtree(item, ett_9P_omode);
585         if(!mode_tree)
586                 return;
587         proto_tree_add_boolean(mode_tree, hf_9P_mode_c, tvb, offset, 1, mode);
588         proto_tree_add_boolean(mode_tree, hf_9P_mode_t, tvb, offset, 1, mode);
589         proto_tree_add_item(mode_tree, hf_9P_mode_rwx, tvb, offset, 1, mode);
590 }
591
592 /* dissect 9P Qid */
593 static void dissect_9P_qid(tvbuff_t * tvb,  proto_tree * tree,int offset)
594 {
595         proto_item *qid_item,*qidtype_item;
596         proto_tree *qid_tree,*qidtype_tree;
597         guint64 path;
598         guint32 vers;
599         guint8 type;
600
601         if(!tree)
602                 return;
603         
604         type = tvb_get_guint8(tvb,offset);
605         vers = tvb_get_letohs(tvb,offset+1);
606         path = tvb_get_letoh64(tvb,offset+1+4);
607
608         qid_item = proto_tree_add_text(tree,tvb,offset,13,"Qid type=0x%02x vers=%d path=%"PRIu64,type,vers,path);
609         qid_tree = proto_item_add_subtree(qid_item,ett_9P_qid);
610
611         qidtype_item = proto_tree_add_item(qid_tree, hf_9P_qidtype, tvb, offset, 1, TRUE);
612         qidtype_tree = proto_item_add_subtree(qidtype_item,ett_9P_qidtype);
613
614         proto_tree_add_text(qidtype_tree, tvb, offset, 1, "%s",
615         decode_boolean_bitfield(type,    QTDIR, 8, "Directory", "not a Directory"));
616         proto_tree_add_text(qidtype_tree, tvb, offset, 1, "%s",
617         decode_boolean_bitfield(type,    QTAPPEND, 8, "Append only", "not Append only"));
618         proto_tree_add_text(qidtype_tree, tvb, offset, 1, "%s",
619         decode_boolean_bitfield(type,    QTEXCL, 8, "Exclusive use", "not Exclusive use"));
620         proto_tree_add_text(qidtype_tree, tvb, offset, 1, "%s",
621         decode_boolean_bitfield(type,    QTMOUNT, 8, "Mounted channel", "not a Mounted channel"));
622         proto_tree_add_text(qidtype_tree, tvb, offset, 1, "%s",
623         decode_boolean_bitfield(type,    QTAUTH, 8, "Authentication file", "not an Authentication file"));
624         proto_tree_add_text(qidtype_tree, tvb, offset, 1, "%s",
625         decode_boolean_bitfield(type,    QTTMP, 8, "Temporary file (not backed up)", "not a Temporary file"));
626
627         proto_tree_add_item(qid_tree, hf_9P_qidvers, tvb, offset+1, 4, TRUE);
628         proto_tree_add_item(qid_tree, hf_9P_qidpath, tvb, offset+1+4, 8, TRUE);
629 }
630
631 /*dissect 9P stat mode and create perm flags */
632 static void dissect_9P_dm(tvbuff_t * tvb,  proto_item * item,int offset,int iscreate)
633 {
634         proto_item *mode_tree;
635         guint32 dm;
636
637
638         dm = tvb_get_letohl(tvb,offset);
639         mode_tree = proto_item_add_subtree(item, ett_9P_dm);
640         if(!mode_tree)
641                 return;
642
643         proto_tree_add_text(mode_tree, tvb, offset, 1, "%s",
644         decode_boolean_bitfield(dm,    DMDIR, 32, "Directory", "not a Directory"));
645         if(!iscreate) { /* Not applicable to Tcreate (?) */
646                 proto_tree_add_text(mode_tree, tvb, offset, 4, "%s",
647                 decode_boolean_bitfield(dm,    DMAPPEND, 32, "Append only", "not Append only"));
648                 proto_tree_add_text(mode_tree, tvb, offset, 4, "%s",
649                 decode_boolean_bitfield(dm,    DMEXCL, 32, "Exclusive use", "not Exclusive use"));
650                 proto_tree_add_text(mode_tree, tvb, offset, 4, "%s",
651                 decode_boolean_bitfield(dm,    DMMOUNT, 32, "Mounted channel", "not a Mounted channel"));
652                 proto_tree_add_text(mode_tree, tvb, offset, 4, "%s",
653                 decode_boolean_bitfield(dm,    DMAUTH, 32, "Authentication file", "not an Authentication file"));
654                 proto_tree_add_text(mode_tree, tvb, offset, 4, "%s",
655                 decode_boolean_bitfield(dm,    DMTMP, 32, "Temporary file (not backed up)", "not a Temporary file"));
656         }
657
658         proto_tree_add_text(mode_tree, tvb, offset, 4, "%s",
659         decode_boolean_bitfield(dm,    0400, 32, "Read permission for owner", "no Read permission for owner"));
660         proto_tree_add_text(mode_tree, tvb, offset, 4, "%s",
661         decode_boolean_bitfield(dm,    0200, 32, "Write permission for owner", "no Write permission for owner"));
662         proto_tree_add_text(mode_tree, tvb, offset, 4, "%s",
663         decode_boolean_bitfield(dm,    0100, 32, "Execute permission for owner", "no Execute permission for owner"));
664         proto_tree_add_text(mode_tree, tvb, offset, 4, "%s",
665         decode_boolean_bitfield(dm,     040, 32, "Read permission for group", "no Read permission for group"));
666         proto_tree_add_text(mode_tree, tvb, offset, 4, "%s",
667         decode_boolean_bitfield(dm,     020, 32, "Write permission for group", "no Write permission for group"));
668         proto_tree_add_text(mode_tree, tvb, offset, 4, "%s",
669         decode_boolean_bitfield(dm,     010, 32, "Execute permission for group", "no Execute permission for group"));
670         proto_tree_add_text(mode_tree, tvb, offset, 4, "%s",
671         decode_boolean_bitfield(dm,      04, 32, "Read permission for others", "no Read permission for others"));
672         proto_tree_add_text(mode_tree, tvb, offset, 4, "%s",
673         decode_boolean_bitfield(dm,      02, 32, "Write permission for others", "no Write permission for others"));
674         proto_tree_add_text(mode_tree, tvb, offset, 4, "%s",
675         decode_boolean_bitfield(dm,      01, 32, "Execute permission for others", "no Execute permission for others"));
676 }
677
678 /* Register 9P with Wireshark */
679 void proto_register_9P(void);
680
681 void proto_register_9P(void)
682 {
683         static hf_register_info hf[] = {
684                 {&hf_9P_msgsz,
685                  {"Msg length", "9p.msglen", FT_UINT32, BASE_DEC, NULL, 0x0,
686                   "9P Message Length", HFILL}},
687                 {&hf_9P_msgtype,
688                  {"Msg Type", "9p.msgtype", FT_UINT8, BASE_DEC, VALS(ninep_msg_type), 0x0,
689                   "Message Type", HFILL}},
690                 {&hf_9P_tag,
691                  {"Tag", "9p.tag", FT_UINT16, BASE_DEC, NULL, 0x0,
692                   "9P Tag", HFILL}},
693                 {&hf_9P_oldtag,
694                  {"Old tag", "9p.oldtag", FT_UINT16, BASE_DEC, NULL, 0x0,
695                   "Old tag", HFILL}},
696                 {&hf_9P_parmsz,
697                  {"Param length", "9p.paramsz", FT_UINT16, BASE_DEC, NULL, 0x0,
698                   "Parameter length", HFILL}},
699                 {&hf_9P_maxsize,
700                  {"Max msg size", "9p.maxsize", FT_UINT32, BASE_DEC, NULL, 0x0,
701                   "Max message size", HFILL}},
702                 {&hf_9P_fid,
703                  {"Fid", "9p.fid", FT_UINT32, BASE_DEC, NULL, 0x0,
704                   "File ID", HFILL}},
705                 {&hf_9P_nqid,
706                  {"Nr Qids", "9p.nqid", FT_UINT16, BASE_DEC, NULL, 0x0,
707                   "Number of Qid results", HFILL}},
708                 {&hf_9P_mode,
709                  {"Mode", "9p.mode", FT_UINT8, BASE_HEX, NULL, 0x0,
710                   "Mode", HFILL}},
711                 {&hf_9P_mode_rwx,
712                  {"Open/Create Mode", "9p.mode.rwx", FT_UINT8, BASE_DEC,VALS(ninep_mode_vals),P9_MODEMASK,
713                   "Open/Create Mode", HFILL}},
714                 {&hf_9P_mode_t,
715                  {"Trunc", "9p.mode.trunc", FT_BOOLEAN, 8, TFS(&flags_set_truth), P9_OTRUNC,
716                   "Truncate", HFILL}},
717                 {&hf_9P_mode_c,
718                  {"Remove on close", "9p.mode.orclose", FT_BOOLEAN, 8, TFS(&flags_set_truth), P9_ORCLOSE,
719                   "", HFILL}},
720                 {&hf_9P_iounit,
721                  {"I/O Unit", "9p.iounit", FT_UINT32, BASE_DEC, NULL, 0x0,
722                   "I/O Unit", HFILL}},
723                 {&hf_9P_count,
724                  {"Count", "9p.count", FT_UINT32, BASE_DEC, NULL, 0x0,
725                   "Count", HFILL}},
726                 {&hf_9P_offset,
727                  {"Offset", "9p.offset", FT_UINT64, BASE_DEC, NULL, 0x0,
728                   "Offset", HFILL}},
729                 {&hf_9P_perm,
730                  {"Permissions", "9p.perm", FT_UINT32, BASE_OCT, NULL, 0x0,
731                   "Permission bits", HFILL}},
732                 {&hf_9P_qidpath,
733                  {"Qid path", "9p.qidpath", FT_UINT64, BASE_DEC, NULL, 0x0,
734                   "Qid path", HFILL}},
735                 {&hf_9P_qidvers,
736                  {"Qid version", "9p.qidvers", FT_UINT32, BASE_DEC, NULL, 0x0,
737                   "Qid version", HFILL}},
738                 {&hf_9P_qidtype,
739                  {"Qid type", "9p.qidtype", FT_UINT8, BASE_HEX, NULL, 0x0,
740                   "Qid type", HFILL}},
741                 {&hf_9P_statmode,
742                  {"Mode", "9p.statmode", FT_UINT32, BASE_OCT, NULL, 0x0,
743                   "File mode flags", HFILL}},
744                 {&hf_9P_stattype,
745                  {"Type", "9p.stattype", FT_UINT16, BASE_DEC, NULL, 0x0,
746                   "Type", HFILL}},
747                 {&hf_9P_atime,
748                  {"Atime", "9p.atime", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
749                   "Access Time", HFILL}},
750                 {&hf_9P_mtime,
751                  {"Mtime", "9p.mtime", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
752                   "Modified Time", HFILL}},
753                 {&hf_9P_length,
754                  {"Length", "9p.length", FT_UINT64, BASE_DEC, NULL, 0x0,
755                   "File Length", HFILL}},
756                 {&hf_9P_dev,
757                  {"Dev", "9p.dev", FT_UINT32, BASE_DEC, NULL, 0x0,
758                   "", HFILL}},
759                 {&hf_9P_wname,
760                  {"Wname", "9p.wname", FT_STRING, BASE_NONE, NULL, 0x0,
761                   "Path Name Element", HFILL}},
762                 {&hf_9P_version,
763                  {"Version", "9p.version", FT_STRING, BASE_NONE, NULL, 0x0,
764                   "Version", HFILL}},
765                 {&hf_9P_afid,
766                  {"Afid", "9p.fid", FT_UINT32, BASE_DEC, NULL, 0x0,
767                   "Authenticating FID", HFILL}},
768                 {&hf_9P_uname,
769                  {"Uname", "9p.uname", FT_STRING, BASE_NONE, NULL, 0x0,
770                   "User Name", HFILL}},
771                 {&hf_9P_aname,
772                  {"Aname", "9p.aname", FT_STRING, BASE_NONE, NULL, 0x0,
773                   "Access Name", HFILL}},
774                 {&hf_9P_ename,
775                  {"Ename", "9p.ename", FT_STRING, BASE_NONE, NULL, 0x0,
776                   "Error", HFILL}},
777                 {&hf_9P_name,
778                  {"Name", "9p.name", FT_STRING, BASE_NONE, NULL, 0x0,
779                   "Name of file", HFILL}},
780                 {&hf_9P_sdlen,
781                  {"Stat data length", "9p.sdlen", FT_UINT16, BASE_DEC, NULL, 0x0,
782                   "Stat data length", HFILL}},
783                 {&hf_9P_filename,
784                  {"File name", "9p.filename", FT_STRING, BASE_NONE, NULL, 0x0,
785                   "File name", HFILL}},
786                 {&hf_9P_uid,
787                  {"Uid", "9p.uid", FT_STRING, BASE_NONE, NULL, 0x0,
788                   "User id", HFILL}},
789                 {&hf_9P_gid,
790                  {"Gid", "9p.gid", FT_STRING, BASE_NONE, NULL, 0x0,
791                   "Group id", HFILL}},
792                 {&hf_9P_muid,
793                  {"Muid", "9p.muid", FT_STRING, BASE_NONE, NULL, 0x0,
794                   "Last modifiers uid", HFILL}},
795                 {&hf_9P_newfid,
796                  {"New fid", "9p.newfid", FT_UINT32, BASE_DEC, NULL, 0x0,
797                   "New file ID", HFILL}},
798                 {&hf_9P_nwalk,
799                  {"Nr Walks", "9p.nwalk", FT_UINT32, BASE_DEC, NULL, 0x0,
800                   "Nr of walk items", HFILL}}
801
802         };
803
804         static gint *ett[] = {
805                 &ett_9P,
806                 &ett_9P_omode,
807                 &ett_9P_dm,
808                 &ett_9P_wname,
809                 &ett_9P_aname,
810                 &ett_9P_ename,
811                 &ett_9P_uname,
812                 &ett_9P_uid,
813                 &ett_9P_gid,
814                 &ett_9P_muid,
815                 &ett_9P_filename,
816                 &ett_9P_version,
817                 &ett_9P_qid,
818                 &ett_9P_qidtype,
819         };
820
821         proto_9P = proto_register_protocol("Plan 9 9P", "9P", "9p");
822
823         proto_register_field_array(proto_9P, hf, array_length(hf));
824
825         proto_register_subtree_array(ett, array_length(ett));
826 }
827
828 void proto_reg_handoff_9P(void);
829
830 void proto_reg_handoff_9P(void)
831 {
832         dissector_handle_t ninep_handle;
833
834         data_handle = find_dissector("data");
835
836         ninep_handle = create_dissector_handle(dissect_9P, proto_9P);
837
838         dissector_add("tcp.port", NINEPORT, ninep_handle);
839 }
840
841