···398398}
399399400400-- ============================================================================
401401+-- LOOKUP TABLES FOR ARGUMENT LABELS
402402+-- ============================================================================
403403+404404+local HAS_DMST_ARG_1 = {
405405+ [0x0000] = true, [0x1000] = true, [0x1001] = true, [0x1002] = true,
406406+ [0x1003] = true, [0x1004] = true, [0x1006] = true, [0x1007] = true,
407407+ [0x1008] = true, [0x100a] = true, [0x100d] = true, [0x1010] = true,
408408+ [0x1011] = true, [0x1012] = true, [0x1013] = true, [0x1014] = true,
409409+ [0x1101] = true, [0x1102] = true, [0x1103] = true, [0x1105] = true,
410410+ [0x1106] = true, [0x1114] = true, [0x1206] = true, [0x1214] = true,
411411+ [0x1300] = true, [0x1301] = true, [0x2002] = true, [0x2003] = true,
412412+ [0x2004] = true, [0x2102] = true, [0x2104] = true, [0x2204] = true,
413413+ [0x2904] = true, [0x2b04] = true, [0x2c04] = true, [0x3000] = true,
414414+ [0x3007] = true, [0x3100] = true, [0x3e03] = true
415415+}
416416+417417+local MSG_ARG_LABELS = {
418418+ [0x0000] = { [1] = "Our Device Number" },
419419+ [0x1000] = { [1] = "DMST", [2] = "Sort", [3] = "Unknown (0x00ffffff)" },
420420+ [0x3100] = { [1] = "DMST", [2] = "Rekordbox ID", [3] = "Unknown 1", [4] = "Unknown 2" },
421421+ [0x2c04] = { [1] = "DMST", [2] = "Rekordbox ID", [3] = "Tag", [4] = "Extension" },
422422+ [0x2102] = { [1] = "DMST", [2] = "Rekordbox ID" },
423423+ [0x4101] = {
424424+ [1] = "Parent ID", [2] = "Main ID", [3] = "Label 1 Len", [4] = "Label 1",
425425+ [5] = "Label 2 Len", [6] = "Label 2", [7] = "Item Type", [8] = "Flags",
426426+ [9] = "Artwork ID", [10] = "Position", [11] = "Unknown", [12] = "Unknown"
427427+ },
428428+ [0x4201] = { [1] = "Status", [2] = "Total Items" },
429429+ [0x4001] = { [1] = "Item Count" },
430430+ [0x4000] = { [1] = "Request Type Echo", [2] = "Items Found" },
431431+ [0x3000] = { [1] = "DMST", [2] = "Offset", [3] = "Limit", [4] = "Unknown", [5] = "Total Items", [6] = "Unknown" },
432432+ [0x4b02] = { [1] = "Request Type Echo", [2] = "Reserved", [3] = "Capability Level", [4] = "Placeholder (Empty String)" }
433433+}
434434+435435+-- ============================================================================
401436-- HELPERS
402437-- ============================================================================
403438404439-- Decodes a 4-byte buffer as a reverse-ASCII string
405440local function get_reverse_ascii(buf)
406441 local b = buf:bytes()
407407- local s = ""
408408- for j = 3, 0, -1 do
409409- local c = b:get_index(j)
410410- if c ~= 0 then s = s .. string.char(c) end
411411- end
412412- return s
442442+ return string.char(
443443+ b:get_index(3),
444444+ b:get_index(2),
445445+ b:get_index(1),
446446+ b:get_index(0)
447447+ ):gsub("%z", "")
413448end
414449415450-- Label for specific arguments based on message type
416451function get_arg_label(msg_type, arg_idx, val)
417417- -- Many request types have DMST as the first argument
418418- if arg_idx == 1 and (
419419- msg_type == 0x1000 or -- Root Menu
420420- msg_type == 0x1001 or -- Genre Menu
421421- msg_type == 0x1002 or -- Artist Menu
422422- msg_type == 0x1003 or -- Album Menu
423423- msg_type == 0x1004 or -- Track Menu
424424- msg_type == 0x1006 or -- BPM Menu
425425- msg_type == 0x1007 or -- Rating Menu
426426- msg_type == 0x1008 or -- Year Menu
427427- msg_type == 0x100a or -- Label Menu
428428- msg_type == 0x100d or -- Color Menu
429429- msg_type == 0x1010 or -- Time Menu
430430- msg_type == 0x1011 or -- Bitrate Menu
431431- msg_type == 0x1012 or -- History Menu
432432- msg_type == 0x1013 or -- Filename Menu
433433- msg_type == 0x1014 or -- Key Menu
434434- msg_type == 0x1101 or -- ArtistsForGenre
435435- msg_type == 0x1102 or -- AlbumsForArtist
436436- msg_type == 0x1103 or -- GetTrackList
437437- msg_type == 0x1105 or -- GetTrackCount
438438- msg_type == 0x1106 or -- BPM Distances
439439- msg_type == 0x1114 or -- DistancesForKey
440440- msg_type == 0x1206 or -- TracksForBpmRange
441441- msg_type == 0x1214 or -- TracksNearKey
442442- msg_type == 0x1300 or -- Search
443443- msg_type == 0x1301 or -- TracksForGenreArtistAlbum
444444- msg_type == 0x2002 or -- GetMetadata
445445- msg_type == 0x2003 or -- GetArtwork
446446- msg_type == 0x2004 or -- GetWaveformPreview
447447- msg_type == 0x2102 or -- GetTrackStreamingReq
448448- msg_type == 0x2104 or -- GetCuePoints
449449- msg_type == 0x2204 or -- GetBeatGrid
450450- msg_type == 0x2904 or -- GetWaveformDetail
451451- msg_type == 0x2b04 or -- GetExtCuePoints
452452- msg_type == 0x2c04 or -- GetAnalysisTag
453453- msg_type == 0x3000 or -- RenderMenu
454454- msg_type == 0x3007 or -- SetupBrowseContext
455455- msg_type == 0x3100 or -- TrackLoadNotification
456456- msg_type == 0x3e03 -- GetCapabilities
457457- ) then
452452+ if arg_idx == 1 and HAS_DMST_ARG_1[msg_type] then
458453 return "DMST"
459454 end
460455461461- if msg_type == 0x1000 then -- Root Menu
462462- local labels = {
463463- [1] = "DMST",
464464- [2] = "Sort",
465465- [3] = "Unknown (0x00ffffff)"
466466- }
467467- return labels[arg_idx]
468468- elseif msg_type == 0x3100 then -- TrackLoadNotification
469469- local labels = {
470470- [1] = "DMST",
471471- [2] = "Rekordbox ID",
472472- [3] = "Unknown 1",
473473- [4] = "Unknown 2"
474474- }
475475- return labels[arg_idx]
476476- elseif msg_type == 0x2c04 then -- GetAnalysisTag
477477- local labels = {
478478- [1] = "DMST",
479479- [2] = "Rekordbox ID",
480480- [3] = "Tag",
481481- [4] = "Extension"
482482- }
483483- return labels[arg_idx]
484484- elseif msg_type == 0x2102 then -- GetTrackStreamingReq
485485- local labels = {
486486- [1] = "DMST",
487487- [2] = "Rekordbox ID"
488488- }
489489- return labels[arg_idx]
490490- elseif msg_type == 0x4101 then -- MenuItem
491491- local labels = {
492492- [1] = "Parent ID",
493493- [2] = "Main ID",
494494- [3] = "Label 1 Len",
495495- [4] = "Label 1",
496496- [5] = "Label 2 Len",
497497- [6] = "Label 2",
498498- [7] = "Item Type",
499499- [8] = "Flags",
500500- [9] = "Artwork ID",
501501- [10] = "Position",
502502- [11] = "Unknown",
503503- [12] = "Unknown"
504504- }
456456+ local labels = MSG_ARG_LABELS[msg_type]
457457+ if labels and labels[arg_idx] then
505458 return labels[arg_idx]
506506- elseif msg_type == 0x4201 then -- MenuFooter
507507- return arg_idx == 1 and "Status" or (arg_idx == 2 and "Total Items" or nil)
508508- elseif msg_type == 0x4001 then -- MenuHeader
509509- return arg_idx == 1 and "Item Count" or nil
510510- elseif msg_type == 0x4000 then -- Success/Ack
511511- return arg_idx == 1 and "Request Type Echo" or (arg_idx == 2 and "Items Found" or nil)
512512- elseif msg_type == 0x4602 or msg_type == 0x4702 or msg_type == 0x4e02 or msg_type == 0x4a02 or msg_type == 0x4402 or msg_type == 0x4002 or msg_type == 0x4f02 then -- Blob Responses
459459+ end
460460+461461+ -- Special case for Blob Responses
462462+ if arg_idx <= 4 and (msg_type == 0x4602 or msg_type == 0x4702 or msg_type == 0x4e02 or msg_type == 0x4a02 or msg_type == 0x4402 or msg_type == 0x4002 or msg_type == 0x4f02) then
513463 if arg_idx == 1 then return "Request Type Echo" end
514464 if arg_idx == 2 then return "Status/Echo" end
515465 if arg_idx == 3 then return "Length" end
516466 if arg_idx == 4 then
517517- local labels = {
467467+ local blob_labels = {
518468 [0x4002] = "Blob (image)",
519469 [0x4602] = "Beat Grid Data",
520470 [0x4702] = "Cue Points Data",
···523473 [0x4a02] = "Waveform Detail Data",
524474 [0x4f02] = "Analysis Tag Data",
525475 }
526526- return labels[msg_type] or "Blob Data"
476476+ return blob_labels[msg_type] or "Blob Data"
527477 end
528528- return nil
529529- elseif msg_type == 0x3000 then -- RenderMenu
530530- local labels = {
531531- [1] = "DMST",
532532- [2] = "Offset",
533533- [3] = "Limit",
534534- [4] = "Unknown",
535535- [5] = "Total Items",
536536- [6] = "Unknown"
537537- }
538538- return labels[arg_idx]
539539- elseif msg_type == 0x0000 then -- Setup
540540- return arg_idx == 1 and "Our Device Number" or nil
541541- elseif msg_type == 0x4b02 then -- CapabilitiesResp
542542- local labels = {
543543- [1] = "Request Type Echo",
544544- [2] = "Reserved",
545545- [3] = "Capability Level",
546546- [4] = "Placeholder (Empty String)"
547547- }
548548- return labels[arg_idx]
549478 end
479479+550480 return nil
551481end
552482···752682 return cur - offset
753683end
754684685685+local function dissect_single_db_message(buf, off, msg_len, root, pkt, stream_id, db_types, tx_ids)
686686+ local msg_tree = root:add(p_djl, buf(off, msg_len))
687687+ msg_tree:add(f_db_magic, buf(off+1, 4))
688688+689689+ local current = off + 5
690690+691691+ -- Transaction ID
692692+ local tx_id = 0
693693+ if msg_len - (current - off) >= 5 then
694694+ local bytes_read, val = dissect_db_field(buf, current, msg_tree, nil, "Transaction ID")
695695+ tx_id = val or 0
696696+ local tx_str = (tx_id == 0xfffffffe) and "Setup/Teardown" or string.format("0x%08x", tx_id)
697697+698698+ local already_added = false
699699+ for _, v in ipairs(tx_ids) do
700700+ if v == tx_str then already_added = true break end
701701+ end
702702+ if not already_added then
703703+ table.insert(tx_ids, tx_str)
704704+ end
705705+706706+ current = bytes_read
707707+ end
708708+709709+ -- Message Type
710710+ local m_type = 0
711711+ if msg_len - (current - off) >= 3 then
712712+ local bytes_read, val, m_type_item = dissect_db_field(buf, current, msg_tree, nil, "Message Type")
713713+ m_type = val or 0
714714+ local m_type_str = DB_MSG_TYPES[m_type] or string.format("Unknown(0x%04x)", m_type)
715715+716716+ if m_type == 0x0100 and tx_id == 0xfffffffe then
717717+ m_type_str = "Device Disconnect"
718718+ if m_type_item then
719719+ m_type_item:set_text("Message Type: " .. m_type_str .. " (0x" .. string.format("%04x", m_type) .. ")")
720720+ end
721721+ end
722722+723723+ table.insert(db_types, m_type_str)
724724+725725+ current = bytes_read
726726+ msg_tree:append_text(": " .. m_type_str)
727727+ end
728728+729729+ -- Arg Count
730730+ local arg_count = 0
731731+ if msg_len - (current - off) >= 2 then
732732+ local bytes_read, val = dissect_db_field(buf, current, msg_tree, nil, "Arg Count")
733733+ arg_count = val or 0
734734+ current = bytes_read
735735+ end
736736+737737+ -- Arg Tag Blob (usually 12 bytes)
738738+ if msg_len - (current - off) >= 5 and buf(current, 1):uint() == 0x14 then
739739+ local tag_len = buf(current+1, 4):uint()
740740+ if msg_len - (current - off) >= 5 + tag_len then
741741+ local tag_item = msg_tree:add(f_db_tag_blob, buf(current+5, tag_len))
742742+ local arg_types = {}
743743+ for i = 0, tag_len - 1 do
744744+ local t = buf(current+5+i, 1):uint()
745745+ if t ~= 0 then
746746+ table.insert(arg_types, ARG_TAGS[t] or string.format("0x%02x", t))
747747+ end
748748+ end
749749+ if #arg_types > 0 then
750750+ tag_item:set_text("Arg Types: " .. table.concat(arg_types, ", "))
751751+ end
752752+ current = current + 5 + tag_len
753753+ end
754754+ end
755755+756756+ -- Arguments
757757+ for i = 1, arg_count do
758758+ if current >= off + msg_len then break end
759759+ local prev_current = current
760760+ local bytes_read, val = dissect_db_field(buf, current, msg_tree, m_type, i)
761761+762762+ -- If it's a Success/Ack, show what it's acking in the summary
763763+ if m_type == 0x4000 then
764764+ if i == 1 and val then
765765+ local ack_type_str = DB_MSG_TYPES[val] or string.format("0x%04x", val)
766766+ msg_tree:append_text(" - " .. ack_type_str)
767767+ db_types[#db_types] = "Ack " .. ack_type_str
768768+ elseif i == 2 and val then
769769+ msg_tree:append_text(": " .. val .. " Items")
770770+ db_types[#db_types] = db_types[#db_types] .. ": " .. val .. " Items"
771771+ end
772772+ end
773773+774774+ -- If it's a GetAnalysisTag request, record the tag for the response
775775+ if m_type == 0x2c04 and i == 3 and val then
776776+ local tag_name = ANALYSIS_TAGS[val] or get_reverse_ascii(buf(prev_current+1, 4))
777777+ analysis_requests[stream_id .. ":" .. tx_id] = tag_name
778778+ msg_tree:append_text(" - " .. tag_name)
779779+ -- Update the last entry in db_types to include the tag
780780+ db_types[#db_types] = db_types[#db_types] .. " - " .. tag_name
781781+ end
782782+783783+ -- If it's a TrackLoadNotification, show the Rekordbox ID in the summary
784784+ if m_type == 0x3100 and i == 2 and val then
785785+ msg_tree:append_text(" - RB ID: " .. val)
786786+ db_types[#db_types] = db_types[#db_types] .. " - RB ID: " .. val
787787+ end
788788+789789+ -- If it's an AnalysisTagResponse, try to find the tag from the request
790790+ if m_type == 0x4f02 and i == 1 then
791791+ local tag_name = analysis_requests[stream_id .. ":" .. tx_id]
792792+ if tag_name then
793793+ msg_tree:append_text(" - " .. tag_name)
794794+ db_types[#db_types] = db_types[#db_types] .. " - " .. tag_name
795795+ end
796796+ end
797797+798798+ current = bytes_read
799799+ if current <= prev_current then break end
800800+ end
801801+802802+ -- Special handling for trailing binary data in blob responses
803803+ if (m_type == 0x4002 or m_type == 0x4602 or m_type == 0x4702 or m_type == 0x4e02 or m_type == 0x4a02 or m_type == 0x4402 or m_type == 0x4f02) and current < off + msg_len then
804804+ local label = get_arg_label(m_type, 4) or "Blob Data"
805805+ local remaining = (off + msg_len) - current
806806+ msg_tree:add(f_db_field_bin, buf(current, remaining)):set_text(label .. ": [" .. remaining .. " bytes]")
807807+ current = current + remaining
808808+ end
809809+810810+ msg_tree:set_len(msg_len)
811811+end
812812+755813local function dissect_db_tcp(buf, pkt, root, length)
756814 local off = 0
757815 local found_db = false
758816 local db_types = {}
759817 local tx_ids = {}
760818761761- local src_port = pkt.src_port
762762- local dst_port = pkt.dst_port
763819 local stream_id = get_stream_key(pkt)
764820765821 while off < length do
···791847 found_db = true
792848 end
793849794794- local msg_tree = root:add(p_djl, buf(off, msg_len))
795795- msg_tree:add(f_db_magic, buf(off+1, 4))
796796-797797- local current = off + 5
798798-799799- -- Transaction ID
800800- local tx_id = 0
801801- if msg_len - (current - off) >= 5 then
802802- local bytes_read, val = dissect_db_field(buf, current, msg_tree, nil, "Transaction ID")
803803- tx_id = val or 0
804804- local tx_str = (tx_id == 0xfffffffe) and "Setup/Teardown" or string.format("0x%08x", tx_id)
805805-806806- local already_added = false
807807- for _, v in ipairs(tx_ids) do
808808- if v == tx_str then already_added = true break end
809809- end
810810- if not already_added then
811811- table.insert(tx_ids, tx_str)
812812- end
813813-814814- current = bytes_read
815815- end
816816-817817- -- Message Type
818818- local m_type = 0
819819- if msg_len - (current - off) >= 3 then
820820- local bytes_read, val, m_type_item = dissect_db_field(buf, current, msg_tree, nil, "Message Type")
821821- m_type = val or 0
822822- local m_type_str = DB_MSG_TYPES[m_type] or string.format("Unknown(0x%04x)", m_type)
823823-824824- if m_type == 0x0100 and tx_id == 0xfffffffe then
825825- m_type_str = "Device Disconnect"
826826- if m_type_item then
827827- m_type_item:set_text("Message Type: " .. m_type_str .. " (0x" .. string.format("%04x", m_type) .. ")")
828828- end
829829- end
830830-831831- table.insert(db_types, m_type_str)
832832-833833- current = bytes_read
834834- msg_tree:append_text(": " .. m_type_str)
835835- end
836836-837837- -- Arg Count
838838- local arg_count = 0
839839- if msg_len - (current - off) >= 2 then
840840- local bytes_read, val = dissect_db_field(buf, current, msg_tree, nil, "Arg Count")
841841- arg_count = val or 0
842842- current = bytes_read
843843- end
844844-845845- -- Arg Tag Blob (usually 12 bytes)
846846- if msg_len - (current - off) >= 5 and buf(current, 1):uint() == 0x14 then
847847- local tag_len = buf(current+1, 4):uint()
848848- if msg_len - (current - off) >= 5 + tag_len then
849849- local tag_item = msg_tree:add(f_db_tag_blob, buf(current+5, tag_len))
850850- local arg_types = {}
851851- for i = 0, tag_len - 1 do
852852- local t = buf(current+5+i, 1):uint()
853853- if t ~= 0 then
854854- table.insert(arg_types, ARG_TAGS[t] or string.format("0x%02x", t))
855855- end
856856- end
857857- if #arg_types > 0 then
858858- tag_item:set_text("Arg Types: " .. table.concat(arg_types, ", "))
859859- end
860860- current = current + 5 + tag_len
861861- end
862862- end
863863-864864- -- Arguments
865865- for i = 1, arg_count do
866866- if current >= off + msg_len then break end
867867- local prev_current = current
868868- local bytes_read, val = dissect_db_field(buf, current, msg_tree, m_type, i)
869869-870870- -- If it's a Success/Ack, show what it's acking in the summary
871871- if m_type == 0x4000 then
872872- if i == 1 and val then
873873- local ack_type_str = DB_MSG_TYPES[val] or string.format("0x%04x", val)
874874- msg_tree:append_text(" - " .. ack_type_str)
875875- db_types[#db_types] = "Ack " .. ack_type_str
876876- elseif i == 2 and val then
877877- msg_tree:append_text(": " .. val .. " Items")
878878- db_types[#db_types] = db_types[#db_types] .. ": " .. val .. " Items"
879879- end
880880- end
881881-882882- -- If it's a GetAnalysisTag request, record the tag for the response
883883- if m_type == 0x2c04 and i == 3 and val then
884884- local tag_name = ANALYSIS_TAGS[val] or get_reverse_ascii(buf(prev_current+1, 4))
885885- analysis_requests[stream_id .. ":" .. tx_id] = tag_name
886886- msg_tree:append_text(" - " .. tag_name)
887887- -- Update the last entry in db_types to include the tag
888888- db_types[#db_types] = db_types[#db_types] .. " - " .. tag_name
889889- end
890890-891891- -- If it's a TrackLoadNotification, show the Rekordbox ID in the summary
892892- if m_type == 0x3100 and i == 2 and val then
893893- msg_tree:append_text(" - RB ID: " .. val)
894894- db_types[#db_types] = db_types[#db_types] .. " - RB ID: " .. val
895895- end
896896-897897- -- If it's an AnalysisTagResponse, try to find the tag from the request
898898- if m_type == 0x4f02 and i == 1 then
899899- local tag_name = analysis_requests[stream_id .. ":" .. tx_id]
900900- if tag_name then
901901- msg_tree:append_text(" - " .. tag_name)
902902- db_types[#db_types] = db_types[#db_types] .. " - " .. tag_name
903903- end
904904- end
905905-906906- current = bytes_read
907907- if current <= prev_current then break end
908908- end
909909-910910- -- Special handling for trailing binary data in blob responses
911911- if (m_type == 0x4002 or m_type == 0x4602 or m_type == 0x4702 or m_type == 0x4e02 or m_type == 0x4a02 or m_type == 0x4402 or m_type == 0x4f02) and current < off + msg_len then
912912- local label = get_arg_label(m_type, 4) or "Blob Data"
913913- local remaining = (off + msg_len) - current
914914- msg_tree:add(f_db_field_bin, buf(current, remaining)):set_text(label .. ": [" .. remaining .. " bytes]")
915915- current = current + remaining
916916- end
917917-918918- msg_tree:set_len(msg_len)
850850+ dissect_single_db_message(buf, off, msg_len, root, pkt, stream_id, db_types, tx_ids)
919851 off = off + msg_len
920852 elseif magic_or_val == 0x00000001 then
921853 if not found_db then