The function pointer in a "per_choice_t" or a "per_sequence_t" is to a
[obnox/wireshark/wip.git] / packet-fcfzs.c
1 /* packet-fcfzs.c
2  * Routines for FC Fabric Zone Server
3  * Copyright 2001, Dinesh G Dutt <ddutt@andiamo.com>
4  *
5  * $Id: packet-fcfzs.c,v 1.2 2003/12/02 06:06:30 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * Copied from WHATEVER_FILE_YOU_USED (where "WHATEVER_FILE_YOU_USED"
12  * is a dissector file; if you just copied this from README.developer,
13  * don't bother with the "Copied from" - you don't even need to put
14  * in a "Copied from" if you copied an existing dissector, especially
15  * if the bulk of the code in the new dissector is your code)
16  * 
17  * This program is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU General Public License
19  * as published by the Free Software Foundation; either version 2
20  * of the License, or (at your option) any later version.
21  * 
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  * 
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30  */
31
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 #ifdef HAVE_SYS_TYPES_H
41 # include <sys/types.h>
42 #endif
43
44 #ifdef HAVE_NETINET_IN_H
45 # include <netinet/in.h>
46 #endif
47
48 #include <glib.h>
49
50 #ifdef NEED_SNPRINTF_H
51 # include "snprintf.h"
52 #endif
53
54 #include <epan/packet.h>
55 #include <epan/conversation.h>
56 #include "etypes.h"
57 #include "packet-fc.h"
58 #include "packet-fcct.h"
59 #include "packet-fcfzs.h"
60
61 /* Initialize the protocol and registered fields */
62 static int proto_fcfzs              = -1;
63 static int hf_fcfzs_opcode          = -1;
64 static int hf_fcfzs_gzc_flags       = -1;
65 static int hf_fcfzs_gzc_vendor      = -1;
66 static int hf_fcfzs_zone_state      = -1;
67 static int hf_fcfzs_gest_vendor     = -1;
68 static int hf_fcfzs_numzoneattrs    = -1;
69 static int hf_fcfzs_zonesetnmlen    = -1;
70 static int hf_fcfzs_zonesetname     = -1;
71 static int hf_fcfzs_numzones        = -1;
72 static int hf_fcfzs_numzonesetattrs = -1;
73 static int hf_fcfzs_zonenmlen       = -1;
74 static int hf_fcfzs_zonename        = -1;
75 static int hf_fcfzs_nummbrs         = -1;
76 static int hf_fcfzs_nummbrentries   = -1;
77 static int hf_fcfzs_mbrid           = -1;
78 static int hf_fcfzs_mbridlen        = -1;
79 static int hf_fcfzs_mbrtype         = -1;
80 static int hf_fcfzs_reason          = -1;
81 static int hf_fcfzs_rjtdetail       = -1;
82 static int hf_fcfzs_rjtvendor       = -1;
83 static int hf_fcfzs_maxres_size     = -1;
84 static int hf_fcfzs_mbrid_lun       = -1;
85
86
87 /* Initialize the subtree pointers */
88 static gint ett_fcfzs = -1;
89
90 typedef struct _fcfzs_conv_key {
91     guint32 conv_idx;
92 } fcfzs_conv_key_t;
93
94 typedef struct _fcfzs_conv_data {
95     guint32 opcode;
96 } fcfzs_conv_data_t;
97
98 GHashTable *fcfzs_req_hash = NULL;
99 GMemChunk *fcfzs_req_keys = NULL;
100 GMemChunk *fcfzs_req_vals = NULL;
101 guint32 fcfzs_init_count = 25;
102
103 static dissector_handle_t data_handle;
104
105 /*
106  * Hash Functions
107  */
108 static gint
109 fcfzs_equal(gconstpointer v, gconstpointer w)
110 {
111   fcfzs_conv_key_t *v1 = (fcfzs_conv_key_t *)v;
112   fcfzs_conv_key_t *v2 = (fcfzs_conv_key_t *)w;
113
114   return (v1->conv_idx == v2->conv_idx);
115 }
116
117 static guint
118 fcfzs_hash (gconstpointer v)
119 {
120         fcfzs_conv_key_t *key = (fcfzs_conv_key_t *)v;
121         guint val;
122
123         val = key->conv_idx;
124
125         return val;
126 }
127
128 /*
129  * Protocol initialization
130  */
131 static void
132 fcfzs_init_protocol(void)
133 {
134         if (fcfzs_req_keys)
135             g_mem_chunk_destroy (fcfzs_req_keys);
136         if (fcfzs_req_vals)
137             g_mem_chunk_destroy (fcfzs_req_vals);
138         if (fcfzs_req_hash)
139             g_hash_table_destroy (fcfzs_req_hash);
140
141         fcfzs_req_hash = g_hash_table_new (fcfzs_hash, fcfzs_equal);
142         fcfzs_req_keys = g_mem_chunk_new ("fcfzs_req_keys",
143                                           sizeof(fcfzs_conv_key_t),
144                                           fcfzs_init_count *
145                                           sizeof(fcfzs_conv_key_t),
146                                           G_ALLOC_AND_FREE);
147         fcfzs_req_vals = g_mem_chunk_new ("fcfzs_req_vals",
148                                           sizeof(fcfzs_conv_data_t),
149                                           fcfzs_init_count *
150                                           sizeof(fcfzs_conv_data_t),
151                                           G_ALLOC_AND_FREE);
152 }
153
154 /* Code to actually dissect the packets */
155 static void
156 dissect_fcfzs_zoneset (tvbuff_t *tvb, proto_tree *tree, int offset)
157 {
158     int numzones, nummbrs, i, j, len;
159     
160     /* The zoneset structure has the following format */
161     /* zoneset name (len[not including pad], name, pad),
162      * number of zones,
163      * for each zone,
164      *     Zone name (len[not including pad], name, pad), num zone mbrs
165      *     for each zone mbr,
166      *         zone mbr id type, zone mbr id (len, name, pad)
167      */
168     if (tree) {
169
170         /* Zoneset Name */   
171         len = tvb_get_guint8 (tvb, offset);
172         proto_tree_add_item (tree, hf_fcfzs_zonesetnmlen, tvb, offset,
173                                 1, 0);
174         proto_tree_add_item (tree, hf_fcfzs_zonesetname, tvb, offset+4,
175                                 len, 0);
176         offset += 4 + len + (4-(len % 4));
177
178         
179         /* Number of zones */   
180         numzones = tvb_get_ntohl (tvb, offset);
181         proto_tree_add_item (tree, hf_fcfzs_numzones, tvb, offset, 4, 0);
182         offset += 4;
183         
184         /* For each zone... */   
185         for (i = 0; i < numzones; i++) {
186             len = tvb_get_guint8 (tvb, offset);
187             proto_tree_add_item (tree, hf_fcfzs_zonenmlen, tvb, offset,
188                                  1, 0);
189             proto_tree_add_item (tree, hf_fcfzs_zonename, tvb, offset+4,
190                                  len, 0);
191             offset += 4 + len + (4-(len % 4));
192
193             nummbrs = tvb_get_ntohl (tvb, offset);
194             proto_tree_add_item (tree, hf_fcfzs_nummbrentries, tvb, offset,
195                                  4, 0);
196
197             offset += 4;
198             for (j = 0; j < nummbrs; j++) {
199                 proto_tree_add_item (tree, hf_fcfzs_mbrtype, tvb, offset, 1, 0);
200                 
201                 switch (tvb_get_guint8 (tvb, offset)) {
202                 case FC_FZS_ZONEMBR_PWWN:
203                 case FC_FZS_ZONEMBR_NWWN:
204                     proto_tree_add_string (tree, hf_fcfzs_mbrid, tvb,
205                                            offset+4, 8,
206                                            fcwwn_to_str (tvb_get_ptr (tvb,
207                                                                       offset+4,
208                                                                       8)));
209                     break;
210                 case FC_FZS_ZONEMBR_DP:
211                     proto_tree_add_string_format (tree,
212                                                   hf_fcfzs_mbrid,
213                                                   tvb, offset+4, 3, " ",
214                                                   "0x%x",
215                                                   tvb_get_ntoh24 (tvb,
216                                                                   offset+4));
217                     break;
218                 case FC_FZS_ZONEMBR_FCID:
219                     proto_tree_add_string (tree, hf_fcfzs_mbrid, tvb,
220                                            offset+4, 4,
221                                            fc_to_str (tvb_get_ptr (tvb,
222                                                                    offset+4,
223                                                                    3)));
224                     break;
225                 case FC_FZS_ZONEMBR_PWWN_LUN:
226                     proto_tree_add_string (tree, hf_fcfzs_mbrid, tvb,
227                                            offset+4, 8,
228                                            fcwwn_to_str (tvb_get_ptr (tvb,
229                                                                       offset+4,
230                                                                       8)));
231                     proto_tree_add_item (tree, hf_fcfzs_mbrid_lun, tvb,
232                                          offset+8, 8, 0);
233                     break;
234                 case FC_FZS_ZONEMBR_DP_LUN:
235                     proto_tree_add_string_format (tree,
236                                                   hf_fcfzs_mbrid,
237                                                   tvb, offset+4, 3, " ",
238                                                   "0x%x",
239                                                   tvb_get_ntoh24 (tvb,
240                                                                   offset+4));
241                     proto_tree_add_item (tree, hf_fcfzs_mbrid_lun, tvb,
242                                          offset+4, 8, 0);
243                     break;
244                 case FC_FZS_ZONEMBR_FCID_LUN:
245                     proto_tree_add_string (tree, hf_fcfzs_mbrid, tvb,
246                                            offset+4, 4,
247                                            fc_to_str (tvb_get_ptr (tvb,
248                                                                    offset+4,
249                                                                    3)));
250                     proto_tree_add_item (tree, hf_fcfzs_mbrid_lun, tvb,
251                                          offset+4, 8, 0);
252                     break;
253                 default:
254                     proto_tree_add_string (tree, hf_fcfzs_mbrid, tvb,
255                                            offset+4, 8,
256                                            "Unknown member type format");
257                 }
258                 offset += 12;
259             }
260         }
261     }
262 }
263
264 static void
265 dissect_fcfzs_gzc (tvbuff_t *tvb, proto_tree *tree, guint8 isreq)
266 {
267     guint8 flags;
268     gchar str[128];
269     int offset = 16;            /* past the fc_ct header */
270     int stroff = 0;
271     
272     if (tree) {
273         if (!isreq) {
274             flags = tvb_get_guint8 (tvb, offset);
275
276             /* Disect the flags field */
277             str[0] = '\0';
278             if (flags & 0x80) {
279                 strcpy (str, "Hard Zones, ");
280                 stroff += 12;
281             }
282
283             if (flags & 0x40) {
284                 strcpy (&str[stroff], "Soft Zones Supported, ");
285                 stroff += 22;
286             }
287
288             if (flags & 0x01) {
289                 strcpy (&str[stroff], "ZoneSet Database Available");
290                 stroff += 26;
291             }
292
293             proto_tree_add_uint_format (tree, hf_fcfzs_gzc_flags, tvb, offset,
294                                         1, flags, "Capabilities: 0x%x (%s)",
295                                         flags, str);
296             proto_tree_add_item (tree, hf_fcfzs_gzc_vendor, tvb, offset+4, 4, 0);
297         }
298     }
299 }
300
301 static void
302 dissect_fcfzs_gest (tvbuff_t *tvb, proto_tree *tree, guint8 isreq)
303 {
304     guint8 flags;
305     gchar str[128];
306     int offset = 16;            /* past the fc_ct header */
307     int stroff = 0;
308
309     if (tree) {
310         if (!isreq) {
311             flags = tvb_get_guint8 (tvb, offset);
312             str[0] = '\0';
313
314             /* dissect the flags field */
315             if (flags & 0x80) {
316                 strcpy (str, "Soft Zone Set Enforced, ");
317                 stroff += 24;
318             }
319
320             if (flags & 0x40) {
321                  strcpy (str, "Hard Zone Set Enforced");
322                 stroff += 24;
323             }
324
325             proto_tree_add_uint_format (tree, hf_fcfzs_zone_state, tvb, offset,
326                                         1, flags, "Zone State: 0x%x (%s)",
327                                         flags, str);
328             proto_tree_add_item (tree, hf_fcfzs_gest_vendor, tvb, offset+4, 4, 0);
329         }
330     }
331 }
332
333 static void
334 dissect_fcfzs_gzsn (tvbuff_t *tvb, proto_tree *tree, guint8 isreq)
335 {
336     int numrec, i, len;
337     int offset = 16;            /* past the fc_ct header */
338     
339     if (tree) {
340         if (!isreq) {
341             numrec = tvb_get_ntohl (tvb, offset);
342
343             proto_tree_add_item (tree, hf_fcfzs_numzonesetattrs, tvb, offset,
344                                  4, 0);
345
346             offset += 4;
347             for (i = 0; i < numrec; i++) {
348                 len = tvb_get_guint8 (tvb, offset);
349                 proto_tree_add_item (tree, hf_fcfzs_zonesetnmlen, tvb, offset,
350                                      1, 0);
351                 proto_tree_add_item (tree, hf_fcfzs_zonesetname, tvb, offset+1,
352                                      len, 0);
353                 offset += len + 1 + (len % 4);
354                 proto_tree_add_item (tree, hf_fcfzs_numzones, tvb, offset,
355                                      4, 0);
356                 offset += 4;
357             }
358         }
359     }
360 }
361
362 static void
363 dissect_fcfzs_gzd (tvbuff_t *tvb, proto_tree *tree, guint8 isreq)
364 {
365     int numrec, i, len;
366     int offset = 16;            /* past the fc_ct header */
367     
368     if (tree) {
369         if (isreq) {
370             len = tvb_get_guint8 (tvb, offset);
371             proto_tree_add_item (tree, hf_fcfzs_zonesetnmlen, tvb, offset,
372                                  1, 0);
373             proto_tree_add_item (tree, hf_fcfzs_zonesetname, tvb, offset+1,
374                                  len, 0);
375         }
376         else {
377             numrec = tvb_get_ntohl (tvb, offset);
378
379             proto_tree_add_item (tree, hf_fcfzs_numzoneattrs, tvb, offset,
380                                  4, 0);
381             
382             offset += 4;
383             for (i = 0; i < numrec; i++) {
384                 len = tvb_get_guint8 (tvb, offset);
385                 proto_tree_add_item (tree, hf_fcfzs_zonenmlen, tvb, offset,
386                                      1, 0);
387                 proto_tree_add_item (tree, hf_fcfzs_zonename, tvb, offset+1,
388                                      len, 0);
389                 offset += len + 1 + (len % 4);
390                 proto_tree_add_item (tree, hf_fcfzs_nummbrs, tvb, offset,
391                                      4, 0);
392                 offset += 4;
393             }
394         }
395     }
396 }
397
398 static void
399 dissect_fcfzs_gzm (tvbuff_t *tvb, proto_tree *tree, guint8 isreq)
400 {
401     int numrec, i, len;
402     int offset = 16;            /* past the fc_ct header */
403  
404     if (tree) {
405         if (isreq) {
406             len = tvb_get_guint8 (tvb, offset);
407             proto_tree_add_item (tree, hf_fcfzs_zonenmlen, tvb, offset,
408                                  1, 0);
409             proto_tree_add_item (tree, hf_fcfzs_zonename, tvb, offset+1,
410                                  len, 0);
411         }
412         else {
413             numrec = tvb_get_ntohl (tvb, offset);
414
415             proto_tree_add_item (tree, hf_fcfzs_nummbrentries, tvb, offset,
416                                  4, 0);
417             offset += 4;
418             for (i = 0; i < numrec; i++) {
419                 proto_tree_add_item (tree, hf_fcfzs_mbrtype, tvb, offset, 1, 0);
420                 switch (tvb_get_guint8 (tvb, offset)) {
421                 case FC_FZS_ZONEMBR_PWWN:
422                 case FC_FZS_ZONEMBR_NWWN:
423                     proto_tree_add_string (tree, hf_fcfzs_mbrid, tvb,
424                                            offset+4, 8,
425                                            fcwwn_to_str (tvb_get_ptr (tvb,
426                                                                       offset+4,
427                                                                       8)));
428                     break;
429                 case FC_FZS_ZONEMBR_DP:
430                     proto_tree_add_string_format (tree,
431                                                   hf_fcfzs_mbrid,
432                                                   tvb, offset+4, 3, " ",
433                                                   "0x%x",
434                                                   tvb_get_ntoh24 (tvb,
435                                                                   offset+4));
436                     break;
437                 case FC_FZS_ZONEMBR_FCID:
438                     proto_tree_add_string (tree, hf_fcfzs_mbrid, tvb,
439                                            offset+4, 4,
440                                            fc_to_str (tvb_get_ptr (tvb,
441                                                                    offset+4,
442                                                                    3)));
443                     break;
444                 default:
445                     proto_tree_add_string (tree, hf_fcfzs_mbrid, tvb,
446                                            offset+4, 8,
447                                            "Unknown member type format");
448                 }
449                 offset += 12;
450             }
451         }
452     }
453 }
454
455 static void
456 dissect_fcfzs_gazs (tvbuff_t *tvb, proto_tree *tree, guint8 isreq)
457 {
458     int offset = 16;            /* past the fc_ct header */
459     
460     if (tree) {
461         if (!isreq) {
462             dissect_fcfzs_zoneset (tvb, tree, offset);
463         }
464     }
465 }
466
467 static void
468 dissect_fcfzs_gzs (tvbuff_t *tvb, proto_tree *tree, guint8 isreq)
469 {
470     int offset = 16;            /* past the fc_ct header */
471     int len;
472     
473     if (tree) {
474         if (isreq) {
475             len = tvb_get_guint8 (tvb, offset);
476             proto_tree_add_item (tree, hf_fcfzs_zonesetnmlen, tvb, offset,
477                                  1, 0);
478             proto_tree_add_item (tree, hf_fcfzs_zonesetname, tvb, offset+4,
479                                  len, 0);
480         }
481         else {
482             dissect_fcfzs_zoneset (tvb, tree, offset);
483         }
484     }
485 }
486
487 static void
488 dissect_fcfzs_adzs (tvbuff_t *tvb, proto_tree *tree, guint8 isreq)
489 {
490     int offset = 16;            /* past the fc_ct header */
491     
492     if (tree) {
493         if (isreq) {
494             dissect_fcfzs_zoneset (tvb, tree, offset);
495         }
496     }
497 }
498
499 static void
500 dissect_fcfzs_azsd (tvbuff_t *tvb, proto_tree *tree, guint8 isreq)
501 {
502     int offset = 16;            /* past the fc_ct header */
503     
504     if (tree) {
505         if (isreq) {
506             dissect_fcfzs_zoneset (tvb, tree, offset);
507         }
508     }
509 }
510
511 static void
512 dissect_fcfzs_arzs (tvbuff_t *tvb, proto_tree *tree, guint8 isreq)
513 {
514     int offset = 16;            /* past the fc_ct header */
515     int len;
516     
517     if (tree) {
518         if (isreq) {
519             len = tvb_get_guint8 (tvb, offset);
520             proto_tree_add_item (tree, hf_fcfzs_zonesetnmlen, tvb, offset,
521                                  1, 0);
522             proto_tree_add_item (tree, hf_fcfzs_zonesetname, tvb, offset+4,
523                                  len, 0);
524         }
525     }
526 }
527
528 static void
529 dissect_fcfzs_dzs (tvbuff_t *tvb _U_, proto_tree *tree _U_, guint8 isreq _U_)
530 {
531     /* Both req & successful response contain just the FC_CT header */
532     return;
533 }
534
535 static void
536 dissect_fcfzs_arzm (tvbuff_t *tvb, proto_tree *tree, guint8 isreq)
537 {
538     int numrec, i, len, plen;
539     int offset = 16;            /* past the fc_ct header */
540  
541     if (tree) {
542         if (isreq) {
543             len = tvb_get_guint8 (tvb, offset);
544             proto_tree_add_item (tree, hf_fcfzs_zonenmlen, tvb, offset,
545                                  1, 0);
546             proto_tree_add_item (tree, hf_fcfzs_zonename, tvb, offset+1,
547                                  len, 0);
548
549             len += (len % 4);
550             plen = tvb_length (tvb) - offset - len;
551
552             numrec = plen/12;   /* each mbr rec is 12 bytes long */
553
554             offset += len;
555             for (i = 0; i < numrec; i++) {
556                 proto_tree_add_item (tree, hf_fcfzs_mbrtype, tvb, offset, 1, 0);
557                 switch (tvb_get_guint8 (tvb, offset)) {
558                 case FC_FZS_ZONEMBR_PWWN:
559                 case FC_FZS_ZONEMBR_NWWN:
560                     proto_tree_add_string (tree, hf_fcfzs_mbrid, tvb,
561                                            offset+4, 8,
562                                            fcwwn_to_str (tvb_get_ptr (tvb,
563                                                                       offset+4,
564                                                                       8)));
565                     break;
566                 case FC_FZS_ZONEMBR_DP:
567                     proto_tree_add_string_format (tree,
568                                                   hf_fcfzs_mbrid,
569                                                   tvb, offset+4, 3, " ",
570                                                   "0x%x",
571                                                   tvb_get_ntoh24 (tvb,
572                                                                   offset+4));
573                     break;
574                 case FC_FZS_ZONEMBR_FCID:
575                     proto_tree_add_string (tree, hf_fcfzs_mbrid, tvb,
576                                            offset+4, 4,
577                                            fc_to_str (tvb_get_ptr (tvb,
578                                                                    offset+4,
579                                                                    3)));
580                     break;
581                 default:
582                     proto_tree_add_string (tree, hf_fcfzs_mbrid, tvb,
583                                            offset+4, 8,
584                                            "Unknown member type format");
585                 }
586                 offset += 12;
587             }
588         }
589     }
590 }
591
592 static void
593 dissect_fcfzs_arzd (tvbuff_t *tvb, proto_tree *tree, guint8 isreq)
594 {
595     int offset = 16;            /* past the fc_ct header */
596     int len;
597     
598     if (tree) {
599         if (isreq) {
600             len = tvb_get_guint8 (tvb, offset);
601             proto_tree_add_item (tree, hf_fcfzs_zonesetnmlen, tvb, offset,
602                                  1, 0);
603             proto_tree_add_item (tree, hf_fcfzs_zonesetname, tvb, offset+4,
604                                  len, 0);
605             len += (len % 4);
606             offset += len;
607             
608             len = tvb_get_guint8 (tvb, offset);
609             proto_tree_add_item (tree, hf_fcfzs_zonenmlen, tvb, offset, 1, 0);
610             proto_tree_add_item (tree, hf_fcfzs_zonename, tvb, offset+4,
611                                  len, 0);
612         }
613     }
614 }
615
616 static void
617 dissect_fcfzs_rjt (tvbuff_t *tvb, proto_tree *tree)
618 {
619     int offset = 0;
620
621     if (tree) {
622         proto_tree_add_item (tree, hf_fcfzs_reason, tvb, offset+13, 1, 0);
623         proto_tree_add_item (tree, hf_fcfzs_rjtdetail, tvb, offset+14, 1, 0);
624         proto_tree_add_item (tree, hf_fcfzs_rjtvendor, tvb, offset+15, 1, 0); 
625     }
626 }
627
628 static void
629 dissect_fcfzs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
630 {
631
632 /* Set up structures needed to add the protocol subtree and manage it */
633     proto_item *ti;
634     proto_tree *fcfzs_tree = NULL;
635     int offset = 0;
636     fc_ct_preamble cthdr;
637     int opcode,
638         failed_opcode = 0;
639     conversation_t *conversation;
640     fcfzs_conv_data_t *cdata;
641     fcfzs_conv_key_t ckey, *req_key;
642     guint8 isreq = 1;
643
644     /* Make entries in Protocol column and Info column on summary display */
645     if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
646         col_set_str(pinfo->cinfo, COL_PROTOCOL, "Zone Server");
647     
648     
649     tvb_memcpy (tvb, (guint8 *)&cthdr, offset, FCCT_PRMBL_SIZE);
650     cthdr.revision = tvb_get_guint8 (tvb, offset+1);
651     cthdr.in_id = tvb_get_ntoh24 (tvb, offset);
652     cthdr.opcode = ntohs (cthdr.opcode);
653     opcode = cthdr.opcode;
654     cthdr.maxres_size = ntohs (cthdr.maxres_size);
655
656     if (tree) {
657         ti = proto_tree_add_protocol_format (tree, proto_fcfzs, tvb, 0,
658                                              tvb_length (tvb),
659                                              "Zone Server");
660         fcfzs_tree = proto_item_add_subtree (ti, ett_fcfzs);
661         proto_tree_add_item (fcfzs_tree, hf_fcfzs_opcode, tvb, offset+8, 2, 0);
662         proto_tree_add_item (fcfzs_tree, hf_fcfzs_maxres_size, tvb, offset+10,
663                              2, 0);
664     }
665     
666     if ((opcode != FCCT_MSG_ACC) && (opcode != FCCT_MSG_RJT)) {
667         conversation = find_conversation (&pinfo->src, &pinfo->dst,
668                                           pinfo->ptype, pinfo->oxid,
669                                           pinfo->rxid, NO_PORT2);
670         if (!conversation) {
671             conversation = conversation_new (&pinfo->src, &pinfo->dst,
672                                              pinfo->ptype, pinfo->oxid,
673                                              pinfo->rxid, NO_PORT2);
674         }
675         
676         ckey.conv_idx = conversation->index;
677         
678         cdata = (fcfzs_conv_data_t *)g_hash_table_lookup (fcfzs_req_hash,
679                                                             &ckey);
680         if (cdata) {
681             /* Since we never free the memory used by an exchange, this maybe a
682              * case of another request using the same exchange as a previous
683              * req. 
684              */
685             cdata->opcode = opcode;
686         }
687         else {
688             req_key = g_mem_chunk_alloc (fcfzs_req_keys);
689             req_key->conv_idx = conversation->index;
690             
691             cdata = g_mem_chunk_alloc (fcfzs_req_vals);
692             cdata->opcode = opcode;
693             
694             g_hash_table_insert (fcfzs_req_hash, req_key, cdata);
695         }
696         if (check_col (pinfo->cinfo, COL_INFO)) {
697             col_set_str (pinfo->cinfo, COL_INFO, val_to_str (opcode, fc_fzs_opcode_val,
698                                                           "0x%x"));
699         }
700     }
701     else {
702         /* Opcode is ACC or RJT */
703         conversation = find_conversation (&pinfo->src, &pinfo->dst,
704                                           pinfo->ptype, pinfo->oxid,
705                                           pinfo->rxid, NO_PORT2);
706         isreq = 0;
707         if (!conversation) {
708             if (tree && (opcode == FCCT_MSG_ACC)) {
709                 if (check_col (pinfo->cinfo, COL_INFO)) {
710                     col_set_str (pinfo->cinfo, COL_INFO,
711                                  val_to_str (opcode, fc_fzs_opcode_val,
712                                              "0x%x"));
713                 }
714                 /* No record of what this accept is for. Can't decode */
715                 proto_tree_add_text (fcfzs_tree, tvb, 0, tvb_length (tvb),
716                                      "No record of Exchg. Unable to decode MSG_ACC");
717                 return;
718             }
719         }
720         else {
721             ckey.conv_idx = conversation->index;
722
723             cdata = (fcfzs_conv_data_t *)g_hash_table_lookup (fcfzs_req_hash, &ckey);
724
725             if (cdata != NULL) {
726                 if (opcode == FCCT_MSG_ACC)
727                     opcode = cdata->opcode;
728                 else
729                     failed_opcode = cdata->opcode;
730             }
731             
732             if (check_col (pinfo->cinfo, COL_INFO)) {
733                 if (opcode != FCCT_MSG_RJT) {
734                     col_add_fstr (pinfo->cinfo, COL_INFO, "MSG_ACC (%s)",
735                                   val_to_str (opcode,
736                                               fc_fzs_opcode_val, "0x%x"));
737                 }
738                 else {
739                     col_add_fstr (pinfo->cinfo, COL_INFO, "MSG_RJT (%s)",
740                                   val_to_str (failed_opcode,
741                                               fc_fzs_opcode_val, "0x%x"));
742                 }
743             }
744                 
745             if (tree) {
746                 if ((cdata == NULL) && (opcode != FCCT_MSG_RJT)) {
747                     /* No record of what this accept is for. Can't decode */
748                     proto_tree_add_text (fcfzs_tree, tvb, 0, tvb_length (tvb),
749                                          "No record of Exchg. Unable to decode MSG_ACC/RJT");
750                     return;
751                 }
752             }
753         }
754     }
755
756     switch (opcode) {
757     case FCCT_MSG_RJT:
758         dissect_fcfzs_rjt (tvb, fcfzs_tree);
759         break;
760     case FC_FZS_GZC:
761         dissect_fcfzs_gzc (tvb, fcfzs_tree, isreq);
762         break;
763     case FC_FZS_GEST:
764         dissect_fcfzs_gest (tvb, fcfzs_tree, isreq);
765         break;
766     case FC_FZS_GZSN:
767         dissect_fcfzs_gzsn (tvb, fcfzs_tree, isreq);
768         break;
769     case FC_FZS_GZD:
770         dissect_fcfzs_gzd (tvb, fcfzs_tree, isreq);
771         break;
772     case FC_FZS_GZM:
773         dissect_fcfzs_gzm (tvb, fcfzs_tree, isreq);
774         break;
775     case FC_FZS_GAZS:
776         dissect_fcfzs_gazs (tvb, fcfzs_tree, isreq);
777         break;
778     case FC_FZS_GZS:
779         dissect_fcfzs_gzs (tvb, fcfzs_tree, isreq);
780         break;
781     case FC_FZS_ADZS:
782         dissect_fcfzs_adzs (tvb, fcfzs_tree, isreq);
783         break;
784     case FC_FZS_AZSD:
785         dissect_fcfzs_azsd (tvb, fcfzs_tree, isreq);
786         break;
787     case FC_FZS_AZS:
788         dissect_fcfzs_arzs (tvb, fcfzs_tree, isreq);
789         break;
790     case FC_FZS_DZS:
791         dissect_fcfzs_dzs (tvb, fcfzs_tree, isreq);
792         break;
793     case FC_FZS_AZM:
794         dissect_fcfzs_arzm (tvb, fcfzs_tree, isreq);
795         break;
796     case FC_FZS_AZD:
797         dissect_fcfzs_arzd (tvb, fcfzs_tree, isreq);
798         break;
799     case FC_FZS_RZM:
800         dissect_fcfzs_arzm (tvb, fcfzs_tree, isreq);
801         break;
802     case FC_FZS_RZD:
803         dissect_fcfzs_arzd (tvb, fcfzs_tree, isreq);
804         break;
805     case FC_FZS_RZS:
806         dissect_fcfzs_arzs (tvb, fcfzs_tree, isreq);
807         break;
808     default:
809         call_dissector (data_handle, tvb, pinfo, tree);
810         break;
811     }
812 }
813
814 /* Register the protocol with Ethereal */
815
816 /* this format is require because a script is used to build the C function
817    that calls all the protocol registration.
818 */
819
820 void
821 proto_register_fcfzs(void)
822 {                 
823
824 /* Setup list of header fields  See Section 1.6.1 for details*/
825     static hf_register_info hf[] = {
826         { &hf_fcfzs_opcode,
827           {"Opcode", "fcfzs.opcode", FT_UINT16, BASE_HEX,
828            VALS (fc_fzs_opcode_val), 0x0, "", HFILL}},
829         { &hf_fcfzs_gzc_flags,
830           {"Capabilities", "fcfzs.gzc.flags", FT_UINT8, BASE_HEX, NULL, 0x0,
831            "", HFILL}},
832         { &hf_fcfzs_gzc_vendor,
833           {"Vendor Specific Flags", "fcfzs.gzc.vendor", FT_UINT32, BASE_HEX,
834            NULL, 0x0, "", HFILL}},
835         { &hf_fcfzs_zone_state,
836           {"Zone State", "fcfzs.zone.state", FT_UINT8, BASE_HEX, NULL, 0x0,
837            "", HFILL}},
838         { &hf_fcfzs_gest_vendor,
839           {"Vendor Specific State", "fcfzs.gest.vendor", FT_UINT32, BASE_HEX,
840            NULL, 0x0, "", HFILL}},
841         { &hf_fcfzs_numzoneattrs,
842           {"Number of Zone Attribute Entries", "fcfzs.zone.numattrs",
843            FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL}},
844         { &hf_fcfzs_zonesetnmlen,
845           {"Zone Set Name Length", "fcfzs.zoneset.namelen", FT_UINT8, BASE_DEC,
846            NULL, 0x0, "", HFILL}},
847         { &hf_fcfzs_zonesetname,
848           {"Zone Set Name", "fcfzs.zoneset.name", FT_STRING, BASE_HEX, NULL,
849            0x0, "", HFILL}},
850         { &hf_fcfzs_numzones,
851           {"Number of Zones", "fcfzs.zoneset.numzones", FT_UINT32, BASE_DEC,
852            NULL, 0x0, "", HFILL}},
853         { &hf_fcfzs_numzonesetattrs,
854           {"Number of Zone Set Attribute Entries", "fcfzs.zoneset.numattrs",
855            FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL}},
856         { &hf_fcfzs_zonenmlen,
857           {"Zone Name Length", "fcfzs.zone.namelen", FT_UINT8, BASE_DEC, NULL,
858            0x0, "", HFILL}},
859         { &hf_fcfzs_zonename,
860           {"Zone Name", "fcfzs.zone.name", FT_STRING, BASE_HEX, NULL, 0x0, "",
861            HFILL}},
862         { &hf_fcfzs_nummbrs,
863           {"Number of Zone Members", "fcfzs.zone.nummbrs", FT_UINT32, BASE_DEC,
864            NULL, 0x0, "", HFILL}},
865         { &hf_fcfzs_nummbrentries,
866           {"Number of Zone Member Attribute Entries", "fcfzs.zonembr.numattrs",
867            FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL}},
868         { &hf_fcfzs_mbrtype,
869           {"Zone Member Identifier Type", "fcfzs.zonembr.idtype", FT_UINT8,
870            BASE_HEX, VALS (fc_fzs_zonembr_type_val), 0x0, "", HFILL}},
871         { &hf_fcfzs_mbridlen,
872           {"Zone Member Identifier Length", "fcfzs.zonembr.idlen", FT_UINT8,
873            BASE_DEC, NULL, 0x0, "", HFILL}},
874         { &hf_fcfzs_mbrid,
875           {"Zone Member Identifier", "fcfzs.zone.mbrid", FT_STRING, BASE_HEX,
876            NULL, 0x0, "", HFILL}},
877         { &hf_fcfzs_reason,
878           {"Reason Code", "fcfzs.reason", FT_UINT8, BASE_HEX,
879            VALS (fc_ct_rjt_code_vals), 0x0, "", HFILL}},
880         { &hf_fcfzs_rjtdetail,
881           {"Reason Code Explanation", "fcfzs.rjtdetail", FT_UINT8, BASE_HEX,
882            VALS (fc_fzs_rjt_code_val), 0x0, "", HFILL}},
883         { &hf_fcfzs_rjtvendor,
884           {"Vendor Specific Reason", "fcfzs.rjtvendor", FT_UINT8, BASE_HEX,
885            NULL, 0x0, "", HFILL}},
886         { &hf_fcfzs_maxres_size,
887           {"Maximum/Residual Size", "fcfzs.maxres_size", FT_UINT16, BASE_DEC,
888            NULL, 0x0, "", HFILL}},
889         { &hf_fcfzs_mbrid_lun,
890           {"LUN", "fcfzs.zone.lun", FT_BYTES, BASE_HEX, NULL, 0x0, "",
891            HFILL}},
892     };
893
894     /* Setup protocol subtree array */
895     static gint *ett[] = {
896         &ett_fcfzs,
897     };
898
899     /* Register the protocol name and description */
900     proto_fcfzs = proto_register_protocol("Fibre Channel Fabric Zone Server", "FC FZS", "FZS");
901
902     /* Required function calls to register the header fields and subtrees used */
903     proto_register_field_array(proto_fcfzs, hf, array_length(hf));
904     proto_register_subtree_array(ett, array_length(ett));
905     register_init_routine (&fcfzs_init_protocol);
906
907 }
908
909 /* If this dissector uses sub-dissector registration add a registration routine.
910    This format is required because a script is used to find these routines and
911    create the code that calls these routines.
912 */
913 void
914 proto_reg_handoff_fcfzs (void)
915 {
916     dissector_handle_t fzs_handle;
917
918     fzs_handle = create_dissector_handle (dissect_fcfzs, proto_fcfzs);
919     dissector_add("fcct.server", FCCT_GSRVR_FZS, fzs_handle);
920
921     data_handle = find_dissector ("data");
922 }
923
924