Ask Your Question

Revision history [back]

Lua dissector is not processing the full TCP payload.

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.

click to hide/show revision 2
None

Lua dissector is not processing the full TCP payload.

Code:

function acses_protocol.dissector(tvb, pinfo, tree)

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

end

I also have a Fields.lua file:

fields = {}

{} -- define the protocol _G.acses_protocol = Proto("ACSES", "ACSES Protocol")

Protocol") -- This section defines each of the fields used in the protocol and defines their attributes. _G.f = acses_protocol.fields

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.