Frame numbers are unsigned.
[obnox/wireshark/wip.git] / packet-afp.c
index 4d8950e164a212a204f0772af28e421893c07b8e..9cb5ee68143336d1223b165a6297d70764ca0034 100644 (file)
@@ -2,7 +2,7 @@
  * Routines for afp packet dissection
  * Copyright 2002, Didier Gautheron <dgautheron@magic.fr>
  *
- * $Id: packet-afp.c,v 1.21 2002/08/28 21:00:06 jmayer Exp $
+ * $Id: packet-afp.c,v 1.30 2003/05/15 05:53:43 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
@@ -50,6 +50,7 @@
   available from http://www.apple.com
 
   AFP3.0.pdf from http://www.apple.com
+  AFP3.1.pdf from http://www.apple.com
 
   The netatalk source code by Wesley Craig & Adrian Sun
        http://netatalk.sf.net
 #define AFPTRANS_TCP          (1 << 1)
 #define AFPTRANS_ALL          (AFPTRANS_DDP | AFPTRANS_TCP)
 
-/* server flags */
-#define AFPSRVRINFO_COPY                       (1<<0)  /* supports copyfile */
-#define AFPSRVRINFO_PASSWD                     (1<<1)  /* supports change password */
-#define AFPSRVRINFO_NOSAVEPASSWD       (1<<2)  /* don't allow save password */
-#define AFPSRVRINFO_SRVMSGS            (1<<3)  /* supports server messages */
-#define AFPSRVRINFO_SRVSIGNATURE       (1<<4)  /* supports server signature */
-#define AFPSRVRINFO_TCPIP              (1<<5)  /* supports tcpip */
-#define AFPSRVRINFO_SRVNOTIFY          (1<<6)  /* supports server notifications */
-#define AFPSRVRINFO_FASTBOZO           (1<<15) /* fast copying */
-
 /* AFP Attention Codes -- 4 bits */
 #define AFPATTN_SHUTDOWN     (1 << 15)            /* shutdown/disconnect */
 #define AFPATTN_CRASH        (1 << 14)            /* server crashed */
 #define AFP_ADDCMT          56
 #define AFP_RMVCMT          57
 #define AFP_GETCMT          58
+#define AFP_ZZZ            122
 #define AFP_ADDICON        192
 
 /* AFP 3.0 new calls */
 #define AFP_ENUMERATE_EXT      66
 #define AFP_READ_EXT           60
 #define AFP_WRITE_EXT          61
+#define AFP_LOGIN_EXT          63
 #define AFP_GETSESSTOKEN       64
 #define AFP_DISCTOLDSESS        65
 
+/* AFP 3.1 new calls */
+#define AFP_ENUMERATE_EXT2     68
+
 /* ----------------------------- */
 static int proto_afp = -1;
 static int hf_afp_reserved = -1;
@@ -155,8 +151,15 @@ static int hf_afp_AFPVersion = -1;
 static int hf_afp_UAM = -1;
 static int hf_afp_user = -1;
 static int hf_afp_passwd = -1;
+static int hf_afp_random = -1;
+
+static int hf_afp_login_flags = -1;
 static int hf_afp_pad = -1;
 
+static int hf_afp_user_type = -1;
+static int hf_afp_user_len = -1;
+static int hf_afp_user_name = -1;
+
 static int hf_afp_vol_flag_passwd       = -1;
 static int hf_afp_vol_flag_unix_priv = -1;
 static int hf_afp_server_time           = -1;
@@ -202,10 +205,13 @@ static int hf_afp_dir_GroupID    = -1;
 static int hf_afp_file_bitmap = -1;
 static int hf_afp_req_count = -1;
 static int hf_afp_start_index = -1;
+static int hf_afp_start_index32 = -1;
 static int hf_afp_max_reply_size = -1;
+static int hf_afp_max_reply_size32 = -1;
 static int hf_afp_file_flag = -1;
 static int hf_afp_create_flag = -1;
 static int hf_afp_struct_size = -1;
+static int hf_afp_struct_size16 = -1;
 
 static int hf_afp_cat_count            = -1;
 static int hf_afp_cat_req_matches   = -1;
@@ -226,6 +232,8 @@ static int hf_afp_unix_privs_ua_permissions = -1;
 static int hf_afp_path_type = -1;
 static int hf_afp_path_len = -1;
 static int hf_afp_path_name = -1;
+static int hf_afp_path_unicode_hint = -1;
+static int hf_afp_path_unicode_len = -1;
 
 static int hf_afp_flag         = -1;
 static int hf_afp_dt_ref       = -1;
@@ -286,9 +294,11 @@ static int hf_afp_rw_count64               = -1;
 
 static int hf_afp_last_written64       = -1;
 
+static int hf_afp_ofork_len64           = -1;
 static int hf_afp_session_token_type   = -1;
 static int hf_afp_session_token_len    = -1;
 static int hf_afp_session_token                = -1;
+static int hf_afp_session_token_timestamp = -1;
 
 static dissector_handle_t data_handle;
 
@@ -354,14 +364,121 @@ static const value_string CommandCode_vals[] = {
   {AFP_BYTELOCK_EXT,   "FPByteRangeLockExt" },
   {AFP_CATSEARCH_EXT,  "FPCatSearchExt" },
   {AFP_ENUMERATE_EXT,  "FPEnumerateExt" },
+  {AFP_ENUMERATE_EXT2, "FPEnumerateExt2" },
   {AFP_READ_EXT,       "FPReadExt" },
   {AFP_WRITE_EXT,      "FPWriteExt" },
+  {AFP_LOGIN_EXT,      "FPLoginExt" },
   {AFP_GETSESSTOKEN,   "FPGetSessionToken" },
   {AFP_DISCTOLDSESS,    "FPDisconnectOldSession" },
+  {AFP_ZZZ,             "FPzzz" },
   {AFP_ADDICON,                "FPAddIcon" },
   {0,                   NULL }
 };
 
+static const value_string unicode_hint_vals[] = {
+   { 0,           "MacRoman" },
+   { 1,           "MacJapanese" },
+   { 2,           "MacChineseTrad" },
+   { 3,           "MacKorean" },
+   { 4,           "MacArabic" },
+   { 5,           "MacHebrew" },
+   { 6,           "MacGreek" },
+   { 7,           "MacCyrillic" },
+   { 9,           "MacDevanagari" },
+   { 10,   "MacGurmukhi" },
+   { 11,   "MacGujarati" },
+   { 12,   "MacOriya" },
+   { 13,   "MacBengali" },
+   { 14,   "MacTamil" },
+   { 15,   "MacTelugu" },
+   { 16,   "MacKannada" },
+   { 17,   "MacMalayalam" },
+   { 18,   "MacSinhalese" },
+   { 19,   "MacBurmese" },
+   { 20,   "MacKhmer" },
+   { 21,   "MacThai" },
+   { 22,   "MacLaotian" },
+   { 23,   "MacGeorgian" },
+   { 24,   "MacArmenian" },
+   { 25,   "MacChineseSimp" },
+   { 26,   "MacTibetan" },
+   { 27,   "MacMongolian" },
+   { 28,   "MacEthiopic" },
+   { 29,   "MacCentralEurRoman" },
+   { 30,   "MacVietnamese" },
+   { 31,   "MacExtArabic" },
+   { 33,   "MacSymbol" },
+   { 34,   "MacDingbats" },
+   { 35,   "MacTurkish" },
+   { 36,   "MacCroatian" },
+   { 37,   "MacIcelandic" },
+   { 38,   "MacRomanian" },
+   { 39,   "MacCeltic" },
+   { 40,   "MacGaelic" },
+   { 41,   "MacKeyboardGlyphs" },
+   { 126,  "MacUnicode" },
+   { 140,  "MacFarsi" },
+   { 152,  "MacUkrainian" },
+   { 236,  "MacInuit" },
+   { 252,  "MacVT100" },
+   { 255,  "MacHFS" },
+   { 256,  "UnicodeDefault" },
+/* { 257,  "UnicodeV1_1" },  */
+   { 257,  "ISO10646_1993" },
+   { 259,  "UnicodeV2_0" },
+   { 259,  "UnicodeV2_1" },
+   { 260,  "UnicodeV3_0" },
+   { 513,  "ISOLatin1" },
+   { 514,  "ISOLatin2" },
+   { 515,  "ISOLatin3" },
+   { 516,  "ISOLatin4" },
+   { 517,  "ISOLatinCyrillic" },
+   { 518,  "ISOLatinArabic" },
+   { 519,  "ISOLatinGreek" },
+   { 520,  "ISOLatinHebrew" },
+   { 521,  "ISOLatin5" },
+   { 522,  "ISOLatin6" },
+   { 525,  "ISOLatin7" },
+   { 526,  "ISOLatin8" },
+   { 527,  "ISOLatin9" },
+   { 1024, "DOSLatinUS" },
+   { 1029, "DOSGreek" },
+   { 1030, "DOSBalticRim" },
+   { 1040, "DOSLatin1" },
+   { 1041, "DOSGreek1" },
+   { 1042, "DOSLatin2" },
+   { 1043, "DOSCyrillic" },
+   { 1044, "DOSTurkish" },
+   { 1045, "DOSPortuguese" },
+   { 1046, "DOSIcelandic" },
+   { 1047, "DOSHebrew" },
+   { 1048, "DOSCanadianFrench" },
+   { 1049, "DOSArabic" },
+   { 1050, "DOSNordic" },
+   { 1051, "DOSRussian" },
+   { 1052, "DOSGreek2" },
+   { 1053, "DOSThai" },
+   { 1056, "DOSJapanese" },
+   { 1057, "DOSChineseSimplif" },
+   { 1058, "DOSKorean" },
+   { 1059, "DOSChineseTrad" },
+   { 1280, "WindowsLatin1" },
+/* { 1280, "WindowsANSI" }, */
+   { 1281, "WindowsLatin2" },
+   { 1282, "WindowsCyrillic" },
+   { 1283, "WindowsGreek" },
+   { 1284, "WindowsLatin5" },
+   { 1285, "WindowsHebrew" },
+   { 1286, "WindowsArabic" },
+   { 1287, "WindowsBalticRim" },
+   { 1288, "WindowsVietnamese" },
+   { 1296, "WindowsKoreanJohab" },
+   { 1536, "US_ASCII" },
+   { 1568, "JIS_X0201_76" },
+   { 1569, "JIS_X0208_83" },
+   { 1570, "JIS_X0208_90" },
+   { 0,           NULL }
+};
 
 /* volume bitmap
   from Apple AFP3.0.pdf
@@ -515,6 +632,8 @@ static const value_string map_id_type_vals[] = {
 #define kSupportsBlankAccessPrivs              (1 << 4)
 #define kSupportsUnixPrivs                     (1 << 5)
 #define kSupportsUTF8Names                     (1 << 6)
+/* AFP3.1 */
+#define kNoNetworkUserIDs                      (1 << 7)
 
 /*
   directory bitmap from Apple AFP3.0.pdf
@@ -636,6 +755,21 @@ kFPUTF8NameBit                     (bit 13)
 #define kMounted       (1 << 3)
 #define kInExpFolder   (1 << 4)
 
+/* AFP 3.1 getsession token type */
+#define kLoginWithoutID         0
+#define kLoginWithID            1      
+#define kReconnWithID           2
+#define kLoginWithTimeAndID     3
+#define kReconnWithTimeAndID    4
+
+static const value_string token_type_vals[] = {
+  {kLoginWithoutID,            "LoginWithoutID"},
+  {kLoginWithID,                "LoginWithID"},
+  {kReconnWithID,               "ReconnWithID"},
+  {kLoginWithTimeAndID,         "LoginWithTimeAndID"},
+  {kReconnWithTimeAndID,        "ReconnWithTimeAndID"},
+  {0,                           NULL } };
+                                      
 #define hash_init_count 20
 
 /* Hash functions */
@@ -657,11 +791,14 @@ static GHashTable *afp_request_hash = NULL;
 static GMemChunk *afp_request_keys = NULL;
 static GMemChunk *afp_request_vals = NULL;
 
+static guint Vol;      /* volume */
+static guint Did;      /* parent directory ID */
+
 /* Hash Functions */
 static gint  afp_equal (gconstpointer v, gconstpointer v2)
 {
-       afp_request_key *val1 = (afp_request_key*)v;
-       afp_request_key *val2 = (afp_request_key*)v2;
+       const afp_request_key *val1 = (const afp_request_key*)v;
+       const afp_request_key *val2 = (const afp_request_key*)v2;
 
        if (val1->conversation == val2->conversation &&
                        val1->seq == val2->seq) {
@@ -672,7 +809,7 @@ static gint  afp_equal (gconstpointer v, gconstpointer v2)
 
 static guint afp_hash  (gconstpointer v)
 {
-        afp_request_key *afp_key = (afp_request_key*)v;
+        const afp_request_key *afp_key = (const afp_request_key*)v;
         return afp_key->seq;
 }
 
@@ -943,13 +1080,71 @@ decode_unix_privs (proto_tree *tree, tvbuff_t *tvb, gint offset)
        }
 }
 
+/* -------------------------- */
+static gint
+parse_long_filename(proto_tree *tree, tvbuff_t *tvb, gint offset, gint org_offset)
+{
+       guint16 lnameoff;
+       gint tp_ofs = 0;
+       guint8 len;
+
+       lnameoff = tvb_get_ntohs(tvb, offset);
+       proto_tree_add_item(tree, hf_afp_long_name_offset,tvb, offset, 2, FALSE);
+       if (lnameoff) {
+               tp_ofs = lnameoff +org_offset;
+               len = tvb_get_guint8(tvb, tp_ofs);
+               proto_tree_add_item(tree, hf_afp_path_len, tvb, tp_ofs,  1,FALSE);
+               tp_ofs++;
+               proto_tree_add_item(tree, hf_afp_path_name, tvb, tp_ofs, len,FALSE);
+               tp_ofs += len;
+       }
+       return tp_ofs;
+}
+
+/* -------------------------- */
+static gint
+parse_UTF8_filename(proto_tree *tree, tvbuff_t *tvb, gint offset, gint org_offset)
+{
+       guint16 unameoff;
+       gint tp_ofs = 0;
+       guint16 len;
+
+       unameoff = tvb_get_ntohs(tvb, offset);
+       proto_tree_add_item(tree, hf_afp_unicode_name_offset,tvb, offset, 2, FALSE);
+       offset += 2;
+       if (unameoff) {
+             /* FIXME AFP3.x reuses PDINFO bit for UTF8. 
+              * In enumerate_ext it's pad with 4 bytes, PDINFO was 6 bytes,
+              * but not in catsearch_ext. 
+              * Last but not least there's a bug in OSX catsearch_ext for spec2
+              * offset is off by 2 bytes.
+              */
+              
+               tp_ofs = unameoff +org_offset;
+              if (tp_ofs > offset) {
+                  PAD(4);
+               }
+               else if (tp_ofs < offset) {
+                   tp_ofs = offset;
+               }
+               proto_tree_add_item( tree, hf_afp_path_unicode_hint, tvb, tp_ofs, 4,FALSE);
+               tp_ofs += 4;
+
+               len = tvb_get_ntohs(tvb, tp_ofs);
+               proto_tree_add_item( tree, hf_afp_path_unicode_len, tvb, tp_ofs, 2,FALSE);
+               tp_ofs += 2;
+
+               proto_tree_add_item(tree, hf_afp_path_name, tvb, tp_ofs, len,FALSE);
+               tp_ofs += len;
+       }
+       return tp_ofs;
+}
+
 /* -------------------------- */
 static gint
 parse_file_bitmap (proto_tree *tree, tvbuff_t *tvb, gint offset, guint16 bitmap, int shared)
 {
-       guint16 lnameoff = 0;
        guint16 snameoff = 0;
-       guint16 unameoff = 0;
        gint    max_offset = 0;
 
        gint    org_offset = offset;
@@ -980,20 +1175,12 @@ parse_file_bitmap (proto_tree *tree, tvbuff_t *tvb, gint offset, guint16 bitmap,
        }
        if ((bitmap & kFPLongNameBit)) {
                gint tp_ofs;
-               guint8 len;
 
-               lnameoff = tvb_get_ntohs(tvb, offset);
-               if (lnameoff) {
-                       tp_ofs = lnameoff +org_offset;
-                       proto_tree_add_item(tree, hf_afp_long_name_offset,tvb, offset, 2, FALSE);
-                       len = tvb_get_guint8(tvb, tp_ofs);
-                       proto_tree_add_item(tree, hf_afp_path_len, tvb, tp_ofs,  1,FALSE);
-                       tp_ofs++;
-                       proto_tree_add_item(tree, hf_afp_path_name, tvb, tp_ofs, len,FALSE);
-                       tp_ofs += len;
-                       max_offset = (tp_ofs >max_offset)?tp_ofs:max_offset;
-               }
+               tp_ofs = parse_long_filename(tree, tvb, offset, org_offset);
+               max_offset = (tp_ofs >max_offset)?tp_ofs:max_offset;
+
                offset += 2;
+
        }
        if ((bitmap & kFPShortNameBit)) {
                snameoff = tvb_get_ntohs(tvb, offset);
@@ -1025,9 +1212,11 @@ parse_file_bitmap (proto_tree *tree, tvbuff_t *tvb, gint offset, guint16 bitmap,
        }
 
        if ((bitmap & kFPUTF8NameBit)) {
-               unameoff = tvb_get_ntohs(tvb, offset);
-               proto_tree_add_item(tree, hf_afp_unicode_name_offset,tvb, offset, 2, FALSE);
-               offset += 2;
+               gint tp_ofs;
+
+               tp_ofs = parse_UTF8_filename(tree, tvb, offset, org_offset);
+               max_offset = (tp_ofs >max_offset)?tp_ofs:max_offset;
+               offset += 6;
        }
 
        if ((bitmap & kFPExtRsrcForkLenBit)) {
@@ -1113,9 +1302,7 @@ decode_dir_attribute(proto_tree *tree, tvbuff_t *tvb, gint offset)
 static gint
 parse_dir_bitmap (proto_tree *tree, tvbuff_t *tvb, gint offset, guint16 bitmap)
 {
-       guint16 lnameoff = 0;
        guint16 snameoff = 0;
-       guint16 unameoff = 0;
        gint    max_offset = 0;
 
        gint    org_offset = offset;
@@ -1146,18 +1333,10 @@ parse_dir_bitmap (proto_tree *tree, tvbuff_t *tvb, gint offset, guint16 bitmap)
        }
        if ((bitmap & kFPLongNameBit)) {
                gint tp_ofs;
-               guint8 len;
-               lnameoff = tvb_get_ntohs(tvb, offset);
-               if (lnameoff) {
-                       tp_ofs = lnameoff +org_offset;
-                       proto_tree_add_item(tree, hf_afp_long_name_offset,tvb, offset, 2, FALSE);
-                       len = tvb_get_guint8(tvb, tp_ofs);
-                       proto_tree_add_item(tree, hf_afp_path_len, tvb, tp_ofs,  1,FALSE);
-                       tp_ofs++;
-                       proto_tree_add_item(tree, hf_afp_path_name, tvb, tp_ofs, len,FALSE);
-                       tp_ofs += len;
-                       max_offset = (tp_ofs >max_offset)?tp_ofs:max_offset;
-               }
+
+               tp_ofs = parse_long_filename(tree, tvb, offset, org_offset);
+               max_offset = (tp_ofs >max_offset)?tp_ofs:max_offset;
+
                offset += 2;
        }
        if ((bitmap & kFPShortNameBit)) {
@@ -1186,9 +1365,11 @@ parse_dir_bitmap (proto_tree *tree, tvbuff_t *tvb, gint offset, guint16 bitmap)
                offset += 4;
        }
        if ((bitmap & kFPUTF8NameBit)) {
-               unameoff = tvb_get_ntohs(tvb, offset);
-               proto_tree_add_item(tree, hf_afp_unicode_name_offset,tvb, offset, 2, FALSE);
-               offset += 2;
+               gint tp_ofs;
+
+               tp_ofs = parse_UTF8_filename(tree, tvb, offset, org_offset);
+               max_offset = (tp_ofs >max_offset)?tp_ofs:max_offset;
+               offset += 6;
        }
        if ((bitmap & kFPUnixPrivsBit)) {
                /*
@@ -1206,30 +1387,31 @@ parse_dir_bitmap (proto_tree *tree, tvbuff_t *tvb, gint offset, guint16 bitmap)
 
 /* -------------------------- */
 static gchar *
-name_in_bitmap(tvbuff_t *tvb, gint *offset, guint16 bitmap)
+name_in_bitmap(tvbuff_t *tvb, gint offset, guint16 bitmap, int isdir)
 {
        gchar *name;
-       gint    org_offset = *offset;
+       gint    org_offset = offset;
        guint16 nameoff;
        guint8  len;
+       guint16 len16;
        gint    tp_ofs;
 
        name = NULL;
-       if ((bitmap & kFPAttributeBit))
-               *offset += 2;
-       if ((bitmap & kFPParentDirIDBit))
-               *offset += 4;
-       if ((bitmap & kFPCreateDateBit))
-               *offset += 4;
-       if ((bitmap & kFPModDateBit))
-               *offset += 4;
-       if ((bitmap & kFPBackupDateBit))
-               *offset += 4;
-       if ((bitmap & kFPFinderInfoBit))
-               *offset += 32;
+       if ((bitmap & kFPAttributeBit))         /* 0 */
+               offset += 2;
+       if ((bitmap & kFPParentDirIDBit))       /* 1 */
+               offset += 4;
+       if ((bitmap & kFPCreateDateBit))        /* 2 */
+               offset += 4;
+       if ((bitmap & kFPModDateBit))           /* 3 */
+               offset += 4;
+       if ((bitmap & kFPBackupDateBit))        /* 4 */
+               offset += 4;
+       if ((bitmap & kFPFinderInfoBit))        /* 5 */
+               offset += 32;
 
-       if ((bitmap & kFPLongNameBit)) {
-               nameoff = tvb_get_ntohs(tvb, *offset);
+       if ((bitmap & kFPLongNameBit)) {        /* 6 */
+               nameoff = tvb_get_ntohs(tvb, offset);
                if (nameoff) {
                        tp_ofs = nameoff +org_offset;
                        len = tvb_get_guint8(tvb, tp_ofs);
@@ -1240,8 +1422,48 @@ name_in_bitmap(tvbuff_t *tvb, gint *offset, guint16 bitmap)
                        *(name +len) = 0;
                        return name;
                }
+               offset += 2;
+       }
+       
+       if ((bitmap & kFPShortNameBit))         /* 7 */
+               offset += 2;
+       if ((bitmap & kFPNodeIDBit))            /* 8 */
+               offset += 4;
+
+        if (isdir) {
+               if ((bitmap & kFPOffspringCountBit))    /* 9 */
+                       offset += 2;
+               if ((bitmap & kFPOwnerIDBit))           /* 10*/
+                       offset += 4;
+               if ((bitmap & kFPGroupIDBit))           /* 11*/
+                       offset += 4;
+               if ((bitmap & kFPAccessRightsBit))      /* 12*/
+                       offset += 4;
+        }
+        else {
+               if ((bitmap & kFPDataForkLenBit))       /* 9 */
+                       offset += 4;
+               if ((bitmap & kFPRsrcForkLenBit))       /* 10*/
+                       offset += 4;
+               if ((bitmap & kFPExtDataForkLenBit))    /* 11*/
+                       offset += 8;
+               if ((bitmap & kFPLaunchLimitBit))       /* 12*/
+                       offset += 2; /* FIXME ? */
+        }
+
+       if ((bitmap & kFPUTF8NameBit)) {                /* 13 */
+               nameoff = tvb_get_ntohs(tvb, offset);
+               if (nameoff) {
+                       tp_ofs = nameoff +org_offset +4;
+                       len16 = tvb_get_ntohs(tvb, tp_ofs);
+                       tp_ofs += 2;
+                       if (!(name = g_malloc(len16 +1)))
+                               return name;
+                       tvb_memcpy(tvb, name, tp_ofs, len16);
+                       *(name +len16) = 0;
+                       return name;
+               }
        }
-       /* short name ? */
        return name;
 }
 
@@ -1251,7 +1473,7 @@ name_in_dbitmap(tvbuff_t *tvb, gint offset, guint16 bitmap)
 {
        gchar *name;
 
-       name = name_in_bitmap(tvb, &offset, bitmap);
+       name = name_in_bitmap(tvb, offset, bitmap, 1);
        if (name != NULL)
                return name;
        /*
@@ -1267,7 +1489,7 @@ name_in_fbitmap(tvbuff_t *tvb, gint offset, guint16 bitmap)
 {
        gchar *name;
 
-       name = name_in_bitmap(tvb, &offset, bitmap);
+       name = name_in_bitmap(tvb, offset, bitmap, 0);
        if (name != NULL)
                return name;
        /*
@@ -1281,9 +1503,11 @@ name_in_fbitmap(tvbuff_t *tvb, gint offset, guint16 bitmap)
 static gint
 decode_vol_did(proto_tree *tree, tvbuff_t *tvb, gint offset)
 {
+       Vol = tvb_get_ntohs(tvb, offset);
        proto_tree_add_item(tree, hf_afp_vol_id, tvb, offset, 2,FALSE);
        offset += 2;
 
+       Did = tvb_get_ntohl(tvb, offset);
        proto_tree_add_item(tree, hf_afp_did, tvb, offset, 4,FALSE);
        offset += 4;
        return offset;
@@ -1308,19 +1532,20 @@ decode_vol_did_file_dir_bitmap (proto_tree *tree, tvbuff_t *tvb, gint offset)
 static gchar *
 get_name(tvbuff_t *tvb, int offset, int type)
 {
-       guint8 len;
+       int   len;
        gchar *string;
 
-       len = tvb_get_guint8(tvb, offset);
-       offset++;
-
        switch (type) {
        case 1:
        case 2:
+               len = tvb_get_guint8(tvb, offset);
+               offset++;
                string = tvb_format_text(tvb,offset, len);
                break;
        case 3:
-               string = "error Unicode...,next time";
+               len = tvb_get_ntohs(tvb, offset +4);
+               offset += 6;
+               string = tvb_format_text(tvb,offset, len);
                break;
        default:
                string = "unknow type";
@@ -1333,30 +1558,51 @@ static gint
 decode_name_label (proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, gint offset, const gchar *label)
 {
        int len;
+       int header;
        gchar *name;
        guint8 type;
        proto_tree *sub_tree = NULL;
        proto_item *item;
 
        type = tvb_get_guint8(tvb, offset);
-       len = tvb_get_guint8(tvb, offset +1);
+       if (type == 3) {
+               header = 7;
+               len = tvb_get_ntohs(tvb, offset +5);
+       }
+       else {
+               header = 2;
+               len = tvb_get_guint8(tvb, offset +1);
+       }
        name = get_name(tvb, offset +1, type);
 
        if (pinfo && check_col(pinfo->cinfo, COL_INFO)) {
-               col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", name);
+               col_append_fstr(pinfo->cinfo, COL_INFO, ": Vol=%u Did=%u", Vol, Did);
+               if (len) {
+                       col_append_fstr(pinfo->cinfo, COL_INFO, " Name=%s", name);
+               }
        }
 
        if (tree) {
-               item = proto_tree_add_text(tree, tvb, offset, len +2, label, name);
+               item = proto_tree_add_text(tree, tvb, offset, len +header, label, name);
                sub_tree = proto_item_add_subtree(item, ett_afp_path_name);
+
                proto_tree_add_item(  sub_tree, hf_afp_path_type, tvb, offset,   1,FALSE);
                offset++;
-               proto_tree_add_item(  sub_tree, hf_afp_path_len,  tvb, offset,   1,FALSE);
-               offset++;
+               if (type == 3) {
+                       proto_tree_add_item( sub_tree, hf_afp_path_unicode_hint,  tvb, offset,  4,FALSE);
+                       offset += 4;
+                       proto_tree_add_item( sub_tree, hf_afp_path_unicode_len,  tvb, offset,   2,FALSE);
+                       offset += 2;
+               }
+               else {
+                       proto_tree_add_item( sub_tree, hf_afp_path_len,  tvb, offset,   1,FALSE);
+                       offset++;
+               }
+
                proto_tree_add_string(sub_tree, hf_afp_path_name, tvb, offset, len,name);
        }
        else
-               offset += 2;
+               offset += header;
 
        return offset +len;
 }
@@ -1368,6 +1614,30 @@ decode_name (proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, gint offset)
        return decode_name_label(tree, pinfo, tvb, offset, "Path: %s");
 }
 
+/* -------------------------- */
+static void
+add_info_fork(tvbuff_t *tvb, packet_info *pinfo, gint offset)
+{
+       guint16 ofork;
+
+       ofork = tvb_get_ntohs(tvb, offset);
+       if (ofork && check_col(pinfo->cinfo, COL_INFO)) {
+               col_append_fstr(pinfo->cinfo, COL_INFO, ": Fork=%u", ofork);
+       }
+}
+
+/* -------------------------- */
+static void
+add_info_vol(tvbuff_t *tvb, packet_info *pinfo, gint offset)
+{
+       guint16 vol;
+
+       vol = tvb_get_ntohs(tvb, offset);
+       if (check_col(pinfo->cinfo, COL_INFO)) {
+               col_append_fstr(pinfo->cinfo, COL_INFO, ": Vol=%u", vol);
+       }
+}
+
 /* ************************** */
 static gint
 dissect_query_afp_open_vol(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
@@ -1520,13 +1790,14 @@ dissect_query_afp_open_fork(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 
 /* -------------------------- */
 static gint
-dissect_reply_afp_open_fork(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+dissect_reply_afp_open_fork(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
 {
        int f_bitmap;
-
+       
        f_bitmap = decode_file_bitmap(tree, tvb, offset);
        offset += 2;
 
+        add_info_fork(tvb, pinfo, offset);
        proto_tree_add_item(tree, hf_afp_ofork, tvb, offset, 2,FALSE);
        offset += 2;
 
@@ -1535,6 +1806,28 @@ dissect_reply_afp_open_fork(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *t
        return offset;
 }
 
+/* ************************** */
+static gint
+dissect_query_afp_enumerate_ext2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+{
+
+       PAD(1);
+       offset = decode_vol_did_file_dir_bitmap(tree, tvb, offset);
+
+       proto_tree_add_item(tree, hf_afp_req_count, tvb, offset, 2,FALSE);
+       offset += 2;
+
+       proto_tree_add_item(tree, hf_afp_start_index32, tvb, offset, 4,FALSE);
+       offset += 4;
+
+       proto_tree_add_item(tree, hf_afp_max_reply_size32, tvb, offset, 4,FALSE);
+       offset += 4;
+
+       offset = decode_name(tree, pinfo, tvb, offset);
+
+       return offset;
+}
+
 /* ************************** */
 static gint
 dissect_query_afp_enumerate(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
@@ -1560,28 +1853,39 @@ dissect_query_afp_enumerate(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 /* -------------------------- */
 static int
 loop_record(tvbuff_t *tvb, proto_tree *ptree, gint offset,
-               int count, guint16 d_bitmap, guint16 f_bitmap, int add)
+               int count, guint16 d_bitmap, guint16 f_bitmap, int add, int ext)
 {
        proto_tree *tree = NULL;
        proto_item *item;
        gchar   *name;
        guint8  flags;
-       guint8  size;
+       guint   size;
        gint    org;
        int i;
+       int decal; 
 
        for (i = 0; i < count; i++) {
                org = offset;
-               name = NULL;
-               size = tvb_get_guint8(tvb, offset) +add;
-               flags = tvb_get_guint8(tvb, offset +1);
+               if (ext) {
+                       size = tvb_get_ntohs(tvb, offset) +add *2;
+                       decal = 2;
+               }
+               else {
+                       size = tvb_get_guint8(tvb, offset) +add;
+                       decal = 1;
+               }
+               if (!size)
+                       return offset;  /* packet is malformed */
+               flags = tvb_get_guint8(tvb, offset +decal);
+
+               decal += (ext)?2:1;
 
                if (ptree) {
                        if (flags) {
-                               name = name_in_dbitmap(tvb, offset +2, d_bitmap);
+                               name = name_in_dbitmap(tvb, offset +decal, d_bitmap);
                        }
                        else {
-                               name = name_in_fbitmap(tvb, offset +2, f_bitmap);
+                               name = name_in_fbitmap(tvb, offset +decal, f_bitmap);
                        }
                        if (!name) {
                                if (!(name = g_malloc(50))) { /* no memory ! */
@@ -1590,12 +1894,22 @@ loop_record(tvbuff_t *tvb, proto_tree *ptree, gint offset,
                        }
                        item = proto_tree_add_text(ptree, tvb, offset, size, name);
                        tree = proto_item_add_subtree(item, ett_afp_enumerate_line);
+                       g_free((gpointer)name);
+               }
+               if (ext) {
+                       proto_tree_add_item(tree, hf_afp_struct_size16, tvb, offset, 2,FALSE);
+                       offset += 2;
+               }
+               else {
+                       proto_tree_add_item(tree, hf_afp_struct_size, tvb, offset, 1,FALSE);
+                       offset++;
                }
-               proto_tree_add_item(tree, hf_afp_struct_size, tvb, offset, 1,FALSE);
-               offset++;
 
                proto_tree_add_item(tree, hf_afp_file_flag, tvb, offset, 1,FALSE);
                offset++;
+               if (ext) {
+                       PAD(1);
+               }
                if (flags) {
                        offset = parse_dir_bitmap(tree, tvb, offset, d_bitmap);
                }
@@ -1605,15 +1919,12 @@ loop_record(tvbuff_t *tvb, proto_tree *ptree, gint offset,
                if ((offset & 1))
                        PAD(1);
                offset = org +size;             /* play safe */
-               if (ptree)
-                       g_free((gpointer)name);
        }
        return offset;
 }
-
 /* ------------------------- */
 static gint
-dissect_reply_afp_enumerate(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+reply_enumerate(tvbuff_t *tvb, proto_tree *tree, gint offset, int ext)
 {
        proto_tree *sub_tree = NULL;
        proto_item *item;
@@ -1634,20 +1945,69 @@ dissect_reply_afp_enumerate(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *t
        }
        offset += 2;
 
-       return loop_record(tvb,sub_tree, offset, count, d_bitmap, f_bitmap,0);
+       return loop_record(tvb,sub_tree, offset, count, d_bitmap, f_bitmap,0, ext);
+}
 
+/* ------------------------- */
+static gint
+dissect_reply_afp_enumerate(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+{
+       return reply_enumerate(tvb, tree, offset, 0);
 }
+
 /* **************************/
 static gint
-dissect_query_afp_cat_search(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *ptree, gint offset)
+dissect_reply_afp_enumerate_ext(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+{
+       return reply_enumerate(tvb, tree, offset, 1);
+}
+
+/* **************************/
+static gint
+catsearch_spec(tvbuff_t *tvb, proto_tree *ptree, gint offset, int ext, guint32 bitmap, const gchar *label)
+{
+       proto_tree *tree = NULL;
+       proto_item *item;
+       guint16 size;
+       gint    org;
+
+       org = offset;
+
+       if (ext) {
+               size = tvb_get_ntohs(tvb, offset) +2;
+       }
+       else {
+               size = tvb_get_guint8(tvb, offset) +2;
+       }
+
+       item = proto_tree_add_text(ptree, tvb, offset, size, label);
+       tree = proto_item_add_subtree(item, ett_afp_cat_spec);
+
+       if (ext) {
+               proto_tree_add_item(tree, hf_afp_struct_size16, tvb, offset, 2,FALSE);
+               offset += 2;
+       }
+       else {
+               proto_tree_add_item(tree, hf_afp_struct_size, tvb, offset, 1,FALSE);
+               offset++;
+               PAD(1);
+       }
+
+       offset = parse_file_bitmap(tree, tvb, offset, bitmap,0);
+       offset = org +size;
+
+       return offset;
+}
+
+/* ------------------------- */
+static gint
+query_catsearch(tvbuff_t *tvb, proto_tree *ptree, gint offset, int ext)
 {
        proto_tree *tree = NULL;
        proto_item *item;
        guint16 f_bitmap;
        guint16 d_bitmap;
        guint32 r_bitmap;
-       guint8  size;
-       gint    org;
 
        if (!ptree)
                return offset;
@@ -1671,46 +2031,39 @@ dissect_query_afp_cat_search(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *
        d_bitmap = decode_dir_bitmap(ptree, tvb, offset);
        offset += 2;
 
-       /* FIXME req bitmap */
+       /* FIXME it's req bitmap and first bit is for partial match */
        item = proto_tree_add_text(ptree, tvb, offset, 4, "Request bitmap");
        tree = proto_item_add_subtree(item, ett_afp_cat_r_bitmap);
        r_bitmap = decode_file_bitmap(tree, tvb, offset+2);
        offset += 4;
 
        /* spec 1 */
-       org = offset;
-       size = tvb_get_guint8(tvb, offset) +2;
-
-       item = proto_tree_add_text(ptree, tvb, offset, size, "Spec 1");
-       tree = proto_item_add_subtree(item, ett_afp_cat_spec);
-
-       proto_tree_add_item(tree, hf_afp_struct_size, tvb, offset, 1,FALSE);
-       offset++;
-       PAD(1);
-
-       offset = parse_file_bitmap(tree, tvb, offset, r_bitmap,0);
-       offset = org +size;
+       offset = catsearch_spec(tvb, ptree, offset, ext, r_bitmap, "Spec 1");
 
        /* spec 2 */
-       org = offset;
-       size = tvb_get_guint8(tvb, offset) +2;
-
-       item = proto_tree_add_text(ptree, tvb, offset, size, "Spec 2");
-       tree = proto_item_add_subtree(item, ett_afp_cat_spec);
+       offset = catsearch_spec(tvb, ptree, offset, ext, r_bitmap, "Spec 2");
+       
+       return offset;
+}
 
-       proto_tree_add_item(tree, hf_afp_struct_size, tvb, offset, 1,FALSE);
-       offset++;
-       PAD(1);
+/* ------------------------- */
+static gint
+dissect_query_afp_cat_search(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *ptree, gint offset)
+{
+       return query_catsearch(tvb, ptree, offset, 0);
 
-       offset = parse_file_bitmap(tree, tvb, offset, r_bitmap,0);
-       offset = org +size;
+}
+/* **************************/
+static gint
+dissect_query_afp_cat_search_ext(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *ptree, gint offset)
+{
+       return query_catsearch(tvb, ptree, offset, 1);
 
-       return offset;
 }
 
-/* -------------------------- */
+/* **************************/
 static gint
-dissect_reply_afp_cat_search(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+reply_catsearch(tvbuff_t *tvb, proto_tree *tree, gint offset, int ext)
 {
        proto_tree *sub_tree = NULL;
        proto_item *item;
@@ -1733,14 +2086,32 @@ dissect_reply_afp_cat_search(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *
                sub_tree = proto_item_add_subtree(item, ett_afp_cat_search);
        }
        offset += 4;
-       return loop_record(tvb,sub_tree, offset, count, d_bitmap, f_bitmap, 2);
+
+       return loop_record(tvb,sub_tree, offset, count, d_bitmap, f_bitmap, 2, ext);
+}
+
+/* -------------------------- */
+static gint
+dissect_reply_afp_cat_search(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+{
+       return reply_catsearch(tvb, tree, offset, 0);
+}
+
+/* **************************/
+static gint
+dissect_reply_afp_cat_search_ext(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+{
+       return reply_catsearch(tvb, tree, offset, 1);
 }
 
 /* **************************/
 static gint
-dissect_query_afp_get_vol_param(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+dissect_query_afp_get_vol_param(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
 {
+
        PAD(1)
+        add_info_vol(tvb, pinfo, offset);
+       
        proto_tree_add_item(tree, hf_afp_vol_id, tvb, offset, 2,FALSE);
        offset += 2;
 
@@ -1766,11 +2137,13 @@ dissect_reply_afp_get_vol_param(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tre
 
 /* **************************/
 static gint
-dissect_query_afp_set_vol_param(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+dissect_query_afp_set_vol_param(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
 {
        guint16 bitmap;
 
        PAD(1)
+
+        add_info_vol(tvb, pinfo, offset);
        proto_tree_add_item(tree, hf_afp_vol_id, tvb, offset, 2,FALSE);
        offset += 2;
 
@@ -1784,41 +2157,130 @@ dissect_query_afp_set_vol_param(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tre
 
 /* ***************************/
 static gint
+decode_uam_parameters(const char *uam, int len_uam, tvbuff_t *tvb, proto_tree *tree, gint offset)
+{
+       int len;
+
+       if (!strncasecmp(uam, "Cleartxt passwrd", len_uam)) {
+               if ((offset & 1))
+                       PAD(1);
+
+               len = 8; /* tvb_strsize(tvb, offset);*/
+               proto_tree_add_item(tree, hf_afp_passwd, tvb, offset, len,FALSE);
+               offset += len;
+       }
+       else if (!strncasecmp(uam, "DHCAST128", len_uam)) {
+               if ((offset & 1))
+                       PAD(1);
+
+               len = 16;
+               proto_tree_add_item(tree, hf_afp_random, tvb, offset, len,FALSE);
+               offset += len;
+        }
+       else if (!strncasecmp(uam, "2-Way Randnum exchange", len_uam)) {
+               /* nothing */
+               return offset;
+       }
+       return offset;
+}
+
+/* ---------------- */
+static gint
 dissect_query_afp_login(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
 {
        int len;
+       int len_uam;
        const char *uam;
 
        len = tvb_get_guint8(tvb, offset);
        proto_tree_add_item(tree, hf_afp_AFPVersion, tvb, offset, 1,FALSE);
        offset += len +1;
-       len = tvb_get_guint8(tvb, offset);
-       uam = tvb_get_ptr(tvb, offset +1, len);
+       len_uam = tvb_get_guint8(tvb, offset);
+       uam = tvb_get_ptr(tvb, offset +1, len_uam);
        proto_tree_add_item(tree, hf_afp_UAM, tvb, offset, 1,FALSE);
+       offset += len_uam +1;
+
+       if (!strncasecmp(uam, "No User Authent", len_uam)) {
+               return offset;
+       }
+
+       len = tvb_get_guint8(tvb, offset);
+       proto_tree_add_item(tree, hf_afp_user, tvb, offset, 1,FALSE);
        offset += len +1;
+       
+       return decode_uam_parameters(uam, len_uam, tvb, tree, offset);
+}
 
-       if (!strncasecmp(uam, "Cleartxt passwrd", len)) {
-               /* clear text */
-               len = tvb_get_guint8(tvb, offset);
-               proto_tree_add_item(tree, hf_afp_user, tvb, offset, 1,FALSE);
-               offset += len +1;
+/* ***************************/
+static gint
+dissect_query_afp_login_ext(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+{
+       int len;
+       int len_uam;
+       const char *uam;
+       guint8 type;
 
-               len = 8; /* tvb_strsize(tvb, offset);*/
-               proto_tree_add_item(tree, hf_afp_passwd, tvb, offset, len,FALSE);
+       type = tvb_get_guint8(tvb, offset);
+
+       PAD(1);
+       proto_tree_add_item(tree, hf_afp_login_flags, tvb, offset, 2,FALSE);
+       offset += 2;
+       
+       len = tvb_get_guint8(tvb, offset);
+       proto_tree_add_item(tree, hf_afp_AFPVersion, tvb, offset, 1,FALSE);
+       offset += len +1;
+
+       len_uam = tvb_get_guint8(tvb, offset);
+       uam = tvb_get_ptr(tvb, offset +1, len_uam);
+       proto_tree_add_item(tree, hf_afp_UAM, tvb, offset, 1,FALSE);
+       offset += len_uam +1;
+
+       type = tvb_get_guint8(tvb, offset);
+       proto_tree_add_item(tree, hf_afp_user_type, tvb, offset, 1,FALSE);
+       offset++;
+       /* only type 3 */
+       len = tvb_get_ntohs(tvb, offset);
+       proto_tree_add_item(tree, hf_afp_user_len, tvb, offset, 2,FALSE);
+       offset += 2;
+       proto_tree_add_item(tree, hf_afp_user_name, tvb, offset, len,FALSE);
+       offset += len;
+
+       /* directory service */
+       type = tvb_get_guint8(tvb, offset);
+       proto_tree_add_item(tree, hf_afp_path_type, tvb, offset, 1,FALSE);
+       offset++;
+       /* FIXME use 16 bit len + unicode from smb dissector */
+       switch (type) {
+       case 1:
+       case 2:
+               len = tvb_get_guint8(tvb, offset);
+               proto_tree_add_item(tree, hf_afp_path_len, tvb, offset,  1,FALSE);
+               offset++;
+               proto_tree_add_item(tree, hf_afp_path_name, tvb, offset, len,FALSE);
                offset += len;
-       }
-       else if (!strncasecmp(uam, "No User Authent", len)) {
-       }
-       return(offset);
+               break;
+       case 3:
+               len = tvb_get_ntohs(tvb, offset);
+               proto_tree_add_item( tree, hf_afp_path_unicode_len, tvb, offset, 2,FALSE);
+               offset += 2;
+               proto_tree_add_item(tree, hf_afp_path_name, tvb, offset, len,FALSE);
+               offset += len;
+               break;
+       default:
+               break;
+       }
+       
+       return decode_uam_parameters(uam, len_uam, tvb, tree, offset);
 }
 
 /* ************************** */
 static gint
-dissect_query_afp_write(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+dissect_query_afp_write(tvbuff_t *tvb, packet_info *pinfo , proto_tree *tree, gint offset)
 {
        proto_tree_add_item(tree, hf_afp_flag, tvb, offset, 1,FALSE);
        offset += 1;
 
+        add_info_fork(tvb, pinfo, offset);
        proto_tree_add_item(tree, hf_afp_ofork, tvb, offset, 2,FALSE);
        offset += 2;
 
@@ -1847,6 +2309,7 @@ dissect_query_afp_write_ext(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *t
        proto_tree_add_item(tree, hf_afp_flag, tvb, offset, 1,FALSE);
        offset += 1;
 
+        add_info_fork(tvb, pinfo, offset);
        proto_tree_add_item(tree, hf_afp_ofork, tvb, offset, 2,FALSE);
        offset += 2;
 
@@ -1874,6 +2337,7 @@ dissect_query_afp_read(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
 {
        PAD(1);
 
+        add_info_fork(tvb, pinfo, offset);
        proto_tree_add_item(tree, hf_afp_ofork, tvb, offset, 2,FALSE);
        offset += 2;
 
@@ -1898,6 +2362,7 @@ dissect_query_afp_read_ext(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tr
 {
        PAD(1);
 
+        add_info_fork(tvb, pinfo, offset);
        proto_tree_add_item(tree, hf_afp_ofork, tvb, offset, 2,FALSE);
        offset += 2;
 
@@ -1945,9 +2410,10 @@ dissect_query_afp_close_dt(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tr
        AFP_CLOSEFORK
 */
 static gint
-dissect_query_afp_with_fork(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+dissect_query_afp_with_fork(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
 {
        PAD(1);
+        add_info_fork(tvb, pinfo, offset);
        proto_tree_add_item(tree, hf_afp_ofork, tvb, offset, 2,FALSE);
        offset += 2;
 
@@ -2138,10 +2604,11 @@ dissect_query_afp_resolve_id(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *
 
 /* ************************** */
 static gint
-dissect_query_afp_get_fork_param(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+dissect_query_afp_get_fork_param(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
 {
 
        PAD(1);
+        add_info_fork(tvb, pinfo, offset);
        proto_tree_add_item(tree, hf_afp_ofork, tvb, offset, 2,FALSE);
        offset += 2;
 
@@ -2166,18 +2633,26 @@ dissect_reply_afp_get_fork_param(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tr
 
 /* ************************** */
 static gint
-dissect_query_afp_set_fork_param(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
+dissect_query_afp_set_fork_param(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
 {
+       guint16 bitmap;
 
        PAD(1);
+        add_info_fork(tvb, pinfo, offset);
        proto_tree_add_item(tree, hf_afp_ofork, tvb, offset, 2,FALSE);
        offset += 2;
 
-       decode_file_bitmap(tree, tvb, offset);
+       bitmap = decode_file_bitmap(tree, tvb, offset);
        offset += 2;
 
-       proto_tree_add_item(tree, hf_afp_ofork_len, tvb, offset, 4,FALSE);
-       offset += 4;
+       if ((bitmap & kFPExtDataForkLenBit) || (bitmap & kFPExtRsrcForkLenBit)) {
+               proto_tree_add_item(tree, hf_afp_ofork_len64, tvb, offset, 8, FALSE);
+               offset += 8;
+       }
+       else {
+               proto_tree_add_item(tree, hf_afp_ofork_len, tvb, offset, 4,FALSE);
+               offset += 4;
+       }
        return offset;
 }
 
@@ -2250,8 +2725,8 @@ dissect_query_afp_rename(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gi
        PAD(1);
        offset = decode_vol_did(tree, tvb, offset);
 
-       offset = decode_name_label(tree, pinfo, tvb, offset, "Old name:     %s");
-       offset = decode_name_label(tree, NULL, tvb, offset,  "New name:     %s");
+       offset = decode_name_label(tree, pinfo, tvb, offset, "Old name: %s");
+       offset = decode_name_label(tree, NULL, tvb, offset,  "New name: %s");
 
        return offset;
 }
@@ -2482,15 +2957,26 @@ dissect_query_afp_add_icon(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tr
        no reply
 */
 static gint
-dissect_query_afp_add_appl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+decode_dt_did(proto_tree *tree, tvbuff_t *tvb, gint offset)
 {
-
-       PAD(1);
+       /* FIXME it's not volume but dt cf decode_name*/
+       Vol = tvb_get_ntohs(tvb, offset);
        proto_tree_add_item(tree, hf_afp_dt_ref, tvb, offset, 2,FALSE);
        offset += 2;
 
+       Did = tvb_get_ntohl(tvb, offset);
        proto_tree_add_item(tree, hf_afp_did, tvb, offset, 4,FALSE);
        offset += 4;
+       return offset;
+}
+
+/* -------------------------- */
+static gint
+dissect_query_afp_add_appl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+{
+
+       PAD(1);
+       offset = decode_dt_did(tree, tvb, offset);
 
        proto_tree_add_item(tree, hf_afp_file_creator, tvb, offset, 4,FALSE);
        offset += 4;
@@ -2511,11 +2997,7 @@ dissect_query_afp_rmv_appl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 {
 
        PAD(1);
-       proto_tree_add_item(tree, hf_afp_dt_ref, tvb, offset, 2,FALSE);
-       offset += 2;
-
-       proto_tree_add_item(tree, hf_afp_did, tvb, offset, 4,FALSE);
-       offset += 4;
+       offset = decode_dt_did(tree, tvb, offset);
 
        proto_tree_add_item(tree, hf_afp_file_creator, tvb, offset, 4,FALSE);
        offset += 4;
@@ -2645,10 +3127,29 @@ int len;
 static gint
 dissect_query_afp_get_session_token(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
 {
+guint16        token;
+int len;
 
        PAD(1);
+       token = tvb_get_ntohs(tvb, offset);
        proto_tree_add_item(tree, hf_afp_session_token_type, tvb, offset, 2,FALSE);
        offset += 2;
+       if (token == kLoginWithoutID) /* 0 */
+               return offset;
+
+       len = tvb_get_ntohl(tvb, offset);
+       proto_tree_add_item(tree, hf_afp_session_token_len, tvb, offset, 4,FALSE);
+       offset += 4;
+
+       switch (token) {
+       case kLoginWithTimeAndID:
+       case kReconnWithTimeAndID:
+               proto_tree_add_item(tree, hf_afp_session_token_timestamp, tvb, offset, 4,FALSE);
+               offset += 4;
+       }
+
+       proto_tree_add_item(tree, hf_afp_session_token, tvb, offset, len,FALSE);
+       offset += len;
 
        return offset;
 }
@@ -2658,13 +3159,17 @@ static gint
 dissect_reply_afp_get_session_token(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset)
 {
 int len;
+int size;
 
-       proto_tree_add_item(tree, hf_afp_session_token_type, tvb, offset, 2,FALSE);
-       offset += 2;
-
+       /* FIXME spec and capture disagree : or it's 4 bytes with no token type, or it's 2 bytes */
+       size = 4;
+       if (size == 2) {
+               proto_tree_add_item(tree, hf_afp_session_token_type, tvb, offset, 2,FALSE);
+               offset += 2;
+       }
        len = tvb_get_ntohl(tvb, offset);
-       proto_tree_add_item(tree, hf_afp_session_token_len, tvb, offset, 4,FALSE);
-       offset += 4;
+       proto_tree_add_item(tree, hf_afp_session_token_len, tvb, offset, size,FALSE);
+       offset += size;
 
        proto_tree_add_item(tree, hf_afp_session_token, tvb, offset, len,FALSE);
        offset += len;
@@ -2800,7 +3305,22 @@ dissect_afp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                afp_tree = proto_item_add_subtree(ti, ett_afp);
        }
        if (!aspinfo->reply)  {
+               
                proto_tree_add_uint(afp_tree, hf_afp_command, tvb,offset, 1, afp_command);
+               if (afp_command != tvb_get_guint8(tvb, offset))
+               {
+                       /* we have the same conversation for different connections eg:
+                        * ip1:2048 --> ip2:548
+                        * ip1:2048 --> ip2:548 <RST>
+                        * ....
+                        * ip1:2048 --> ip2:548 <SYN> use the same port but it's a new session!
+                        */
+                       if (check_col(pinfo->cinfo, COL_INFO)) {
+                               col_add_fstr(pinfo->cinfo, COL_INFO, 
+                                 "[Error!IP port reused, you need to split the capture file]");
+                               return;
+                       }
+               }
                offset++;
                switch(afp_command) {
                case AFP_BYTELOCK:
@@ -2825,6 +3345,8 @@ dissect_afp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                        offset = dissect_query_afp_create_file(tvb, pinfo, afp_tree, offset);break;
                case AFP_DISCTOLDSESS:
                        offset = dissect_query_afp_disconnect_old_session(tvb, pinfo, afp_tree, offset);break;
+               case AFP_ENUMERATE_EXT2:
+                       offset = dissect_query_afp_enumerate_ext2(tvb, pinfo, afp_tree, offset);break;
                case AFP_ENUMERATE_EXT:
                case AFP_ENUMERATE:
                        offset = dissect_query_afp_enumerate(tvb, pinfo, afp_tree, offset);break;
@@ -2840,6 +3362,8 @@ dissect_afp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                        break;                                  /* no parameters */
                case AFP_GETVOLPARAM:
                        offset = dissect_query_afp_get_vol_param(tvb, pinfo, afp_tree, offset);break;
+               case AFP_LOGIN_EXT:
+                       offset = dissect_query_afp_login_ext(tvb, pinfo, afp_tree, offset);break;
                case AFP_LOGIN:
                        offset = dissect_query_afp_login(tvb, pinfo, afp_tree, offset);break;
                case AFP_LOGINCONT:
@@ -2893,6 +3417,7 @@ dissect_afp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                case AFP_EXCHANGEFILE:
                        offset = dissect_query_afp_exchange_file(tvb, pinfo, afp_tree, offset);break;
                case AFP_CATSEARCH_EXT:
+                       offset = dissect_query_afp_cat_search_ext(tvb, pinfo, afp_tree, offset);break;
                case AFP_CATSEARCH:
                        offset = dissect_query_afp_cat_search(tvb, pinfo, afp_tree, offset);break;
                case AFP_GETICON:
@@ -2927,7 +3452,9 @@ dissect_afp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                        offset = dissect_reply_afp_byte_lock(tvb, pinfo, afp_tree, offset);break;
                case AFP_BYTELOCK_EXT:
                        offset = dissect_reply_afp_byte_lock_ext(tvb, pinfo, afp_tree, offset);break;
+               case AFP_ENUMERATE_EXT2:
                case AFP_ENUMERATE_EXT:
+                       offset = dissect_reply_afp_enumerate_ext(tvb, pinfo, afp_tree, offset);break;
                case AFP_ENUMERATE:
                        offset = dissect_reply_afp_enumerate(tvb, pinfo, afp_tree, offset);break;
                case AFP_OPENVOL:
@@ -2958,8 +3485,8 @@ dissect_afp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                        offset = dissect_reply_afp_get_fldr_param(tvb, pinfo, afp_tree, offset);break;
                case AFP_OPENDT:
                        offset = dissect_reply_afp_open_dt(tvb, pinfo, afp_tree, offset);break;
-
                case AFP_CATSEARCH_EXT:
+                       offset = dissect_reply_afp_cat_search_ext(tvb, pinfo, afp_tree, offset);break;
                case AFP_CATSEARCH:
                        offset = dissect_reply_afp_cat_search(tvb, pinfo, afp_tree, offset);break;
                case AFP_GTICNINFO:
@@ -3033,11 +3560,34 @@ proto_register_afp(void)
                FT_UINT_STRING, BASE_NONE, NULL, 0x0,
        "User", HFILL }},
 
+    { &hf_afp_user_type,
+      { "Type",         "afp.user_type",
+               FT_UINT8, BASE_HEX, VALS(path_type_vals), 0,
+       "Type of user name", HFILL }},
+    { &hf_afp_user_len,
+      { "Len",  "afp.user_len",
+               FT_UINT16, BASE_DEC, NULL, 0x0,
+       "User name length (unicode)", HFILL }},
+    { &hf_afp_user_name,
+      { "User",  "afp.user_name",
+               FT_STRING, BASE_NONE, NULL, 0x0,
+       "User name (unicode)", HFILL }},
+
     { &hf_afp_passwd,
       { "Password",     "afp.passwd",
                FT_STRINGZ, BASE_NONE, NULL, 0x0,
        "Password", HFILL }},
 
+    { &hf_afp_random,
+      { "Random number",         "afp.random",
+               FT_BYTES, BASE_HEX, NULL, 0x0,
+       "UAM random number", HFILL }},
+
+    { &hf_afp_login_flags,
+      { "Flags",         "afp.afp_login_flags",
+               FT_UINT16, BASE_HEX, NULL, 0 /* 0x0FFF*/,
+       "Login flags", HFILL }},
+
     { &hf_afp_vol_bitmap,
       { "Bitmap",         "afp.vol_bitmap",
                FT_UINT16, BASE_HEX, NULL, 0 /* 0x0FFF*/,
@@ -3593,8 +4143,18 @@ proto_register_afp(void)
     { &hf_afp_max_reply_size,
       { "Reply size",         "afp.reply_size",
                FT_UINT16, BASE_DEC, NULL, 0x0,
+       "Reply size", HFILL }},
+
+    { &hf_afp_start_index32,
+      { "Start index",         "afp.start_index32",
+               FT_UINT32, BASE_DEC, NULL, 0x0,
        "First structure returned", HFILL }},
 
+    { &hf_afp_max_reply_size32,
+      { "Reply size",         "afp.reply_size32",
+               FT_UINT32, BASE_DEC, NULL, 0x0,
+       "Reply size", HFILL }},
+
     { &hf_afp_file_flag,
       { "Dir",         "afp.file_flag",
                FT_BOOLEAN, 8, NULL, 0x80,
@@ -3610,6 +4170,11 @@ proto_register_afp(void)
                FT_UINT8, BASE_DEC, NULL,0,
        "Sizeof of struct", HFILL }},
 
+    { &hf_afp_struct_size16,
+      { "Struct size",         "afp.struct_size16",
+               FT_UINT16, BASE_DEC, NULL,0,
+       "Sizeof of struct", HFILL }},
+
     { &hf_afp_flag,
       { "From",         "afp.flag",
                FT_UINT8, BASE_HEX, VALS(flag_vals), 0x80,
@@ -3670,6 +4235,16 @@ proto_register_afp(void)
                FT_UINT8, BASE_DEC, NULL, 0x0,
        "Path length", HFILL }},
 
+    { &hf_afp_path_unicode_len,
+      { "Len",  "afp.path_unicode_len",
+               FT_UINT16, BASE_DEC, NULL, 0x0,
+       "Path length (unicode)", HFILL }},
+
+    { &hf_afp_path_unicode_hint,
+      { "Unicode hint",  "afp.path_unicode_hint",
+               FT_UINT32, BASE_HEX, VALS(unicode_hint_vals), 0x0,
+       "Unicode hint", HFILL }},
+
     { &hf_afp_path_name,
       { "Name",  "afp.path_name",
                FT_STRING, BASE_NONE, NULL, 0x0,
@@ -3927,16 +4502,27 @@ proto_register_afp(void)
                FT_UINT64, BASE_DEC, NULL, 0x0,
        "Offset of the last byte written (64 bits)", HFILL }},
 
+    { &hf_afp_ofork_len64,
+      { "New length",         "afp.ofork_len64",
+               FT_INT64, BASE_DEC, NULL, 0x0,
+       "New length (64 bits)", HFILL }},
+
     { &hf_afp_session_token_type,
       { "Type",         "afp.session_token_type",
-               FT_UINT16, BASE_HEX, NULL, 0x0,
+               FT_UINT16, BASE_HEX, VALS(token_type_vals), 0x0,
        "Session token type", HFILL }},
 
+    /* FIXME FT_UINT32 in specs */
     { &hf_afp_session_token_len,
       { "Len",         "afp.session_token_len",
                FT_UINT32, BASE_DEC, NULL, 0x0,
        "Session token length", HFILL }},
 
+    { &hf_afp_session_token_timestamp,
+      { "Time stamp",         "afp.session_token_timestamp",
+               FT_UINT32, BASE_HEX, NULL, 0x0,
+       "Session time stamp", HFILL }},
+
     { &hf_afp_session_token,
       { "Token",         "afp.session_token",
                FT_BYTES, BASE_HEX, NULL, 0x0,