Wireshark iAP2 协议解析插件
Wireshark iAP2 协议解析插件
什么是 iAP2
iAP2(iPod Accessory Protocol 2)是 Apple 设备与外部配件之间的通信协议,广泛用于 CarPlay、MFi 配件认证、蓝牙配对、媒体播放控制等场景。iAP2 的数据包是二进制格式,直接看原始数据非常痛苦。
插件功能
iap2.lua 是一个 Wireshark Lua 解析插件,能将 iAP2 二进制数据自动解析为可读的协议树,主要功能包括:
- 链路层解析:SYN/ACK/RST 等控制标志、序列号、会话 ID、校验和验证(错误时红色高亮)
- 消息类型识别:覆盖认证、设备识别、CarPlay、媒体播放、蓝牙配对、Wi-Fi 共享、通话控制、VoiceOver 等数十种 CSM 消息
- 关键参数深度解析:设备识别信息(名称/型号/制造商)、Wi-Fi 配置(SSID/密码/安全类型)、设备时间、UUID 等
- 蓝牙 UUID 自动匹配:蓝牙抓包时自动识别 iAP2 流量,无需手动配置
安装方法
将 iap2.lua 复制到 Wireshark 插件目录:
- Windows:
%APPDATA%\Wireshark\plugins\ - macOS / Linux:
~/.local/lib/wireshark/plugins/
重启 Wireshark,通过 Help → About Wireshark → Plugins 确认加载成功。
使用方法
蓝牙场景:打开 btsnoop / HCI 日志文件,插件根据蓝牙 UUID 自动识别,直接就能看到解析结果。
其他场景(USB/串口):右键数据包 → Decode As → 选择 iAP2。
加载后 Wireshark 会在 Protocol 列显示 iAP2,Info 列显示具体消息类型(如 AuthenticationSucceeded、IdentificationInformation),展开数据包可查看完整协议字段。
-- IAP2 协议解析器
-- 基于 Apple 的 iAP2 协议规范
local csm_msg_id_types = {
--1)AUTH
--AA表示Accessory Authentication
[0xAA00] = "RequestAuthenticationCertificate",
[0xAA01] = "AuthenticationCertificate",
[0xAA02] = "RequestAuthenticationChallengeResponse",
[0xAA03] = "AuthenticationResponse",
[0xAA04] = "AuthenticationFailed",
[0xAA05] = "AuthenticationSucceeded",
[0xAA06] = "AccessoryAuthenticationSerialNumber",
[0xAA10] = "RequestDeviceAuthenticationCertificate",
[0xAA11] = "DeviceAuthenticationCertificate",
[0xAA12] = "RequestDeviceAuthenticationChallengeResponse",
[0xAA13] = "DeviceAuthenticationResponse",
[0xAA14] = "DeviceAuthenticationFailed",
[0xAA15] = "DeviceAuthenticationSucceeded",
--Power
--AE
[0xAE00] = "StartPowerUpdates",
[0xAE01] = "PowerUpdate",
[0xAE02] = "StopPowerUpdates",
[0xAE03] = "PowerSourceUpdate",
--2)Identification
--1D表示Identification
[0x1D00] = "StartIdentification",
[0x1D01] = "IdentificationInformation",
[0x1D02] = "IdentificationAccepted",
[0x1D03] = "IdentificationRejected",
[0x1D05] = "CancelIdentification",
[0x1D06] = "IdentificationInformationUpdate",
--3)HID over iAP2
[0x6800] = "StartHID",
[0x6801] = "DeviceHIDReport",
[0x6802] = "AccessoryHIDReport",
[0x6803] = "StopHID",
[0x6806] = "StartNativeHID",
--4)iPod音频播放模式
--DA表示Digital Audio
[0xDA00] = "StartUSBDeviceModeAudio",
[0xDA01] = "USBDeviceModeAudioInformation",
[0xDA02] = "StopUSBDeviceModeAudio",
--5)媒体库访问
--- 媒体库信息
[0x4C00] = "StartMediaLibraryInformation",
[0x4C01] = "MediaLibraryInformation",
[0x4C02] = "StopMediaLibraryInformation",
--- 媒体库信息更新
[0x4C03] = "StartMediaLibraryUpdates",
[0x4C04] = "MediaLibraryUpdate",
[0x4C05] = "StopMediaLibraryUpdates",
--- 媒体库播放命令
[0x4C06] = "PlayMediaLibraryCurrentSelection",
[0x4C07] = "PlayMediaLibraryItems",
[0x4C08] = "PlayMediaLibraryCollection",
[0x4C09] = "PlayMediaLibrarySpecial",
--6)Now Playing - 显示正在播放歌曲的metadata信息
[0x5000] = "StartNowPlayingUpdates",
[0x5001] = "NowPlayingUpdate",
[0x5002] = "StopNowPlayingUpdates",
[0x5003] = "SetNowPlayingInformation",
--7)External Accessory Protocol
--EA表示External Accessory
[0xEA00] = "StartExternalAccessoryProtocolSession",
[0xEA01] = "StopExternalAccessoryProtocolSession",
[0xEA02] = "RequestAppLaunch",
[0xEA03] = "StatusExternalAccessoryProtocolSession",
--Device Notifications
--4E
[0x4E01] = "BluetoothComponentInformation",
[0x4E03] = "StartBluetoothConnectionUpdates",
[0x4E04] = "BluetoothConnectionUpdate",
[0x4E05] = "StopBluetoothConnectionUpdates",
[0x4E09] = "DeviceInformationUpdate",
[0x4E0A] = "DeviceLanguageUpdate",
[0x4E0B] = "DeviceTimeUpdate",
[0x4E0C] = "DeviceUUIDUpdate",
[0x4E0D] = "WirelessCarPlayUpdate",
[0x4E0E] = "DeviceTransportIdentifierNotification",
--Wi-Fi Information Sharing
--57
[0x5700] = "RequestWiFiInformation",
[0x5701] = "WiFiInformation",
[0x5702] = "RequestAccessoryWiFiConfigurationInformation",
[0x5703] = "AccessoryWiFiConfigurationInformation",
--Carplay new
--43
[0x4300] = "CarPlayAvailability",
[0x4301] = "CarPlayStartSession",
--vehicle_status
--A1
[0xA100] = "StartVehicleStatusUpdates",
[0xA101] = "VehicleStatusUpdate",
[0xA102] = "StopVehicleStatusUpdates",
[0x4170] = "StartListUpdates",
[0x4171] = "ListUpdate",
[0x4172] = "StopListUpdates",
--Assistive Touch
--54
[0x5400] = "StartAssistiveTouch",
[0x5401] = "StopAssistiveTouch",
[0x5402] = "StartAssistiveTouchInformation",
[0x5403] = "AssistiveTouchInformation",
[0x5404] = "StopAssistiveTouchInformation",
--VoiceOver
--56
[0x5601] = "RequestVoiceOverMoveCursor",
[0x5602] = "RequestVoiceOverActivateCursor",
[0x5603] = "RequestVoiceOverScrollPage",
[0x5606] = "RequestVoiceOverSpeakText",
[0x5608] = "RequestVoiceOverPauseText",
[0x5609] = "RequestVoiceOverResumeText",
[0x560B] = "StartVoiceOverUpdates",
[0x560C] = "VoiceOverUpdate",
[0x560D] = "StopVoiceOverUpdates",
[0x560E] = "RequestVoiceOverConfiguration",
[0x560F] = "StartVoiceOverCursorUpdates",
[0x5610] = "VoiceOverCursorUpdate",
[0x5611] = "StopVoiceOverCursorUpdates",
[0x5612] = "StartVoiceOver",
[0x5613] = "StopVoiceOver",
--Communications
--41
[0x4154] = "StartCallStateUpdates",
[0x4155] = "CallStateUpdate",
[0x4156] = "StopCallStateUpdates",
[0x4157] = "StartCommunicationUpdates",
[0x4158] = "CommunicationsUpdate",
[0x4159] = "StopCommunicationsUpdates",
[0x415A] = "InitiateCall",
[0x415B] = "AcceptCall",
[0x415C] = "EndCall",
[0x415D] = "SwapCalls",
[0x415E] = "MergeCalls",
[0x415F] = "HoldStatusUpdate",
[0x4160] = "MuteStatusUpdate",
[0x4161] = "SendDTMF",
--Out-of-Band Bluetooth Pairing
--00B
[0x00B0] = "StartOOBBTPairing",
[0x00B1] = "OOBBTPairingAccessoryInformation",
[0x00B2] = "OOBBTPairingLinkKeyInformation",
[0x00B3] = "OOBBTPairingCompletionInformation",
[0x00B4] = "StopOOBBTPairing",
--Location
--FF
[0xFFF0] = "GPRMCDataStatusValuesNotification",
[0xFFFA] = "StartLocationInformation",
[0xFFFB] = "LocationInformation",
[0xFFFC] = "StopLocationInformation",
}
IdentificationInformationParamId = {
[0x00] = "name",
[0x01] = "model_identifier",
[0x02] = "manufacturer",
[0x03] = "serial_number",
[0x04] = "fireware_version",
[0x05] = "hardware_version",
[0x06] = "messages_sent_by_accessory",
[0x07] = "messages_received_from_accessory",
[0x08] = "power_providing_capability",
[0x09] = "maximum_current_drawn_from_device",
[0x0A] = "supported_external_accessory_protocol",
[0x0B] = "app_match_team_id",
[0x0C] = "current_language",
[0x0D] = "supported_language",
[0x0E] = "serial_transport_component",
[0x0F] = "usb_device_transport_component",
[0x10] = "usb_host_transport_component",
[0x11] = "bluetooth_transport_component",
[0x14] = "vehicle_information_component",
[0x15] = "vehicle_status_component",
[0x18] = "wireless_car_play_transport_component"
}
IdentificationInformationParamType = {
[0x00] = "string",
[0x01] = "string",
[0x02] = "string",
[0x03] = "string",
[0x04] = "string",
[0x05] = "string",
[0x06] = "uint32",
[0x07] = "uint32",
[0x08] = "bool",
[0x09] = "uint16",
[0x0A] = "string",
[0x0B] = "string",
[0x0C] = "string",
[0x0D] = "string",
[0x0E] = "bytes",
[0x0F] = "bytes",
[0x10] = "bytes",
[0x11] = "bytes",
[0x12] = "bytes",
[0x13] = "bytes",
[0x14] = "bytes"
}
SecurityType = {
[0] = 'NONE',
[1] = 'WEP_NEW',
[2] = 'WPA_WPA2',
}
AccessoryWiFiConfigurationInformation = {
[0x0] = "unknown",
[0x1] = "ssid",
[0x2] = "passphrase",
[0x3] = "security_type",
[0x4] = "channel",
}
-- 定义协议
local iap2_proto = Proto("iAP2", "Apple iAP2 Protocol")
-- 定义字段
local f = iap2_proto.fields
f.info = ProtoField.string("iap2.info", "Info")
f.sop = ProtoField.uint8("iap2.sop", "SOP", base.HEX)
f.len = ProtoField.uint16("iap2.len", "Length", base.DEC)
f.ctl = ProtoField.uint8("iap2.ctl", "Control", base.HEX)
f.ctl_syn = ProtoField.bool("iap2.ctl.syn", "SYN", 8, nil, 0x80)
f.ctl_ack = ProtoField.bool("iap2.ctl.ack", "ACK", 8, nil, 0x40)
f.ctl_eak = ProtoField.bool("iap2.ctl.eak", "EAK", 8, nil, 0x20)
f.ctl_rst = ProtoField.bool("iap2.ctl.rst", "RST", 8, nil, 0x10)
f.ctl_sus = ProtoField.bool("iap2.ctl.sus", "SUS", 8, nil, 0x08)
f.seq = ProtoField.uint8("iap2.seq", "Sequence Number", base.DEC)
f.ack = ProtoField.uint8("iap2.ack", "Acknowledgement Number", base.DEC)
f.sess = ProtoField.uint8("iap2.sess", "Session ID", base.DEC)
f.chk_header = ProtoField.uint8("iap2.hchk", "Header Checksum", base.HEX)
f.payload = ProtoField.bytes("iap2.payload", "Payload")
f.chk_payload = ProtoField.uint8("iap2.pchk", "Payload Checksum", base.HEX)
-- 定义 SYN 数据包特殊字段
f.syn_version = ProtoField.uint8("iap2.syn.version", "Version", base.DEC)
f.syn_maxOutstanding = ProtoField.uint8("iap2.syn.maxOutstanding", "Max Outstanding Packets", base.DEC)
f.syn_maxPacketSize = ProtoField.uint16("iap2.syn.maxPacketSize", "Max Packet Size", base.DEC)
f.syn_retransTimeout = ProtoField.uint16("iap2.syn.retransTimeout", "Retransmit Timeout (ms)", base.DEC)
f.syn_cumAckTimeout = ProtoField.uint16("iap2.syn.cumAckTimeout", "Cumulative ACK Timeout (ms)", base.DEC)
f.syn_maxRetrans = ProtoField.uint8("iap2.syn.maxRetrans", "Max Retransmissions", base.DEC)
f.syn_maxCumAck = ProtoField.uint8("iap2.syn.maxCumAck", "Max Cumulative ACK", base.DEC)
f.csm_control = ProtoField.uint8("iap2.csm.control", "Csm Control", base.HEX)
f.csm_len = ProtoField.uint8("iap2.csm.len", "Csm Length", base.DEC)
f.csm_msg_id = ProtoField.uint8("iap2.csm.msg_id", "Csm Message Id", base.HEX, csm_msg_id_types)
f.csm_param_list = ProtoField.bytes("iap2.csm.param_list", "Csm Param List")
f.csm_param_length = ProtoField.uint8("iap2.csm.length", "Csm Param Length", base.DEC)
f.csm_param_id = ProtoField.uint8("iap2.csm.param_id", "Csm Param Id", base.HEX)
f.csm_param = ProtoField.bytes("iap2.csm.param", "Csm Param")
f.csm_param_str = ProtoField.string("iap2.csm.param", "Csm Param")
f.IdentificationInformationParamId = ProtoField.uint8("iap2.IdentificationInformationParamId", "Identification Information Param Id", base.Dec, IdentificationInformationParamId)
f.AccessoryWiFiConfigurationInformation = ProtoField.uint8("iap2.AccessoryWiFiConfigurationInformation", "Accessory WiFi Configuration Information", base.Dec, AccessoryWiFiConfigurationInformation)
f.SecurityType = ProtoField.uint8("iap2.SecurityType", "Security Type", base.Dec, SecurityType)
f.ssid = ProtoField.string("iap2.ssid", "SSID")
f.passphrase = ProtoField.string("iap2.passphrase", "Passphrase")
f.channel = ProtoField.uint8("iap2.channel", "Channel", base.DEC)
f.uuid = ProtoField.string("iap2.uuid", "UUID")
f.name = ProtoField.string("iap2.name", "Name")
f.language = ProtoField.string("iap2.language", "Language")
f.bluetooth_id = ProtoField.string("iap2.bluetooth_id", "Bluetooth ID")
f.usb_id = ProtoField.string("iap2.usb_id", "USB ID")
f.available = ProtoField.bool("iap2.available", "Available")
f.time = ProtoField.absolute_time("iap2.time", "Time")
-- 会话信息字段
f.session = ProtoField.bytes("iap2.session", "Session Information")
f.sess_id = ProtoField.uint8("iap2.session.id", "ID", base.DEC)
f.sess_type = ProtoField.uint8("iap2.session.type", "Type", base.DEC, {[0] = "Control", [1] = "Buffer", [2] = "EA"})
f.sess_version = ProtoField.uint8("iap2.session.version", "Version", base.DEC)
f.AuthenticationCertificate = ProtoField.bytes("iap2.AuthenticationCertificate", "Authentication Certificate")
-- Detect/Handshake 包字段 (固定序列 FF 55 02 00 EE 10)
f.detect_bytes = ProtoField.bytes("iap2.detect", "Detect")
-- 计算校验和
local function calc_checksum(buffer, start, length)
local sum = 0
for i = start, start + length - 1 do
sum = sum + buffer(i, 1):uint()
end
return bit.band(0x100 - sum, 0xFF)
end
--解析器函数
---@param tvb Tvb buffer对象
---@param pinfo Pinfo 数据包信息
---@param tree TreeItem 树节点
---@return boolean
function iap2_proto.dissector(tvb, pinfo, tree)
local total = 0
::restart::
if tvb:len() < total + 6 then
return true
end
local buffer = tvb(total)
local length = buffer:len()
-- 检查 Detect/Handshake 包: 固定序列 FF 55 02 00 EE 10
if buffer(0, 1):uint() == 0xFF and buffer(1, 1):uint() == 0x55
and buffer(2, 1):uint() == 0x02 and buffer(3, 1):uint() == 0x00
and buffer(4, 1):uint() == 0xEE and buffer(5, 1):uint() == 0x10 then
pinfo.cols.protocol:set("iAP2")
local subtree = tree:add(iap2_proto, buffer(0, 6), "Apple iAP2 Detect")
subtree:add(f.detect_bytes, buffer(0, 6)):set_text("Detect: FF 55 02 00 EE 10")
pinfo.cols.info:append(" Detect")
total = total + 6
goto restart
end
if tvb:len() < total + 9 then
if tvb:len() > total then
local subtree = tree:add(iap2_proto, tvb(total), "Apple iAP2 Protocol")
end
return true
end
-- 检查 SOP 标记
if buffer(0, 1):uint() ~= 0xFF or buffer(1, 1):uint() ~= 0x5A then
return false
end
-- 设置协议列
pinfo.cols.protocol:set("iAP2")
-- 计算总长度
local packet_len = buffer(2, 1):uint() * 256 + buffer(3, 1):uint()
total = total + packet_len
-- 创建协议树
if packet_len > length then packet_len = length end
local subtree = tree:add(iap2_proto, buffer(0, packet_len), "Apple iAP2 Protocol")
-- 解析包头
subtree:add(f.sop, buffer(0, 2))
subtree:add(f.len, buffer(2, 2))
-- 控制字节
local ctl = buffer(4, 1):uint()
local ctl_tree = subtree:add(f.ctl, buffer(4, 1))
ctl_tree:add(f.ctl_syn, buffer(4, 1))
ctl_tree:add(f.ctl_ack, buffer(4, 1))
ctl_tree:add(f.ctl_eak, buffer(4, 1))
ctl_tree:add(f.ctl_rst, buffer(4, 1))
ctl_tree:add(f.ctl_sus, buffer(4, 1))
-- 序列号、确认号和会话ID
subtree:add(f.seq, buffer(5, 1))
subtree:add(f.ack, buffer(6, 1))
subtree:add(f.sess, buffer(7, 1))
-- 头校验和
local hchk = buffer(8, 1):uint()
local hchk_calc = calc_checksum(buffer, 0, 8)
local hchk_item = subtree:add(f.chk_header, buffer(8, 1))
if hchk ~= hchk_calc then
hchk_item:add_expert_info(PI_CHECKSUM, PI_ERROR, "Header checksum incorrect")
end
-- 确定包类型并添加到信息列
local packet_type = ""
if bit.band(ctl, 0x80) ~= 0 then packet_type = packet_type .. "SYN " end
if bit.band(ctl, 0x40) ~= 0 then packet_type = packet_type .. "ACK " end
if bit.band(ctl, 0x20) ~= 0 then packet_type = packet_type .. "EAK " end
if bit.band(ctl, 0x10) ~= 0 then packet_type = packet_type .. "RST " end
if bit.band(ctl, 0x08) ~= 0 then packet_type = packet_type .. "SUS " end
if packet_type == "" then packet_type = "DATA " end
--pinfo.cols.info = tostring(pinfo.cols.info) .. " " .. packet_type .. "Seq=" .. buffer(5, 1):uint() .. " Ack=" .. buffer(6, 1):uint()
if packet_len == 9 then
pinfo.cols.info:append(" ACK")
end
-- 检查是否有负载数据
local payload_len = packet_len - 9 - 1 -- 包长度减去头部和负载校验和
if payload_len < 0 then
goto restart
end
if length < packet_len then
return true
end
local payload_data = buffer(9, payload_len)
local payload_tree = subtree:add(f.payload, payload_data)
-- 如果是SYN包,解析SYN数据
if bit.band(ctl, 0x80) ~= 0 and payload_len >= 10 then
pinfo.cols.info:append(" SYN")
subtree:add(f.syn_version, payload_data(0, 1))
subtree:add(f.syn_maxOutstanding, payload_data(1, 1))
-- 最大包大小 (2字节)
subtree:add(f.syn_maxPacketSize, payload_data(2, 2))
-- 重传超时 (2字节)
subtree:add(f.syn_retransTimeout, payload_data(4, 2))
-- 累积确认超时 (2字节)
subtree:add(f.syn_cumAckTimeout, payload_data(6, 2))
subtree:add(f.syn_maxRetrans, payload_data(8, 1))
subtree:add(f.syn_maxCumAck, payload_data(9, 1))
-- 会话数量
if payload_len > 10 then
for i = 10, payload_len - 1, 3 do
local sess_tree = subtree:add(f.session, payload_data(i, 3))
sess_tree:add(f.sess_id, payload_data(i, 1))
sess_tree:add(f.sess_type, payload_data(i + 1, 1))
sess_tree:add(f.sess_version, payload_data(i + 2, 1))
end
end
elseif payload_data(0,1):uint() == 0x40 and payload_data(1,1):uint() == 0x40 then
subtree:add(f.csm_control, payload_data(0, 2))
subtree:add(f.csm_len, payload_data(2, 2))
subtree:add(f.csm_msg_id, payload_data(4, 2))
local csm_msg_id = payload_data(4, 2):uint()
local csm_msg_id_str = csm_msg_id_types[csm_msg_id] or string.format("0x%X", csm_msg_id)
pinfo.cols.info:append(" " .. csm_msg_id_str)
if payload_len <= 6 then goto checksum end
local pos = 6
while pos + 4 <= payload_len do
local csm_param_length = payload_data(pos, 2):uint()
local csm_param_id = payload_data(pos + 2, 2):uint()
-- 添加 CSM 参数到树中
local csm_param_tree = subtree:add(f.csm_param_list, payload_data(pos, csm_param_length))
csm_param_tree:add(f.csm_param_length, payload_data(pos, 2))
if csm_msg_id == 0x1D01 then
csm_param_tree:add(f.IdentificationInformationParamId, payload_data(pos + 2, 2))
elseif csm_msg_id == 0x5703 then
csm_param_tree:add(f.AccessoryWiFiConfigurationInformation, payload_data(pos + 2, 2))
else
csm_param_tree:add(f.csm_param_id, payload_data(pos + 2, 2))
end
if csm_param_length > 4 then
if csm_msg_id == 0x1D01 then
if IdentificationInformationParamType[csm_param_id] == "string" then
csm_param_tree:add(f.csm_param_str, payload_data(pos + 4, csm_param_length - 4))
local param_value = payload_data(pos + 4, csm_param_length - 4):string()
local param_name = IdentificationInformationParamId[csm_param_id] or string.format("0x%X", csm_param_id)
csm_param_tree:set_text(param_name .. ": " .. param_value)
else
csm_param_tree:add(f.csm_param, payload_data(pos + 4, csm_param_length - 4))
local param_value = payload_data(pos + 4, csm_param_length - 4)
local param_name = IdentificationInformationParamId[csm_param_id] or string.format("0x%X", csm_param_id)
csm_param_tree:set_text(param_name .. ": " .. param_value)
end
elseif csm_msg_id == 0x5703 then
if csm_param_id == 0x1 then
csm_param_tree:add(f.ssid, payload_data(pos + 4, csm_param_length - 4))
csm_param_tree:set_text("SSID: " .. payload_data(pos + 4, csm_param_length - 4):string())
pinfo.cols.info:append(" SSID:" .. payload_data(pos + 4, csm_param_length - 4):string())
elseif csm_param_id == 0x2 then
csm_param_tree:add(f.passphrase, payload_data(pos + 4, csm_param_length - 4))
csm_param_tree:set_text("Passphrase: " .. payload_data(pos + 4, csm_param_length - 4):string())
pinfo.cols.info:append(" Passphrase:" .. payload_data(pos + 4, csm_param_length - 4):string())
elseif csm_param_id == 0x3 then
csm_param_tree:add(f.SecurityType, payload_data(pos + 4, csm_param_length - 4))
local security_type = payload_data(pos + 4, csm_param_length - 4):uint()
local security_type_str = SecurityType[security_type] or string.format("0x%X", security_type)
csm_param_tree:set_text("Security Type: " .. security_type_str)
pinfo.cols.info:append(" SecurityType:" .. security_type_str)
elseif csm_param_id == 0x4 then
csm_param_tree:add(f.channel, payload_data(pos + 4, csm_param_length - 4))
csm_param_tree:set_text("Channel: " .. payload_data(pos + 4, csm_param_length - 4):uint())
pinfo.cols.info:append(" Channel:" .. payload_data(pos + 4, csm_param_length - 4):uint())
else
csm_param_tree:add(f.csm_param, payload_data(pos + 4, csm_param_length - 4))
csm_param_tree:set_text(string.format("Param 0x%X", csm_param_id) .. ": " .. payload_data(pos + 4, csm_param_length - 4))
end
elseif csm_msg_id == 0x4E09 then
if csm_param_id == 0x00 then
csm_param_tree:add(f.name, payload_data(pos + 4, csm_param_length - 4))
csm_param_tree:set_text("Name: " .. payload_data(pos + 4, csm_param_length - 4):string())
pinfo.cols.info:append(" Name:" .. payload_data(pos + 4, csm_param_length - 4):string())
else
csm_param_tree:add(f.csm_param, payload_data(pos + 4, csm_param_length - 4))
csm_param_tree:set_text(string.format("Param 0x%X", csm_param_id) .. ": " .. payload_data(pos + 4, csm_param_length - 4))
end
elseif csm_msg_id == 0x4E0A then
if csm_param_id == 0x00 then
csm_param_tree:add(f.language, payload_data(pos + 4, csm_param_length - 4))
csm_param_tree:set_text("Language: " .. payload_data(pos + 4, csm_param_length - 4):string())
pinfo.cols.info:append(" Language:" .. payload_data(pos + 4, csm_param_length - 4):string())
else
csm_param_tree:add(f.csm_param, payload_data(pos + 4, csm_param_length - 4))
csm_param_tree:set_text(string.format("Param 0x%X", csm_param_id) .. ": " .. payload_data(pos + 4, csm_param_length - 4))
end
elseif csm_msg_id == 0x4E0B then
if csm_param_id == 0x00 then
local time_seconds = payload_data(pos + 8, csm_param_length - 8):uint()
csm_param_tree:add(f.time, payload_data(pos + 8, csm_param_length - 8))
local time_str = tostring(os.date("%Y-%m-%d %H:%M:%S", time_seconds))
csm_param_tree:set_text("Time: " .. time_str)
pinfo.cols.info:append(" Time:" .. time_str)
else
csm_param_tree:add(f.csm_param, payload_data(pos + 4, csm_param_length - 4))
csm_param_tree:set_text(string.format("Param 0x%X", csm_param_id) .. ": " .. payload_data(pos + 4, csm_param_length - 4))
end
elseif csm_msg_id == 0x4E0C then
if csm_param_id == 0x00 then
csm_param_tree:add(f.uuid, payload_data(pos + 4, csm_param_length - 4))
csm_param_tree:set_text("UUID: " .. payload_data(pos + 4, csm_param_length - 4):string())
pinfo.cols.info:append(" UUID:" .. payload_data(pos + 4, csm_param_length - 4):string())
else
csm_param_tree:add(f.csm_param, payload_data(pos + 4, csm_param_length - 4))
csm_param_tree:set_text(string.format("Param 0x%X", csm_param_id) .. ": " .. payload_data(pos + 4, csm_param_length - 4))
end
elseif csm_msg_id == 0x4E0D then
if csm_param_id == 0x00 then
csm_param_tree:add(f.available, payload_data(pos + 4, csm_param_length - 4))
local available = payload_data(pos + 4, csm_param_length - 4):uint() ~= 0
csm_param_tree:set_text("Available: " .. tostring(available))
pinfo.cols.info:append(" Available:" .. tostring(available))
else
csm_param_tree:add(f.csm_param, payload_data(pos + 4, csm_param_length - 4))
csm_param_tree:set_text(string.format("Param 0x%X", csm_param_id) .. ": " .. payload_data(pos + 4, csm_param_length - 4))
end
elseif csm_msg_id == 0x4E0E then
if csm_param_id == 0x00 then
csm_param_tree:add(f.bluetooth_id, payload_data(pos + 4, csm_param_length - 4))
csm_param_tree:set_text("Bluetooth ID: " .. payload_data(pos + 4, csm_param_length - 4):string())
pinfo.cols.info:append(" BluetoothID:" .. payload_data(pos + 4, csm_param_length - 4):string())
elseif csm_param_id == 0x01 then
csm_param_tree:add(f.usb_id, payload_data(pos + 4, csm_param_length - 4))
csm_param_tree:set_text("USB ID: " .. payload_data(pos + 4, csm_param_length - 4):string())
pinfo.cols.info:append(" USBID:" .. payload_data(pos + 4, csm_param_length - 4):string())
else
csm_param_tree:add(f.csm_param, payload_data(pos + 4, csm_param_length - 4))
csm_param_tree:set_text(string.format("Param 0x%X", csm_param_id) .. ": " .. payload_data(pos + 4, csm_param_length - 4))
end
else
csm_param_tree:add(f.csm_param, payload_data(pos + 4, csm_param_length - 4))
csm_param_tree:set_text(string.format("Param 0x%X", csm_param_id) .. ": " .. payload_data(pos + 4, csm_param_length - 4))
end
end
pos = pos + csm_param_length
end
end
::checksum::
-- 负载校验和 (如果存在)
if length >= 9 + payload_len + 1 then
local pchk = buffer(9 + payload_len, 1):uint()
local pchk_calc = calc_checksum(buffer, 9, payload_len)
local pchk_item = subtree:add(f.chk_payload, buffer(9 + payload_len, 1))
if pchk ~= pchk_calc then
pchk_item:add_expert_info(PI_CHECKSUM, PI_ERROR, "Payload checksum incorrect, length:" .. tostring(length))
end
end
if tvb:len() >= total + 9 then
goto restart
end
return true
end
-- iAP2 协议 UUID,请替换为实际的 iAP2 UUID
local IAP2_SERVICE_UUID1 = "00000000-deca-fade-deca-deafdecacaff" --device
local IAP2_SERVICE_UUID2 = "00000000-deca-fade-deca-deafdecacafe" --phone
local IAP2_SERVICE_UUID3 = "02030302-1d19-415f-86f2-22a2106a0a77" --iap2
-- 注册蓝牙 iAP2 协议
local bt_table = DissectorTable.get("bluetooth.uuid")
bt_table:add(IAP2_SERVICE_UUID1, iap2_proto)
bt_table:add(IAP2_SERVICE_UUID2, iap2_proto)
bt_table:add(IAP2_SERVICE_UUID3, iap2_proto)
浙公网安备 33010602011771号