summaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-9p.c
diff options
context:
space:
mode:
Diffstat (limited to 'epan/dissectors/packet-9p.c')
-rw-r--r--epan/dissectors/packet-9p.c2875
1 files changed, 2875 insertions, 0 deletions
diff --git a/epan/dissectors/packet-9p.c b/epan/dissectors/packet-9p.c
new file mode 100644
index 00000000..e35072d4
--- /dev/null
+++ b/epan/dissectors/packet-9p.c
@@ -0,0 +1,2875 @@
+/* packet-9p.c
+ * Routines for 9P dissection
+ * Copyright 2005, Nils O. Selaasdal
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * File permission bits decoding taken from packet-nfs.c
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+
+#include <epan/packet.h>
+#include <epan/expert.h>
+
+#include "packet-tcp.h"
+
+/*
+ * Protocol specifications:
+ *
+ * 9P2000: http://ericvh.github.io/9p-rfc/rfc9p2000.html
+ * 9P2000.L: https://github.com/chaos/diod/blob/master/protocol.md
+ * 9P2000.u: https://ericvh.github.io/9p-rfc/rfc9p2000.u.html
+ */
+
+/**
+ * enum _9p_msg_t - 9P message types
+ * @_9P_TLERROR: not used
+ * @_9P_RLERROR: response for any failed request for 9P2000.L
+ * @_9P_TSTATFS: file system status request
+ * @_9P_RSTATFS: file system status response
+ * @_9P_TSYMLINK: make symlink request
+ * @_9P_RSYMLINK: make symlink response
+ * @_9P_TMKNOD: create a special file object request
+ * @_9P_RMKNOD: create a special file object response
+ * @_9P_TLCREATE: prepare a handle for I/O on an new file for 9P2000.L
+ * @_9P_RLCREATE: response with file access information for 9P2000.L
+ * @_9P_TRENAME: rename request
+ * @_9P_RRENAME: rename response
+ * @_9P_TMKDIR: create a directory request
+ * @_9P_RMKDIR: create a directory response
+ * @_9P_TVERSION: version handshake request
+ * @_9P_RVERSION: version handshake response
+ * @_9P_TAUTH: request to establish authentication channel
+ * @_9P_RAUTH: response with authentication information
+ * @_9P_TATTACH: establish user access to file service
+ * @_9P_RATTACH: response with top level handle to file hierarchy
+ * @_9P_TERROR: not used
+ * @_9P_RERROR: response for any failed request
+ * @_9P_TFLUSH: request to abort a previous request
+ * @_9P_RFLUSH: response when previous request has been cancelled
+ * @_9P_TWALK: descend a directory hierarchy
+ * @_9P_RWALK: response with new handle for position within hierarchy
+ * @_9P_TOPEN: prepare a handle for I/O on an existing file
+ * @_9P_ROPEN: response with file access information
+ * @_9P_TCREATE: prepare a handle for I/O on a new file
+ * @_9P_RCREATE: response with file access information
+ * @_9P_TREAD: request to transfer data from a file or directory
+ * @_9P_RREAD: response with data requested
+ * @_9P_TWRITE: request to transfer data to a file
+ * @_9P_RWRITE: response with out much data was transferred to file
+ * @_9P_TCLUNK: forget about a handle to an entity within the file system
+ * @_9P_RCLUNK: response when server has forgotten about the handle
+ * @_9P_TREMOVE: request to remove an entity from the hierarchy
+ * @_9P_RREMOVE: response when server has removed the entity
+ * @_9P_TSTAT: request file entity attributes
+ * @_9P_RSTAT: response with file entity attributes
+ * @_9P_TWSTAT: request to update file entity attributes
+ * @_9P_RWSTAT: response when file entity attributes are updated
+ *
+ * There are 14 basic operations in 9P2000, paired as
+ * requests and responses. The one special case is ERROR
+ * as there is no @_9P_TERROR request for clients to transmit to
+ * the server, but the server may respond to any other request
+ * with an @_9P_RERROR.
+ *
+ * See Also: http://plan9.bell-labs.com/sys/man/5/INDEX.html
+ */
+
+static dissector_handle_t ninep_handle;
+
+enum _9p_msg_t {
+ _9P_TLERROR = 6,
+ _9P_RLERROR,
+ _9P_TSTATFS = 8,
+ _9P_RSTATFS,
+ _9P_TLOPEN = 12,
+ _9P_RLOPEN,
+ _9P_TLCREATE = 14,
+ _9P_RLCREATE,
+ _9P_TSYMLINK = 16,
+ _9P_RSYMLINK,
+ _9P_TMKNOD = 18,
+ _9P_RMKNOD,
+ _9P_TRENAME = 20,
+ _9P_RRENAME,
+ _9P_TREADLINK = 22,
+ _9P_RREADLINK,
+ _9P_TGETATTR = 24,
+ _9P_RGETATTR,
+ _9P_TSETATTR = 26,
+ _9P_RSETATTR,
+ _9P_TXATTRWALK = 30,
+ _9P_RXATTRWALK,
+ _9P_TXATTRCREATE = 32,
+ _9P_RXATTRCREATE,
+ _9P_TREADDIR = 40,
+ _9P_RREADDIR,
+ _9P_TFSYNC = 50,
+ _9P_RFSYNC,
+ _9P_TLOCK = 52,
+ _9P_RLOCK,
+ _9P_TGETLOCK = 54,
+ _9P_RGETLOCK,
+ _9P_TLINK = 70,
+ _9P_RLINK,
+ _9P_TMKDIR = 72,
+ _9P_RMKDIR,
+ _9P_TRENAMEAT = 74,
+ _9P_RRENAMEAT,
+ _9P_TUNLINKAT = 76,
+ _9P_RUNLINKAT,
+ _9P_TVERSION = 100,
+ _9P_RVERSION,
+ _9P_TAUTH = 102,
+ _9P_RAUTH,
+ _9P_TATTACH = 104,
+ _9P_RATTACH,
+ _9P_TERROR = 106,
+ _9P_RERROR,
+ _9P_TFLUSH = 108,
+ _9P_RFLUSH,
+ _9P_TWALK = 110,
+ _9P_RWALK,
+ _9P_TOPEN = 112,
+ _9P_ROPEN,
+ _9P_TCREATE = 114,
+ _9P_RCREATE,
+ _9P_TREAD = 116,
+ _9P_RREAD,
+ _9P_TWRITE = 118,
+ _9P_RWRITE,
+ _9P_TCLUNK = 120,
+ _9P_RCLUNK,
+ _9P_TREMOVE = 122,
+ _9P_RREMOVE,
+ _9P_TSTAT = 124,
+ _9P_RSTAT,
+ _9P_TWSTAT = 126,
+ _9P_RWSTAT
+};
+
+/* 9P Msg types to name mapping */
+static const value_string ninep_msg_type[] =
+{
+ {_9P_TLERROR, "Tlerror"},
+ {_9P_RLERROR, "Rlerror"},
+ {_9P_TSTATFS, "Tstatfs"},
+ {_9P_RSTATFS, "Rstatfs"},
+ {_9P_TLOPEN, "Tlopen"},
+ {_9P_RLOPEN, "Rlopen"},
+ {_9P_TLCREATE, "Tlcreate"},
+ {_9P_RLCREATE, "Rlcreate"},
+ {_9P_TSYMLINK, "Tsymlink"},
+ {_9P_RSYMLINK, "Rsymlink"},
+ {_9P_TMKNOD, "Tmknod"},
+ {_9P_RMKNOD, "Rmknod"},
+ {_9P_TRENAME, "Trename"},
+ {_9P_RRENAME, "Rrename"},
+ {_9P_TREADLINK, "Treadlink"},
+ {_9P_RREADLINK, "Rreadlink"},
+ {_9P_TGETATTR, "Tgetattr"},
+ {_9P_RGETATTR, "Rgetattr"},
+ {_9P_TSETATTR, "Tsetattr"},
+ {_9P_RSETATTR, "Rsetattr"},
+ {_9P_TXATTRWALK, "Txattrwalk"},
+ {_9P_RXATTRWALK, "Rxattrwalk"},
+ {_9P_TXATTRCREATE, "Txattrcreate"},
+ {_9P_RXATTRCREATE, "Rxattrcreate"},
+ {_9P_TREADDIR, "Treaddir"},
+ {_9P_RREADDIR, "Rreaddir"},
+ {_9P_TFSYNC, "Tfsync"},
+ {_9P_RFSYNC, "Rfsync"},
+ {_9P_TLOCK, "Tlock"},
+ {_9P_RLOCK, "Rlock"},
+ {_9P_TGETLOCK, "Tgetlock"},
+ {_9P_RGETLOCK, "Rgetlock"},
+ {_9P_TLINK, "Tlink"},
+ {_9P_RLINK, "Rlink"},
+ {_9P_TMKDIR, "Tmkdir"},
+ {_9P_RMKDIR, "Rmkdir"},
+ {_9P_TRENAMEAT, "Trenameat"},
+ {_9P_RRENAMEAT, "Rrenameat"},
+ {_9P_TUNLINKAT, "Tunlinkat"},
+ {_9P_RUNLINKAT, "Runlinkat"},
+ {_9P_TVERSION, "Tversion"},
+ {_9P_RVERSION, "Rversion"},
+ {_9P_TAUTH, "Tauth"},
+ {_9P_RAUTH, "Rauth"},
+ {_9P_TATTACH, "Tattach"},
+ {_9P_RATTACH, "Rattach"},
+ {_9P_TERROR, "Terror"},
+ {_9P_RERROR, "Rerror"},
+ {_9P_TFLUSH, "Tflush"},
+ {_9P_RFLUSH, "Rflush"},
+ {_9P_TWALK, "Twalk"},
+ {_9P_RWALK, "Rwalk"},
+ {_9P_TOPEN, "Topen"},
+ {_9P_ROPEN, "Ropen"},
+ {_9P_TCREATE, "Tcreate"},
+ {_9P_RCREATE, "Rcreate"},
+ {_9P_TREAD, "Tread"},
+ {_9P_RREAD, "Rread"},
+ {_9P_TWRITE, "Twrite"},
+ {_9P_RWRITE, "Rwrite"},
+ {_9P_TCLUNK, "Tclunk"},
+ {_9P_RCLUNK, "Rclunk"},
+ {_9P_TREMOVE, "Tremove"},
+ {_9P_RREMOVE, "Rremove"},
+ {_9P_TSTAT, "Tstat"},
+ {_9P_RSTAT, "Rstat"},
+ {_9P_TWSTAT, "Twstat"},
+ {_9P_RWSTAT, "Rwstat"},
+ {0, NULL},
+};
+static value_string_ext ninep_msg_type_ext = VALUE_STRING_EXT_INIT(ninep_msg_type);
+
+enum _9p_version {
+ _9P = 1,
+ _9P2000,
+ _9P2000_L,
+ _9P2000_u
+};
+
+static const value_string ninep_version[] =
+{
+ {_9P, "9P"},
+ {_9P2000, "9P2000"},
+ {_9P2000_L, "9P2000.L"},
+ {_9P2000_u, "9P2000.u"},
+ {0, NULL},
+};
+static value_string_ext ninep_version_ext = VALUE_STRING_EXT_INIT(ninep_version);
+
+
+/* File open modes */
+#define _9P_OREAD 0x0
+#define _9P_OWRITE 0x1
+#define _9P_ORDWR 0x2
+#define _9P_OEXEC 0x3
+#define _9P_MODEMASK 0x3
+#define _9P_OTRUNC 0x10
+#define _9P_ORCLOSE 0x40
+
+/* Open/Create modes */
+static const value_string ninep_mode_vals[] =
+{
+ {_9P_OREAD, "Read Access"},
+ {_9P_OWRITE, "Write Access"},
+ {_9P_ORDWR, "Read/Write Access "},
+ {_9P_OEXEC, "Execute Access"},
+ {0, NULL},
+};
+static value_string_ext ninep_mode_vals_ext = VALUE_STRING_EXT_INIT(ninep_mode_vals);
+
+
+/* stat mode flags */
+#define DMDIR 0x80000000 /* Directory */
+#define DMAPPEND 0x40000000 /* Append only */
+#define DMEXCL 0x20000000 /* Exclusive use */
+#define DMMOUNT 0x10000000 /* Mounted channel */
+#define DMAUTH 0x08000000 /* Authentication */
+#define DMTMP 0x04000000 /* Temporary */
+
+
+/**
+ * enum _9p_qid_t - QID types
+ * @_9P_QTDIR: directory
+ * @_9P_QTAPPEND: append-only
+ * @_9P_QTEXCL: excluse use (only one open handle allowed)
+ * @_9P_QTMOUNT: mount points
+ * @_9P_QTAUTH: authentication file
+ * @_9P_QTTMP: non-backed-up files
+ * @_9P_QTSYMLINK: symbolic links (9P2000.u)
+ * @_9P_QTLINK: hard-link (9P2000.u)
+ * @_9P_QTFILE: normal files
+ *
+ * QID types are a subset of permissions - they are primarily
+ * used to differentiate semantics for a file system entity via
+ * a jump-table. Their value is also the most significant 16 bits
+ * of the permission_t
+ *
+ * See Also: http://plan9.bell-labs.com/magic/man2html/2/stat
+ */
+enum _9p_qid_t {
+ _9P_QTDIR = 0x80,
+ _9P_QTAPPEND = 0x40,
+ _9P_QTEXCL = 0x20,
+ _9P_QTMOUNT = 0x10,
+ _9P_QTAUTH = 0x08,
+ _9P_QTTMP = 0x04,
+ _9P_QTSYMLINK = 0x02,
+ _9P_QTLINK = 0x01,
+ _9P_QTFILE = 0x00
+};
+
+/* 9P Magic Numbers */
+#define _9P_NOTAG (guint16)(~0)
+#define _9P_NOFID (guint32)(~0)
+#define _9P_NONUNAME (guint32)(~0)
+#define _9P_MAXWELEM 16
+
+
+/**
+ * @brief Length prefixed string type
+ *
+ * The protocol uses length prefixed strings for all
+ * string data, so we replicate that for our internal
+ * string members.
+ */
+
+struct _9p_str {
+ guint16 len; /* Length of the string */
+ char *str; /* The string */
+};
+
+/**
+ * @brief file system entity information
+ *
+ * qids are /identifiers used by 9P servers to track file system
+ * entities. The type is used to differentiate semantics for operations
+ * on the entity (ie. read means something different on a directory than
+ * on a file). The path provides a server unique index for an entity
+ * (roughly analogous to an inode number), while the version is updated
+ * every time a file is modified and can be used to maintain cache
+ * coherency between clients and serves.
+ * Servers will often differentiate purely synthetic entities by setting
+ * their version to 0, signaling that they should never be cached and
+ * should be accessed synchronously.
+ *
+ * See Also://plan9.bell-labs.com/magic/man2html/2/stat
+ */
+
+struct _9p_qid {
+ guint8 type; /* Type */
+ guint32 version; /* Monotonically incrementing version number */
+ guint64 path; /* Per-server-unique ID for a file system element */
+};
+
+
+/* Bit values for getattr valid field.
+ */
+#define _9P_GETATTR_MODE 0x00000001U
+#define _9P_GETATTR_NLINK 0x00000002U
+#define _9P_GETATTR_UID 0x00000004U
+#define _9P_GETATTR_GID 0x00000008U
+#define _9P_GETATTR_RDEV 0x00000010U
+#define _9P_GETATTR_ATIME 0x00000020U
+#define _9P_GETATTR_MTIME 0x00000040U
+#define _9P_GETATTR_CTIME 0x00000080U
+#define _9P_GETATTR_INO 0x00000100U
+#define _9P_GETATTR_SIZE 0x00000200U
+#define _9P_GETATTR_BLOCKS 0x00000400U
+
+#define _9P_GETATTR_BTIME 0x00000800U
+#define _9P_GETATTR_GEN 0x00001000U
+#define _9P_GETATTR_DATA_VERSION 0x00002000U
+
+#if 0
+#define _9P_GETATTR_BASIC 0x000007ffU /* Mask for fields up to BLOCKS */
+#endif
+#define _9P_GETATTR_ALL 0x00003fffU /* Mask for All fields above */
+
+
+/* Bit values for setattr valid field from <linux/fs.h>.
+ */
+#define _9P_SETATTR_MODE 0x00000001U
+#define _9P_SETATTR_UID 0x00000002U
+#define _9P_SETATTR_GID 0x00000004U
+#define _9P_SETATTR_SIZE 0x00000008U
+#define _9P_SETATTR_ATIME 0x00000010U
+#define _9P_SETATTR_MTIME 0x00000020U
+#define _9P_SETATTR_CTIME 0x00000040U
+#define _9P_SETATTR_ATIME_SET 0x00000080U
+#define _9P_SETATTR_MTIME_SET 0x00000100U
+
+#define _9P_SETATTR_ALL 0x000001FFU
+
+/* 9p2000.L open flags */
+#define _9P_DOTL_RDONLY 00000000
+#define _9P_DOTL_WRONLY 00000001
+#define _9P_DOTL_RDWR 00000002
+#define _9P_DOTL_NOACCESS 00000003
+#define _9P_DOTL_CREATE 00000100
+#define _9P_DOTL_EXCL 00000200
+#define _9P_DOTL_NOCTTY 00000400
+#define _9P_DOTL_TRUNC 00001000
+#define _9P_DOTL_APPEND 00002000
+#define _9P_DOTL_NONBLOCK 00004000
+#define _9P_DOTL_DSYNC 00010000
+#define _9P_DOTL_FASYNC 00020000
+#define _9P_DOTL_DIRECT 00040000
+#define _9P_DOTL_LARGEFILE 00100000
+#define _9P_DOTL_DIRECTORY 00200000
+#define _9P_DOTL_NOFOLLOW 00400000
+#define _9P_DOTL_NOATIME 01000000
+#define _9P_DOTL_CLOEXEC 02000000
+#define _9P_DOTL_SYNC 04000000
+
+
+/* Bit values for lock type.
+ */
+#define _9P_LOCK_TYPE_RDLCK 0
+#define _9P_LOCK_TYPE_WRLCK 1
+#define _9P_LOCK_TYPE_UNLCK 2
+
+/* 9P lock type to string table */
+static const value_string ninep_lock_type[] =
+{
+ {_9P_LOCK_TYPE_RDLCK, "Read lock"},
+ {_9P_LOCK_TYPE_WRLCK, "Write lock"},
+ {_9P_LOCK_TYPE_UNLCK, "Unlock"},
+ { 0, NULL},
+};
+static value_string_ext ninep_lock_type_ext = VALUE_STRING_EXT_INIT(ninep_lock_type);
+
+/* Bit values for lock status.
+ */
+#define _9P_LOCK_SUCCESS 0
+#define _9P_LOCK_BLOCKED 1
+#define _9P_LOCK_ERROR 2
+#define _9P_LOCK_GRACE 3
+
+/* 9P lock status to string table */
+static const value_string ninep_lock_status[] =
+{
+ {_9P_LOCK_SUCCESS, "Success"},
+ {_9P_LOCK_BLOCKED, "Blocked"},
+ {_9P_LOCK_ERROR, "Error"},
+ {_9P_LOCK_GRACE, "Grace"},
+ { 0, NULL},
+};
+static value_string_ext ninep_lock_status_ext = VALUE_STRING_EXT_INIT(ninep_lock_status);
+
+/* Bit values for lock flags.
+ */
+#define _9P_LOCK_FLAGS_NONE 0
+#define _9P_LOCK_FLAGS_BLOCK 1
+#define _9P_LOCK_FLAGS_RECLAIM 2
+
+/* 9P lock flag to string table */
+static const value_string ninep_lock_flag[] =
+{
+ {_9P_LOCK_FLAGS_NONE, "No flag"},
+ {_9P_LOCK_FLAGS_BLOCK, "Block"},
+ {_9P_LOCK_FLAGS_RECLAIM,"Reclaim"},
+ { 0, NULL},
+};
+static value_string_ext ninep_lock_flag_ext = VALUE_STRING_EXT_INIT(ninep_lock_flag);
+
+/*
+ * Linux error code values to descriptions table.
+ * Note that the error code values on Linux are platform-dependent;
+ * Linux, on some platforms, tried to match the values of existing UN*Xes
+ * on the platform in question.
+ *
+ * The platforms in question appear to be:
+ *
+ * 32-bit PowerPC (AIX?)
+ * 32-bit and 64-bit SPARC (SunOS - pre-5, or 5?)
+ * PA-RISC (HP-UX)
+ * Alpha (Tru64 UNIX)
+ * 32-bit MIPS (IRIX?)
+ * 64-bit MIPS (IRIX?)
+ *
+ * For now, we don't worry about this, and use the errno values used
+ * on most Linux platforms.
+ */
+static const value_string linux_errno[] =
+{
+ {1, "Operation not permitted"}, /* EPERM */
+ {2, "No such file or directory"}, /* ENOENT */
+ {3, "No such process"}, /* ESRCH */
+ {4, "Interrupted system call"}, /* EINTR */
+ {5, "I/O error"}, /* EIO */
+ {6, "No such device or address"}, /* ENXIO */
+ {7, "Argument list too long"}, /* E2BIG */
+ {8, "Exec format error"}, /* ENOEXEC */
+ {9, "Bad file number"}, /* EBADF */
+ {10, "No child processes"}, /* ECHILD */
+ {11, "Try again"}, /* EAGAIN */
+ {12, "Out of memory"}, /* ENOMEM */
+ {13, "Permission denied"}, /* EACCES */
+ {14, "Bad address"}, /* EFAULT */
+ {15, "Block device required"}, /* ENOTBLK */
+ {16, "Device or resource busy"}, /* EBUSY */
+ {17, "File exists"}, /* EEXIST */
+ {18, "Cross-device link"}, /* EXDEV */
+ {19, "No such device"}, /* ENODEV */
+ {20, "Not a directory"}, /* ENOTDIR */
+ {21, "Is a directory"}, /* EISDIR */
+ {22, "Invalid argument"}, /* EINVAL */
+ {23, "File table overflow"}, /* ENFILE */
+ {24, "Too many open files"}, /* EMFILE */
+ {25, "Not a typewriter"}, /* ENOTTY */
+ {26, "Text file busy"}, /* ETXTBSY */
+ {27, "File too large"}, /* EFBIG */
+ {28, "No space left on device"}, /* ENOSPC */
+ {29, "Illegal seek"}, /* ESPIPE */
+ {30, "Read-only file system"}, /* EROFS */
+ {31, "Too many links"}, /* EMLINK */
+ {32, "Broken pipe"}, /* EPIPE */
+ {33, "Math argument out of domain of func"}, /* EDOM */
+ {34, "Math result not representable"}, /* ERANGE */
+ {35, "Resource deadlock would occur"}, /* EDEADLK */
+ {36, "File name too long"}, /* ENAMETOOLONG */
+ {37, "No record locks available"}, /* ENOLCK */
+ {38, "Function not implemented"}, /* ENOSYS */
+ {39, "Directory not empty"}, /* ENOTEMPTY */
+ {40, "Too many symbolic links encountered"}, /* ELOOP */
+ {42, "No message of desired type"}, /* ENOMSG */
+ {43, "Identifier removed"}, /* EIDRM */
+ {44, "Channel number out of range"}, /* ECHRNG */
+ {45, "Level 2 not synchronized"}, /* EL2NSYNC */
+ {46, "Level 3 halted"}, /* EL3HLT */
+ {47, "Level 3 reset"}, /* EL3RST */
+ {48, "Link number out of range"}, /* ELNRNG */
+ {49, "Protocol driver not attached"}, /* EUNATCH */
+ {50, "No CSI structure available"}, /* ENOCSI */
+ {51, "Level 2 halted"}, /* EL2HLT */
+ {52, "Invalid exchange"}, /* EBADE */
+ {53, "Invalid request descriptor"}, /* EBADR */
+ {54, "Exchange full"}, /* EXFULL */
+ {55, "No anode"}, /* ENOANO */
+ {56, "Invalid request code"}, /* EBADRQC */
+ {57, "Invalid slot"}, /* EBADSLT */
+ {58, "File locking deadlock error"}, /* EDEADLOCK */
+ {59, "Bad font file format"}, /* EBFONT */
+ {60, "Device not a stream"}, /* ENOSTR */
+ {61, "No data available"}, /* ENODATA */
+ {62, "Timer expired"}, /* ETIME */
+ {63, "Out of streams resources"}, /* ENOSR */
+ {64, "Machine is not on the network"}, /* ENONET */
+ {65, "Package not installed"}, /* ENOPKG */
+ {66, "Object is remote"}, /* EREMOTE */
+ {67, "Link has been severed"}, /* ENOLINK */
+ {68, "Advertise error"}, /* EADV */
+ {69, "Srmount error"}, /* ESRMNT */
+ {70, "Communication error on send"}, /* ECOMM */
+ {71, "Protocol error"}, /* EPROTO */
+ {72, "Multihop attempted"}, /* EMULTIHOP */
+ {73, "RFS specific error"}, /* EDOTDOT */
+ {74, "Not a data message"}, /* EBADMSG */
+ {75, "Value too large for defined data type"}, /* EOVERFLOW */
+ {76, "Name not unique on network"}, /* ENOTUNIQ */
+ {77, "File descriptor in bad state"}, /* EBADFD */
+ {78, "Remote address changed"}, /* EREMCHG */
+ {79, "Can not access a needed shared library"}, /* ELIBACC */
+ {80, "Accessing a corrupted shared library"}, /* ELIBBAD */
+ {81, ".lib section in a.out corrupted"}, /* ELIBSCN */
+ {82, "Attempting to link in too many shared libraries"}, /* ELIBMAX */
+ {83, "Cannot exec a shared library directly"}, /* ELIBEXEC */
+ {84, "Illegal byte sequence"}, /* EILSEQ */
+ {85, "Interrupted system call should be restarted"}, /* ERESTART */
+ {86, "Streams pipe error"}, /* ESTRPIPE */
+ {87, "Too many users"}, /* EUSERS */
+ {88, "Socket operation on non-socket"}, /* ENOTSOCK */
+ {89, "Destination address required"}, /* EDESTADDRREQ */
+ {90, "Message too long"}, /* EMSGSIZE */
+ {91, "Protocol wrong type for socket"}, /* EPROTOTYPE */
+ {92, "Protocol not available"}, /* ENOPROTOOPT */
+ {93, "Protocol not supported"}, /* EPROTONOSUPPORT */
+ {94, "Socket type not supported"}, /* ESOCKTNOSUPPORT */
+ {95, "Operation not supported on transport endpoint"}, /* EOPNOTSUPP */
+ {96, "Protocol family not supported"}, /* EPFNOSUPPORT */
+ {97, "Address family not supported by protocol"}, /* EAFNOSUPPORT */
+ {98, "Address already in use"}, /* EADDRINUSE */
+ {99, "Cannot assign requested address"}, /* EADDRNOTAVAIL */
+ {100, "Network is down"}, /* ENETDOWN */
+ {101, "Network is unreachable"}, /* ENETUNREACH */
+ {102, "Network dropped connection because of reset"}, /* ENETRESET */
+ {103, "Software caused connection abort"}, /* ECONNABORTED */
+ {104, "Connection reset by peer"}, /* ECONNRESET */
+ {105, "No buffer space available"}, /* ENOBUFS */
+ {106, "Transport endpoint is already connected"}, /* EISCONN */
+ {107, "Transport endpoint is not connected"}, /* ENOTCONN */
+ {108, "Cannot send after transport endpoint shutdown"}, /* ESHUTDOWN */
+ {109, "Too many references: cannot splice"}, /* ETOOMANYREFS */
+ {110, "Connection timed out"}, /* ETIMEDOUT */
+ {111, "Connection refused"}, /* ECONNREFUSED */
+ {112, "Host is down"}, /* EHOSTDOWN */
+ {113, "No route to host"}, /* EHOSTUNREACH */
+ {114, "Operation already in progress"}, /* EALREADY */
+ {115, "Operation now in progress"}, /* EINPROGRESS */
+ {116, "Stale NFS file handle"}, /* ESTALE */
+ {117, "Structure needs cleaning"}, /* EUCLEAN */
+ {118, "Not a XENIX named type file"}, /* ENOTNAM */
+ {119, "No XENIX semaphores available"}, /* ENAVAIL */
+ {120, "Is a named type file"}, /* EISNAM */
+ {121, "Remote I/O error"}, /* EREMOTEIO */
+ {122, "Quota exceeded"}, /* EDQUOT */
+ {123, "No medium found"}, /* ENOMEDIUM */
+ {124, "Wrong medium type"}, /* EMEDIUMTYPE */
+ {125, "Operation Canceled"}, /* ECANCELED */
+ {126, "Required key not available"}, /* ENOKEY */
+ {127, "Key has expired"}, /* EKEYEXPIRED */
+ {128, "Key has been revoked"}, /* EKEYREVOKED */
+ {129, "Key was rejected by service"}, /* EKEYREJECTED */
+ {130, "Owner died"}, /* EOWNERDEAD */
+ {131, "State not recoverable"}, /* ENOTRECOVERABLE */
+ {132, "Operation not possible due to RF-kill"}, /* ERFKILL */
+ {133, "Memory page has hardware error"}, /* EHWPOISON */
+ {0, NULL}
+};
+static value_string_ext linux_errno_ext = VALUE_STRING_EXT_INIT(linux_errno);
+
+static const char *const invalid_fid_str = "<invalid fid>";
+static const char *const afid_str = "<afid>";
+
+/* Structures for Protocol Operations */
+struct _9p_rlerror {
+ guint32 ecode;
+};
+struct _9p_tstatfs {
+ guint32 fid;
+};
+struct _9p_rstatfs {
+ guint32 type;
+ guint32 bsize;
+ guint64 blocks;
+ guint64 bfree;
+ guint64 bavail;
+ guint64 files;
+ guint64 ffree;
+ guint64 fsid;
+ guint32 namelen;
+};
+struct _9p_tlopen {
+ guint32 fid;
+ guint32 flags;
+};
+struct _9p_rlopen {
+ struct _9p_qid qid;
+ guint32 iounit;
+};
+struct _9p_tlcreate {
+ guint32 fid;
+ struct _9p_str name;
+ guint32 flags;
+ guint32 mode;
+ guint32 gid;
+};
+struct _9p_rlcreate {
+ struct _9p_qid qid;
+ guint32 iounit;
+};
+struct _9p_tsymlink {
+ guint32 fid;
+ struct _9p_str name;
+ struct _9p_str symtgt;
+ guint32 gid;
+};
+struct _9p_rsymlink {
+ struct _9p_qid qid;
+};
+struct _9p_tmknod {
+ guint32 fid;
+ struct _9p_str name;
+ guint32 mode;
+ guint32 major;
+ guint32 minor;
+ guint32 gid;
+};
+struct _9p_rmknod {
+ struct _9p_qid qid;
+};
+struct _9p_trename {
+ guint32 fid;
+ guint32 dfid;
+ struct _9p_str name;
+};
+#if 0
+struct _9p_rrename {
+};
+#endif
+struct _9p_treadlink {
+ guint32 fid;
+};
+struct _9p_rreadlink {
+ struct _9p_str target;
+};
+struct _9p_tgetattr {
+ guint32 fid;
+ guint64 request_mask;
+};
+struct _9p_rgetattr {
+ guint64 valid;
+ struct _9p_qid qid;
+ guint32 mode;
+ guint32 uid;
+ guint32 gid;
+ guint64 nlink;
+ guint64 rdev;
+ guint64 size;
+ guint64 blksize;
+ guint64 blocks;
+ guint64 atime_sec;
+ guint64 atime_nsec;
+ guint64 mtime_sec;
+ guint64 mtime_nsec;
+ guint64 ctime_sec;
+ guint64 ctime_nsec;
+ guint64 btime_sec;
+ guint64 btime_nsec;
+ guint64 gen;
+ guint64 data_version;
+};
+struct _9p_tsetattr {
+ guint32 fid;
+ guint32 valid;
+ guint32 mode;
+ guint32 uid;
+ guint32 gid;
+ guint64 size;
+ guint64 atime_sec;
+ guint64 atime_nsec;
+ guint64 mtime_sec;
+ guint64 mtime_nsec;
+};
+#if 0
+struct _9p_rsetattr {
+};
+#endif
+struct _9p_txattrwalk {
+ guint32 fid;
+ guint32 attrfid;
+ struct _9p_str name;
+};
+struct _9p_rxattrwalk {
+ guint64 size;
+};
+struct _9p_txattrcreate {
+ guint32 fid;
+ struct _9p_str name;
+ guint64 size;
+ guint32 flag;
+};
+#if 0
+struct _9p_rxattrcreate {
+};
+#endif
+struct _9p_treaddir {
+ guint32 fid;
+ guint64 offset;
+ guint32 count;
+};
+struct _9p_rreaddir {
+ guint32 count;
+ guint8 *data;
+};
+struct _9p_tfsync {
+ guint32 fid;
+};
+#if 0
+struct _9p_rfsync {
+};
+#endif
+struct _9p_tlock {
+ guint32 fid;
+ guint8 type;
+ guint32 flags;
+ guint64 start;
+ guint64 length;
+ guint32 proc_id;
+ struct _9p_str client_id;
+};
+struct _9p_rlock {
+ guint8 status;
+};
+struct _9p_tgetlock {
+ guint32 fid;
+ guint8 type;
+ guint64 start;
+ guint64 length;
+ guint32 proc_id;
+ struct _9p_str client_id;
+};
+struct _9p_rgetlock {
+ guint8 type;
+ guint64 start;
+ guint64 length;
+ guint32 proc_id;
+ struct _9p_str client_id;
+};
+struct _9p_tlink {
+ guint32 dfid;
+ guint32 fid;
+ struct _9p_str name;
+};
+#if 0
+struct _9p_rlink {
+};
+#endif
+struct _9p_tmkdir {
+ guint32 fid;
+ struct _9p_str name;
+ guint32 mode;
+ guint32 gid;
+};
+struct _9p_rmkdir {
+ struct _9p_qid qid;
+};
+struct _9p_trenameat {
+ guint32 olddirfid;
+ struct _9p_str oldname;
+ guint32 newdirfid;
+ struct _9p_str newname;
+};
+#if 0
+struct _9p_rrenameat {
+};
+#endif
+struct _9p_tunlinkat {
+ guint32 dirfid;
+ struct _9p_str name;
+ guint32 flags;
+};
+#if 0
+struct _9p_runlinkat {
+};
+#endif
+struct _9p_tawrite {
+ guint32 fid;
+ guint8 datacheck;
+ guint64 offset;
+ guint32 count;
+ guint32 rsize;
+ guint8 *data;
+ guint32 check;
+};
+struct _9p_rawrite {
+ guint32 count;
+};
+struct _9p_tversion {
+ guint32 msize ;
+ struct _9p_str version ;
+};
+struct _9p_rversion {
+ guint32 msize;
+ struct _9p_str version;
+};
+struct _9p_tauth {
+ guint32 afid;
+ struct _9p_str uname;
+ struct _9p_str aname;
+ guint32 n_uname; /* 9P2000.u extensions */
+};
+struct _9p_rauth {
+ struct _9p_qid qid;
+};
+struct _9p_rerror {
+ struct _9p_str error;
+ guint32 errnum; /* 9p2000.u extension */
+};
+struct _9p_tflush {
+ guint16 oldtag;
+};
+#if 0
+struct _9p_rflush {
+};
+#endif
+struct _9p_tattach {
+ guint32 fid;
+ guint32 afid;
+ struct _9p_str uname;
+ struct _9p_str aname;
+ guint32 n_uname; /* 9P2000.u extensions */
+};
+struct _9p_rattach {
+ struct _9p_qid qid;
+};
+struct _9p_twalk {
+ guint32 fid;
+ guint32 newfid;
+ guint16 nwname;
+ struct _9p_str wnames[_9P_MAXWELEM];
+};
+struct _9p_rwalk {
+ guint16 nwqid;
+ struct _9p_qid wqids[_9P_MAXWELEM];
+};
+struct _9p_topen {
+ guint32 fid;
+ guint8 mode;
+};
+struct _9p_ropen {
+ struct _9p_qid qid;
+ guint32 iounit;
+};
+struct _9p_tcreate {
+ guint32 fid;
+ struct _9p_str name;
+ guint32 perm;
+ guint8 mode;
+ struct _9p_str extension;
+};
+struct _9p_rcreate {
+ struct _9p_qid qid;
+ guint32 iounit;
+};
+struct _9p_tread {
+ guint32 fid;
+ guint64 offset;
+ guint32 count;
+};
+struct _9p_rread {
+ guint32 count;
+ guint8 *data;
+};
+struct _9p_twrite {
+ guint32 fid;
+ guint64 offset;
+ guint32 count;
+ guint8 *data;
+};
+struct _9p_rwrite {
+ guint32 count;
+};
+struct _9p_tclunk {
+ guint32 fid;
+};
+#if 0
+struct _9p_rclunk {
+};
+#endif
+struct _9p_tremove {
+ guint32 fid;
+};
+#if 0
+struct _9p_rremove {
+};
+
+union _9p_tmsg {
+} ;
+#endif
+#define NINEPORT 564
+
+/* Forward declarations */
+void proto_register_9P(void);
+void proto_reg_handoff_9P(void);
+
+/* Initialize the protocol and registered fields */
+static int proto_9P = -1;
+static int hf_9P_msgsz = -1;
+static int hf_9P_msgtype = -1;
+static int hf_9P_tag = -1;
+static int hf_9P_oldtag = -1;
+static int hf_9P_parmsz = -1;
+static int hf_9P_maxsize = -1;
+static int hf_9P_fid = -1;
+static int hf_9P_nqid = -1;
+static int hf_9P_mode = -1;
+static int hf_9P_mode_rwx = -1;
+static int hf_9P_mode_t = -1;
+static int hf_9P_mode_c = -1;
+static int hf_9P_extension = -1;
+static int hf_9P_iounit = -1;
+static int hf_9P_count = -1;
+static int hf_9P_offset = -1;
+static int hf_9P_perm = -1;
+static int hf_9P_qidtype = -1;
+static int hf_9P_qidtype_dir = -1;
+static int hf_9P_qidtype_append = -1;
+static int hf_9P_qidtype_exclusive = -1;
+static int hf_9P_qidtype_mount = -1;
+static int hf_9P_qidtype_auth_file = -1;
+static int hf_9P_qidtype_temp_file = -1;
+static int hf_9P_qidvers = -1;
+static int hf_9P_qidpath = -1;
+static int hf_9P_dm_dir = -1;
+static int hf_9P_dm_append = -1;
+static int hf_9P_dm_exclusive = -1;
+static int hf_9P_dm_mount = -1;
+static int hf_9P_dm_auth_file = -1;
+static int hf_9P_dm_temp_file = -1;
+static int hf_9P_dm_read_owner = -1;
+static int hf_9P_dm_write_owner = -1;
+static int hf_9P_dm_exec_owner = -1;
+static int hf_9P_dm_read_group = -1;
+static int hf_9P_dm_write_group = -1;
+static int hf_9P_dm_exec_group = -1;
+static int hf_9P_dm_read_others = -1;
+static int hf_9P_dm_write_others = -1;
+static int hf_9P_dm_exec_others = -1;
+static int hf_9P_stattype = -1;
+static int hf_9P_statmode = -1;
+static int hf_9P_atime = -1;
+static int hf_9P_mtime = -1;
+static int hf_9P_ctime = -1;
+static int hf_9P_btime = -1;
+static int hf_9P_length = -1;
+static int hf_9P_dev = -1;
+static int hf_9P_wname = -1;
+static int hf_9P_version = -1;
+static int hf_9P_afid = -1;
+static int hf_9P_uname = -1;
+static int hf_9P_aname = -1;
+static int hf_9P_ename = -1;
+static int hf_9P_enum = -1;
+/* static int hf_9P_name = -1; */
+static int hf_9P_filename = -1;
+static int hf_9P_sdlen = -1;
+static int hf_9P_user = -1;
+static int hf_9P_group = -1;
+static int hf_9P_uid = -1;
+static int hf_9P_gid = -1;
+static int hf_9P_muid = -1;
+static int hf_9P_nwalk = -1;
+static int hf_9P_newfid = -1;
+static int hf_9P_dfid = -1;
+static int hf_9P_getattr_flags = -1;
+static int hf_9P_getattr_mode = -1;
+static int hf_9P_getattr_nlink = -1;
+static int hf_9P_getattr_uid = -1;
+static int hf_9P_getattr_gid = -1;
+static int hf_9P_getattr_rdev = -1;
+static int hf_9P_getattr_atime = -1;
+static int hf_9P_getattr_mtime = -1;
+static int hf_9P_getattr_ctime = -1;
+static int hf_9P_getattr_ino = -1;
+static int hf_9P_getattr_size = -1;
+static int hf_9P_getattr_blocks = -1;
+static int hf_9P_getattr_btime = -1;
+static int hf_9P_getattr_gen = -1;
+static int hf_9P_getattr_dataversion = -1;
+static int hf_9P_setattr_flags = -1;
+static int hf_9P_setattr_mode = -1;
+static int hf_9P_setattr_uid = -1;
+static int hf_9P_setattr_gid = -1;
+static int hf_9P_setattr_size = -1;
+static int hf_9P_setattr_atime = -1;
+static int hf_9P_setattr_mtime = -1;
+static int hf_9P_setattr_ctime = -1;
+static int hf_9P_setattr_atime_set = -1;
+static int hf_9P_setattr_mtime_set = -1;
+static int hf_9P_unlinkat_flags = -1;
+static int hf_9P_nlink = -1;
+static int hf_9P_rdev = -1;
+static int hf_9P_size = -1;
+static int hf_9P_blksize = -1;
+static int hf_9P_blocks = -1;
+static int hf_9P_gen = -1;
+static int hf_9P_dataversion = -1;
+static int hf_9P_fstype = -1;
+static int hf_9P_bfree = -1;
+static int hf_9P_bavail = -1;
+static int hf_9P_files = -1;
+static int hf_9P_ffree = -1;
+static int hf_9P_fsid = -1;
+static int hf_9P_namelen = -1;
+static int hf_9P_mknod_major = -1;
+static int hf_9P_mknod_minor = -1;
+static int hf_9P_lflags = -1;
+static int hf_9P_lflags_rdonly = -1;
+static int hf_9P_lflags_wronly = -1;
+static int hf_9P_lflags_rdwr = -1;
+static int hf_9P_lflags_create = -1;
+static int hf_9P_lflags_excl = -1;
+static int hf_9P_lflags_noctty = -1;
+static int hf_9P_lflags_trunc = -1;
+static int hf_9P_lflags_append = -1;
+static int hf_9P_lflags_nonblock = -1;
+static int hf_9P_lflags_dsync = -1;
+static int hf_9P_lflags_fasync = -1;
+static int hf_9P_lflags_direct = -1;
+static int hf_9P_lflags_largefile = -1;
+static int hf_9P_lflags_directory = -1;
+static int hf_9P_lflags_nofollow = -1;
+static int hf_9P_lflags_noatime = -1;
+static int hf_9P_lflags_cloexec = -1;
+static int hf_9P_lflags_sync = -1;
+static int hf_9P_xattr_flag = -1;
+static int hf_9P_lock_type = -1;
+static int hf_9P_lock_flag = -1;
+static int hf_9P_lock_start = -1;
+static int hf_9P_lock_length = -1;
+static int hf_9P_lock_procid = -1;
+static int hf_9P_lock_status = -1;
+static int hf_9P_unknown_message = -1;
+
+/* subtree pointers */
+static gint ett_9P = -1;
+static gint ett_9P_omode = -1;
+static gint ett_9P_dm = -1;
+static gint ett_9P_wname = -1;
+static gint ett_9P_aname = -1;
+static gint ett_9P_ename = -1;
+static gint ett_9P_uname = -1;
+static gint ett_9P_user = -1;
+static gint ett_9P_group = -1;
+static gint ett_9P_muid = -1;
+static gint ett_9P_filename = -1;
+static gint ett_9P_version = -1;
+static gint ett_9P_qid = -1;
+static gint ett_9P_qidtype = -1;
+static gint ett_9P_getattr_flags = -1;
+static gint ett_9P_setattr_flags = -1;
+static gint ett_9P_lflags = -1;
+
+static expert_field ei_9P_first_250 = EI_INIT;
+static expert_field ei_9P_msgtype = EI_INIT;
+
+static wmem_map_t *_9p_hashtable = NULL;
+
+static void dissect_9P_dm(tvbuff_t *tvb, proto_item *tree, int offset, int iscreate);
+static void dissect_9P_qid(tvbuff_t *tvb, proto_tree *tree, int offset);
+static void dissect_9P_lflags(tvbuff_t *tvb, proto_tree *tree, int offset);
+static void dissect_9P_getattrflags(tvbuff_t *tvb, proto_tree *tree, int offset);
+static void dissect_9P_setattrflags(tvbuff_t *tvb, proto_tree *tree, int offset);
+
+static int * const _9P_modes[] = {
+ &hf_9P_mode_c,
+ &hf_9P_mode_t,
+ &hf_9P_mode_rwx,
+ NULL
+};
+
+struct _9p_hashkey {
+ guint32 conv_index;
+ guint16 tag;
+ guint32 fid;
+};
+
+struct _9p_hashval {
+ gsize len;
+ void *data;
+};
+
+struct _9p_taginfo {
+ enum _9p_msg_t msgtype;
+ guint32 fid;
+ /* fid path used for create and lcreate */
+ char *fid_path;
+};
+
+static gint _9p_hash_equal(gconstpointer k1, gconstpointer k2) {
+ const struct _9p_hashkey *key1 = (const struct _9p_hashkey *)k1, *key2 = (const struct _9p_hashkey *)k2;
+
+ return ((key1->conv_index == key2->conv_index) && (key1->tag == key2->tag) && (key1->fid == key2->fid));
+}
+
+static guint _9p_hash_hash(gconstpointer k)
+{
+ const struct _9p_hashkey *key = (const struct _9p_hashkey *)k;
+
+ return (key->conv_index ^ key->tag ^ key->fid);
+}
+
+static struct _9p_hashval *_9p_hash_new_val(gsize len)
+{
+ struct _9p_hashval *val;
+ val = wmem_new(wmem_file_scope(), struct _9p_hashval);
+
+ val->data = wmem_alloc(wmem_file_scope(), len);
+ val->len = len;
+
+ return val;
+}
+
+static void _9p_hash_set(packet_info *pinfo, guint16 tag, guint32 fid, struct _9p_hashval *val)
+{
+ struct _9p_hashkey *key;
+ struct _9p_hashval *oldval;
+ conversation_t *conv;
+
+ conv = find_or_create_conversation(pinfo);
+
+ key = wmem_new(wmem_file_scope(), struct _9p_hashkey);
+
+ key->conv_index = conv->conv_index;
+ key->tag = tag;
+ key->fid = fid;
+
+ /* remove eventual old entry */
+ oldval = (struct _9p_hashval *)wmem_map_lookup(_9p_hashtable, key);
+ if (oldval) {
+ wmem_map_remove(_9p_hashtable, key);
+ }
+ wmem_map_insert(_9p_hashtable, key, val);
+}
+
+static struct _9p_hashval *_9p_hash_get(packet_info *pinfo, guint16 tag, guint32 fid)
+{
+ struct _9p_hashkey key;
+ conversation_t *conv;
+
+ conv = find_or_create_conversation(pinfo);
+
+ key.conv_index = conv->conv_index;
+ key.tag = tag;
+ key.fid = fid;
+
+ return (struct _9p_hashval *)wmem_map_lookup(_9p_hashtable, &key);
+}
+
+static void _9p_hash_free(packet_info *pinfo, guint16 tag, guint32 fid)
+{
+ struct _9p_hashkey key;
+ conversation_t *conv;
+
+ conv = find_or_create_conversation(pinfo);
+
+ key.conv_index = conv->conv_index;
+ key.tag = tag;
+ key.fid = fid;
+
+ wmem_map_remove(_9p_hashtable, &key);
+}
+
+static void conv_set_version(packet_info *pinfo, enum _9p_version version)
+{
+ struct _9p_hashval *val;
+
+ val = _9p_hash_new_val(sizeof(enum _9p_version));
+
+
+ *(enum _9p_version*)val->data = version;
+
+ _9p_hash_set(pinfo, _9P_NOTAG, _9P_NOFID, val);
+}
+
+static enum _9p_version conv_get_version(packet_info *pinfo)
+{
+ struct _9p_hashval *val;
+
+ val = _9p_hash_get(pinfo, _9P_NOTAG, _9P_NOFID);
+
+ return val ? *(enum _9p_version*)val->data : _9P;
+}
+
+static void conv_set_fid_nocopy(packet_info *pinfo, guint32 fid, const char *path)
+{
+ struct _9p_hashval *val;
+
+ if (pinfo->fd->visited || fid == _9P_NOFID)
+ return;
+
+ /* get or create&insert fid tree */
+ val = _9p_hash_get(pinfo, _9P_NOTAG, fid);
+ if (!val) {
+ val = _9p_hash_new_val(0);
+ val->data = wmem_tree_new(wmem_file_scope());
+ /* val->len is intentionally left to 0 so the tree won't be freed */
+ _9p_hash_set(pinfo, _9P_NOTAG, fid, val);
+ }
+
+ /* fill it */
+ wmem_tree_insert32((wmem_tree_t *)val->data, pinfo->num, (void *)path);
+}
+
+static void conv_set_fid(packet_info *pinfo, guint32 fid, const gchar *path, gsize len)
+{
+ char *str;
+
+ if (pinfo->fd->visited || fid == _9P_NOFID || len == 0)
+ return;
+
+ str = (char*)wmem_alloc(wmem_file_scope(), len);
+ (void) g_strlcpy(str, path, len);
+ conv_set_fid_nocopy(pinfo, fid, str);
+}
+
+static const char *conv_get_fid(packet_info *pinfo, guint32 fid)
+{
+ struct _9p_hashval *val;
+
+ if (fid == _9P_NOFID)
+ return invalid_fid_str;
+
+ val = _9p_hash_get(pinfo, _9P_NOTAG, fid);
+ if (!val)
+ return invalid_fid_str;
+
+ /* -1 because the fid needs to have been set on a previous message.
+ Let's ignore the possibility of num == 0... */
+ return (char*)wmem_tree_lookup32_le((wmem_tree_t*)val->data, pinfo->num-1);
+}
+
+static inline void conv_free_fid(packet_info *pinfo, guint32 fid)
+{
+ conv_set_fid_nocopy(pinfo, fid, invalid_fid_str);
+}
+
+static void conv_set_tag(packet_info *pinfo, guint16 tag, enum _9p_msg_t msgtype, guint32 fid, wmem_strbuf_t *fid_path)
+{
+ struct _9p_hashval *val;
+ struct _9p_taginfo *taginfo;
+
+ if (pinfo->fd->visited || tag == _9P_NOTAG)
+ return;
+
+ val = _9p_hash_new_val(sizeof(struct _9p_taginfo));
+ taginfo = (struct _9p_taginfo*)val->data;
+
+ taginfo->msgtype = msgtype;
+ taginfo->fid = fid;
+ if (fid_path) {
+ taginfo->fid_path = (char*)wmem_alloc(wmem_file_scope(), wmem_strbuf_get_len(fid_path)+1);
+ (void) g_strlcpy(taginfo->fid_path, wmem_strbuf_get_str(fid_path), wmem_strbuf_get_len(fid_path)+1);
+ } else {
+ taginfo->fid_path = NULL;
+ }
+
+ _9p_hash_set(pinfo, tag, _9P_NOFID, val);
+}
+
+static inline struct _9p_taginfo *conv_get_tag(packet_info *pinfo, guint16 tag)
+{
+ struct _9p_hashval *val;
+
+ /* get tag only makes sense on first pass, as tree isn't built like fid */
+ if (pinfo->fd->visited || tag == _9P_NOTAG)
+ return NULL;
+
+ /* check that length matches? */
+ val = _9p_hash_get(pinfo, tag, _9P_NOFID);
+
+ return val ? (struct _9p_taginfo*)val->data : NULL;
+}
+
+static inline void conv_free_tag(packet_info *pinfo, guint16 tag)
+{
+ if (pinfo->fd->visited || tag == _9P_NOTAG)
+ return;
+
+ _9p_hash_free(pinfo, tag, _9P_NOFID);
+}
+
+/* dissects a string[s] (2 bytes followed by UTF-8 string) */
+static guint _9p_dissect_string(tvbuff_t *tvb, proto_tree *ninep_tree,
+ guint offset, int hf_string, gint ett_string)
+{
+ guint16 _9p_len;
+ proto_item *ti;
+ proto_tree *sub_tree;
+
+ _9p_len = tvb_get_letohs(tvb, offset);
+ ti = proto_tree_add_item(ninep_tree, hf_string, tvb, offset + 2,
+ _9p_len, ENC_UTF_8|ENC_NA);
+ sub_tree = proto_item_add_subtree(ti, ett_string);
+ proto_tree_add_item(sub_tree, hf_9P_parmsz, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+
+ return 2 + _9p_len;
+}
+
+/* Dissect 9P messages*/
+static int dissect_9P_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
+{
+ guint32 u32, i, fid, dfid, newfid;
+ guint16 u16, tag, _9p_len;
+ enum _9p_msg_t ninemsg;
+ guint offset = 0;
+ const char *mname, *fid_path;
+ char *tvb_s;
+ wmem_strbuf_t *tmppath = NULL;
+ gint len, reportedlen;
+ tvbuff_t *next_tvb;
+ proto_item *ti, *msg_item;
+ proto_tree *ninep_tree;
+ struct _9p_taginfo *taginfo;
+ int _9p_version;
+
+ _9p_version = conv_get_version(pinfo);
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, val_to_str_ext_const(_9p_version, &ninep_version_ext, "9P"));
+
+ col_clear(pinfo->cinfo, COL_INFO);
+
+ /*ninesz = tvb_get_letohl(tvb, offset);*/
+ ninemsg = (enum _9p_msg_t)tvb_get_guint8(tvb, offset + 4);
+
+ mname = val_to_str_ext_const(ninemsg, &ninep_msg_type_ext, "Unknown");
+
+ if(strcmp(mname, "Unknown") == 0) {
+ col_add_fstr(pinfo->cinfo, COL_INFO, "9P Data (Message type %u)", (guint)ninemsg);
+ return 0;
+ }
+
+ tag = tvb_get_letohs(tvb, offset+5);
+ col_append_fstr(pinfo->cinfo, COL_INFO, "%s Tag=%u", mname, (guint)tag);
+
+ ti = proto_tree_add_item(tree, proto_9P, tvb, 0, -1, ENC_NA);
+ ninep_tree = proto_item_add_subtree(ti, ett_9P);
+ proto_tree_add_item(ninep_tree, hf_9P_msgsz, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset+= 4;
+
+ msg_item = proto_tree_add_item(ninep_tree, hf_9P_msgtype, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+ ++offset;
+ proto_tree_add_item(ninep_tree, hf_9P_tag, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+ offset += 2;
+
+ switch(ninemsg) {
+ case _9P_RVERSION:
+ case _9P_TVERSION:
+ proto_tree_add_item(ninep_tree, hf_9P_maxsize, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ if (!pinfo->fd->visited) {
+ _9p_len = tvb_get_letohs(tvb, offset);
+ tvb_s = (char *)tvb_get_string_enc(pinfo->pool, tvb, offset+2, _9p_len, ENC_UTF_8|ENC_NA);
+
+ if (!strcmp(tvb_s, "9P2000.L")) {
+ u32 = _9P2000_L;
+ } else if (!strcmp(tvb_s, "9P2000")) {
+ u32 = _9P2000;
+ } else if (!strcmp(tvb_s, "9P2000.u")) {
+ u32 = _9P2000_u;
+ } else {
+ u32 = _9P;
+ }
+
+ conv_set_version(pinfo, (enum _9p_version)u32);
+ }
+ offset += _9p_dissect_string(tvb, ninep_tree, offset, hf_9P_version, ett_9P_version);
+
+ /* don't set tag for tversion/free it for rversion,
+ we need that for the actual version number */
+ break;
+
+ case _9P_TAUTH:
+ proto_tree_add_item(ninep_tree, hf_9P_afid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ fid = tvb_get_letohl(tvb, offset);
+ conv_set_fid_nocopy(pinfo, fid, afid_str);
+ offset += 4;
+
+ offset += _9p_dissect_string(tvb, ninep_tree, offset, hf_9P_uname, ett_9P_uname);
+ offset += _9p_dissect_string(tvb, ninep_tree, offset, hf_9P_aname, ett_9P_aname);
+
+ conv_set_tag(pinfo, tag, ninemsg, fid, NULL);
+ break;
+
+ case _9P_RERROR:
+ if (_9p_version == _9P2000_L) {
+ u32 = tvb_get_letohl(tvb, offset);
+ ti = proto_tree_add_item(ninep_tree, hf_9P_enum, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_item_append_text(ti, " (%s)", val_to_str_ext_const(u32, &linux_errno_ext, "Unknown"));
+ offset += 4;
+ } else {
+ offset += _9p_dissect_string(tvb, ninep_tree, offset, hf_9P_ename, ett_9P_ename);
+ }
+
+ /* conv_get_tag checks we're in first pass */
+ taginfo = conv_get_tag(pinfo, tag);
+ if (taginfo && (taginfo->msgtype == _9P_TWALK || taginfo->msgtype == _9P_TATTACH))
+ conv_free_fid(pinfo, taginfo->fid);
+
+ conv_free_tag(pinfo, tag);
+ break;
+
+ case _9P_TFLUSH:
+ u16 = tvb_get_letohs(tvb, offset);
+ proto_tree_add_item(ninep_tree, hf_9P_oldtag, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+ conv_free_tag(pinfo, u16);
+
+ conv_set_tag(pinfo, tag, ninemsg, _9P_NOFID, NULL);
+ break;
+
+ case _9P_TATTACH:
+ fid = tvb_get_letohl(tvb, offset);
+ proto_tree_add_item(ninep_tree, hf_9P_fid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ proto_tree_add_item(ninep_tree, hf_9P_afid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ offset += _9p_dissect_string(tvb, ninep_tree, offset, hf_9P_uname, ett_9P_uname);
+
+ if(!pinfo->fd->visited) {
+ _9p_len = tvb_get_letohs(tvb, offset);
+ tvb_s = (char*)tvb_get_string_enc(pinfo->pool, tvb, offset+2, _9p_len, ENC_UTF_8|ENC_NA);
+ conv_set_fid(pinfo, fid, tvb_s, strlen(tvb_s)+1);
+ }
+ offset += _9p_dissect_string(tvb, ninep_tree, offset, hf_9P_aname, ett_9P_aname);
+
+ if (_9p_version == _9P2000_u || _9p_version == _9P2000_L) {
+ proto_tree_add_item(ninep_tree, hf_9P_uid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+ }
+
+ conv_set_tag(pinfo, tag, ninemsg, fid, NULL);
+ break;
+
+ case _9P_TWALK:
+ fid = tvb_get_letohl(tvb, offset);
+ ti = proto_tree_add_item(ninep_tree, hf_9P_fid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ fid_path = conv_get_fid(pinfo, fid);
+ proto_item_append_text(ti, " (%s)", fid_path);
+ if (!pinfo->fd->visited) {
+ tmppath = wmem_strbuf_create(pinfo->pool);
+ wmem_strbuf_append(tmppath, fid_path);
+ }
+ offset += 4;
+
+ fid = tvb_get_letohl(tvb, offset);
+ proto_tree_add_item(ninep_tree, hf_9P_newfid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ u16 = tvb_get_letohs(tvb, offset);
+ proto_tree_add_item(ninep_tree, hf_9P_nwalk, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+ offset += 2;
+
+ for(i = 0 ; i < u16; i++) {
+ if (!pinfo->fd->visited) {
+ _9p_len = tvb_get_letohs(tvb, offset);
+ tvb_s = (char*)tvb_get_string_enc(pinfo->pool, tvb, offset+2, _9p_len, ENC_UTF_8|ENC_NA);
+ wmem_strbuf_append_c(tmppath, '/');
+ wmem_strbuf_append(tmppath, tvb_s);
+ }
+
+ if (i < 250) {
+ offset += _9p_dissect_string(tvb, ninep_tree, offset, hf_9P_wname, ett_9P_wname);
+ }
+ }
+
+ /* I can't imagine anyone having a directory depth more than 25,
+ Limit to 10 times that to be sure, 2^16 is too much */
+ if(u16 > 250) {
+ expert_add_info(pinfo, ti, &ei_9P_first_250);
+ }
+
+ if (!pinfo->fd->visited) {
+ conv_set_fid(pinfo, fid, wmem_strbuf_get_str(tmppath), wmem_strbuf_get_len(tmppath)+1);
+ }
+
+ conv_set_tag(pinfo, tag, ninemsg, fid, NULL);
+ break;
+
+ case _9P_RWALK:
+ u16 = tvb_get_letohs(tvb, offset);
+ ti = proto_tree_add_item(ninep_tree, hf_9P_nqid, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+ offset += 2;
+ /* I can't imagine anyone having a directory depth more than 25,
+ Limit to 10 times that to be sure, 2^16 is too much */
+ if(u16 > 250) {
+ u16 = 250;
+ }
+
+ for(i = 0; i < u16; i++) {
+ dissect_9P_qid(tvb, ninep_tree, offset);
+ offset += 13;
+ }
+
+ if (i >= 250) {
+ expert_add_info(pinfo, ti, &ei_9P_first_250);
+ }
+
+ conv_free_tag(pinfo, tag);
+ break;
+ case _9P_TLOPEN:
+ fid = tvb_get_letohl(tvb, offset);
+ ti = proto_tree_add_item(ninep_tree, hf_9P_fid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_item_append_text(ti, " (%s)", conv_get_fid(pinfo, fid));
+ offset += 4;
+
+ ti = proto_tree_add_item(ninep_tree, hf_9P_statmode, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ dissect_9P_lflags(tvb, ti, offset);
+ offset += 4;
+ conv_set_tag(pinfo, tag, ninemsg, _9P_NOFID, NULL);
+ break;
+
+ case _9P_TOPEN:
+ fid = tvb_get_letohl(tvb, offset);
+ ti = proto_tree_add_item(ninep_tree, hf_9P_fid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_item_append_text(ti, " (%s)", conv_get_fid(pinfo, fid));
+ offset += 4;
+
+ proto_tree_add_bitmask(ninep_tree, tvb, offset, hf_9P_mode, ett_9P_omode, _9P_modes, ENC_LITTLE_ENDIAN);
+ offset += 1;
+
+ conv_set_tag(pinfo, tag, ninemsg, _9P_NOFID, NULL);
+ break;
+
+ case _9P_TCREATE:
+ fid = tvb_get_letohl(tvb, offset);
+ ti = proto_tree_add_item(ninep_tree, hf_9P_fid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ fid_path = conv_get_fid(pinfo, fid);
+ proto_item_append_text(ti, " (%s)", fid_path);
+ offset += 4;
+
+ if (!pinfo->fd->visited) {
+ _9p_len = tvb_get_letohs(tvb, offset);
+ tmppath = wmem_strbuf_create(pinfo->pool);
+ wmem_strbuf_append(tmppath, fid_path);
+ wmem_strbuf_append_c(tmppath, '/');
+ tvb_s = (char*)tvb_get_string_enc(pinfo->pool, tvb, offset+2, _9p_len, ENC_UTF_8|ENC_NA);
+ wmem_strbuf_append(tmppath, tvb_s);
+ }
+ offset += _9p_dissect_string(tvb, ninep_tree, offset, hf_9P_filename, ett_9P_filename);
+
+ ti = proto_tree_add_item(ninep_tree, hf_9P_perm, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ dissect_9P_dm(tvb, ti, offset, 1);
+ offset += 4;
+
+ proto_tree_add_bitmask(ninep_tree, tvb, offset, hf_9P_mode, ett_9P_omode, _9P_modes, ENC_LITTLE_ENDIAN);
+ offset += 1;
+
+ if (_9p_version == _9P2000_u) {
+ _9p_len = tvb_get_letohs(tvb, offset);
+ proto_tree_add_item(ninep_tree, hf_9P_extension, tvb, offset+2, 4, ENC_ASCII);
+ offset += 2 + _9p_len;
+ }
+
+ conv_set_tag(pinfo, tag, ninemsg, fid, tmppath);
+ break;
+
+ case _9P_TLCREATE:
+ fid = tvb_get_letohl(tvb, offset);
+ ti = proto_tree_add_item(ninep_tree, hf_9P_fid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ fid_path = conv_get_fid(pinfo, fid);
+ proto_item_append_text(ti, " (%s)", fid_path);
+ offset += 4;
+
+ if (!pinfo->fd->visited) {
+ _9p_len = tvb_get_letohs(tvb, offset);
+ tmppath = wmem_strbuf_create(pinfo->pool);
+ wmem_strbuf_append(tmppath, fid_path);
+ wmem_strbuf_append_c(tmppath, '/');
+ tvb_s = (char*)tvb_get_string_enc(pinfo->pool, tvb, offset+2, _9p_len, ENC_UTF_8|ENC_NA);
+ wmem_strbuf_append(tmppath, tvb_s);
+ }
+ offset += _9p_dissect_string(tvb, ninep_tree, offset, hf_9P_filename, ett_9P_filename);
+
+ ti = proto_tree_add_item(ninep_tree, hf_9P_lflags, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ dissect_9P_lflags(tvb, ti, offset);
+ offset += 4;
+
+ ti = proto_tree_add_item(ninep_tree, hf_9P_statmode, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ dissect_9P_dm(tvb, ti, offset, 0);
+ offset += 4;
+
+ proto_tree_add_item(ninep_tree, hf_9P_gid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ conv_set_tag(pinfo, tag, ninemsg, fid, tmppath);
+ break;
+
+ case _9P_TREAD:
+ case _9P_TREADDIR:
+ fid = tvb_get_letohl(tvb, offset);
+ ti = proto_tree_add_item(ninep_tree, hf_9P_fid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_item_append_text(ti, " (%s)", conv_get_fid(pinfo, fid));
+ offset += 4;
+
+ proto_tree_add_item(ninep_tree, hf_9P_offset, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+ offset += 8;
+
+ proto_tree_add_item(ninep_tree, hf_9P_count, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ conv_set_tag(pinfo, tag, ninemsg, _9P_NOFID, NULL);
+ break;
+
+ case _9P_RREAD:
+ case _9P_RREADDIR:
+ u32 = tvb_get_letohl(tvb, offset);
+ proto_tree_add_item(ninep_tree, hf_9P_count, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ len = tvb_reported_length_remaining(tvb, offset);
+ reportedlen = ((gint)u32&0xffff) > len ? len : (gint)u32&0xffff;
+ next_tvb = tvb_new_subset_length_caplen(tvb, offset, len, reportedlen);
+ call_data_dissector(next_tvb, pinfo, tree);
+ offset += len;
+
+ conv_free_tag(pinfo, tag);
+ break;
+
+ case _9P_TWRITE:
+ fid = tvb_get_letohl(tvb, offset);
+ ti = proto_tree_add_item(ninep_tree, hf_9P_fid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_item_append_text(ti, " (%s)", conv_get_fid(pinfo, fid));
+ offset += 4;
+
+ proto_tree_add_item(ninep_tree, hf_9P_offset, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+ offset += 8;
+
+ u32 = tvb_get_letohl(tvb, offset);
+ proto_tree_add_item(ninep_tree, hf_9P_count, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+ len = tvb_reported_length_remaining(tvb, offset);
+ reportedlen = ((gint)u32&0xffff) > len ? len : (gint)u32&0xffff;
+ next_tvb = tvb_new_subset_length_caplen(tvb, offset, len, reportedlen);
+ call_data_dissector(next_tvb, pinfo, tree);
+ offset += len;
+
+ conv_set_tag(pinfo, tag, ninemsg, _9P_NOFID, NULL);
+ break;
+
+ case _9P_RWRITE:
+ proto_tree_add_item(ninep_tree, hf_9P_count, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ conv_free_tag(pinfo, tag);
+ break;
+
+ case _9P_RSTAT:
+ proto_tree_add_item(ninep_tree, hf_9P_parmsz, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+ offset += 2;
+
+ proto_tree_add_item(ninep_tree, hf_9P_sdlen, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+ offset += 2;
+
+ proto_tree_add_item(ninep_tree, hf_9P_stattype, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+ offset += 2;
+
+ proto_tree_add_item(ninep_tree, hf_9P_dev, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ dissect_9P_qid(tvb, ninep_tree, offset);
+ offset += 13;
+
+ ti = proto_tree_add_item(ninep_tree, hf_9P_statmode, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ dissect_9P_dm(tvb, ti, offset, 0);
+ offset += 4;
+
+ proto_tree_add_item(ninep_tree, hf_9P_atime, tvb, offset, 4, ENC_TIME_SECS|ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ proto_tree_add_item(ninep_tree, hf_9P_mtime, tvb, offset, 4, ENC_TIME_SECS|ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ proto_tree_add_item(ninep_tree, hf_9P_length, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+ offset += 8;
+
+ offset += _9p_dissect_string(tvb, ninep_tree, offset, hf_9P_filename, ett_9P_filename);
+ offset += _9p_dissect_string(tvb, ninep_tree, offset, hf_9P_user, ett_9P_user);
+ offset += _9p_dissect_string(tvb, ninep_tree, offset, hf_9P_group, ett_9P_group);
+ offset += _9p_dissect_string(tvb, ninep_tree, offset, hf_9P_muid, ett_9P_muid);
+
+ conv_free_tag(pinfo, tag);
+ break;
+
+ case _9P_TWSTAT:
+ fid = tvb_get_letohl(tvb, offset);
+ ti = proto_tree_add_item(ninep_tree, hf_9P_fid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_item_append_text(ti, " (%s)", conv_get_fid(pinfo, fid));
+ offset += 4;
+
+ proto_tree_add_item(ninep_tree, hf_9P_parmsz, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+ offset += 2;
+
+ proto_tree_add_item(ninep_tree, hf_9P_sdlen, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+ offset += 2;
+
+ proto_tree_add_item(ninep_tree, hf_9P_stattype, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+ offset += 2;
+
+ proto_tree_add_item(ninep_tree, hf_9P_dev, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ dissect_9P_qid(tvb, ninep_tree, offset);
+ offset += 13;
+
+ ti = proto_tree_add_item(ninep_tree, hf_9P_statmode, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ dissect_9P_dm(tvb, ti, offset, 0);
+ offset += 4;
+
+ proto_tree_add_item(ninep_tree, hf_9P_atime, tvb, offset, 4, ENC_TIME_SECS|ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ proto_tree_add_item(ninep_tree, hf_9P_mtime, tvb, offset, 4, ENC_TIME_SECS|ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ proto_tree_add_item(ninep_tree, hf_9P_length, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+ offset += 8;
+
+ offset += _9p_dissect_string(tvb, ninep_tree, offset, hf_9P_filename, ett_9P_filename);
+ offset += _9p_dissect_string(tvb, ninep_tree, offset, hf_9P_user, ett_9P_user);
+ offset += _9p_dissect_string(tvb, ninep_tree, offset, hf_9P_group, ett_9P_group);
+ offset += _9p_dissect_string(tvb, ninep_tree, offset, hf_9P_muid, ett_9P_muid);
+
+ conv_set_tag(pinfo, tag, ninemsg, _9P_NOFID, NULL);
+ break;
+
+ case _9P_TGETATTR:
+ fid = tvb_get_letohl(tvb, offset);
+ ti = proto_tree_add_item(ninep_tree, hf_9P_fid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_item_append_text(ti, " (%s)", conv_get_fid(pinfo, fid));
+ offset += 4;
+
+ ti = proto_tree_add_item(ninep_tree, hf_9P_getattr_flags, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+ dissect_9P_getattrflags(tvb, ti, offset);
+ offset += 8;
+
+ conv_set_tag(pinfo, tag, ninemsg, _9P_NOFID, NULL);
+ break;
+
+ case _9P_RGETATTR:
+ ti = proto_tree_add_item(ninep_tree, hf_9P_getattr_flags, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+ dissect_9P_getattrflags(tvb, ti, offset);
+ offset += 8;
+
+ dissect_9P_qid(tvb, ninep_tree, offset);
+ offset += 13;
+
+ ti = proto_tree_add_item(ninep_tree, hf_9P_statmode, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ dissect_9P_dm(tvb, ti, offset, 0);
+ offset += 4;
+
+ proto_tree_add_item(ninep_tree, hf_9P_uid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ proto_tree_add_item(ninep_tree, hf_9P_gid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ proto_tree_add_item(ninep_tree, hf_9P_nlink, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+ offset += 8;
+
+ proto_tree_add_item(ninep_tree, hf_9P_rdev, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+ offset += 8;
+
+ proto_tree_add_item(ninep_tree, hf_9P_size, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+ offset += 8;
+
+ proto_tree_add_item(ninep_tree, hf_9P_blksize, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+ offset += 8;
+
+ proto_tree_add_item(ninep_tree, hf_9P_blocks, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+ offset += 8;
+
+ proto_tree_add_item(ninep_tree, hf_9P_atime, tvb, offset, 16, ENC_TIME_SECS_NSECS|ENC_LITTLE_ENDIAN);
+ offset += 16;
+
+ proto_tree_add_item(ninep_tree, hf_9P_mtime, tvb, offset, 16, ENC_TIME_SECS_NSECS|ENC_LITTLE_ENDIAN);
+ offset += 16;
+
+ proto_tree_add_item(ninep_tree, hf_9P_ctime, tvb, offset, 16, ENC_TIME_SECS_NSECS|ENC_LITTLE_ENDIAN);
+ offset += 16;
+
+ proto_tree_add_item(ninep_tree, hf_9P_btime, tvb, offset, 16, ENC_TIME_SECS_NSECS|ENC_LITTLE_ENDIAN);
+ offset += 16;
+
+ proto_tree_add_item(ninep_tree, hf_9P_gen, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+ offset += 8;
+
+ proto_tree_add_item(ninep_tree, hf_9P_dataversion, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+ offset += 8;
+
+ conv_free_tag(pinfo, tag);
+ break;
+
+ case _9P_TSETATTR:
+ fid = tvb_get_letohl(tvb, offset);
+ ti = proto_tree_add_item(ninep_tree, hf_9P_fid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_item_append_text(ti, " (%s)", conv_get_fid(pinfo, fid));
+ offset += 4;
+
+ ti = proto_tree_add_item(ninep_tree, hf_9P_setattr_flags, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ dissect_9P_setattrflags(tvb, ti, offset);
+ offset += 4;
+
+ ti = proto_tree_add_item(ninep_tree, hf_9P_statmode, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ dissect_9P_dm(tvb, ti, offset, 0);
+ offset += 4;
+
+ proto_tree_add_item(ninep_tree, hf_9P_uid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ proto_tree_add_item(ninep_tree, hf_9P_gid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ proto_tree_add_item(ninep_tree, hf_9P_size, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+ offset += 8;
+
+ proto_tree_add_item(ninep_tree, hf_9P_atime, tvb, offset, 16, ENC_TIME_SECS_NSECS|ENC_LITTLE_ENDIAN);
+ offset += 16;
+
+ proto_tree_add_item(ninep_tree, hf_9P_mtime, tvb, offset, 16, ENC_TIME_SECS_NSECS|ENC_LITTLE_ENDIAN);
+ offset += 16;
+
+ conv_set_tag(pinfo, tag, ninemsg, _9P_NOFID, NULL);
+ break;
+
+ case _9P_RSTATFS:
+ proto_tree_add_item(ninep_tree, hf_9P_fstype, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ proto_tree_add_item(ninep_tree, hf_9P_blksize, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ proto_tree_add_item(ninep_tree, hf_9P_blocks, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+ offset += 8;
+
+ proto_tree_add_item(ninep_tree, hf_9P_bfree, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+ offset += 8;
+
+ proto_tree_add_item(ninep_tree, hf_9P_bavail, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+ offset += 8;
+
+ proto_tree_add_item(ninep_tree, hf_9P_files, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+ offset += 8;
+
+ proto_tree_add_item(ninep_tree, hf_9P_ffree, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+ offset += 8;
+
+ proto_tree_add_item(ninep_tree, hf_9P_fsid, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+ offset += 8;
+
+ proto_tree_add_item(ninep_tree, hf_9P_namelen, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ conv_free_tag(pinfo, tag);
+ break;
+
+ case _9P_TSYMLINK:
+ fid = tvb_get_letohl(tvb, offset);
+ ti = proto_tree_add_item(ninep_tree, hf_9P_fid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_item_append_text(ti, " (%s)", conv_get_fid(pinfo, fid));
+ offset += 4;
+
+ /* name */
+ offset += _9p_dissect_string(tvb, ninep_tree, offset, hf_9P_wname, ett_9P_wname);
+ /* XXX: maybe use a new field for symtgt? */
+ offset += _9p_dissect_string(tvb, ninep_tree, offset, hf_9P_wname, ett_9P_wname);
+
+ proto_tree_add_item(ninep_tree, hf_9P_gid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ conv_set_tag(pinfo, tag, ninemsg, _9P_NOFID, NULL);
+ break;
+
+ case _9P_TMKNOD:
+ fid = tvb_get_letohl(tvb, offset);
+ ti = proto_tree_add_item(ninep_tree, hf_9P_fid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_item_append_text(ti, " (%s)", conv_get_fid(pinfo, fid));
+ offset += 4;
+
+ offset += _9p_dissect_string(tvb, ninep_tree, offset, hf_9P_wname, ett_9P_wname);
+
+ ti = proto_tree_add_item(ninep_tree, hf_9P_statmode, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ dissect_9P_dm(tvb, ti, offset, 0);
+ offset += 4;
+
+ proto_tree_add_item(ninep_tree, hf_9P_mknod_major, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ proto_tree_add_item(ninep_tree, hf_9P_mknod_minor, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ proto_tree_add_item(ninep_tree, hf_9P_gid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ conv_set_tag(pinfo, tag, ninemsg, _9P_NOFID, NULL);
+ break;
+
+ case _9P_TRENAME:
+ fid = tvb_get_letohl(tvb, offset);
+ ti = proto_tree_add_item(ninep_tree, hf_9P_fid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_item_append_text(ti, " (%s)", conv_get_fid(pinfo, fid));
+ offset += 4;
+
+ dfid = tvb_get_letohl(tvb, offset);
+ ti = proto_tree_add_item(ninep_tree, hf_9P_dfid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ fid_path = conv_get_fid(pinfo, dfid);
+ proto_item_append_text(ti, " (%s)", fid_path);
+ offset += 4;
+
+ if (!pinfo->fd->visited) {
+ _9p_len = tvb_get_letohs(tvb, offset);
+ tmppath = wmem_strbuf_create(pinfo->pool);
+ wmem_strbuf_append(tmppath, conv_get_fid(pinfo, dfid));
+ wmem_strbuf_append_c(tmppath, '/');
+
+ tvb_s = (char*)tvb_get_string_enc(pinfo->pool, tvb, offset+2, _9p_len, ENC_UTF_8|ENC_NA);
+ wmem_strbuf_append(tmppath, tvb_s);
+
+ conv_set_fid(pinfo, fid, wmem_strbuf_get_str(tmppath), wmem_strbuf_get_len(tmppath)+1);
+ }
+ offset += _9p_dissect_string(tvb, ninep_tree, offset, hf_9P_wname, ett_9P_wname);
+
+ conv_set_tag(pinfo, tag, ninemsg, _9P_NOFID, NULL);
+ break;
+
+ case _9P_RREADLINK:
+ offset += _9p_dissect_string(tvb, ninep_tree, offset, hf_9P_wname, ett_9P_wname);
+
+ conv_free_tag(pinfo, tag);
+ break;
+
+ case _9P_TXATTRWALK:
+ fid = tvb_get_letohl(tvb, offset);
+ ti = proto_tree_add_item(ninep_tree, hf_9P_fid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ fid_path = conv_get_fid(pinfo, fid);
+ proto_item_append_text(ti, " (%s)", fid_path);
+ offset += 4;
+
+ newfid = tvb_get_letohl(tvb, offset);
+ proto_tree_add_item(ninep_tree, hf_9P_newfid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ conv_set_fid_nocopy(pinfo, newfid, fid_path);
+ offset += 4;
+
+ offset += _9p_dissect_string(tvb, ninep_tree, offset, hf_9P_wname, ett_9P_wname);
+
+ conv_set_tag(pinfo, tag, ninemsg, _9P_NOFID, NULL);
+ break;
+
+ case _9P_RXATTRWALK:
+ proto_tree_add_item(ninep_tree, hf_9P_size, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+ offset += 8;
+
+ conv_free_tag(pinfo, tag);
+ break;
+
+ case _9P_TXATTRCREATE:
+ fid = tvb_get_letohl(tvb, offset);
+ ti = proto_tree_add_item(ninep_tree, hf_9P_fid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_item_append_text(ti, " (%s)", conv_get_fid(pinfo, fid));
+ offset += 4;
+
+ offset += _9p_dissect_string(tvb, ninep_tree, offset, hf_9P_wname, ett_9P_wname);
+
+ proto_tree_add_item(ninep_tree, hf_9P_size, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+ offset += 8;
+
+ proto_tree_add_item(ninep_tree, hf_9P_xattr_flag, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ conv_set_tag(pinfo, tag, ninemsg, _9P_NOFID, NULL);
+ break;
+
+ case _9P_TLOCK:
+ case _9P_TGETLOCK:
+ fid = tvb_get_letohl(tvb, offset);
+ ti = proto_tree_add_item(ninep_tree, hf_9P_fid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_item_append_text(ti, " (%s)", conv_get_fid(pinfo, fid));
+ offset += 4;
+
+ proto_tree_add_item(ninep_tree, hf_9P_lock_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+ offset += 1;
+
+ proto_tree_add_item(ninep_tree, hf_9P_lock_flag, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ proto_tree_add_item(ninep_tree, hf_9P_lock_start, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+ offset += 8;
+
+ proto_tree_add_item(ninep_tree, hf_9P_lock_length, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+ offset += 8;
+
+ proto_tree_add_item(ninep_tree, hf_9P_lock_procid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ offset += _9p_dissect_string(tvb, ninep_tree, offset, hf_9P_wname, ett_9P_wname);
+
+ conv_set_tag(pinfo, tag, ninemsg, _9P_NOFID, NULL);
+ break;
+
+ case _9P_RLOCK:
+ proto_tree_add_item(ninep_tree, hf_9P_lock_status, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+ offset += 1;
+
+ conv_free_tag(pinfo, tag);
+ break;
+
+ case _9P_RGETLOCK:
+ proto_tree_add_item(ninep_tree, hf_9P_lock_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+ offset += 1;
+
+ proto_tree_add_item(ninep_tree, hf_9P_lock_flag, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ proto_tree_add_item(ninep_tree, hf_9P_lock_start, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+ offset += 8;
+
+ proto_tree_add_item(ninep_tree, hf_9P_lock_length, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+ offset += 8;
+
+ proto_tree_add_item(ninep_tree, hf_9P_lock_procid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ offset += _9p_dissect_string(tvb, ninep_tree, offset, hf_9P_wname, ett_9P_wname);
+
+ conv_free_tag(pinfo, tag);
+ break;
+
+ case _9P_TLINK:
+ fid = tvb_get_letohl(tvb, offset);
+ ti = proto_tree_add_item(ninep_tree, hf_9P_dfid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_item_append_text(ti, " (%s)", conv_get_fid(pinfo, fid));
+ offset += 4;
+
+ fid = tvb_get_letohl(tvb, offset);
+ ti = proto_tree_add_item(ninep_tree, hf_9P_fid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_item_append_text(ti, " (%s)", conv_get_fid(pinfo, fid));
+ offset += 4;
+
+ offset += _9p_dissect_string(tvb, ninep_tree, offset, hf_9P_wname, ett_9P_wname);
+
+ conv_set_tag(pinfo, tag, ninemsg, _9P_NOFID, NULL);
+ break;
+
+ case _9P_TMKDIR:
+ fid = tvb_get_letohl(tvb, offset);
+ ti = proto_tree_add_item(ninep_tree, hf_9P_fid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_item_append_text(ti, " (%s)", conv_get_fid(pinfo, fid));
+ offset += 4;
+
+ offset += _9p_dissect_string(tvb, ninep_tree, offset, hf_9P_wname, ett_9P_wname);
+
+ ti = proto_tree_add_item(ninep_tree, hf_9P_statmode, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ dissect_9P_dm(tvb, ti, offset, 0);
+ offset += 4;
+
+ proto_tree_add_item(ninep_tree, hf_9P_gid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ conv_set_tag(pinfo, tag, ninemsg, _9P_NOFID, NULL);
+ break;
+
+ case _9P_TRENAMEAT:
+ fid = tvb_get_letohl(tvb, offset);
+ ti = proto_tree_add_item(ninep_tree, hf_9P_dfid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_item_append_text(ti, " (%s)", conv_get_fid(pinfo, fid));
+ offset += 4;
+
+ offset += _9p_dissect_string(tvb, ninep_tree, offset, hf_9P_wname, ett_9P_wname);
+
+ fid = tvb_get_letohl(tvb, offset);
+ ti = proto_tree_add_item(ninep_tree, hf_9P_newfid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_item_append_text(ti, " (%s)", conv_get_fid(pinfo, fid));
+ offset += 4;
+
+ offset += _9p_dissect_string(tvb, ninep_tree, offset, hf_9P_wname, ett_9P_wname);
+
+ conv_set_tag(pinfo, tag, ninemsg, _9P_NOFID, NULL);
+ break;
+
+ case _9P_TUNLINKAT:
+ fid = tvb_get_letohl(tvb, offset);
+ ti = proto_tree_add_item(ninep_tree, hf_9P_dfid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_item_append_text(ti, " (%s)", conv_get_fid(pinfo, fid));
+ offset += 4;
+
+ offset += _9p_dissect_string(tvb, ninep_tree, offset, hf_9P_wname, ett_9P_wname);
+
+ proto_tree_add_item(ninep_tree, hf_9P_unlinkat_flags, tvb,
+ offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ conv_set_tag(pinfo, tag, ninemsg, _9P_NOFID, NULL);
+ break;
+
+ case _9P_TREMOVE:
+ case _9P_TCLUNK:
+ fid = tvb_get_letohl(tvb, offset);
+ ti = proto_tree_add_item(ninep_tree, hf_9P_fid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+ proto_item_append_text(ti, " (%s)", conv_get_fid(pinfo, fid));
+ conv_free_fid(pinfo, fid);
+
+ conv_set_tag(pinfo, tag, ninemsg, fid, NULL);
+ break;
+
+ /* Request with only fid */
+ case _9P_TSTATFS:
+ case _9P_TREADLINK:
+ case _9P_TFSYNC:
+ case _9P_TSTAT:
+ fid = tvb_get_letohl(tvb, offset);
+ ti = proto_tree_add_item(ninep_tree, hf_9P_fid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+ proto_item_append_text(ti, " (%s)", conv_get_fid(pinfo, fid));
+
+ conv_set_tag(pinfo, tag, ninemsg, _9P_NOFID, NULL);
+ break;
+
+ /* Reply with qid and ionuit */
+ case _9P_RCREATE:
+ case _9P_RLCREATE:
+ dissect_9P_qid(tvb, ninep_tree, offset);
+ offset += 13;
+ proto_tree_add_item(ninep_tree, hf_9P_iounit, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ taginfo = conv_get_tag(pinfo, tag);
+ if (taginfo && taginfo->fid_path) {
+ conv_set_fid_nocopy(pinfo, taginfo->fid, taginfo->fid_path);
+ }
+
+ conv_free_tag(pinfo, tag);
+ break;
+
+ case _9P_ROPEN:
+ case _9P_RLOPEN:
+ dissect_9P_qid(tvb, ninep_tree, offset);
+ offset += 13;
+ proto_tree_add_item(ninep_tree, hf_9P_iounit, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
+
+ conv_free_tag(pinfo, tag);
+ break;
+
+ /* Reply with only qid */
+ case _9P_RSYMLINK:
+ case _9P_RMKNOD:
+ case _9P_RMKDIR:
+ case _9P_RAUTH:
+ case _9P_RATTACH:
+ dissect_9P_qid(tvb, ninep_tree, offset);
+ offset += 13;
+
+ conv_free_tag(pinfo, tag);
+ break;
+
+ /* Empty reply */
+ case _9P_RRENAME:
+ case _9P_RSETATTR:
+ case _9P_RXATTRCREATE:
+ case _9P_RFSYNC:
+ case _9P_RLINK:
+ case _9P_RRENAMEAT:
+ case _9P_RUNLINKAT:
+ case _9P_RFLUSH:
+ case _9P_RCLUNK:
+ case _9P_RREMOVE:
+ /* Unhandled reply */
+ case _9P_RWSTAT:
+ case _9P_RLERROR:
+ conv_free_tag(pinfo, tag);
+ break;
+
+ /* Should-not-happen query */
+ case _9P_TLERROR:
+ case _9P_TERROR:
+ default:
+ expert_add_info(pinfo, msg_item, &ei_9P_msgtype);
+ break;
+ }
+
+ /* Show any extra data at the end of the message (but only
+ if it was captured) */
+ if (offset != tvb_captured_length(tvb))
+ proto_tree_add_item(ninep_tree, hf_9P_unknown_message, tvb, offset, -1, ENC_NA);
+ return tvb_captured_length(tvb);
+}
+
+static guint get_9P_message_len(packet_info *pinfo _U_, tvbuff_t *tvb,
+ int offset, void *data _U_)
+{
+ return (guint) tvb_get_letohl(tvb, offset);
+}
+
+static int dissect_9P(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
+{
+ tcp_dissect_pdus(tvb, pinfo, tree, TRUE, 4,
+ get_9P_message_len, dissect_9P_message, data);
+ return tvb_captured_length(tvb);
+}
+
+/* dissect 9P Qid */
+static void dissect_9P_qid(tvbuff_t *tvb, proto_tree *tree, int offset)
+{
+ proto_item *qidtype_item;
+ proto_tree *qid_tree,*qidtype_tree;
+ guint64 path;
+ guint32 vers;
+ guint8 type;
+
+ if(!tree)
+ return;
+
+ type = tvb_get_guint8(tvb, offset);
+ vers = tvb_get_letohs(tvb, offset+1);
+ path = tvb_get_letoh64(tvb, offset+1+4);
+
+ qid_tree = proto_tree_add_subtree_format(tree, tvb, offset, 13, ett_9P_qid, NULL,
+ "Qid type=0x%02x vers=%d path=%" PRIu64, type, vers, path);
+
+ qidtype_item = proto_tree_add_item(qid_tree, hf_9P_qidtype, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+ qidtype_tree = proto_item_add_subtree(qidtype_item, ett_9P_qidtype);
+
+ proto_tree_add_item(qidtype_tree, hf_9P_qidtype_dir, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(qidtype_tree, hf_9P_qidtype_append, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(qidtype_tree, hf_9P_qidtype_exclusive, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(qidtype_tree, hf_9P_qidtype_mount, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(qidtype_tree, hf_9P_qidtype_auth_file, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(qidtype_tree, hf_9P_qidtype_temp_file, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+
+ proto_tree_add_item(qid_tree, hf_9P_qidvers, tvb, offset+1, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(qid_tree, hf_9P_qidpath, tvb, offset+1+4, 8, ENC_LITTLE_ENDIAN);
+}
+
+/*dissect 9P stat mode and create perm flags */
+static void dissect_9P_dm(tvbuff_t *tvb, proto_item *item, int offset, int iscreate)
+{
+ proto_item *mode_tree;
+
+
+ mode_tree = proto_item_add_subtree(item, ett_9P_dm);
+ if(!mode_tree)
+ return;
+
+ proto_tree_add_item(mode_tree, hf_9P_dm_dir, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ if(!iscreate) { /* Not applicable to Tcreate (?) */
+ proto_tree_add_item(mode_tree, hf_9P_dm_append, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(mode_tree, hf_9P_dm_exclusive, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(mode_tree, hf_9P_dm_mount, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(mode_tree, hf_9P_dm_auth_file, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(mode_tree, hf_9P_dm_temp_file, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ }
+
+ proto_tree_add_item(mode_tree, hf_9P_dm_read_owner, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(mode_tree, hf_9P_dm_write_owner, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(mode_tree, hf_9P_dm_exec_owner, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(mode_tree, hf_9P_dm_read_group, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(mode_tree, hf_9P_dm_write_group, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(mode_tree, hf_9P_dm_exec_group, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(mode_tree, hf_9P_dm_read_others, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(mode_tree, hf_9P_dm_write_others, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(mode_tree, hf_9P_dm_exec_others, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+}
+
+/* Dissect 9P getattr_flags */
+static void dissect_9P_getattrflags(tvbuff_t *tvb, proto_item *item, int offset)
+{
+ proto_item *attrmask_tree;
+
+ attrmask_tree = proto_item_add_subtree(item, ett_9P_getattr_flags);
+ if(!attrmask_tree)
+ return;
+
+ /* fixme: This is actually 8 bytes (64bit) long, but masks have to fit on 32bit. */
+ proto_tree_add_item(attrmask_tree, hf_9P_getattr_mode, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_getattr_nlink, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_getattr_uid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_getattr_gid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_getattr_rdev, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_getattr_atime, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_getattr_mtime, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_getattr_ctime, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_getattr_ino, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_getattr_size, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_getattr_blocks, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_getattr_btime, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_getattr_gen, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_getattr_dataversion, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+}
+
+/* Dissect 9P setattr_flags */
+static void dissect_9P_setattrflags(tvbuff_t *tvb, proto_item *item, int offset)
+{
+ proto_item *attrmask_tree;
+
+ attrmask_tree = proto_item_add_subtree(item, ett_9P_setattr_flags);
+ if(!attrmask_tree)
+ return;
+
+ proto_tree_add_item(attrmask_tree, hf_9P_setattr_mode, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_setattr_uid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_setattr_gid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_setattr_size, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_setattr_atime, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_setattr_mtime, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_setattr_ctime, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_setattr_atime_set, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_setattr_mtime_set, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+}
+
+/* Dissect 9P lflags */
+static void dissect_9P_lflags(tvbuff_t *tvb, proto_item *item, int offset)
+{
+ proto_item *attrmask_tree;
+
+ attrmask_tree = proto_item_add_subtree(item, ett_9P_lflags);
+ if(!attrmask_tree)
+ return;
+
+ proto_tree_add_item(attrmask_tree, hf_9P_lflags_rdonly, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_lflags_wronly, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_lflags_rdwr, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_lflags_create, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_lflags_excl, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_lflags_noctty, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_lflags_trunc, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_lflags_append, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_lflags_nonblock, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_lflags_dsync, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_lflags_fasync, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_lflags_direct, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_lflags_largefile, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_lflags_directory, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_lflags_nofollow, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_lflags_noatime, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_lflags_cloexec, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ proto_tree_add_item(attrmask_tree, hf_9P_lflags_sync, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+}
+
+
+/* Register 9P with Wireshark */
+void proto_register_9P(void)
+{
+ static hf_register_info hf[] = {
+ {&hf_9P_msgsz,
+ {"Msg length", "9p.msglen", FT_UINT32, BASE_DEC, NULL, 0x0,
+ "9P Message Length", HFILL}},
+ {&hf_9P_msgtype,
+ {"Msg Type", "9p.msgtype", FT_UINT8, BASE_DEC | BASE_EXT_STRING, &ninep_msg_type_ext, 0x0,
+ "Message Type", HFILL}},
+ {&hf_9P_tag,
+ {"Tag", "9p.tag", FT_UINT16, BASE_DEC, NULL, 0x0,
+ "9P Tag", HFILL}},
+ {&hf_9P_oldtag,
+ {"Old tag", "9p.oldtag", FT_UINT16, BASE_DEC, NULL, 0x0,
+ NULL, HFILL}},
+ {&hf_9P_parmsz,
+ {"Param length", "9p.paramsz", FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Parameter length", HFILL}},
+ {&hf_9P_maxsize,
+ {"Max msg size", "9p.maxsize", FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Max message size", HFILL}},
+ {&hf_9P_fid,
+ {"Fid", "9p.fid", FT_UINT32, BASE_DEC, NULL, 0x0,
+ "File ID", HFILL}},
+ {&hf_9P_nqid,
+ {"Nr Qids", "9p.nqid", FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Number of Qid results", HFILL}},
+ {&hf_9P_mode,
+ {"Mode", "9p.mode", FT_UINT8, BASE_HEX, NULL, 0x0,
+ NULL, HFILL}},
+ {&hf_9P_mode_rwx,
+ {"Open/Create Mode", "9p.mode.rwx", FT_UINT8, BASE_OCT | BASE_EXT_STRING, &ninep_mode_vals_ext, _9P_MODEMASK,
+ NULL, HFILL}},
+ {&hf_9P_mode_t,
+ {"Trunc", "9p.mode.trunc", FT_BOOLEAN, 8, TFS(&tfs_set_notset), _9P_OTRUNC,
+ "Truncate", HFILL}},
+ {&hf_9P_mode_c,
+ {"Remove on close", "9p.mode.orclose", FT_BOOLEAN, 8, TFS(&tfs_set_notset), _9P_ORCLOSE,
+ NULL, HFILL}},
+ {&hf_9P_extension,
+ {"Extension string", "9p.extension", FT_STRING, BASE_NONE, NULL, 0x0,
+ "Link target for DSYMLINK mode, major+minor for DMDEVICE, empty for normal files", HFILL}},
+ {&hf_9P_iounit,
+ {"I/O Unit", "9p.iounit", FT_UINT32, BASE_DEC, NULL, 0x0,
+ NULL, HFILL}},
+ {&hf_9P_count,
+ {"Count", "9p.count", FT_UINT32, BASE_DEC, NULL, 0x0,
+ NULL, HFILL}},
+ {&hf_9P_offset,
+ {"Offset", "9p.offset", FT_UINT64, BASE_DEC, NULL, 0x0,
+ NULL, HFILL}},
+ {&hf_9P_perm,
+ {"Permissions", "9p.perm", FT_UINT32, BASE_OCT, NULL, 0x0,
+ "Permission bits", HFILL}},
+ {&hf_9P_qidpath,
+ {"Qid path", "9p.qidpath", FT_UINT64, BASE_DEC, NULL, 0x0,
+ NULL, HFILL}},
+ {&hf_9P_dm_dir,
+ {"Directory", "9p.dm.dir", FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x80000000,
+ NULL, HFILL}},
+ {&hf_9P_dm_append,
+ {"Append only", "9p.dm.append", FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x40000000,
+ NULL, HFILL}},
+ {&hf_9P_dm_exclusive,
+ {"Exclusive use", "9p.dm.exclusive", FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x20000000,
+ NULL, HFILL}},
+ {&hf_9P_dm_mount,
+ {"Mounted channel", "9p.dm.mount", FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x10000000,
+ NULL, HFILL}},
+ {&hf_9P_dm_auth_file,
+ {"Authentication file", "9p.dm.auth_file", FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x08000000,
+ NULL, HFILL}},
+ {&hf_9P_dm_temp_file,
+ {"Temporary file (not backed up)", "9p.dm.temp_file", FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x04000000,
+ NULL, HFILL}},
+ {&hf_9P_dm_read_owner,
+ {"Read permission for owner", "9p.dm.read_owner", FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00000400,
+ NULL, HFILL}},
+ {&hf_9P_dm_write_owner,
+ {"Write permission for owner", "9p.dm.write_owner", FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00000200,
+ NULL, HFILL}},
+ {&hf_9P_dm_exec_owner,
+ {"Execute permission for owner", "9p.dm.exec_owner", FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00000100,
+ NULL, HFILL}},
+ {&hf_9P_dm_read_group,
+ {"Read permission for group", "9p.dm.read_group", FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00000040,
+ NULL, HFILL}},
+ {&hf_9P_dm_write_group,
+ {"Write permission for group", "9p.dm.write_group", FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00000020,
+ NULL, HFILL}},
+ {&hf_9P_dm_exec_group,
+ {"Execute permission for group", "9p.dm.exec_group", FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00000010,
+ NULL, HFILL}},
+ {&hf_9P_dm_read_others,
+ {"Read permission for others", "9p.dm.read_others", FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00000004,
+ NULL, HFILL}},
+ {&hf_9P_dm_write_others,
+ {"Write permission for others", "9p.dm.write_others", FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00000002,
+ NULL, HFILL}},
+ {&hf_9P_dm_exec_others,
+ {"Execute permission for others", "9p.dm.exec_others", FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00000001,
+ NULL, HFILL}},
+ {&hf_9P_qidvers,
+ {"Qid version", "9p.qidvers", FT_UINT32, BASE_DEC, NULL, 0x0,
+ NULL, HFILL}},
+ {&hf_9P_qidtype,
+ {"Qid type", "9p.qidtype", FT_UINT8, BASE_HEX, NULL, 0x0,
+ NULL, HFILL}},
+ {&hf_9P_qidtype_dir,
+ {"Directory", "9p.qidtype.dir", FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x80,
+ NULL, HFILL}},
+ {&hf_9P_qidtype_append,
+ {"Append only", "9p.qidtype.append", FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x40,
+ NULL, HFILL}},
+ {&hf_9P_qidtype_exclusive,
+ {"Exclusive use", "9p.qidtype.exclusive", FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x20,
+ NULL, HFILL}},
+ {&hf_9P_qidtype_mount,
+ {"Mounted channel", "9p.qidtype.mount", FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x10,
+ NULL, HFILL}},
+ {&hf_9P_qidtype_auth_file,
+ {"Authentication file", "9p.qidtype.auth_file", FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x08,
+ NULL, HFILL}},
+ {&hf_9P_qidtype_temp_file,
+ {"Temporary file (not backed up)", "9p.qidtype.temp_file", FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x04,
+ NULL, HFILL}},
+ {&hf_9P_statmode,
+ {"Mode", "9p.statmode", FT_UINT32, BASE_OCT, NULL, 0x0,
+ "File mode flags", HFILL}},
+ {&hf_9P_stattype,
+ {"Type", "9p.stattype", FT_UINT16, BASE_DEC, NULL, 0x0,
+ NULL, HFILL}},
+ {&hf_9P_atime,
+ {"Atime", "9p.atime", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0,
+ "Access Time", HFILL}},
+ {&hf_9P_mtime,
+ {"Mtime", "9p.mtime", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0,
+ "Modified Time", HFILL}},
+ {&hf_9P_ctime,
+ {"Ctime", "9p.ctime", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0,
+ "Creation Time", HFILL}},
+ {&hf_9P_btime,
+ {"Btime", "9p.btime", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0,
+ "Btime (Synchronization information)", HFILL}},
+ {&hf_9P_length,
+ {"Length", "9p.length", FT_UINT64, BASE_DEC, NULL, 0x0,
+ "File Length", HFILL}},
+ {&hf_9P_dev,
+ {"Dev", "9p.dev", FT_UINT32, BASE_DEC, NULL, 0x0,
+ NULL, HFILL}},
+ {&hf_9P_wname,
+ {"Wname", "9p.wname", FT_STRING, BASE_NONE, NULL, 0x0,
+ "Path Name Element", HFILL}},
+ {&hf_9P_version,
+ {"Version", "9p.version", FT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL}},
+ {&hf_9P_afid,
+ {"Afid", "9p.afid", FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Authenticating FID", HFILL}},
+ {&hf_9P_uname,
+ {"Uname", "9p.uname", FT_STRING, BASE_NONE, NULL, 0x0,
+ "User Name", HFILL}},
+ {&hf_9P_aname,
+ {"Aname", "9p.aname", FT_STRING, BASE_NONE, NULL, 0x0,
+ "Access Name", HFILL}},
+ {&hf_9P_ename,
+ {"Ename", "9p.ename", FT_STRING, BASE_NONE, NULL, 0x0,
+ "Error", HFILL}},
+ {&hf_9P_enum,
+ {"Enum", "9p.enum", FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Error", HFILL}},
+#if 0
+ {&hf_9P_name,
+ {"Name", "9p.name", FT_STRING, BASE_NONE, NULL, 0x0,
+ "Name of file", HFILL}},
+#endif
+ {&hf_9P_sdlen,
+ {"Stat data length", "9p.sdlen", FT_UINT16, BASE_DEC, NULL, 0x0,
+ NULL, HFILL}},
+ {&hf_9P_filename,
+ {"File name", "9p.filename", FT_STRING, BASE_NONE, NULL, 0x0,
+ NULL, HFILL}},
+ {&hf_9P_user,
+ {"User", "9p.user", FT_STRING, BASE_NONE, NULL, 0x0,
+ "User name", HFILL}},
+ {&hf_9P_group,
+ {"Group", "9p.group", FT_STRING, BASE_NONE, NULL, 0x0,
+ "Group name", HFILL}},
+ {&hf_9P_uid,
+ {"Uid", "9p.uid", FT_UINT32, BASE_DEC, NULL, 0x0,
+ "User id", HFILL}},
+ {&hf_9P_gid,
+ {"Gid", "9p.gid", FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Group id", HFILL}},
+ {&hf_9P_muid,
+ {"Muid", "9p.muid", FT_STRING, BASE_NONE, NULL, 0x0,
+ "Last modifiers uid", HFILL}},
+ {&hf_9P_newfid,
+ {"New fid", "9p.newfid", FT_UINT32, BASE_DEC, NULL, 0x0,
+ "New file ID", HFILL}},
+ {&hf_9P_dfid,
+ {"Directory fid", "9p.dfid", FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Directory ID", HFILL}},
+ {&hf_9P_nwalk,
+ {"Nr Walks", "9p.nwalk", FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Nr of walk items", HFILL}},
+ {&hf_9P_nlink,
+ {"nlink", "9p.nlink", FT_UINT64, BASE_DEC, NULL, 0x0,
+ "Number of links", HFILL}},
+ {&hf_9P_getattr_flags,
+ {"getattr_flags", "9p.getattr.flags", FT_UINT64, BASE_HEX, NULL, _9P_GETATTR_ALL,
+ "Getattr flags", HFILL}},
+ {&hf_9P_getattr_mode,
+ {"Mode", "9p.getattr.mode", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_GETATTR_MODE,
+ NULL, HFILL}},
+ {&hf_9P_getattr_nlink,
+ {"Nlink", "9p.getattr.nlink", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_GETATTR_NLINK,
+ NULL, HFILL}},
+ {&hf_9P_getattr_uid,
+ {"UID", "9p.getattr.uid", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_GETATTR_UID,
+ NULL, HFILL}},
+ {&hf_9P_getattr_gid,
+ {"GID", "9p.getattr.gid", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_GETATTR_GID,
+ NULL, HFILL}},
+ {&hf_9P_getattr_rdev,
+ {"Rdev", "9p.getattr.rdev", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_GETATTR_RDEV,
+ NULL, HFILL}},
+ {&hf_9P_getattr_atime,
+ {"Atime", "9p.getattr.atime", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_GETATTR_ATIME,
+ NULL, HFILL}},
+ {&hf_9P_getattr_mtime,
+ {"Mtime", "9p.getattr.mtime", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_GETATTR_MTIME,
+ NULL, HFILL}},
+ {&hf_9P_getattr_ctime,
+ {"Ctime", "9p.getattr.ctime", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_GETATTR_CTIME,
+ NULL, HFILL}},
+ {&hf_9P_getattr_ino,
+ {"Inode", "9p.getattr.inode", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_GETATTR_INO,
+ NULL, HFILL}},
+ {&hf_9P_getattr_size,
+ {"Size", "9p.getattr.size", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_GETATTR_SIZE,
+ NULL, HFILL}},
+ {&hf_9P_getattr_blocks,
+ {"Blocks", "9p.getattr.blocks", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_GETATTR_BLOCKS,
+ NULL, HFILL}},
+ {&hf_9P_getattr_btime,
+ {"Btime", "9p.getattr.btime", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_GETATTR_BTIME,
+ NULL, HFILL}},
+ {&hf_9P_getattr_gen,
+ {"Gen", "9p.getattr.gen", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_GETATTR_GEN,
+ NULL, HFILL}},
+ {&hf_9P_getattr_dataversion,
+ {"Data version", "9p.getattr.dataversion", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_GETATTR_DATA_VERSION,
+ NULL, HFILL}},
+ {&hf_9P_setattr_flags,
+ {"setattr_flags", "9p.setattr.flags", FT_UINT32, BASE_HEX, NULL, _9P_SETATTR_ALL,
+ "Setattr flags", HFILL}},
+ {&hf_9P_setattr_mode,
+ {"Mode", "9p.setattr.mode", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_SETATTR_MODE,
+ NULL, HFILL}},
+ {&hf_9P_setattr_uid,
+ {"UID", "9p.setattr.uid", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_SETATTR_UID,
+ NULL, HFILL}},
+ {&hf_9P_setattr_gid,
+ {"GID", "9p.setattr.gid", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_SETATTR_GID,
+ NULL, HFILL}},
+ {&hf_9P_setattr_size,
+ {"Size", "9p.setattr.size", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_SETATTR_SIZE,
+ NULL, HFILL}},
+ {&hf_9P_setattr_atime,
+ {"Atime", "9p.setattr.atime", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_SETATTR_ATIME,
+ NULL, HFILL}},
+ {&hf_9P_setattr_mtime,
+ {"Mtime", "9p.setattr.mtime", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_SETATTR_MTIME,
+ NULL, HFILL}},
+ {&hf_9P_setattr_ctime,
+ {"Ctime", "9p.setattr.ctime", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_SETATTR_CTIME,
+ NULL, HFILL}},
+ {&hf_9P_setattr_atime_set,
+ {"Atime set", "9p.setattr.atimeset", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_SETATTR_ATIME_SET,
+ NULL, HFILL}},
+ {&hf_9P_setattr_mtime_set,
+ {"Mtime set", "9p.setattr.mtimeset", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_SETATTR_MTIME_SET,
+ NULL, HFILL}},
+ {&hf_9P_unlinkat_flags,
+ {"unlinkat flags", "9p.unlinkat.flags", FT_UINT32, BASE_HEX, NULL, 0,
+ NULL, HFILL}},
+ {&hf_9P_rdev,
+ {"rdev", "9p.rdev", FT_UINT64, BASE_DEC, NULL, 0x0,
+ "Device associated with file", HFILL}},
+ {&hf_9P_size,
+ {"Size", "9p.size", FT_UINT64, BASE_DEC, NULL, 0x0,
+ NULL, HFILL}},
+ {&hf_9P_blksize,
+ {"Blksize", "9p.blksize", FT_UINT64, BASE_DEC, NULL, 0x0,
+ "Block size", HFILL}},
+ {&hf_9P_blocks,
+ {"Blocks", "9p.blocks", FT_UINT64, BASE_DEC, NULL, 0x0,
+ NULL, HFILL}},
+ {&hf_9P_gen,
+ {"Gen", "9p.gen", FT_UINT64, BASE_DEC, NULL, 0x0,
+ "inode generation number", HFILL}},
+ {&hf_9P_dataversion,
+ {"Dataversion", "9p.dataversion", FT_UINT64, BASE_DEC, NULL, 0x0,
+ "Data version", HFILL}},
+ {&hf_9P_fstype,
+ {"fstype", "9p.fstype", FT_UINT32, BASE_HEX, NULL, 0x0,
+ "Filesystem type", HFILL}},
+ {&hf_9P_bfree,
+ {"bfree", "9p.bfree", FT_UINT64, BASE_DEC, NULL, 0x0,
+ "Free blocks", HFILL}},
+ {&hf_9P_bavail,
+ {"bavail", "9p.bavail", FT_UINT64, BASE_DEC, NULL, 0x0,
+ "Available blocks", HFILL}},
+ {&hf_9P_files,
+ {"files", "9p.files", FT_UINT64, BASE_DEC, NULL, 0x0,
+ "Total files", HFILL}},
+ {&hf_9P_ffree,
+ {"ffree", "9p.ffree", FT_UINT64, BASE_DEC, NULL, 0x0,
+ "Free files", HFILL}},
+ {&hf_9P_fsid,
+ {"fsid", "9p.fsid", FT_UINT64, BASE_DEC, NULL, 0x0,
+ "Filesystem id", HFILL}},
+ {&hf_9P_namelen,
+ {"namelen", "9p.namelen", FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Max name length", HFILL}},
+ {&hf_9P_mknod_major,
+ {"mknod_major", "9p.mknod.major", FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Major node number", HFILL}},
+ {&hf_9P_mknod_minor,
+ {"mknod_minor", "9p.mknod.minor", FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Minor node number", HFILL}},
+ {&hf_9P_lflags,
+ {"lflags", "9p.lcreate.flags", FT_UINT32, BASE_HEX, NULL, 0x0,
+ "Lcreate flags", HFILL}},
+ /* rdonly is 0x00, check instead that we are neither wronly nor rdwrite */
+ {&hf_9P_lflags_rdonly,
+ {"Read only", "9p.lflags.rdonly", FT_BOOLEAN, 32, TFS(&tfs_no_yes), _9P_DOTL_WRONLY|_9P_DOTL_RDWR,
+ NULL, HFILL}},
+ {&hf_9P_lflags_wronly,
+ {"Write only", "9p.lflags.wronly", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_DOTL_WRONLY,
+ NULL, HFILL}},
+ {&hf_9P_lflags_rdwr,
+ {"Read Write", "9p.lflags.rdwr", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_DOTL_RDWR,
+ NULL, HFILL}},
+ {&hf_9P_lflags_create,
+ {"Create", "9p.lflags.create", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_DOTL_CREATE,
+ NULL, HFILL}},
+ {&hf_9P_lflags_excl,
+ {"Exclusive", "9p.lflags.excl", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_DOTL_EXCL,
+ NULL, HFILL}},
+ {&hf_9P_lflags_noctty,
+ {"noctty", "9p.lflags.noctty", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_DOTL_NOCTTY,
+ NULL, HFILL}},
+ {&hf_9P_lflags_trunc,
+ {"Truncate", "9p.lflags.trunc", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_DOTL_TRUNC,
+ NULL, HFILL}},
+ {&hf_9P_lflags_append,
+ {"Append", "9p.lflags.append", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_DOTL_APPEND,
+ NULL, HFILL}},
+ {&hf_9P_lflags_nonblock,
+ {"Nonblock", "9p.lflags.nonblock", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_DOTL_NONBLOCK,
+ NULL, HFILL}},
+ {&hf_9P_lflags_dsync,
+ {"dsync", "9p.lflags.dsync", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_DOTL_DSYNC,
+ NULL, HFILL}},
+ {&hf_9P_lflags_fasync,
+ {"fasync", "9p.lflags.fasync", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_DOTL_FASYNC,
+ NULL, HFILL}},
+ {&hf_9P_lflags_direct,
+ {"Direct", "9p.lflags.direct", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_DOTL_DIRECT,
+ NULL, HFILL}},
+ {&hf_9P_lflags_largefile,
+ {"Large File", "9p.lflags.largefile", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_DOTL_LARGEFILE,
+ NULL, HFILL}},
+ {&hf_9P_lflags_directory,
+ {"Directory", "9p.lflags.directory", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_DOTL_DIRECTORY,
+ NULL, HFILL}},
+ {&hf_9P_lflags_nofollow,
+ {"No follow", "9p.lflags.nofollow", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_DOTL_NOFOLLOW,
+ NULL, HFILL}},
+ {&hf_9P_lflags_noatime,
+ {"No atime", "9p.lflags.noatime", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_DOTL_NOATIME,
+ NULL, HFILL}},
+ {&hf_9P_lflags_cloexec,
+ {"cloexec", "9p.lflags.cloexec", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_DOTL_CLOEXEC,
+ NULL, HFILL}},
+ {&hf_9P_lflags_sync,
+ {"Sync", "9p.lflags.sync", FT_BOOLEAN, 32, TFS(&tfs_yes_no), _9P_DOTL_SYNC,
+ NULL, HFILL}},
+ {&hf_9P_xattr_flag,
+ {"xattr_flag", "9p.xattr.flag", FT_UINT32, BASE_HEX, NULL, 0x0,
+ "Xattr flag", HFILL}},
+ {&hf_9P_lock_type,
+ {"lock_type", "9p.lock.type", FT_UINT32, BASE_HEX | BASE_EXT_STRING, &ninep_lock_type_ext, 0x0,
+ "Lock type", HFILL}},
+ {&hf_9P_lock_flag,
+ {"lock_flag", "9p.lock.flag", FT_UINT32, BASE_HEX | BASE_EXT_STRING, &ninep_lock_flag_ext, 0x0,
+ "Lock flag", HFILL}},
+ {&hf_9P_lock_start,
+ {"lock_start", "9p.lock.start", FT_UINT64, BASE_DEC, NULL, 0x0,
+ "Lock start", HFILL}},
+ {&hf_9P_lock_length,
+ {"lock_length", "9p.lock.length", FT_UINT64, BASE_DEC, NULL, 0x0,
+ "Lock length", HFILL}},
+ {&hf_9P_lock_procid,
+ {"lock_procid", "9p.lock.procid", FT_UINT32, BASE_HEX, NULL, 0x0,
+ "Lock procid", HFILL}},
+ {&hf_9P_lock_status,
+ {"lock_status", "9p.lock.status", FT_UINT8, BASE_HEX | BASE_EXT_STRING, &ninep_lock_status_ext, 0x0,
+ "Lock status", HFILL}},
+ {&hf_9P_unknown_message,
+ {"Message data", "9p.message_data", FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL}}
+ };
+
+ static gint *ett[] = {
+ &ett_9P,
+ &ett_9P_omode,
+ &ett_9P_dm,
+ &ett_9P_wname,
+ &ett_9P_aname,
+ &ett_9P_ename,
+ &ett_9P_uname,
+ &ett_9P_user,
+ &ett_9P_group,
+ &ett_9P_muid,
+ &ett_9P_filename,
+ &ett_9P_version,
+ &ett_9P_qid,
+ &ett_9P_qidtype,
+ &ett_9P_getattr_flags,
+ &ett_9P_setattr_flags,
+ &ett_9P_lflags,
+ };
+
+ expert_module_t* expert_9P;
+
+ static ei_register_info ei[] = {
+ { &ei_9P_first_250, { "9p.first_250", PI_PROTOCOL, PI_NOTE, "Only first 250 items shown", EXPFILL }},
+ { &ei_9P_msgtype, { "9p.msgtype.unknown", PI_PROTOCOL, PI_WARN, "This message type should not happen", EXPFILL }},
+ };
+
+ proto_9P = proto_register_protocol("Plan 9", "9P", "9p");
+
+ proto_register_field_array(proto_9P, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+ expert_9P = expert_register_protocol(proto_9P);
+ expert_register_field_array(expert_9P, ei, array_length(ei));
+
+ _9p_hashtable = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), _9p_hash_hash, _9p_hash_equal);
+
+ ninep_handle = register_dissector("9p", dissect_9P, proto_9P);
+}
+
+void proto_reg_handoff_9P(void)
+{
+ dissector_add_uint_with_preference("tcp.port", NINEPORT, ninep_handle);
+}
+
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ *
+ * vi: set shiftwidth=8 tabstop=8 noexpandtab:
+ * :indentSize=8:tabSize=8:noTabs=false:
+ */