-- создаем описание нового протокола local egts_proto = Proto("egts", "EGTS") -- настройки плагина local default_settings = { port = 5020 } local EGTS_PT_RESPONSE = "EGTS_PT_RESPONSE" local EGTS_PT_APPDATA = "EGTS_PT_APPDATA" local EGTS_PT_SIGNED_APPDATA = "EGTS_PT_SIGNED_APPDATA" local egts_packet_type = { [0] = EGTS_PT_RESPONSE, [1] = EGTS_PT_APPDATA, [2] = EGTS_PT_SIGNED_APPDATA, } local egts_subrecord_type = { [0] = "EGTS_SR_RECORD_RESPONSE", [1] = "EGTS_SR_TERM_IDENTITY", [9] = "EGTS_SR_RESULT_CODE", [15] = "EGTS_SR_EGTSPLUS_DATA", [16] = "EGTS_SR_POS_DATA", [17] = "EGTS_SR_EXT_POS_DATA", [18] = "EGTS_SR_AD_SENSORS_DATA", [19] = "EGTS_SR_COUNTERS_DATA", [20] = "EGTS_SR_STATE_DATA", [22] = "EGTS_SR_LOOPIN_DATA", [23] = "EGTS_SR_ABS_DIG_SENS_DATA", [24] = "EGTS_SR_ABS_AN_SENS_DATA", [25] = "EGTS_SR_ABS_CNTR_DATA", [26] = "EGTS_SR_ABS_LOOPIN_DATA", [27] = "EGTS_SR_LIQUID_LEVEL_SENSOR", -- Список подзаписей сервиса EGTS_ECALL_SERVICE --[20] = "EGTS_SR_ACCEL_DATA", [40] = "EGTS_SR_RAW_MSD_DATA", [62] = "EGTS_SR_TRACK_DATA", -- Описание подзаписей сервиса EGTS_COMMAND_SERVICE [51] = "EGTS_SR_COMМAND_DАТА", } local result_code = { [0] = "EGTS_PC_OK", [1] = "EGTS_PC_IN_PROGRESS", [128] = "EGTS_PC_UNS_PROTOCOL", [129] = "EGTS_PC_DECRYPT_ERROR", [130] = "EGTS_PC_PROC_DENIED", [131] = "EGTS_PC_INC_HEADERFORM", [132] = "EGTS_PC_INC_DATAFORM", [133] = "EGTS_PC_UNS_TYPE", [134] = "EGTS_PC_NOTEN_PARAMS", [135] = "EGTS_PC_DBL_PROC", [136] = "EGTS_PC_PROC_SRC_DENIED", [137] = "EGTS_PC_HEADERCRC_ERROR", [138] = "EGTS_PC_DATACRC_ERROR", [139] = "EGTS_PC_INVDATALEN", [140] = "EGTS_PC_ROUTE_NFOUND", [141] = "EGTS_PC_ROUTE_CLOSED", [142] = "EGTS_PC_ROUTE_DENIED", [143] = "EGTS_PC_INVADDR", [144] = "EGTS_PC_TTLEXPIRED", [145] = "EGTS_PC_NO_ACK", [146] = "EGTS_PC_OBJ_NFOUND", [147] = "EGTS_PC_EVNT_NFOUND", [148] = "EGTS_PC_SRVC_NFOUND", [149] = "EGTS_PC_SRVC_DENIED", [150] = "EGTS_PC_SRVC_UNKN", [151] = "EGTS_PC_AUTH_DENIED", [152] = "EGTS_PC_ALREADY_EXISTS", [153] = "EGTS_PC_ID_NFOUND", [154] = "EGTS_PC_INC_DATETIME", [155] = "EGTS_PC_IO_ERROR", [156] = "EGTS_PC_NO_RES_AVAIL", [157] = "EGTS_PC_MODULE_FAULT", [158] = "EGTS_PC_MODULE_PWR_FLT", [159] = "EGTS_PC_MODULE_PROC_FLT", [160] = "EGTS_PC_MODULE_SW_FLT", [161] = "EGTS_PC_MODULE_FW_FLT", [162] = "EGTS_PC_MODULE_IO_FLT", [163] = "EGTS_PC_MODULE_MEM_FLT", [164] = "EGTS_PC_TEST_FAILED", } local command_srv_command_type = { [0001] = "СT_COMCONF", [0010] = "CT_MSGCONF", [0011] = "CT_MSGFROM", [0100] = "CT_MSGTO", [0101] = "CT_COM", [0110] = "CT_DELCOM", [0111] = "CT_SUBREQ", [1000] = "CT_DELIV", } local command_srv_command_confirmation_type = { [0000] = "CC_OK", [0001] = "CC_ERROR", [0010] = "CC_ILL", [0011] = "CC_DEL", [0100] = "CC_NFOUND", [0101] = "CC_NCONF", [0110] = "CC_INPROG", } local command_srv_command_code = { [0x0000] = "EGTS_RAW_DATA", [0x0001] = "EGTS_TEST_MODE", [0x0006] = "EGTS_CONFIG_RESET", [0x0007] = "EGTS_SET_AUTH_CODE", [0x0108] = "EGTS_RESTART", [0x020D] = "EGTS_ECALL_TEST_NUMBER", [0x0223] = "EGTS_ECALL_SMS_FALLBACK_NUMBER", } local header = { prv = ProtoField.new("ProtocolVersion", "egts.prv", ftypes.UINT8, nil, base.DEC), skid = ProtoField.new("SecurityKeyID", "egts.skid", ftypes.UINT8, nil, base.DEC), prf = ProtoField.new("Prefix", "egts.prf", ftypes.UINT8, nil, base.DEC, 0xc0), rte = ProtoField.new("Route", "egts.rte", ftypes.UINT8, nil, base.DEC, 0x20), ena = ProtoField.new("Encryption alg", "egts.ena", ftypes.UINT8, nil, base.DEC, 0x18), cmp = ProtoField.new("Compression", "egts.cmp", ftypes.UINT8, nil, base.DEC, 0x4), prt = ProtoField.new("Priority", "egts.prt", ftypes.UINT8, nil, base.DEC, 0x3), hl = ProtoField.new("Header length", "egts.hl", ftypes.UINT8, nil, base.DEC), he = ProtoField.new("Header encoding", "egts.he", ftypes.UINT8, nil, base.DEC), fdl = ProtoField.new("Frame data length", "egts.fdl", ftypes.UINT16, nil, base.DEC), pid = ProtoField.new("Packet identifier", "egts.pid", ftypes.UINT16, nil, base.DEC), pt = ProtoField.new("Packet type", "egts.pt", ftypes.UINT8, egts_packet_type, base.DEC), pra = ProtoField.new("Peer address", "egts.pra", ftypes.UINT16, nil, base.DEC), rca = ProtoField.new("Recipient address", "egts.rca", ftypes.UINT16, nil, base.DEC), ttl = ProtoField.new("Time to live", "egts.ttl", ftypes.UINT8, nil, base.DEC), hcs = ProtoField.new("Header checksum", "egts.hcs", ftypes.UINT8, nil, base.HEX), sfrd = ProtoField.new("Services frame data", "egts.sfrd", ftypes.BYTES), rpid = ProtoField.new("Response packetID", "egts.rpid", ftypes.UINT16, nil, base.DEC), pr = ProtoField.new("Processing result", "egts.pr", ftypes.UINT8, nil, base.DEC), rl = ProtoField.new("Record length", "egts.rl", ftypes.UINT16, nil, base.DEC), rn = ProtoField.new("Record number", "egts.rn", ftypes.UINT16, nil, base.DEC), ssod = ProtoField.new("Source service on device", "egts.ssod", ftypes.UINT8, nil, base.DEC, 0x80), rsod = ProtoField.new("Recipient service on device", "egts.rsod", ftypes.UINT8, nil, base.DEC, 0x40), grp = ProtoField.new("Group", "egts.grp", ftypes.UINT8, nil, base.DEC, 0x20), rpr = ProtoField.new("Record processing priority", "egts.rpr", ftypes.UINT8, nil, base.DEC, 0x18), tmfe = ProtoField.new("Time field exists", "egts.tmfe", ftypes.UINT8, nil, base.DEC, 0x4), evfe = ProtoField.new("Event ID field exists", "egts.evfe", ftypes.UINT8, nil, base.DEC, 0x2), obfe = ProtoField.new("Object ID field exists", "egts.obfe", ftypes.UINT8, nil, base.DEC, 0x1), oid = ProtoField.new("Object identifier", "egts.oid", ftypes.UINT32, nil, base.DEC), evid = ProtoField.new("Event identifier", "egts.evid", ftypes.UINT32, nil, base.DEC), tm = ProtoField.new("Time", "egts.tm", ftypes.UINT32, nil, base.DEC), sst = ProtoField.new("Source service type", "egts.sst", ftypes.UINT8, nil, base.DEC), rst = ProtoField.new("Recipient service type", "egts.rst", ftypes.UINT8, nil, base.DEC), rd = ProtoField.new("Record data", "egts.rd", ftypes.BYTES), srt = ProtoField.new("Subrecord type", "egts.srt", ftypes.UINT8, egts_subrecord_type, base.DEC), srl = ProtoField.new("Subrecord length", "egts.srl", ftypes.UINT16, nil, base.DEC), srd = ProtoField.new("Subrecord data", "egts.srd", ftypes.STRING), crn = ProtoField.new("Confirmed record number", "egts.crn", ftypes.UINT16, nil, base.DEC), rs = ProtoField.new("Record status", "egts.rs", ftypes.UINT8, result_code, base.DEC), tid = ProtoField.new("Terminal identifier", "egts.tid", ftypes.UINT32, nil, base.DEC), mne = ProtoField.new("MNE", "egts.mne", ftypes.UINT8, nil, base.DEC, 0x80), bse = ProtoField.new("BSE", "egts.bse", ftypes.UINT8, nil, base.DEC, 0x40), nide = ProtoField.new("NIDE", "egts.nide", ftypes.UINT8, nil, base.DEC, 0x20), ssra = ProtoField.new("SSRA", "egts.ssra", ftypes.UINT8, nil, base.DEC, 0x10), lngce = ProtoField.new("LNGCE", "egts.lngce", ftypes.UINT8, nil, base.DEC, 0x8), imsie = ProtoField.new("IMSIE", "egts.imsie", ftypes.UINT8, nil, base.DEC, 0x4), imeie = ProtoField.new("IMEIE", "egts.imeie", ftypes.UINT8, nil, base.DEC, 0x2), hdide = ProtoField.new("HDIDE", "egts.hdide", ftypes.UINT8, nil, base.DEC, 0x1), hdid = ProtoField.new("Home dispatcher identifier", "egts.hdid", ftypes.UINT16, nil, base.DEC), imei = ProtoField.new("International mobile equipment identity", "egts.imei", ftypes.STRING), imsi = ProtoField.new("International mobile subscriber identity", "egts.imsi", ftypes.STRING), lngc = ProtoField.new("Language code", "egts.lngc", ftypes.STRING), nid = ProtoField.new("Network identifier", "egts.nid", ftypes.UINT32, nil, base.DEC), bs = ProtoField.new("Buffer size", "egts.bs", ftypes.UINT32, nil, base.DEC), msisdn = ProtoField.new("Mobile station integrated services digital network number", "egts.msisdn", ftypes.STRING), ntm = ProtoField.new("Navigation time", "egts.ntm", ftypes.ABSOLUTE_TIME), lat = ProtoField.new("Latitude", "egts.lat", ftypes.DOUBLE), long = ProtoField.new("Longitude", "egts.long", ftypes.DOUBLE), alte = ProtoField.new("ALTE", "egts.alte", ftypes.UINT8, nil, base.DEC, 0x80), lohs = ProtoField.new("LONS", "egts.lohs", ftypes.UINT8, nil, base.DEC, 0x40), lahs = ProtoField.new("LAHS", "egts.lahs", ftypes.UINT8, nil, base.DEC, 0x20), mv = ProtoField.new("MV", "egts.mv", ftypes.UINT8, nil, base.DEC, 0x10), bb = ProtoField.new("BB", "egts.bb", ftypes.UINT8, nil, base.DEC, 0x8), cs = ProtoField.new("CS", "egts.cs", ftypes.UINT8, nil, base.DEC, 0x4), fix = ProtoField.new("FIX", "egts.fix", ftypes.UINT8, nil, base.DEC, 0x2), vld = ProtoField.new("VLD", "egts.vld", ftypes.UINT8, nil, base.DEC, 0x1), dirh = ProtoField.new("Direction the Highest bit", "egts.dirh", ftypes.UINT16, nil, base.DEC, 0x8000), alts = ProtoField.new("Altitude sign", "egts.alts", ftypes.UINT16, nil, base.DEC, 0x4000), spd = ProtoField.new("Speed", "egts.spd", ftypes.UINT16, nil, base.DEC, 0x3fff), dir = ProtoField.new("Direction", "egts.dir", ftypes.UINT8, nil, base.DEC), odm = ProtoField.new("Odometer", "egts.odm", ftypes.UINT32, nil, base.DEC), din = ProtoField.new("Digital inputs", "egts.din", ftypes.UINT8, nil, base.DEC), src = ProtoField.new("Source", "egts.src", ftypes.UINT8, nil, base.DEC), alt = ProtoField.new("Altitude", "egts.alt", ftypes.UINT32, nil, base.DEC), srcd = ProtoField.new("Source data", "egts.srcd", ftypes.UINT16, nil, base.DEC), nsfe = ProtoField.new("NSFE", "egts.nsfe", ftypes.UINT8, nil, base.DEC, 0x10), sfe = ProtoField.new("SFE", "egts.sfe", ftypes.UINT8, nil, base.DEC, 0x8), pfe = ProtoField.new("PFE", "egts.pfe", ftypes.UINT8, nil, base.DEC, 0x4), hfe = ProtoField.new("HFE", "egts.hfe", ftypes.UINT8, nil, base.DEC, 0x2), vfe = ProtoField.new("VFE", "egts.vfe", ftypes.UINT8, nil, base.DEC, 0x1), vdop = ProtoField.new("Vertical dilution of precision", "egts.vdop", ftypes.UINT16, nil, base.DEC), hdop = ProtoField.new("Horizontal dilution of precision", "egts.hdop", ftypes.UINT16, nil, base.DEC), pdop = ProtoField.new("Position dilution of precision", "egts.pdop", ftypes.UINT16, nil, base.DEC), sat = ProtoField.new("Satellites", "egts.sat", ftypes.UINT8, nil, base.DEC), ns = ProtoField.new("Navigation system", "egts.ns", ftypes.UINT16, nil, base.DEC), st = ProtoField.new("State", "egts.ns", ftypes.UINT8, nil, base.DEC), mpsv = ProtoField.new("Main power source voltage", "egts.mpsv", ftypes.UINT8, nil, base.DEC), bbv = ProtoField.new("Back up battery voltage", "egts.bbv", ftypes.UINT8, nil, base.DEC), ibv = ProtoField.new("Internal battery voltage", "egts.ibv", ftypes.UINT8, nil, base.DEC), nms = ProtoField.new("NMS", "egts.nms", ftypes.UINT8, nil, base.DEC, 0x4), ibu = ProtoField.new("IBU", "egts.ibu", ftypes.UINT8, nil, base.DEC, 0x2), bbu = ProtoField.new("BBU", "egts.bbu", ftypes.UINT8, nil, base.DEC, 0x1), sfrcs = ProtoField.new("Services frame data checksum", "egts.sfrcs", ftypes.UINT16, nil, base.HEX), llsef = ProtoField.new("Liquid Level Sensor Error Flag", "egts.llsef", ftypes.UINT8, nil, base.DEC, 0x40), llsvu = ProtoField.new("Liquid Level Sensor Value Unit", "egts.llsvu", ftypes.UINT8, nil, base.DEC, 0x30), rdf = ProtoField.new("Raw Data Flag", "egts.rdf", ftypes.UINT8, nil, base.DEC, 0x8), llsn = ProtoField.new("Liquid Level Sensor Number", "egts.llsn", ftypes.UINT8, nil, base.DEC, 0x7), maddr = ProtoField.new("Module address", "egts.maddr", ftypes.UINT16, nil, base.DEC), llsd = ProtoField.new("Liquid Level Sensor Data", "egts.llsd", ftypes.UINT32, nil, base.DEC), llsdraw = ProtoField.new("Liquid Level Sensor Data bytes", "egts.llsdraw", ftypes.STRING), dioe1 = ProtoField.new("Digital Inputs Octet Exists 1", "egts.dioe1", ftypes.UINT8, nil, base.DEC, 0x1), dioe2 = ProtoField.new("Digital Inputs Octet Exists 2", "egts.dioe2", ftypes.UINT8, nil, base.DEC, 0x2), dioe3 = ProtoField.new("Digital Inputs Octet Exists 3", "egts.dioe3", ftypes.UINT8, nil, base.DEC, 0x4), dioe4 = ProtoField.new("Digital Inputs Octet Exists 4", "egts.dioe4", ftypes.UINT8, nil, base.DEC, 0x8), dioe5 = ProtoField.new("Digital Inputs Octet Exists 5", "egts.dioe5", ftypes.UINT8, nil, base.DEC, 0x10), dioe6 = ProtoField.new("Digital Inputs Octet Exists 6", "egts.dioe6", ftypes.UINT8, nil, base.DEC, 0x20), dioe7 = ProtoField.new("Digital Inputs Octet Exists 7", "egts.dioe7", ftypes.UINT8, nil, base.DEC, 0x40), dioe8 = ProtoField.new("Digital Inputs Octet Exists 8", "egts.dioe8", ftypes.UINT8, nil, base.DEC, 0x80), dout = ProtoField.new("Digital Outputs", "egts.dout", ftypes.UINT8, nil, base.DEC), asfe1 = ProtoField.new("Analog Sensor Fields Exist 1", "egts.asfe1", ftypes.UINT8, nil, base.DEC, 0x1), asfe2 = ProtoField.new("Analog Sensor Fields Exist 2", "egts.asfe2", ftypes.UINT8, nil, base.DEC, 0x2), asfe3 = ProtoField.new("Analog Sensor Fields Exist 3", "egts.asfe3", ftypes.UINT8, nil, base.DEC, 0x4), asfe4 = ProtoField.new("Analog Sensor Fields Exist 4", "egts.asfe4", ftypes.UINT8, nil, base.DEC, 0x8), asfe5 = ProtoField.new("Analog Sensor Fields Exist 5", "egts.asfe5", ftypes.UINT8, nil, base.DEC, 0x10), asfe6 = ProtoField.new("Analog Sensor Fields Exist 6", "egts.asfe6", ftypes.UINT8, nil, base.DEC, 0x20), asfe7 = ProtoField.new("Analog Sensor Fields Exist 7", "egts.asfe7", ftypes.UINT8, nil, base.DEC, 0x40), asfe8 = ProtoField.new("Analog Sensor Fields Exist 8", "egts.asfe8", ftypes.UINT8, nil, base.DEC, 0x80), adio1 = ProtoField.new("Additional Digital Inputs Octet 1", "egts.adio1", ftypes.UINT8, nil, base.DEC), adio2 = ProtoField.new("Additional Digital Inputs Octet 2", "egts.adio2", ftypes.UINT8, nil, base.DEC), adio3 = ProtoField.new("Additional Digital Inputs Octet 3", "egts.adio3", ftypes.UINT8, nil, base.DEC), adio4 = ProtoField.new("Additional Digital Inputs Octet 4", "egts.adio4", ftypes.UINT8, nil, base.DEC), adio5 = ProtoField.new("Additional Digital Inputs Octet 5", "egts.adio5", ftypes.UINT8, nil, base.DEC), adio6 = ProtoField.new("Additional Digital Inputs Octet 6", "egts.adio6", ftypes.UINT8, nil, base.DEC), adio7 = ProtoField.new("Additional Digital Inputs Octet 7", "egts.adio7", ftypes.UINT8, nil, base.DEC), adio8 = ProtoField.new("Additional Digital Inputs Octet 8", "egts.adio8", ftypes.UINT8, nil, base.DEC), ans1 = ProtoField.new("Analog Sensor 1", "egts.ans1", ftypes.UINT16, nil, base.DEC), ans2 = ProtoField.new("Analog Sensor 2", "egts.ans2", ftypes.UINT16, nil, base.DEC), ans3 = ProtoField.new("Analog Sensor 3", "egts.ans3", ftypes.UINT16, nil, base.DEC), ans4 = ProtoField.new("Analog Sensor 4", "egts.ans4", ftypes.UINT16, nil, base.DEC), ans5 = ProtoField.new("Analog Sensor 5", "egts.ans5", ftypes.UINT16, nil, base.DEC), ans6 = ProtoField.new("Analog Sensor 6", "egts.ans6", ftypes.UINT16, nil, base.DEC), ans7 = ProtoField.new("Analog Sensor 7", "egts.ans7", ftypes.UINT16, nil, base.DEC), ans8 = ProtoField.new("Analog Sensor 8", "egts.ans8", ftypes.UINT16, nil, base.DEC), cn = ProtoField.new("Counter Number", "egts.cn", ftypes.UINT8, nil, base.DEC), cnv = ProtoField.new("Counter Value", "egts.cnv", ftypes.UINT16, nil, base.DEC), -- EGTS_SR_COMMAND_DATA CT = ProtoField.new("Command Type", "egts.CT", ftypes.UINT8, command_srv_command_type, base.DEC, 0xF0), CCT = ProtoField.new("Command Confirmation Type", "egts.CCT", ftypes.UINT8, command_srv_command_confirmation_type, base.DEC, 0x0F), CID = ProtoField.new("Command Identifier", "egts.CID", ftypes.UINT32, nil, base.DEC), SID = ProtoField.new("Source Identifier", "egts.SID", ftypes.UINT32, nil, base.DEC), ACFE = ProtoField.new("Authorization Code Field Exist", "egts.ACFE", ftypes.UINT8, nil, base.DEC, 0x02), CHSFE = ProtoField.new("Charset Field Exists", "egts.CHSFE", ftypes.UINT8, nil, base.DEC, 0x01), CHS = ProtoField.new("Charset", "egts.CHS", ftypes.UINT8, nil, base.DEC), ACL = ProtoField.new("Authorization Code Length", "egts.ACL", ftypes.UINT8, nil, base.DEC), AC = ProtoField.new("Authorization Code", "egts.AC", ftypes.STRING), ADR = ProtoField.new("Address", "egts.ADR", ftypes.UINT16, nil, base.DEC), SZ = ProtoField.new("Size", "egts.SZ", ftypes.UINT8, nil, base.DEC, 0xF0), ACT = ProtoField.new("Action", "egts.ACT", ftypes.UINT8, nil, base.DEC, 0x0F), CCD = ProtoField.new("Command Code", "egts.CCD", ftypes.UINT16, command_srv_command_code, base.HEX), DT = ProtoField.new("Data", "egts.DT", ftypes.STRING), } -- регистрация полей протокола egts_proto.fields = header local function parse_sr_command_data_body(buf, tree) local cur_offset = 0 tree:add(header.ADR, buf:range(cur_offset, 2):le_uint()) cur_offset = cur_offset + 2 local sub = buf:range(cur_offset, 1):le_uint() tree:add(header.SZ, sub) tree:add(header.ACT, sub) cur_offset = cur_offset + 1 tree:add(header.CCD, buf:range(cur_offset, 2):le_uint()) cur_offset = cur_offset + 2 if cur_offset < buf:len() then tree:add(header.DT, buf:range(cur_offset)) end end local function parse_sr_command_data(buf, tree) local cur_offset = 0 local types = buf:range(cur_offset, 1):le_uint() tree:add(header.CT, types) tree:add(header.CCT, types) cur_offset = cur_offset + 1 tree:add(header.CID, buf:range(cur_offset, 4):le_uint()) cur_offset = cur_offset + 4 tree:add(header.SID, buf:range(cur_offset, 4):le_uint()) cur_offset = cur_offset + 4 local flags = buf:range(cur_offset, 1):le_uint() tree:add(header.ACFE, flags) tree:add(header.CHSFE, flags) cur_offset = cur_offset + 1 if bit.band(flags, 0x1) ~= 0 then tree:add(header.CHS, buf:range(cur_offset, 1):le_uint()) cur_offset = cur_offset + 1 end if bit.band(flags, 0x2) ~= 0 then local len = buf:range(cur_offset, 1):le_uint(); tree:add(header.ACL, len) cur_offset = cur_offset + 1 tree:add(header.AC, buf:range(cur_offset, len)) cur_offset = cur_offset + len end --tree:add(header.srd, buf:range(cur_offset):bytes():tohex()) local cmd_data = buf:range(cur_offset) local cmd = tree:add(egts_proto, cmd_data, "Subrecord data") parse_sr_command_data_body(cmd_data, cmd); return buf:len() end local MIN_HEADE_LENGHT = 11 local function get_packet_type(type_id) return egts_packet_type[type_id] end local function get_egts_length(tvbuf, pktinfo, offset) local header_len = tvbuf:range(offset + 3, 1):uint() local data_len = tvbuf:range(offset + 5, 2):le_uint() return header_len + data_len + 2 end local function parse_sr_response(buf, tree) local cur_offset = 0 tree:add(header.crn, buf:range(cur_offset, 2):le_uint()) cur_offset = cur_offset + 2 tree:add(header.rs, buf:range(cur_offset, 1):uint()) cur_offset = cur_offset + 1 return buf:len() end local function parse_sr_term_identity(buf, tree) local cur_offset = 0 tree:add(header.tid, buf:range(cur_offset, 4):le_uint()) cur_offset = cur_offset + 4 local flags = buf:range(cur_offset, 1):le_uint() tree:add(header.mne, flags) tree:add(header.bse, flags) tree:add(header.nide, flags) tree:add(header.ssra, flags) tree:add(header.lngce, flags) tree:add(header.imsie, flags) tree:add(header.imeie, flags) tree:add(header.hdide, flags) cur_offset = cur_offset + 1 if bit.band(flags, 0x1) ~= 0 then tree:add(header.hdid, buf:range(cur_offset, 2):uint()) cur_offset = cur_offset + 2 end if bit.band(flags, 0x2) ~= 0 then tree:add(header.imei, buf:range(cur_offset, 15):string()) cur_offset = cur_offset + 15 end if bit.band(flags, 0x4) ~= 0 then tree:add(header.imsi, buf:range(cur_offset, 16):string()) cur_offset = cur_offset + 16 end if bit.band(flags, 0x8) ~= 0 then tree:add(header.lngc, buf:range(cur_offset, 3):string()) cur_offset = cur_offset + 3 end if bit.band(flags, 0x20) ~= 0 then tree:add(header.nid, buf:range(cur_offset, 3):le_uint()) cur_offset = cur_offset + 3 end if bit.band(flags, 0x40) ~= 0 then tree:add(header.bs, buf:range(cur_offset, 2):le_uint()) cur_offset = cur_offset + 2 end if bit.band(flags, 0x80) ~= 0 then tree:add(header.msisdn, buf:range(cur_offset, 15):le_uint()) cur_offset = cur_offset + 15 end return cur_offset end local function parse_sr_pos_data(buf, tree) local cur_offset = 0 local ntm = buf:range(cur_offset, 4):le_uint() local offset_time = os.time { year = 2010, month = 1, day = 1, hour = 0 } ntm = ntm + offset_time tree:add(header.ntm, NSTime.new(ntm)) cur_offset = cur_offset + 4 tree:add(header.lat, buf:range(cur_offset, 4):le_uint() * 90 / 0xFFFFFFFF) cur_offset = cur_offset + 4 tree:add(header.long, buf:range(cur_offset, 4):le_uint() * 180 / 0xFFFFFFFF) cur_offset = cur_offset + 4 local flg = buf:range(cur_offset, 1):uint() tree:add(header.alte, flg) tree:add(header.lohs, flg) tree:add(header.lahs, flg) tree:add(header.mv, flg) tree:add(header.bb, flg) tree:add(header.cs, flg) tree:add(header.fix, flg) tree:add(header.vld, flg) cur_offset = cur_offset + 1 local spd = buf:range(cur_offset, 2):le_uint() tree:add(header.dirh, spd) tree:add(header.alts, spd) tree:add(header.spd, spd) cur_offset = cur_offset + 2 tree:add(header.dir, buf:range(cur_offset, 1):uint()) cur_offset = cur_offset + 1 tree:add(header.odm, buf:range(cur_offset, 3):le_uint()) cur_offset = cur_offset + 3 tree:add(header.din, buf:range(cur_offset, 1):uint()) cur_offset = cur_offset + 1 tree:add(header.src, buf:range(cur_offset, 1):uint()) cur_offset = cur_offset + 1 if bit.band(flg, 0x80) ~= 0 then tree:add(header.alt, buf:range(cur_offset, 3):le_uint()) cur_offset = cur_offset + 3 end -- TODO: разобраться с разбором SourceData return buf:len() end local function parse_sr_ext_pos_data(buf, tree) local cur_offset = 0 local flags = buf:range(cur_offset, 1):uint() tree:add(header.nsfe, flags) tree:add(header.sfe, flags) tree:add(header.pfe, flags) tree:add(header.hfe, flags) tree:add(header.vfe, flags) cur_offset = cur_offset + 1 if bit.band(flags, 0x1) ~= 0 then -- если флаг VFE установлен, то есть поле снижение точности в вертикальной плоскости tree:add(header.vdop, buf:range(cur_offset, 2):le_uint()) cur_offset = cur_offset + 2 end if bit.band(flags, 0x2) ~= 0 then -- если флаг HFE установлен, то есть поле снижение точности в горизонтальной плоскости tree:add(header.hdop, buf:range(cur_offset, 2):le_uint()) cur_offset = cur_offset + 2 end if bit.band(flags, 0x4) ~= 0 then -- если флаг HFE установлен, то есть поле снижение точности по местоположению tree:add(header.pdop, buf:range(cur_offset, 2):le_uint()) cur_offset = cur_offset + 2 end local sectionLen = buf:len() if bit.band(flags, 0x8) ~= 0 then -- если флаг SFE установлен, то есть поле c данными о текущем количестве видимых спутников и типе используемой навигационной спутниковой системы tree:add(header.sat, buf:range(cur_offset, 1):uint()) cur_offset = cur_offset + 1 if cur_offset < sectionLen then tree:add(header.ns, buf:range(cur_offset, 2):le_uint()) cur_offset = cur_offset + 2 end end return sectionLen end local function parse_sr_state_data(buf, tree) local cur_offset = 0 tree:add(header.st, buf:range(cur_offset, 1):uint()) cur_offset = cur_offset + 1 tree:add(header.mpsv, buf:range(cur_offset, 1):uint()) cur_offset = cur_offset + 1 tree:add(header.bbv, buf:range(cur_offset, 1):uint()) cur_offset = cur_offset + 1 tree:add(header.ibv, buf:range(cur_offset, 1):uint()) cur_offset = cur_offset + 1 local flags = buf:range(cur_offset, 1):uint() tree:add(header.nms, flags) tree:add(header.ibu, flags) tree:add(header.bbu, flags) cur_offset = cur_offset + 1 return cur_offset end local function parse_sr_liquid_level_sensor(buf, tree) local cur_offset = 0 local flags = buf:range(cur_offset, 1):uint() tree:add(header.llsef, flags) tree:add(header.llsvu, flags) tree:add(header.rdf, flags) tree:add(header.llsn, flags) cur_offset = cur_offset + 1 tree:add(header.maddr, buf:range(cur_offset, 2):le_uint()) cur_offset = cur_offset + 2 if bit.band(flags, 0x8) == 0 then -- если флаг RDF флаг установлен, то значение имеет длину 4 байта tree:add(header.llsd, buf:range(cur_offset, 4):le_uint()) cur_offset = cur_offset + 4 else tree:add(header.llsdraw, buf:bytes():tohex()) end return cur_offset end local function parse_sr_ad_sensors_data(buf, tree) local cur_offset = 0 local sectionLen = buf:len() local diflg = buf:range(cur_offset, 1):uint() tree:add(header.dioe1, diflg) tree:add(header.dioe2, diflg) tree:add(header.dioe3, diflg) tree:add(header.dioe4, diflg) tree:add(header.dioe5, diflg) tree:add(header.dioe6, diflg) tree:add(header.dioe7, diflg) tree:add(header.dioe8, diflg) cur_offset = cur_offset + 1 tree:add(header.dout, buf:range(cur_offset, 1):uint()) cur_offset = cur_offset + 1 local ansflg = buf:range(cur_offset, 1):uint() tree:add(header.asfe1, ansflg) tree:add(header.asfe2, ansflg) tree:add(header.asfe3, ansflg) tree:add(header.asfe4, ansflg) tree:add(header.asfe5, ansflg) tree:add(header.asfe6, ansflg) tree:add(header.asfe7, ansflg) tree:add(header.asfe8, ansflg) cur_offset = cur_offset + 1 if bit.band(diflg, 0x1) ~= 0 then tree:add(header.adio1, buf:range(cur_offset, 1):uint()) cur_offset = cur_offset + 1 end if bit.band(diflg, 0x2) ~= 0 then tree:add(header.adio2, buf:range(cur_offset, 1):uint()) cur_offset = cur_offset + 1 end if bit.band(diflg, 0x4) ~= 0 then tree:add(header.adio3, buf:range(cur_offset, 1):uint()) cur_offset = cur_offset + 1 end if bit.band(diflg, 0x8) ~= 0 then tree:add(header.adio4, buf:range(cur_offset, 1):uint()) cur_offset = cur_offset + 1 end if bit.band(diflg, 0x10) ~= 0 then tree:add(header.adio5, buf:range(cur_offset, 1):uint()) cur_offset = cur_offset + 1 end if bit.band(diflg, 0x20) ~= 0 then tree:add(header.adio6, buf:range(cur_offset, 1):uint()) cur_offset = cur_offset + 1 end if bit.band(diflg, 0x40) ~= 0 then tree:add(header.adio7, buf:range(cur_offset, 1):uint()) cur_offset = cur_offset + 1 end if bit.band(diflg, 0x80) ~= 0 then tree:add(header.adio8, buf:range(cur_offset, 1):uint()) cur_offset = cur_offset + 1 end if bit.band(ansflg, 0x1) ~= 0 then tree:add(header.ans1, buf:range(cur_offset, 3):le_uint()) cur_offset = cur_offset + 3 end if bit.band(ansflg, 0x2) ~= 0 then tree:add(header.ans2, buf:range(cur_offset, 3):le_uint()) cur_offset = cur_offset + 3 end if bit.band(ansflg, 0x4) ~= 0 then tree:add(header.ans3, buf:range(cur_offset, 3):le_uint()) cur_offset = cur_offset + 3 end if bit.band(ansflg, 0x8) ~= 0 then tree:add(header.ans4, buf:range(cur_offset, 3):le_uint()) cur_offset = cur_offset + 3 end if bit.band(ansflg, 0x10) ~= 0 then tree:add(header.ans5, buf:range(cur_offset, 3):le_uint()) cur_offset = cur_offset + 3 end if bit.band(ansflg, 0x20) ~= 0 then tree:add(header.ans6, buf:range(cur_offset, 3):le_uint()) cur_offset = cur_offset + 3 end if bit.band(ansflg, 0x40) ~= 0 then tree:add(header.ans7, buf:range(cur_offset, 3):le_uint()) cur_offset = cur_offset + 3 end if bit.band(ansflg, 0x80) ~= 0 then tree:add(header.ans8, buf:range(cur_offset, 3):le_uint()) cur_offset = cur_offset + 3 end return sectionLen end local function parse_sr_abs_cntr_data(buf, tree) local cur_offset = 0 tree:add(header.cnv, buf:range(cur_offset, 1):uint()) cur_offset = cur_offset + 1 tree:add(header.cnv, buf:range(cur_offset, 3):le_uint()) cur_offset = cur_offset + 3 return offset end local function parse_sr_result_code(buf, tree) local cur_offset = 0 tree:add(header.rs, buf:range(cur_offset, 1):uint()) cur_offset = cur_offset + 1 return buf:len() end local function parse_subrecord(buf, tree) local subrecords = tree:add(egts_proto, buf, "Record data") local current_offset = 0 while current_offset < buf:len() do local subrecord = subrecords:add(egts_proto, buf, "Subrecord") local subrecord_type = buf:range(current_offset, 1):uint() subrecord:add(header.srt, subrecord_type) current_offset = current_offset + 1 local subrecord_data_len = buf:range(current_offset, 2):le_uint() subrecord:add(header.srl, subrecord_data_len) current_offset = current_offset + 2 local sr_data = buf:range(current_offset, subrecord_data_len) local srd = subrecord:add(egts_proto, sr_data, "Subrecord data") if subrecord_type == 0 then parse_sr_response(sr_data, srd) elseif subrecord_type == 1 then parse_sr_term_identity(sr_data, srd) elseif subrecord_type == 9 then parse_sr_result_code(sr_data, srd) elseif subrecord_type == 16 then parse_sr_pos_data(sr_data, srd) elseif subrecord_type == 17 then parse_sr_ext_pos_data(sr_data, srd) elseif subrecord_type == 20 then parse_sr_state_data(sr_data, srd) elseif subrecord_type == 27 then parse_sr_liquid_level_sensor(sr_data, srd) elseif subrecord_type == 18 then parse_sr_ad_sensors_data(sr_data, srd) elseif subrecord_type == 25 then parse_sr_abs_cntr_data(sr_data, srd) elseif subrecord_type == 51 then parse_sr_command_data(sr_data, srd) else subrecord:add(header.srd, sr_data:bytes():tohex()) end current_offset = current_offset + subrecord_data_len end return current_offset end local function parse_sdr(buf, tree) local current_offset = 0 local sdr_len = 0 while (current_offset < buf:len()) do sdr_len = buf:range(current_offset, 2):le_uint() local service_data_record = tree:add(egts_proto, buf, "Service Data Record") current_offset = current_offset + 2 service_data_record:add(header.rl, sdr_len) service_data_record:add(header.rn, buf:range(current_offset, 2):le_uint()) current_offset = current_offset + 2 local rfl = buf:range(current_offset, 1):uint() service_data_record:add(header.ssod, rfl) service_data_record:add(header.rsod, rfl) service_data_record:add(header.grp, rfl) service_data_record:add(header.rpr, rfl) service_data_record:add(header.tmfe, rfl) service_data_record:add(header.evfe, rfl) service_data_record:add(header.obfe, rfl) current_offset = current_offset + 1 if bit.band(rfl, 0x1) ~= 0 then -- если флаг OBFE установлен, то значит есть поле с id объекта и его надо заполнить service_data_record:add(header.oid, buf:range(current_offset, 4):le_uint()) current_offset = current_offset + 4 end if bit.band(rfl, 0x2) ~= 0 then -- если флаг EVFE установлен, то значит присутствует поле с id события service_data_record:add(header.evid, buf:range(current_offset, 4):le_uint()) current_offset = current_offset + 4 end if bit.band(rfl, 0x4) ~= 0 then -- если флаг TMFE установлен, то есть поле со временем, которое нужно разобрать service_data_record:add(header.tm, buf:range(current_offset, 4):le_uint()) current_offset = current_offset + 4 end service_data_record:add(header.sst, buf:range(current_offset, 1):uint()) current_offset = current_offset + 1 service_data_record:add(header.rst, buf:range(current_offset, 1):uint()) current_offset = current_offset + 1 local computed_bytes = parse_subrecord(buf:range(current_offset, sdr_len), service_data_record) current_offset = current_offset + computed_bytes end return current_offset end local function parse_pt_response (buf, tree) local current_offset = 0 tree:add(header.rpid, buf:range(current_offset, 2):le_uint()) current_offset = current_offset + 2 tree:add(header.pr, buf:range(current_offset, 1):uint()) current_offset = current_offset + 1 if buf:len() - current_offset > 0 then local computed_bytes = parse_sdr(buf:range(current_offset), tree) current_offset = current_offset + computed_bytes end return buf:len() end local function parse_pt_appdata (buf, tree) local current_offset = 0 local computed_bytes = 0 while (current_offset < buf:len()) do computed_bytes = parse_sdr(buf:range(current_offset), tree) current_offset = current_offset + computed_bytes end return current_offset end local function parse_pt_signed_appdata (buf, tree) tree:add(header.sfrd, buf:raw()) return buf:len() end local function dissect_egts_pdu(tvbuf, pktinfo, root) local header_len = tvbuf:range(3, 1):uint() local data_len = tvbuf:range(5, 2):le_uint() local msglen = header_len + data_len + 2 pktinfo.cols.protocol:set("EGTS") -- Начинаем заполнения дерева в отображении local tree = root:add(egts_proto, tvbuf:range(0, msglen)) tree:add(header.prv, tvbuf:range(0, 1):uint()) tree:add(header.skid, tvbuf:range(1, 1):uint()) local prf_tvbr = tvbuf:range(2, 1):uint() tree:add(header.prf, prf_tvbr) tree:add(header.rte, prf_tvbr) tree:add(header.ena, prf_tvbr) tree:add(header.cmp, prf_tvbr) tree:add(header.prt, prf_tvbr) tree:add(header.hl, header_len) tree:add(header.he, tvbuf:range(4, 1):uint()) tree:add(header.fdl, data_len) tree:add(header.pid, tvbuf:range(7, 2):le_uint()) local packet_type_id = tvbuf:range(9, 1):uint() tree:add(header.pt, packet_type_id) local field_offset = 10; if bit.band(prf_tvbr, 0x20) ~= 0 then -- если RTE флаг присутствует, то заполняем не обязательные поля tree:add(header.pra, tvbuf:range(field_offset, 2):le_uint()) field_offset = field_offset + 2 tree:add(header.rca, tvbuf:range(field_offset, 2):le_uint()) field_offset = field_offset + 2 tree:add(header.ttl, tvbuf:range(field_offset, 1):uint()) field_offset = field_offset + 1 end tree:add(header.hcs, tvbuf:range(field_offset, 1):uint()) field_offset = field_offset + 1 local subtree = tree:add(egts_proto, tvbuf, "Services frame data") if get_packet_type(packet_type_id) == EGTS_PT_RESPONSE then parse_pt_response(tvbuf:range(field_offset, data_len), subtree) elseif get_packet_type(packet_type_id) == EGTS_PT_APPDATA then parse_pt_appdata(tvbuf:range(field_offset, data_len), subtree) else parse_pt_signed_appdata(tvbuf:range(field_offset, data_len), subtree) end tree:add(header.sfrcs, tvbuf:range(field_offset + data_len, 2):le_uint()) return msglen end -- задаем функию обработки, которая получает на вход данные tvbuf (объект Tvb), информацию о пакете -- pktinfo (объект Pinfo) и root дерево распарсенного объекта. function egts_proto.dissector(tvbuf, pktinfo, root) dissect_tcp_pdus(tvbuf, root, MIN_HEADE_LENGHT, get_egts_length, dissect_egts_pdu) local bytes_consumed = tvbuf:len() return bytes_consumed end -- добавляем парсер в таблицу DissectorTable.get("tcp.port"):add(default_settings.port, egts_proto)