Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-mq-pcf.c
blob40e7bdc037b5749428e44df6502c5a9ca2a0ed51
1 /* packet-mq-pcf.c
2 * Routines for IBM WebSphere MQ PCF packet dissection
4 * metatech <metatech@flashmail.com>
5 * Robert Grange <robionekenobi@bluewin.ch>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * SPDX-License-Identifier: GPL-2.0-or-later
14 /* MQ PCF in a nutshell
16 * The MQ Programmable Command Formats API allows remotely configuring a queue manager.
18 * MQ PCF documentation is called "WebSphere MQ Programmable Command Formats and Administration Interface"
19 * Formats and Administration Interface"
21 * See:
23 * ftp://public.dhe.ibm.com/software/integration/wmq/docs/V7.0/PDFs/V7.0_2008/csqzak11.pdf
26 #include "config.h"
28 #include <math.h>
30 #include <epan/packet.h>
31 #include <epan/expert.h>
32 #include <epan/prefs.h>
33 #include <epan/strutil.h>
35 #include "packet-mq.h"
37 void proto_register_mqpcf(void);
38 void proto_reg_handoff_mqpcf(void);
40 #define PCF_MAX_PARM 999
41 #define PCF_MAX_LIST 20000
43 static unsigned mq_pcf_maxprm = PCF_MAX_PARM;
44 static unsigned mq_pcf_maxlst = PCF_MAX_LIST;
46 static int proto_mqpcf;
48 static int hf_mqpcf_cfh_type;
49 static int hf_mqpcf_cfh_length;
50 static int hf_mqpcf_cfh_version;
51 static int hf_mqpcf_cfh_command;
52 static int hf_mqpcf_cfh_MsgSeqNbr;
53 static int hf_mqpcf_cfh_control;
54 static int hf_mqpcf_cfh_compcode;
55 static int hf_mqpcf_cfh_reason;
56 static int hf_mqpcf_cfh_ParmCount;
58 static int hf_mq_pcf_prmtyp;
59 static int hf_mq_pcf_prmlen;
60 static int hf_mq_pcf_prmid;
61 static int hf_mq_pcf_prmidnovals;
62 static int hf_mq_pcf_filterop;
63 static int hf_mq_pcf_prmccsid;
64 static int hf_mq_pcf_prmstrlen;
65 static int hf_mq_pcf_prmcount;
66 static int hf_mq_pcf_prmunused;
68 static int hf_mq_pcf_string;
69 static int hf_mq_pcf_stringlist;
70 static int hf_mq_pcf_int;
71 static int hf_mq_pcf_intlist;
72 static int hf_mq_pcf_bytestring;
73 static int hf_mq_pcf_int64;
74 static int hf_mq_pcf_int64list;
76 static expert_field ei_mq_pcf_hdrlne;
77 static expert_field ei_mq_pcf_prmln0;
78 static expert_field ei_mq_pcf_MaxInt;
79 static expert_field ei_mq_pcf_MaxStr;
80 static expert_field ei_mq_pcf_MaxI64;
81 static expert_field ei_mq_pcf_MaxPrm;
82 static expert_field ei_mq_pcf_PrmCnt;
84 static int ett_mqpcf_prm;
85 static int ett_mqpcf_grp;
86 static int ett_mqpcf;
87 static int ett_mqpcf_cfh;
89 #define MQ_TEXT_CFH "MQ Command Format Header"
91 static uint32_t dissect_mqpcf_getDigits(unsigned uCnt)
93 return (uint32_t)(log10((double)uCnt) + 1);
96 * Here we get a special value_string, that return another value_string
97 * pointer instead of string value. This let us use the try_val_to_str
98 * to get val_to_str value from the value of a parameter on a more
99 * easier way than using switch cases.
101 const uint8_t *dissect_mqpcf_parm_getintval(unsigned uPrm, unsigned uVal)
103 const value_string *pVs;
104 pVs = (const value_string *)try_val_to_str_ext(uPrm, GET_VALS_EXTP(MQCFINT_Parse));
106 if (pVs)
108 return (const uint8_t *)try_val_to_str(uVal, pVs);
110 return NULL;
113 static void dissect_mqpcf_parm_int(tvbuff_t *tvb, proto_tree *tree, unsigned offset, unsigned uPrm,
114 unsigned uVal, int hfindex, unsigned iCnt, unsigned iMaxCnt,
115 unsigned iDigit, bool bParse)
117 header_field_info *hfinfo;
118 const uint8_t *pVal = NULL;
120 if (bParse)
121 pVal = dissect_mqpcf_parm_getintval(uPrm, uVal);
123 hfinfo = proto_registrar_get_nth(hfindex);
125 if (iMaxCnt > 1)
127 if (pVal)
129 proto_tree_add_int_format(tree, hfindex, tvb, offset, 4, uVal,
130 "%s[%*d]: %s (%d)", hfinfo->name, iDigit, iCnt, pVal, uVal);
132 else
134 proto_tree_add_int_format(tree, hfindex, tvb, offset, 4, uVal,
135 "%s[%*d]: 0x%08x (%d)", hfinfo->name, iDigit, iCnt, uVal, uVal);
138 else
140 if (pVal)
142 proto_tree_add_int_format_value(tree, hfindex, tvb, offset, 4, uVal,
143 "%s (%d) ", pVal, uVal);
145 else
147 proto_tree_add_int_format_value(tree, hfindex, tvb, offset, 4, uVal,
148 "0x%08x (%d)", uVal, uVal);
153 // NOLINTNEXTLINE(misc-no-recursion)
154 int dissect_mqpcf_parm_grp(tvbuff_t* tvb, packet_info* pinfo, proto_tree* mq_tree,
155 unsigned offset, unsigned bLittleEndian, bool bParse)
157 uint32_t uLen = 0;
158 uint32_t uCnt = 0;
160 uLen = tvb_get_uint32(tvb, offset + 4, bLittleEndian);
161 uCnt = tvb_get_uint32(tvb, offset + 12, bLittleEndian);
163 dissect_mqpcf_parm(tvb, pinfo, mq_tree, offset + uLen, uCnt, bLittleEndian, bParse);
164 offset += uLen;
165 for (uint32_t u = 0; u < uCnt; u++)
167 offset += tvb_get_uint32(tvb, offset + 4, bLittleEndian);
169 offset -= uLen;
171 return offset;
174 // NOLINTNEXTLINE(misc-no-recursion)
175 uint32_t dissect_mqpcf_parm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *mq_tree,
176 unsigned offset, uint32_t uCount, unsigned bLittleEndian, bool bParse)
178 uint32_t u = 0;
179 uint32_t tOfs = 0;
180 uint32_t uLenF;
181 char strPrm[256];
182 uint32_t uTyp;
183 uint32_t uLen = 0;
184 uint32_t uMax = 0;
185 uint32_t uPrm;
186 uint32_t uCnt;
187 uint32_t uCCS;
188 uint32_t uSLn;
189 uint32_t uVal;
190 uint64_t uVal64;
191 uint32_t uDig;
192 uint32_t _offset = offset;
194 static const char *sMaxLst = " Max # of List reached. DECODE interrupted (actual %u of %u)";
195 static const char *sPrmLn0 = " MQPrm[%3u] has a zero length. DECODE Failed (MQPrm Count: %u)";
196 static const char *sHdrLne = " MQPrm[%3u] PCF Header not enough remaining bytes in pdu. DECODE Failed (MQPrm Count: %u)";
197 static const char *sMaxPrm = " Max # of Parm reached. DECODE interrupted (actual %u of %u)";
198 static const char *sPrmCnt = " Cnt=-1 and Length(%u) < 16. DECODE interrupted for elem %u";
200 proto_item *ti = NULL;
201 proto_tree *tree = NULL;
203 if (uCount == (uint32_t)-1)
205 uint32_t xOfs = offset;
207 uCnt = 0;
208 while (tvb_reported_length_remaining(tvb, xOfs) >= 16)
210 uLen = tvb_get_uint32(tvb, xOfs + 4, bLittleEndian);
211 if (uLen < 16)
213 proto_tree_add_expert_format(tree, pinfo, &ei_mq_pcf_PrmCnt, tvb, xOfs, 16, sPrmCnt, uLen, uCnt);
214 break;
216 uCnt++;
217 xOfs += uLen;
219 uCount = uCnt;
222 uDig = dissect_mqpcf_getDigits(uCount);
223 for (u = 0; u < uCount && u < mq_pcf_maxprm; u++)
225 tOfs = offset;
226 uMax = (unsigned)tvb_reported_length_remaining(tvb, tOfs);
227 if (uMax < 12)
229 proto_tree_add_expert_format(tree, pinfo, &ei_mq_pcf_hdrlne, tvb, offset, 12, sHdrLne, u + 1, uCount);
230 u = uCount;
231 break;
233 uTyp = tvb_get_uint32(tvb, offset, bLittleEndian);
234 uLen = tvb_get_uint32(tvb, offset + 4, bLittleEndian);
235 if (uLen == 0)
237 proto_tree_add_expert_format(tree, pinfo, &ei_mq_pcf_prmln0, tvb, offset, 12, sPrmLn0, u + 1, uCount);
238 u = uCount;
239 break;
241 /* Try to decode as much as possible value */
242 uLen = MIN(uLen, uMax);
244 uPrm = tvb_get_uint32(tvb, offset + 8, bLittleEndian);
245 uLenF = 12;
247 if (bParse)
248 snprintf(strPrm, sizeof(strPrm) - 1, " %-s[%*u] {%2d-%-4.4s} 0x%08x (%4d) %-30.30s",
249 "MQPrm", uDig, u + 1,
250 uTyp, val_to_str_ext_const(uTyp, GET_VALS_EXTP(PrmTyp2), " Unkn") + 6,
251 uPrm, uPrm, val_to_str_ext_const(uPrm, GET_VALS_EXTP(PrmId), "Unknown"));
252 else
253 snprintf(strPrm, sizeof(strPrm) - 1, " %-s[%*u] {%2d-%-4.4s} 0x%08x (%4d)",
254 "XtraD", uDig, u + 1,
255 uTyp, val_to_str_ext_const(uTyp, GET_VALS_EXTP(PrmTyp2), " Unkn") + 6,
256 uPrm, uPrm);
258 increment_dissection_depth(pinfo);
259 switch (uTyp)
261 case MQ_MQCFT_NONE:
262 break;
263 case MQ_MQCFT_COMMAND:
264 break;
265 case MQ_MQCFT_RESPONSE:
266 break;
267 case MQ_MQCFT_INTEGER:
269 const uint8_t *pVal = NULL;
270 uVal = tvb_get_uint32(tvb, offset + uLenF, bLittleEndian);
271 if (bParse)
272 pVal = dissect_mqpcf_parm_getintval(uPrm, uVal);
274 if (pVal)
276 tree = proto_tree_add_subtree_format(mq_tree, tvb, offset, uLen, ett_mqpcf_prm, NULL,
277 "%s: %s (%d)", strPrm, pVal, uVal);
279 else
281 tree = proto_tree_add_subtree_format(mq_tree, tvb, offset, uLen, ett_mqpcf_prm, NULL,
282 "%s: 0x%08x (%d)", strPrm, uVal, uVal);
285 proto_tree_add_item(tree, hf_mq_pcf_prmtyp, tvb, offset, 4, bLittleEndian);
286 proto_tree_add_item(tree, hf_mq_pcf_prmlen, tvb, offset + 4, 4, bLittleEndian);
287 proto_tree_add_item(tree, (bParse) ? hf_mq_pcf_prmid : hf_mq_pcf_prmidnovals, tvb, offset + 8, 4, bLittleEndian);
289 dissect_mqpcf_parm_int(tvb, tree, offset + uLenF, uPrm, uVal, hf_mq_pcf_int, 0, 0, 0, bParse);
291 break;
292 case MQ_MQCFT_STRING:
294 uint8_t *sStr;
296 uCCS = tvb_get_uint32(tvb, offset + uLenF, bLittleEndian);
297 uSLn = tvb_get_uint32(tvb, offset + uLenF + 4, bLittleEndian);
298 sStr = tvb_get_string_enc(pinfo->pool, tvb, offset + uLenF + 8,
299 uSLn, IS_EBCDIC(uCCS) ? ENC_EBCDIC : ENC_ASCII);
300 if (*sStr)
301 strip_trailing_blanks(sStr, uSLn);
302 if (*sStr)
303 sStr = (uint8_t*)format_text_chr(pinfo->pool, sStr, strlen((const char *)sStr), '.');
305 tree = proto_tree_add_subtree_format(mq_tree, tvb, offset, uLen, ett_mqpcf_prm, NULL, "%s: %s", strPrm, sStr);
307 proto_tree_add_item(tree, hf_mq_pcf_prmtyp, tvb, offset, 4, bLittleEndian);
308 proto_tree_add_item(tree, hf_mq_pcf_prmlen, tvb, offset + 4, 4, bLittleEndian);
309 proto_tree_add_item(tree, (bParse) ? hf_mq_pcf_prmid : hf_mq_pcf_prmidnovals, tvb, offset + 8, 4, bLittleEndian);
310 proto_tree_add_item(tree, hf_mq_pcf_prmccsid, tvb, offset + 12, 4, bLittleEndian);
311 proto_tree_add_item(tree, hf_mq_pcf_prmstrlen, tvb, offset + 16, 4, bLittleEndian);
313 proto_tree_add_item(tree, hf_mq_pcf_string, tvb, offset + uLenF + 8, uSLn, IS_EBCDIC(uCCS) ? ENC_EBCDIC : ENC_ASCII);
315 break;
316 case MQ_MQCFT_INTEGER_LIST:
318 uint32_t u2;
319 uint32_t uDigit = 0;
321 uCnt = tvb_get_uint32(tvb, offset + uLenF, bLittleEndian);
322 uDigit = dissect_mqpcf_getDigits(uCnt);
324 tree = proto_tree_add_subtree_format(mq_tree, tvb, offset, uLen, ett_mqpcf_prm, &ti, "%s-> contain %d Element(s)", strPrm, uCnt);
326 proto_tree_add_item(tree, hf_mq_pcf_prmtyp, tvb, offset, 4, bLittleEndian);
327 proto_tree_add_item(tree, hf_mq_pcf_prmlen, tvb, offset + 4, 4, bLittleEndian);
328 proto_tree_add_item(tree, (bParse) ? hf_mq_pcf_prmid : hf_mq_pcf_prmidnovals, tvb, offset + 8, 4, bLittleEndian);
329 proto_tree_add_item(tree, hf_mq_pcf_prmcount, tvb, offset + 12, 4, bLittleEndian);
331 offset += uLenF + 4;
332 for (u2 = 0; u2 < uCnt && u2 < mq_pcf_maxlst; u2++)
334 uVal = tvb_get_uint32(tvb, offset, bLittleEndian);
335 dissect_mqpcf_parm_int(tvb, tree, offset, uPrm, uVal, hf_mq_pcf_intlist, u2 + 1, uCnt, uDigit, bParse);
336 offset += 4;
338 if (u2 != uCnt)
340 proto_tree_add_expert_format(tree, pinfo, &ei_mq_pcf_MaxInt, tvb, offset, (uCnt - u2) * 4, sMaxLst, u2, uCnt);
343 break;
344 case MQ_MQCFT_STRING_LIST:
346 uint32_t u2;
347 uint32_t uDigit;
348 uint8_t *sStr;
349 header_field_info *hfinfo;
351 hfinfo = proto_registrar_get_nth(hf_mq_pcf_stringlist);
353 uCCS = tvb_get_uint32(tvb, offset + uLenF, bLittleEndian);
354 uCnt = tvb_get_uint32(tvb, offset + uLenF + 4, bLittleEndian);
355 uSLn = tvb_get_uint32(tvb, offset + uLenF + 8, bLittleEndian);
357 tree = proto_tree_add_subtree_format(mq_tree, tvb, offset, uLen, ett_mqpcf_prm, NULL, "%s-> contain %d Element(s)", strPrm, uCnt);
359 proto_tree_add_item(tree, hf_mq_pcf_prmtyp, tvb, offset, 4, bLittleEndian);
360 proto_tree_add_item(tree, hf_mq_pcf_prmlen, tvb, offset + 4, 4, bLittleEndian);
361 proto_tree_add_item(tree, (bParse) ? hf_mq_pcf_prmid : hf_mq_pcf_prmidnovals, tvb, offset + 8, 4, bLittleEndian);
362 proto_tree_add_item(tree, hf_mq_pcf_prmccsid, tvb, offset + 12, 4, bLittleEndian);
363 proto_tree_add_item(tree, hf_mq_pcf_prmcount, tvb, offset + 16, 4, bLittleEndian);
364 proto_tree_add_item(tree, hf_mq_pcf_prmstrlen, tvb, offset + 20, 4, bLittleEndian);
366 uDigit = dissect_mqpcf_getDigits(uCnt);
368 offset += uLenF + 12;
369 for (u2 = 0; u2 < uCnt && u2 < mq_pcf_maxlst; u2++)
371 sStr = tvb_get_string_enc(pinfo->pool, tvb, offset,
372 uSLn, IS_EBCDIC(uCCS) ? ENC_EBCDIC : ENC_ASCII);
373 if (*sStr)
374 strip_trailing_blanks(sStr, uSLn);
375 if (*sStr)
376 sStr = (uint8_t*)format_text_chr(pinfo->pool, sStr, strlen((const char *)sStr), '.');
378 proto_tree_add_string_format(tree, hf_mq_pcf_stringlist, tvb, offset, uSLn, (const char *)sStr,
379 "%s[%*d]: %s", hfinfo->name, uDigit, u2 + 1, sStr);
380 offset += uSLn;
382 if (u2 != uCnt)
384 proto_tree_add_expert_format(tree, pinfo, &ei_mq_pcf_MaxStr, tvb, offset, (uCnt - u2) * uSLn, sMaxLst, u2, uCnt);
387 break;
388 case MQ_MQCFT_GROUP:
390 uCnt = tvb_get_uint32(tvb, offset + 12, bLittleEndian);
392 tree = proto_tree_add_subtree_format(mq_tree, tvb, offset, uLen, ett_mqpcf_prm, &ti, "%s-> contain %d Element(s)", strPrm, uCnt);
394 proto_tree_add_item(tree, hf_mq_pcf_prmtyp, tvb, offset, 4, bLittleEndian);
395 proto_tree_add_item(tree, hf_mq_pcf_prmlen, tvb, offset + 4, 4, bLittleEndian);
396 proto_tree_add_item(tree, (bParse) ? hf_mq_pcf_prmid : hf_mq_pcf_prmidnovals, tvb, offset + 8, 4, bLittleEndian);
397 proto_tree_add_item(tree, hf_mq_pcf_prmcount, tvb, offset + 12, 4, bLittleEndian);
399 tOfs = dissect_mqpcf_parm_grp(tvb, pinfo, tree, offset, bLittleEndian, bParse);
401 break;
402 case MQ_MQCFT_EVENT:
403 break;
404 case MQ_MQCFT_USER:
406 tree = proto_tree_add_subtree(mq_tree, tvb, offset, uLen, ett_mqpcf_prm, NULL, strPrm);
408 proto_tree_add_item(tree, hf_mq_pcf_prmtyp, tvb, offset, 4, bLittleEndian);
409 proto_tree_add_item(tree, hf_mq_pcf_prmlen, tvb, offset + 4, 4, bLittleEndian);
410 proto_tree_add_item(tree, hf_mq_pcf_bytestring, tvb, offset + 8, uLen - 8, bLittleEndian);
412 break;
413 case MQ_MQCFT_BYTE_STRING:
415 uSLn = tvb_get_uint32(tvb, offset + uLenF, bLittleEndian);
416 if (uSLn)
418 uint8_t *sStrA = (uint8_t *)format_text_chr(pinfo->pool, tvb_get_string_enc(pinfo->pool, tvb, offset + uLenF + 4, uSLn, ENC_ASCII), uSLn, '.');
419 uint8_t *sStrE = (uint8_t *)format_text_chr(pinfo->pool, tvb_get_string_enc(pinfo->pool, tvb, offset + uLenF + 4, uSLn, ENC_EBCDIC), uSLn, '.');
420 if (uSLn > 35)
422 tree = proto_tree_add_subtree_format(mq_tree, tvb, offset, uLen, ett_mqpcf_prm, NULL,
423 "%s: [Truncated] A(%-.35s) E(%-.35s)", strPrm, sStrA, sStrE);
425 else
427 tree = proto_tree_add_subtree_format(mq_tree, tvb, offset, uLen, ett_mqpcf_prm, NULL,
428 "%s: A(%s) E(%s)", strPrm, sStrA, sStrE);
431 else
433 tree = proto_tree_add_subtree_format(mq_tree, tvb, offset, uLen, ett_mqpcf_prm, NULL, "%s <MISSING>", strPrm);
436 proto_tree_add_item(tree, hf_mq_pcf_prmtyp, tvb, offset, 4, bLittleEndian);
437 proto_tree_add_item(tree, hf_mq_pcf_prmlen, tvb, offset + 4, 4, bLittleEndian);
438 proto_tree_add_item(tree, (bParse) ? hf_mq_pcf_prmid : hf_mq_pcf_prmidnovals, tvb, offset + 8, 4, bLittleEndian);
439 proto_tree_add_item(tree, hf_mq_pcf_prmstrlen, tvb, offset + 12, 4, bLittleEndian);
441 proto_tree_add_item(tree, hf_mq_pcf_bytestring, tvb, offset + uLenF + 4, uSLn, bLittleEndian);
443 break;
444 case MQ_MQCFT_TRACE_ROUTE:
445 break;
446 case MQ_MQCFT_REPORT:
447 break;
448 case MQ_MQCFT_INTEGER_FILTER:
450 uint32_t uOpe;
452 uOpe = tvb_get_uint32(tvb, offset + uLenF, bLittleEndian);
453 uVal = tvb_get_uint32(tvb, offset + uLenF + 4, bLittleEndian);
455 tree = proto_tree_add_subtree_format(mq_tree, tvb, offset, uLen, ett_mqpcf_prm, NULL, "%s: %s 0x%08x (%d)",
456 strPrm, val_to_str(uOpe, GET_VALSV(FilterOP), " Unknown (0x%02x)") + 7, uVal, uVal);
458 proto_tree_add_item(tree, hf_mq_pcf_prmtyp, tvb, offset, 4, bLittleEndian);
459 proto_tree_add_item(tree, hf_mq_pcf_prmlen, tvb, offset + 4, 4, bLittleEndian);
460 proto_tree_add_item(tree, (bParse) ? hf_mq_pcf_prmid : hf_mq_pcf_prmidnovals, tvb, offset + 8, 4, bLittleEndian);
461 proto_tree_add_item(tree, hf_mq_pcf_filterop, tvb, offset + 12, 4, bLittleEndian);
463 proto_tree_add_item(tree, hf_mq_pcf_int, tvb, offset + uLenF + 4, 4, bLittleEndian);
465 break;
466 case MQ_MQCFT_STRING_FILTER:
468 uint8_t *sStr;
469 uint32_t uOpe;
471 uOpe = tvb_get_uint32(tvb, offset + uLenF, bLittleEndian);
472 uCCS = tvb_get_uint32(tvb, offset + uLenF + 4, bLittleEndian);
473 uSLn = tvb_get_uint32(tvb, offset + uLenF + 8, bLittleEndian);
474 sStr = (uint8_t *)format_text_chr(pinfo->pool,
475 tvb_get_string_enc(pinfo->pool, tvb, offset + uLenF + 12, uSLn, IS_EBCDIC(uCCS) ? ENC_EBCDIC : ENC_ASCII),
476 uSLn, '.');
477 strip_trailing_blanks(sStr, uSLn);
479 tree = proto_tree_add_subtree_format(mq_tree, tvb, offset, uLen, ett_mqpcf_prm, NULL, "%s: %s %s",
480 strPrm, val_to_str(uOpe, GET_VALSV(FilterOP), " Unknown (0x%02x)") + 7, sStr);
482 proto_tree_add_item(tree, hf_mq_pcf_prmtyp, tvb, offset, 4, bLittleEndian);
483 proto_tree_add_item(tree, hf_mq_pcf_prmlen, tvb, offset + 4, 4, bLittleEndian);
484 proto_tree_add_item(tree, (bParse) ? hf_mq_pcf_prmid : hf_mq_pcf_prmidnovals, tvb, offset + 8, 4, bLittleEndian);
485 proto_tree_add_item(tree, hf_mq_pcf_filterop, tvb, offset + 12, 4, bLittleEndian);
486 proto_tree_add_item(tree, hf_mq_pcf_prmccsid, tvb, offset + 16, 4, bLittleEndian);
487 proto_tree_add_item(tree, hf_mq_pcf_prmstrlen, tvb, offset + 20, 4, bLittleEndian);
489 proto_tree_add_item(tree, hf_mq_pcf_string, tvb, offset + uLenF + 12, uSLn, IS_EBCDIC(uCCS) ? ENC_EBCDIC : ENC_ASCII);
491 break;
492 case MQ_MQCFT_BYTE_STRING_FILTER:
494 uint32_t uOpe;
495 uOpe = tvb_get_uint32(tvb, offset + uLenF, bLittleEndian);
496 uSLn = tvb_get_uint32(tvb, offset + uLenF + 4, bLittleEndian);
497 if (uSLn)
499 uint8_t *sStrA = (uint8_t *)format_text_chr(pinfo->pool, tvb_get_string_enc(pinfo->pool, tvb, offset + uLenF + 8, uSLn, ENC_ASCII), uSLn, '.');
500 uint8_t *sStrE = (uint8_t *)format_text_chr(pinfo->pool, tvb_get_string_enc(pinfo->pool, tvb, offset + uLenF + 8, uSLn, ENC_EBCDIC), uSLn, '.');
501 tree = proto_tree_add_subtree_format(mq_tree, tvb, offset, uLen, ett_mqpcf_prm, NULL, "%s: %s A(%s) E(%s)",
502 strPrm, val_to_str(uOpe, GET_VALSV(FilterOP), " Unknown (0x%02x)") + 7, sStrA, sStrE);
504 else
506 tree = proto_tree_add_subtree_format(mq_tree, tvb, offset, uLen, ett_mqpcf_prm, NULL, "%s: %s <MISSING>",
507 strPrm, val_to_str(uOpe, GET_VALSV(FilterOP), " Unknown (0x%02x)") + 7);
510 proto_tree_add_item(tree, hf_mq_pcf_prmtyp, tvb, offset, 4, bLittleEndian);
511 proto_tree_add_item(tree, hf_mq_pcf_prmlen, tvb, offset + 4, 4, bLittleEndian);
512 proto_tree_add_item(tree, (bParse) ? hf_mq_pcf_prmid : hf_mq_pcf_prmidnovals, tvb, offset + 8, 4, bLittleEndian);
513 proto_tree_add_item(tree, hf_mq_pcf_filterop, tvb, offset + 12, 4, bLittleEndian);
514 proto_tree_add_item(tree, hf_mq_pcf_prmstrlen, tvb, offset + 16, 4, bLittleEndian);
516 proto_tree_add_item(tree, hf_mq_pcf_bytestring, tvb, offset + uLenF + 8, uSLn, bLittleEndian);
518 break;
519 case MQ_MQCFT_COMMAND_XR:
520 break;
521 case MQ_MQCFT_XR_MSG:
522 break;
523 case MQ_MQCFT_XR_ITEM:
524 break;
525 case MQ_MQCFT_XR_SUMMARY:
526 break;
527 case MQ_MQCFT_STATISTICS:
528 break;
529 case MQ_MQCFT_ACCOUNTING:
530 break;
531 case MQ_MQCFT_INTEGER64:
533 uVal64 = tvb_get_uint64(tvb, offset + uLenF + 4, bLittleEndian);
534 tree = proto_tree_add_subtree_format(mq_tree, tvb, offset, uLen, ett_mqpcf_prm, NULL,
535 "%s: 0x%" PRIx64 " (%" PRId64 ")", strPrm, uVal64, uVal64);
537 proto_tree_add_item(tree, hf_mq_pcf_prmtyp, tvb, offset, 4, bLittleEndian);
538 proto_tree_add_item(tree, hf_mq_pcf_prmlen, tvb, offset + 4, 4, bLittleEndian);
539 proto_tree_add_item(tree, (bParse) ? hf_mq_pcf_prmid : hf_mq_pcf_prmidnovals, tvb, offset + 8, 4, bLittleEndian);
540 proto_tree_add_item(tree, hf_mq_pcf_prmunused, tvb, offset + 12, 4, bLittleEndian);
542 proto_tree_add_item(tree, hf_mq_pcf_int64, tvb, offset + uLenF + 4, 8, bLittleEndian);
544 break;
545 case MQ_MQCFT_INTEGER64_LIST:
547 uint32_t u2;
548 uint32_t uDigit;
549 header_field_info *hfinfo;
551 hfinfo = proto_registrar_get_nth(hf_mq_pcf_int64list);
553 uCnt = tvb_get_uint32(tvb, offset + uLenF, bLittleEndian);
554 tree = proto_tree_add_subtree_format(mq_tree, tvb, offset, uLen, ett_mqpcf_prm, NULL, "%s-> contain %d Element(s)", strPrm, uCnt);
555 uDigit = dissect_mqpcf_getDigits(uCnt);
557 proto_tree_add_item(tree, hf_mq_pcf_prmtyp, tvb, offset, 4, bLittleEndian);
558 proto_tree_add_item(tree, hf_mq_pcf_prmlen, tvb, offset + 4, 4, bLittleEndian);
559 proto_tree_add_item(tree, (bParse) ? hf_mq_pcf_prmid : hf_mq_pcf_prmidnovals, tvb, offset + 8, 4, bLittleEndian);
560 proto_tree_add_item(tree, hf_mq_pcf_prmcount, tvb, offset + 12, 4, bLittleEndian);
562 offset += uLenF + 4;
563 for (u2 = 0; u2 < uCnt && u2 < mq_pcf_maxlst; u2++)
565 uVal64 = tvb_get_uint64(tvb, offset, bLittleEndian);
566 proto_tree_add_int64_format(tree, hf_mq_pcf_int64list, tvb, offset, 8, uVal64,
567 "%s[%*d]: 0x%" PRIx64 " (%" PRId64 ")",
568 hfinfo->name, uDigit, u2 + 1, uVal64, uVal64);
569 offset += 8;
571 if (u2 != uCnt)
573 proto_tree_add_expert_format(tree, pinfo, &ei_mq_pcf_MaxI64, tvb, offset, (uCnt - u2) * 8, sMaxLst, u2, uCnt);
576 break;
578 decrement_dissection_depth(pinfo);
579 offset = tOfs + uLen;
581 if (u != uCount)
583 proto_tree_add_expert_format(mq_tree, pinfo, &ei_mq_pcf_MaxPrm, tvb, offset, tvb_reported_length_remaining(tvb, offset), sMaxPrm, u, uCount);
585 return offset - _offset;
588 static void dissect_mqpcf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, mq_parm_t* p_mq_parm)
590 int offset = 0;
591 unsigned bLittleEndian;
593 bLittleEndian = ((p_mq_parm->mq_cur_ccsid.encod & MQ_MQENC_INTEGER_MASK) == MQ_MQENC_INTEGER_REVERSED) ? ENC_LITTLE_ENDIAN : ENC_BIG_ENDIAN;
595 if (tvb_reported_length(tvb) >= 36)
597 int iSizeMQCFH = 36;
598 uint32_t iCommand = tvb_get_uint32(tvb, offset + 12, bLittleEndian);
600 if (tree)
602 proto_item *ti;
603 proto_tree *mq_tree;
604 proto_tree *mqroot_tree;
605 char sTmp[256];
606 uint32_t uCnt;
607 uint32_t uTyp;
608 uint32_t uCmd;
609 uint32_t uCC;
610 uint32_t uRC;
612 uTyp = tvb_get_uint32(tvb, offset, bLittleEndian);
613 uCmd = tvb_get_uint32(tvb, offset + 12, bLittleEndian);
614 uCC = tvb_get_uint32(tvb, offset + 24, bLittleEndian);
615 uRC = tvb_get_uint32(tvb, offset + 28, bLittleEndian);
616 uCnt = tvb_get_uint32(tvb, offset + 32, bLittleEndian);
618 if (uCC || uRC)
620 snprintf(sTmp, sizeof(sTmp) - 1, " %-s [%d-%s] {%d-%s} PrmCnt(%d) CC(%d-%s) RC(%d-%s)",
621 MQ_TEXT_CFH,
622 uTyp, val_to_str_const(uTyp, GET_VALSV(mqcft), "Unknown"),
623 uCmd, val_to_str_ext_const(uCmd, GET_VALS_EXTP(MQCMD), "Unknown"),
624 uCnt,
625 uCC, val_to_str_const(uCC, GET_VALSV(mqcc), "Unknown"),
626 uRC, val_to_str_ext_const(uRC, GET_VALS_EXTP(MQRC), "Unknown"));
628 else
630 snprintf(sTmp, sizeof(sTmp) - 1, " %-s [%d-%s] {%d-%s} PrmCnt(%d)",
631 MQ_TEXT_CFH,
632 uTyp, val_to_str_const(uTyp, GET_VALSV(mqcft), "Unknown"),
633 uCmd, val_to_str_ext_const(uCmd, GET_VALS_EXTP(MQCMD), "Unknown"),
634 uCnt);
637 ti = proto_tree_add_item(tree, proto_mqpcf, tvb, offset, -1, ENC_NA);
639 proto_item_append_text(ti, " (%s)", val_to_str_ext(iCommand, GET_VALS_EXTP(MQCMD), "Unknown (0x%02x)"));
640 mqroot_tree = proto_item_add_subtree(ti, ett_mqpcf);
642 mq_tree = proto_tree_add_subtree(mqroot_tree, tvb, offset, iSizeMQCFH, ett_mqpcf_cfh, NULL, sTmp);
644 proto_tree_add_item(mq_tree, hf_mqpcf_cfh_type, tvb, offset + 0, 4, bLittleEndian);
645 proto_tree_add_item(mq_tree, hf_mqpcf_cfh_length, tvb, offset + 4, 4, bLittleEndian);
646 proto_tree_add_item(mq_tree, hf_mqpcf_cfh_version, tvb, offset + 8, 4, bLittleEndian);
647 proto_tree_add_item(mq_tree, hf_mqpcf_cfh_command, tvb, offset + 12, 4, bLittleEndian);
648 proto_tree_add_item(mq_tree, hf_mqpcf_cfh_MsgSeqNbr, tvb, offset + 16, 4, bLittleEndian);
649 proto_tree_add_item(mq_tree, hf_mqpcf_cfh_control, tvb, offset + 20, 4, bLittleEndian);
650 proto_tree_add_item(mq_tree, hf_mqpcf_cfh_compcode, tvb, offset + 24, 4, bLittleEndian);
651 proto_tree_add_item(mq_tree, hf_mqpcf_cfh_reason, tvb, offset + 28, 4, bLittleEndian);
652 proto_tree_add_item(mq_tree, hf_mqpcf_cfh_ParmCount, tvb, offset + 32, 4, bLittleEndian);
653 dissect_mqpcf_parm(tvb, pinfo, mqroot_tree, offset + iSizeMQCFH, uCnt, bLittleEndian, true);
658 static bool dissect_mqpcf_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
660 if (data && tvb_reported_length(tvb) >= 36)
662 mq_parm_t *p_mq_parm = (mq_parm_t *)data;
663 if (strncmp((const char*)p_mq_parm->mq_format, MQ_MQFMT_ADMIN, 8) == 0
664 || strncmp((const char*)p_mq_parm->mq_format, MQ_MQFMT_EVENT, 8) == 0
665 || strncmp((const char*)p_mq_parm->mq_format, MQ_MQFMT_PCF, 8) == 0)
667 /* Dissect the packet */
668 dissect_mqpcf(tvb, pinfo, tree, p_mq_parm);
669 return true;
671 if (strncmp((const char *)p_mq_parm->mq_format, "LPOO", 4) == 0)
673 unsigned bLittleEndian;
674 bLittleEndian = ((p_mq_parm->mq_cur_ccsid.encod & MQ_MQENC_INTEGER_MASK) == MQ_MQENC_INTEGER_REVERSED) ? ENC_LITTLE_ENDIAN : ENC_BIG_ENDIAN;
675 dissect_mqpcf_parm(tvb, pinfo, tree, 0, (uint32_t)-1, bLittleEndian, false);
676 return true;
679 return false;
682 void proto_register_mqpcf(void)
684 expert_module_t *expert_mqpcf;
686 static hf_register_info hf[] =
688 { &hf_mqpcf_cfh_type , { "Type.....", "mqpcf.cfh.type" , FT_UINT32, BASE_DEC, VALS(mq_mqcft_vals), 0x0, "CFH type", HFILL }},
689 { &hf_mqpcf_cfh_length , { "Length...", "mqpcf.cfh.length" , FT_UINT32, BASE_DEC, NULL, 0x0, "CFH length", HFILL }},
690 { &hf_mqpcf_cfh_version , { "Version..", "mqpcf.cfh.version" , FT_UINT32, BASE_DEC, NULL, 0x0, "CFH version", HFILL }},
691 { &hf_mqpcf_cfh_command , { "Command..", "mqpcf.cfh.command" , FT_UINT32, BASE_DEC | BASE_EXT_STRING, GET_VALS_EXTP(MQCMD), 0x0, "CFH command", HFILL }},
692 { &hf_mqpcf_cfh_MsgSeqNbr, { "MsgSeqNbr", "mqpcf.cfh.MsgSeqNbr" , FT_UINT32, BASE_DEC, NULL, 0x0, "CFH message sequence number", HFILL }},
693 { &hf_mqpcf_cfh_control , { "Control..", "mqpcf.cfh.control" , FT_UINT32, BASE_DEC, VALS(mq_CtlOpt_vals), 0x0, "CFH control", HFILL }},
694 { &hf_mqpcf_cfh_compcode , { "CompCode.", "mqpcf.cfh.compcode" , FT_UINT32, BASE_DEC, VALS(mq_mqcc_vals), 0x0, "CFH completion code", HFILL }},
695 { &hf_mqpcf_cfh_reason , { "ReasCode.", "mqpcf.cfh.reasoncode", FT_UINT32, BASE_DEC | BASE_EXT_STRING, GET_VALS_EXTP(MQRC), 0x0, "CFH reason code", HFILL }},
696 { &hf_mqpcf_cfh_ParmCount, { "ParmCount", "mqpcf.cfh.ParmCount" , FT_UINT32, BASE_DEC, NULL, 0x0, "CFH parameter count", HFILL }},
698 { &hf_mq_pcf_prmtyp , { "ParmTyp..", "mqpcf.parm.type" , FT_UINT32 , BASE_DEC | BASE_EXT_STRING, GET_VALS_EXTP(PrmTyp), 0x0, "MQPCF parameter type", HFILL }},
699 { &hf_mq_pcf_prmlen , { "ParmLen..", "mqpcf.parm.len" , FT_UINT32 , BASE_DEC, NULL, 0x0, "MQPCF parameter length", HFILL }},
700 { &hf_mq_pcf_prmid , { "ParmID...", "mqpcf.parm.id" , FT_UINT32 , BASE_DEC | BASE_EXT_STRING, GET_VALS_EXTP(PrmId), 0x0, "MQPCF parameter id", HFILL }},
701 { &hf_mq_pcf_prmidnovals , { "ParmID...", "mqpcf.parm.idNoVals" , FT_UINT32 , BASE_HEX_DEC, NULL, 0x0, "MQPCF parameter id No Vals", HFILL }},
702 { &hf_mq_pcf_filterop , { "FilterOP.", "mqpcf.filter.op" , FT_UINT32 , BASE_DEC, VALS(mq_FilterOP_vals), 0x0, "MQPCF Filter operator", HFILL }},
703 { &hf_mq_pcf_prmccsid , { "ParmCCSID", "mqpcf.parm.ccsid" , FT_UINT32 , BASE_DEC | BASE_RANGE_STRING, RVALS(mq_ccsid_rvals), 0x0, "MQPCF parameter ccsid", HFILL }},
704 { &hf_mq_pcf_prmstrlen , { "ParmStrLn", "mqpcf.parm.strlen" , FT_UINT32 , BASE_DEC, NULL, 0x0, "MQPCF parameter strlen", HFILL }},
705 { &hf_mq_pcf_prmcount , { "ParmCount", "mqpcf.parm.count" , FT_UINT32 , BASE_DEC, NULL, 0x0, "MQPCF parameter count", HFILL }},
706 { &hf_mq_pcf_prmunused , { "ParmUnuse", "mqpcf.parm.unused" , FT_UINT32 , BASE_DEC, NULL, 0x0, "MQPCF parameter unused", HFILL }},
707 { &hf_mq_pcf_string , { "String...", "mqpcf.parm.string" , FT_STRING, BASE_NONE, NULL, 0x0, "MQPCF parameter string", HFILL }},
708 { &hf_mq_pcf_stringlist , { "StrList..", "mqpcf.parm.stringlist", FT_STRING, BASE_NONE, NULL, 0x0, "MQPCF parameter string list", HFILL }},
709 { &hf_mq_pcf_int , { "Integer..", "mqpcf.parm.int" , FT_INT32 , BASE_DEC, NULL, 0x0, "MQPCF parameter int", HFILL }},
710 { &hf_mq_pcf_intlist , { "IntList..", "mqpcf.parm.intlist" , FT_INT32 , BASE_DEC, NULL, 0x0, "MQPCF parameter int list", HFILL }},
711 { &hf_mq_pcf_bytestring , { "ByteStr..", "mqpcf.parm.bytestring", FT_BYTES , BASE_NONE, NULL, 0x0, "MQPCF parameter byte string", HFILL }},
712 { &hf_mq_pcf_int64 , { "Int64....", "mqpcf.parm.int64" , FT_INT64 , BASE_DEC, NULL, 0x0, "MQPCF parameter int64", HFILL }},
713 { &hf_mq_pcf_int64list , { "Int64List", "mqpcf.parm.int64list" , FT_INT64 , BASE_DEC, NULL, 0x0, "MQPCF parameter int64 list", HFILL }},
715 static int *ett[] =
717 &ett_mqpcf,
718 &ett_mqpcf_prm,
719 &ett_mqpcf_grp,
720 &ett_mqpcf_cfh,
722 static ei_register_info ei[] =
724 { &ei_mq_pcf_prmln0, { "mqpcf.parm.len0" , PI_MALFORMED, PI_ERROR, "MQPCF Parameter length is 0", EXPFILL }},
725 { &ei_mq_pcf_hdrlne, { "mqpcf.parm.hdrlenerr", PI_MALFORMED, PI_ERROR, "MQPCF Header not enough bytes in pdu", EXPFILL}},
726 { &ei_mq_pcf_MaxInt, { "mqpcf.parm.IntList" , PI_UNDECODED, PI_WARN , "MQPCF Parameter Integer list exhausted", EXPFILL }},
727 { &ei_mq_pcf_MaxStr, { "mqpcf.parm.StrList" , PI_UNDECODED, PI_WARN , "MQPCF Parameter String list exhausted", EXPFILL }},
728 { &ei_mq_pcf_MaxI64, { "mqpcf.parm.Int64List", PI_UNDECODED, PI_WARN , "MQPCF Parameter Int64 list exhausted", EXPFILL }},
729 { &ei_mq_pcf_MaxPrm, { "mqpcf.parm.MaxPrm" , PI_UNDECODED, PI_WARN , "MQPCF Max number of parameter exhausted", EXPFILL }},
730 { &ei_mq_pcf_PrmCnt, { "mqpcf.parm.PrmCnt" , PI_UNDECODED, PI_WARN , "MQPCF Unkn Parm Cnt Length invalid", EXPFILL }},
733 module_t *mq_pcf_module;
735 proto_mqpcf = proto_register_protocol("WebSphere MQ Programmable Command Formats", "MQ PCF", "mqpcf");
736 proto_register_field_array(proto_mqpcf, hf, array_length(hf));
737 proto_register_subtree_array(ett, array_length(ett));
739 expert_mqpcf = expert_register_protocol(proto_mqpcf);
740 expert_register_field_array(expert_mqpcf, ei, array_length(ei));
742 mq_pcf_module = prefs_register_protocol(proto_mqpcf, NULL);
743 prefs_register_uint_preference(mq_pcf_module, "maxprm",
744 "Set the maximum number of parameters in the PCF to decode",
745 "When dissecting PCF there can be a lot of parameters."
746 " You can limit the number of parameter decoded, before it continue with the next PCF.",
747 10, &mq_pcf_maxprm);
748 prefs_register_uint_preference(mq_pcf_module, "maxlst",
749 "Set the maximum number of Parameter List that are displayed",
750 "When dissecting a parameter of a PCFm, if it is a StringList, IntegerList or Integer64 List, "
751 " You can limit the number of elements displayed, before it continues with the next Parameter.",
752 10, &mq_pcf_maxlst);
756 void proto_reg_handoff_mqpcf(void)
758 heur_dissector_add("mq", dissect_mqpcf_heur, "WebSphere MQ PCF", "mqpcf_mq", proto_mqpcf, HEURISTIC_ENABLE);
762 * Editor modelines - https://www.wireshark.org/tools/modelines.html
764 * Local variables:
765 * c-basic-offset: 4
766 * tab-width: 8
767 * indent-tabs-mode: nil
768 * End:
770 * vi: set shiftwidth=4 tabstop=8 expandtab:
771 * :indentSize=4:tabSize=8:noTabs=true: