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