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