add basic ITU-T T.70 and T.62 LUA dissectors

This commit is contained in:
Harald Welte 2024-03-06 19:38:41 +01:00
parent 5ca585e4b0
commit 4431c23d40
3 changed files with 376 additions and 2 deletions

View File

@ -47,13 +47,13 @@ Pdu rsl_pdu Proto gsm_abis_rsl Transport gsm_ipa/tcp/ip {
Criteria Accept Strict (rsl_msg_dsc {4|1|63}); // DCHAN || RLL || IPA
};
/* somehow this definition for the Gop doesn't work, as ip_addr exists only one if source and dest are
* identical */
Gop rsl_lchan On rsl_pdu Match (ip_addr, ip_addr, port, port, rsl_cbits, rsl_tn) {
Start (rsl_msg_type = 33); // CHAN_ACT
Stop (rsl_msg_type {36|51}); // CHAN_ACT_NACK || RF_CHAN_REL_ACK
};
/***********************************************************************
* SCCP
***********************************************************************/

247
t62.lua Normal file
View File

@ -0,0 +1,247 @@
-- wireshark LUA dissector for the ITU-T T.62 protocol
-- (C) 2024 by Harald Welte <laforge@osmocom.org>
-- SPDX-License-Identifier: GPL-2.0+
--
-- Usage: Move this file to your "personal lua plugins" folder that
-- can be found in the Wireshark Help->About Wireshark->Folders tab
-- Windows: %APPDATA%\Wireshark\plugins.
-- Unix-like systems: ~/.local/lib/wireshark/plugins.
t62_protocol = Proto("T.62", "ITU-T T.62 Control Procedures for Teletex and Group 4 Facsimile Services")
local session_cri_names_long = {
-- Table 4/T.62: CRI for session elements
[0x0d] = "Command Session Start",
[0x09] = "Command Session End",
[0x19] = "Command Session Abort",
[0x15] = "Command Session Change Control",
[0x01] = "Command Session User Information",
[0x0e] = "Response Session Start Positive",
[0x0c] = "Response Session Start Negative",
[0x0a] = "Response Session End Positive",
[0x1a] = "Response Session Abort Positive",
[0x16] = "Response Session Change Control Positive",
[0x02] = "Response Session User Information",
}
local session_cri_names = {
-- Table 4/T.62: CRI for session elements
[0x0d] = "CSS",
[0x09] = "CSE",
[0x19] = "CSA",
[0x15] = "CSCC",
[0x01] = "CSUI",
[0x0e] = "RSSP",
[0x0c] = "RSSN",
[0x0a] = "RSEP",
[0x1a] = "RSAP",
[0x16] = "RSCCP",
[0x02] = "RSUI",
}
local hf_session_cri = ProtoField.uint8("t62.session.cri", "Command/Response Identifier", base.HEX, session_cri_names)
local hf_session_li = ProtoField.uint8("t62.session.li", "Length Identifier", base.DEC)
-- Table 7/T.62
local session_pi_pgi_names = {
[0x00] = "Reserved for extension",
[0x01] = "Session reference",
[0x09] = "Terminal identifier of the called terminal",
[0x0a] = "Terminal identifier of the calling terminal",
[0x0b] = "Date and time",
[0x0c] = "Additional session reference number",
[0x02] = "Non-basic session capabilities",
[0x0d] = "Miscellaneous session capabilities",
[0x0e] = "Window size",
-- No PGI associated with these PIs
[0x08] = "Service identifier",
[0x10] = "Session control functions",
[0x11] = "Session termination parameter",
[0x12] = "Inactivity timer",
[0x14] = "Session service functions",
[0x32] = "Reason",
[0x41] = "Non-basic Teletex terminal capabilities",
[0x49] = "Control character set",
[0x4a] = "Teletex page format",
[0x4b] = "Miscellaneous Teletex terminal capabilities",
[0xc1] = "Session user data",
[0xe0] = "Private use 0",
[0xe1] = "Private use 1",
[0xe2] = "Private use 2",
[0xe3] = "Private use 3",
[0xe4] = "Private use 4",
[0xe5] = "Private use 5",
[0xe6] = "Private use 6",
[0xe7] = "Private use 7",
[0xe8] = "Non-standardixed capabilities",
}
local hf_session_pi_pgi = ProtoField.uint8("t64.session.pi", "Parameter (Group) Identifier", base.HEX, session_pi_pgi_names)
local doc_cri_names_long = {
-- Table 5/T.62: CRI for document command identifiers
[0x2d] = "Command Document Start",
[0x1d] = "Command Document Continue",
[0x29] = "Command Document End",
[0x19] = "Command Document Resynchronize",
[0x39] = "Command Document Discard",
[0x31] = "Comman Document Page Boundary",
[0x3d] = "Command Document Capability List",
[0x01] = "Command Document User Information",
-- Table 6/T.62: CRI for document response identifiers
[0x2a] = "Response Document End Potve",
[0x1a] = "Response Document Resynchronize Positive",
[0x3a] = "Response Document Discard Positive",
[0x32] = "Response Document Page Boundary Positive",
[0x30] = "Response Document Page Boundary Negative",
[0x3e] = "Response Document Capability List Positive",
[0x00] = "Resposne Documnet General Reject",
}
local doc_cri_names = {
-- Table 5/T.62: CRI for document command identifiers
[0x2d] = "CDS",
[0x1d] = "CDC",
[0x29] = "CDE",
[0x19] = "CDR",
[0x39] = "CDD",
[0x31] = "CDPB",
[0x3d] = "CDCL",
[0x01] = "CDUI",
-- Table 6/T.62: CRI for document response identifiers
[0x2a] = "RDEP",
[0x1a] = "RDRP",
[0x3a] = "RDDP",
[0x32] = "RDPBP",
[0x30] = "RDPBN",
[0x3e] = "RDCLP",
[0x00] = "RDGR",
}
local hf_document_cri = ProtoField.uint8("t62.document.cri", "Command/Response Identifier", base.HEX, doc_cri_names)
local hf_document_li = ProtoField.uint8("t62.document.li", "Length Identifier", base.DEC)
local hf_document_data = ProtoField.bytes("t62.document.data", "Data")
-- Table 8/T.62
local doc_pi_pgi_names = {
[0x20] = "Reserved fro extension",
[0x21] = "Document linking",
[0x09] = "Terminal identifier of the called terminal",
[0x0a] = "Terminal identifier of the calling terminal",
[0x0b] = "Date and time",
[0x0c] = "Additional session reference number",
[0x29] = "Document reference number",
[0x2a] = "Checkpoint reference number",
-- no PGI associated wih these PI
[0x12] = "Inactivity timer",
[0x28] = "Service interworking identifier",
[0x29] = "Document reference number",
[0x2a] = "Checkpoint reference number",
[0x2c] = "Acceptance of CDCL parameters",
[0x2d] = "Storage capacity negotiation",
[0x2e] = "Receiving ability jeopardized",
[0x2f] = "Reserved",
[0x30] = "Document type identifier",
[0x31] = "Reflect parameter values",
[0x32] = "Reason",
[0x40] = "Reserved for extension",
[0x41] = "Non-basic Teletex terminal capabilities",
[0x48] = "Graphic character set",
[0x49] = "Control character set",
[0x4a] = "Teletex page format",
[0x4b] = "Miscellaneous Teletex terminal capabilities",
[0x4d] = "Character box height",
[0x4e] = "Character box width",
[0xc1] = "Session user data",
[0xe0] = "Private use 0",
[0xe1] = "Private use 1",
[0xe2] = "Private use 2",
[0xe3] = "Private use 3",
[0xe4] = "Private use 4",
[0xe5] = "Private use 5",
[0xe6] = "Private use 6",
[0xe7] = "Private use 7",
[0xe8] = "Non-standardized capabilities",
}
local hf_doc_pi_pgi = ProtoField.uint8("t64.document.pi", "Parameter (Group) Identifier", base.HEX, doc_pi_pgi_names)
-- 5.7.2.10 Reason (session or document)
local reason_names = {
[0x00] = "No specific reason stated (used for session or document reasons other than those listed)",
[0x01] = "Temporarily unable to enter into, or to continue, a session (e.g. due to memory full or out of recording paper)",
[0x02] = "Explicit text message only for use with RSSN",
[0x03] = "Sequence error",
[0x05] = "Local terminal error",
[0x06] = "Unrecoverable procedural error",
}
-- 5.7.3.7 Document type identiifer
local doc_type_id_names = {
[0x01] = "Operator document",
[0x02] = "Control document",
[0x03] = "Monitor document",
}
-- Table 11/T.62
local teletex_page_format_names = {
[0x01] = "ISO A4, horizontal and vertical",
[0x02] = "North American, horizontal and vertical",
[0x84] = "ISO A4 extended (ISO standard 3535), vertical",
[0x44] = "ISO A4 extended (ISO standard 3535), horizontal",
[0x88] = "North American legal, vertical",
[0x48] = "North American legal, horizontal",
[0x03] = "ISO A4, horizontal and vertical (for use by Japanese Kanji and Chinese ideogram terminals)",
[0x10] = "ISO B5, horizontal and vertical (for use by Japanese Kanji and Chinese ideogram terminals)",
[0x20] = "ISO B4, horizontal and vertical (for use by Japanese Kanji and Chinese ideogram terminals)",
}
t62_protocol.fields = {
hf_session_cri, hf_session_li, hf_session_pi_pgi,
hf_document_cri, hf_document_li, hf_doc_pi_pgi,
hf_document_data,
}
function decode_t62_document(buffer, pinfo, tree)
local d_cri = buffer(0, 1):uint()
local d_li = buffer(1, 1):uint()
pinfo.cols.info:append(" " .. doc_cri_names[d_cri])
tree:append_text(" " .. doc_cri_names[d_cri] .. "(" .. doc_cri_names_long[d_cri] .. ")")
tree:add(hf_document_cri, buffer(0, 1))
tree:add(hf_document_li, buffer(1, 1))
if (d_li > 0) then
-- FIXME: document parameters
end
-- user data only exists in CDUI
if (d_cri == 0x01) then
tree:add(hf_document_data, buffer(2))
end
end
function t62_protocol.dissector(buffer, pinfo, tree)
pinfo.cols.protocol = t62_protocol.name
local subtree = tree:add(t62_protocol, buffer(), "T.62")
local offset = 0
local s_cri = buffer(0, 1):uint()
local s_li = buffer(1, 1):uint()
pinfo.cols.info:append(" " .. session_cri_names[s_cri])
subtree:append_text(" " .. session_cri_names[s_cri] .. " (" .. session_cri_names_long[s_cri] .. ")")
subtree:add(hf_session_cri, buffer(0, 1))
subtree:add(hf_session_li, buffer(1, 1))
if (s_li > 0) then
-- FIXME: session parameters
end
-- document layer data only exists in CSUI / RSUI
if (s_cri == 0x01 or s_cri == 0x02) then
decode_t62_document(buffer(2+s_li), pinfo, tree)
end
end
function t62_protocol.init()
local t70_dissectors = DissectorTable.get("t70.subdissector")
t70_dissectors:add_for_decode_as(t62_protocol)
end

127
t70.lua Normal file
View File

@ -0,0 +1,127 @@
-- wireshark LUA dissector for the ITU-T T.70 protocol
-- (C) 2024 by Harald Welte <laforge@osmocom.org>
-- SPDX-License-Identifier: GPL-2.0+
--
-- Usage: Move this file to your "personal lua plugins" folder that
-- can be found in the Wireshark Help->About Wireshark->Folders tab
-- Windows: %APPDATA%\Wireshark\plugins.
-- Unix-like systems: ~/.local/lib/wireshark/plugins.
t70_protocol = Proto("T.70", "ITU-T T.70 Network-Independent Basic Transport Service for the Telematic services")
t70_subdissectors = DissectorTable.new("t70.subdissector", "T.70 payload subdissector", ftypes.NONE, base.NONE, t70_protocol)
local hf_net_block_hdr_len = ProtoField.uint8("t70.net_block_hdr_len", "Network Block Header Length", base.DEC)
local hf_net_block_hdr = ProtoField.bytes("t70.net_block_hdr", "Network Block Header")
local hf_net_block_hdr_m = ProtoField.bool("70.net_block_hdr.m", "M(ore data mark) bit", base.HEX, nil, 0x80)
local hf_net_block_hdr_q = ProtoField.bool("70.net_block_hdr.q", "Q(ualifier) bit", base.HEX, nil, 0x40)
local hf_src_ref = ProtoField.uint16("t70.src_ref", "Source Reference", base.HEX)
local hf_dst_ref = ProtoField.uint16("t70.dst_ref", "Destination Reference", base.HEX)
-- Fogure 15/T.70
local reject_cause_names = {
[0x00] = "Reason not specified",
[0x01] = "Function not implemented",
[0x02] = "Invalid block",
[0x03] = "Invalid parameter",
}
local hf_rej_cause = ProtoField.uint8("t70.rej_cause", "Reject Cause", base.HEX, reject_cause_names)
local hf_block_len = ProtoField.uint8("t70.block_len", "Block Length", base.DEC)
local block_types = {
[0xe0] = "TCR",
[0xd0] = "TCA",
[0x80] = "TCC",
[0x70] = "TBR",
[0xf0] = "TDT",
}
local block_types_long = {
[0xe0] = "Transport Connection Request",
[0xd0] = "Transport Connection Accept",
[0x80] = "Transport Connection Clear",
[0x70] = "Transport Block Reject",
[0xf0] = "Transport Data",
}
local hf_block_type = ProtoField.uint8("t70.block_type", "Block Type", base.HEX, block_types, 0xff)
local hf_data = ProtoField.bytes("t70.data", "Data")
local param_names = {
[0xc0] = "Transport data block size", -- Figure 11/T.70
[0xc1] = "Calling address", -- Figure 10/T.70 (but also Figure 16/T.70: Rejected block)
[0xc2] = "Called address", -- Fiure 10/T.70
}
-- Figure 13/T.70
local clearing_cause_names = {
[0x00] = "Reason not specified",
[0x01] = "Terminal occupied",
[0x02] = "Terminal out of order",
[0x03] = "Address unknown",
}
local hf_clearing_cause = ProtoField.uint8("t70.clearing_cause", "Clearing Cause", base.HEX, clearing_cause_names)
local hf_tsdu_end_mark = ProtoField.bool("t70.tsdu_end_mark", "TSDU end mark", base.HEX, nil, 0x80)
t70_protocol.fields = {
hf_net_block_hdr_len, hf_net_block_hdr, hf_net_block_hdr_m, hf_net_block_hdr_q, hf_tsdu_end_mark,
hf_src_ref, hf_dst_ref, hf_rej_cause, hf_block_len, hf_block_type, hf_data, hf_clearing_cause,
}
function dissect_block(buffer, pinfo, tree, maintree)
local blen = buffer(0, 1):uint()
local btype = buffer(1, 1):uint()
pinfo.cols.info = block_types[btype]
tree:append_text(" " .. block_types[btype] .. " (" .. block_types_long[btype] .. ")")
tree:add(hf_block_len, buffer(0, 1))
tree:add(hf_block_type, buffer(1, 1))
if (btype == 0xe0) then -- TCR (Section 5.5.4)
tree:add(hf_src_ref, buffer(4, 2))
-- TODO: parameters (calling, called, block size)
elseif (btype == 0xd0) then -- TCA (Section 5.5.5)
tree:add(hf_dst_ref, buffer(2, 2))
tree:add(hf_src_ref, buffer(4, 2))
-- TODO: parameters (calling, called, block size)
elseif (btype == 0x80) then -- TCC (Section 5.5.6)
tree:add(hf_dst_ref, buffer(2, 2))
tree:add(hf_src_ref, buffer(4, 2))
tree:add(hf_clearing_cause, buffer(6, 1))
-- TODO: parameters (addl clearing info)
elseif (btype == 0x70) then -- TBR (Section 5.5.7)
tree:add(hf_dst_ref, buffer(2, 2))
tree:add(hf_rej_cause, buffer(4, 1))
-- TODO: parameters (rejected block [mandatory])
elseif (btype == 0xf0) then -- TDT (Section 5.5.8)
-- TSDU end mark
tree:add(hf_tsdu_end_mark, buffer(2, 1))
-- data
if (not t70_subdissectors:try(0, buffer(3):tvb(), pinfo, maintree)) then
tree:add(hf_data, buffer(3))
end
else
-- unknown
end
end
function t70_protocol.dissector(buffer, pinfo, tree)
pinfo.cols.protocol = t70_protocol.name
local subtree = tree:add(t70_protocol, buffer(), "T.70")
local net_bhl = buffer(0, 1):uint()
-- 2-byte network block header, see Figure 4/T.70
subtree:add(hf_net_block_hdr_len, buffer(0, 1))
subtree:add(hf_net_block_hdr, buffer(1, net_bhl))
subtree:add(hf_net_block_hdr_m, buffer(1, 1))
subtree:add(hf_net_block_hdr_q, buffer(1, 1))
-- actual block
dissect_block(buffer(1+net_bhl), pinfo, subtree, tree)
end
function t70_protocol.init()
local x75_dissectors = DissectorTable.get("x75.subdissector")
x75_dissectors:add_for_decode_as(t70_protocol)
end