Add {0, NULL} to the isup_Pass_on_not_possible_indicator_vals and
[obnox/wireshark/wip.git] / packet-fcels.c
1 /* packet-fcels.c
2  * Routines for FC Extended Link Services
3  * Copyright 2001, Dinesh G Dutt <ddutt@cisco.com>
4  *
5  * $Id: packet-fcels.c,v 1.6 2003/11/07 08:50:43 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
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 /*
27  * TODO Still (Complete compliance with FC-MI):
28  * - Decode RNID, RLIR
29  */
30
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38
39 #ifdef HAVE_SYS_TYPES_H
40 # include <sys/types.h>
41 #endif
42
43 #ifdef HAVE_NETINET_IN_H
44 # include <netinet/in.h>
45 #endif
46
47 #include <glib.h>
48
49 #ifdef NEED_SNPRINTF_H
50 # include "snprintf.h"
51 #endif
52
53 #include <epan/packet.h>
54 #include <epan/conversation.h>
55 #include "etypes.h"
56 #include "packet-fc.h"
57 #include "packet-fcels.h"
58
59 #define FC_ELS_RPLY 0
60 #define FC_ELS_REQ  1
61
62 /* Initialize the protocol and registered fields */
63 static int proto_fcels               = -1;
64 static int hf_fcels_opcode           = -1;
65 static int hf_fcels_rjtcode          = -1;
66 static int hf_fcels_rjtdetcode       = -1;
67 static int hf_fcels_vnduniq          = -1;
68 static int hf_fcels_b2b              = -1;
69 static int hf_fcels_cmnfeatures      = -1;
70 static int hf_fcels_bbscnum          = -1;
71 static int hf_fcels_rcvsize          = -1;
72 static int hf_fcels_maxconseq        = -1;
73 static int hf_fcels_reloffset        = -1;
74 static int hf_fcels_edtov            = -1;
75 static int hf_fcels_npname           = -1;
76 static int hf_fcels_fnname           = -1;
77 static int hf_fcels_cls1param        = -1;
78 static int hf_fcels_cls2param        = -1;
79 static int hf_fcels_cls3param        = -1;
80 static int hf_fcels_cls4param        = -1;
81 static int hf_fcels_vendorvers       = -1;
82 static int hf_fcels_svcavail         = -1;
83 static int hf_fcels_clsflags         = -1;
84 static int hf_fcels_initctl          = -1;
85 static int hf_fcels_rcptctl          = -1;
86 static int hf_fcels_clsrcvsize       = -1;
87 static int hf_fcels_conseq           = -1;
88 static int hf_fcels_e2e              = -1;
89 static int hf_fcels_openseq          = -1;
90 static int hf_fcels_nportid          = -1;
91 static int hf_fcels_oxid             = -1;
92 static int hf_fcels_rxid             = -1;
93 static int hf_fcels_recovqual        = -1;
94 static int hf_fcels_fabricaddr       = -1;
95 static int hf_fcels_fabricpname      = -1;
96 static int hf_fcels_failedrcvr       = -1;
97 static int hf_fcels_flacompliance    = -1;
98 static int hf_fcels_loopstate        = -1;
99 static int hf_fcels_publicloop_bmap  = -1;
100 static int hf_fcels_pvtloop_bmap     = -1;
101 static int hf_fcels_alpa_map         = -1;
102 static int hf_fcels_scrregn          = -1;
103 static int hf_fcels_farp_matchcodept = -1;
104 static int hf_fcels_farp_respaction  = -1;
105 static int hf_fcels_resportid        = -1;
106 static int hf_fcels_respname         = -1;
107 static int hf_fcels_respnname        = -1;
108 static int hf_fcels_reqipaddr        = -1;
109 static int hf_fcels_respipaddr       = -1;
110 static int hf_fcels_hardaddr         = -1;
111 static int hf_fcels_rps_flag         = -1;
112 static int hf_fcels_rps_portnum      = -1;
113 static int hf_fcels_rps_portstatus   = -1;
114 static int hf_fcels_rnft_fc4type     = -1;
115 static int hf_fcels_rscn_evqual      = -1;
116 static int hf_fcels_rscn_addrfmt     = -1;
117 static int hf_fcels_rscn_domain      = -1;
118 static int hf_fcels_rscn_area        = -1;
119 static int hf_fcels_rscn_port        = -1;
120 static int hf_fcels_nodeidfmt = -1;
121 static int hf_fcels_spidlen = -1;
122 static int hf_fcels_vendoruniq = -1;
123 static int hf_fcels_vendorsp = -1;
124 static int hf_fcels_asstype = -1;
125 static int hf_fcels_physport = -1;
126 static int hf_fcels_attnodes = -1;
127 static int hf_fcels_nodemgmt = -1;
128 static int hf_fcels_ipvers = -1;
129 static int hf_fcels_tcpport = -1;
130 static int hf_fcels_ip = -1;
131
132 static gint ett_fcels;           
133 static gint ett_fcels_lsrjt;
134 static gint ett_fcels_acc;
135 static gint ett_fcels_logi;
136 static gint ett_fcels_logi_cmnsvc;
137 static gint ett_fcels_logi_clssvc;
138 static gint ett_fcels_logo;
139 static gint ett_fcels_abtx;
140 static gint ett_fcels_rsi;
141 static gint ett_fcels_rrq;
142 static gint ett_fcels_prli;
143 static gint ett_fcels_prli_svcpg;
144 static gint ett_fcels_adisc;
145 static gint ett_fcels_farp;
146 static gint ett_fcels_rps;
147 static gint ett_fcels_rpl;
148 static gint ett_fcels_rplpb;
149 static gint ett_fcels_fan;
150 static gint ett_fcels_rscn;
151 static gint ett_fcels_rscn_rec;
152 static gint ett_fcels_scr;
153 static gint ett_fcels_rnft;
154 static gint ett_fcels_rnft_fc4;
155 static gint ett_fcels_lsts;
156 static gint ett_fcels_rnid;
157 static gint ett_fcels_rlir;
158 static gint ett_fcels_lirr;
159 static gint ett_fcels_srl;
160 static gint ett_fcels_rpsc;         
161
162 static const value_string fc_prli_fc4_val[] = {
163     {FC_TYPE_SCSI    , "FCP"},
164     {FC_TYPE_IP      , "IP/FC"},
165     {FC_TYPE_LLCSNAP , "LLC_SNAP"},
166     {FC_TYPE_ELS     , "Ext Link Svc"},
167     {FC_TYPE_FCCT    , "FC_CT"},
168     {FC_TYPE_SWILS   , "SW_ILS"},
169     {FC_TYPE_AL      , "AL"},
170     {FC_TYPE_SNMP    , "SNMP"},
171     {FC_TYPE_CMNSVC  , "Common to all FC-4 Types"},
172     {0, NULL},
173 };
174
175 typedef struct _fcels_conv_key {
176     guint32 conv_idx;
177 } fcels_conv_key_t;
178
179 typedef struct _fcels_conv_data {
180     guint32 opcode;
181 } fcels_conv_data_t;
182
183 GHashTable *fcels_req_hash = NULL;
184 GMemChunk *fcels_req_keys = NULL;
185 GMemChunk *fcels_req_vals = NULL;
186 guint32 fcels_init_count = 25;
187
188 static dissector_handle_t data_handle, fcsp_handle;
189
190 /*
191  * Hash Functions
192  */
193 static gint
194 fcels_equal(gconstpointer v, gconstpointer w)
195 {
196   fcels_conv_key_t *v1 = (fcels_conv_key_t *)v;
197   fcels_conv_key_t *v2 = (fcels_conv_key_t *)w;
198
199   return (v1->conv_idx == v2->conv_idx);
200 }
201
202 static guint
203 fcels_hash (gconstpointer v)
204 {
205         fcels_conv_key_t *key = (fcels_conv_key_t *)v;
206         guint val;
207
208         val = key->conv_idx;
209
210         return val;
211 }
212
213 /*
214  * Protocol initialization
215  */
216 static void
217 fcels_init_protocol(void)
218 {
219         if (fcels_req_keys)
220             g_mem_chunk_destroy(fcels_req_keys);
221         if (fcels_req_vals)
222             g_mem_chunk_destroy(fcels_req_vals);
223         if (fcels_req_hash)
224             g_hash_table_destroy(fcels_req_hash);
225
226         fcels_req_hash = g_hash_table_new(fcels_hash, fcels_equal);
227         fcels_req_keys = g_mem_chunk_new ("fcels_req_keys",
228                                           sizeof(fcels_conv_key_t),
229                                           fcels_init_count *
230                                           sizeof(fcels_conv_key_t),
231                                           G_ALLOC_AND_FREE);
232         fcels_req_vals = g_mem_chunk_new ("fcels_req_vals",
233                                           sizeof(fcels_conv_data_t),
234                                           fcels_init_count *
235                                           sizeof(fcels_conv_data_t),
236                                           G_ALLOC_AND_FREE);
237 }
238
239 static void
240 construct_cmnsvc_string (guint16 flag, gchar *flagstr, guint8 opcode)
241 {
242     int stroff = 0;
243     gchar punc[3];
244
245     punc[0] = '\0';
246     
247     if (flag & 0x8000) {
248         strcpy (flagstr, "Cont. Incr. Offset Supported");
249         stroff += 28;
250         strcpy (punc, ", ");
251     }
252     if (flag & 0x4000) {
253         sprintf (&flagstr[stroff], "%sRRO Supported", punc);
254         stroff += 15;
255         strcpy (punc, ", ");
256     }
257     
258     if (flag & 0x2000) {
259         sprintf (flagstr, "%sValid Vendor Version Level", punc);
260         strcpy (punc, ", ");
261         stroff += 28;
262     }
263     
264     if (flag & 0x0800) {
265         sprintf (&flagstr[stroff], "%sAlt B2B Credit Mgmt", punc);
266         strcpy (punc, ", ");
267         stroff += 24;
268     }
269     else {
270         sprintf (&flagstr[stroff], "%sNormal B2B Credit Mgmt", punc);
271         strcpy (punc, ", ");
272         stroff += 22;
273     }
274
275     if ((opcode == FC_ELS_PLOGI) || (opcode == FC_ELS_PDISC)) {
276         if (flag & 0x0400) {
277             strcpy (&flagstr[stroff], ", E_D_TOV Resolution in ns");
278         }
279         else {
280             strcpy (&flagstr[stroff], ", E_D_TOV Resolution in ms");
281         }
282         stroff += 26;
283
284         if (flag & 0x0040) {
285             strcpy (&flagstr[stroff], ", Simplex Dedicated Conn Supported");
286             stroff += 34;
287         }
288     }
289
290     if (flag & 0x0200) {
291         strcpy (&flagstr[stroff], ", Multicast Supported");
292         stroff += 21;
293     }
294     
295     if (flag & 0x0100) {
296         strcpy (&flagstr[stroff], ", Broadcast Supported");
297         stroff += 21;
298     }
299
300     if (flag & 0x0020) {
301         strcpy (&flagstr[stroff], ", Security Bit");
302         stroff += 14;
303     }
304     
305     if (flag & 0x0010) {
306         strcpy (&flagstr[stroff], ", Clk Sync Prim Capable");
307         stroff += 23;
308     }
309     if (flag & 0x0004) {
310         strcpy (&flagstr[stroff], ", DHD Capable");
311         stroff += 13;
312     }
313
314     if ((opcode == FC_ELS_PLOGI) || (opcode == FC_ELS_PDISC)) {
315         if (flag & 0x0002) {
316             strcpy (&flagstr[stroff], ", Cont. Incr SEQCNT rules");
317             stroff += 25;
318         }
319         else {
320             strcpy (&flagstr[stroff], ", Normal SEQCNT rules");
321             stroff += 21;
322         }
323     }
324
325     if (flag & 0x0001) {
326         sprintf (&flagstr[stroff], ", Payload Len=256 bytes");
327     }
328     else {
329         sprintf (&flagstr[stroff], ", Payload Len=116 bytes");
330     }
331 }
332
333 /* The next 3 routines decode only Class 2 & Class 3 relevant bits */
334 static void
335 construct_clssvc_string (guint16 flag, gchar *flagstr, guint8 opcode)
336 {
337     int stroff = 0;
338
339     if (!(flag & 0x8000)) {
340         strcpy (flagstr, "Class Not Supported");
341         return;
342     }
343
344     if ((opcode == FC_ELS_FLOGI) || (opcode == FC_ELS_FDISC)) {
345         if (flag & 0x0800) {
346             strcpy (flagstr, "Seq Delivery Requested");
347             stroff += 22;
348         }
349         else {
350             strcpy (flagstr, "Out of Order Delivery Requested");
351             stroff += 31;
352         }
353     }
354
355     if (flag & 0x0080) {
356         strcpy (&flagstr[stroff], ", Priority/preemption supported");
357         stroff += 31;
358     }
359
360     if ((opcode == FC_ELS_PLOGI) || (opcode == FC_ELS_PDISC)) {
361         if (flag & 0x0040) {
362             strcpy (&flagstr[stroff], "Non-zero CS_CTL Tolerated");
363         }
364         else {
365             strcpy (&flagstr[stroff], "Non-zero CS_CTL Maybe Tolerated");
366         }
367     }
368 }
369
370 static void
371 construct_initctl_string (guint16 flag, gchar *flagstr, guint8 opcode)
372 {
373     int stroff = 0;
374     
375     if ((opcode == FC_ELS_PLOGI) || (opcode == FC_ELS_PDISC)) {
376         switch ((flag & 0x3000)) {
377         case 0x0:
378             strcpy (flagstr, "Initial P_A Not Supported");
379             stroff += 25;
380             break;
381         case 0x1000:
382             strcpy (flagstr, "Initial P_A Supported");
383             stroff += 21;
384             break;
385         case 0x3000:
386             strcpy (flagstr, "Initial P_A Required & Supported");
387             stroff += 32;
388             break;
389         }
390
391         if (flag & 0x0800) {
392             strcpy (&flagstr[stroff], ", ACK0 Capable");
393             stroff += 14;
394         }
395
396         if (flag & 0x0200) {
397             strcpy (&flagstr[stroff], ", ACK Generation Assistance Avail");
398             stroff += 33;
399         }
400         if (flag & 0x0010) {
401             strcpy (&flagstr[stroff], ", Clock Sync ELS Supported");
402         }
403     }
404     else {
405         if (flag & 0x0010) {
406             strcpy (&flagstr[stroff], "Clock Sync ELS Supported");
407         }
408     }
409 }
410
411 static void
412 construct_rcptctl_string (guint16 flag, gchar *flagstr, guint8 opcode)
413 {
414     int stroff = 0;
415     gchar punc[3];
416
417     punc[0] = '\0';
418
419     if ((opcode == FC_ELS_PLOGI) || (opcode == FC_ELS_PDISC)) {
420         if (flag & 0x8000) {
421             strcpy (flagstr, "ACK_0 Supported");
422             stroff += 15;
423         }
424         else {
425             strcpy (flagstr, "ACK_0 Not Supported");
426             stroff += 19;
427         }
428
429         if (flag & 0x2000) {
430             strcpy (&flagstr[stroff], ", X_ID Interlock Reqd");
431             stroff += 21;
432         }
433
434         switch (flag & 0x1800) {
435         case 0x0:
436             strcpy (&flagstr[stroff], ", Error Policy: Discard Policy only");
437             stroff += 43;
438             break;
439         case 0x1000:
440             strcpy (&flagstr[stroff], ", Error Policy: Both discard and process policies supported");
441             stroff += 52;
442             break;
443         case 0x0800:
444             strcpy (&flagstr[stroff], ", Error Policy: Reserved");
445             stroff += 41;
446             break;
447         case 0x1800:
448             strcpy (&flagstr[stroff], ", Error Policy: Reserved");
449             stroff += 52;
450             break;
451         }
452
453         switch (flag & 0x0030) {
454         case 0:
455             strcpy (&flagstr[stroff], ", 1 Category/Seq");
456             stroff += 16;
457             break;
458         case 0x0010:
459             strcpy (&flagstr[stroff], ", 2 Categories/Seq");
460             stroff += 18;
461             break;
462         case 0x0030:
463             strcpy (&flagstr[stroff], ", More than 2 Categories/Seq");
464             stroff += 28;
465             break;
466         }
467
468         if (flag & 0x0008) {
469             strcpy (&flagstr[stroff], ", Clk Sync ELS Supported");
470         }
471     }
472     else {
473         if (flag & 0x0008) {
474             strcpy (&flagstr[stroff], "Clk Sync ELS Supported");
475         }
476     }
477 }
478
479
480 static void
481 dissect_fcels_logi (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
482                     proto_item *ti, guint8 opcode)
483 {
484     /* Set up structures needed to add the protocol subtree and manage it */
485     int offset = 0,
486         svcvld = 0,
487         class;
488     proto_tree *logi_tree, *cmnsvc_tree;
489     proto_item *subti;
490     gchar flagstr[256];
491     guint16 flag;
492     
493     if (tree) {
494         logi_tree = proto_item_add_subtree (ti, ett_fcels_logi);
495         proto_tree_add_item (logi_tree, hf_fcels_opcode, tvb, offset, 1, FALSE);
496         
497         subti = proto_tree_add_text (logi_tree, tvb, offset+4, 16,
498                                      "Common Svc Parameters");
499         cmnsvc_tree = proto_item_add_subtree (subti, ett_fcels_logi_cmnsvc);
500         proto_tree_add_item (cmnsvc_tree, hf_fcels_b2b, tvb, offset+6, 2, FALSE);
501         flag = tvb_get_ntohs (tvb, offset+8);
502         
503         if (flag & 0x0001) {
504             svcvld = 1;
505         }
506
507         construct_cmnsvc_string (flag, flagstr, opcode);
508         proto_tree_add_uint_format (cmnsvc_tree, hf_fcels_cmnfeatures, tvb,
509                                     offset+8, 2, flag,
510                                     "Common Svc Parameters: 0x%x (%s)",
511                                     flag, flagstr);
512         
513         proto_tree_add_item (cmnsvc_tree, hf_fcels_bbscnum, tvb, offset+10, 1, FALSE);
514         proto_tree_add_item (cmnsvc_tree, hf_fcels_rcvsize, tvb, offset+10, 2, FALSE);
515         proto_tree_add_item (cmnsvc_tree, hf_fcels_maxconseq, tvb, offset+12, 2, FALSE);
516         proto_tree_add_item (cmnsvc_tree, hf_fcels_reloffset, tvb, offset+14, 2, FALSE);
517         proto_tree_add_item (cmnsvc_tree, hf_fcels_edtov, tvb, offset+16, 4, FALSE);
518         proto_tree_add_string (cmnsvc_tree, hf_fcels_npname, tvb, offset+20, 8,
519                                fcwwn_to_str (tvb_get_ptr (tvb, offset+20, 8)));
520         proto_tree_add_string (cmnsvc_tree, hf_fcels_fnname, tvb, offset+28, 8,
521                                fcwwn_to_str (tvb_get_ptr (tvb, offset+28, 8)));
522
523         /* Add subtree for class paramters */
524         offset = 36;
525         for (class = 1; class < 5; class++) {
526             subti = proto_tree_add_text (logi_tree, tvb, offset, 16,
527                                          "Class %d Svc Parameters", class);
528             cmnsvc_tree = proto_item_add_subtree (subti, ett_fcels_logi_cmnsvc);
529
530             flag = tvb_get_ntohs (tvb, offset);
531             construct_clssvc_string (flag, flagstr, opcode);
532             proto_tree_add_uint_format (cmnsvc_tree, hf_fcels_clsflags, tvb,
533                                         offset, 2, flag,
534                                         "Service Options: 0x%x(%s)", flag,
535                                         flagstr);
536             if (flag & 0x8000) {
537                 flag = tvb_get_ntohs (tvb, offset+2);
538                 construct_initctl_string (flag, flagstr, opcode);
539                 proto_tree_add_uint_format (cmnsvc_tree, hf_fcels_initctl, tvb,
540                                             offset+2, 2, flag,
541                                             "Initiator Control: 0x%x(%s)", flag,
542                                             flagstr);
543
544                 flag = tvb_get_ntohs (tvb, offset+4);
545                 construct_rcptctl_string (flag, flagstr, opcode);
546                 proto_tree_add_uint_format (cmnsvc_tree, hf_fcels_initctl, tvb,
547                                             offset+4, 2, flag,
548                                             "Recipient Control: 0x%x(%s)", flag,
549                                             flagstr);
550
551                 proto_tree_add_item (cmnsvc_tree, hf_fcels_clsrcvsize, tvb,
552                                      offset+6, 2, FALSE);
553                 proto_tree_add_item (cmnsvc_tree, hf_fcels_conseq, tvb,
554                                      offset+8, 2, FALSE);
555                 proto_tree_add_item (cmnsvc_tree, hf_fcels_e2e, tvb,
556                                      offset+10, 2, FALSE);
557                 proto_tree_add_item (cmnsvc_tree, hf_fcels_openseq, tvb,
558                                      offset+12, 2, FALSE);
559             }
560             offset += 16;
561         }
562         proto_tree_add_item (logi_tree, hf_fcels_vendorvers, tvb, offset, 16, FALSE);
563         if (svcvld) {
564             proto_tree_add_item (logi_tree, hf_fcels_svcavail, tvb, offset+32, 8, FALSE);
565         }
566     }
567 }
568
569 static void
570 dissect_fcels_plogi (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
571                      guint8 isreq _U_, proto_item *ti)
572 {
573     dissect_fcels_logi (tvb, pinfo, tree, ti, FC_ELS_PLOGI);
574 }
575
576 static void
577 dissect_fcels_flogi (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
578                      guint8 isreq _U_, proto_item *ti)
579 {
580     dissect_fcels_logi (tvb, pinfo, tree, ti, FC_ELS_FLOGI);
581 }
582
583 static void
584 dissect_fcels_logout (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
585                       guint8 isreq, proto_item *ti)
586 {
587     /* Set up structures needed to add the protocol subtree and manage it */
588     int offset = 5;             /* bypass opcode+rsvd field */
589     proto_tree *logo_tree;
590
591     if (tree) {
592         logo_tree = proto_item_add_subtree (ti, ett_fcels_logo);
593
594         proto_tree_add_item (logo_tree, hf_fcels_opcode, tvb, offset-5, 1, FALSE);
595
596         if (!isreq) {
597             /* Accept has no payload */
598             return;
599         }
600         
601         proto_tree_add_string (logo_tree, hf_fcels_nportid, tvb, offset, 3,
602                                fc_to_str (tvb_get_ptr (tvb, offset, 3)));
603         proto_tree_add_string (logo_tree, hf_fcels_npname, tvb, offset+3, 6,
604                                fcwwn_to_str (tvb_get_ptr (tvb, offset+3, 6)));
605     }
606 }
607
608 static void
609 dissect_fcels_abtx (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
610                     guint8 isreq, proto_item *ti)
611 {
612     /* Set up structures needed to add the protocol subtree and manage it */
613     int offset = 0;
614     proto_tree *abtx_tree;
615
616     if (tree) {
617         abtx_tree = proto_item_add_subtree (ti, ett_fcels_abtx);
618
619         proto_tree_add_item (abtx_tree, hf_fcels_opcode, tvb, offset, 1, FALSE);
620
621         if (!isreq) {
622             return;
623         }
624
625         proto_tree_add_text (abtx_tree, tvb, offset+4, 1,
626                              "Recovery Qualifier Status: 0x%x",
627                              tvb_get_guint8 (tvb, offset+4));
628         proto_tree_add_string (abtx_tree, hf_fcels_nportid, tvb, offset+5, 3,
629                                fc_to_str (tvb_get_ptr (tvb, offset+5, 3)));
630         proto_tree_add_item (abtx_tree, hf_fcels_oxid, tvb, offset+8, 2, FALSE);
631         proto_tree_add_item (abtx_tree, hf_fcels_rxid, tvb, offset+10, 2, FALSE);
632     }
633 }
634
635 static void
636 dissect_fcels_rsi (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
637                    guint8 isreq, proto_item *ti)
638 {
639     /* Set up structures needed to add the protocol subtree and manage it */
640     int offset = 4;
641     proto_tree *rsi_tree;
642
643     if (tree) {
644         rsi_tree = proto_item_add_subtree (ti, ett_fcels_rsi);
645
646         proto_tree_add_item (rsi_tree, hf_fcels_opcode, tvb, offset-4, 1, FALSE);
647         if (!isreq)
648             return;
649
650         proto_tree_add_item (rsi_tree, hf_fcels_recovqual, tvb, offset, 1, FALSE);
651         proto_tree_add_string (rsi_tree, hf_fcels_nportid, tvb, offset+1, 3,
652                                fc_to_str (tvb_get_ptr (tvb, offset+1, 3)));
653         proto_tree_add_item (rsi_tree, hf_fcels_rxid, tvb, offset+4, 2, FALSE);
654         proto_tree_add_item (rsi_tree, hf_fcels_oxid, tvb, offset+6, 2, FALSE);
655     }
656 }
657
658 static void
659 dissect_fcels_rrq (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
660                    guint8 isreq, proto_item *ti)
661 {
662     /* Set up structures needed to add the protocol subtree and manage it */
663     int offset = 0;
664     proto_tree *rrq_tree;
665
666     if (tree) {
667         rrq_tree = proto_item_add_subtree (ti, ett_fcels_rrq);
668
669         proto_tree_add_item (rrq_tree, hf_fcels_opcode, tvb, offset, 1, FALSE);
670         if (!isreq)
671             return;
672
673         proto_tree_add_string (rrq_tree, hf_fcels_nportid, tvb, offset+5, 3,
674                                fc_to_str (tvb_get_ptr (tvb, offset+5, 3)));
675         proto_tree_add_item (rrq_tree, hf_fcels_oxid, tvb, offset+8, 2, FALSE);
676         proto_tree_add_item (rrq_tree, hf_fcels_rxid, tvb, offset+10, 2, FALSE);
677     }
678 }
679
680 static void
681 dissect_fcels_pdisc (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
682                      guint8 isreq _U_, proto_item *ti)
683 {
684     dissect_fcels_logi (tvb, pinfo, tree, ti, FC_ELS_PDISC);
685 }
686
687 static void
688 dissect_fcels_fdisc (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
689                      guint8 isreq _U_, proto_item *ti)
690 {
691     dissect_fcels_logi (tvb, pinfo, tree, ti, FC_ELS_FDISC);
692 }
693
694 static void
695 dissect_fcels_adisc (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
696                      guint8 isreq _U_, proto_item *ti)
697 {
698     /* Set up structures needed to add the protocol subtree and manage it */
699     int offset = 5;
700     proto_tree *adisc_tree;
701
702     if (tree) {
703         adisc_tree = proto_item_add_subtree (ti, ett_fcels_adisc);
704
705         proto_tree_add_item (adisc_tree, hf_fcels_opcode, tvb, offset-5, 1, FALSE);
706
707         proto_tree_add_string (adisc_tree, hf_fcels_hardaddr, tvb, offset, 3,
708                                fc_to_str (tvb_get_ptr (tvb, offset, 3)));
709         proto_tree_add_string (adisc_tree, hf_fcels_npname, tvb, offset+3, 8,
710                                fcwwn_to_str (tvb_get_ptr (tvb, offset+3, 8)));
711         proto_tree_add_string (adisc_tree, hf_fcels_fnname, tvb, offset+11, 8,
712                                fcwwn_to_str (tvb_get_ptr (tvb, offset+11, 8)));
713         proto_tree_add_string (adisc_tree, hf_fcels_nportid, tvb, offset+20, 3,
714                                fc_to_str (tvb_get_ptr (tvb, offset+20, 3)));
715     }
716
717 }
718
719 static void
720 dissect_fcels_farp (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
721                     proto_item *ti)
722 {
723     int offset = 4;
724     proto_tree *farp_tree;
725     
726     if (tree) {
727         farp_tree = proto_item_add_subtree (ti, ett_fcels_farp);
728
729         proto_tree_add_item (farp_tree, hf_fcels_opcode, tvb, offset-4, 1, FALSE);
730
731         proto_tree_add_item (farp_tree, hf_fcels_farp_matchcodept,
732                              tvb, offset, 1, FALSE);
733         proto_tree_add_string (farp_tree, hf_fcels_nportid, tvb, offset+1,
734                                3, fc_to_str (tvb_get_ptr (tvb, offset+1, 3)));
735         proto_tree_add_item (farp_tree, hf_fcels_farp_respaction, tvb,
736                              offset+4, 1, FALSE);
737         proto_tree_add_string (farp_tree, hf_fcels_resportid, tvb, offset+5,
738                                3, fc_to_str (tvb_get_ptr (tvb, offset+5, 3)));
739         proto_tree_add_string (farp_tree, hf_fcels_npname, tvb, offset+8,
740                                8, fcwwn_to_str (tvb_get_ptr (tvb, offset+8, 8)));
741         proto_tree_add_string (farp_tree, hf_fcels_fnname, tvb, offset+16,
742                                8, fcwwn_to_str (tvb_get_ptr (tvb, offset+16, 8)));
743         proto_tree_add_string (farp_tree, hf_fcels_respname, tvb, offset+24,
744                                8, fcwwn_to_str (tvb_get_ptr (tvb, offset+24, 8)));
745         proto_tree_add_string (farp_tree, hf_fcels_respnname, tvb, offset+32,
746                                8, fcwwn_to_str (tvb_get_ptr (tvb, offset+32, 8)));
747         proto_tree_add_item (farp_tree, hf_fcels_reqipaddr, tvb, offset+40,
748                              16, FALSE);
749         proto_tree_add_item (farp_tree, hf_fcels_respipaddr, tvb, offset+56,
750                              16, FALSE);
751     }
752 }
753
754 static void
755 dissect_fcels_farp_req (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
756                         guint8 isreq _U_, proto_item *ti)
757 {
758     dissect_fcels_farp (tvb, pinfo, tree, ti);
759 }
760
761 static void
762 dissect_fcels_farp_rply (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
763                          guint8 isreq _U_, proto_item *ti)
764 {
765     dissect_fcels_farp (tvb, pinfo, tree, ti);
766 }
767
768 static void
769 dissect_fcels_rps (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
770                    guint8 isreq, proto_item *ti)
771 {
772     /* Set up structures needed to add the protocol subtree and manage it */
773     int offset = 3;
774     guint8 flag;
775     proto_tree *rps_tree;
776
777     flag = tvb_get_guint8 (tvb, offset);
778
779     if (tree) {
780         rps_tree = proto_item_add_subtree (ti, ett_fcels_rps);
781
782         if (isreq) {
783             proto_tree_add_item (rps_tree, hf_fcels_rps_flag, tvb, offset, 1, FALSE);
784
785             proto_tree_add_item (rps_tree, hf_fcels_opcode, tvb, offset-3, 1, FALSE);
786
787             if (flag & 0x2) {
788                 proto_tree_add_string (rps_tree, hf_fcels_npname, tvb, offset+1,
789                                        8, fcwwn_to_str (tvb_get_ptr (tvb,
790                                                                      offset+1,
791                                                                      8)));
792             }
793             else if (flag & 0x1) {
794                 proto_tree_add_item (rps_tree, hf_fcels_rps_portnum, tvb,
795                                      offset+5, 3, FALSE);
796             }
797         }
798         else {
799             proto_tree_add_item (rps_tree, hf_fcels_rps_flag, tvb, offset, 1, FALSE);
800             proto_tree_add_item (rps_tree, hf_fcels_rps_portstatus, tvb,
801                                  offset+3, 2, FALSE);
802             /* Next 6 fields are from Link Error Status Block (LESB) */
803             proto_tree_add_text (rps_tree, tvb, offset+5, 4,
804                                  "Link Failure Count: %u",
805                                  tvb_get_ntohl (tvb, offset+5));
806             proto_tree_add_text (rps_tree, tvb, offset+9, 4,
807                                  "Loss of Sync Count: %u",
808                                  tvb_get_ntohl (tvb, offset+9));
809             proto_tree_add_text (rps_tree, tvb, offset+13, 4,
810                                  "Loss of Signal Count: %u",
811                                  tvb_get_ntohl (tvb, offset+13));
812             proto_tree_add_text (rps_tree, tvb, offset+17, 4,
813                                  "Primitive Seq Protocol Err: %u",
814                                  tvb_get_ntohl (tvb, offset+17));
815             proto_tree_add_text (rps_tree, tvb, offset+21, 4,
816                                  "Invalid Xmission Word: %u",
817                                  tvb_get_ntohl (tvb, offset+21));
818             proto_tree_add_text (rps_tree, tvb, offset+25, 4,
819                                  "Invalid CRC Count: %u",
820                                  tvb_get_ntohl (tvb, offset+25));
821             if (flag & 0x01) {
822                 /* Next 6 fields are from L_Port Extension field */
823                 proto_tree_add_text (rps_tree, tvb, offset+31, 2,
824                                      "L_Port Status: 0x%x",
825                                      tvb_get_ntohs (tvb, offset+31));
826                 proto_tree_add_text (rps_tree, tvb, offset+36, 1,
827                                      "LIP AL_PS: 0x%x",
828                                      tvb_get_guint8 (tvb, offset+36));
829                 proto_tree_add_text (rps_tree, tvb, offset+37, 4,
830                                      "LIP F7 Initiated Count: %u",
831                                      tvb_get_ntohl (tvb, offset+37));
832                 proto_tree_add_text (rps_tree, tvb, offset+41, 4,
833                                      "LIP F7 Received Count: %u",
834                                      tvb_get_ntohl (tvb, offset+41));
835                 proto_tree_add_text (rps_tree, tvb, offset+45, 4,
836                                      "LIP F8 Initiated Count: %u",
837                                      tvb_get_ntohl (tvb, offset+45));
838                 proto_tree_add_text (rps_tree, tvb, offset+49, 4,
839                                      "LIP F8 Received Count: %u",
840                                      tvb_get_ntohl (tvb, offset+49));
841                 proto_tree_add_text (rps_tree, tvb, offset+53, 4,
842                                      "LIP Reset Initiated Count: %u",
843                                      tvb_get_ntohl (tvb, offset+53));
844                 proto_tree_add_text (rps_tree, tvb, offset+57, 4,
845                                      "LIP Reset Received Count: %u",
846                                      tvb_get_ntohl (tvb, offset+57));
847             }
848         }
849     }
850 }
851
852 static void
853 dissect_fcels_rpl (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
854                    guint8 isreq, proto_item *ti)
855 {
856     /* Set up structures needed to add the protocol subtree and manage it */
857     int offset = 0;
858     proto_tree *rpl_tree, *pb_tree;
859     proto_item *subti;
860     int loop;
861
862     if (tree) {
863         rpl_tree = proto_item_add_subtree (ti, ett_fcels_rpl);
864
865         proto_tree_add_item (rpl_tree, hf_fcels_opcode, tvb, offset, 1, FALSE);
866
867         if (isreq) {
868             proto_tree_add_text (rpl_tree, tvb, offset+6, 2,
869                                  "Max Size: %u",
870                                  tvb_get_ntohs (tvb, offset+6));
871             proto_tree_add_text (rpl_tree, tvb, offset+9, 3,
872                                  "Index: %u",
873                                  tvb_get_ntoh24 (tvb, offset+9));
874         }
875         else {
876             /* Reply consists of a header and a number of port blocks */
877             proto_tree_add_text (rpl_tree, tvb, offset+2, 2, 
878                                  "Payload Length: %u",
879                                  tvb_get_ntohs (tvb, offset+2));
880             proto_tree_add_text (rpl_tree, tvb, offset+5, 3, 
881                                  "List Length: %u",
882                                  tvb_get_ntoh24 (tvb, offset+5));
883             proto_tree_add_text (rpl_tree, tvb, offset+9, 3,
884                                  "Index of I Port Block: %u",
885                                  tvb_get_ntoh24 (tvb, offset+9));
886             offset = 12;
887             /* The following loop is for dissecting the port blocks */
888             for (loop = tvb_get_ntoh24 (tvb, 5); loop > 0; loop--) {
889                 subti = proto_tree_add_text (rpl_tree, tvb, offset+12, 16,
890                                              "Port Block %u", loop);
891                 pb_tree = proto_item_add_subtree (subti, ett_fcels_rplpb);
892
893                 proto_tree_add_text (pb_tree, tvb, offset, 4,
894                                      "Physical Port #: %u",
895                                      tvb_get_ntohl (tvb, offset));
896                 proto_tree_add_text (pb_tree, tvb, offset+5, 3,
897                                      "Port Identifier: %s",
898                                      fc_to_str (tvb_get_ptr (tvb, offset+5, 3)));
899                 proto_tree_add_text (pb_tree, tvb, offset+8, 8,
900                                      "Port Name: %s",
901                                      fcwwn_to_str (tvb_get_ptr (tvb, offset+8, 8)));
902                 offset += 16;
903             }
904         }
905     }
906 }
907
908 static void
909 dissect_fcels_fan (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
910                    guint8 isreq _U_, proto_item *ti)
911 {
912     /* Set up structures needed to add the protocol subtree and manage it */
913     int offset = 5;
914     proto_tree *fan_tree;
915
916     if (tree) {
917         fan_tree = proto_item_add_subtree (ti, ett_fcels_fan);
918
919         proto_tree_add_item (fan_tree, hf_fcels_opcode, tvb, offset-5, 1, FALSE);
920
921         proto_tree_add_string (fan_tree, hf_fcels_fabricaddr, tvb, offset, 3,
922                                fc_to_str (tvb_get_ptr (tvb, offset, 3)));
923         proto_tree_add_string (fan_tree, hf_fcels_fabricpname, tvb, offset+3,
924                                8, fcwwn_to_str (tvb_get_ptr (tvb, offset, 8)));
925         proto_tree_add_string (fan_tree, hf_fcels_fnname, tvb, offset+11, 8,
926                                fcwwn_to_str (tvb_get_ptr (tvb, offset+11, 8)));
927     }
928 }
929
930 static void
931 dissect_fcels_rscn (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
932                     guint8 isreq, proto_item *ti)
933 {
934     /* Set up structures needed to add the protocol subtree and manage it */
935     int offset = 1;
936     proto_tree *rscn_tree, *rectree;
937     proto_item *subti;
938     int numrec, plen, i;
939
940     if (tree) {
941         rscn_tree = proto_item_add_subtree (ti, ett_fcels_rscn);
942
943         proto_tree_add_item (rscn_tree, hf_fcels_opcode, tvb, offset-1, 1, FALSE);
944         if (!isreq)
945             return;
946
947         proto_tree_add_text (rscn_tree, tvb, offset, 1,
948                              "Page Len: %u", tvb_get_guint8 (tvb, offset));
949         plen = tvb_get_ntohs (tvb, offset+1);
950         proto_tree_add_text (rscn_tree, tvb, offset+1, 2,
951                              "Payload Len: %u", plen);
952         numrec = (plen - 4)/4;
953         
954         offset = 4;
955         for (i = 0; i < numrec; i++) {
956             subti = proto_tree_add_text (rscn_tree, tvb, offset, 4,
957                                          "Affected N_Port Page %u", i);
958             rectree = proto_item_add_subtree (subti, ett_fcels_rscn_rec);
959
960             proto_tree_add_item (rectree, hf_fcels_rscn_evqual, tvb, offset,
961                                  1, FALSE);
962             proto_tree_add_item (rectree, hf_fcels_rscn_addrfmt, tvb, offset,
963                                  1, FALSE);
964             proto_tree_add_item (rectree, hf_fcels_rscn_domain, tvb, offset+1,
965                                  1, FALSE);
966             proto_tree_add_item (rectree, hf_fcels_rscn_area, tvb, offset+2,
967                                  1, FALSE);
968             proto_tree_add_item (rectree, hf_fcels_rscn_port, tvb, offset+3,
969                                  1, FALSE);
970             offset += 4;
971         }
972     }
973 }
974
975 static void
976 dissect_fcels_scr (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
977                    guint8 isreq, proto_item *ti)
978 {
979     /* Set up structures needed to add the protocol subtree and manage it */
980     int offset = 7;
981     proto_tree *scr_tree;
982
983     if (tree) {
984         scr_tree = proto_item_add_subtree (ti, ett_fcels_scr);
985         proto_tree_add_item (scr_tree, hf_fcels_opcode, tvb, offset-7, 1, FALSE);
986         if (isreq)
987             proto_tree_add_item (scr_tree, hf_fcels_scrregn, tvb, offset, 1, FALSE);
988     }
989 }
990
991 static void
992 dissect_fcels_rnft (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
993                     guint8 isreq, proto_item *ti)
994 {
995     int offset = 0;
996     guint16 numrec, i;
997     proto_tree *rnft_tree, *fc4_tree;
998     proto_item *subti;
999
1000     if (tree) {
1001         rnft_tree = proto_item_add_subtree (ti, ett_fcels_rnft);
1002
1003         proto_tree_add_item (rnft_tree, hf_fcels_opcode, tvb, offset, 1, FALSE);
1004
1005         if (isreq) {
1006             proto_tree_add_text (rnft_tree, tvb, offset+2, 2,
1007                                  "Max Size: %u", tvb_get_ntohs (tvb, offset+2));
1008             proto_tree_add_text (rnft_tree, tvb, offset+7, 1,
1009                                  "Index: %u", tvb_get_guint8 (tvb, offset+7));
1010         }
1011         else {
1012             proto_tree_add_text (rnft_tree, tvb, offset+2, 2,
1013                                  "Payload Len: %u",
1014                                  tvb_get_ntohs (tvb, offset+2));
1015             numrec = tvb_get_guint8 (tvb, offset+5);
1016             proto_tree_add_text (rnft_tree, tvb, offset+5, 1,
1017                                  "List Length: %u", numrec);
1018             proto_tree_add_text (rnft_tree, tvb, offset+7, 1,
1019                                  "Index of First Rec in List: %u",
1020                                  tvb_get_guint8 (tvb, offset+7));
1021             offset = 8;
1022             for (i = 0; i < numrec; i++) {
1023                 subti = proto_tree_add_text (rnft_tree, tvb, offset, 4,
1024                                              "FC-4 Entry #%u", i);
1025                 fc4_tree = proto_item_add_subtree (subti, ett_fcels_rnft_fc4);
1026
1027                 proto_tree_add_item (fc4_tree, hf_fcels_rnft_fc4type, tvb,
1028                                      offset, 1, FALSE);
1029                 proto_tree_add_text (fc4_tree, tvb, offset+1, 3,
1030                                      "FC-4 Qualifier 0x%x",
1031                                      tvb_get_ntoh24 (tvb, offset+1));
1032                 offset += 4;
1033             }
1034         }
1035     }
1036 }
1037
1038 static void
1039 dissect_fcels_lsts (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
1040                     guint8 isreq, proto_item *ti)
1041 {
1042     /* Set up structures needed to add the protocol subtree and manage it */
1043     int offset = 5;
1044     proto_tree *lsts_tree;
1045
1046     if (tree) {
1047         lsts_tree = proto_item_add_subtree (ti, ett_fcels_lsts);
1048
1049         proto_tree_add_item (lsts_tree, hf_fcels_opcode, tvb, offset-5, 1, FALSE);
1050         if (isreq) {
1051             /* In case of LSTS, the reply has the meat */
1052             return;
1053         }
1054         proto_tree_add_item (lsts_tree, hf_fcels_failedrcvr, tvb, offset, 1, FALSE);
1055         proto_tree_add_item (lsts_tree, hf_fcels_flacompliance, tvb, offset+1,
1056                              1, FALSE);
1057         proto_tree_add_item (lsts_tree, hf_fcels_loopstate, tvb, offset+2, 1, FALSE);
1058         proto_tree_add_item (lsts_tree, hf_fcels_publicloop_bmap, tvb, offset+3,
1059                              16, FALSE);
1060         proto_tree_add_item (lsts_tree, hf_fcels_pvtloop_bmap, tvb, offset+19,
1061                              16, FALSE);
1062         proto_tree_add_item (lsts_tree, hf_fcels_alpa_map, tvb, offset+35,
1063                              128, FALSE);
1064     }
1065 }
1066
1067 static void
1068 dissect_fcels_prlilo_payload (tvbuff_t *tvb, packet_info *pinfo _U_,
1069                               guint8 isreq, proto_item *ti, guint8 opcode)
1070 {
1071     int offset = 0,
1072         stroff = 0;
1073     guint8 type;
1074     proto_tree *prli_tree, *svcpg_tree;
1075     int num_svcpg, payload_len, i, flag;
1076     proto_item *subti;
1077     gchar flagstr[100];
1078
1079     /* We're assuming that we're invoked only if tree is not NULL i.e.
1080      * we don't do the usual "if (tree)" check here, the caller must.
1081      */
1082     prli_tree = proto_item_add_subtree (ti, ett_fcels_prli);
1083
1084     proto_tree_add_item (prli_tree, hf_fcels_opcode, tvb, offset, 1, FALSE);
1085
1086     proto_tree_add_text (prli_tree, tvb, offset+1, 1,
1087                          "Page Length: %u",
1088                          tvb_get_guint8 (tvb, offset+1));
1089     payload_len = tvb_get_ntohs (tvb, offset+2);
1090     proto_tree_add_text (prli_tree, tvb, offset+2, 2,
1091                          "Payload Length: %u", payload_len);
1092     num_svcpg = payload_len/16;
1093
1094     offset = 4;
1095     for (i = 0; i < num_svcpg; i++) {
1096         subti = proto_tree_add_text (prli_tree, tvb, offset, 16,
1097                                      "Service Parameter Page %u", i);
1098         svcpg_tree = proto_item_add_subtree (subti, ett_fcels_prli_svcpg);
1099
1100         type = tvb_get_guint8 (tvb, offset);
1101         proto_tree_add_text (svcpg_tree, tvb, offset, 1,
1102                              "TYPE: %s",
1103                              val_to_str (type,
1104                                          fc_prli_fc4_val, "0x%x"));
1105         proto_tree_add_text (svcpg_tree, tvb, offset+1, 1,
1106                              "TYPE Code Extension: %u",
1107                              tvb_get_guint8 (tvb, offset+1));
1108
1109         flag = tvb_get_guint8 (tvb, offset+2);
1110         flagstr[0] = '\0';
1111         stroff = 0;
1112         if (opcode != FC_ELS_TPRLO) {
1113             if (flag & 0x80) {
1114                 strcpy (flagstr, "Orig PA Valid, ");
1115                 stroff += 15;
1116             }
1117             if (flag & 0x40) {
1118                 strcpy (&flagstr[stroff], "Resp PA Valid, ");
1119                 stroff += 15;
1120             }
1121
1122             if (opcode == FC_ELS_PRLI) {
1123                 if (!isreq) {
1124                     if (flag & 0x20) {
1125                         strcpy (&flagstr[stroff], "Image Pair Estd., ");
1126                         stroff += 18;
1127                     }
1128                     else {
1129                         strcpy (&flagstr[stroff], "Image Pair Not Estd., ");
1130                         stroff += 22;
1131                     }
1132                 }
1133                 else {
1134                     if (flag & 0x20) {
1135                         strcpy (&flagstr[stroff], "Est Image Pair & Exchg Svc Param, ");
1136                         stroff += 34;
1137                     }
1138                     else {
1139                         strcpy (&flagstr[stroff], "Exchange Svc Param Only, ");
1140                         stroff += 25;
1141                     }
1142                 }
1143             }
1144         }
1145         else { /* Assuming opcode is TPRLO */
1146             if (flag & 0x80) {
1147                 strcpy (flagstr, "3rd Party Orig PA Valid, ");
1148                 stroff += 25;
1149             }
1150             if (flag & 0x40) {
1151                 strcpy (&flagstr[stroff], "Resp PA Valid, ");
1152                 stroff += 15;
1153             }
1154             if (flag & 0x20) {
1155                 strcpy (&flagstr[stroff], "3rd Party N_Port Valid, ");
1156                 stroff += 24;
1157             }
1158             if (flag & 0x10) {
1159                 strcpy (&flagstr[stroff], "Global PRLO, ");
1160                 stroff += 13;
1161             }
1162         }
1163
1164         proto_tree_add_text (svcpg_tree, tvb, offset+2, 1,
1165                              "Flags: %s", flagstr);
1166         if (!isreq && (opcode != FC_ELS_TPRLO)) {
1167             /* This is valid only for ACC */
1168             proto_tree_add_text (svcpg_tree, tvb, offset+2, 1,
1169                                  "Response Code: 0x%x",
1170                                  (tvb_get_guint8 (tvb, offset+2) & 0x0F));
1171         }
1172         if (opcode != FC_ELS_TPRLO) {
1173             proto_tree_add_text (svcpg_tree, tvb, offset+4, 4,
1174                                  "Originator PA: 0x%x",
1175                                  tvb_get_ntohl (tvb, offset+4));
1176         }
1177         else {
1178             proto_tree_add_text (svcpg_tree, tvb, offset+4, 4,
1179                                  "3rd Party Originator PA: 0x%x",
1180                                  tvb_get_ntohl (tvb, offset+4));
1181         }
1182         proto_tree_add_text (svcpg_tree, tvb, offset+8, 4,
1183                              "Responder PA: 0x%x",
1184                              tvb_get_ntohl (tvb, offset+8));
1185
1186         if (type == FC_TYPE_SCSI) {
1187             flag = tvb_get_ntohs (tvb, offset+14);
1188             flagstr[0] = '\0';
1189             stroff = 0;
1190             
1191             if (flag & 0x2000) {
1192                 if (isreq) {
1193                     strcpy (flagstr, "Task Retry Ident Req, ");
1194                     stroff += 22;
1195                 }
1196                 else {
1197                     strcpy (flagstr, "Task Retry Ident Acc, ");
1198                     stroff += 22;
1199                 }
1200             }
1201             if (flag & 0x1000) {
1202                 strcpy (&flagstr[stroff], "Retry Possible, ");
1203                 stroff += 16;
1204             }
1205             if (flag & 0x0080) {
1206                 strcpy (&flagstr[stroff], "Confirmed Comp, ");
1207                 stroff += 16;
1208             }
1209             if (flag & 0x0040) {
1210                 strcpy (&flagstr[stroff], "Data Overlay, ");
1211                 stroff += 14;
1212             }
1213             if (flag & 0x0020) {
1214                 strcpy (&flagstr[stroff], "Initiator, ");
1215                 stroff += 11;
1216             }
1217             if (flag & 0x0010) {
1218                 strcpy (&flagstr[stroff], "Target, ");
1219                 stroff += 8;
1220             }
1221             if (flag & 0x0002) {
1222                 strcpy (&flagstr[stroff], "Rd Xfer_Rdy Dis, ");
1223                 stroff += 17;
1224             }
1225             if (flag & 0x0001) {
1226                 strcpy (&flagstr[stroff], "Wr Xfer_Rdy Dis");
1227                 stroff += 15;
1228             }
1229             proto_tree_add_text (svcpg_tree, tvb, offset+12, 4,
1230                                  "FCP Flags: 0x%x (%s)", flag,
1231                                  flagstr);
1232         }
1233         else if ((opcode == FC_ELS_PRLI) && !isreq) {
1234             proto_tree_add_text (svcpg_tree, tvb, offset+12, 4,
1235                                  "Service Parameter Response: 0x%x",
1236                                  tvb_get_ntohl (tvb, offset+12));
1237         }
1238         else if (opcode == FC_ELS_TPRLO) {
1239             proto_tree_add_text (svcpg_tree, tvb, offset+13, 3,
1240                                  "3rd Party N_Port Id: %s",
1241                                  fc_to_str (tvb_get_ptr (tvb, offset+13, 3)));
1242         }
1243     }
1244 }
1245
1246 static void
1247 dissect_fcels_prli (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1248                     guint8 isreq, proto_item *ti)
1249 {
1250     if (tree) {
1251         dissect_fcels_prlilo_payload (tvb, pinfo, isreq, ti, FC_ELS_PRLI);
1252     }
1253 }
1254
1255 static void
1256 dissect_fcels_prlo (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1257                     guint8 isreq, proto_item *ti)
1258 {
1259     /* Set up structures needed to add the protocol subtree and manage it */
1260     if (tree) {
1261         dissect_fcels_prlilo_payload (tvb, pinfo, isreq, ti, FC_ELS_PRLO);
1262     }
1263 }
1264
1265 static void
1266 dissect_fcels_tprlo (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1267                      guint8 isreq, proto_item *ti)
1268 {
1269     /* Set up structures needed to add the protocol subtree and manage it */
1270
1271     if (tree) {
1272         dissect_fcels_prlilo_payload (tvb, pinfo, isreq, ti, FC_ELS_TPRLO);
1273     }
1274 }
1275
1276 static void
1277 dissect_fcels_lirr (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
1278                     guint8 isreq _U_, proto_item *ti)
1279 {
1280     /* Set up structures needed to add the protocol subtree and manage it */
1281     int offset = 4;
1282     proto_tree *lirr_tree;
1283     guint8 lirr_fmt;
1284
1285     if (tree) {
1286         lirr_tree = proto_item_add_subtree (ti, ett_fcels_lirr);
1287
1288         proto_tree_add_item (lirr_tree, hf_fcels_opcode, tvb, offset-4, 1, FALSE);
1289
1290         proto_tree_add_text (lirr_tree, tvb, offset, 1,
1291                              "Regn. Function: %s",
1292                              val_to_str (tvb_get_guint8 (tvb, offset),
1293                                          fc_els_lirr_regfunc_val,
1294                                          "Reserved (0x%x)"));
1295         lirr_fmt = tvb_get_guint8 (tvb, offset+1);
1296         if (!lirr_fmt) {
1297             /* This scheme is resorted to because the value 0 has a string in
1298              * the value_string that is not what we want displayed here.
1299              */
1300             proto_tree_add_text (lirr_tree, tvb, offset, 1,
1301                                  "Regn. Format: Common Format");
1302         }
1303         else {
1304             proto_tree_add_text (lirr_tree, tvb, offset, 1,
1305                                  "Regn. Format: %s",
1306                                  val_to_str (lirr_fmt, fc_fc4_val, "0x%x"));
1307         }
1308     }
1309 }
1310
1311 static void
1312 dissect_fcels_srl (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
1313                    guint8 isreq, proto_item *ti)
1314 {
1315     /* Set up structures needed to add the protocol subtree and manage it */
1316     int offset = 4,
1317         flag = 0;
1318     proto_tree *srl_tree;
1319
1320     if (tree) {
1321         srl_tree = proto_item_add_subtree (ti, ett_fcels_srl);
1322
1323         proto_tree_add_item (srl_tree, hf_fcels_opcode, tvb, offset-4, 1, FALSE);
1324         if (!isreq)
1325             return;
1326
1327         flag = tvb_get_guint8 (tvb, offset);
1328         if (flag & 0x1) {
1329             proto_tree_add_text (srl_tree, tvb, offset, 1,
1330                                  "Flag: Scan only specified FL Port");
1331         }
1332         else {
1333             proto_tree_add_text (srl_tree, tvb, offset, 1,
1334                                  "Flag: Scan all loops in domain");
1335         }
1336         proto_tree_add_text (srl_tree, tvb, offset+1, 3,
1337                              "FL_Port Addr: %s",
1338                              fc_to_str (tvb_get_ptr (tvb, offset+1, 3)));
1339     }
1340 }
1341
1342 static void
1343 dissect_fcels_rpsc (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
1344                     guint8 isreq, proto_item *ti)
1345 {
1346     /* Set up structures needed to add the protocol subtree and manage it */
1347     int offset = 2;
1348     int num_entries, i, cap;
1349     gchar speed_str[40];
1350     int stroff = 0;
1351     proto_tree *rpsc_tree;
1352
1353     if (tree) {
1354         rpsc_tree = proto_item_add_subtree (ti, ett_fcels_rpsc);
1355
1356         proto_tree_add_item (rpsc_tree, hf_fcels_opcode, tvb, offset-2, 1, FALSE);
1357         if (isreq)
1358             return;
1359
1360         num_entries = tvb_get_ntohs (tvb, offset);
1361         proto_tree_add_text (rpsc_tree, tvb, offset, 2,
1362                              "Number of Entries: %u", num_entries);
1363         offset = 4;
1364         for (i = 0; i < num_entries; i++) {
1365             cap = tvb_get_ntohs (tvb, offset);
1366             speed_str[0] = '\0';
1367             stroff = 0;
1368             if (cap & 0x8000) {
1369                 strcpy (speed_str, "1,");
1370                 stroff += 2;
1371             }
1372             if (cap & 0x4000) {
1373                 strcpy (speed_str, "2,");
1374                 stroff += 2;
1375             }
1376             if (cap & 0x2000) {
1377                 strcpy (speed_str, "4,");
1378                 stroff += 2;
1379             }
1380             if (cap & 0x1000) {
1381                 strcpy (speed_str, "10");
1382                 stroff += 2;
1383             }
1384             strcpy (&speed_str[stroff], "Gb");
1385             proto_tree_add_text (rpsc_tree, tvb, offset, 2,
1386                                  "Port Speed Capabilities (Port %u): %s", i,
1387                                  speed_str);
1388             cap = tvb_get_ntohs (tvb, offset+2);
1389             proto_tree_add_text (rpsc_tree, tvb, offset+2, 2,
1390                                  "Port Oper Speed: %s",
1391                                  val_to_str (cap, fc_els_portspeed_val,
1392                                              "0x%x"));
1393         }
1394     }
1395 }
1396
1397 static void
1398 dissect_fcels_rnid (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
1399                     guint8 isreq, proto_item *ti)
1400 {
1401     /* Set up structures needed to add the protocol subtree and manage it */
1402     int offset = 0;
1403     int clen, slen;
1404     proto_tree *rnid_tree;
1405
1406     if (tree) {
1407         rnid_tree = proto_item_add_subtree (ti, ett_fcels_rnid);
1408
1409         proto_tree_add_item (rnid_tree, hf_fcels_opcode, tvb, offset, 1, FALSE);
1410         if (isreq) {
1411             proto_tree_add_item (rnid_tree, hf_fcels_nodeidfmt, tvb, offset+4,
1412                                  1, FALSE);
1413         }
1414         else {
1415             /* We only decode responses to nodeid fmt DF */
1416             proto_tree_add_item (rnid_tree, hf_fcels_nodeidfmt, tvb, offset+4,
1417                                  1, FALSE);
1418             clen = tvb_get_guint8 (tvb, offset+5);
1419             proto_tree_add_text (rnid_tree, tvb, offset+5, 1,
1420                                  "Common Identification Data Length: %u", clen);
1421             slen = tvb_get_guint8 (tvb, offset+7);
1422             proto_tree_add_item (rnid_tree, hf_fcels_spidlen, tvb, offset+7,
1423                                  1, FALSE);
1424             if (clen) {
1425                 proto_tree_add_string (rnid_tree, hf_fcels_npname, tvb,
1426                                        offset+8, 8,
1427                                        fcwwn_to_str (tvb_get_ptr (tvb, offset+8,
1428                                                                   8)));
1429                 proto_tree_add_string (rnid_tree, hf_fcels_fnname, tvb,
1430                                        offset+16, 8,
1431                                        fcwwn_to_str (tvb_get_ptr (tvb,
1432                                                                   offset+16,
1433                                                                   8)));
1434             }
1435             if (tvb_get_guint8 (tvb, offset+4) == 0xDF) {
1436                 /* Decode the Specific Node ID Format as this is known */
1437                 proto_tree_add_item (rnid_tree, hf_fcels_vendoruniq, tvb,
1438                                      offset+24, 16, FALSE);
1439                 proto_tree_add_item (rnid_tree, hf_fcels_asstype, tvb,
1440                                      offset+40, 4, FALSE);
1441                 proto_tree_add_item (rnid_tree, hf_fcels_physport, tvb,
1442                                      offset+44, 4, FALSE);
1443                 proto_tree_add_item (rnid_tree, hf_fcels_attnodes, tvb,
1444                                      offset+48, 4, FALSE);
1445                 proto_tree_add_item (rnid_tree, hf_fcels_nodemgmt, tvb,
1446                                      offset+52, 1, FALSE);
1447                 proto_tree_add_item (rnid_tree, hf_fcels_ipvers, tvb,
1448                                      offset+53, 1, FALSE);
1449                 proto_tree_add_item (rnid_tree, hf_fcels_tcpport, tvb,
1450                                      offset+54, 2, FALSE);
1451                 proto_tree_add_item (rnid_tree, hf_fcels_ip, tvb, offset+56,
1452                                      16, FALSE);
1453                 proto_tree_add_item (rnid_tree, hf_fcels_vendorsp, tvb,
1454                                      offset+74, 2, FALSE);
1455             }
1456         }
1457     }
1458 }
1459
1460 static void
1461 dissect_fcels_rlir (tvbuff_t *tvb _U_, packet_info *pinfo _U_,
1462                     proto_tree *tree, guint8 isreq _U_,
1463                     proto_item *ti _U_)
1464 {
1465     /* Set up structures needed to add the protocol subtree and manage it */
1466
1467     if (tree) {
1468     }
1469 }
1470
1471 static void
1472 dissect_fcels_lsrjt (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
1473                      guint8 isreq _U_, proto_item *ti)
1474 {
1475     /* Set up structures needed to add the protocol subtree and manage it */
1476     int offset = 5;
1477     proto_tree *lsrjt_tree;
1478
1479     if (tree) {
1480         lsrjt_tree = proto_item_add_subtree (ti, ett_fcels_lsrjt);
1481
1482         proto_tree_add_item (lsrjt_tree, hf_fcels_opcode, tvb, offset-5, 1, FALSE);
1483
1484         proto_tree_add_item (lsrjt_tree, hf_fcels_rjtcode, tvb, offset++, 1, FALSE);
1485         proto_tree_add_item (lsrjt_tree, hf_fcels_rjtdetcode, tvb, offset++, 1, FALSE);
1486         proto_tree_add_item (lsrjt_tree, hf_fcels_vnduniq, tvb, offset, 1, FALSE);
1487     }
1488 }
1489
1490 static void
1491 dissect_fcels (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1492 {
1493
1494 /* Set up structures needed to add the protocol subtree and manage it */
1495     proto_item *ti = NULL;
1496     proto_tree *acc_tree;
1497     guint8 isreq = FC_ELS_REQ;
1498     int offset = 0;
1499     guint8 opcode,
1500            failed_opcode = 0;
1501     conversation_t *conversation;
1502     fcels_conv_data_t *cdata;
1503     fcels_conv_key_t ckey, *req_key;
1504     guint options;
1505     address dstaddr;
1506     guint8 addrdata[3];
1507
1508     /* Make entries in Protocol column and Info column on summary display */
1509     if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
1510         col_set_str(pinfo->cinfo, COL_PROTOCOL, "FC ELS");
1511
1512     /* decoding of this is done by each individual opcode handler */
1513     opcode = tvb_get_guint8 (tvb, 0);
1514     
1515     if (tree) {
1516         ti = proto_tree_add_protocol_format (tree, proto_fcels, tvb, 0,
1517                                              tvb_length (tvb), "FC ELS");
1518     }
1519
1520     /* Register conversation in case this is not a response */
1521     if ((opcode != FC_ELS_LSRJT) && (opcode != FC_ELS_ACC)) {
1522         if (opcode == FC_ELS_FLOGI) {
1523             if (pinfo->src.data[2]) {
1524                 /* If it is a loop port, we'll need to remember the ALPA */
1525                 options = NO_PORT2;
1526             }
1527             else {
1528                 options = NO_PORT2 | NO_ADDR2;
1529             }
1530         }
1531         else {
1532             options = NO_PORT2;
1533         }
1534         conversation = find_conversation (&pinfo->dst, &pinfo->src,
1535                                           pinfo->ptype, pinfo->oxid,
1536                                           pinfo->rxid, options);
1537             
1538         if (!conversation) {
1539             conversation = conversation_new (&pinfo->dst, &pinfo->src,
1540                                              pinfo->ptype, pinfo->oxid,
1541                                              pinfo->rxid, options);
1542         }
1543     
1544         ckey.conv_idx = conversation->index;
1545         
1546         cdata = (fcels_conv_data_t *)g_hash_table_lookup (fcels_req_hash,
1547                                                           &ckey);
1548         if (cdata) {
1549             /* Since we never free the memory used by an exchange, this maybe a
1550              * case of another request using the same exchange as a previous
1551              * req. 
1552              */
1553             cdata->opcode = opcode;
1554         }
1555         else {
1556             req_key = g_mem_chunk_alloc (fcels_req_keys);
1557             req_key->conv_idx = conversation->index;
1558             
1559             cdata = g_mem_chunk_alloc (fcels_req_vals);
1560             cdata->opcode = opcode;
1561             
1562             g_hash_table_insert (fcels_req_hash, req_key, cdata);
1563         }
1564     }
1565     else {
1566         isreq = FC_ELS_RPLY;
1567
1568         options = NO_PORT2;
1569         conversation = find_conversation (&pinfo->dst, &pinfo->src,
1570                                           pinfo->ptype, pinfo->oxid,
1571                                           pinfo->rxid, options);
1572         if (!conversation) {
1573             /* FLOGI has two ways to save state: without the src and using just
1574              * the port (ALPA) part of the address. Try both.
1575              */
1576             addrdata[0] = addrdata[1] = 0;
1577             addrdata[2] = pinfo->dst.data[2];
1578             SET_ADDRESS (&dstaddr, AT_FC, 3, addrdata);
1579             conversation = find_conversation (&dstaddr, &pinfo->src,
1580                                               pinfo->ptype, pinfo->oxid,
1581                                               pinfo->rxid, options);
1582         }
1583
1584         if (!conversation) {
1585             /* Finally check for FLOGI with both NO_PORT2 and NO_ADDR2 set */
1586             options = NO_ADDR2 | NO_PORT2;
1587             conversation = find_conversation (&pinfo->src, &pinfo->dst,
1588                                               pinfo->ptype, pinfo->oxid,
1589                                               pinfo->rxid, options);
1590             if (!conversation) {
1591                 if (tree && (opcode == FC_ELS_ACC)) {
1592                     /* No record of what this accept is for. Can't decode */
1593                     acc_tree = proto_item_add_subtree (ti, ett_fcels_acc);
1594                     proto_tree_add_text (acc_tree, tvb, offset, tvb_length (tvb),
1595                                          "No record of Exchange. Unable to decode ACC");
1596                     return;
1597                 }
1598                 failed_opcode = 0;
1599             }
1600         }
1601         
1602         if (conversation) {
1603             ckey.conv_idx = conversation->index;
1604             
1605             cdata = (fcels_conv_data_t *)g_hash_table_lookup (fcels_req_hash, &ckey);
1606             
1607             if (cdata != NULL) {
1608                 if ((options & NO_ADDR2) && (cdata->opcode != FC_ELS_FLOGI)) {
1609                     /* only FLOGI can have this special check */
1610                     if (tree && (opcode == FC_ELS_ACC)) {
1611                         /* No record of what this accept is for. Can't decode */
1612                         acc_tree = proto_item_add_subtree (ti,
1613                                                            ett_fcels_acc);
1614                         proto_tree_add_text (acc_tree, tvb, offset,
1615                                              tvb_length (tvb),
1616                                              "No record of Exchg. Unable to decode ACC");
1617                         return;
1618                     }
1619                 }
1620                 if (opcode == FC_ELS_ACC)
1621                     opcode = cdata->opcode;
1622                 else
1623                     failed_opcode = cdata->opcode;
1624             }
1625             
1626             if (tree) {
1627                 if ((cdata == NULL) && (opcode != FC_ELS_LSRJT)) {
1628                     /* No record of what this accept is for. Can't decode */
1629                     acc_tree = proto_item_add_subtree (ti, ett_fcels_acc);
1630                     proto_tree_add_text (acc_tree, tvb, offset, tvb_length (tvb),
1631                                          "No record of ELS Req. Unable to decode ACC");
1632                     return;
1633                 }
1634             }
1635         }
1636     }
1637
1638     if (check_col (pinfo->cinfo, COL_INFO)) {
1639         if (isreq == FC_ELS_REQ) {
1640             col_add_str (pinfo->cinfo, COL_INFO,
1641                          val_to_str (opcode, fc_els_proto_val, "0x%x"));
1642         }
1643         else if (opcode == FC_ELS_LSRJT) {
1644             col_add_fstr (pinfo->cinfo, COL_INFO, "LS_RJT (%s)",
1645                           val_to_str (failed_opcode, fc_els_proto_val, "0x%x"));
1646         }
1647         else {
1648             col_add_fstr (pinfo->cinfo, COL_INFO, "ACC (%s)",
1649                           val_to_str (opcode, fc_els_proto_val, "0x%x"));
1650         }
1651     }
1652     
1653     switch (opcode) {
1654     case FC_ELS_LSRJT:
1655         dissect_fcels_lsrjt (tvb, pinfo, tree, isreq, ti);
1656         break;
1657     case FC_ELS_PLOGI:
1658         dissect_fcels_plogi (tvb, pinfo, tree, isreq, ti);
1659         break;
1660     case FC_ELS_FLOGI:
1661         dissect_fcels_flogi (tvb, pinfo, tree, isreq, ti);
1662         break;
1663     case FC_ELS_LOGOUT:
1664         dissect_fcels_logout (tvb, pinfo, tree, isreq, ti);
1665         break;
1666     case FC_ELS_ABTX:
1667         dissect_fcels_abtx (tvb, pinfo, tree, isreq, ti);
1668         break;
1669     case FC_ELS_RSI:
1670         dissect_fcels_rsi (tvb, pinfo, tree, isreq, ti);
1671         break;
1672     case FC_ELS_RRQ:
1673         dissect_fcels_rrq (tvb, pinfo, tree, isreq, ti);
1674         break;
1675     case FC_ELS_PRLI:
1676         dissect_fcels_prli (tvb, pinfo, tree, isreq, ti);
1677         break;
1678     case FC_ELS_PRLO:
1679         dissect_fcels_prlo (tvb, pinfo, tree, isreq, ti);
1680         break;
1681     case FC_ELS_TPRLO:
1682         dissect_fcels_tprlo (tvb, pinfo, tree, isreq, ti);
1683         break;
1684     case FC_ELS_PDISC:
1685         dissect_fcels_pdisc (tvb, pinfo, tree, isreq, ti);
1686         break;
1687     case FC_ELS_FDISC:
1688         dissect_fcels_fdisc (tvb, pinfo, tree, isreq, ti);
1689         break;
1690     case FC_ELS_ADISC:
1691         dissect_fcels_adisc (tvb, pinfo, tree, isreq, ti);
1692         break;
1693     case FC_ELS_FARP_REQ:
1694         dissect_fcels_farp_req (tvb, pinfo, tree, isreq, ti);
1695         break;
1696     case FC_ELS_FARP_RPLY:
1697         dissect_fcels_farp_rply (tvb, pinfo, tree, isreq, ti);
1698         break;
1699     case FC_ELS_RPS:
1700         dissect_fcels_rps (tvb, pinfo, tree, isreq, ti);
1701         break;
1702     case FC_ELS_RPL:
1703         dissect_fcels_rpl (tvb, pinfo, tree, isreq, ti);
1704         break;
1705     case FC_ELS_FAN:
1706         dissect_fcels_fan (tvb, pinfo, tree, isreq, ti);
1707         break;
1708     case FC_ELS_RSCN:
1709         dissect_fcels_rscn (tvb, pinfo, tree, isreq, ti);
1710         break;
1711     case FC_ELS_SCR:
1712         dissect_fcels_scr (tvb, pinfo, tree, isreq, ti);
1713         break;
1714     case FC_ELS_RNFT:
1715         dissect_fcels_rnft (tvb, pinfo, tree, isreq, ti);
1716         break;
1717     case FC_ELS_LSTS:
1718         dissect_fcels_lsts (tvb, pinfo, tree, isreq, ti);
1719         break;
1720     case FC_ELS_RNID:
1721         dissect_fcels_rnid (tvb, pinfo, tree, isreq, ti);
1722         break;
1723     case FC_ELS_RLIR:
1724         dissect_fcels_rlir (tvb, pinfo, tree, isreq, ti);
1725         break;
1726     case FC_ELS_LIRR:
1727         dissect_fcels_lirr (tvb, pinfo, tree, isreq, ti);
1728         break;
1729     case FC_ELS_SRL:
1730         dissect_fcels_srl (tvb, pinfo, tree, isreq, ti);
1731         break;
1732     case FC_ELS_RPSC:
1733         dissect_fcels_rpsc (tvb, pinfo, tree, isreq, ti);
1734         break;
1735     case FC_ELS_AUTH:
1736         if (isreq && fcsp_handle)
1737             call_dissector (fcsp_handle, tvb, pinfo, tree);
1738         break;
1739     default:
1740         /* proto_tree_add_text ( */
1741         call_dissector (data_handle, tvb, pinfo, tree);
1742         break;
1743     }
1744 }
1745
1746 void
1747 proto_register_fcels (void)
1748 {                 
1749
1750 /* Setup list of header fields  See Section 1.6.1 for details*/
1751     static hf_register_info hf[] = {
1752         { &hf_fcels_opcode,
1753           {"Cmd Code", "fcels.opcode", FT_UINT8, BASE_HEX,
1754            VALS (fc_els_proto_val), 0x0, "", HFILL}},
1755         { &hf_fcels_rjtcode,
1756           {"Reason Code", "fcels.rjt.reason", FT_UINT8, BASE_HEX,
1757            VALS (fc_els_rjt_val), 0x0, "", HFILL}},
1758         { &hf_fcels_rjtdetcode,
1759           {"Reason Explanation", "fcels.rjt.detail", FT_UINT8, BASE_HEX,
1760            VALS (fc_els_rjt_det_val), 0x0, "", HFILL}},
1761         { &hf_fcels_vnduniq,
1762           {"Vendor Unique", "fcels.rjt.vnduniq", FT_UINT8, BASE_HEX, NULL,
1763            0x0, "", HFILL}},
1764         { &hf_fcels_b2b,
1765           {"B2B Credit", "fcels.logi.b2b", FT_UINT8, BASE_DEC, NULL, 0x0, "",
1766            HFILL}},
1767         { &hf_fcels_cmnfeatures,
1768           {"Common Features", "fcels.logi.cmnfeatures", FT_UINT16, BASE_HEX, NULL,
1769            0x0, "", HFILL}},
1770         { &hf_fcels_bbscnum,
1771           {"BB_SC Number", "fcels.logi.bbscnum", FT_UINT8, BASE_DEC, NULL, 0xF0, "",
1772            HFILL}},
1773         { &hf_fcels_rcvsize,
1774           {"Receive Size", "fcels.logi.rcvsize", FT_UINT16, BASE_DEC, NULL, 0x0FFF, "",
1775            HFILL}},
1776         { &hf_fcels_maxconseq,
1777           {"Max Concurrent Seq", "fcels.logi.maxconseq", FT_UINT16, BASE_DEC, NULL,
1778            0x0, "", HFILL}},
1779         { &hf_fcels_reloffset,
1780           {"Relative Offset By Info Cat", "fcels.logi.reloff", FT_UINT16, BASE_DEC,
1781            NULL, 0x0, "", HFILL}},
1782         { &hf_fcels_edtov,
1783           {"E_D_TOV", "fcels.edtov", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL}},
1784         { &hf_fcels_npname,
1785           {"N_Port Port_Name", "fcels.npname", FT_STRING, BASE_HEX, NULL, 0x0,
1786            "", HFILL}},
1787         { &hf_fcels_fnname,
1788           {"Fabric/Node Name", "fcels.fnname", FT_STRING, BASE_HEX, NULL, 0x0,
1789            "", HFILL}},
1790         { &hf_fcels_cls1param,
1791           {"Class 1 Svc Param", "fcels.logi.cls1param", FT_BYTES, BASE_HEX, NULL, 0x0,
1792            "", HFILL}},
1793         { &hf_fcels_cls2param,
1794           {"Class 2 Svc Param", "fcels.logi.cls2param", FT_BYTES, BASE_HEX, NULL, 0x0,
1795            "", HFILL}},
1796         { &hf_fcels_cls3param,
1797           {"Class 3 Svc Param", "fcels.logi.cls3param", FT_BYTES, BASE_HEX, NULL, 0x0,
1798            "", HFILL}},
1799         { &hf_fcels_cls4param,
1800           {"Class 4 Svc Param", "fcels.logi.cls4param", FT_BYTES, BASE_HEX, NULL, 0x0,
1801            "", HFILL}},
1802         { &hf_fcels_vendorvers,
1803           {"Vendor Version", "fcels.logi.vendvers", FT_BYTES, BASE_HEX, NULL, 0x0, "",
1804            HFILL}},
1805         { &hf_fcels_svcavail,
1806           {"Services Availability", "fcels.logi.svcavail", FT_BYTES, BASE_HEX, NULL,
1807            0x0, "", HFILL}},
1808         { &hf_fcels_clsflags,
1809           {"Class Flags", "fcels.logi.clsflags", FT_UINT16, BASE_HEX, NULL, 0x0, "",
1810            HFILL}},
1811         { &hf_fcels_initctl,
1812           {"Initiator Ctl", "fcels.logi.initctl", FT_UINT16, BASE_HEX, NULL, 0x0, "",
1813            HFILL}},
1814         { &hf_fcels_rcptctl,
1815           {"Recipient Ctl", "fcels.logi.rcptctl", FT_UINT16, BASE_HEX, NULL, 0x0, "",
1816            HFILL}},
1817         { &hf_fcels_clsrcvsize,
1818           {"Class Recv Size", "fcels.logi.clsrcvsize", FT_UINT16, BASE_DEC, NULL,
1819            0x0, "", HFILL}},
1820         { &hf_fcels_conseq,
1821           {"Total Concurrent Seq", "fcels.logi.totconseq", FT_UINT8, BASE_DEC, NULL,
1822            0x0, "", HFILL}},
1823         { &hf_fcels_e2e,
1824           {"End2End Credit", "fcels.logi.e2e", FT_UINT16, BASE_DEC, NULL, 0x0, "",
1825            HFILL}},
1826         { &hf_fcels_openseq,
1827           {"Open Seq Per Exchg", "fcels.logi.openseq", FT_UINT8, BASE_DEC, NULL, 0x0,
1828            "", HFILL}},
1829         { &hf_fcels_nportid,
1830           {"Originator S_ID", "fcels.portid", FT_STRING, BASE_HEX, NULL, 0x0,
1831            "", HFILL}},
1832         { &hf_fcels_oxid,
1833           {"OXID", "fcels.oxid", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL}},
1834         { &hf_fcels_rxid,
1835           {"RXID", "fcels.rxid", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL}},
1836         { &hf_fcels_recovqual,
1837           {"Recovery Qualifier", "fcels.rcovqual", FT_UINT8, BASE_HEX, NULL,
1838            0x0, "", HFILL}},
1839         { &hf_fcels_fabricaddr,
1840           {"Fabric Address", "fcels.faddr", FT_STRING, BASE_HEX, NULL, 0x0, "",
1841            HFILL}},
1842         { &hf_fcels_fabricpname,
1843           {"Fabric Port Name", "fcels.fpname", FT_STRING, BASE_HEX, NULL, 0x0,
1844            "", HFILL}},
1845         { &hf_fcels_failedrcvr,
1846           {"Failed Receiver AL_PA", "fcels.faildrcvr", FT_UINT8, BASE_HEX, NULL,
1847            0x0, "", HFILL}},
1848         { &hf_fcels_flacompliance,
1849           {"FC-FLA Compliance", "fcels.flacompliance", FT_UINT8, BASE_HEX,
1850            VALS (fc_els_flacompliance_val), 0x0, "", HFILL}},
1851         { &hf_fcels_loopstate,
1852           {"Loop State", "fcels.loopstate", FT_UINT8, BASE_HEX,
1853            VALS (fc_els_loopstate_val), 0x0, "", HFILL}},
1854         { &hf_fcels_publicloop_bmap,
1855           {"Public Loop Device Bitmap", "fcels.pubdev_bmap", FT_BYTES, BASE_HEX,
1856            NULL, 0x0, "", HFILL}},
1857         { &hf_fcels_pvtloop_bmap,
1858           {"Private Loop Device Bitmap", "fcels.pvtdev_bmap", FT_BYTES,
1859            BASE_HEX, NULL, 0x0, "", HFILL}},
1860         { &hf_fcels_alpa_map,
1861           {"AL_PA Map", "fcels.alpa", FT_BYTES, BASE_HEX, NULL, 0x0, "",
1862            HFILL}},
1863         { &hf_fcels_scrregn,
1864           {"Registration Function", "fcels.scr.regn", FT_UINT8, BASE_HEX,
1865            VALS (fc_els_scr_reg_val), 0x0, "", HFILL}},
1866         { &hf_fcels_farp_matchcodept,
1867           {"Match Address Code Points", "fcels.matchcp", FT_UINT8, BASE_DEC,
1868            NULL, 0x0, "", HFILL}},
1869         { &hf_fcels_farp_respaction,
1870           {"Responder Action", "fcels.respaction", FT_UINT8, BASE_HEX, 
1871            VALS (fc_els_farp_respaction_val), 0x0, "", HFILL}},
1872         { &hf_fcels_resportid,
1873           {"Responding Port ID", "fcels.resportid", FT_STRING, BASE_HEX,
1874            NULL, 0x0, "", HFILL}},
1875         { &hf_fcels_respname,
1876           {"Responding Port Name", "fcels.respname", FT_STRING, BASE_HEX,
1877            NULL, 0x0, "", HFILL}},
1878         { &hf_fcels_respnname,
1879           {"Responding Node Name", "fcels.respnname", FT_STRING, BASE_HEX,
1880            NULL, 0x0, "", HFILL}},
1881         { &hf_fcels_reqipaddr,
1882           {"Requesting IP Address", "fcels.reqipaddr", FT_IPv6, BASE_DEC,
1883            NULL, 0x0, "", HFILL}},
1884         { &hf_fcels_respipaddr,
1885           {"Responding IP Address", "fcels.respipaddr", FT_IPv6, BASE_DEC,
1886            NULL, 0x0, "", HFILL}},
1887         { &hf_fcels_hardaddr,
1888           {"Hard Address of Originator", "fcels.hrdaddr", FT_STRING, BASE_HEX,
1889            NULL, 0x0, "", HFILL}},
1890         { &hf_fcels_rps_flag,
1891           {"Flag", "fcels.flag", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL}},
1892         { &hf_fcels_rps_portnum,
1893           {"Physical Port Number", "fcels.portnum", FT_UINT32, BASE_HEX, NULL,
1894            0x0, "", HFILL}},
1895         { &hf_fcels_rps_portstatus,
1896           {"Port Status", "fcels.portstatus", FT_UINT16, BASE_HEX,
1897            VALS(fc_els_portstatus_val), 0x0, "", HFILL}},
1898         { &hf_fcels_rnft_fc4type,
1899           {"FC-4 Type", "fcels.rnft.fc4type", FT_UINT8, BASE_HEX,
1900            VALS (fc_fc4_val), 0x0, "", HFILL}},
1901         { &hf_fcels_rscn_evqual,
1902           {"Event Qualifier", "fcels.rscn.evqual", FT_UINT8, BASE_HEX,
1903            VALS (fc_els_rscn_evqual_val), 0x3C, "", HFILL}},
1904         { &hf_fcels_rscn_addrfmt,
1905           {"Address Format", "fcels.rscn.addrfmt", FT_UINT8, BASE_HEX,
1906            VALS (fc_els_rscn_addrfmt_val), 0x03, "", HFILL}},
1907         { &hf_fcels_rscn_domain,
1908           {"Affected Domain", "fcels.rscn.domain", FT_UINT8, BASE_HEX,
1909            NULL, 0x0, "", HFILL}},
1910         { &hf_fcels_rscn_area,
1911           {"Affected Area", "fcels.rscn.area", FT_UINT8, BASE_HEX,
1912            NULL, 0x0, "", HFILL}},
1913         { &hf_fcels_rscn_port,
1914           {"Affected Port", "fcels.rscn.port", FT_UINT8, BASE_HEX,
1915            NULL, 0x0, "", HFILL}},
1916         { &hf_fcels_nodeidfmt,
1917           {"Node Identification Format", "fcels.rnid.nodeidfmt", FT_UINT8,
1918            BASE_HEX, VALS (fc_els_nodeid_val), 0x0, "", HFILL}},
1919         { &hf_fcels_spidlen,
1920           {"Specific Id Length", "fcels.rnid.spidlen", FT_UINT8, BASE_DEC, NULL,
1921            0x0, "", HFILL}},
1922         { &hf_fcels_vendoruniq,
1923           {"Vendor Unique", "fcels.rnid.vendoruniq", FT_BYTES, BASE_HEX, NULL,
1924            0x0, "", HFILL}},
1925         { &hf_fcels_vendorsp,
1926           {"Vendor Specific", "fcels.rnid.vendorsp", FT_UINT16, BASE_HEX, NULL,
1927            0x0, "", HFILL}},
1928         { &hf_fcels_asstype,
1929           {"Associated Type", "fcels.rnid.asstype", FT_UINT32, BASE_HEX, 
1930            VALS (fc_els_rnid_asstype_val), 0x0, "", HFILL}},
1931         { &hf_fcels_physport,
1932           {"Physical Port Number", "fcels.rnid.physport", FT_UINT32, BASE_HEX,
1933            NULL, 0x0, "", HFILL}},
1934         { &hf_fcels_attnodes,
1935           {"Number of Attached Nodes", "fcels.rnid.attnodes", FT_UINT32,
1936            BASE_HEX, NULL, 0x0, "", HFILL}},
1937         { &hf_fcels_nodemgmt,
1938           {"Node Management", "fcels.rnid.nodemgmt", FT_UINT8, BASE_HEX,
1939            VALS (fc_els_rnid_mgmt_val), 0x0, "", HFILL}},
1940         { &hf_fcels_ipvers,
1941           {"IP Version", "fcels.rnid.ipvers", FT_UINT8, BASE_HEX,
1942            VALS (fc_els_rnid_ipvers_val), 0x0, "", HFILL}},
1943         { &hf_fcels_tcpport,
1944           {"TCP/UDP Port Number", "fcels.rnid.tcpport", FT_UINT16, BASE_DEC,
1945            NULL, 0x0, "", HFILL}},
1946         { &hf_fcels_ip,
1947           {"IP Address", "fcels.rnid.ip", FT_IPv6, BASE_HEX, NULL, 0x0, "",
1948            HFILL}},
1949     };
1950
1951     static gint *ett[] = {
1952         &ett_fcels,
1953         &ett_fcels,
1954         &ett_fcels_lsrjt,
1955         &ett_fcels_acc,
1956         &ett_fcels_logi,
1957         &ett_fcels_logi_cmnsvc,
1958         &ett_fcels_logi_clssvc,
1959         &ett_fcels_logo,
1960         &ett_fcels_abtx,
1961         &ett_fcels_rsi,
1962         &ett_fcels_rrq,
1963         &ett_fcels_prli,
1964         &ett_fcels_prli_svcpg,
1965         &ett_fcels_adisc,
1966         &ett_fcels_farp,
1967         &ett_fcels_rps,
1968         &ett_fcels_rpl,
1969         &ett_fcels_rplpb,
1970         &ett_fcels_fan,
1971         &ett_fcels_rscn,
1972         &ett_fcels_rscn_rec,
1973         &ett_fcels_scr,
1974         &ett_fcels_rnft,
1975         &ett_fcels_rnft_fc4,
1976         &ett_fcels_lsts,
1977         &ett_fcels_rnid,
1978         &ett_fcels_rlir,
1979         &ett_fcels_lirr,
1980         &ett_fcels_srl,
1981         &ett_fcels_rpsc,
1982     };
1983
1984     /* Register the protocol name and description */
1985     proto_fcels = proto_register_protocol("FC Extended Link Svc", "FC ELS", "els");
1986
1987     /* Required function calls to register the header fields and subtrees used */
1988     proto_register_field_array(proto_fcels, hf, array_length(hf));
1989     proto_register_subtree_array(ett, array_length(ett));
1990     register_init_routine (&fcels_init_protocol);
1991 }
1992
1993 void
1994 proto_reg_handoff_fcels (void)
1995 {
1996     dissector_handle_t els_handle;
1997
1998     els_handle = create_dissector_handle (dissect_fcels, proto_fcels);
1999     dissector_add("fc.ftype", FC_FTYPE_ELS, els_handle);
2000
2001     data_handle = find_dissector ("data");
2002     fcsp_handle = find_dissector ("fcsp");
2003 }