2 * Routines for PDC dissection
3 * Copyright 2014, Antony Bridle <antony.bridle@nats.co.uk>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
14 #include <epan/packet.h>
15 #include "packet-tcp.h"
17 void proto_register_pdc(void);
18 void proto_reg_handoff_pdc(void);
21 #define PDC_PROCOTOL "PDC"
34 /*Variable length Parameter Codes*/
35 #define PARAM_CODE_VERSION 2
36 #define PARAM_CODE_REFERENCES 3
37 #define PARAM_CODE_TRANSPORT 4
39 /* required for the TCP split packet combining */
40 #define PDC_MSG_SIZE_FIELD_LENGTH 2 /* minimum amount of data to find out how big the split packet should be when recombined */
41 #define FRAME_HEADER_LEN 8
43 /* global handle for our dissector */
44 static dissector_handle_t pdc_tcp_handle
;
46 /* global handle for calling asterix decoder if required */
47 static dissector_handle_t asterix_handle
;
52 static int hf_pdc_len
;
53 static int hf_pdc_mpdu_code
;
54 static int hf_pdc_credit
;
55 static int hf_pdc_simpdu_state
;
56 static int hf_pdc_yr_admu_nr
;
57 static int hf_pdc_akmpdu_mns
;
58 static int hf_pdc_akmpdu_cdt
;
59 static int hf_pdc_simpdu_var
;
60 static int hf_pdc_simpdu_var_len
;
61 static int hf_pdc_simpdu_param
;
62 static int hf_pdc_simpdu_var_version
;
63 static int hf_pdc_simpdu_var_REFSRC
;
64 static int hf_pdc_simpdu_var_REFDEST
;
65 static int hf_pdc_simpdu_var_TSEL
;
66 static int hf_pdc_drmpdu_abort
;
67 static int hf_pdc_drmpdu_reason
;
68 static int hf_pdc_drmpdu_mode
;
69 static int hf_pdc_drmpdu_init
;
70 static int hf_pdc_dtmpdu_user_size
;
71 static int hf_pdc_admpdu_admpdunr
;
72 static int hf_pdc_admpdu_size
;
76 static int ett_pdc_simpdu_var
;
79 /*Value String Declarations*/
80 static const value_string valstr_simpdu_state
[] = {
89 static const value_string valstr_simpdu_param
[] = {
90 { 2, "Version Number" },
92 { 4, "Transport Selector" },
96 static const value_string valstr_mpdus
[] = {
97 { 1, "State Information" },
98 { 2, "Request State" },
99 { 3, "Disconnect Request" },
101 { 5, "Acknowledged Data" },
102 { 6, "Expedited Data" },
103 { 8, "Data Acknowledgement" },
107 static const value_string valstr_drmpdu_abort
[] = {
108 { 0, "Orderly Release" },
109 { 1, "Abortive Release" },
113 static const value_string valstr_drmpdu_mode
[] = {
114 { 0, "Node Shutdown" },
119 static const value_string valstr_drmpdu_initatior
[] = {
125 static const value_string valstr_drmpdu_reason
[] = {
126 { 0, "Reason Not Specified" },
127 { 1, "Normal Disconnect Initiated by the MS-User" },
128 { 2, "Protocol Error" },
129 { 3, "Connection Request Refused" },
130 { 4, "The Remote Operational MS Entity Does Not Respond" },
131 { 5, "The Protocol Version Is Not Supported" },
132 { 6, "Mismatched References" },
136 /* start of functions here */
137 static int dissect_simpdu(tvbuff_t
*tvb
, proto_tree
*tree
, uint16_t offset
, uint8_t lenIndicator
)
141 proto_item
*simpduItem
;
142 proto_tree
*simpduVarTree
;
143 proto_tree
*simpduVarTree1
;
147 /*Add the Credit allocation*/
148 proto_tree_add_item(tree
, hf_pdc_credit
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
152 proto_tree_add_item(tree
, hf_pdc_simpdu_state
, tvb
, offset
+ bytesProcessed
, 1, ENC_BIG_ENDIAN
);
155 /*Add the YR-ADMU-NR*/
156 proto_tree_add_item(tree
, hf_pdc_yr_admu_nr
, tvb
, offset
+ bytesProcessed
, 4, ENC_BIG_ENDIAN
);
159 /*Determine what's in the variable part*/
160 if (lenIndicator
> 7)
162 /*Add the Variable Length Tree*/
163 simpduItem
= proto_tree_add_item (tree
, hf_pdc_simpdu_var
, tvb
, offset
+ bytesProcessed
, lenIndicator
- 7, ENC_NA
);
164 simpduVarTree
= proto_item_add_subtree (simpduItem
, ett_pdc_simpdu_var
);
166 while ((offset
+ bytesProcessed
) < ( lenIndicator
+ 1 ))
168 /*Get the parameter code*/
169 paramCode
= tvb_get_uint8(tvb
, offset
+ bytesProcessed
);
170 simpduItem
= proto_tree_add_item (simpduVarTree
, hf_pdc_simpdu_param
, tvb
, offset
+ bytesProcessed
, 1, ENC_BIG_ENDIAN
);
171 simpduVarTree1
= proto_item_add_subtree (simpduItem
, ett_pdc_simpdu_var
);
175 case PARAM_CODE_VERSION
:
176 proto_tree_add_item(simpduVarTree1
, hf_pdc_simpdu_var_len
, tvb
, offset
+ bytesProcessed
, 1, ENC_BIG_ENDIAN
);
177 proto_tree_add_item(simpduVarTree1
, hf_pdc_simpdu_var_version
, tvb
, offset
+ bytesProcessed
+ 1, 1, ENC_BIG_ENDIAN
);
180 case PARAM_CODE_REFERENCES
:
181 proto_tree_add_item(simpduVarTree1
, hf_pdc_simpdu_var_len
, tvb
, offset
+ bytesProcessed
, 1, ENC_BIG_ENDIAN
);
182 proto_tree_add_item(simpduVarTree1
, hf_pdc_simpdu_var_REFSRC
, tvb
, offset
+ bytesProcessed
+ 1, 2, ENC_BIG_ENDIAN
);
183 proto_tree_add_item(simpduVarTree1
, hf_pdc_simpdu_var_REFDEST
, tvb
, offset
+ bytesProcessed
+ 3, 2, ENC_BIG_ENDIAN
);
186 case PARAM_CODE_TRANSPORT
:
187 proto_tree_add_item(simpduVarTree1
, hf_pdc_simpdu_var_len
, tvb
, offset
+ bytesProcessed
, 1, ENC_BIG_ENDIAN
);
188 proto_tree_add_item(simpduVarTree1
, hf_pdc_simpdu_var_TSEL
, tvb
, offset
+ bytesProcessed
+ 1, 2, ENC_BIG_ENDIAN
);
192 } /* end of whileloop */
194 return (bytesProcessed
);
197 static int dissect_rsmpdu(void)
202 static int dissect_drmpdu(tvbuff_t
*tvb
, proto_tree
*tree
, uint16_t offset
)
205 proto_tree_add_item(tree
, hf_pdc_drmpdu_abort
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
206 proto_tree_add_item(tree
, hf_pdc_drmpdu_mode
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
207 proto_tree_add_item(tree
, hf_pdc_drmpdu_init
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
208 proto_tree_add_item(tree
, hf_pdc_drmpdu_reason
, tvb
, offset
+ 1, 1, ENC_BIG_ENDIAN
);
213 #if (PDC_VERSION == 2)
214 static int dissect_admpdu(tvbuff_t
*tvb
, proto_tree
*parent_tree
, proto_tree
*tree
, uint16_t offset
, packet_info
*pinfo
)
216 uint16_t userDataLen
;
218 tvbuff_t
*asterixTVB
;
221 proto_tree_add_item(tree
, hf_pdc_admpdu_admpdunr
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
224 proto_tree_add_item(tree
, hf_pdc_admpdu_size
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
225 /* length of user data field */
226 userDataLen
= tvb_get_ntohs(tvb
, offset
);
229 returnLen
= userDataLen
+ 6;
230 asterixTVB
= tvb_new_subset_length(tvb
, offset
, userDataLen
);
232 if (asterix_handle
!= NULL
)
233 call_dissector(asterix_handle
, asterixTVB
, pinfo
, parent_tree
);
238 static int dissect_admpdu(tvbuff_t
*tvb
, proto_tree
*parent_tree _U_
, proto_tree
*tree
, uint16_t offset
, packet_info
*pinfo _U_
)
241 proto_tree_add_item(tree
, hf_pdc_admpdu_admpdunr
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
247 #if (PDC_VERSION == 2)
248 static int dissect_dtmpdu(tvbuff_t
*tvb
, proto_tree
*parent_tree
, proto_tree
*tree
, uint16_t offset
, packet_info
*pinfo
)
250 uint16_t userDataLen
;
252 tvbuff_t
*asterixTVB
;
254 proto_tree_add_item(tree
, hf_pdc_dtmpdu_user_size
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
255 /* length of user data field */
256 userDataLen
= tvb_get_ntohs(tvb
, 2);
257 returnLen
= userDataLen
+ 2;
258 asterixTVB
= tvb_new_subset_length(tvb
, offset
+ 2, userDataLen
);
260 if (asterix_handle
!= NULL
)
261 call_dissector(asterix_handle
, asterixTVB
, pinfo
, parent_tree
);
266 static int dissect_dtmpdu(tvbuff_t
*tvb _U_
, proto_tree
*parent_tree _U_
, proto_tree
*tree _U_
, uint16_t offset _U_
, packet_info
*pinfo _U_
)
273 #if (PDC_VERSION == 2)
274 static int dissect_edmpdu(tvbuff_t
*tvb
, proto_tree
*parent_tree
, proto_tree
*tree
, uint16_t offset
, packet_info
*pinfo
)
276 uint16_t userDataLen
;
278 tvbuff_t
*asterixTVB
;
280 proto_tree_add_item(tree
, hf_pdc_dtmpdu_user_size
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
281 /* length of user data field */
282 userDataLen
= tvb_get_ntohs(tvb
, 2);
283 returnLen
= userDataLen
+ 2;
284 asterixTVB
= tvb_new_subset_length(tvb
, offset
+ 2, userDataLen
);
286 if (asterix_handle
!= NULL
)
287 call_dissector(asterix_handle
, asterixTVB
, pinfo
, parent_tree
);
292 static int dissect_edmpdu(tvbuff_t
*tvb _U_
, proto_tree
*parent_tree _U_
, proto_tree
*tree _U_
, uint16_t offset _U_
, packet_info
*pinfo _U_
)
298 static int dissect_akmpdu(tvbuff_t
*tvb
, proto_tree
*tree
, uint16_t offset
)
300 proto_tree_add_item(tree
, hf_pdc_akmpdu_mns
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
301 proto_tree_add_item(tree
, hf_pdc_akmpdu_cdt
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
302 proto_tree_add_item(tree
, hf_pdc_yr_admu_nr
, tvb
, offset
+ 2, 4, ENC_BIG_ENDIAN
);
306 static int dissect_pdc_packet(tvbuff_t
*tvb
, proto_tree
*tree
, packet_info
*pinfo
)
309 uint8_t len_indicator
;
312 proto_item
*pdcPacketItem
;
313 proto_tree
*pdcPacketTree
;
317 /*Get the length indictor and the MPDU Code*/
318 len_indicator
= tvb_get_uint8 (tvb
, i
);
319 mpduCode
= tvb_get_uint8 (tvb
, i
+ 1);
323 pdcPacketItem
= proto_tree_add_item (tree
, proto_pdc
, tvb
, i
, len_indicator
+ 1, ENC_NA
);
324 pdcPacketTree
= proto_item_add_subtree (pdcPacketItem
, ett_pdc
);
326 /*Add the Length and packet type*/
327 proto_tree_add_item(pdcPacketTree
, hf_pdc_len
, tvb
, i
, 1, ENC_BIG_ENDIAN
);
328 proto_tree_add_item(pdcPacketTree
, hf_pdc_mpdu_code
, tvb
, i
+ 1, 1, ENC_BIG_ENDIAN
);
330 /*Call the correct dissecting function*/
334 length
+= dissect_simpdu(tvb
, pdcPacketTree
, length
, len_indicator
);
335 col_set_str(pinfo
->cinfo
, COL_INFO
, "SIMPDU");
338 length
+= dissect_rsmpdu();
339 col_set_str(pinfo
->cinfo
, COL_INFO
, "RSMPDU");
342 length
+= dissect_drmpdu(tvb
, pdcPacketTree
, length
);
343 col_set_str(pinfo
->cinfo
, COL_INFO
, "DRMPDU");
346 length
+= dissect_dtmpdu(tvb
, tree
, pdcPacketTree
, length
, pinfo
);
347 col_set_str(pinfo
->cinfo
, COL_INFO
, "DTMPDU");
350 length
+= dissect_admpdu(tvb
, tree
, pdcPacketTree
, length
, pinfo
);
351 col_set_str(pinfo
->cinfo
, COL_INFO
, "ADMPDU");
354 length
+= dissect_edmpdu(tvb
, tree
, pdcPacketTree
, length
, pinfo
);
355 col_set_str(pinfo
->cinfo
, COL_INFO
, "EDMPDU");
358 length
+= dissect_akmpdu(tvb
, pdcPacketTree
, length
);
359 col_set_str(pinfo
->cinfo
, COL_INFO
, "AKMPDU");
364 return (length
); /* XXX: returned length ignored by caller: Remove keeping track of data processed ? */
365 /* col_set_str() could then be done separately with 'if (tree)' around the dissection */
368 /* Actual dissector bits and bytes done here */
369 static int dissect_pdc(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
372 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, PDC_PROCOTOL
);
373 col_clear(pinfo
->cinfo
, COL_INFO
);
375 dissect_pdc_packet(tvb
, tree
, pinfo
);
377 return tvb_reported_length(tvb
);
380 /* function to provide TCP split packet combiner with size of packet */
381 static unsigned get_pdc_message_len(packet_info
*pinfo _U_
, tvbuff_t
*tvb
,
382 int offset
, void *data _U_
)
388 mpdu_type
= tvb_get_uint8(tvb
, offset
+1);
392 size
= tvb_get_uint8(tvb
, offset
);
396 size
= tvb_get_uint8(tvb
, offset
);
400 size
= tvb_get_uint8(tvb
, offset
);
404 size
= tvb_get_ntohs(tvb
, offset
+2);
408 size
= tvb_get_ntohs(tvb
, offset
+6);
412 size
= tvb_get_uint8(tvb
, offset
);
416 size
= tvb_get_uint8(tvb
, offset
)+1;
426 /* top level call to recombine split tcp packets */
428 static int tcp_dissect_pdc(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
431 uint8_t minimum_bytes
;
433 mpdu_type
= tvb_get_uint8(tvb
,1);
461 tcp_dissect_pdus(tvb
, pinfo
, tree
, true, minimum_bytes
, get_pdc_message_len
, dissect_pdc
, NULL
);
462 return tvb_captured_length(tvb
);
465 void proto_register_pdc(void)
467 static hf_register_info hf
[] =
470 { "Length Indicator", "pdc.li",
471 FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
474 { "MPDU code", "pdc.mpducode",
475 FT_UINT8
, BASE_DEC
, VALS(valstr_mpdus
), 0x0, NULL
, HFILL
}},
478 { "Credit", "pdc.cdt",
479 FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
481 { &hf_pdc_yr_admu_nr
,
482 { "YR-ADMU-NR", "pdc.yradmunr",
483 FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
485 { &hf_pdc_simpdu_state
,
486 { "State", "pdc.state",
487 FT_UINT8
, BASE_DEC
, VALS(valstr_simpdu_state
), 0x0, NULL
, HFILL
}},
489 { &hf_pdc_akmpdu_mns
,
490 { "MNS", "pdc.akmpdu.mns",
491 FT_UINT16
, BASE_DEC
, NULL
, 0x8000, NULL
, HFILL
}},
493 { &hf_pdc_akmpdu_cdt
,
494 { "CDT", "pdc.akmpdu.cdt",
495 FT_UINT16
, BASE_DEC
, NULL
, 0x07FF, NULL
, HFILL
}},
497 { &hf_pdc_simpdu_var
,
498 { "Variable Part", "pdc.simpdu.variable",
499 FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
501 { &hf_pdc_simpdu_param
,
502 { "Parameter", "pdc.simpdu.param",
503 FT_UINT8
, BASE_DEC
, VALS(valstr_simpdu_param
), 0x0, NULL
, HFILL
}},
505 { &hf_pdc_simpdu_var_len
,
506 { "Length", "pdc.simpdu.variable.length",
507 FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
509 { &hf_pdc_simpdu_var_version
,
510 { "PDC Version Number", "pdc.simpdu.variable.version",
511 FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
513 { &hf_pdc_simpdu_var_REFSRC
,
514 { "Reference Source", "pdc.simpdu.variable.refsrc",
515 FT_UINT32
, BASE_DEC
, NULL
, 0x0,NULL
, HFILL
}},
517 { &hf_pdc_simpdu_var_REFDEST
,
518 { "Reference Destination", "pdc.simpdu.variable.refdst",
519 FT_UINT32
, BASE_DEC
, NULL
, 0x0,NULL
, HFILL
}},
521 { &hf_pdc_simpdu_var_TSEL
,
522 { "Transport Selector", "pdc.simpdu.tsel",
523 FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
525 { &hf_pdc_drmpdu_abort
,
526 { "Abort", "pdc.drmpdu.abort",
527 FT_UINT8
, BASE_DEC
, VALS(valstr_drmpdu_abort
), 0x80, NULL
, HFILL
}},
529 { &hf_pdc_drmpdu_reason
,
530 { "Reason", "pdc.drmpdu.reason",
531 FT_UINT8
, BASE_DEC
, VALS(valstr_drmpdu_reason
), 0x0, NULL
, HFILL
}},
533 { &hf_pdc_drmpdu_mode
,
534 { "Mode", "pdc.drmpdu.mode",
535 FT_UINT8
, BASE_DEC
, VALS(valstr_drmpdu_mode
), 0x70, NULL
, HFILL
}},
537 { &hf_pdc_drmpdu_init
,
538 { "Reason", "pdc.drmpdu.init",
539 FT_UINT8
, BASE_DEC
, VALS(valstr_drmpdu_initatior
), 0x0F, NULL
, HFILL
}},
541 { &hf_pdc_dtmpdu_user_size
,
542 { "User Data Length", "pdc.dtmpdu.usersize",
543 FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
545 { &hf_pdc_admpdu_admpdunr
,
546 { "AD-MPDU-NR", "pdc.admpdu.admpdunr",
547 FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
549 { &hf_pdc_admpdu_size
,
550 { "User Data Size", "pdc.admpdu.usersize",
551 FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
554 /* Setup protocol subtree array */
555 static int *ett
[] = {
560 proto_pdc
= proto_register_protocol (
561 "PDC Protocol", /* name */
562 "PDC", /* short name */
566 /*Required Function Calls to register the header fields and subtrees used*/
567 proto_register_field_array(proto_pdc
, hf
, array_length(hf
));
568 proto_register_subtree_array(ett
, array_length(ett
));
570 /* Register our dissector handle */
571 pdc_tcp_handle
= register_dissector("pdc", tcp_dissect_pdc
, proto_pdc
);
574 /* Function to add pdc dissector to tcp.port dissector table and to get handle for asterix dissector */
575 void proto_reg_handoff_pdc(void)
577 asterix_handle
= find_dissector_add_dependency("asterix", proto_pdc
);
578 dissector_add_for_decode_as_with_preference("tcp.port", pdc_tcp_handle
);
582 * Editor modelines - https://www.wireshark.org/tools/modelines.html
587 * indent-tabs-mode: t
590 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
591 * :indentSize=8:tabSize=8:noTabs=false: