Remove all preferences related to enabling/disabling heuristic dissectors.
[metze/wireshark/wip.git] / epan / dissectors / packet-mq-pcf.c
1 /* packet-mq-pcf.c
2  * Routines for IBM WebSphere MQ PCF packet dissection
3  *
4  * metatech <metatech@flashmail.com>
5  * robionekenobi <robionekenobi@bluewin.ch>
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25
26 /*  MQ PCF in a nutshell
27  *
28  *   The MQ Programmable Command Formats API allows remotely configuring a queue manager.
29  *
30  *   MQ PCF documentation is called "WebSphere MQ Programmable Command Formats and Administration Interface"
31 */
32
33 #include "config.h"
34
35 #include <math.h>
36
37 #include <epan/packet.h>
38 #include <epan/expert.h>
39 #include <epan/prefs.h>
40 #include <epan/strutil.h>
41
42 #include "packet-mq.h"
43
44 void proto_register_mqpcf(void);
45 void proto_reg_handoff_mqpcf(void);
46
47 #define PCF_MAX_PARM 999
48 #define PCF_MAX_LIST 20000
49
50 guint mq_pcf_maxprm = PCF_MAX_PARM;
51 guint mq_pcf_maxlst = PCF_MAX_LIST;
52
53 static int proto_mqpcf = -1;
54
55 static int hf_mqpcf_cfh_type = -1;
56 static int hf_mqpcf_cfh_length = -1;
57 static int hf_mqpcf_cfh_version = -1;
58 static int hf_mqpcf_cfh_command = -1;
59 static int hf_mqpcf_cfh_MsgSeqNbr = -1;
60 static int hf_mqpcf_cfh_control = -1;
61 static int hf_mqpcf_cfh_compcode = -1;
62 static int hf_mqpcf_cfh_reason = -1;
63 static int hf_mqpcf_cfh_ParmCount = -1;
64
65 static int hf_mq_pcf_prmtyp = -1;
66 static int hf_mq_pcf_prmlen = -1;
67 static int hf_mq_pcf_prmid = -1;
68 static int hf_mq_pcf_prmidnovals = -1;
69 static int hf_mq_pcf_filterop = -1;
70 static int hf_mq_pcf_prmccsid = -1;
71 static int hf_mq_pcf_prmstrlen = -1;
72 static int hf_mq_pcf_prmcount = -1;
73 static int hf_mq_pcf_prmunused = -1;
74
75 static int hf_mq_pcf_string = -1;
76 static int hf_mq_pcf_stringlist = -1;
77 static int hf_mq_pcf_int = -1;
78 static int hf_mq_pcf_intlist = -1;
79 static int hf_mq_pcf_bytestring = -1;
80 static int hf_mq_pcf_int64 = -1;
81 static int hf_mq_pcf_int64list = -1;
82
83 static expert_field ei_mq_pcf_prmln0 = EI_INIT;
84 static expert_field ei_mq_pcf_MaxInt = EI_INIT;
85 static expert_field ei_mq_pcf_MaxStr = EI_INIT;
86 static expert_field ei_mq_pcf_MaxI64 = EI_INIT;
87 static expert_field ei_mq_pcf_MaxPrm = EI_INIT;
88 static expert_field ei_mq_pcf_PrmCnt = EI_INIT;
89
90 static gint ett_mqpcf_prm = -1;
91 static gint ett_mqpcf = -1;
92 static gint ett_mqpcf_cfh = -1;
93
94 #define MQ_TEXT_CFH   "MQ Command Format Header"
95
96 static guint32 dissect_mqpcf_getDigits(guint uCnt)
97 {
98     return (guint32)(log10( (double)uCnt ) + 1);
99 }
100 /*
101 * Here we get a special value_string, that return another value_string
102 * pointer instead of string value. This let us use the try_val_to_str
103 * to get val_to_str value from the value of a parameter on a more
104 * easier way than using switch cases
105 */
106 static const guint8 *dissect_mqpcf_parm_getintval(guint uPrm, guint uVal)
107 {
108     const value_string *pVs;
109     pVs = (const value_string *)try_val_to_str_ext(uPrm, GET_VALS_EXTP(MQCFINT_Parse));
110
111     if (pVs)
112     {
113         return (const guint8 *)try_val_to_str(uVal, pVs);
114     }
115     return NULL;
116 }
117
118 static void dissect_mqpcf_parm_int(tvbuff_t *tvb, proto_tree *tree, guint offset, guint uPrm,
119                                    guint uVal, int hfindex, guint iCnt, guint iMaxCnt,
120                                    guint iDigit, gboolean bParse)
121 {
122     header_field_info *hfinfo;
123     const guint8 *pVal = NULL;
124
125     if (bParse)
126         pVal = dissect_mqpcf_parm_getintval(uPrm, uVal);
127
128     hfinfo = proto_registrar_get_nth(hfindex);
129
130     if (iMaxCnt > 1)
131     {
132         if (pVal)
133         {
134             proto_tree_add_int_format(tree, hfindex, tvb, offset, 4, uVal,
135                 "%s[%*d]: %8x-(%9d)-%s", hfinfo->name, iDigit, iCnt, uVal, uVal, pVal);
136         }
137         else
138         {
139             proto_tree_add_int_format(tree, hfindex, tvb, offset, 4, uVal,
140                 "%s[%*d]: %8x-(%9d)", hfinfo->name, iDigit, iCnt, uVal, uVal);
141         }
142     }
143     else
144     {
145         if (pVal)
146         {
147             proto_tree_add_int_format_value(tree, hfindex, tvb, offset, 4, uVal,
148                 "%8x-(%9d)-%s", uVal, uVal, pVal);
149         }
150         else
151         {
152             proto_tree_add_int_format_value(tree, hfindex, tvb, offset, 4, uVal,
153                 "%8x-(%9d)", uVal, uVal);
154         }
155     }
156 }
157
158 void dissect_mqpcf_parm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *mq_tree,
159                         guint offset, guint32 uCount, guint bLittleEndian, gboolean bParse)
160 {
161     guint32 u    = 0;
162     guint32 tOfs = 0;
163     guint32 uLenF;
164     char    strPrm[256];
165     guint32 uTyp;
166     guint32 uLen = 0;
167     guint32 uPrm;
168     guint32 uCnt;
169     guint32 uCCS;
170     guint32 uSLn;
171     guint32 uVal;
172     guint64 uVal64;
173     guint32 uDig;
174
175     const char sMaxLst[] = " Max # of List reached. DECODE interrupted   (actual %u of %u)";
176     const char sPrmLn0[] = " MQPrm[%3u] has a zero length. DECODE Failed (MQPrm Count: %u)";
177     const char sMaxPrm[] = " Max # of Parm reached. DECODE interrupted   (actual %u of %u)";
178     const char sPrmCnt[] = " Cnt=-1 and Length(%u) < 16. DECODE interrupted for elem %u";
179
180     proto_item *ti   = NULL;
181     proto_tree *tree = NULL;
182
183     if (uCount == (guint32)-1)
184     {
185         guint32 xOfs = offset;
186
187         uCnt = 0;
188         while (tvb_reported_length_remaining(tvb, xOfs) >= 16)
189         {
190             uLen = tvb_get_guint32(tvb, xOfs + 4, bLittleEndian);
191             if (uLen < 16)
192             {
193                 proto_tree_add_expert_format(tree, pinfo, &ei_mq_pcf_PrmCnt, tvb, xOfs, 16, sPrmCnt, uLen, uCnt);
194                 break;
195             }
196             uCnt++;
197             xOfs += uLen;
198         }
199         uCount = uCnt;
200     }
201
202     uDig = dissect_mqpcf_getDigits(uCount);
203
204     for (u = 0; u < uCount && u < mq_pcf_maxprm; u++)
205     {
206         tOfs = offset;
207         uTyp = tvb_get_guint32(tvb, offset    , bLittleEndian);
208         uLen = tvb_get_guint32(tvb, offset + 4, bLittleEndian);
209         if (uLen == 0)
210         {
211             proto_tree_add_expert_format(tree, pinfo, &ei_mq_pcf_prmln0, tvb, offset, 12, sPrmLn0, u+1, uCount);
212             u = uCount;
213             break;
214         }
215         uPrm = tvb_get_guint32(tvb, offset + 8, bLittleEndian);
216         uLenF = 12;
217
218         if (bParse)
219             g_snprintf(strPrm, (gulong)sizeof(strPrm) - 1, " %-s[%*u] {%2d-%-15.15s} %8x/%5d-%-30.30s",
220                 "MQPrm", uDig, u+1,
221                 uTyp, val_to_str_ext_const(uTyp, GET_VALS_EXTP(PrmTyp), "      Unknown") + 6,
222                 uPrm, uPrm, val_to_str_ext_const(uPrm, GET_VALS_EXTP(PrmId), "Unknown"));
223         else
224             g_snprintf(strPrm, (gulong)sizeof(strPrm) - 1, " %-s[%*u] {%2d-%-15.15s} %8x/%5d",
225                 "XtraD", uDig, u+1,
226                 uTyp, val_to_str_ext_const(uTyp, GET_VALS_EXTP(PrmTyp), "      Unknown") + 6,
227                 uPrm, uPrm);
228
229         switch (uTyp)
230         {
231         case MQ_MQCFT_NONE:
232             break;
233         case MQ_MQCFT_COMMAND:
234             break;
235         case MQ_MQCFT_RESPONSE:
236             break;
237         case MQ_MQCFT_INTEGER:
238             {
239                 const guint8 *pVal = NULL;
240                 uVal = tvb_get_guint32(tvb, offset + uLenF, bLittleEndian);
241                 if (bParse)
242                     pVal = dissect_mqpcf_parm_getintval(uPrm, uVal);
243
244                 if (pVal)
245                 {
246                     tree = proto_tree_add_subtree_format(mq_tree, tvb, offset, uLen, ett_mqpcf_prm, NULL,
247                                                              "%s %8x-(%9d) %s", strPrm, uVal, uVal, pVal);
248                 }
249                 else
250                 {
251                     tree = proto_tree_add_subtree_format(mq_tree, tvb, offset, uLen, ett_mqpcf_prm, NULL,
252                                                              "%s %8x-(%9d)", strPrm, uVal, uVal);
253                 }
254
255                 proto_tree_add_item(tree, hf_mq_pcf_prmtyp, tvb, offset    , 4, bLittleEndian);
256                 proto_tree_add_item(tree, hf_mq_pcf_prmlen, tvb, offset + 4, 4, bLittleEndian);
257                 proto_tree_add_item(tree, (bParse) ? hf_mq_pcf_prmid : hf_mq_pcf_prmidnovals, tvb, offset + 8, 4, bLittleEndian);
258
259                 dissect_mqpcf_parm_int(tvb, tree, offset+uLenF, uPrm, uVal, hf_mq_pcf_int, 0, 0, 0, bParse);
260             }
261             break;
262         case MQ_MQCFT_STRING:
263             {
264                 guint8 *sStr;
265
266                 uCCS = tvb_get_guint32(tvb, offset + uLenF, bLittleEndian);
267                 uSLn = tvb_get_guint32(tvb, offset + uLenF + 4, bLittleEndian);
268                 sStr = tvb_get_string_enc(wmem_packet_scope(), tvb, offset + uLenF + 8,
269                     uSLn, (uCCS != 500) ? ENC_ASCII : ENC_EBCDIC);
270                 if (*sStr)
271                     strip_trailing_blanks(sStr, uSLn);
272                 if (*sStr)
273                     format_text_chr(sStr, strlen((const char *)sStr), '.');
274
275                 tree = proto_tree_add_subtree_format(mq_tree, tvb, offset, uLen, ett_mqpcf_prm, NULL, "%s %s", strPrm, sStr);
276
277                 proto_tree_add_item(tree, hf_mq_pcf_prmtyp   , tvb, offset     , 4, bLittleEndian);
278                 proto_tree_add_item(tree, hf_mq_pcf_prmlen   , tvb, offset +  4, 4, bLittleEndian);
279                 proto_tree_add_item(tree, (bParse) ? hf_mq_pcf_prmid : hf_mq_pcf_prmidnovals, tvb, offset +  8, 4, bLittleEndian);
280                 proto_tree_add_item(tree, hf_mq_pcf_prmccsid , tvb, offset + 12, 4, bLittleEndian);
281                 proto_tree_add_item(tree, hf_mq_pcf_prmstrlen, tvb, offset + 16, 4, bLittleEndian);
282
283                 proto_tree_add_item(tree, hf_mq_pcf_string, tvb, offset + uLenF + 8, uSLn, (uCCS != 500) ? ENC_ASCII : ENC_EBCDIC);
284             }
285             break;
286         case MQ_MQCFT_INTEGER_LIST:
287             {
288                 guint32 u2;
289                 guint32 uDigit = 0;
290
291                 uCnt = tvb_get_guint32(tvb, offset+uLenF, bLittleEndian);
292                 uDigit = dissect_mqpcf_getDigits(uCnt);
293
294                 tree = proto_tree_add_subtree_format(mq_tree, tvb, offset, uLen, ett_mqpcf_prm, &ti, "%s Cnt(%d)", strPrm, uCnt);
295
296                 proto_tree_add_item(tree, hf_mq_pcf_prmtyp  , tvb, offset     , 4, bLittleEndian);
297                 proto_tree_add_item(tree, hf_mq_pcf_prmlen  , tvb, offset +  4, 4, bLittleEndian);
298                 proto_tree_add_item(tree, (bParse) ? hf_mq_pcf_prmid : hf_mq_pcf_prmidnovals, tvb, offset +  8, 4, bLittleEndian);
299                 proto_tree_add_item(tree, hf_mq_pcf_prmcount, tvb, offset + 12, 4, bLittleEndian);
300
301                 offset += uLenF+4;
302                 for (u2 = 0; u2 < uCnt && u2 < mq_pcf_maxlst; u2++)
303                 {
304                     uVal = tvb_get_guint32(tvb, offset, bLittleEndian);
305                     dissect_mqpcf_parm_int(tvb, tree, offset, uPrm, uVal, hf_mq_pcf_intlist, u2+1, uCnt, uDigit, bParse);
306                     offset += 4;
307                 }
308                 if (u2 != uCnt)
309                 {
310                     proto_tree_add_expert_format(tree, pinfo, &ei_mq_pcf_MaxInt, tvb, offset, (uCnt- u2) * 4, sMaxLst, u2, uCnt);
311                 }
312             }
313             break;
314         case MQ_MQCFT_STRING_LIST:
315             {
316                 guint32  u2;
317                 guint32  uDigit;
318                 guint8  *sStr;
319                 header_field_info *hfinfo;
320
321                 hfinfo = proto_registrar_get_nth(hf_mq_pcf_stringlist);
322
323                 uCCS = tvb_get_guint32(tvb, offset + uLenF    , bLittleEndian);
324                 uCnt = tvb_get_guint32(tvb, offset + uLenF + 4, bLittleEndian);
325                 uSLn = tvb_get_guint32(tvb, offset + uLenF + 8, bLittleEndian);
326
327                 tree = proto_tree_add_subtree_format(mq_tree, tvb, offset, uLen, ett_mqpcf_prm, NULL, "%s Cnt(%d)", strPrm, uCnt);
328
329                 proto_tree_add_item(tree, hf_mq_pcf_prmtyp   , tvb, offset     , 4, bLittleEndian);
330                 proto_tree_add_item(tree, hf_mq_pcf_prmlen   , tvb, offset +  4, 4, bLittleEndian);
331                 proto_tree_add_item(tree, (bParse) ? hf_mq_pcf_prmid : hf_mq_pcf_prmidnovals, tvb, offset +  8, 4, bLittleEndian);
332                 proto_tree_add_item(tree, hf_mq_pcf_prmccsid , tvb, offset + 12, 4, bLittleEndian);
333                 proto_tree_add_item(tree, hf_mq_pcf_prmcount , tvb, offset + 16, 4, bLittleEndian);
334                 proto_tree_add_item(tree, hf_mq_pcf_prmstrlen, tvb, offset + 20, 4, bLittleEndian);
335
336                 uDigit = dissect_mqpcf_getDigits(uCnt);
337
338                 offset += uLenF+12;
339                 for (u2 = 0; u2 < uCnt && u2 < mq_pcf_maxlst; u2++)
340                 {
341                     sStr = tvb_get_string_enc(wmem_packet_scope(), tvb, offset,
342                         uSLn, (uCCS != 500) ? ENC_ASCII : ENC_EBCDIC);
343                     if (*sStr)
344                         strip_trailing_blanks(sStr, uSLn);
345                     if (*sStr)
346                         format_text_chr(sStr, strlen((const char *)sStr),  '.');
347
348                     proto_tree_add_string_format(tree, hf_mq_pcf_stringlist, tvb, offset, uSLn, (const char *)sStr,
349                         "%s[%*d]: %s", hfinfo->name, uDigit, u2+1, sStr);
350                     offset += uSLn;
351                 }
352                 if (u2 != uCnt)
353                 {
354                     proto_tree_add_expert_format(tree, pinfo, &ei_mq_pcf_MaxStr, tvb, offset,(uCnt - u2) * uSLn, sMaxLst, u2, uCnt);
355                 }
356             }
357             break;
358         case MQ_MQCFT_EVENT:
359             break;
360         case MQ_MQCFT_USER:
361             {
362                 tree = proto_tree_add_subtree(mq_tree, tvb, offset, uLen, ett_mqpcf_prm, NULL, strPrm);
363
364                 proto_tree_add_item(tree, hf_mq_pcf_prmtyp   , tvb, offset     , 4, bLittleEndian);
365                 proto_tree_add_item(tree, hf_mq_pcf_prmlen   , tvb, offset +  4, 4, bLittleEndian);
366
367                 proto_tree_add_item(tree, hf_mq_pcf_bytestring, tvb, offset + 8, uLen - 8, bLittleEndian);
368             }
369             break;
370         case MQ_MQCFT_BYTE_STRING:
371             {
372                 uSLn = tvb_get_guint32(tvb, offset + uLenF, bLittleEndian);
373                 if (uSLn)
374                 {
375                     guint8 *sStrA = (guint8 *)format_text_chr(tvb_get_string_enc(wmem_packet_scope(), tvb, offset + uLenF + 4, uSLn, ENC_ASCII) , uSLn, '.');
376                     guint8 *sStrE = (guint8 *)format_text_chr(tvb_get_string_enc(wmem_packet_scope(), tvb, offset + uLenF + 4, uSLn, ENC_EBCDIC), uSLn, '.');
377                     if (uSLn > 35)
378                     {
379                         tree = proto_tree_add_subtree_format(mq_tree, tvb, offset, uLen, ett_mqpcf_prm, NULL,
380                                                         "%s [Truncated] A(%-.35s) E(%-.35s)", strPrm, sStrA, sStrE);
381                     }
382                     else
383                     {
384                         tree = proto_tree_add_subtree_format(mq_tree, tvb, offset, uLen, ett_mqpcf_prm, NULL,
385                                                         "%s A(%s) E(%s)", strPrm, sStrA, sStrE);
386                     }
387                 }
388                 else
389                 {
390                     tree = proto_tree_add_subtree_format(mq_tree, tvb, offset, uLen, ett_mqpcf_prm, NULL, "%s <MISSING>", strPrm);
391                 }
392
393                 proto_tree_add_item(tree, hf_mq_pcf_prmtyp   , tvb, offset     , 4, bLittleEndian);
394                 proto_tree_add_item(tree, hf_mq_pcf_prmlen   , tvb, offset +  4, 4, bLittleEndian);
395                 proto_tree_add_item(tree, (bParse) ? hf_mq_pcf_prmid : hf_mq_pcf_prmidnovals, tvb, offset +  8, 4, bLittleEndian);
396                 proto_tree_add_item(tree, hf_mq_pcf_prmstrlen, tvb, offset + 12, 4, bLittleEndian);
397
398                 proto_tree_add_item(tree, hf_mq_pcf_bytestring, tvb, offset + uLenF + 4 , uSLn, bLittleEndian);
399             }
400             break;
401         case MQ_MQCFT_TRACE_ROUTE:
402             break;
403         case MQ_MQCFT_REPORT:
404             break;
405         case MQ_MQCFT_INTEGER_FILTER:
406             {
407                 guint32 uOpe;
408
409                 uOpe = tvb_get_guint32(tvb, offset + uLenF    , bLittleEndian);
410                 uVal = tvb_get_guint32(tvb, offset + uLenF + 4, bLittleEndian);
411
412                 tree = proto_tree_add_subtree_format(mq_tree, tvb, offset, uLen, ett_mqpcf_prm, NULL, "%s %s %8x-(%9d)",
413                     strPrm, val_to_str(uOpe, GET_VALSV(FilterOP), "       Unknown (0x%02x)")+7, uVal, uVal);
414
415                 proto_tree_add_item(tree, hf_mq_pcf_prmtyp   , tvb, offset     , 4, bLittleEndian);
416                 proto_tree_add_item(tree, hf_mq_pcf_prmlen   , tvb, offset +  4, 4, bLittleEndian);
417                 proto_tree_add_item(tree, (bParse) ? hf_mq_pcf_prmid : hf_mq_pcf_prmidnovals, tvb, offset +  8, 4, bLittleEndian);
418                 proto_tree_add_item(tree, hf_mq_pcf_filterop , tvb, offset + 12, 4, bLittleEndian);
419
420                 proto_tree_add_item(tree, hf_mq_pcf_int, tvb, offset + uLenF + 4, 4, bLittleEndian);
421             }
422             break;
423         case MQ_MQCFT_STRING_FILTER:
424             {
425                 guint8 *sStr;
426                 guint32 uOpe;
427
428                 uOpe = tvb_get_guint32(tvb, offset + uLenF, bLittleEndian);
429                 uCCS = tvb_get_guint32(tvb, offset + uLenF + 4, bLittleEndian);
430                 uSLn = tvb_get_guint32(tvb, offset + uLenF + 8, bLittleEndian);
431                 sStr = (guint8 *)format_text_chr(tvb_get_string_enc(wmem_packet_scope(), tvb, offset + uLenF + 12, uSLn, (uCCS != 500) ? ENC_ASCII : ENC_EBCDIC), uSLn, '.');
432                 strip_trailing_blanks(sStr, uSLn);
433
434                 tree = proto_tree_add_subtree_format(mq_tree, tvb, offset, uLen, ett_mqpcf_prm, NULL, "%s %s %s",
435                     strPrm, val_to_str(uOpe, GET_VALSV(FilterOP), "       Unknown (0x%02x)")+7, sStr);
436
437                 proto_tree_add_item(tree, hf_mq_pcf_prmtyp   , tvb, offset     , 4, bLittleEndian);
438                 proto_tree_add_item(tree, hf_mq_pcf_prmlen   , tvb, offset +  4, 4, bLittleEndian);
439                 proto_tree_add_item(tree, (bParse) ? hf_mq_pcf_prmid : hf_mq_pcf_prmidnovals, tvb, offset +  8, 4, bLittleEndian);
440                 proto_tree_add_item(tree, hf_mq_pcf_filterop , tvb, offset + 12, 4, bLittleEndian);
441                 proto_tree_add_item(tree, hf_mq_pcf_prmccsid , tvb, offset + 16, 4, bLittleEndian);
442                 proto_tree_add_item(tree, hf_mq_pcf_prmstrlen, tvb, offset + 20, 4, bLittleEndian);
443
444                 proto_tree_add_item(tree, hf_mq_pcf_string, tvb, offset + uLenF + 12, uSLn, (uCCS != 500) ? ENC_ASCII : ENC_EBCDIC);
445             }
446             break;
447         case MQ_MQCFT_BYTE_STRING_FILTER:
448             {
449                 guint32 uOpe;
450                 uOpe = tvb_get_guint32(tvb, offset + uLenF, bLittleEndian);
451                 uSLn = tvb_get_guint32(tvb, offset + uLenF + 4, bLittleEndian);
452                 if (uSLn)
453                 {
454                     guint8 *sStrA = (guint8 *)format_text_chr(tvb_get_string_enc(wmem_packet_scope(), tvb, offset + uLenF + 8, uSLn, ENC_ASCII), uSLn, '.');
455                     guint8 *sStrE = (guint8 *)format_text_chr(tvb_get_string_enc(wmem_packet_scope(), tvb, offset + uLenF + 8, uSLn, ENC_EBCDIC), uSLn, '.');
456                     tree = proto_tree_add_subtree_format(mq_tree, tvb, offset, uLen, ett_mqpcf_prm, NULL, "%s %s A(%s) E(%s)",
457                         strPrm, val_to_str(uOpe, GET_VALSV(FilterOP), "       Unknown (0x%02x)")+7, sStrA, sStrE);
458                 }
459                 else
460                 {
461                     tree = proto_tree_add_subtree_format(mq_tree, tvb, offset, uLen, ett_mqpcf_prm, NULL, "%s %s <MISSING>",
462                         strPrm, val_to_str(uOpe, GET_VALSV(FilterOP), "       Unknown (0x%02x)")+7);
463                 }
464
465                 proto_tree_add_item(tree, hf_mq_pcf_prmtyp   , tvb, offset     , 4, bLittleEndian);
466                 proto_tree_add_item(tree, hf_mq_pcf_prmlen   , tvb, offset +  4, 4, bLittleEndian);
467                 proto_tree_add_item(tree, (bParse) ? hf_mq_pcf_prmid : hf_mq_pcf_prmidnovals, tvb, offset +  8, 4, bLittleEndian);
468                 proto_tree_add_item(tree, hf_mq_pcf_filterop , tvb, offset + 12, 4, bLittleEndian);
469                 proto_tree_add_item(tree, hf_mq_pcf_prmstrlen, tvb, offset + 16, 4, bLittleEndian);
470
471                 proto_tree_add_item(tree, hf_mq_pcf_bytestring, tvb, offset + uLenF + 8 , uSLn, bLittleEndian);
472             }
473             break;
474         case MQ_MQCFT_COMMAND_XR:
475             break;
476         case MQ_MQCFT_XR_MSG:
477             break;
478         case MQ_MQCFT_XR_ITEM:
479             break;
480         case MQ_MQCFT_XR_SUMMARY:
481             break;
482         case MQ_MQCFT_GROUP:
483             break;
484         case MQ_MQCFT_STATISTICS:
485             break;
486         case MQ_MQCFT_ACCOUNTING:
487             break;
488         case MQ_MQCFT_INTEGER64:
489             {
490                 uVal64 = tvb_get_guint64(tvb, offset + uLenF + 4, bLittleEndian);
491                 tree = proto_tree_add_subtree_format(mq_tree, tvb, offset, uLen, ett_mqpcf_prm, NULL,
492                     "%s %" G_GINT64_MODIFIER "x (%" G_GINT64_MODIFIER "d)", strPrm, uVal64, uVal64);
493
494                 proto_tree_add_item(tree, hf_mq_pcf_prmtyp   , tvb, offset     , 4, bLittleEndian);
495                 proto_tree_add_item(tree, hf_mq_pcf_prmlen   , tvb, offset +  4, 4, bLittleEndian);
496                 proto_tree_add_item(tree, (bParse) ? hf_mq_pcf_prmid : hf_mq_pcf_prmidnovals, tvb, offset +  8, 4, bLittleEndian);
497                 proto_tree_add_item(tree, hf_mq_pcf_prmunused, tvb, offset + 12, 4, bLittleEndian);
498
499                 proto_tree_add_item(tree, hf_mq_pcf_int64, tvb, offset + uLenF + 4, 8, bLittleEndian);
500             }
501             break;
502         case MQ_MQCFT_INTEGER64_LIST:
503             {
504                 guint32 u2;
505                 guint32 uDigit;
506                 header_field_info *hfinfo;
507
508                 hfinfo = proto_registrar_get_nth(hf_mq_pcf_int64list);
509
510                 uCnt = tvb_get_guint32(tvb, offset + uLenF, bLittleEndian);
511                 tree = proto_tree_add_subtree_format(mq_tree, tvb, offset, uLen, ett_mqpcf_prm, NULL, "%s Cnt(%d)", strPrm, uCnt);
512                 uDigit = dissect_mqpcf_getDigits(uCnt);
513
514                 proto_tree_add_item(tree, hf_mq_pcf_prmtyp  , tvb, offset     , 4, bLittleEndian);
515                 proto_tree_add_item(tree, hf_mq_pcf_prmlen  , tvb, offset +  4, 4, bLittleEndian);
516                 proto_tree_add_item(tree, (bParse) ? hf_mq_pcf_prmid : hf_mq_pcf_prmidnovals, tvb, offset +  8, 4, bLittleEndian);
517                 proto_tree_add_item(tree, hf_mq_pcf_prmcount, tvb, offset + 12, 4, bLittleEndian);
518
519                 offset += uLenF + 4;
520                 for (u2 = 0; u2 < uCnt && u2 < mq_pcf_maxlst; u2++)
521                 {
522                     uVal64 = tvb_get_guint64(tvb, offset, bLittleEndian);
523                     proto_tree_add_int64_format(tree, hf_mq_pcf_int64list, tvb, offset, 8, uVal64,
524                         "%s[%*d]: %" G_GINT64_MODIFIER "x (%" G_GINT64_MODIFIER "d)",
525                         hfinfo->name, uDigit, u2+1, uVal64, uVal64);
526                     offset += 8;
527                 }
528                 if (u2 != uCnt)
529                 {
530                     proto_tree_add_expert_format(tree, pinfo, &ei_mq_pcf_MaxI64, tvb, offset, (uCnt - u2) * 8, sMaxLst, u2, uCnt);
531                 }
532             }
533             break;
534         }
535         offset = tOfs+uLen;
536     }
537     if (u != uCount)
538     {
539         proto_tree_add_expert_format(mq_tree, pinfo, &ei_mq_pcf_MaxPrm, tvb, offset, tvb_reported_length_remaining(tvb, offset), sMaxPrm, u, uCount);
540     }
541 }
542
543 static void dissect_mqpcf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, mq_parm_t* p_mq_parm)
544 {
545     gint offset = 0;
546     gboolean bLittleEndian;
547
548     bLittleEndian = ((p_mq_parm->mq_cur_ccsid.encod & MQ_MQENC_INTEGER_MASK) == MQ_MQENC_INTEGER_REVERSED) ? ENC_LITTLE_ENDIAN : ENC_BIG_ENDIAN;
549
550     if (tvb_reported_length(tvb) >= 36)
551     {
552         gint iSizeMQCFH = 36;
553         guint32 iCommand = tvb_get_guint32(tvb, offset + 12, bLittleEndian);
554
555         if (tree)
556         {
557             proto_item *ti;
558             proto_tree *mq_tree;
559             proto_tree *mqroot_tree;
560             char        sTmp[256];
561             guint32     uCnt;
562             guint32     uTyp;
563             guint32     uCmd;
564             guint32     uCC;
565             guint32     uRC;
566
567             uTyp = tvb_get_guint32(tvb, offset     , bLittleEndian);
568             uCmd = tvb_get_guint32(tvb, offset + 12, bLittleEndian);
569             uCC  = tvb_get_guint32(tvb, offset + 24, bLittleEndian);
570             uRC  = tvb_get_guint32(tvb, offset + 28, bLittleEndian);
571             uCnt = tvb_get_guint32(tvb, offset + 32, bLittleEndian);
572
573             if (uCC || uRC)
574             {
575                 g_snprintf(sTmp, (gulong)sizeof(sTmp)-1, " %-s [%d-%s] {%d-%s} PrmCnt(%d) CC(%d-%s) RC(%d-%s)",
576                     MQ_TEXT_CFH,
577                     uTyp, val_to_str_const(uTyp, GET_VALSV(mqcft), "Unknown"),
578                     uCmd, val_to_str_ext_const(uCmd, GET_VALS_EXTP(mqcmd), "Unknown"),
579                     uCnt,
580                     uCC, val_to_str_const(uCC, GET_VALSV(mqcc), "Unknown"),
581                     uRC, val_to_str_ext_const(uRC, GET_VALS_EXTP(mqrc), "Unknown"));
582             }
583             else
584             {
585                 g_snprintf(sTmp, (gulong)sizeof(sTmp)-1, " %-s [%d-%s] {%d-%s} PrmCnt(%d)",
586                     MQ_TEXT_CFH,
587                     uTyp, val_to_str_const(uTyp, GET_VALSV(mqcft), "Unknown"),
588                     uCmd, val_to_str_ext_const(uCmd, GET_VALS_EXTP(mqcmd), "Unknown"),
589                     uCnt);
590             }
591
592             ti = proto_tree_add_item(tree, proto_mqpcf, tvb, offset, -1, ENC_NA);
593
594             proto_item_append_text(ti, " (%s)", val_to_str_ext_const(iCommand, GET_VALS_EXTP(mqcmd), "Unknown (0x%02x)"));
595             mqroot_tree = proto_item_add_subtree(ti, ett_mqpcf);
596
597             mq_tree = proto_tree_add_subtree(mqroot_tree, tvb, offset, iSizeMQCFH, ett_mqpcf_cfh, NULL, sTmp);
598
599             proto_tree_add_item(mq_tree, hf_mqpcf_cfh_type     , tvb, offset +  0, 4, bLittleEndian);
600             proto_tree_add_item(mq_tree, hf_mqpcf_cfh_length   , tvb, offset +  4, 4, bLittleEndian);
601             proto_tree_add_item(mq_tree, hf_mqpcf_cfh_version  , tvb, offset +  8, 4, bLittleEndian);
602             proto_tree_add_item(mq_tree, hf_mqpcf_cfh_command  , tvb, offset + 12, 4, bLittleEndian);
603             proto_tree_add_item(mq_tree, hf_mqpcf_cfh_MsgSeqNbr, tvb, offset + 16, 4, bLittleEndian);
604             proto_tree_add_item(mq_tree, hf_mqpcf_cfh_control  , tvb, offset + 20, 4, bLittleEndian);
605             proto_tree_add_item(mq_tree, hf_mqpcf_cfh_compcode , tvb, offset + 24, 4, bLittleEndian);
606             proto_tree_add_item(mq_tree, hf_mqpcf_cfh_reason   , tvb, offset + 28, 4, bLittleEndian);
607             proto_tree_add_item(mq_tree, hf_mqpcf_cfh_ParmCount, tvb, offset + 32, 4, bLittleEndian);
608             dissect_mqpcf_parm(tvb, pinfo, mqroot_tree, offset + iSizeMQCFH, uCnt, bLittleEndian, TRUE);
609         }
610     }
611 }
612
613 static gboolean dissect_mqpcf_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
614 {
615     if (data && tvb_reported_length(tvb) >= 36)
616     {
617         mq_parm_t *p_mq_parm = (mq_parm_t *)data;
618         if (strncmp((const char*)p_mq_parm->mq_format, MQ_MQFMT_ADMIN, 8) == 0
619             || strncmp((const char*)p_mq_parm->mq_format, MQ_MQFMT_EVENT, 8) == 0
620             || strncmp((const char*)p_mq_parm->mq_format, MQ_MQFMT_PCF, 8) == 0)
621         {
622             /* Dissect the packet */
623             dissect_mqpcf(tvb, pinfo, tree, p_mq_parm);
624             return TRUE;
625         }
626         if (strncmp((const char *)p_mq_parm->mq_format, "LPOO", 4) == 0)
627         {
628             gboolean bLittleEndian;
629             bLittleEndian = ((p_mq_parm->mq_cur_ccsid.encod & MQ_MQENC_INTEGER_MASK) == MQ_MQENC_INTEGER_REVERSED) ? ENC_LITTLE_ENDIAN:ENC_BIG_ENDIAN;
630             dissect_mqpcf_parm(tvb, pinfo, tree, 0, (guint32)-1, bLittleEndian, FALSE);
631             return TRUE;
632         }
633     }
634     return FALSE;
635 }
636
637 void proto_register_mqpcf(void)
638 {
639     expert_module_t *expert_mqpcf;
640
641     static hf_register_info hf[] =
642     {
643         { &hf_mqpcf_cfh_type     , { "Type.....", "mqpcf.cfh.type"      , FT_UINT32, BASE_DEC, VALS(mq_mqcft_vals), 0x0, "CFH type", HFILL }},
644         { &hf_mqpcf_cfh_length   , { "Length...", "mqpcf.cfh.length"    , FT_UINT32, BASE_DEC, NULL, 0x0, "CFH length", HFILL }},
645         { &hf_mqpcf_cfh_version  , { "Version..", "mqpcf.cfh.version"   , FT_UINT32, BASE_DEC, NULL, 0x0, "CFH version", HFILL }},
646         { &hf_mqpcf_cfh_command  , { "Command..", "mqpcf.cfh.command"   , FT_UINT32, BASE_DEC | BASE_EXT_STRING, &mq_mqcmd_xvals, 0x0, "CFH command", HFILL }},
647         { &hf_mqpcf_cfh_MsgSeqNbr, { "MsgSeqNbr", "mqpcf.cfh.MsgSeqNbr" , FT_UINT32, BASE_DEC, NULL, 0x0, "CFH message sequence number", HFILL }},
648         { &hf_mqpcf_cfh_control  , { "Control..", "mqpcf.cfh.control"   , FT_UINT32, BASE_DEC, VALS(mq_CtlOpt_vals), 0x0, "CFH control", HFILL }},
649         { &hf_mqpcf_cfh_compcode , { "CompCode.", "mqpcf.cfh.compcode"  , FT_UINT32, BASE_DEC, VALS(mq_mqcc_vals), 0x0, "CFH completion code", HFILL }},
650         { &hf_mqpcf_cfh_reason   , { "ReasCode.", "mqpcf.cfh.reasoncode", FT_UINT32, BASE_DEC | BASE_EXT_STRING, &mq_mqrc_xvals, 0x0, "CFH reason code", HFILL }},
651         { &hf_mqpcf_cfh_ParmCount, { "ParmCount", "mqpcf.cfh.ParmCount" , FT_UINT32, BASE_DEC, NULL, 0x0, "CFH parameter count", HFILL }},
652
653         { &hf_mq_pcf_prmtyp      , { "ParmTyp..", "mqpcf.parm.type"      , FT_UINT32 , BASE_DEC | BASE_EXT_STRING, &mq_PrmTyp_xvals, 0x0, "MQPCF parameter type", HFILL }},
654         { &hf_mq_pcf_prmlen      , { "ParmLen..", "mqpcf.parm.len"       , FT_UINT32 , BASE_DEC, NULL, 0x0, "MQPCF parameter length", HFILL }},
655         { &hf_mq_pcf_prmid       , { "ParmID...", "mqpcf.parm.id"        , FT_UINT32 , BASE_DEC | BASE_EXT_STRING, &mq_PrmId_xvals, 0x0, "MQPCF parameter id", HFILL }},
656         { &hf_mq_pcf_prmidnovals , { "ParmID...", "mqpcf.parm.idNoVals"  , FT_UINT32 , BASE_HEX_DEC, NULL, 0x0, "MQPCF parameter id No Vals", HFILL }},
657         { &hf_mq_pcf_filterop    , { "FilterOP.", "mqpcf.filter.op"      , FT_UINT32 , BASE_DEC, VALS(mq_FilterOP_vals), 0x0, "MQPCF Filter operator", HFILL }},
658         { &hf_mq_pcf_prmccsid    , { "ParmCCSID", "mqpcf.parm.ccsid"     , FT_UINT32 , BASE_DEC | BASE_RANGE_STRING, RVALS(mq_ccsid_rvals), 0x0, "MQPCF parameter ccsid", HFILL }},
659         { &hf_mq_pcf_prmstrlen   , { "ParmStrLn", "mqpcf.parm.strlen"    , FT_UINT32 , BASE_DEC, NULL, 0x0, "MQPCF parameter strlen", HFILL }},
660         { &hf_mq_pcf_prmcount    , { "ParmCount", "mqpcf.parm.count"     , FT_UINT32 , BASE_DEC, NULL, 0x0, "MQPCF parameter count", HFILL }},
661         { &hf_mq_pcf_prmunused   , { "ParmUnuse", "mqpcf.parm.unused"    , FT_UINT32 , BASE_DEC, NULL, 0x0, "MQPCF parameter unused", HFILL }},
662         { &hf_mq_pcf_string      , { "String...", "mqpcf.parm.string"    , FT_STRINGZ, BASE_NONE, NULL, 0x0, "MQPCF parameter string", HFILL }},
663         { &hf_mq_pcf_stringlist  , { "StrList..", "mqpcf.parm.stringlist", FT_STRINGZ, BASE_NONE, NULL, 0x0, "MQPCF parameter string list", HFILL }},
664         { &hf_mq_pcf_int         , { "Integer..", "mqpcf.parm.int"       , FT_INT32  , BASE_DEC, NULL, 0x0, "MQPCF parameter int", HFILL }},
665         { &hf_mq_pcf_intlist     , { "IntList..", "mqpcf.parm.intlist"   , FT_INT32  , BASE_DEC, NULL, 0x0, "MQPCF parameter int list", HFILL }},
666         { &hf_mq_pcf_bytestring  , { "ByteStr..", "mqpcf.parm.bytestring", FT_BYTES  , BASE_NONE, NULL, 0x0, "MQPCF parameter byte string", HFILL }},
667         { &hf_mq_pcf_int64       , { "Int64....", "mqpcf.parm.int64"     , FT_INT64  , BASE_DEC, NULL, 0x0, "MQPCF parameter int64", HFILL }},
668         { &hf_mq_pcf_int64list   , { "Int64List", "mqpcf.parm.int64list" , FT_INT64  , BASE_DEC, NULL, 0x0, "MQPCF parameter int64 list", HFILL }},
669     };
670     static gint *ett[] =
671     {
672         &ett_mqpcf,
673         &ett_mqpcf_prm,
674         &ett_mqpcf_cfh,
675     };
676     static ei_register_info ei[] =
677     {
678         { &ei_mq_pcf_prmln0, { "mqpcf.parm.len0"     , PI_MALFORMED, PI_ERROR, "MQPCF Parameter length is 0", EXPFILL }},
679         { &ei_mq_pcf_MaxInt, { "mqpcf.parm.IntList"  , PI_UNDECODED, PI_WARN , "MQPCF Parameter Integer list exhausted", EXPFILL }},
680         { &ei_mq_pcf_MaxStr, { "mqpcf.parm.StrList"  , PI_UNDECODED, PI_WARN , "MQPCF Parameter String list exhausted", EXPFILL }},
681         { &ei_mq_pcf_MaxI64, { "mqpcf.parm.Int64List", PI_UNDECODED, PI_WARN , "MQPCF Parameter Int64 list exhausted", EXPFILL }},
682         { &ei_mq_pcf_MaxPrm, { "mqpcf.parm.MaxPrm"   , PI_UNDECODED, PI_WARN , "MQPCF Max number of parameter exhausted", EXPFILL }},
683         { &ei_mq_pcf_PrmCnt, { "mqpcf.parm.PrmCnt"   , PI_UNDECODED, PI_WARN , "MQPCF Unkn Parm Cnt Length invalid", EXPFILL }},
684     };
685
686     module_t *mq_pcf_module;
687
688     proto_mqpcf = proto_register_protocol("WebSphere MQ Programmable Command Formats", "MQ PCF", "mqpcf");
689     proto_register_field_array(proto_mqpcf, hf, array_length(hf));
690     proto_register_subtree_array(ett, array_length(ett));
691
692     expert_mqpcf = expert_register_protocol(proto_mqpcf);
693     expert_register_field_array(expert_mqpcf, ei, array_length(ei));
694
695     mq_pcf_module = prefs_register_protocol(proto_mqpcf, NULL);
696     prefs_register_uint_preference(mq_pcf_module, "maxprm",
697         "Set the maximun number of parameter in the PCF to decode",
698         "When dissecting PCF there can be a lot of parameters."
699         " You can limit the number of parameter decoded, before it continue with the next PCF.",
700         10, &mq_pcf_maxprm);
701     prefs_register_uint_preference(mq_pcf_module, "maxlst",
702         "Set the maximun number of Parameter List that are displayed",
703         "When dissecting a parameter of a PCFm, if it is a StringList, IntegerList or Integer64 List, "
704         " You can limit the number of element displayed, before it continue with the next Parameter.",
705         10, &mq_pcf_maxlst);
706
707 }
708
709 void proto_reg_handoff_mqpcf(void)
710 {
711     heur_dissector_add("mq", dissect_mqpcf_heur, "WebSphere MQ PCF", "mqpcf_mq", proto_mqpcf, HEURISTIC_ENABLE);
712 }
713
714 /*
715  * Editor modelines - http://www.wireshark.org/tools/modelines.html
716  *
717  * Local variables:
718  * c-basic-offset: 4
719  * tab-width: 8
720  * indent-tabs-mode: nil
721  * End:
722  *
723  * vi: set shiftwidth=4 tabstop=8 expandtab:
724  * :indentSize=4:tabSize=8:noTabs=true:
725  */