This is our old Q&A Site. Please post any new questions and answers at


I have no idea how to solve one problem:

  1. with the help of dumpcap I capture pcap file
  2. after that I parse pcap file with tshark
  3. some frames are muti-chunk. For example mapping of the frame is the following:

    SCTP -> MTP3 -> SCCP -> TCAP -> GSM_MAP -> GSM_SMS ->

    SCTP -> MTP3 -> SCCP -> TCAP -> GSM_MAP ->

    SCTP -> MTP3 -> SCCP -> TCAP -> GSM_MAP -> GSM_SMS ->

    SCTP -> MTP3 -> SCCP -> TCAP -> GSM_MAP -> GSM_SMS

And with the help of lua script I devide multi-chunk in separate strings

Code of LUA script:

local logfile = "/en_""%Y%m%d%H%M%S")..".lua"

local frame_time ="frame.time")
local frame_protocols ="frame.protocols")
local gsm_map_tbcd_digits ="gsm_map.tbcd_digits")

local gsm_map_cap =,"gsm_map")

function gsm_map_cap.packet(pinfo,tvb)

    local Mas_frame_time = frame_time()
    XMas_frame_time = string.gsub(tostring(Mas_frame_time),"  "," ")
    local Mas_frame_protocols = frame_protocols()
    local Mas_gsm_map_tbcd_digits = {gsm_map_tbcd_digits()}
    p="(%a+) (%d+), (%d+) (%d+):(%d+):(%d+).(%d+) (%a+)"

    Max_count = 0
    count = 0
    for k,v in ipairs(Mas_gsm_map_tbcd_digits) do
        count = count + 1

    for i=1,Max_count do
        local convertedTimestamp ="%Y-%m-%d %H:%M:%S",os.time({year = xyear, month = month, day = xday, hour = xhour, min = xmin, sec = xsec}))
        io.write(tostring(convertedTimestamp) .. "\t" ..  tostring(Mas_frame_protocols) .. "\t" .. tostring(Mas_gsm_map_tbcd_digits[i]) .. "\n")


But the problem is that in one multi-chunk frame one field (gsm_map.tbcd_digits) could exit in one GSM_MAP and in another GSM_MAP in the same frame this field does not exist.

Somebody may be knows how to write listener in LUA to get NULL for the field even if this field does not exist in one of the protocol in multi-chunk frame?

As the result a want to have from lua the following array for field “ gsm_map.tbcd_digits “:





But now a have only following:




asked 18 Aug '15, 04:17

domeno's gravatar image

accept rate: 0%

edited 18 Aug '15, 04:49

Hadriel's gravatar image


Try something like this - this doesn't do your whole thing, but should give you the idea:

-- creates a Proto object, but doesn't register it yet
local proxy = Proto("tcap_proxy","TCAP-Proxy Fake Protocol")

-- these protofields are only used for debugging this thing
local total_tbcd_pf = ProtoField.uint16("tcap_proxy.total_tbcd",
                                        "Number of TBCD entries created (real and NULL)")
local real_tbcd_pf  = ProtoField.uint16("tcap_proxy.real_tbcd", 
                                        "Number of real TBCD entries created")
local null_tbcd_pf  = ProtoField.uint16("tcap_proxy.null_tbcd", 
                                        "Number of null TBCD entries created")
proxy.fields = { total_tbcd_pf, real_tbcd_pf, null_tbcd_pf }

-- this is the field we're going to keep track of
local tbcd_digits_field ="gsm_map.tbcd_digits")

-- this will be the tcap dissector, once we get it later
local tcap_dissector

-- this holds all of counts, in subtables per packet number
local packets = {}

function proxy.dissector(tvbuf,pinfo,root)

    if not pinfo.visited then
        -- first time for this packet, but might not be the first time we've
        -- been invoked in this packet; let's find out
        local counts = packets[pinfo.number]

        if not counts then
            -- ok, it's the first time we've been invoked for this packet, ever.
            -- so create a subtable for this packet's tbcd_digit counts
            counts = { ["number_real_entries"] = 0 }
            packets[pinfo.number] = counts

        local current_count = #counts

        -- for debugging, we're going to add our proxy protocol to the tree
        local tree = root:add(proxy, tvbuf:range(0,pktlen))
        tree:add(total_tbcd_pf, current_count):set_generated()
        tree:add(real_tbcd_pf, counts.number_real_entries):set_generated()
        tree:add(null_tbcd_pf, current_count - counts.number_real_entries):set_generated()

        -- call the TCAP dissector

        local num_fields = { tbcd_digits_field() }

        if #num_fields > counts.number_real_entries then
            -- we got a new one; it must be the last one in the num_fields table
            counts[current_count + 1] = num_fields[#num_fields].value
            counts.number_real_entries = counts.number_real_entries + 1
            -- no tbcd digits, add a <NONE> entry
            counts[current_count + 1] = "<NONE>"
        -- we've processed this whole packet before; just show the debug info
        -- of the counts and invoke the TCAP dissector
        local counts = packets[pinfo.number]

        -- for debugging, we're going to add our proxy protocol to the tree
        local tree = root:add(proxy, tvbuf:range(0,pktlen))
        tree:add(total_tbcd_pf, #counts):set_generated()
        tree:add(real_tbcd_pf, counts.number_real_entries):set_generated()
        tree:add(null_tbcd_pf, #counts - counts.number_real_entries):set_generated()

        -- call the TCAP dissector


-- we're intercepting SSN range 6-9 for GSM MAP
local sccp_tbl = DissectorTable.get("sccp.ssn")
-- get the TCAP dissector
tcap_dissector = sccp_tbl:get_dissector(6)
-- replace it with our proxy dissector, for the 6-9 range
sccp_tbl:set("6-9", proxy)
permanent link

answered 19 Aug '15, 20:19

Hadriel's gravatar image

accept rate: 18%


Could you please explain for what is calling "tcap_dissector" inside of "proxy.dissector" (artificial dissector for uor needs)?

Thanks for help!

(20 Aug '15, 23:04) domeno

If you look at the bottom of the script, you'll see I'm getting the "sccp.ssn" dissector table, and then from within that I'm getting the dissector registered for SCCP SSN number 6, and I'm replacing it with this "proxy" protocol's dissector. (in fact, I'm replacing the whole 6-9 range of SSNs) That dissector I'm replacing is the TCAP dissector - the one written in C-code built into wireshark.

So basically whenever SCCP goes to decode a message of SSN 6-9, instead of invoking TCAP like it would normally do, it invokes our proxy dissector instead. So within the proxy dissector I invoke the original TCAP dissector with the "tcap_dissector:call(tvbuf,pinfo,root)" line.

The reason I'm doing all that is that I can see if the number of GSM MAP TBCD fields has changed. If it's change, then we've got a new TBCD in the message to save; if it has not changed, then I add a "<none>" entry instead.

The reason I'm replacing the range 6-9 is that those are the GSM MAP SSN numbers, I think.

(21 Aug '15, 05:58) Hadriel

See the answer to question 43543 which is similar.

permanent link

answered 18 Aug '15, 05:12

Hadriel's gravatar image

accept rate: 18%

Hadriel, thanks for the reply.

I am a little bit newbie in LUA and WireShark. That’s why I could not understand how to read every protocol in one frame successively.

Here is the code of LUA script for my experiments:

local logfile = "en_""%Y%m%d%H%M%S")..".lua" io.output(logfile)

local gsm_map_tbcd_digits ="gsm_map.tbcd_digits") local m3ua =,"m3ua")

function m3ua.packet(pinfo,tvb)

local Mas_gsm_map_tbcd_digits = {gsm_map_tbcd_digits()} io.write("imsi:" .. tostring( Mas_gsm_map_tbcd_digits[0]) .."\n") io.write("imsi:" .. tostring( Mas_gsm_map_tbcd_digits[1]) .."\n") io.write("imsi:" .. tostring( Mas_gsm_map_tbcd_digits[2]) .."\n") io.write("imsi:" .. tostring( Mas_gsm_map_tbcd_digits[3]) .."\n") io.write("imsi:" .. tostring( Mas_gsm_map_tbcd_digits[4]) .."\n") io.write("imsi:" .. tostring( Mas_gsm_map_tbcd_digits[5]) .."\n") io.write("imsi:" .. tostring( Mas_gsm_map_tbcd_digits[6]) .."\n") io.write("imsi:" .. tostring( Mas_gsm_map_tbcd_digits[7]) .."\n")


I run it by the command:

Tshark –r /file.pcap –X lua_script:devide_imsi.lua

As far as I can judge I get the whole array of all “gsm_map.tbcd_digits” write in the beginning of the function m3ua.packet. Would you be so kind and explain how to read every protocol in one frame successively? May be you some usefull examples?!

Thanks for any help!

(18 Aug '15, 06:43) domeno

Oh yeah I keep forgetting the taps aren't invoked until after the whole packet's been dissected. Crap.

Hmmm... the only way to do it might be to create a "proxy" Lua protocol, remove the "gsm_map" dissector from TCAP's table, register the proxy Lua dissector in its place for TCAP, and within the proxy one invoke the gsm_map dissector and after it returns see what's changed about the fields you're interested in. Yuck.

Can you share an example capture file for this problem? I might have some time later today to see if I can get the info you want using a Lua script.

(18 Aug '15, 07:30) Hadriel

Hadriel, thanks for the reply.

Could you please give me an advise how can i share the pcap file with example for you? Is it possible to send you this file personally as this file has some private information?

Thanks for any help!

(19 Aug '15, 05:23) domeno

Sure, my email is either [email protected], or [email protected]

(19 Aug '15, 05:31) Hadriel

Wiresharks export-pdu function can do SCTP dechunking if that's of any use, this patch in gerrit implements it for tshark but I think the work on it may have stalled

(19 Aug '15, 07:59) Anders ♦
Your answer
toggle preview

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here



Answers and Comments

Markdown Basics

  • *italic* or _italic_
  • **bold** or __bold__
  • link:[text]( "title")
  • image?![alt text](/path/img.jpg "title")
  • numbered list: 1. Foo 2. Bar
  • to add a line break simply add two spaces to where you would like the new line to be.
  • basic HTML tags are also supported

Question tags:


question asked: 18 Aug '15, 04:17

question was seen: 2,245 times

last updated: 21 Aug '15, 05:58

p​o​w​e​r​e​d by O​S​Q​A