From Todd Sabin: allocate the buffer for the decrypted payload, rather
[obnox/wireshark/wip.git] / packet-fcfcs.c
1 /* packet-fcfcs.c
2  * Routines for FC Fabric Configuration Server
3  * Copyright 2001, Dinesh G Dutt <ddutt@andiamo.com>
4  *
5  * $Id: packet-fcfcs.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-fcfcs.h"
60
61 /* Initialize the protocol and registered fields */
62 static int proto_fcfcs          = -1;
63 static int hf_fcs_opcode        = -1;
64 static int hf_fcs_iename        = -1;
65 static int hf_fcs_ietype        = -1;
66 static int hf_fcs_iedomainid    = -1;
67 static int hf_fcs_mgmtid        = -1;
68 static int hf_fcs_fabricname    = -1;
69 static int hf_fcs_mgmtaddr      = -1;
70 static int hf_fcs_lname         = -1;
71 static int hf_fcs_vendorname    = -1;
72 static int hf_fcs_modelname     = -1;
73 static int hf_fcs_portname      = -1;
74 static int hf_fcs_portmodtype   = -1;
75 static int hf_fcs_porttxtype    = -1;
76 static int hf_fcs_porttype      = -1;
77 static int hf_fcs_physportnum   = -1;
78 static int hf_fcs_portflags     = -1;
79 static int hf_fcs_portstate     = -1;
80 static int hf_fcs_platformname  = -1;
81 static int hf_fcs_platformnname = -1;
82 static int hf_fcs_platformtype  = -1;
83 static int hf_fcs_platformaddr  = -1;
84 static int hf_fcs_reason        = -1;
85 static int hf_fcs_rjtdetail     = -1;
86 static int hf_fcs_vendor        = -1;
87 static int hf_fcs_numcap        = -1;
88 static int hf_fcs_mgmt_subtype  = -1;
89 static int hf_fcs_unsmask       = -1;
90 static int hf_fcs_vnd_capmask   = -1;
91 static int hf_fcs_fcsmask       = -1;
92 static int hf_fcs_maxres_size   = -1;
93 static int hf_fcs_releasecode   = -1;
94
95
96 /* Initialize the subtree pointers */
97 static gint ett_fcfcs = -1;
98
99 typedef struct _fcfcs_conv_key {
100     guint32 conv_idx;
101 } fcfcs_conv_key_t;
102
103 typedef struct _fcfcs_conv_data {
104     guint32 opcode;
105 } fcfcs_conv_data_t;
106
107 GHashTable *fcfcs_req_hash = NULL;
108 GMemChunk *fcfcs_req_keys = NULL;
109 GMemChunk *fcfcs_req_vals = NULL;
110 guint32 fcfcs_init_count = 25;
111
112 static dissector_handle_t data_handle;
113
114 /*
115  * Hash Functions
116  */
117 static gint
118 fcfcs_equal(gconstpointer v, gconstpointer w)
119 {
120   fcfcs_conv_key_t *v1 = (fcfcs_conv_key_t *)v;
121   fcfcs_conv_key_t *v2 = (fcfcs_conv_key_t *)w;
122
123   return (v1->conv_idx == v2->conv_idx);
124 }
125
126 static guint
127 fcfcs_hash (gconstpointer v)
128 {
129         fcfcs_conv_key_t *key = (fcfcs_conv_key_t *)v;
130         guint val;
131
132         val = key->conv_idx;
133
134         return val;
135 }
136
137 /*
138  * Protocol initialization
139  */
140 static void
141 fcfcs_init_protocol(void)
142 {
143         if (fcfcs_req_keys)
144             g_mem_chunk_destroy (fcfcs_req_keys);
145         if (fcfcs_req_vals)
146             g_mem_chunk_destroy (fcfcs_req_vals);
147         if (fcfcs_req_hash)
148             g_hash_table_destroy (fcfcs_req_hash);
149
150         fcfcs_req_hash = g_hash_table_new(fcfcs_hash, fcfcs_equal);
151         fcfcs_req_keys = g_mem_chunk_new ("fcfcs_req_keys",
152                                           sizeof(fcfcs_conv_key_t),
153                                           fcfcs_init_count *
154                                           sizeof(fcfcs_conv_key_t),
155                                                         G_ALLOC_AND_FREE);
156         fcfcs_req_vals = g_mem_chunk_new ("fcfcs_req_vals",
157                                           sizeof(fcfcs_conv_data_t),
158                                           fcfcs_init_count *
159                                           sizeof(fcfcs_conv_data_t),
160                                           G_ALLOC_AND_FREE);
161 }
162
163 /* Code to actually dissect the packets */
164 static void
165 dissect_fcfcs_giel (tvbuff_t *tvb, proto_tree *tree, gboolean isreq)
166 {
167     int offset = 16;            /* past the ct header */
168     int numelem, i;
169     
170     if (!isreq && tree) {
171         numelem = tvb_get_ntohl (tvb, offset);
172
173         proto_tree_add_text (tree, tvb, offset, 4, "Number of IE entries: 0x%d",
174                              numelem);
175         offset += 4;
176         for (i = 0; i < numelem; i++) {
177             proto_tree_add_string (tree, hf_fcs_iename, tvb, offset, 8,
178                                    fcwwn_to_str (tvb_get_ptr (tvb, offset, 8)));
179             proto_tree_add_item (tree, hf_fcs_ietype, tvb, offset+11, 1, 0);
180             offset += 12;
181         }
182     }
183 }
184
185 static void
186 dissect_fcfcs_giet (tvbuff_t *tvb, proto_tree *tree, gboolean isreq)
187 {
188     int offset = 16; /* past the fcct header */
189
190     if (tree) {
191         if (isreq) {
192             proto_tree_add_string (tree, hf_fcs_iename, tvb, offset, 8,
193                                    fcwwn_to_str (tvb_get_ptr (tvb, offset, 8)));
194         }
195         else {
196             proto_tree_add_item (tree, hf_fcs_ietype, tvb, offset+3, 1, 0);
197         }
198     }
199 }
200
201 static void
202 dissect_fcfcs_gdid (tvbuff_t *tvb, proto_tree *tree, gboolean isreq)
203 {
204     int offset = 16; /* past the fcct header */
205
206     if (tree) {
207         if (isreq) {
208             proto_tree_add_string (tree, hf_fcs_iename, tvb, offset, 8,
209                                    fcwwn_to_str (tvb_get_ptr (tvb, offset, 8)));
210         }
211         else {
212             proto_tree_add_item (tree, hf_fcs_iedomainid, tvb, offset+1, 1, 0);
213         }
214     }
215 }
216
217 static void
218 dissect_fcfcs_gmid (tvbuff_t *tvb, proto_tree *tree, gboolean isreq)
219 {
220     int offset = 16; /* past the fcct header */
221
222     if (tree) {
223         if (isreq) {
224             proto_tree_add_string (tree, hf_fcs_iename, tvb, offset, 8,
225                                    fcwwn_to_str (tvb_get_ptr (tvb, offset, 8)));
226         }
227         else {
228             proto_tree_add_string (tree, hf_fcs_mgmtid, tvb, offset+1, 3,
229                                    fc_to_str (tvb_get_ptr (tvb, offset+1, 3)));
230         }
231     }
232 }
233
234 static void
235 dissect_fcfcs_gfn (tvbuff_t *tvb, proto_tree *tree, gboolean isreq)
236 {
237     int offset = 16; /* past the fcct header */
238
239     if (tree) {
240         if (isreq) {
241             proto_tree_add_string (tree, hf_fcs_iename, tvb, offset, 8,
242                                    fcwwn_to_str (tvb_get_ptr (tvb, offset, 8)));
243         }
244         else {
245             proto_tree_add_string (tree, hf_fcs_fabricname, tvb, offset, 8,
246                                    fcwwn_to_str (tvb_get_ptr (tvb, offset, 8)));
247         }
248     }
249 }
250
251 static void
252 dissect_fcfcs_gieln (tvbuff_t *tvb, proto_tree *tree, gboolean isreq)
253 {
254     int offset = 16; /* past the fcct header */
255
256     if (tree) {
257         if (isreq) {
258             proto_tree_add_string (tree, hf_fcs_iename, tvb, offset, 8,
259                                    fcwwn_to_str (tvb_get_ptr (tvb, offset, 8)));
260         }
261         else {
262             proto_tree_add_text (tree, tvb, offset, 1, "Name Length: %d",
263                                  tvb_get_guint8 (tvb, offset));
264             proto_tree_add_item (tree, hf_fcs_lname, tvb, offset+1,
265                                  tvb_get_guint8 (tvb, offset), 0);
266         }
267     }
268 }
269
270 static void
271 dissect_fcfcs_gmal (tvbuff_t *tvb, proto_tree *tree, gboolean isreq)
272 {
273     int offset = 16; /* past the fcct header */
274     int numelem, i;
275
276     if (tree) {
277         if (isreq) {
278             proto_tree_add_string (tree, hf_fcs_iename, tvb, offset, 8,
279                                    fcwwn_to_str (tvb_get_ptr (tvb, offset, 8)));
280         }
281         else {
282             numelem = tvb_get_ntohl (tvb, offset);
283             proto_tree_add_text (tree, tvb, offset, 4,
284                                  "Number of Mgmt. Addresses: 0x%d", numelem);
285             
286             offset += 4;
287             for (i = 0; i < numelem; i++) {
288                 proto_tree_add_text (tree, tvb, offset, 1, "Name Length: %d",
289                                      tvb_get_guint8 (tvb, offset));
290                 proto_tree_add_item (tree, hf_fcs_mgmtaddr, tvb, offset+1,
291                                      tvb_get_guint8 (tvb, offset), 0);
292                 offset += 256;
293             }
294         }
295     }
296 }
297
298 static void
299 dissect_fcfcs_gieil (tvbuff_t *tvb, proto_tree *tree, gboolean isreq)
300 {
301     int offset = 16; /* past the fcct header */
302     gchar *str;
303     int len, tot_len, prevlen;
304
305     if (tree) {
306         if (isreq) {
307             proto_tree_add_string (tree, hf_fcs_iename, tvb, offset, 8,
308                                    fcwwn_to_str (tvb_get_ptr (tvb, offset, 8)));
309         }
310         else {
311             tot_len = tvb_get_guint8 (tvb, offset+3);
312             proto_tree_add_text (tree, tvb, offset+3, 1, "List Length: %d",
313                                  tot_len);
314
315             prevlen = 0;
316             str = (gchar *)tvb_get_ptr (tvb, offset+4, tot_len);
317             len = strlen (str);
318             if (len) {
319                 proto_tree_add_item (tree, hf_fcs_vendorname, tvb, offset+4,
320                                      len, 0);
321             }
322             
323             prevlen += (len+1);
324             str = (gchar *)tvb_get_ptr (tvb, offset+4+prevlen, tot_len-prevlen);
325             len = strlen (str);
326
327             if (len) {
328                 proto_tree_add_item (tree, hf_fcs_modelname, tvb, offset+4+prevlen,
329                                      len, 0);
330             }
331
332             prevlen += (len+1);
333             str = (gchar *)tvb_get_ptr (tvb, offset+4+prevlen, tot_len-prevlen);
334             len = strlen (str);
335
336             if (len) {
337                 proto_tree_add_item (tree, hf_fcs_releasecode, tvb,
338                                      offset+4+prevlen, len, 0);
339             }
340             
341             prevlen += (len+1);
342             offset += (4+prevlen);
343             while (tot_len > prevlen) {
344                 str = (gchar *)tvb_get_ptr (tvb, offset, tot_len-prevlen);
345                 len = strlen (str);
346                 if (len) {
347                     proto_tree_add_text (tree, tvb, offset, len,
348                                          "Vendor-specific Information: %s",
349                                          str);
350                 }
351                 prevlen += (len+1);
352                 offset += (len+1);
353             }
354         }
355     }
356 }
357
358 static void
359 dissect_fcfcs_gpl (tvbuff_t *tvb, proto_tree *tree, gboolean isreq)
360 {
361     int offset = 16; /* past the fcct header */
362     int numelem, i;
363
364     if (tree) {
365         if (isreq) {
366             proto_tree_add_string (tree, hf_fcs_iename, tvb, offset, 8,
367                                    fcwwn_to_str (tvb_get_ptr (tvb, offset, 8)));
368         }
369         else {
370             numelem = tvb_get_ntohl (tvb, offset);
371             proto_tree_add_text (tree, tvb, offset, 4,
372                                  "Number of Port Entries: %d",
373                                  numelem);
374             offset += 4;
375
376             for (i = 0; i < numelem; i++) {
377                 proto_tree_add_string (tree, hf_fcs_portname, tvb, offset, 8,
378                                        fcwwn_to_str (tvb_get_ptr (tvb, offset,
379                                                                   8)));
380                 proto_tree_add_item (tree, hf_fcs_portmodtype, tvb, offset+9,
381                                      1, 0);
382                 proto_tree_add_item (tree, hf_fcs_porttxtype, tvb, offset+10,
383                                      1, 0);
384                 proto_tree_add_item (tree, hf_fcs_porttype, tvb, offset+11,
385                                      1, 0);
386                 offset += 12;
387             }
388         }
389     }
390 }
391
392 static void
393 dissect_fcfcs_gpt (tvbuff_t *tvb, proto_tree *tree, gboolean isreq)
394 {
395     int offset = 16; /* past the fcct header */
396
397     if (tree) {
398         if (isreq) {
399             proto_tree_add_string (tree, hf_fcs_portname, tvb, offset, 8,
400                                    fcwwn_to_str (tvb_get_ptr (tvb, offset, 8)));
401         }
402         else {
403             proto_tree_add_item (tree, hf_fcs_porttype, tvb, offset+3, 1, 0);
404         }
405     }
406 }
407
408 static void
409 dissect_fcfcs_gppn (tvbuff_t *tvb, proto_tree *tree, gboolean isreq)
410 {
411     int offset = 16; /* past the fcct header */
412
413     if (tree) {
414         if (isreq) {
415             proto_tree_add_string (tree, hf_fcs_portname, tvb, offset, 8,
416                                    fcwwn_to_str (tvb_get_ptr (tvb, offset, 8)));
417         }
418         else {
419             proto_tree_add_item (tree, hf_fcs_physportnum, tvb, offset, 4, 0);
420         }
421     }
422 }
423
424 static void
425 dissect_fcfcs_gapnl (tvbuff_t *tvb, proto_tree *tree, gboolean isreq)
426 {
427     int offset = 16; /* past the fcct header */
428     int numelem, i;
429
430     if (tree) {
431         if (isreq) {
432             proto_tree_add_string (tree, hf_fcs_portname, tvb, offset, 8,
433                                    fcwwn_to_str (tvb_get_ptr (tvb, offset, 8)));
434         }
435         else {
436             numelem = tvb_get_ntohl (tvb, offset);
437             proto_tree_add_text (tree, tvb, offset, 4,
438                                  "Number of Attached Port Entries: %d",
439                                  numelem);
440             offset += 4;
441             for (i = 0; i < numelem; i++) {
442                 proto_tree_add_string (tree, hf_fcs_portname, tvb, offset, 8,
443                                        fcwwn_to_str (tvb_get_ptr (tvb, offset,
444                                                                   8)));
445                 proto_tree_add_item (tree, hf_fcs_portflags, tvb, offset+10,
446                                      1, 0);
447                 proto_tree_add_item (tree, hf_fcs_porttype, tvb, offset+11,
448                                      1, 0);
449                 offset += 12;
450             }
451         }
452     }
453 }
454
455 static void
456 dissect_fcfcs_gps (tvbuff_t *tvb, proto_tree *tree, gboolean isreq)
457 {
458     int offset = 16; /* past the fcct header */
459
460     if (tree) {
461         if (isreq) {
462             proto_tree_add_string (tree, hf_fcs_portname, tvb, offset, 8,
463                                    fcwwn_to_str (tvb_get_ptr (tvb, offset, 8)));
464         }
465         else {
466             proto_tree_add_item (tree, hf_fcs_porttype, tvb, offset+3, 1, 0);
467             proto_tree_add_item (tree, hf_fcs_portstate, tvb, offset+7, 1, 0);
468         }
469     }
470 }
471
472 static void
473 dissect_fcfcs_gplnl (tvbuff_t *tvb, proto_tree *tree, gboolean isreq)
474 {
475     int offset = 16; /* past the fcct header */
476     int numelem, i, len;
477
478     if (tree) {
479         if (isreq) {
480             len = tvb_get_guint8 (tvb, offset);
481             proto_tree_add_text (tree, tvb, offset, 1,
482                                  "Platform Name Length: %d", len);
483             proto_tree_add_item (tree, hf_fcs_platformname, tvb, offset+1,
484                                  len, 0);
485         }
486         else {
487             numelem = tvb_get_ntohl (tvb, offset);
488             proto_tree_add_text (tree, tvb, offset, 4,
489                                  "Number of Platform Node Name Entries: %d",
490                                  numelem);
491             offset += 4;
492             for (i = 0; i < numelem; i++) {
493                 proto_tree_add_string (tree, hf_fcs_platformnname, tvb, offset,
494                                        8,
495                                        fcwwn_to_str (tvb_get_ptr (tvb, offset,
496                                                                   8)));
497                 offset += 8;
498             }
499         }
500     }
501 }
502
503 static void
504 dissect_fcfcs_gplt (tvbuff_t *tvb, proto_tree *tree, gboolean isreq)
505 {
506     int offset = 16; /* past the fcct header */
507     int len;
508
509     if (tree) {
510         if (isreq) {
511             len = tvb_get_guint8 (tvb, offset);
512             proto_tree_add_text (tree, tvb, offset, 1,
513                                  "Platform Name Length: %d", len);
514             proto_tree_add_item (tree, hf_fcs_platformname, tvb, offset+1,
515                                  len, 0);
516         }
517         else {
518             proto_tree_add_item (tree, hf_fcs_platformtype, tvb, offset+3,
519                                  1, 0);
520         }
521     }
522 }
523
524 static void
525 dissect_fcfcs_gplml (tvbuff_t *tvb, proto_tree *tree, gboolean isreq)
526 {
527     int offset = 16; /* past the fcct header */
528     int numelem, i, len;
529
530     if (tree) {
531         if (isreq) {
532             len = tvb_get_guint8 (tvb, offset);
533             proto_tree_add_text (tree, tvb, offset, 1,
534                                  "Platform Name Length: %d", len);
535             proto_tree_add_item (tree, hf_fcs_platformname, tvb, offset+1,
536                                  len, 0);
537         }
538         else {
539             numelem = tvb_get_ntohl (tvb, offset);
540             proto_tree_add_text (tree, tvb, offset, 4,
541                                  "Number of Mgmt. Address Entries: %d",
542                                  numelem);
543             offset += 4;
544             for (i = 0; i < numelem; i++) {
545                 len = tvb_get_guint8 (tvb, offset);
546                 proto_tree_add_text (tree, tvb, offset, 1,
547                                      "Mgmt Address Length: %d",
548                                      len);
549                 proto_tree_add_item (tree, hf_fcs_platformaddr, tvb, offset+1,
550                                      len, 0);
551                 offset += 256;
552             }
553         }
554     }
555 }
556
557 static void
558 dissect_fcfcs_gnpl (tvbuff_t *tvb, proto_tree *tree, gboolean isreq)
559 {
560     int offset = 16; /* past the fcct header */
561     int len;
562
563     if (tree) {
564         if (isreq) {
565             proto_tree_add_string (tree, hf_fcs_platformnname, tvb, offset, 8,
566                                    fcwwn_to_str (tvb_get_ptr (tvb, offset, 8)));
567         }
568         else {
569             len = tvb_get_guint8 (tvb, offset);
570             proto_tree_add_text (tree, tvb, offset, 1,
571                                  "Platform Name Length: %d", len);
572             proto_tree_add_item (tree, hf_fcs_platformname, tvb, offset+1,
573                                  len, 0);
574         }
575     }
576 }
577
578 static void
579 dissect_fcfcs_gpnl (tvbuff_t *tvb, proto_tree *tree, gboolean isreq)
580 {
581     int offset = 16; /* past the fcct header */
582     int numelem, i, len;
583
584     if (tree) {
585         if (!isreq) {
586             numelem = tvb_get_ntohl (tvb, offset);
587
588             proto_tree_add_text (tree, tvb, offset, 4,
589                                  "Number of Platform Name Entries: %d",
590                                  numelem);
591             offset += 4;
592             for (i = 0; i < numelem; i++) {
593                 len = tvb_get_guint8 (tvb, offset);
594                 proto_tree_add_text (tree, tvb, offset, 1,
595                                      "Platform Name Length: %d",
596                                      len);
597                 proto_tree_add_item (tree, hf_fcs_platformname, tvb, offset+1,
598                                      len, 0);
599                 offset += 256;
600             }
601         }
602     }
603 }
604
605 static void
606 dissect_fcfcs_rieln (tvbuff_t *tvb, proto_tree *tree, gboolean isreq)
607 {
608     int offset = 16;            /* past the fc_ct header */
609     int len;
610
611     if (tree) {
612         if (isreq) {
613             proto_tree_add_string (tree, hf_fcs_iename, tvb, offset, 8,
614                                    fcwwn_to_str (tvb_get_ptr (tvb, offset, 8)));
615             len = tvb_get_guint8 (tvb, offset+8);
616             proto_tree_add_text (tree, tvb, offset+8, 1,
617                                  "Logical Name Length: %d", len);
618             proto_tree_add_item (tree, hf_fcs_lname, tvb, offset+9, len, 0);
619         }
620     }
621 }
622
623 static void
624 dissect_fcfcs_rpl (tvbuff_t *tvb, proto_tree *tree, gboolean isreq)
625 {
626     int offset = 16;            /* past the fc_ct header */
627     int numelem, i, len;
628
629     if (tree) {
630         if (isreq) {
631             len = tvb_get_guint8 (tvb, offset);
632             proto_tree_add_text (tree, tvb, offset, 1,
633                                  "Platform Name Length: %d", len);
634             proto_tree_add_item (tree, hf_fcs_platformname, tvb, offset+1,
635                                  len, 0);
636             proto_tree_add_item (tree, hf_fcs_platformtype, tvb, offset+259, 1,
637                                  0);
638             numelem = tvb_get_ntohl (tvb, offset+260);
639             proto_tree_add_text (tree, tvb, offset+260, 4,
640                                  "Number of Mgmt. Addr Entries: %d", numelem);
641             offset += 264;
642             for (i = 0; i < numelem; i++) {
643                 len = tvb_get_guint8 (tvb, offset);
644                 proto_tree_add_text (tree, tvb, offset, 1,
645                                      "Mgmt. Addr Length: %d", len);
646                 proto_tree_add_item (tree, hf_fcs_mgmtaddr, tvb, offset+1,
647                                      len, 0);
648                 offset += 256;
649             }
650
651             numelem = tvb_get_ntohl (tvb, offset);
652             proto_tree_add_text (tree, tvb, offset, 4,
653                                  "Number of Platform Node Name Entries: %d",
654                                  numelem);
655             offset += 4;
656             for (i = 0; i < numelem; i++) {
657                 proto_tree_add_string (tree, hf_fcs_platformnname, tvb, offset,
658                                        8,
659                                        fcwwn_to_str (tvb_get_ptr (tvb, offset,
660                                                                   8)));
661                 offset += 8;
662             }
663         }
664     }
665 }
666
667 static void
668 dissect_fcfcs_rpln (tvbuff_t *tvb, proto_tree *tree, gboolean isreq)
669 {
670     int offset = 16;            /* past the fc_ct header */
671     int len;
672
673     if (tree) {
674         if (isreq) {
675             len = tvb_get_guint8 (tvb, offset);
676             proto_tree_add_text (tree, tvb, offset, 1,
677                                  "Platform Name Length: %d", len);
678             proto_tree_add_item (tree, hf_fcs_platformname, tvb, offset+1,
679                                  len, 0);
680             proto_tree_add_string (tree, hf_fcs_platformnname, tvb, offset+256,
681                                    8,
682                                    fcwwn_to_str (tvb_get_ptr (tvb, offset+256,
683                                                               8)));
684         }
685     }
686 }
687
688 static void
689 dissect_fcfcs_rplt (tvbuff_t *tvb, proto_tree *tree, gboolean isreq)
690 {
691     int offset = 16;            /* past the fc_ct header */
692     int len;
693
694     if (tree) {
695         if (isreq) {
696             len = tvb_get_guint8 (tvb, offset);
697             proto_tree_add_text (tree, tvb, offset, 1,
698                                  "Platform Name Length: %d", len);
699             proto_tree_add_item (tree, hf_fcs_platformname, tvb, offset+1,
700                                  len, 0);
701             proto_tree_add_item (tree, hf_fcs_platformtype, tvb, offset+259,
702                                  4, 0);
703         }
704     }
705 }
706
707 static void
708 dissect_fcfcs_rplm (tvbuff_t *tvb, proto_tree *tree, gboolean isreq)
709 {
710     int offset = 16;            /* past the fc_ct header */
711     int len;
712
713     if (tree) {
714         if (isreq) {
715             len = tvb_get_guint8 (tvb, offset);
716             proto_tree_add_text (tree, tvb, offset, 1,
717                                  "Platform Name Length: %d", len);
718             proto_tree_add_item (tree, hf_fcs_platformname, tvb, offset+1,
719                                  len, 0);
720             len = tvb_get_guint8 (tvb, offset+256);
721             proto_tree_add_text (tree, tvb, offset+256, 1,
722                                  "Platform Mgmt. Address Length: %d", len);
723             proto_tree_add_item (tree, hf_fcs_platformaddr, tvb, offset+257,
724                                  len, 0);
725         }
726     }
727 }
728
729 static void
730 dissect_fcfcs_dpl (tvbuff_t *tvb, proto_tree *tree, gboolean isreq)
731 {
732     int offset = 16;            /* past the fc_ct header */
733     int len;
734
735     if (tree) {
736         if (isreq) {
737             len = tvb_get_guint8 (tvb, offset);
738             proto_tree_add_text (tree, tvb, offset, 1,
739                                  "Platform Name Length: %d", len);
740             proto_tree_add_item (tree, hf_fcs_platformname, tvb, offset+1,
741                                  len, 0);
742         }
743     }
744 }
745
746 static void
747 dissect_fcfcs_dpln (tvbuff_t *tvb, proto_tree *tree, gboolean isreq)
748 {
749     int offset = 16;            /* past the fc_ct header */
750
751     if (tree) {
752         if (isreq) {
753             proto_tree_add_string (tree, hf_fcs_platformnname, tvb, offset, 8,
754                                    fcwwn_to_str (tvb_get_ptr (tvb, offset, 8)));
755         }
756     }
757 }
758
759 static void
760 dissect_fcfcs_dplml (tvbuff_t *tvb, proto_tree *tree, gboolean isreq)
761 {
762     int offset = 16;            /* past the fc_ct header */
763     int len;
764
765     if (tree) {
766         if (isreq) {
767             len = tvb_get_guint8 (tvb, offset);
768             proto_tree_add_text (tree, tvb, offset, 1,
769                                  "Platform Name Length: %d", len);
770             proto_tree_add_item (tree, hf_fcs_platformname, tvb, offset+1,
771                                  len, 0);
772         }
773     }
774 }
775
776 static void
777 dissect_fcfcs_gcap (tvbuff_t *tvb, proto_tree *tree, gboolean isreq)
778 {
779     int offset = 16;            /* past the fc_ct header */
780     int numrec, i;
781     guint8 subtype;
782
783     if (tree) {
784         if (!isreq) {
785             numrec = tvb_get_ntohl (tvb, offset);
786             proto_tree_add_item (tree, hf_fcs_numcap, tvb, offset, 4, 0);
787
788             offset += 4;
789             for (i = 0; i < numrec; i++) {
790                 proto_tree_add_item (tree, hf_fcs_mgmt_subtype, tvb, offset,
791                                      1, 0);
792                 subtype = tvb_get_guint8 (tvb, offset);
793
794                 proto_tree_add_item (tree, hf_fcs_vnd_capmask, tvb, offset+1,
795                                      3, 0);
796                 if (subtype == FCCT_GSSUBTYPE_FCS) {
797                     proto_tree_add_item (tree, hf_fcs_fcsmask, tvb, offset+4,
798                                          4, 0);
799                 }
800                 else if (subtype == FCCT_GSSUBTYPE_UNS) {
801                     proto_tree_add_item (tree, hf_fcs_unsmask, tvb, offset+4,
802                                          4, 0);
803                 }
804             }
805         }
806     }
807 }
808
809 static void
810 dissect_fcfcs_rjt (tvbuff_t *tvb, proto_tree *tree)
811 {
812     int offset = 0;
813
814     if (tree) {
815         proto_tree_add_item (tree, hf_fcs_reason, tvb, offset+13, 1, 0);
816         proto_tree_add_item (tree, hf_fcs_rjtdetail, tvb, offset+14, 1,
817                              0);
818         proto_tree_add_item (tree, hf_fcs_vendor, tvb, offset+15, 1, 0);
819     }
820     
821 }
822
823 static void
824 dissect_fcfcs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
825 {
826     
827 /* Set up structures needed to add the protocol subtree and manage it */
828     int offset = 0;
829     proto_item *ti;
830     proto_tree *fcfcs_tree = NULL;
831     fc_ct_preamble cthdr;
832     gboolean isreq = 1;
833     conversation_t *conversation;
834     fcfcs_conv_data_t *cdata;
835     fcfcs_conv_key_t ckey, *req_key;
836     int opcode,
837         failed_opcode = 0;
838
839     /* Make entries in Protocol column and Info column on summary display */
840     if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
841         col_set_str(pinfo->cinfo, COL_PROTOCOL, "FC-FCS");
842     
843     if (tree) {
844         ti = proto_tree_add_protocol_format (tree, proto_fcfcs, tvb, 0,
845                                              tvb_reported_length (tvb),
846                                              "FCS");
847         fcfcs_tree = proto_item_add_subtree (ti, ett_fcfcs);
848     }
849
850     tvb_memcpy (tvb, (guint8 *)&cthdr, offset, FCCT_PRMBL_SIZE);
851     cthdr.revision = tvb_get_guint8 (tvb, offset);
852     cthdr.in_id = tvb_get_ntoh24 (tvb, offset+1);
853     cthdr.opcode = ntohs (cthdr.opcode);
854     opcode = tvb_get_ntohs (tvb, offset+8);
855     cthdr.maxres_size = ntohs (cthdr.maxres_size);
856
857     if ((opcode != FCCT_MSG_ACC) && (opcode != FCCT_MSG_RJT)) {
858         conversation = find_conversation (&pinfo->src, &pinfo->dst,
859                                           pinfo->ptype, pinfo->oxid,
860                                           pinfo->rxid, NO_PORT2);
861         if (!conversation) {
862             conversation = conversation_new (&pinfo->src, &pinfo->dst,
863                                              pinfo->ptype, pinfo->oxid,
864                                              pinfo->rxid, NO_PORT2);
865         }
866     
867         ckey.conv_idx = conversation->index;
868         
869         cdata = (fcfcs_conv_data_t *)g_hash_table_lookup (fcfcs_req_hash,
870                                                             &ckey);
871         if (cdata) {
872             /* Since we never free the memory used by an exchange, this maybe a
873              * case of another request using the same exchange as a previous
874              * req. 
875              */
876             cdata->opcode = opcode;
877         }
878         else {
879             req_key = g_mem_chunk_alloc (fcfcs_req_keys);
880             req_key->conv_idx = conversation->index;
881             
882             cdata = g_mem_chunk_alloc (fcfcs_req_vals);
883             cdata->opcode = opcode;
884             
885             g_hash_table_insert (fcfcs_req_hash, req_key, cdata);
886         }
887         if (check_col (pinfo->cinfo, COL_INFO)) {
888             col_set_str (pinfo->cinfo, COL_INFO,
889                          val_to_str (opcode, fc_fcs_opcode_abbrev_val, "0x%x"));
890         }
891     }
892     else {
893         /* Opcode is ACC or RJT */
894         conversation = find_conversation (&pinfo->src, &pinfo->dst,
895                                           pinfo->ptype, pinfo->oxid,
896                                           pinfo->rxid, NO_PORT2);
897         isreq = 0;
898         if (!conversation) {
899             if (tree && (opcode == FCCT_MSG_ACC)) {
900                 if (check_col (pinfo->cinfo, COL_INFO)) {
901                     col_set_str (pinfo->cinfo, COL_INFO,
902                                  val_to_str (opcode, fc_fcs_opcode_abbrev_val,
903                                              "0x%x"));
904                 }
905                 /* No record of what this accept is for. Can't decode */
906                 proto_tree_add_text (fcfcs_tree, tvb, 0, tvb_length (tvb),
907                                      "No record of Exchg. Unable to decode MSG_ACC/RJT");
908                 return;
909             }
910         }
911         else {
912             ckey.conv_idx = conversation->index;
913
914             cdata = (fcfcs_conv_data_t *)g_hash_table_lookup (fcfcs_req_hash,
915                                                               &ckey);
916
917             if (cdata != NULL) {
918                 if (opcode == FCCT_MSG_ACC)
919                     opcode = cdata->opcode;
920                 else
921                     failed_opcode = cdata->opcode;
922             }
923             
924             if (check_col (pinfo->cinfo, COL_INFO)) {
925                 if (opcode != FCCT_MSG_RJT) {
926                     col_add_fstr (pinfo->cinfo, COL_INFO, "MSG_ACC (%s)",
927                                   val_to_str (opcode, fc_fcs_opcode_abbrev_val,
928                                               "0x%x"));
929                 }
930                 else {
931                     col_add_fstr (pinfo->cinfo, COL_INFO, "MSG_RJT (%s)",
932                                   val_to_str (failed_opcode,
933                                               fc_fcs_opcode_abbrev_val,
934                                               "0x%x"));
935                 }
936             }
937                 
938             if (tree) {
939                 if ((cdata == NULL) && (opcode != FCCT_MSG_RJT)) {
940                     /* No record of what this accept is for. Can't decode */
941                     proto_tree_add_text (fcfcs_tree, tvb, 0, tvb_length (tvb),
942                                          "No record of Exchg. Unable to decode MSG_ACC/RJT");
943                     return;
944                 }
945             }
946         }
947     }
948
949     
950     if (tree) {
951         proto_tree_add_item (fcfcs_tree, hf_fcs_opcode, tvb, offset+8, 2, 0);
952         proto_tree_add_item (fcfcs_tree, hf_fcs_maxres_size, tvb, offset+10,
953                              2, 0);
954     }
955
956     switch (opcode) {
957     case FCCT_MSG_RJT:
958         dissect_fcfcs_rjt (tvb, fcfcs_tree);
959         break;
960     case FCFCS_GIEL:
961         dissect_fcfcs_giel (tvb, fcfcs_tree, isreq);
962         break;
963     case FCFCS_GIET:
964         dissect_fcfcs_giet (tvb, fcfcs_tree, isreq);
965         break;
966     case FCFCS_GDID:
967         dissect_fcfcs_gdid (tvb, fcfcs_tree, isreq);
968         break;
969     case FCFCS_GMID:
970         dissect_fcfcs_gmid (tvb, fcfcs_tree, isreq);
971         break;
972     case FCFCS_GFN:
973         dissect_fcfcs_gfn (tvb, fcfcs_tree, isreq);
974         break;
975     case FCFCS_GIELN:
976         dissect_fcfcs_gieln (tvb, fcfcs_tree, isreq);
977         break;
978     case FCFCS_GMAL:
979         dissect_fcfcs_gmal (tvb, fcfcs_tree, isreq);
980         break;
981     case FCFCS_GIEIL:
982         dissect_fcfcs_gieil (tvb, fcfcs_tree, isreq);
983         break;
984     case FCFCS_GPL:
985         dissect_fcfcs_gpl (tvb, fcfcs_tree, isreq);
986         break;
987     case FCFCS_GPT:
988         dissect_fcfcs_gpt (tvb, fcfcs_tree, isreq);
989         break;
990     case FCFCS_GPPN:
991         dissect_fcfcs_gppn (tvb, fcfcs_tree, isreq);
992         break;
993     case FCFCS_GAPNL:
994         dissect_fcfcs_gapnl (tvb, fcfcs_tree, isreq);
995         break;
996     case FCFCS_GPS:
997         dissect_fcfcs_gps (tvb, fcfcs_tree, isreq);
998         break;
999     case FCFCS_GPLNL:
1000         dissect_fcfcs_gplnl (tvb, fcfcs_tree, isreq);
1001         break;
1002     case FCFCS_GPLT:
1003         dissect_fcfcs_gplt (tvb, fcfcs_tree, isreq);
1004         break;
1005     case FCFCS_GPLML:
1006         dissect_fcfcs_gplml (tvb, fcfcs_tree, isreq);
1007         break;
1008     case FCFCS_GNPL:
1009         dissect_fcfcs_gnpl (tvb, fcfcs_tree, isreq);
1010         break;
1011     case FCFCS_GPNL:
1012         dissect_fcfcs_gpnl (tvb, fcfcs_tree, isreq);
1013         break;
1014     case FCFCS_RIELN:
1015         dissect_fcfcs_rieln (tvb, fcfcs_tree, isreq);
1016         break;
1017     case FCFCS_RPL:
1018         dissect_fcfcs_rpl (tvb, fcfcs_tree, isreq);
1019         break;
1020     case FCFCS_RPLN:
1021         dissect_fcfcs_rpln (tvb, fcfcs_tree, isreq);
1022         break;
1023     case FCFCS_RPLT:
1024         dissect_fcfcs_rplt (tvb, fcfcs_tree, isreq);
1025         break;
1026     case FCFCS_RPLM:
1027         dissect_fcfcs_rplm (tvb, fcfcs_tree, isreq);
1028         break;
1029     case FCFCS_DPL:
1030         dissect_fcfcs_dpl (tvb, fcfcs_tree, isreq);
1031         break;
1032     case FCFCS_DPLN:
1033         dissect_fcfcs_dpln (tvb, fcfcs_tree, isreq);
1034         break;
1035     case FCFCS_DPLML:
1036         dissect_fcfcs_dplml (tvb, fcfcs_tree, isreq);
1037         break;
1038     case FCFCS_GCAP:
1039         dissect_fcfcs_gcap (tvb, fcfcs_tree, isreq);
1040         break;
1041     default:
1042         call_dissector (data_handle, tvb, pinfo, fcfcs_tree);
1043         break;
1044     }
1045 }
1046
1047 /* Register the protocol with Ethereal */
1048
1049 /* this format is require because a script is used to build the C function
1050    that calls all the protocol registration.
1051 */
1052
1053 void
1054 proto_register_fcfcs (void)
1055 {                 
1056
1057 /* Setup list of header fields  See Section 1.6.1 for details*/
1058     static hf_register_info hf[] = {
1059         { &hf_fcs_opcode,
1060           {"Opcode", "fcs.opcode", FT_UINT16, BASE_HEX,
1061            VALS (fc_fcs_opcode_val), 0x0, "", HFILL}},
1062         { &hf_fcs_iename,
1063           {"Interconnect Element Name", "fcs.ie.name", FT_STRING, BASE_HEX,
1064            NULL, 0x0, "", HFILL}},
1065         { &hf_fcs_ietype,
1066           {"Interconnect Element Type", "fcs.ie.type", FT_UINT8, BASE_HEX,
1067            VALS (fc_fcs_ietype_val), 0x0, "", HFILL}},
1068         { &hf_fcs_iedomainid,
1069           {"Interconnect Element Domain ID", "fcs.ie.domainid", FT_UINT8,
1070            BASE_HEX, NULL, 0x0, "", HFILL}},
1071         { &hf_fcs_mgmtid,
1072           {"Interconnect Element Mgmt. ID", "fcs.ie.mgmtid", FT_STRING,
1073            BASE_HEX, NULL, 0x0, "", HFILL}},
1074         { &hf_fcs_fabricname,
1075           {"Interconnect Element Fabric Name", "fcs.ie.fname", FT_STRING,
1076            BASE_HEX, NULL, 0x0, "", HFILL}},
1077         { &hf_fcs_mgmtaddr,
1078           {"Interconnect Element Mgmt. Address", "fcs.ie.mgmtaddr", FT_STRING,
1079            BASE_HEX, NULL, 0x0, "", HFILL}},
1080         { &hf_fcs_lname,
1081           {"Interconnect Element Logical Name", "fcs.ie.logname", FT_STRING,
1082            BASE_HEX, NULL, 0x0, "", HFILL}},
1083         { &hf_fcs_vendorname,
1084           {"Vendor Name", "fcs.vendorname", FT_STRING, BASE_HEX, NULL, 0x0, "",
1085            HFILL}},
1086         { &hf_fcs_modelname,
1087           {"Model Name/Number", "fcs.modelname", FT_STRING, BASE_HEX, NULL,
1088            0x0, "", HFILL}},
1089         { &hf_fcs_portname,
1090           {"Port Name", "fcs.port.name", FT_STRING, BASE_HEX, NULL, 0x0, "",
1091            HFILL}},
1092         { &hf_fcs_portmodtype,
1093           {"Port Module Type", "fcs.port.moduletype", FT_UINT8, BASE_HEX,
1094            VALS (fc_fcs_port_modtype_val), 0x0, "", HFILL}},
1095         { &hf_fcs_porttxtype,
1096           {"Port TX Type", "fcs.port.txtype", FT_UINT8, BASE_HEX,
1097            VALS (fc_fcs_port_txtype_val), 0x0, "", HFILL}},
1098         { &hf_fcs_porttype,
1099           {"Port Type", "fcs.port.type", FT_UINT8, BASE_HEX,
1100            VALS (fc_fcs_port_type_val), 0x0, "", HFILL}},
1101         { &hf_fcs_physportnum,
1102           {"Physical Port Number", "fcs.port.physportnum", FT_BYTES, BASE_HEX,
1103            NULL, 0x0, "", HFILL}},
1104         { &hf_fcs_portflags,
1105           {"Port Flags", "fcs.port.flags", FT_BOOLEAN, BASE_NONE,
1106            TFS (&fc_fcs_portflags_tfs), 0x0, "", HFILL}},
1107         { &hf_fcs_portstate,
1108           {"Port State", "fcs.port.state", FT_UINT8, BASE_HEX,
1109            VALS (fc_fcs_port_state_val), 0x0, "", HFILL}},
1110         { &hf_fcs_platformname,
1111           {"Platform Name", "fcs.platform.name", FT_STRING, BASE_HEX, NULL, 0x0,
1112            "", HFILL}},
1113         { &hf_fcs_platformnname,
1114           {"Platform Node Name", "fcs.platform.nodename", FT_STRING, BASE_HEX,
1115            NULL, 0x0, "", HFILL}},
1116         { &hf_fcs_platformtype,
1117           {"Platform Type", "fcs.platform.type", FT_UINT8, BASE_HEX,
1118            VALS (fc_fcs_plat_type_val), 0x0, "", HFILL}},
1119         { &hf_fcs_platformaddr,
1120           {"Management Address", "fcs.platform.mgmtaddr", FT_STRING, BASE_HEX,
1121            NULL, 0x0, "", HFILL}},
1122         { &hf_fcs_reason,
1123           {"Reason Code", "fcs.reason", FT_UINT8, BASE_HEX,
1124            VALS (fc_ct_rjt_code_vals), 0x0, "", HFILL}},
1125         { &hf_fcs_rjtdetail,
1126           {"Reason Code Explanantion", "fcs.reasondet", FT_UINT8, BASE_HEX,
1127            VALS (fc_fcs_rjt_code_val), 0x0, "", HFILL}},
1128         { &hf_fcs_vendor,
1129           {"Vendor Unique Reject Code", "fcs.err.vendor", FT_UINT8, BASE_HEX,
1130            NULL, 0x0, "", HFILL}},
1131         { &hf_fcs_numcap,
1132           {"Number of Capabilities", "fcs.numcap", FT_UINT32, BASE_DEC, NULL,
1133            0x0, "", HFILL}},
1134         { &hf_fcs_mgmt_subtype,
1135           {"Management GS Subtype", "fcs.gssubtype", FT_UINT8, BASE_HEX, NULL,
1136            0x0, "", HFILL}},
1137         { &hf_fcs_vnd_capmask,
1138           {"Vendor Unique Capability Bitmask", "fcs.vbitmask", FT_UINT24,
1139            BASE_HEX, NULL, 0x0, "", HFILL}},
1140         { &hf_fcs_fcsmask,
1141           {"Subtype Capability Bitmask", "fcs.fcsmask", FT_UINT32, BASE_HEX,
1142            VALS (fc_fcs_fcsmask_val), 0x0, "", HFILL}},
1143         { &hf_fcs_unsmask,
1144           {"Subtype Capability Bitmask", "fcs.unsmask", FT_UINT32, BASE_HEX,
1145            VALS (fc_fcs_unsmask_val), 0x0, "", HFILL}},
1146         { &hf_fcs_maxres_size,
1147           {"Maximum/Residual Size", "fcs.maxres_size", FT_UINT16, BASE_DEC,
1148            NULL, 0x0, "", HFILL}},
1149         { &hf_fcs_releasecode,
1150           {"Release Code", "fcs.releasecode", FT_STRING, BASE_HEX, NULL, 0x0,
1151            "", HFILL}},
1152     };
1153
1154     /* Setup protocol subtree array */
1155     static gint *ett[] = {
1156         &ett_fcfcs,
1157     };
1158
1159     /* Register the protocol name and description */
1160     proto_fcfcs = proto_register_protocol("FC Fabric Configuration Server",
1161                                           "FC-FCS", "fcs");
1162
1163     /* Required function calls to register the header fields and subtrees used */
1164     proto_register_field_array(proto_fcfcs, hf, array_length(hf));
1165     proto_register_subtree_array(ett, array_length(ett));
1166     register_init_routine (&fcfcs_init_protocol);
1167 }
1168
1169 /* If this dissector uses sub-dissector registration add a registration routine.
1170    This format is required because a script is used to find these routines and
1171    create the code that calls these routines.
1172 */
1173 void
1174 proto_reg_handoff_fcfcs (void)
1175 {
1176     dissector_handle_t fcs_handle;
1177
1178     fcs_handle = create_dissector_handle (dissect_fcfcs, proto_fcfcs);
1179     
1180     dissector_add("fcct.server", FCCT_GSRVR_FCS, fcs_handle);
1181
1182     data_handle = find_dissector ("data");
1183 }
1184
1185