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