From Olivier Biot: have a separate subtree ett_ value for concatenated
[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.1 2003/01/14 01:17:44 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     /* number of zones,
162      * for each zone,
163      *     Zone name (len, name, pad), num zone mbrs
164      *     for each zone mbr,
165      *         zone mbr id type, zone mbr id (len, name, pad)
166      */
167     if (tree) {
168         numzones = tvb_get_ntohl (tvb, offset);
169         proto_tree_add_item (tree, hf_fcfzs_numzonesetattrs, tvb, offset, 4, 0);
170
171         offset += 4;
172         for (i = 0; i < numzones; i++) {
173             len = tvb_get_guint8 (tvb, offset);
174             proto_tree_add_item (tree, hf_fcfzs_zonenmlen, tvb, offset,
175                                  1, 0);
176             proto_tree_add_item (tree, hf_fcfzs_zonename, tvb, offset+1,
177                                  len, 0);
178             offset += len;
179
180             nummbrs = tvb_get_guint8 (tvb, offset);
181             proto_tree_add_item (tree, hf_fcfzs_nummbrentries, tvb, offset,
182                                  4, 0);
183
184             offset += 4;
185             for (j = 0; j < nummbrs; j++) {
186                 proto_tree_add_item (tree, hf_fcfzs_mbrtype, tvb, offset, 1, 0);
187                 
188                 switch (tvb_get_guint8 (tvb, offset)) {
189                 case FC_FZS_ZONEMBR_PWWN:
190                 case FC_FZS_ZONEMBR_NWWN:
191                     proto_tree_add_string (tree, hf_fcfzs_mbrid, tvb,
192                                            offset+4, 8,
193                                            fcwwn_to_str (tvb_get_ptr (tvb,
194                                                                       offset+4,
195                                                                       8)));
196                     break;
197                 case FC_FZS_ZONEMBR_DP:
198                     proto_tree_add_string_format (tree,
199                                                   hf_fcfzs_mbrid,
200                                                   tvb, offset+4, 3, " ",
201                                                   "0x%x",
202                                                   tvb_get_ntoh24 (tvb,
203                                                                   offset+4));
204                     break;
205                 case FC_FZS_ZONEMBR_FCID:
206                     proto_tree_add_string (tree, hf_fcfzs_mbrid, tvb,
207                                            offset+4, 4,
208                                            fc_to_str (tvb_get_ptr (tvb,
209                                                                    offset+4,
210                                                                    3)));
211                     break;
212                 case FC_FZS_ZONEMBR_PWWN_LUN:
213                     proto_tree_add_string (tree, hf_fcfzs_mbrid, tvb,
214                                            offset+4, 8,
215                                            fcwwn_to_str (tvb_get_ptr (tvb,
216                                                                       offset+4,
217                                                                       8)));
218                     proto_tree_add_item (tree, hf_fcfzs_mbrid_lun, tvb,
219                                          offset+8, 8, 0);
220                     break;
221                 case FC_FZS_ZONEMBR_DP_LUN:
222                     proto_tree_add_string_format (tree,
223                                                   hf_fcfzs_mbrid,
224                                                   tvb, offset+4, 3, " ",
225                                                   "0x%x",
226                                                   tvb_get_ntoh24 (tvb,
227                                                                   offset+4));
228                     proto_tree_add_item (tree, hf_fcfzs_mbrid_lun, tvb,
229                                          offset+4, 8, 0);
230                     break;
231                 case FC_FZS_ZONEMBR_FCID_LUN:
232                     proto_tree_add_string (tree, hf_fcfzs_mbrid, tvb,
233                                            offset+4, 4,
234                                            fc_to_str (tvb_get_ptr (tvb,
235                                                                    offset+4,
236                                                                    3)));
237                     proto_tree_add_item (tree, hf_fcfzs_mbrid_lun, tvb,
238                                          offset+4, 8, 0);
239                     break;
240                 default:
241                     proto_tree_add_string (tree, hf_fcfzs_mbrid, tvb,
242                                            offset+4, 8,
243                                            "Unknown member type format");
244                 }
245                 offset += 12;
246             }
247         }
248     }
249 }
250
251 static void
252 dissect_fcfzs_gzc (tvbuff_t *tvb, proto_tree *tree, guint8 isreq)
253 {
254     guint8 flags;
255     gchar str[128];
256     int offset = 16;            /* past the fc_ct header */
257     int stroff = 0;
258     
259     if (tree) {
260         if (!isreq) {
261             flags = tvb_get_guint8 (tvb, offset);
262
263             /* Disect the flags field */
264             str[0] = '\0';
265             if (flags & 0x80) {
266                 strcpy (str, "Hard Zones, ");
267                 stroff += 12;
268             }
269
270             if (flags & 0x40) {
271                 strcpy (&str[stroff], "Soft Zones Supported, ");
272                 stroff += 22;
273             }
274
275             if (flags & 0x01) {
276                 strcpy (&str[stroff], "ZoneSet Database Available");
277                 stroff += 26;
278             }
279
280             proto_tree_add_uint_format (tree, hf_fcfzs_gzc_flags, tvb, offset,
281                                         1, flags, "Capabilities: 0x%x (%s)",
282                                         flags, str);
283             proto_tree_add_item (tree, hf_fcfzs_gzc_vendor, tvb, offset+4, 4, 0);
284         }
285     }
286 }
287
288 static void
289 dissect_fcfzs_gest (tvbuff_t *tvb, proto_tree *tree, guint8 isreq)
290 {
291     guint8 flags;
292     gchar str[128];
293     int offset = 16;            /* past the fc_ct header */
294     int stroff = 0;
295
296     if (tree) {
297         if (!isreq) {
298             flags = tvb_get_guint8 (tvb, offset);
299             str[0] = '\0';
300
301             /* dissect the flags field */
302             if (flags & 0x80) {
303                 strcpy (str, "Soft Zone Set Enforced, ");
304                 stroff += 24;
305             }
306
307             if (flags & 0x40) {
308                  strcpy (str, "Hard Zone Set Enforced");
309                 stroff += 24;
310             }
311
312             proto_tree_add_uint_format (tree, hf_fcfzs_zone_state, tvb, offset,
313                                         1, flags, "Zone State: 0x%x (%s)",
314                                         flags, str);
315             proto_tree_add_item (tree, hf_fcfzs_gest_vendor, tvb, offset+4, 4, 0);
316         }
317     }
318 }
319
320 static void
321 dissect_fcfzs_gzsn (tvbuff_t *tvb, proto_tree *tree, guint8 isreq)
322 {
323     int numrec, i, len;
324     int offset = 16;            /* past the fc_ct header */
325     
326     if (tree) {
327         if (!isreq) {
328             numrec = tvb_get_ntohl (tvb, offset);
329
330             proto_tree_add_item (tree, hf_fcfzs_numzonesetattrs, tvb, offset,
331                                  4, 0);
332
333             offset += 4;
334             for (i = 0; i < numrec; i++) {
335                 len = tvb_get_guint8 (tvb, offset);
336                 proto_tree_add_item (tree, hf_fcfzs_zonesetnmlen, tvb, offset,
337                                      1, 0);
338                 proto_tree_add_item (tree, hf_fcfzs_zonesetname, tvb, offset+1,
339                                      len, 0);
340                 offset += len + 1 + (len % 4);
341                 proto_tree_add_item (tree, hf_fcfzs_numzones, tvb, offset,
342                                      4, 0);
343                 offset += 4;
344             }
345         }
346     }
347 }
348
349 static void
350 dissect_fcfzs_gzd (tvbuff_t *tvb, proto_tree *tree, guint8 isreq)
351 {
352     int numrec, i, len;
353     int offset = 16;            /* past the fc_ct header */
354     
355     if (tree) {
356         if (isreq) {
357             len = tvb_get_guint8 (tvb, offset);
358             proto_tree_add_item (tree, hf_fcfzs_zonesetnmlen, tvb, offset,
359                                  1, 0);
360             proto_tree_add_item (tree, hf_fcfzs_zonesetname, tvb, offset+1,
361                                  len, 0);
362         }
363         else {
364             numrec = tvb_get_ntohl (tvb, offset);
365
366             proto_tree_add_item (tree, hf_fcfzs_numzoneattrs, tvb, offset,
367                                  4, 0);
368             
369             offset += 4;
370             for (i = 0; i < numrec; i++) {
371                 len = tvb_get_guint8 (tvb, offset);
372                 proto_tree_add_item (tree, hf_fcfzs_zonenmlen, tvb, offset,
373                                      1, 0);
374                 proto_tree_add_item (tree, hf_fcfzs_zonename, tvb, offset+1,
375                                      len, 0);
376                 offset += len + 1 + (len % 4);
377                 proto_tree_add_item (tree, hf_fcfzs_nummbrs, tvb, offset,
378                                      4, 0);
379                 offset += 4;
380             }
381         }
382     }
383 }
384
385 static void
386 dissect_fcfzs_gzm (tvbuff_t *tvb, proto_tree *tree, guint8 isreq)
387 {
388     int numrec, i, len;
389     int offset = 16;            /* past the fc_ct header */
390  
391     if (tree) {
392         if (isreq) {
393             len = tvb_get_guint8 (tvb, offset);
394             proto_tree_add_item (tree, hf_fcfzs_zonenmlen, tvb, offset,
395                                  1, 0);
396             proto_tree_add_item (tree, hf_fcfzs_zonename, tvb, offset+1,
397                                  len, 0);
398         }
399         else {
400             numrec = tvb_get_ntohl (tvb, offset);
401
402             proto_tree_add_item (tree, hf_fcfzs_nummbrentries, tvb, offset,
403                                  4, 0);
404             offset += 4;
405             for (i = 0; i < numrec; i++) {
406                 proto_tree_add_item (tree, hf_fcfzs_mbrtype, tvb, offset, 1, 0);
407                 switch (tvb_get_guint8 (tvb, offset)) {
408                 case FC_FZS_ZONEMBR_PWWN:
409                 case FC_FZS_ZONEMBR_NWWN:
410                     proto_tree_add_string (tree, hf_fcfzs_mbrid, tvb,
411                                            offset+4, 8,
412                                            fcwwn_to_str (tvb_get_ptr (tvb,
413                                                                       offset+4,
414                                                                       8)));
415                     break;
416                 case FC_FZS_ZONEMBR_DP:
417                     proto_tree_add_string_format (tree,
418                                                   hf_fcfzs_mbrid,
419                                                   tvb, offset+4, 3, " ",
420                                                   "0x%x",
421                                                   tvb_get_ntoh24 (tvb,
422                                                                   offset+4));
423                     break;
424                 case FC_FZS_ZONEMBR_FCID:
425                     proto_tree_add_string (tree, hf_fcfzs_mbrid, tvb,
426                                            offset+4, 4,
427                                            fc_to_str (tvb_get_ptr (tvb,
428                                                                    offset+4,
429                                                                    3)));
430                     break;
431                 default:
432                     proto_tree_add_string (tree, hf_fcfzs_mbrid, tvb,
433                                            offset+4, 8,
434                                            "Unknown member type format");
435                 }
436                 offset += 12;
437             }
438         }
439     }
440 }
441
442 static void
443 dissect_fcfzs_gazs (tvbuff_t *tvb, proto_tree *tree, guint8 isreq)
444 {
445     int offset = 16;            /* past the fc_ct header */
446     int len;
447     
448     if (tree) {
449         if (!isreq) {
450             len = tvb_get_guint8 (tvb, offset);
451             proto_tree_add_item (tree, hf_fcfzs_zonesetnmlen, tvb, offset,
452                                  1, 0);
453             proto_tree_add_item (tree, hf_fcfzs_zonesetname, tvb, offset+4,
454                                  len, 0);
455             offset += (len + (len % 4));
456
457             dissect_fcfzs_zoneset (tvb, tree, offset);
458         }
459     }
460 }
461
462 static void
463 dissect_fcfzs_gzs (tvbuff_t *tvb, proto_tree *tree, guint8 isreq)
464 {
465     int offset = 16;            /* past the fc_ct header */
466     int len;
467     
468     if (tree) {
469         if (isreq) {
470             len = tvb_get_guint8 (tvb, offset);
471             proto_tree_add_item (tree, hf_fcfzs_zonesetnmlen, tvb, offset,
472                                  1, 0);
473             proto_tree_add_item (tree, hf_fcfzs_zonesetname, tvb, offset+4,
474                                  len, 0);
475         }
476         else {
477             len = tvb_get_guint8 (tvb, offset);
478             proto_tree_add_item (tree, hf_fcfzs_zonesetnmlen, tvb, offset,
479                                  1, 0);
480             proto_tree_add_item (tree, hf_fcfzs_zonesetname, tvb, offset+4,
481                                  len, 0);
482             offset += (len + (len % 4));
483
484             dissect_fcfzs_zoneset (tvb, tree, offset);
485         }
486     }
487 }
488
489 static void
490 dissect_fcfzs_adzs (tvbuff_t *tvb, proto_tree *tree, guint8 isreq)
491 {
492     int offset = 16;            /* past the fc_ct header */
493     int len;
494     
495     if (tree) {
496         if (isreq) {
497             len = tvb_get_guint8 (tvb, offset);
498             proto_tree_add_item (tree, hf_fcfzs_zonesetnmlen, tvb, offset,
499                                  1, 0);
500             proto_tree_add_item (tree, hf_fcfzs_zonesetname, tvb, offset+4,
501                                  len, 0);
502             offset += (len + (len % 4));
503
504             dissect_fcfzs_zoneset (tvb, tree, offset);
505         }
506     }
507 }
508
509 static void
510 dissect_fcfzs_azsd (tvbuff_t *tvb, proto_tree *tree, guint8 isreq)
511 {
512     int offset = 16;            /* past the fc_ct header */
513     int len;
514     
515     if (tree) {
516         if (isreq) {
517             len = tvb_get_guint8 (tvb, offset);
518             proto_tree_add_item (tree, hf_fcfzs_zonesetnmlen, tvb, offset,
519                                  1, 0);
520             proto_tree_add_item (tree, hf_fcfzs_zonesetname, tvb, offset+4,
521                                  len, 0);
522             offset += (len + (len % 4));
523
524             dissect_fcfzs_zoneset (tvb, tree, offset);
525         }
526     }
527 }
528
529 static void
530 dissect_fcfzs_arzs (tvbuff_t *tvb, proto_tree *tree, guint8 isreq)
531 {
532     int offset = 16;            /* past the fc_ct header */
533     int len;
534     
535     if (tree) {
536         if (isreq) {
537             len = tvb_get_guint8 (tvb, offset);
538             proto_tree_add_item (tree, hf_fcfzs_zonesetnmlen, tvb, offset,
539                                  1, 0);
540             proto_tree_add_item (tree, hf_fcfzs_zonesetname, tvb, offset+4,
541                                  len, 0);
542         }
543     }
544 }
545
546 static void
547 dissect_fcfzs_dzs (tvbuff_t *tvb _U_, proto_tree *tree _U_, guint8 isreq _U_)
548 {
549     /* Both req & successful response contain just the FC_CT header */
550     return;
551 }
552
553 static void
554 dissect_fcfzs_arzm (tvbuff_t *tvb, proto_tree *tree, guint8 isreq)
555 {
556     int numrec, i, len, plen;
557     int offset = 16;            /* past the fc_ct header */
558  
559     if (tree) {
560         if (isreq) {
561             len = tvb_get_guint8 (tvb, offset);
562             proto_tree_add_item (tree, hf_fcfzs_zonenmlen, tvb, offset,
563                                  1, 0);
564             proto_tree_add_item (tree, hf_fcfzs_zonename, tvb, offset+1,
565                                  len, 0);
566
567             len += (len % 4);
568             plen = tvb_length (tvb) - offset - len;
569
570             numrec = plen/12;   /* each mbr rec is 12 bytes long */
571
572             offset += len;
573             for (i = 0; i < numrec; i++) {
574                 proto_tree_add_item (tree, hf_fcfzs_mbrtype, tvb, offset, 1, 0);
575                 switch (tvb_get_guint8 (tvb, offset)) {
576                 case FC_FZS_ZONEMBR_PWWN:
577                 case FC_FZS_ZONEMBR_NWWN:
578                     proto_tree_add_string (tree, hf_fcfzs_mbrid, tvb,
579                                            offset+4, 8,
580                                            fcwwn_to_str (tvb_get_ptr (tvb,
581                                                                       offset+4,
582                                                                       8)));
583                     break;
584                 case FC_FZS_ZONEMBR_DP:
585                     proto_tree_add_string_format (tree,
586                                                   hf_fcfzs_mbrid,
587                                                   tvb, offset+4, 3, " ",
588                                                   "0x%x",
589                                                   tvb_get_ntoh24 (tvb,
590                                                                   offset+4));
591                     break;
592                 case FC_FZS_ZONEMBR_FCID:
593                     proto_tree_add_string (tree, hf_fcfzs_mbrid, tvb,
594                                            offset+4, 4,
595                                            fc_to_str (tvb_get_ptr (tvb,
596                                                                    offset+4,
597                                                                    3)));
598                     break;
599                 default:
600                     proto_tree_add_string (tree, hf_fcfzs_mbrid, tvb,
601                                            offset+4, 8,
602                                            "Unknown member type format");
603                 }
604                 offset += 12;
605             }
606         }
607     }
608 }
609
610 static void
611 dissect_fcfzs_arzd (tvbuff_t *tvb, proto_tree *tree, guint8 isreq)
612 {
613     int offset = 16;            /* past the fc_ct header */
614     int len;
615     
616     if (tree) {
617         if (isreq) {
618             len = tvb_get_guint8 (tvb, offset);
619             proto_tree_add_item (tree, hf_fcfzs_zonesetnmlen, tvb, offset,
620                                  1, 0);
621             proto_tree_add_item (tree, hf_fcfzs_zonesetname, tvb, offset+4,
622                                  len, 0);
623             len += (len % 4);
624             offset += len;
625             
626             len = tvb_get_guint8 (tvb, offset);
627             proto_tree_add_item (tree, hf_fcfzs_zonenmlen, tvb, offset, 1, 0);
628             proto_tree_add_item (tree, hf_fcfzs_zonename, tvb, offset+4,
629                                  len, 0);
630         }
631     }
632 }
633
634 static void
635 dissect_fcfzs_rjt (tvbuff_t *tvb, proto_tree *tree)
636 {
637     int offset = 0;
638
639     if (tree) {
640         proto_tree_add_item (tree, hf_fcfzs_reason, tvb, offset+13, 1, 0);
641         proto_tree_add_item (tree, hf_fcfzs_rjtdetail, tvb, offset+14, 1, 0);
642         proto_tree_add_item (tree, hf_fcfzs_rjtvendor, tvb, offset+15, 1, 0); 
643     }
644 }
645
646 static void
647 dissect_fcfzs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
648 {
649
650 /* Set up structures needed to add the protocol subtree and manage it */
651     proto_item *ti;
652     proto_tree *fcfzs_tree = NULL;
653     int offset = 0;
654     fc_ct_preamble cthdr;
655     int opcode,
656         failed_opcode = 0;
657     conversation_t *conversation;
658     fcfzs_conv_data_t *cdata;
659     fcfzs_conv_key_t ckey, *req_key;
660     guint8 isreq = 1;
661
662     /* Make entries in Protocol column and Info column on summary display */
663     if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
664         col_set_str(pinfo->cinfo, COL_PROTOCOL, "Zone Server");
665     
666     
667     tvb_memcpy (tvb, (guint8 *)&cthdr, offset, FCCT_PRMBL_SIZE);
668     cthdr.revision = tvb_get_guint8 (tvb, offset+1);
669     cthdr.in_id = tvb_get_ntoh24 (tvb, offset);
670     cthdr.opcode = ntohs (cthdr.opcode);
671     opcode = cthdr.opcode;
672     cthdr.maxres_size = ntohs (cthdr.maxres_size);
673
674     if (tree) {
675         ti = proto_tree_add_protocol_format (tree, proto_fcfzs, tvb, 0,
676                                              tvb_length (tvb),
677                                              "Zone Server");
678         fcfzs_tree = proto_item_add_subtree (ti, ett_fcfzs);
679         proto_tree_add_item (fcfzs_tree, hf_fcfzs_opcode, tvb, offset+8, 2, 0);
680         proto_tree_add_item (fcfzs_tree, hf_fcfzs_maxres_size, tvb, offset+10,
681                              2, 0);
682     }
683     
684     if ((opcode != FCCT_MSG_ACC) && (opcode != FCCT_MSG_RJT)) {
685         conversation = find_conversation (&pinfo->src, &pinfo->dst,
686                                           pinfo->ptype, pinfo->oxid,
687                                           pinfo->rxid, NO_PORT2);
688         if (!conversation) {
689             conversation = conversation_new (&pinfo->src, &pinfo->dst,
690                                              pinfo->ptype, pinfo->oxid,
691                                              pinfo->rxid, NO_PORT2);
692         }
693         
694         ckey.conv_idx = conversation->index;
695         
696         cdata = (fcfzs_conv_data_t *)g_hash_table_lookup (fcfzs_req_hash,
697                                                             &ckey);
698         if (cdata) {
699             /* Since we never free the memory used by an exchange, this maybe a
700              * case of another request using the same exchange as a previous
701              * req. 
702              */
703             cdata->opcode = opcode;
704         }
705         else {
706             req_key = g_mem_chunk_alloc (fcfzs_req_keys);
707             req_key->conv_idx = conversation->index;
708             
709             cdata = g_mem_chunk_alloc (fcfzs_req_vals);
710             cdata->opcode = opcode;
711             
712             g_hash_table_insert (fcfzs_req_hash, req_key, cdata);
713         }
714         if (check_col (pinfo->cinfo, COL_INFO)) {
715             col_set_str (pinfo->cinfo, COL_INFO, val_to_str (opcode, fc_fzs_opcode_val,
716                                                           "0x%x"));
717         }
718     }
719     else {
720         /* Opcode is ACC or RJT */
721         conversation = find_conversation (&pinfo->src, &pinfo->dst,
722                                           pinfo->ptype, pinfo->oxid,
723                                           pinfo->rxid, NO_PORT2);
724         isreq = 0;
725         if (!conversation) {
726             if (tree && (opcode == FCCT_MSG_ACC)) {
727                 if (check_col (pinfo->cinfo, COL_INFO)) {
728                     col_set_str (pinfo->cinfo, COL_INFO,
729                                  val_to_str (opcode, fc_fzs_opcode_val,
730                                              "0x%x"));
731                 }
732                 /* No record of what this accept is for. Can't decode */
733                 proto_tree_add_text (fcfzs_tree, tvb, 0, tvb_length (tvb),
734                                      "No record of Exchg. Unable to decode MSG_ACC");
735                 return;
736             }
737         }
738         else {
739             ckey.conv_idx = conversation->index;
740
741             cdata = (fcfzs_conv_data_t *)g_hash_table_lookup (fcfzs_req_hash, &ckey);
742
743             if (cdata != NULL) {
744                 if (opcode == FCCT_MSG_ACC)
745                     opcode = cdata->opcode;
746                 else
747                     failed_opcode = cdata->opcode;
748             }
749             
750             if (check_col (pinfo->cinfo, COL_INFO)) {
751                 if (opcode != FCCT_MSG_RJT) {
752                     col_add_fstr (pinfo->cinfo, COL_INFO, "MSG_ACC (%s)",
753                                   val_to_str (opcode,
754                                               fc_fzs_opcode_val, "0x%x"));
755                 }
756                 else {
757                     col_add_fstr (pinfo->cinfo, COL_INFO, "MSG_RJT (%s)",
758                                   val_to_str (failed_opcode,
759                                               fc_fzs_opcode_val, "0x%x"));
760                 }
761             }
762                 
763             if (tree) {
764                 if ((cdata == NULL) && (opcode != FCCT_MSG_RJT)) {
765                     /* No record of what this accept is for. Can't decode */
766                     proto_tree_add_text (fcfzs_tree, tvb, 0, tvb_length (tvb),
767                                          "No record of Exchg. Unable to decode MSG_ACC/RJT");
768                     return;
769                 }
770             }
771         }
772     }
773
774     switch (opcode) {
775     case FCCT_MSG_RJT:
776         dissect_fcfzs_rjt (tvb, fcfzs_tree);
777         break;
778     case FC_FZS_GZC:
779         dissect_fcfzs_gzc (tvb, fcfzs_tree, isreq);
780         break;
781     case FC_FZS_GEST:
782         dissect_fcfzs_gest (tvb, fcfzs_tree, isreq);
783         break;
784     case FC_FZS_GZSN:
785         dissect_fcfzs_gzsn (tvb, fcfzs_tree, isreq);
786         break;
787     case FC_FZS_GZD:
788         dissect_fcfzs_gzd (tvb, fcfzs_tree, isreq);
789         break;
790     case FC_FZS_GZM:
791         dissect_fcfzs_gzm (tvb, fcfzs_tree, isreq);
792         break;
793     case FC_FZS_GAZS:
794         dissect_fcfzs_gazs (tvb, fcfzs_tree, isreq);
795         break;
796     case FC_FZS_GZS:
797         dissect_fcfzs_gzs (tvb, fcfzs_tree, isreq);
798         break;
799     case FC_FZS_ADZS:
800         dissect_fcfzs_adzs (tvb, fcfzs_tree, isreq);
801         break;
802     case FC_FZS_AZSD:
803         dissect_fcfzs_azsd (tvb, fcfzs_tree, isreq);
804         break;
805     case FC_FZS_AZS:
806         dissect_fcfzs_arzs (tvb, fcfzs_tree, isreq);
807         break;
808     case FC_FZS_DZS:
809         dissect_fcfzs_dzs (tvb, fcfzs_tree, isreq);
810         break;
811     case FC_FZS_AZM:
812         dissect_fcfzs_arzm (tvb, fcfzs_tree, isreq);
813         break;
814     case FC_FZS_AZD:
815         dissect_fcfzs_arzd (tvb, fcfzs_tree, isreq);
816         break;
817     case FC_FZS_RZM:
818         dissect_fcfzs_arzm (tvb, fcfzs_tree, isreq);
819         break;
820     case FC_FZS_RZD:
821         dissect_fcfzs_arzd (tvb, fcfzs_tree, isreq);
822         break;
823     case FC_FZS_RZS:
824         dissect_fcfzs_arzs (tvb, fcfzs_tree, isreq);
825         break;
826     default:
827         call_dissector (data_handle, tvb, pinfo, tree);
828         break;
829     }
830 }
831
832 /* Register the protocol with Ethereal */
833
834 /* this format is require because a script is used to build the C function
835    that calls all the protocol registration.
836 */
837
838 void
839 proto_register_fcfzs(void)
840 {                 
841
842 /* Setup list of header fields  See Section 1.6.1 for details*/
843     static hf_register_info hf[] = {
844         { &hf_fcfzs_opcode,
845           {"Opcode", "fcfzs.opcode", FT_UINT16, BASE_HEX,
846            VALS (fc_fzs_opcode_val), 0x0, "", HFILL}},
847         { &hf_fcfzs_gzc_flags,
848           {"Capabilities", "fcfzs.gzc.flags", FT_UINT8, BASE_HEX, NULL, 0x0,
849            "", HFILL}},
850         { &hf_fcfzs_gzc_vendor,
851           {"Vendor Specific Flags", "fcfzs.gzc.vendor", FT_UINT32, BASE_HEX,
852            NULL, 0x0, "", HFILL}},
853         { &hf_fcfzs_zone_state,
854           {"Zone State", "fcfzs.zone.state", FT_UINT8, BASE_HEX, NULL, 0x0,
855            "", HFILL}},
856         { &hf_fcfzs_gest_vendor,
857           {"Vendor Specific State", "fcfzs.gest.vendor", FT_UINT32, BASE_HEX,
858            NULL, 0x0, "", HFILL}},
859         { &hf_fcfzs_numzoneattrs,
860           {"Number of Zone Attribute Entries", "fcfzs.zone.numattrs",
861            FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL}},
862         { &hf_fcfzs_zonesetnmlen,
863           {"Zone Set Name Length", "fcfzs.zoneset.namelen", FT_UINT8, BASE_DEC,
864            NULL, 0x0, "", HFILL}},
865         { &hf_fcfzs_zonesetname,
866           {"Zone Set Name", "fcfzs.zoneset.name", FT_STRING, BASE_HEX, NULL,
867            0x0, "", HFILL}},
868         { &hf_fcfzs_numzones,
869           {"Number of Zones", "fcfzs.zoneset.numzones", FT_UINT32, BASE_DEC,
870            NULL, 0x0, "", HFILL}},
871         { &hf_fcfzs_numzonesetattrs,
872           {"Number of Zone Set Attribute Entries", "fcfzs.zoneset.numattrs",
873            FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL}},
874         { &hf_fcfzs_zonenmlen,
875           {"Zone Name Length", "fcfzs.zone.namelen", FT_UINT8, BASE_DEC, NULL,
876            0x0, "", HFILL}},
877         { &hf_fcfzs_zonename,
878           {"Zone Name", "fcfzs.zone.name", FT_STRING, BASE_HEX, NULL, 0x0, "",
879            HFILL}},
880         { &hf_fcfzs_nummbrs,
881           {"Number of Zone Members", "fcfzs.zone.nummbrs", FT_UINT32, BASE_DEC,
882            NULL, 0x0, "", HFILL}},
883         { &hf_fcfzs_nummbrentries,
884           {"Number of Zone Member Attribute Entries", "fcfzs.zonembr.numattrs",
885            FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL}},
886         { &hf_fcfzs_mbrtype,
887           {"Zone Member Identifier Type", "fcfzs.zonembr.idtype", FT_UINT8,
888            BASE_HEX, VALS (fc_fzs_zonembr_type_val), 0x0, "", HFILL}},
889         { &hf_fcfzs_mbridlen,
890           {"Zone Member Identifier Length", "fcfzs.zonembr.idlen", FT_UINT8,
891            BASE_DEC, NULL, 0x0, "", HFILL}},
892         { &hf_fcfzs_mbrid,
893           {"Zone Member Identifier", "fcfzs.zone.mbrid", FT_STRING, BASE_HEX,
894            NULL, 0x0, "", HFILL}},
895         { &hf_fcfzs_reason,
896           {"Reason Code", "fcfzs.reason", FT_UINT8, BASE_HEX,
897            VALS (fc_ct_rjt_code_vals), 0x0, "", HFILL}},
898         { &hf_fcfzs_rjtdetail,
899           {"Reason Code Explanation", "fcfzs.rjtdetail", FT_UINT8, BASE_HEX,
900            VALS (fc_fzs_rjt_code_val), 0x0, "", HFILL}},
901         { &hf_fcfzs_rjtvendor,
902           {"Vendor Specific Reason", "fcfzs.rjtvendor", FT_UINT8, BASE_HEX,
903            NULL, 0x0, "", HFILL}},
904         { &hf_fcfzs_maxres_size,
905           {"Maximum/Residual Size", "fcfzs.maxres_size", FT_UINT16, BASE_DEC,
906            NULL, 0x0, "", HFILL}},
907         { &hf_fcfzs_mbrid_lun,
908           {"LUN", "fcfzs.zone.lun", FT_BYTES, BASE_HEX, NULL, 0x0, "",
909            HFILL}},
910     };
911
912     /* Setup protocol subtree array */
913     static gint *ett[] = {
914         &ett_fcfzs,
915     };
916
917     /* Register the protocol name and description */
918     proto_fcfzs = proto_register_protocol("Fibre Channel Fabric Zone Server", "FC FZS", "FZS");
919
920     /* Required function calls to register the header fields and subtrees used */
921     proto_register_field_array(proto_fcfzs, hf, array_length(hf));
922     proto_register_subtree_array(ett, array_length(ett));
923     register_init_routine (&fcfzs_init_protocol);
924
925 }
926
927 /* If this dissector uses sub-dissector registration add a registration routine.
928    This format is required because a script is used to find these routines and
929    create the code that calls these routines.
930 */
931 void
932 proto_reg_handoff_fcfzs (void)
933 {
934     dissector_handle_t fzs_handle;
935
936     fzs_handle = create_dissector_handle (dissect_fcfzs, proto_fcfzs);
937     dissector_add("fcct.server", FCCT_GSRVR_FZS, fzs_handle);
938
939     data_handle = find_dissector ("data");
940 }
941
942