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