function acses_protocol.dissector(tvb, pinfo, tree)
-- tvb is the data buffer that contains all of the message information. Reference the information with tvb(x, y)
-- where x is the starting position and y is the length to read (in bytes). Therefore, if the frame has no length,
-- then exit the dissector
local frame_len = tvb:len()
if frame_len == 0 then return end
-- Create the GIU tab for ACSES information
_G.subtree = tree:add(acses_protocol, tvb(), "ACSES Protocol Data")
-- Add ACSES to the "Protocol" column in Wireshark
pinfo.cols.protocol = acses_protocol.name ..":"
--check for the weird split message
if frame_len == 6 then
if (tvb(0, 4):uint() == 0xfff555ff) then
acsesHeader = tvb(0, 4):uint()
acsesLength = tvb(4, 2):uint()
subtree:add(f.isSplitMessage, true)
pinfo.cols.protocol = tostring(pinfo.cols.protocol) .. " [SPLIT MESSAGE]"
return
end
end
-- Process the payload from beginning to end looking for ACSES messages
-- since there may be more than 1 in a message.
local msg_cnt = 0
for i = 0, frame_len - 4, 1 do
-- Determine if the message is an ACSES Message
if tvb(i, 4):uint() == 0xfff555ff or (acsesHeader == 0xfff555ff and tvb(i, 4):uint() ~= 0xfff555ff and i == 0) then
-- Add a separator between messages when there is more than 1
-- submessage embedded in a larger message
if (msg_cnt > 0) then
subtree:add(f.test_s, "###", "**************************************************", " ")
end
-- get the message length from the buffer or get it from the previous message buffer
if acsesLength ~= 0 and tvb(i, 4):uint() ~= 0xfff555ff and i == 0 then
msg_len = acsesLength
i = i-6
--reset the previous message buffers
acsesLength = 0
acsesHeader = 0
bufferFlag_ResetI = 1
splitFlag = 1
else
msg_len = tvb(i + 4, 2):uint()
end
-- Determine if the message is a Maintience Train Alarm or Maintience Train Ack
-- because they have the message label in a different location. For some unearthly reason.
-- Also, check to see if the source address is 0, because if it is, that means it's a tsr response, but structured differently
local msg_index = 0
if ((msg_len == 36) or (msg_len == 58)) then
msg_index = i + 27
elseif tvb(i+8, 4):uint() == 0x00000a14 then
msg_index = i + 20
else
msg_index = i + 25
end
-- It seems that the only defining feature of a self addressed message is its length
-- otherwise, use the label.
if (msg_len == 15) then
msg_lbl = 0
msg_type = "Self_Addressed_Message"
subtree:add(f.isSelfAddrMsg, true)
else
msg_lbl = tvb(msg_index, 2):uint()
msg_type = label_msg_type(msg_lbl)
end
--Add the message type to the protocol column
pinfo.cols.protocol = tostring(pinfo.cols.protocol) .. " " .. msg_type .. " (" .. msgtocode(msg_lbl) .. ")"
-- Output the message type to the top of the tree before dissecting the rest of the message
subtree:append_text(" (" .. msg_type .. ") ")
--[[Functions located in ixl.lua]]--
if (msg_type == "IXL_Status_Request") then
ixl.ixl_request(tvb(i + 6, msg_len))
--[[Functions located in wiu.lua]]--
elseif (msg_type == "WIU_Response_w_LoMA") then
wiu_resp_w_loma(tvb(i + 6, msg_len))
elseif (msg_type == "WIU_Response_wo_LoMA") then
wiu_resp_wo_loma(tvb(i + 6, msg_len))
elseif (msg_type == "WIU_Error_Response") then
wiu_error(tvb(i + 6, msg_len))
--[[Functions located in tsr.lua]]--
elseif tvb(i+8, 4):uint() == 0x00000a14 then
tsr.tsr_answer_alt(tvb(i + 6, msg_len))
elseif (msg_type == "TSR_Request") then
tsr.tsr_request(tvb(i + 6, msg_len))
elseif (msg_type == "TSR_Answer") then
tsr.tsr_answer(tvb(i + 6, msg_len))
elseif (msg_type == "TSR_Answer_No_Change") then
tsr.tsr_no_change(tvb(i + 6, msg_len))
--[[Functions located in mta.lua]]--
elseif (msg_type == "MTA") then
mta.mta_request(tvb(i + 6, msg_len))
elseif (msg_type == "MTA_Ack") then
mta.mta_ack(tvb(i + 6, msg_len))
--[[Functions located in signal.lua]]--
elseif (msg_type == "Signal_Address") then
signal.signal_address(tvb(i + 6, msg_len))
elseif (msg_type == "Distance_to_Signal") then
signal.distance_to_signal(tvb(i + 6, msg_len))
--[[ Functions located in selfHealth.lua]]--
elseif (msg_type == "Query_for_Health") then
selfHealth.query_for_health(tvb(i + 6, msg_len))
elseif (msg_type == "Health_Report") then
selfHealth.health_report(tvb(i + 6, msg_len))
elseif (msg_type == "Query_for_Self_Test") then
selfHealth.query_for_self_test(tvb(i+6, msg_len))
elseif (msg_type == "Self_Test_Results") then
selfHealth.self_test_results(tvb(i+6, msg_len))
elseif (msg_type == "Self_Addressed_Message") then
selfHealth.self_addressed_message(tvb(i+6, msg_len))
end
if bufferFlag_ResetI then
i = i + 6
end
bufferFlag_ResetI = 0
end
if msg_len + 6 < frame_len and acsesHeader == 0 then
msg_cnt = 1
end
end
if splitFlag == 1 then
return msg_len
else
return msg_len + 6
end
end
I also have a Fields.lua file:
fields = {}
-- define the protocol _G.acses_protocol = Proto("ACSES", "ACSES Protocol")
-- This section defines each of the fields used in the protocol and defines their attributes. _G.f = acses_protocol.fields
Then all of the fields are defined here.
So! My dissector will process the first message within the TCP payload, but it will not process any messages in the same payload after. I get the Lua Error of 74: Attempt to concatenate field '?' (a nil value). Every example I have found online has only local variables, but my dissector depends heavily on my other files, so I have global variables. Any help is appreciated.