mirror of
https://github.com/halleysfifthinc/Toyota-AVC-LAN
synced 2025-07-26 19:26:47 +00:00
Add Wireshark packet dissector plugin and associated tools
This commit is contained in:
parent
fadd2c4259
commit
e857bbb09f
251
scripts/packet-analysis/Manifest.toml
Normal file
251
scripts/packet-analysis/Manifest.toml
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
# This file is machine-generated - editing it directly is not advised
|
||||||
|
|
||||||
|
julia_version = "1.10.0"
|
||||||
|
manifest_format = "2.0"
|
||||||
|
project_hash = "2d299f8e3abb5302e3c8ed5120acc4d9928016b1"
|
||||||
|
|
||||||
|
[[deps.ArgTools]]
|
||||||
|
uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f"
|
||||||
|
version = "1.1.1"
|
||||||
|
|
||||||
|
[[deps.Artifacts]]
|
||||||
|
uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"
|
||||||
|
|
||||||
|
[[deps.Base64]]
|
||||||
|
uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
|
||||||
|
|
||||||
|
[[deps.Compat]]
|
||||||
|
deps = ["UUIDs"]
|
||||||
|
git-tree-sha1 = "886826d76ea9e72b35fcd000e535588f7b60f21d"
|
||||||
|
uuid = "34da2185-b29b-5c13-b0c7-acf172513d20"
|
||||||
|
version = "4.10.1"
|
||||||
|
|
||||||
|
[deps.Compat.extensions]
|
||||||
|
CompatLinearAlgebraExt = "LinearAlgebra"
|
||||||
|
|
||||||
|
[deps.Compat.weakdeps]
|
||||||
|
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
|
||||||
|
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
|
||||||
|
|
||||||
|
[[deps.Dates]]
|
||||||
|
deps = ["Printf"]
|
||||||
|
uuid = "ade2ca70-3891-5945-98fb-dc099432e06a"
|
||||||
|
|
||||||
|
[[deps.Downloads]]
|
||||||
|
deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"]
|
||||||
|
uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6"
|
||||||
|
version = "1.6.0"
|
||||||
|
|
||||||
|
[[deps.ExprTools]]
|
||||||
|
git-tree-sha1 = "27415f162e6028e81c72b82ef756bf321213b6ec"
|
||||||
|
uuid = "e2ba6199-217a-4e67-a87a-7c52f15ade04"
|
||||||
|
version = "0.1.10"
|
||||||
|
|
||||||
|
[[deps.FileWatching]]
|
||||||
|
uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee"
|
||||||
|
|
||||||
|
[[deps.InlineStrings]]
|
||||||
|
deps = ["Parsers"]
|
||||||
|
git-tree-sha1 = "9cc2baf75c6d09f9da536ddf58eb2f29dedaf461"
|
||||||
|
uuid = "842dd82b-1e85-43dc-bf29-5d0ee9dffc48"
|
||||||
|
version = "1.4.0"
|
||||||
|
|
||||||
|
[[deps.InteractiveUtils]]
|
||||||
|
deps = ["Markdown"]
|
||||||
|
uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
|
||||||
|
|
||||||
|
[[deps.JLLWrappers]]
|
||||||
|
deps = ["Artifacts", "Preferences"]
|
||||||
|
git-tree-sha1 = "7e5d6779a1e09a36db2a7b6cff50942a0a7d0fca"
|
||||||
|
uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210"
|
||||||
|
version = "1.5.0"
|
||||||
|
|
||||||
|
[[deps.LazyArtifacts]]
|
||||||
|
deps = ["Artifacts", "Pkg"]
|
||||||
|
uuid = "4af54fe1-eca0-43a8-85a7-787d91b784e3"
|
||||||
|
|
||||||
|
[[deps.LibCURL]]
|
||||||
|
deps = ["LibCURL_jll", "MozillaCACerts_jll"]
|
||||||
|
uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21"
|
||||||
|
version = "0.6.4"
|
||||||
|
|
||||||
|
[[deps.LibCURL_jll]]
|
||||||
|
deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"]
|
||||||
|
uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0"
|
||||||
|
version = "8.4.0+0"
|
||||||
|
|
||||||
|
[[deps.LibGit2]]
|
||||||
|
deps = ["Base64", "LibGit2_jll", "NetworkOptions", "Printf", "SHA"]
|
||||||
|
uuid = "76f85450-5226-5b5a-8eaa-529ad045b433"
|
||||||
|
|
||||||
|
[[deps.LibGit2_jll]]
|
||||||
|
deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll"]
|
||||||
|
uuid = "e37daf67-58a4-590a-8e99-b0245dd2ffc5"
|
||||||
|
version = "1.6.4+0"
|
||||||
|
|
||||||
|
[[deps.LibSSH2_jll]]
|
||||||
|
deps = ["Artifacts", "Libdl", "MbedTLS_jll"]
|
||||||
|
uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8"
|
||||||
|
version = "1.11.0+1"
|
||||||
|
|
||||||
|
[[deps.LibSerialPort]]
|
||||||
|
deps = ["Libdl", "libserialport_jll"]
|
||||||
|
git-tree-sha1 = "69403284a6217f6e60e76553032a103893b7d910"
|
||||||
|
uuid = "a05a14c7-6e3b-5ba9-90a2-45558833e1df"
|
||||||
|
version = "0.5.2"
|
||||||
|
|
||||||
|
[[deps.Libdl]]
|
||||||
|
uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb"
|
||||||
|
|
||||||
|
[[deps.Logging]]
|
||||||
|
uuid = "56ddb016-857b-54e1-b83d-db4d58db5568"
|
||||||
|
|
||||||
|
[[deps.Markdown]]
|
||||||
|
deps = ["Base64"]
|
||||||
|
uuid = "d6f4376e-aef5-505a-96c1-9c027394607a"
|
||||||
|
|
||||||
|
[[deps.MbedTLS_jll]]
|
||||||
|
deps = ["Artifacts", "Libdl"]
|
||||||
|
uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1"
|
||||||
|
version = "2.28.2+1"
|
||||||
|
|
||||||
|
[[deps.Mmap]]
|
||||||
|
uuid = "a63ad114-7e13-5084-954f-fe012c677804"
|
||||||
|
|
||||||
|
[[deps.Mocking]]
|
||||||
|
deps = ["Compat", "ExprTools"]
|
||||||
|
git-tree-sha1 = "4cc0c5a83933648b615c36c2b956d94fda70641e"
|
||||||
|
uuid = "78c3b35d-d492-501b-9361-3d52fe80e533"
|
||||||
|
version = "0.7.7"
|
||||||
|
|
||||||
|
[[deps.MozillaCACerts_jll]]
|
||||||
|
uuid = "14a3606d-f60d-562e-9121-12d972cd8159"
|
||||||
|
version = "2023.1.10"
|
||||||
|
|
||||||
|
[[deps.NetworkOptions]]
|
||||||
|
uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908"
|
||||||
|
version = "1.2.0"
|
||||||
|
|
||||||
|
[[deps.Parsers]]
|
||||||
|
deps = ["Dates", "PrecompileTools", "UUIDs"]
|
||||||
|
git-tree-sha1 = "8489905bcdbcfac64d1daa51ca07c0d8f0283821"
|
||||||
|
uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
|
||||||
|
version = "2.8.1"
|
||||||
|
|
||||||
|
[[deps.PcapTools]]
|
||||||
|
deps = ["Dates", "Mmap", "UnixTimes", "UnsafeArrays"]
|
||||||
|
path = "dev/PcapTools"
|
||||||
|
uuid = "222fe7e8-3f39-464a-bf97-d9bbb753f246"
|
||||||
|
version = "1.1.1"
|
||||||
|
|
||||||
|
[[deps.Pkg]]
|
||||||
|
deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"]
|
||||||
|
uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
|
||||||
|
version = "1.10.0"
|
||||||
|
|
||||||
|
[[deps.PrecompileTools]]
|
||||||
|
deps = ["Preferences"]
|
||||||
|
git-tree-sha1 = "03b4c25b43cb84cee5c90aa9b5ea0a78fd848d2f"
|
||||||
|
uuid = "aea7be01-6a6a-4083-8856-8a6e6704d82a"
|
||||||
|
version = "1.2.0"
|
||||||
|
|
||||||
|
[[deps.Preferences]]
|
||||||
|
deps = ["TOML"]
|
||||||
|
git-tree-sha1 = "00805cd429dcb4870060ff49ef443486c262e38e"
|
||||||
|
uuid = "21216c6a-2e73-6563-6e65-726566657250"
|
||||||
|
version = "1.4.1"
|
||||||
|
|
||||||
|
[[deps.Printf]]
|
||||||
|
deps = ["Unicode"]
|
||||||
|
uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7"
|
||||||
|
|
||||||
|
[[deps.REPL]]
|
||||||
|
deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"]
|
||||||
|
uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
|
||||||
|
|
||||||
|
[[deps.Random]]
|
||||||
|
deps = ["SHA"]
|
||||||
|
uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
|
||||||
|
|
||||||
|
[[deps.SHA]]
|
||||||
|
uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"
|
||||||
|
version = "0.7.0"
|
||||||
|
|
||||||
|
[[deps.Scratch]]
|
||||||
|
deps = ["Dates"]
|
||||||
|
git-tree-sha1 = "3bac05bc7e74a75fd9cba4295cde4045d9fe2386"
|
||||||
|
uuid = "6c6a2e73-6563-6170-7368-637461726353"
|
||||||
|
version = "1.2.1"
|
||||||
|
|
||||||
|
[[deps.Serialization]]
|
||||||
|
uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
|
||||||
|
|
||||||
|
[[deps.Sockets]]
|
||||||
|
uuid = "6462fe0b-24de-5631-8697-dd941f90decc"
|
||||||
|
|
||||||
|
[[deps.TOML]]
|
||||||
|
deps = ["Dates"]
|
||||||
|
uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76"
|
||||||
|
version = "1.0.3"
|
||||||
|
|
||||||
|
[[deps.TZJData]]
|
||||||
|
deps = ["Artifacts"]
|
||||||
|
git-tree-sha1 = "d39314cdbaf5b90a047db33858626f8d1cc973e1"
|
||||||
|
uuid = "dc5dba14-91b3-4cab-a142-028a31da12f7"
|
||||||
|
version = "1.0.0+2023c"
|
||||||
|
|
||||||
|
[[deps.Tar]]
|
||||||
|
deps = ["ArgTools", "SHA"]
|
||||||
|
uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e"
|
||||||
|
version = "1.10.0"
|
||||||
|
|
||||||
|
[[deps.TimeZones]]
|
||||||
|
deps = ["Artifacts", "Dates", "Downloads", "InlineStrings", "LazyArtifacts", "Mocking", "Printf", "Scratch", "TZJData", "Unicode", "p7zip_jll"]
|
||||||
|
git-tree-sha1 = "89e64d61ef3cd9e80f7fc12b7d13db2d75a23c03"
|
||||||
|
uuid = "f269a46b-ccf7-5d73-abea-4c690281aa53"
|
||||||
|
version = "1.13.0"
|
||||||
|
|
||||||
|
[deps.TimeZones.extensions]
|
||||||
|
TimeZonesRecipesBaseExt = "RecipesBase"
|
||||||
|
|
||||||
|
[deps.TimeZones.weakdeps]
|
||||||
|
RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
|
||||||
|
|
||||||
|
[[deps.UUIDs]]
|
||||||
|
deps = ["Random", "SHA"]
|
||||||
|
uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
|
||||||
|
|
||||||
|
[[deps.Unicode]]
|
||||||
|
uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"
|
||||||
|
|
||||||
|
[[deps.UnixTimes]]
|
||||||
|
deps = ["Dates", "TimeZones"]
|
||||||
|
git-tree-sha1 = "406de9a6ee22f2030477ed7a50455aef3038bd4b"
|
||||||
|
uuid = "ab1a18e7-b408-4913-896c-624bb82ed7f4"
|
||||||
|
version = "1.3.0"
|
||||||
|
|
||||||
|
[[deps.UnsafeArrays]]
|
||||||
|
git-tree-sha1 = "e7f1c67ba99ac6df440de191fa4d5cbfcbdddcd1"
|
||||||
|
uuid = "c4a57d5a-5b31-53a6-b365-19f8c011fbd6"
|
||||||
|
version = "1.0.5"
|
||||||
|
|
||||||
|
[[deps.Zlib_jll]]
|
||||||
|
deps = ["Libdl"]
|
||||||
|
uuid = "83775a58-1f1d-513f-b197-d71354ab007a"
|
||||||
|
version = "1.2.13+1"
|
||||||
|
|
||||||
|
[[deps.libserialport_jll]]
|
||||||
|
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
|
||||||
|
git-tree-sha1 = "aacc5af8e8ba0b48a6feadac7afd4bca5d4e98d8"
|
||||||
|
uuid = "220460dc-b50e-5ed0-8176-09b0fd261e90"
|
||||||
|
version = "0.1.3+0"
|
||||||
|
|
||||||
|
[[deps.nghttp2_jll]]
|
||||||
|
deps = ["Artifacts", "Libdl"]
|
||||||
|
uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d"
|
||||||
|
version = "1.52.0+1"
|
||||||
|
|
||||||
|
[[deps.p7zip_jll]]
|
||||||
|
deps = ["Artifacts", "Libdl"]
|
||||||
|
uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0"
|
||||||
|
version = "17.4.0+2"
|
10
scripts/packet-analysis/Project.toml
Normal file
10
scripts/packet-analysis/Project.toml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
name = "AVCLANPipe"
|
||||||
|
uuid = "bfacebfd-1bd5-49e7-81bd-5edd8f4074de"
|
||||||
|
authors = ["Allen Hill <allenofthehills@gmail.com>"]
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
|
||||||
|
LibSerialPort = "a05a14c7-6e3b-5ba9-90a2-45558833e1df"
|
||||||
|
PcapTools = "222fe7e8-3f39-464a-bf97-d9bbb753f246"
|
||||||
|
UnixTimes = "ab1a18e7-b408-4913-896c-624bb82ed7f4"
|
11
scripts/packet-analysis/README.md
Normal file
11
scripts/packet-analysis/README.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Packet analysis with Wireshark
|
||||||
|
|
||||||
|
- Install the Lua IEBUS/AVCLAN packet dissector to the Wireshark Lua Plugins folder
|
||||||
|
- Look in Help > About Wireshark dialog, Folders tab, "Personal Lua Plugins". It was `~/.local/lib/wireshark/plugins` for me, but it didn't exist until I manually created it.
|
||||||
|
- Copy or link `avclan_plugin.lua` to the Wireshark Lua Pluginds folder
|
||||||
|
- Linking is more convenient if modifying/developing the dissector
|
||||||
|
`ln -s $(pwd)/avclan_plugin.lua ~/.local/lib/wireshark/plugins/avclan_plugin.lua`
|
||||||
|
- Install Julia and needed packages (I recommend using [juliaup](https://github.com/JuliaLang/juliaup) or an official binary from the Julialang website. Binaries from your distribution are typically out of date and/or built incorrectly.)
|
||||||
|
- From this folder, start Julia with the local project environment using `julia --project=@.`
|
||||||
|
- Run `] instantiate` to install the necessary Julia packages
|
||||||
|
- Run `julia src/pipepackets.jl | wireshark -k -i -` to pipe packets logged by the Mockingboard over serial into Wireshark. If the Lua dissector is installed correctly, the packets should be correctly recognized and dissected as IEBUS/AVCLAN packets
|
583
scripts/packet-analysis/avclan_plugin.lua
Normal file
583
scripts/packet-analysis/avclan_plugin.lua
Normal file
@ -0,0 +1,583 @@
|
|||||||
|
--[[
|
||||||
|
Copyright (C) 2023 Allen Hill <allenofthehills@gmail.com>
|
||||||
|
|
||||||
|
Portions of the following are based on code from libsigrokdecode PR that is
|
||||||
|
copyright (C) 2023 Maciej Grela <enki@fsck.pl>
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
--]]
|
||||||
|
|
||||||
|
local iebusproto = Proto("iebus", "IEBus protocol")
|
||||||
|
|
||||||
|
local f_broadcast = ProtoField.bool("iebus.broadcast", "Broadcast", base.NONE, { [1] = "false", [2] = "true" })
|
||||||
|
local f_controller_addr = ProtoField.uint16("iebus.controller", "Controller address", base.HEX, nil, 0x0FFF)
|
||||||
|
local f_peripheral_addr = ProtoField.uint16("iebus.peripheral", "Peripheral address", base.HEX, nil, 0x0FFF)
|
||||||
|
local f_control = ProtoField.uint8("iebus.control", "Control field", base.HEX)
|
||||||
|
local f_length = ProtoField.uint8("iebus.length", "Data length", base.DEC)
|
||||||
|
local f_data = ProtoField.bytes("iebus.data", "Frame data", base.SPACE)
|
||||||
|
|
||||||
|
iebusproto.fields = {
|
||||||
|
f_broadcast,
|
||||||
|
f_controller_addr,
|
||||||
|
f_peripheral_addr,
|
||||||
|
f_control,
|
||||||
|
f_length,
|
||||||
|
f_data
|
||||||
|
}
|
||||||
|
|
||||||
|
local controlbits = {
|
||||||
|
[0x0] = "READ PERIPH STATUS (SSR)",
|
||||||
|
[0x1] = "UNDEFINED",
|
||||||
|
[0x2] = "UNDEFINED",
|
||||||
|
[0x3] = "READ & LOCK DATA",
|
||||||
|
[0x4] = "READ LOCK ADDR (lo8)",
|
||||||
|
[0x5] = "READ LOCK ADDR (hi4)",
|
||||||
|
[0x6] = "READ & UNLOCK PERIPH STATUS (SSR)",
|
||||||
|
[0x7] = "READ DATA",
|
||||||
|
[0x8] = "UNDEFINED",
|
||||||
|
[0x9] = "UNDEFINED",
|
||||||
|
[0xA] = "WRITE & LOCK CMD",
|
||||||
|
[0xB] = "WRITE & LOCK DATA",
|
||||||
|
[0xC] = "UNDEFINED",
|
||||||
|
[0xD] = "UNDEFINED",
|
||||||
|
[0xE] = "WRITE CMD",
|
||||||
|
[0xF] = "WRITE DATA"
|
||||||
|
}
|
||||||
|
|
||||||
|
local periphstatusbits = {
|
||||||
|
[0] = "TX BUFFER EMPTY",
|
||||||
|
[1] = "RX BUFFER EMPTY",
|
||||||
|
[2] = "UNIT LOCKED",
|
||||||
|
[4] = "TX ENABLED",
|
||||||
|
[6] = "IEBUS MODE 1",
|
||||||
|
[7] = "IEBUS MODE 2",
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Expert info for unknown packet types, set as group PI_UNDECODED, severity PI_NOTE or PI_WARN
|
||||||
|
-- Expert info for LAN Check [0x3, SW_ID, 0x01, 0x20] as severity PI_CHAT
|
||||||
|
|
||||||
|
function iebusproto.dissector(buffer, pinfo, tree)
|
||||||
|
length = buffer:len()
|
||||||
|
if length == 0 then return end
|
||||||
|
|
||||||
|
pinfo.cols.protocol = iebusproto.name
|
||||||
|
|
||||||
|
local subtree = tree:add(iebusproto, buffer(), "IEBus frame")
|
||||||
|
|
||||||
|
subtree:add_le(f_broadcast, buffer(0,1))
|
||||||
|
pinfo.cols.src = buffer(1,2):bytes():tohex():sub(2,-1)
|
||||||
|
pinfo.cols.dst = buffer(3,2):bytes():tohex():sub(2,-1)
|
||||||
|
|
||||||
|
local control_item, control = subtree:add_packet_field(f_control, buffer(5,1), ENC_LITTLE_ENDIAN)
|
||||||
|
-- print("control val" .. control)
|
||||||
|
control_item:append_text(" (" .. controlbits[buffer(5,1):uint()] .. ")")
|
||||||
|
|
||||||
|
local _, datalen = subtree:add_packet_field(f_length, buffer(6,1), ENC_LITTLE_ENDIAN)
|
||||||
|
|
||||||
|
local data = subtree:add(iebusproto, buffer(), "IEBus message")
|
||||||
|
data:add(f_data, buffer(7, datalen))
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
local udlt = DissectorTable.get("wtap_encap")
|
||||||
|
udlt:add(wtap.USER15, iebusproto)
|
||||||
|
|
||||||
|
local avclanproto = Proto("avclan", "AVCLAN protocol")
|
||||||
|
|
||||||
|
local known_devices_names = {
|
||||||
|
["COMM_CTRL"] = 0x01,
|
||||||
|
["COMMUNICATION v1"] = 0x11,
|
||||||
|
["COMMUNICATION v2"] = 0x12,
|
||||||
|
["SW"] = 0x21,
|
||||||
|
["SW_NAME"] = 0x23,
|
||||||
|
["SW_CONVERTING"] = 0x24,
|
||||||
|
["CMD_SW"] = 0x25,
|
||||||
|
["STATUS"] = 0x31,
|
||||||
|
["BEEP_HU"] = 0x28,
|
||||||
|
["BEEP_SPEAKERS"] = 0x29,
|
||||||
|
["FRONT_PSNG_MONITOR"] = 0x34,
|
||||||
|
["CD_CHANGER2"] = 0x43,
|
||||||
|
["BLUETOOTH_TEL"] = 0x55,
|
||||||
|
["INFO_DRAWING"] = 0x56,
|
||||||
|
["NAV_ECU"] = 0x58,
|
||||||
|
["CAMERA"] = 0x5C,
|
||||||
|
["CLIMATE_DRAWING"] = 0x5D,
|
||||||
|
["AUDIO_DRAWING"] = 0x5E,
|
||||||
|
["TRIP_INFO_DRAWING"] = 0x5F,
|
||||||
|
["TUNER"] = 0x60,
|
||||||
|
["TAPE_DECK"] = 0x61,
|
||||||
|
["CD"] = 0x62,
|
||||||
|
["CD_CHANGER"] = 0x63,
|
||||||
|
["AUDIO_AMP"] = 0x74,
|
||||||
|
["GPS"] = 0x80,
|
||||||
|
["VOICE_CTRL"] = 0x85,
|
||||||
|
["CLIMATE_CTRL_DEV"] = 0xE0,
|
||||||
|
["TRIP_INFO"] = 0xE5,
|
||||||
|
}
|
||||||
|
|
||||||
|
local known_devices = {
|
||||||
|
[0x01] = "COMM_CTRL",
|
||||||
|
[0x11] = "COMMUNICATION v1",
|
||||||
|
[0x12] = "COMMUNICATION v2",
|
||||||
|
[0x21] = "SW",
|
||||||
|
[0x23] = "SW_NAME",
|
||||||
|
[0x24] = "SW_CONVERTING",
|
||||||
|
[0x25] = "CMD_SW",
|
||||||
|
[0x31] = "STATUS",
|
||||||
|
[0x28] = "BEEP_HU",
|
||||||
|
[0x29] = "BEEP_SPEAKERS",
|
||||||
|
[0x34] = "FRONT_PSNG_MONITOR",
|
||||||
|
[0x43] = "CD_CHANGER2",
|
||||||
|
[0x55] = "BLUETOOTH_TEL",
|
||||||
|
[0x56] = "INFO_DRAWING",
|
||||||
|
[0x58] = "NAV_ECU",
|
||||||
|
[0x5C] = "CAMERA",
|
||||||
|
[0x5D] = "CLIMATE_DRAWING",
|
||||||
|
[0x5E] = "AUDIO_DRAWING",
|
||||||
|
[0x5F] = "TRIP_INFO_DRAWING",
|
||||||
|
[0x60] = "TUNER",
|
||||||
|
[0x61] = "TAPE_DECK",
|
||||||
|
[0x62] = "CD",
|
||||||
|
[0x63] = "CD_CHANGER",
|
||||||
|
[0x74] = "AUDIO_AMP",
|
||||||
|
[0x80] = "GPS",
|
||||||
|
[0x85] = "VOICE_CTRL",
|
||||||
|
[0xE0] = "CLIMATE_CTRL_DEV",
|
||||||
|
[0xE5] = "TRIP_INFO",
|
||||||
|
}
|
||||||
|
|
||||||
|
local f_from_device = ProtoField.uint8("avclan.from_device", "From device", base.HEX, known_devices)
|
||||||
|
local f_to_device = ProtoField.uint8("avclan.to_device", "To device", base.HEX, known_devices)
|
||||||
|
local f_active_device = ProtoField.uint8("avclan.active_device", "Active device", base.HEX, known_devices)
|
||||||
|
|
||||||
|
local known_actions_names = {
|
||||||
|
-- LAN related
|
||||||
|
["LIST_FUNCTIONS_REQ"] = 0x00,
|
||||||
|
["LIST_FUNCTIONS_RESP"] = 0x10,
|
||||||
|
["RESTART_LAN"] = 0x01,
|
||||||
|
["LANCHECK_END_REQ"] = 0x08,
|
||||||
|
["LANCHECK_END_RESP"] = 0x18,
|
||||||
|
["LANCHECK_SCAN_REQ"] = 0x0a,
|
||||||
|
["LANCHECK_SCAN_RESP"] = 0x1a,
|
||||||
|
["LANCHECK_REQ"] = 0x0c,
|
||||||
|
["LANCHECK_RESP"] = 0x1c,
|
||||||
|
["PING_REQ"] = 0x20,
|
||||||
|
["PING_RESP"] = 0x30,
|
||||||
|
|
||||||
|
-- Device switching
|
||||||
|
["DISABLE_FUNCTION_REQ"] = 0x43,
|
||||||
|
["DISABLE_FUNCTION_RESP"] = 0x53,
|
||||||
|
["ENABLE_FUNCTION_REQ"] = 0x42,
|
||||||
|
["ENABLE_FUNCTION_RESP"] = 0x52,
|
||||||
|
|
||||||
|
["ADVERTISE_FUNCTION"] = 0x45,
|
||||||
|
["GENERAL_QUERY"] = 0x46,
|
||||||
|
|
||||||
|
-- Physical interface
|
||||||
|
["EJECT"] = 0x80,
|
||||||
|
["DISC_UP"] = 0x90,
|
||||||
|
["DISC_DOWN"] = 0x91,
|
||||||
|
["PWRVOL_KNOB_RIGHTHAND_TURN"] = 0x9c,
|
||||||
|
["PWRVOL_KNOB_LEFTHAND_TURN"] = 0x9d,
|
||||||
|
["TRACK_SEEK_UP"] = 0x94,
|
||||||
|
["TRACK_SEEK_DOWN"] = 0x95,
|
||||||
|
["CD_ENABLE_SCAN"] = 0xa6,
|
||||||
|
["CD_DISABLE_SCAN"] = 0xa7,
|
||||||
|
["CD_ENABLE_REPEAT"] = 0xa0,
|
||||||
|
["CD_DISABLE_REPEAT"] = 0xa1,
|
||||||
|
["CD_ENABLE_RANDOM"] = 0xb0,
|
||||||
|
["CD_DISABLE_RANDOM"] = 0xb1,
|
||||||
|
|
||||||
|
-- CD functions
|
||||||
|
-- Events
|
||||||
|
["INSERTED_CD"] = 0x50,
|
||||||
|
["REMOVED_CD"] = 0x51,
|
||||||
|
|
||||||
|
-- Requests
|
||||||
|
["REQUEST_REPORT"] = 0xe0,
|
||||||
|
["REQUEST_REPORT2"] = 0xe2,
|
||||||
|
["REQUEST_LOADER2"] = 0xe4,
|
||||||
|
["REQUEST_TRACK_NAME"] = 0xed,
|
||||||
|
|
||||||
|
-- Reports
|
||||||
|
["REPORT"] = 0xf1,
|
||||||
|
["REPORT2"] = 0xf2,
|
||||||
|
["REPORT_LOADER"] = 0xf3,
|
||||||
|
["REPORT_LOADER2"] = 0xf4,
|
||||||
|
["REPORT_TOC"] = 0xf9,
|
||||||
|
["REPORT_TRACK_NAME"] = 0xfd,
|
||||||
|
}
|
||||||
|
local known_actions = {
|
||||||
|
-- LAN related
|
||||||
|
[0x00] = "LIST_FUNCTIONS_REQ",
|
||||||
|
[0x10] = "LIST_FUNCTIONS_RESP",
|
||||||
|
[0x01] = "RESTART_LAN",
|
||||||
|
[0x08] = "LANCHECK_END_REQ",
|
||||||
|
[0x18] = "LANCHECK_END_RESP",
|
||||||
|
[0x0a] = "LANCHECK_SCAN_REQ",
|
||||||
|
[0x1a] = "LANCHECK_SCAN_RESP",
|
||||||
|
[0x0c] = "LANCHECK_REQ",
|
||||||
|
[0x1c] = "LANCHECK_RESP",
|
||||||
|
[0x20] = "PING_REQ",
|
||||||
|
[0x30] = "PING_RESP",
|
||||||
|
|
||||||
|
-- Used when HU is switching between Radio and CD
|
||||||
|
[0x43] = "DISABLE_FUNCTION_REQ",
|
||||||
|
[0x53] = "DISABLE_FUNCTION_RESP",
|
||||||
|
[0x42] = "ENABLE_FUNCTION_REQ",
|
||||||
|
[0x52] = "ENABLE_FUNCTION_RESP",
|
||||||
|
|
||||||
|
[0x45] = "ADVERTISE_FUNCTION",
|
||||||
|
[0x46] = "GENERAL_QUERY",
|
||||||
|
|
||||||
|
-- Physical interface
|
||||||
|
[0x80] = "EJECT",
|
||||||
|
[0x90] = "DISC_UP",
|
||||||
|
[0x91] = "DISC_DOWN",
|
||||||
|
[0x9c] = "PWRVOL_KNOB_RIGHTHAND_TURN",
|
||||||
|
[0x9d] = "PWRVOL_KNOB_LEFTHAND_TURN",
|
||||||
|
[0x94] = "TRACK_SEEK_UP",
|
||||||
|
[0x95] = "TRACK_SEEK_DOWN",
|
||||||
|
[0xa6] = "CD_ENABLE_SCAN",
|
||||||
|
[0xa7] = "CD_DISABLE_SCAN",
|
||||||
|
[0xa0] = "CD_ENABLE_REPEAT",
|
||||||
|
[0xa1] = "CD_DISABLE_REPEAT",
|
||||||
|
[0xb0] = "CD_ENABLE_RANDOM",
|
||||||
|
[0xb1] = "CD_DISABLE_RANDOM",
|
||||||
|
|
||||||
|
-- CD functions
|
||||||
|
-- Events
|
||||||
|
[0x50] = "INSERTED_CD",
|
||||||
|
[0x51] = "REMOVED_CD",
|
||||||
|
|
||||||
|
-- Requests
|
||||||
|
[0xe0] = "REQUEST_REPORT",
|
||||||
|
[0xe2] = "REQUEST_REPORT2",
|
||||||
|
[0xe4] = "REQUEST_LOADER2",
|
||||||
|
[0xed] = "REQUEST_TRACK_NAME",
|
||||||
|
|
||||||
|
-- Reports
|
||||||
|
[0xf1] = "REPORT",
|
||||||
|
[0xf2] = "REPORT2",
|
||||||
|
[0xf3] = "REPORT_LOADER",
|
||||||
|
[0xf4] = "REPORT_LOADER2",
|
||||||
|
[0xf9] = "REPORT_TOC",
|
||||||
|
[0xfd] = "REPORT_TRACK_NAME",
|
||||||
|
}
|
||||||
|
|
||||||
|
local f_action = ProtoField.uint8("avclan.action", "Action", base.HEX, known_actions)
|
||||||
|
local f_functions = ProtoField.bytes("avclan.functions", "Functions", base.SPACE, "Device functions")
|
||||||
|
|
||||||
|
local f_ping_count = ProtoField.uint8("avclan.ping.count", "Ping count")
|
||||||
|
|
||||||
|
local f_radio_active = ProtoField.bool("avclan.radio.active", "Radio", base.NONE, {"ON", "OFF"})
|
||||||
|
local f_radio_status = ProtoField.uint8("avclan.radio.status", "Radio status", base.HEX,
|
||||||
|
{
|
||||||
|
[0x00] = "OFF",
|
||||||
|
[0x01] = "READY",
|
||||||
|
[0x06] = "SCAN UP",
|
||||||
|
[0x07] = "SCAN DOWN",
|
||||||
|
[0x0A] = "AST SEARCH",
|
||||||
|
[0x27] = "MANUAL"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
local f_radio_flags = ProtoField.uint8("avclan.radio.flags", "Radio flags")
|
||||||
|
local f_radio_flags2 = ProtoField.uint8("avclan.radio.flags2", "Radio flags (byte 2)")
|
||||||
|
|
||||||
|
local f_radioflag_st = ProtoField.bool("avclan.radio.flags.st", "Stereo", 8, {"Set", "Not set"}, 0x04)
|
||||||
|
local f_radioflag_ta = ProtoField.bool("avclan.radio.flags.ta", "TA", 8, {"Set", "Not set"}, 0x08)
|
||||||
|
local f_radioflag_reg = ProtoField.bool("avclan.radio.flags.reg", "REG", 8, {"Set", "Not set"}, 0x10)
|
||||||
|
local f_radioflag_af = ProtoField.bool("avclan.radio.flags.af", "AF", 8, {"Set", "Not set"}, 0x40)
|
||||||
|
|
||||||
|
local f_radio_band = ProtoField.uint8("avclan.radio.band", "Radio band", base.HEX,
|
||||||
|
{[0x8] = "FM", [0xC] = "AM (Long-wave)", [0x0] = "AM (Medium-wave)"}, 0xF0)
|
||||||
|
local f_radio_bandnumber = ProtoField.int8("avclan.radio.bandnumber", "Radio band number", base.DEC, nil, 0x0F)
|
||||||
|
local f_radio_freq = ProtoField.uint16("avclan.radio.freq", "Radio frequency")
|
||||||
|
|
||||||
|
local f_amp_volume = ProtoField.uint8("avclan.amp.volume", "Volume", base.DEC)
|
||||||
|
local f_amp_bass = ProtoField.uint8("avclan.amp.bass", "Bass", base.HEX, {
|
||||||
|
[0x0B] = "-5", [0x0C] = "-4", [0x0D] = "-3", [0x0E] = "-2", [0x0F] = "-1",
|
||||||
|
[0x10] = "0",
|
||||||
|
[0x11] = "+1", [0x12] = "+2", [0x13] = "+3", [0x14] = "+4", [0x15] = "+5"
|
||||||
|
})
|
||||||
|
local f_amp_mid = ProtoField.uint8("avclan.amp.mid", "Mid", base.HEX, {
|
||||||
|
[0x0B] = "-5", [0x0C] = "-4", [0x0D] = "-3", [0x0E] = "-2", [0x0F] = "-1",
|
||||||
|
[0x10] = "0",
|
||||||
|
[0x11] = "+1", [0x12] = "+2", [0x13] = "+3", [0x14] = "+4", [0x15] = "+5"
|
||||||
|
})
|
||||||
|
local f_amp_treble = ProtoField.uint8("avclan.amp.treble", "Treble", base.HEX, {
|
||||||
|
[0x0B] = "-5", [0x0C] = "-4", [0x0D] = "-3", [0x0E] = "-2", [0x0F] = "-1",
|
||||||
|
[0x10] = "0",
|
||||||
|
[0x11] = "+1", [0x12] = "+2", [0x13] = "+3", [0x14] = "+4", [0x15] = "+5"
|
||||||
|
})
|
||||||
|
local f_amp_fade = ProtoField.uint8("avclan.amp.fade", "Fade (forward/rear)", base.HEX, {
|
||||||
|
[0x09] = "-7", [0x0A] = "-6", [0x0B] = "-5", [0x0C] = "-4", [0x0D] = "-3", [0x0E] = "-2", [0x0F] = "-1",
|
||||||
|
[0x10] = "0",
|
||||||
|
[0x11] = "+1", [0x12] = "+2", [0x13] = "+3", [0x14] = "+4", [0x15] = "+5", [0x16] = "+6", [0x17] = "+7"
|
||||||
|
})
|
||||||
|
local f_amp_balance = ProtoField.uint8("avclan.amp.balance", "Balance (right/left)", base.HEX, {
|
||||||
|
[0x09] = "-7", [0x0A] = "-6", [0x0B] = "-5", [0x0C] = "-4", [0x0D] = "-3", [0x0E] = "-2", [0x0F] = "-1",
|
||||||
|
[0x10] = "0",
|
||||||
|
[0x11] = "+1", [0x12] = "+2", [0x13] = "+3", [0x14] = "+4", [0x15] = "+5", [0x16] = "+6", [0x17] = "+7"
|
||||||
|
})
|
||||||
|
|
||||||
|
local f_cd_slots = ProtoField.uint8("avclan.cd.slots", "CD player disc slots")
|
||||||
|
local f_cd_slot1 = ProtoField.bool("avclan.cd.slot1", "Slot 1", 6, {"Filled", "Empty"}, 0x01)
|
||||||
|
local f_cd_slot2 = ProtoField.bool("avclan.cd.slot1", "Slot 2", 6, {"Filled", "Empty"}, 0x02)
|
||||||
|
local f_cd_slot3 = ProtoField.bool("avclan.cd.slot1", "Slot 3", 6, {"Filled", "Empty"}, 0x04)
|
||||||
|
local f_cd_slot4 = ProtoField.bool("avclan.cd.slot1", "Slot 4", 6, {"Filled", "Empty"}, 0x08)
|
||||||
|
local f_cd_slot5 = ProtoField.bool("avclan.cd.slot1", "Slot 5", 6, {"Filled", "Empty"}, 0x10)
|
||||||
|
local f_cd_slot6 = ProtoField.bool("avclan.cd.slot1", "Slot 6", 6, {"Filled", "Empty"}, 0x20)
|
||||||
|
|
||||||
|
local f_cd_state = ProtoField.uint8("avclan.cd.state", "CD player state")
|
||||||
|
local f_cd_open = ProtoField.bool("avclan.cd.state.open", "OPEN", 8, nil, 0x01)
|
||||||
|
local f_cd_err1 = ProtoField.bool("avclan.cd.state.err1", "ERR1", 8, nil, 0x02)
|
||||||
|
local f_cd_seeking = ProtoField.bool("avclan.cd.state.seeking", "SEEKING", 8, nil, 0x08)
|
||||||
|
local f_cd_playback = ProtoField.bool("avclan.cd.state.playback", "PLAYBACK", 8, nil, 0x10)
|
||||||
|
local f_cd_seeking_track = ProtoField.bool("avclan.cd.state.seeking_track", "SEEKING_TRACK", 8, nil, 0x20)
|
||||||
|
local f_cd_loading = ProtoField.bool("avclan.cd.state.loading", "LOADING", 8, nil, 0x80)
|
||||||
|
|
||||||
|
local f_cd_disc = ProtoField.uint8("avclan.cd.disc", "Current disc", base.DEC)
|
||||||
|
local f_cd_track = ProtoField.uint8("avclan.cd.track", "Track number", base.HEX)
|
||||||
|
local f_cd_min = ProtoField.uint8("avclan.cd.mins", "CD track play time, minutes", base.HEX)
|
||||||
|
local f_cd_sec = ProtoField.uint8("avclan.cd.secs", "CD track play time, seconds", base.HEX)
|
||||||
|
|
||||||
|
local f_cd_flags = ProtoField.uint8("avclan.cd.flags", "CD player flags", base.HEX, {
|
||||||
|
[0x02] = "DISK_RANDOM",
|
||||||
|
[0x04] = "RANDOM",
|
||||||
|
[0x08] = "DISK_REPEAT",
|
||||||
|
[0x10] = "REPEAT",
|
||||||
|
[0x20] = "DISK_SCAN",
|
||||||
|
[0x40] = "SCAN",
|
||||||
|
})
|
||||||
|
|
||||||
|
avclanproto.fields = {
|
||||||
|
f_from_device,
|
||||||
|
f_to_device,
|
||||||
|
f_active_device,
|
||||||
|
f_action,
|
||||||
|
f_functions,
|
||||||
|
f_ping_count,
|
||||||
|
f_radio_active,
|
||||||
|
f_radio_status,
|
||||||
|
f_radio_flags,
|
||||||
|
f_radio_flags2,
|
||||||
|
f_radio_band,
|
||||||
|
f_radio_bandnumber,
|
||||||
|
f_radio_freq,
|
||||||
|
f_radioflag_af,
|
||||||
|
f_radioflag_reg,
|
||||||
|
f_radioflag_st,
|
||||||
|
f_radioflag_ta,
|
||||||
|
f_amp_volume,
|
||||||
|
f_amp_bass,
|
||||||
|
f_amp_mid,
|
||||||
|
f_amp_treble,
|
||||||
|
f_amp_fade,
|
||||||
|
f_amp_balance,
|
||||||
|
f_cd_slots,
|
||||||
|
f_cd_slot1,
|
||||||
|
f_cd_slot2,
|
||||||
|
f_cd_slot3,
|
||||||
|
f_cd_slot4,
|
||||||
|
f_cd_slot5,
|
||||||
|
f_cd_slot6,
|
||||||
|
f_cd_state,
|
||||||
|
f_cd_open,
|
||||||
|
f_cd_err1,
|
||||||
|
f_cd_seeking,
|
||||||
|
f_cd_playback,
|
||||||
|
f_cd_seeking_track,
|
||||||
|
f_cd_loading,
|
||||||
|
f_cd_disc,
|
||||||
|
f_cd_track,
|
||||||
|
f_cd_min,
|
||||||
|
f_cd_sec,
|
||||||
|
f_cd_flags,
|
||||||
|
}
|
||||||
|
|
||||||
|
local pe_unhandled_msg = ProtoExpert.new("avclan.expert", "Message not decoded",
|
||||||
|
expert.group.UNDECODED, expert.severity.WARN)
|
||||||
|
-- local pe_lan_check = ProtoExpert.new("avclan.lan.expert", "")
|
||||||
|
local pe_ping_req = ProtoExpert.new("avclan.ping_req.expert", "Ping request",
|
||||||
|
expert.group.SEQUENCE, expert.severity.CHAT)
|
||||||
|
local pe_ping_resp = ProtoExpert.new("avclan.ping_resp.expert", "Ping response",
|
||||||
|
expert.group.SEQUENCE, expert.severity.CHAT)
|
||||||
|
|
||||||
|
avclanproto.experts = {
|
||||||
|
pe_unhandled_msg,
|
||||||
|
pe_ping_req,
|
||||||
|
pe_ping_resp,
|
||||||
|
}
|
||||||
|
|
||||||
|
local field_from_device = Field.new("avclan.from_device")
|
||||||
|
local field_to_device = Field.new("avclan.to_device")
|
||||||
|
local field_action = Field.new("avclan.action")
|
||||||
|
local field_radio_freq = Field.new("avclan.radio.freq")
|
||||||
|
local field_radio_band = Field.new("avclan.radio.band")
|
||||||
|
local field_cd_disc = Field.new("avclan.cd.disc")
|
||||||
|
local field_cd_track = Field.new("avclan.cd.track")
|
||||||
|
local field_cd_min = Field.new("avclan.cd.mins")
|
||||||
|
local field_cd_sec = Field.new("avclan.cd.secs")
|
||||||
|
|
||||||
|
function avclanproto.dissector(buffer, pinfo, tree)
|
||||||
|
local length = buffer:len()
|
||||||
|
if length == 0 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
iebusproto.dissector(buffer, pinfo, tree)
|
||||||
|
|
||||||
|
local subtree = tree:add(avclanproto, buffer(7,-1), "AVCLAN message")
|
||||||
|
local offset = 7
|
||||||
|
if buffer(7,1):uint() == 0 then
|
||||||
|
offset = 8
|
||||||
|
subtree:add(f_from_device, buffer(offset+0,1))
|
||||||
|
subtree:add(f_to_device, buffer(offset+1,1))
|
||||||
|
else
|
||||||
|
subtree:add(f_from_device, buffer(offset+0,1))
|
||||||
|
subtree:add(f_to_device, buffer(offset+1,1))
|
||||||
|
end
|
||||||
|
|
||||||
|
local from_device = field_from_device().value
|
||||||
|
local to_device = field_to_device().value
|
||||||
|
|
||||||
|
if from_device == known_devices_names["CMD_SW"] then
|
||||||
|
subtree:add(f_action, buffer(offset+2,1))
|
||||||
|
elseif from_device == known_devices_names["COMMUNICATION v1"] or
|
||||||
|
from_device == known_devices_names["COMMUNICATION v2"] then
|
||||||
|
if to_device == known_devices_names["COMM_CTRL"] then
|
||||||
|
subtree:add(f_action, buffer(offset+2,1))
|
||||||
|
local action = field_action().value
|
||||||
|
if action == known_actions_names["ADVERTISE_FUNCTION"] then
|
||||||
|
subtree:add(f_active_device, buffer(offset+3,1))
|
||||||
|
elseif action == known_actions_names["PING_REQ"] then
|
||||||
|
subtree:add(f_ping_count, buffer(offset+3,1))
|
||||||
|
subtree:add_proto_expert_info(pe_ping_req, "Ping request " .. buffer(offset+3,1):uint())
|
||||||
|
elseif known_actions[action] then
|
||||||
|
else
|
||||||
|
subtree:add_proto_expert_info(pe_unhandled_msg)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
subtree:add_proto_expert_info(pe_unhandled_msg)
|
||||||
|
end
|
||||||
|
elseif from_device == known_devices_names["COMM_CTRL"] then
|
||||||
|
if to_device == known_devices_names["COMMUNICATION v1"] or
|
||||||
|
to_device == known_devices_names["COMMUNICATION v2"] then
|
||||||
|
local action_tree = subtree:add(f_action, buffer(offset+2,1))
|
||||||
|
local action = field_action().value
|
||||||
|
if action == known_actions_names["PING_RESP"] then
|
||||||
|
subtree:add(f_ping_count, buffer(offset+3,1))
|
||||||
|
subtree:add_proto_expert_info(pe_ping_resp, "Ping response " .. buffer(offset+3,1):uint())
|
||||||
|
elseif action == known_actions_names["LIST_FUNCTIONS_RESP"] then
|
||||||
|
local functions = action_tree:add(f_functions, buffer(offset+3))
|
||||||
|
functions:append_text(" (")
|
||||||
|
for v = 0,(buffer:bytes(offset+3)):len()-1 do
|
||||||
|
if known_devices[buffer(offset+3+v,1):uint()] then
|
||||||
|
functions:append_text(" " .. known_devices[buffer(offset+3+v,1):uint()])
|
||||||
|
else
|
||||||
|
functions:append_text(" UNKNOWN_DEVICE")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
functions:append_text(" ) ")
|
||||||
|
elseif known_actions[action] then
|
||||||
|
else
|
||||||
|
subtree:add_proto_expert_info(pe_unhandled_msg)
|
||||||
|
end
|
||||||
|
elseif to_device == known_actions_names["LANCHECK_SCAN_REQ"] or
|
||||||
|
to_device == known_actions_names["LANCHECK_REQ"] or
|
||||||
|
to_device == known_actions_names["LANCHECK_END_REQ"] then
|
||||||
|
subtree:add(f_action, buffer(offset+1,1))
|
||||||
|
elseif to_device == 0x00 then
|
||||||
|
subtree:add(f_action, buffer(offset+2,1))
|
||||||
|
else
|
||||||
|
subtree:add_proto_expert_info(pe_unhandled_msg)
|
||||||
|
end
|
||||||
|
elseif from_device == known_devices_names["STATUS"] then
|
||||||
|
subtree:add(f_action, buffer(offset+2,1))
|
||||||
|
elseif from_device == known_devices_names["TUNER"] then
|
||||||
|
subtree:add(f_action, buffer(offset+2,1))
|
||||||
|
local radiotree = subtree:add(avclanproto, buffer(offset,10), "Device: Radio")
|
||||||
|
radiotree:add_le(f_radio_active, buffer(offset+3,1))
|
||||||
|
radiotree:add_le(f_radio_status, buffer(offset+4,1))
|
||||||
|
radiotree:add_le(f_radio_band, buffer(offset+5,1))
|
||||||
|
radiotree:add(f_radio_bandnumber, buffer(offset+5,1))
|
||||||
|
local freqtree = radiotree:add(f_radio_freq, buffer(offset+6,2))
|
||||||
|
local radio_band = buffer(offset+5,1):uint()
|
||||||
|
local freq = field_radio_freq().value
|
||||||
|
if bit32.band(radio_band, 0xF0) == 0x80 then
|
||||||
|
freqtree:append_text(" (" .. 87.5+(freq-1)*.05 .. " MHz)")
|
||||||
|
elseif bit32.band(radio_band, 0xF0) == 0xC0 then
|
||||||
|
freqtree:append_text(" (" .. 153+(freq-1)*1 .. " kHz)")
|
||||||
|
elseif bit32.band(radio_band, 0xF0) == 0x00 then
|
||||||
|
freqtree:append_text(" (" .. 522+(freq-1)*9 .. " kHz)")
|
||||||
|
end
|
||||||
|
|
||||||
|
local flags = radiotree:add(f_radio_flags, buffer(15,1))
|
||||||
|
flags:add(f_radioflag_st, buffer(15,1))
|
||||||
|
flags:add(f_radioflag_ta, buffer(15,1))
|
||||||
|
flags:add(f_radioflag_reg, buffer(15,1))
|
||||||
|
flags:add(f_radioflag_af, buffer(15,1))
|
||||||
|
radiotree:add(f_radio_flags2, buffer(16,1))
|
||||||
|
elseif from_device == known_devices_names["AUDIO_AMP"] then
|
||||||
|
subtree:add(f_action, buffer(offset+2,1))
|
||||||
|
local amptree = subtree:add(avclanproto, buffer(offset,10), "Device: Audio amplifier")
|
||||||
|
|
||||||
|
amptree:add(f_amp_volume, buffer(offset+4,1))
|
||||||
|
amptree:add(f_amp_balance, buffer(offset+5,1))
|
||||||
|
amptree:add(f_amp_fade, buffer(offset+6,1))
|
||||||
|
amptree:add(f_amp_bass, buffer(offset+7,1))
|
||||||
|
amptree:add(f_amp_mid, buffer(offset+8,1))
|
||||||
|
amptree:add(f_amp_treble, buffer(offset+9,1))
|
||||||
|
elseif from_device == known_devices_names["CD"] or
|
||||||
|
from_device == known_devices_names["CD_CHANGER"] or
|
||||||
|
from_device == known_devices_names["CD_CHANGER2"] then
|
||||||
|
subtree:add(f_action, buffer(offset+2,1))
|
||||||
|
|
||||||
|
local action = field_action().value
|
||||||
|
if action == known_actions_names["REPORT"] then
|
||||||
|
local cdtree = subtree:add(avclanproto, buffer(offset,9), "Device: CD player")
|
||||||
|
local cd_slots = cdtree:add(f_cd_slots, buffer(offset+3,1))
|
||||||
|
cd_slots:add(f_cd_slot1, buffer(offset+3,1))
|
||||||
|
cd_slots:add(f_cd_slot2, buffer(offset+3,1))
|
||||||
|
cd_slots:add(f_cd_slot3, buffer(offset+3,1))
|
||||||
|
cd_slots:add(f_cd_slot4, buffer(offset+3,1))
|
||||||
|
cd_slots:add(f_cd_slot5, buffer(offset+3,1))
|
||||||
|
cd_slots:add(f_cd_slot6, buffer(offset+3,1))
|
||||||
|
|
||||||
|
local cd_state = cdtree:add(f_cd_state, buffer(offset+4,1))
|
||||||
|
cd_state:add(f_cd_open, buffer(offset+4,1))
|
||||||
|
cd_state:add(f_cd_err1, buffer(offset+4,1))
|
||||||
|
cd_state:add(f_cd_seeking, buffer(offset+4,1))
|
||||||
|
cd_state:add(f_cd_playback, buffer(offset+4,1))
|
||||||
|
cd_state:add(f_cd_seeking_track, buffer(offset+4,1))
|
||||||
|
cd_state:add(f_cd_loading, buffer(offset+4,1))
|
||||||
|
local cd_status = cdtree:add(avclanproto, buffer(offset+5,-1), "")
|
||||||
|
cd_status:add(f_cd_disc, buffer(offset+5,1))
|
||||||
|
cd_status:add(f_cd_track, buffer(offset+6,1))
|
||||||
|
cd_status:add(f_cd_min, buffer(offset+7,1))
|
||||||
|
cd_status:add(f_cd_sec, buffer(offset+8,1))
|
||||||
|
cd_status:append_text("Disc " .. field_cd_disc().value .. ", ")
|
||||||
|
cd_status:append_text("track " .. tostring(buffer(offset+6,1)):gsub("(.)(.)", "%1%2") .. ", ")
|
||||||
|
cd_status:append_text("time " .. tostring(buffer(offset+7,1)):gsub("0x(.)(.)", "%1%2") .. ":")
|
||||||
|
cd_status:append_text(tostring(buffer(offset+8,1)):gsub("(.)(.)", "%1%2"))
|
||||||
|
cdtree:add(f_cd_flags, buffer(offset+9,1))
|
||||||
|
end
|
||||||
|
else
|
||||||
|
subtree:add_proto_expert_info(pe_unhandled_msg)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- for i,v in ipairs(DissectorTable.list()) do print(v) end
|
||||||
|
udlt:add(wtap.USER15, avclanproto)
|
19
scripts/packet-analysis/dev/PcapTools/LICENSE
Normal file
19
scripts/packet-analysis/dev/PcapTools/LICENSE
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) 2020 Christian Rorvik <christian.rorvik@gmail.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
21
scripts/packet-analysis/dev/PcapTools/Project.toml
Normal file
21
scripts/packet-analysis/dev/PcapTools/Project.toml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
name = "PcapTools"
|
||||||
|
uuid = "222fe7e8-3f39-464a-bf97-d9bbb753f246"
|
||||||
|
authors = ["Christian Rorvik <christian.rorvik@gmail.com>"]
|
||||||
|
version = "1.1.1"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
|
||||||
|
Mmap = "a63ad114-7e13-5084-954f-fe012c677804"
|
||||||
|
UnixTimes = "ab1a18e7-b408-4913-896c-624bb82ed7f4"
|
||||||
|
UnsafeArrays = "c4a57d5a-5b31-53a6-b365-19f8c011fbd6"
|
||||||
|
|
||||||
|
[compat]
|
||||||
|
UnixTimes = "1"
|
||||||
|
UnsafeArrays = "1"
|
||||||
|
julia = "1.4"
|
||||||
|
|
||||||
|
[extras]
|
||||||
|
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
|
||||||
|
|
||||||
|
[targets]
|
||||||
|
test = ["Test"]
|
5
scripts/packet-analysis/dev/PcapTools/README.md
Normal file
5
scripts/packet-analysis/dev/PcapTools/README.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# PcapTools
|
||||||
|
|
||||||
|
[](https://travis-ci.com/ancapdev/PcapTools.jl)
|
||||||
|
|
||||||
|
[](https://coveralls.io/github/ancapdev/PcapTools.jl)
|
26
scripts/packet-analysis/dev/PcapTools/src/PcapTools.jl
Normal file
26
scripts/packet-analysis/dev/PcapTools/src/PcapTools.jl
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
module PcapTools
|
||||||
|
|
||||||
|
using Dates
|
||||||
|
using Mmap
|
||||||
|
using UnixTimes
|
||||||
|
using UnsafeArrays
|
||||||
|
|
||||||
|
export PcapHeader, RecordHeader
|
||||||
|
export PcapRecord
|
||||||
|
export PcapReader, PcapStreamReader, PcapBufferReader
|
||||||
|
export PcapWriter, PcapStreamWriter
|
||||||
|
export LINKTYPE_NULL, LINKTYPE_ETHERNET
|
||||||
|
export splitcap
|
||||||
|
|
||||||
|
abstract type PcapReader end
|
||||||
|
abstract type PcapWriter end
|
||||||
|
|
||||||
|
include("pcap_header.jl")
|
||||||
|
include("record_header.jl")
|
||||||
|
include("record.jl")
|
||||||
|
include("buffer_reader.jl")
|
||||||
|
include("stream_reader.jl")
|
||||||
|
include("stream_writer.jl")
|
||||||
|
include("splitcap.jl")
|
||||||
|
|
||||||
|
end
|
96
scripts/packet-analysis/dev/PcapTools/src/buffer_reader.jl
Normal file
96
scripts/packet-analysis/dev/PcapTools/src/buffer_reader.jl
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
"""
|
||||||
|
Reads pcap data from an array of bytes.
|
||||||
|
"""
|
||||||
|
mutable struct PcapBufferReader <: PcapReader
|
||||||
|
data::Vector{UInt8}
|
||||||
|
raw_header::Vector{UInt8}
|
||||||
|
header::PcapHeader
|
||||||
|
offset::Int64
|
||||||
|
mark::Int64
|
||||||
|
usec_mul::Int64
|
||||||
|
bswapped::Bool
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
PcapBufferReader(data::Vector{UInt8})
|
||||||
|
|
||||||
|
Create reader over `data`. Will read and process pcap header,
|
||||||
|
and yield records through `read(::PcapBufferReader)`.
|
||||||
|
"""
|
||||||
|
function PcapBufferReader(data::Vector{UInt8})
|
||||||
|
length(data) < sizeof(PcapHeader) && throw(EOFError())
|
||||||
|
rh = data[1:sizeof(PcapHeader)]
|
||||||
|
h = unsafe_load(Ptr{PcapHeader}(pointer(data)))
|
||||||
|
h, bswapped, nanotime = process_header(h)
|
||||||
|
new(data, rh, h, sizeof(h), -1, nanotime ? 1 : 1000, bswapped)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
"""
|
||||||
|
PcapBufferReader(path::AbstractString)
|
||||||
|
|
||||||
|
Memory map file in `path` and create PcapBufferReader over its content.
|
||||||
|
"""
|
||||||
|
function PcapBufferReader(path::AbstractString)
|
||||||
|
io = open(path)
|
||||||
|
data = Mmap.mmap(io)
|
||||||
|
PcapBufferReader(data)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Base.close(x::PcapBufferReader)
|
||||||
|
x.data = UInt8[]
|
||||||
|
x.offset = 0
|
||||||
|
nothing
|
||||||
|
end
|
||||||
|
|
||||||
|
Base.length(x::PcapBufferReader) = length(x.data)
|
||||||
|
Base.position(x::PcapBufferReader) = x.offset; nothing
|
||||||
|
Base.seek(x::PcapBufferReader, pos) = x.offset = pos; nothing
|
||||||
|
|
||||||
|
function Base.mark(x::PcapBufferReader)
|
||||||
|
x.mark = x.offset
|
||||||
|
x.mark
|
||||||
|
end
|
||||||
|
|
||||||
|
function Base.unmark(x::PcapBufferReader)
|
||||||
|
if x.mark >= 0
|
||||||
|
x.mark = -1
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Base.ismarked(x::PcapBufferReader) = x.mark >= 0
|
||||||
|
|
||||||
|
function Base.reset(x::PcapBufferReader)
|
||||||
|
!ismarked(x) && error("PcapBufferReader not marked")
|
||||||
|
x.offset = x.mark
|
||||||
|
x.mark = -1
|
||||||
|
x.offset
|
||||||
|
end
|
||||||
|
|
||||||
|
Base.eof(x::PcapBufferReader) = (length(x) - x.offset) < sizeof(RecordHeader)
|
||||||
|
|
||||||
|
"""
|
||||||
|
read(x::PcapBufferReader) -> PcapRecord
|
||||||
|
|
||||||
|
Read one record from pcap data.
|
||||||
|
Throws `EOFError` if no more data available.
|
||||||
|
"""
|
||||||
|
@inline function Base.read(x::PcapBufferReader)
|
||||||
|
eof(x) && throw(EOFError())
|
||||||
|
record_offset = x.offset
|
||||||
|
p = pointer(x.data) + record_offset
|
||||||
|
GC.@preserve x begin
|
||||||
|
h = unsafe_load(Ptr{RecordHeader}(p))
|
||||||
|
end
|
||||||
|
if x.bswapped
|
||||||
|
h = bswap(h)
|
||||||
|
end
|
||||||
|
t1 = (h.ts_sec + x.header.thiszone) * 1_000_000_000
|
||||||
|
t2 = Int64(h.ts_usec) * x.usec_mul
|
||||||
|
t = UnixTime(Dates.UTInstant(Nanosecond(t1 + t2)))
|
||||||
|
x.offset += sizeof(RecordHeader) + h.incl_len
|
||||||
|
x.offset > length(x) && error("Insufficient data in pcap record")
|
||||||
|
PcapRecord(h, t, x.data, record_offset)
|
||||||
|
end
|
46
scripts/packet-analysis/dev/PcapTools/src/pcap_header.jl
Normal file
46
scripts/packet-analysis/dev/PcapTools/src/pcap_header.jl
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# NOTE: Not using @enum because it craps out when displaying unknown values
|
||||||
|
const LINKTYPE_NULL = UInt32(0)
|
||||||
|
const LINKTYPE_ETHERNET = UInt32(1)
|
||||||
|
|
||||||
|
struct PcapHeader
|
||||||
|
magic::UInt32
|
||||||
|
version_major::UInt16
|
||||||
|
version_minor::UInt16
|
||||||
|
thiszone::Int32
|
||||||
|
sigfigs::UInt32
|
||||||
|
snaplen::UInt32
|
||||||
|
linktype::UInt32
|
||||||
|
end
|
||||||
|
|
||||||
|
function Base.bswap(x::PcapHeader)
|
||||||
|
PcapHeader(
|
||||||
|
bswap(x.magic),
|
||||||
|
bswap(x.version_major),
|
||||||
|
bswap(x.version_minor),
|
||||||
|
bswap(x.thiszone),
|
||||||
|
bswap(x.sigfigs),
|
||||||
|
bswap(x.snaplen),
|
||||||
|
bswap(x.linktype))
|
||||||
|
end
|
||||||
|
|
||||||
|
function process_header(x::PcapHeader)
|
||||||
|
if x.magic == 0xa1b2c3d4
|
||||||
|
bswapped = false
|
||||||
|
nanotime = false
|
||||||
|
elseif x.magic == 0xd4c3b2a1
|
||||||
|
bswapped = true
|
||||||
|
nanotime = false
|
||||||
|
elseif x.magic == 0xa1b23c4d
|
||||||
|
bswapped = false
|
||||||
|
nanotime = true
|
||||||
|
elseif x.magic == 0x4d3cb2a1
|
||||||
|
bswapped = true
|
||||||
|
nanotime = true
|
||||||
|
else
|
||||||
|
throw(ArgumentError("Invalid pcap header"))
|
||||||
|
end
|
||||||
|
if bswapped
|
||||||
|
x = bswap(x)
|
||||||
|
end
|
||||||
|
x, bswapped, nanotime
|
||||||
|
end
|
25
scripts/packet-analysis/dev/PcapTools/src/record.jl
Normal file
25
scripts/packet-analysis/dev/PcapTools/src/record.jl
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
"""
|
||||||
|
Record of pcap data
|
||||||
|
"""
|
||||||
|
struct PcapRecord
|
||||||
|
header::RecordHeader
|
||||||
|
timestamp::UnixTime
|
||||||
|
underlying_data::Vector{UInt8}
|
||||||
|
record_offset::Int
|
||||||
|
end
|
||||||
|
|
||||||
|
@inline function record_field_(x::PcapRecord, ::Val{:data})
|
||||||
|
offset = getfield(x, :record_offset) + sizeof(RecordHeader)
|
||||||
|
len = Int(getfield(x, :header).incl_len)
|
||||||
|
UnsafeArray{UInt8, 1}(pointer(getfield(x, :underlying_data)) + offset, (len,))
|
||||||
|
end
|
||||||
|
|
||||||
|
@inline function record_field_(x::PcapRecord, ::Val{:raw})
|
||||||
|
offset = getfield(x, :record_offset)
|
||||||
|
len = sizeof(RecordHeader) + getfield(x, :header).incl_len
|
||||||
|
UnsafeArray{UInt8, 1}(pointer(getfield(x, :underlying_data)) + offset, (len,))
|
||||||
|
end
|
||||||
|
|
||||||
|
@inline record_field_(x::PcapRecord, ::Val{f}) where {f} = getfield(x, f)
|
||||||
|
|
||||||
|
@inline Base.getproperty(x::PcapRecord, f::Symbol) = record_field_(x, Val(f))
|
14
scripts/packet-analysis/dev/PcapTools/src/record_header.jl
Normal file
14
scripts/packet-analysis/dev/PcapTools/src/record_header.jl
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
struct RecordHeader
|
||||||
|
ts_sec::UInt32
|
||||||
|
ts_usec::UInt32
|
||||||
|
incl_len::UInt32
|
||||||
|
orig_len::UInt32
|
||||||
|
end
|
||||||
|
|
||||||
|
function Base.bswap(x::RecordHeader)
|
||||||
|
RecordHeader(
|
||||||
|
bswap(x.ts_sec),
|
||||||
|
bswap(x.ts_usec),
|
||||||
|
bswap(x.incl_len),
|
||||||
|
bswap(x.orig_len))
|
||||||
|
end
|
102
scripts/packet-analysis/dev/PcapTools/src/splitcap.jl
Normal file
102
scripts/packet-analysis/dev/PcapTools/src/splitcap.jl
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
strip_nothing_(::Type{Union{Nothing, T}}) where T = T
|
||||||
|
strip_nothing_(::Type{T}) where T = T
|
||||||
|
|
||||||
|
progress_noop_(n) = nothing
|
||||||
|
|
||||||
|
mutable struct SplitCapOutput{S}
|
||||||
|
work_buffer::Vector{UInt8}
|
||||||
|
complete_buffers::Channel{Vector{UInt8}}
|
||||||
|
stream::S
|
||||||
|
end
|
||||||
|
|
||||||
|
# Since Julia (as of 1.5) doesn't support task migration,
|
||||||
|
# continue with new task after each buffer write, to rebalance across threads
|
||||||
|
function write_one_and_continue_(output::SplitCapOutput, free_buffers::Channel, pending::Threads.Atomic{Int})
|
||||||
|
i = iterate(output.complete_buffers)
|
||||||
|
if i === nothing
|
||||||
|
Threads.atomic_sub!(pending, 1)
|
||||||
|
return nothing
|
||||||
|
end
|
||||||
|
b, _ = i
|
||||||
|
write(output.stream, b)
|
||||||
|
empty!(b)
|
||||||
|
put!(free_buffers, b)
|
||||||
|
Threads.@spawn write_one_and_continue_($output, $free_buffers, $pending)
|
||||||
|
end
|
||||||
|
|
||||||
|
function splitcap(
|
||||||
|
::Type{KeyType},
|
||||||
|
::Type{StreamType},
|
||||||
|
reader::PcapReader,
|
||||||
|
record2key,
|
||||||
|
key2stream,
|
||||||
|
progress_callback = progress_noop_;
|
||||||
|
own_streams::Bool = true
|
||||||
|
) where {KeyType, StreamType}
|
||||||
|
buffer_size = 1024 * 1024 * 2
|
||||||
|
max_pending_buffers = 4
|
||||||
|
outputs = Dict{KeyType, SplitCapOutput{StreamType}}()
|
||||||
|
free_buffers = Channel{Vector{UInt8}}(Inf)
|
||||||
|
n = 0
|
||||||
|
pending = Threads.Atomic{Int}(0)
|
||||||
|
try
|
||||||
|
while !eof(reader)
|
||||||
|
record = read(reader)
|
||||||
|
dst = record2key(record)
|
||||||
|
if dst isa KeyType
|
||||||
|
output = get!(outputs, dst) do
|
||||||
|
stream = key2stream(dst)
|
||||||
|
buffer = sizehint!(UInt8[], buffer_size + 1500)
|
||||||
|
own_streams && append!(buffer, reader.raw_header)
|
||||||
|
output = SplitCapOutput{StreamType}(
|
||||||
|
buffer,
|
||||||
|
Channel{Vector{UInt8}}(max_pending_buffers),
|
||||||
|
stream)
|
||||||
|
Threads.atomic_add!(pending, 1)
|
||||||
|
Threads.@spawn write_one_and_continue_($output, $free_buffers, $pending)
|
||||||
|
output
|
||||||
|
end
|
||||||
|
append!(output.work_buffer, record.raw)
|
||||||
|
if length(output.work_buffer) >= buffer_size
|
||||||
|
put!(output.complete_buffers, output.work_buffer)
|
||||||
|
if isready(free_buffers)
|
||||||
|
output.work_buffer = take!(free_buffers)
|
||||||
|
else
|
||||||
|
output.work_buffer = sizehint!(UInt8[], buffer_size + 1500)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
n += 1
|
||||||
|
progress_callback(n)
|
||||||
|
GC.safepoint()
|
||||||
|
end
|
||||||
|
for output in values(outputs)
|
||||||
|
if !isempty(output.work_buffer)
|
||||||
|
put!(output.complete_buffers, output.work_buffer)
|
||||||
|
end
|
||||||
|
close(output.complete_buffers)
|
||||||
|
end
|
||||||
|
while pending[] != 0
|
||||||
|
sleep(0.1)
|
||||||
|
end
|
||||||
|
finally
|
||||||
|
if own_streams
|
||||||
|
for output in values(outputs)
|
||||||
|
close(output.stream)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
nothing
|
||||||
|
end
|
||||||
|
|
||||||
|
function splitcap(
|
||||||
|
reader::PcapReader,
|
||||||
|
record2key,
|
||||||
|
key2stream,
|
||||||
|
progress_callback = progress_noop_;
|
||||||
|
kwargs...
|
||||||
|
)
|
||||||
|
KeyType = strip_nothing_(Core.Compiler.return_type(record2key, Tuple{PcapRecord}))
|
||||||
|
StreamType = Core.Compiler.return_type(key2stream, Tuple{KeyType})
|
||||||
|
splitcap(KeyType, StreamType, reader, record2key, key2stream, progress_callback; kwargs...)
|
||||||
|
end
|
63
scripts/packet-analysis/dev/PcapTools/src/stream_reader.jl
Normal file
63
scripts/packet-analysis/dev/PcapTools/src/stream_reader.jl
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
"""
|
||||||
|
Reads pcap data from a stream.
|
||||||
|
"""
|
||||||
|
mutable struct PcapStreamReader{Src <: IO} <: PcapReader
|
||||||
|
src::Src
|
||||||
|
raw_header::Vector{UInt8}
|
||||||
|
header::PcapHeader
|
||||||
|
usec_mul::Int64
|
||||||
|
bswapped::Bool
|
||||||
|
record_buffer::Vector{UInt8}
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
PcapStreamReader(src::IO)
|
||||||
|
|
||||||
|
Create reader over `src`. Will read and process pcap header,
|
||||||
|
and yield records through `read(::PcapStreamReader)`.
|
||||||
|
"""
|
||||||
|
function PcapStreamReader(src::Src) where {Src <: IO}
|
||||||
|
raw_header = read(src, sizeof(PcapHeader))
|
||||||
|
length(raw_header) != sizeof(PcapHeader) && throw(EOFError())
|
||||||
|
h = GC.@preserve raw_header unsafe_load(Ptr{PcapHeader}(pointer(raw_header)))
|
||||||
|
header, bswapped, nanotime = process_header(h)
|
||||||
|
new{Src}(src, raw_header, header, nanotime ? 1 : 1000, bswapped, zeros(UInt8, 9000 + sizeof(RecordHeader)))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
"""
|
||||||
|
PcapStreamReader(path)
|
||||||
|
|
||||||
|
Open file at `path` and create PcapStreamReader over its content.
|
||||||
|
"""
|
||||||
|
PcapStreamReader(path::AbstractString) = PcapStreamReader(open(path))
|
||||||
|
|
||||||
|
Base.close(x::PcapStreamReader) = close(x.src)
|
||||||
|
Base.position(x::PcapStreamReader) = position(x.src)
|
||||||
|
Base.seek(x::PcapStreamReader, pos) = seek(x.src, pos)
|
||||||
|
Base.mark(x::PcapStreamReader) = mark(x.src)
|
||||||
|
Base.unmark(x::PcapStreamReader) = unmark(x.src)
|
||||||
|
Base.ismarked(x::PcapStreamReader) = ismarked(x.src)
|
||||||
|
Base.reset(x::PcapStreamReader) = reset(x.src)
|
||||||
|
Base.eof(x::PcapStreamReader) = eof(x.src)
|
||||||
|
|
||||||
|
"""
|
||||||
|
read(x::PcapStreamReader) -> PcapRecord
|
||||||
|
|
||||||
|
Read one record from pcap data. Record is valid until next read().
|
||||||
|
Throws `EOFError` if no more data available.
|
||||||
|
"""
|
||||||
|
function Base.read(x::PcapStreamReader)
|
||||||
|
p = pointer(x.record_buffer)
|
||||||
|
GC.@preserve x begin
|
||||||
|
unsafe_read(x.src, p, sizeof(RecordHeader))
|
||||||
|
h = unsafe_load(Ptr{RecordHeader}(p))
|
||||||
|
if x.bswapped
|
||||||
|
h = bswap(h)
|
||||||
|
end
|
||||||
|
unsafe_read(x.src, p + sizeof(RecordHeader), h.incl_len)
|
||||||
|
end
|
||||||
|
t1 = (h.ts_sec + x.header.thiszone) * 1_000_000_000
|
||||||
|
t2 = Int64(h.ts_usec) * x.usec_mul
|
||||||
|
t = UnixTime(Dates.UTInstant(Nanosecond(t1 + t2)))
|
||||||
|
PcapRecord(h, t, x.record_buffer, 0)
|
||||||
|
end
|
30
scripts/packet-analysis/dev/PcapTools/src/stream_writer.jl
Normal file
30
scripts/packet-analysis/dev/PcapTools/src/stream_writer.jl
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
struct PcapStreamWriter{Dst <: IO} <: PcapWriter
|
||||||
|
dst::Dst
|
||||||
|
|
||||||
|
function PcapStreamWriter{Dst}(dst::Dst; thiszone = 0, snaplen = 65535, linktype = LINKTYPE_ETHERNET) where {Dst <: IO}
|
||||||
|
h = PcapHeader(
|
||||||
|
0xa1b23c4d,
|
||||||
|
0x0002,
|
||||||
|
0x0004,
|
||||||
|
thiszone,
|
||||||
|
0,
|
||||||
|
snaplen,
|
||||||
|
linktype)
|
||||||
|
write(dst, reinterpret(UInt8, [h]))
|
||||||
|
new(dst)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
PcapStreamWriter(io::IO; kwargs...) = PcapStreamWriter{typeof(io)}(io; kwargs...)
|
||||||
|
PcapStreamWriter(path::AbstractString; kwargs...) = PcapStreamWriter(open(path, "w"); kwargs...)
|
||||||
|
|
||||||
|
Base.close(x::PcapStreamWriter) = close(x.dst)
|
||||||
|
|
||||||
|
function Base.write(x::PcapStreamWriter, timestamp::UnixTime, data)
|
||||||
|
sec, nsec = fldmod(Dates.value(timestamp), 1_000_000_000)
|
||||||
|
data_length = length(data)
|
||||||
|
h = RecordHeader(sec, nsec, data_length, data_length)
|
||||||
|
write(x.dst, reinterpret(UInt8, [h]))
|
||||||
|
write(x.dst, collect(data))
|
||||||
|
nothing
|
||||||
|
end
|
BIN
scripts/packet-analysis/msgdumps/CQ-TS7471LC_bootup.pcap
Normal file
BIN
scripts/packet-analysis/msgdumps/CQ-TS7471LC_bootup.pcap
Normal file
Binary file not shown.
BIN
scripts/packet-analysis/msgdumps/amp-settings.pcapng
Normal file
BIN
scripts/packet-analysis/msgdumps/amp-settings.pcapng
Normal file
Binary file not shown.
BIN
scripts/packet-analysis/msgdumps/avclan.pcap
Normal file
BIN
scripts/packet-analysis/msgdumps/avclan.pcap
Normal file
Binary file not shown.
Binary file not shown.
BIN
scripts/packet-analysis/msgdumps/initial-bus-scan.pcap
Normal file
BIN
scripts/packet-analysis/msgdumps/initial-bus-scan.pcap
Normal file
Binary file not shown.
BIN
scripts/packet-analysis/msgdumps/lan-test-bus-scan.pcap
Normal file
BIN
scripts/packet-analysis/msgdumps/lan-test-bus-scan.pcap
Normal file
Binary file not shown.
BIN
scripts/packet-analysis/msgdumps/startup.pcapng
Normal file
BIN
scripts/packet-analysis/msgdumps/startup.pcapng
Normal file
Binary file not shown.
Binary file not shown.
73
scripts/packet-analysis/src/AVCLANPipe.jl
Normal file
73
scripts/packet-analysis/src/AVCLANPipe.jl
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
module AVCLANPipe
|
||||||
|
|
||||||
|
using PcapTools, Dates, UnixTimes
|
||||||
|
|
||||||
|
export AVCLANframe, avclan_text_to_pcap, tobytes
|
||||||
|
|
||||||
|
mutable struct AVCLANframe
|
||||||
|
broadcast::Bool
|
||||||
|
controller_addr::UInt16
|
||||||
|
peripheral_addr::UInt16
|
||||||
|
control::UInt8
|
||||||
|
length::UInt8
|
||||||
|
data::NTuple{32,UInt8}
|
||||||
|
end
|
||||||
|
|
||||||
|
AVCLANframe() = AVCLANframe(false, 0x0000, 0x0000, 0xf, 0x0, ntuple(x -> 0x0, 32))
|
||||||
|
|
||||||
|
function Base.tryparse(::Type{AVCLANframe}, str::String)
|
||||||
|
vals = split(str)
|
||||||
|
|
||||||
|
broadcast = tryparse(Bool, vals[1])
|
||||||
|
isnothing(broadcast) && return nothing
|
||||||
|
|
||||||
|
controller_addr = tryparse(UInt16, vals[2])
|
||||||
|
isnothing(controller_addr) && return nothing
|
||||||
|
|
||||||
|
peripheral_addr = tryparse(UInt16, vals[3])
|
||||||
|
isnothing(peripheral_addr) && return nothing
|
||||||
|
|
||||||
|
control = tryparse(UInt8, vals[4])
|
||||||
|
isnothing(control) && return nothing
|
||||||
|
|
||||||
|
len = tryparse(UInt8, vals[5])
|
||||||
|
isnothing(len) && return nothing
|
||||||
|
|
||||||
|
if (length(vals) - 5) != len || len > 32
|
||||||
|
return nothing
|
||||||
|
end
|
||||||
|
_data = tryparse.(UInt8, vals[6:end])
|
||||||
|
data = ntuple(i -> checkindex(Bool, axes(_data, 1), i) ? _data[i] : 0x0, 32)
|
||||||
|
|
||||||
|
return AVCLANframe(broadcast, controller_addr, peripheral_addr, control, len, data)
|
||||||
|
end
|
||||||
|
|
||||||
|
function tobytes(frame::AVCLANframe)
|
||||||
|
data = Vector{UInt8}(undef, 0)
|
||||||
|
push!(data, frame.broadcast)
|
||||||
|
append!(data, reverse(reinterpret(reshape, UInt8, [frame.controller_addr])),
|
||||||
|
reverse(reinterpret(reshape, UInt8, [frame.peripheral_addr])),
|
||||||
|
reinterpret(reshape, UInt8, [frame.control]),
|
||||||
|
reinterpret(reshape, UInt8, [frame.length]),
|
||||||
|
frame.data[1:frame.length])
|
||||||
|
|
||||||
|
return data
|
||||||
|
end
|
||||||
|
|
||||||
|
function avclan_text_to_pcap(textlog::String, pcap_fn::String)
|
||||||
|
pcapstream = PcapStreamWriter(pcap_fn; snaplen=64, linktype = 162)
|
||||||
|
t = UnixTime(now())
|
||||||
|
|
||||||
|
for line in eachline(textlog)
|
||||||
|
frame = tryparse(AVCLANframe, line)
|
||||||
|
t += Microsecond(rand(1:15))
|
||||||
|
if !isnothing(frame)
|
||||||
|
write(pcapstream, t, tobytes(frame))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
close(pcapstream)
|
||||||
|
|
||||||
|
return pcap_fn
|
||||||
|
end
|
||||||
|
|
||||||
|
end # module AVCLANPipe
|
55
scripts/packet-analysis/src/convert-sr-annotation-export.jl
Normal file
55
scripts/packet-analysis/src/convert-sr-annotation-export.jl
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
using AVCLANPipe, PcapTools, Dates, UnixTimes
|
||||||
|
|
||||||
|
file = ARGS[1]
|
||||||
|
outfile = ARGS[2]
|
||||||
|
|
||||||
|
function convert_fields_to_pcap(file, outfile)
|
||||||
|
|
||||||
|
io = open(file, "r")
|
||||||
|
outio = PcapStreamWriter(outfile; snaplen=64, linktype = 162)
|
||||||
|
|
||||||
|
packet = AVCLANframe()
|
||||||
|
packetcomplete = false
|
||||||
|
local t::UnixTime
|
||||||
|
i = 1
|
||||||
|
|
||||||
|
for line in readlines(io)
|
||||||
|
m = match(r"(\d+)-(\d+) IEBus: Raw Fields: (?<field>\w+)(:? ((?<hex>0x[0-9a-f]{2,3})|WRITE_DATA|Length: (?<length>\d+)))?",
|
||||||
|
line)
|
||||||
|
|
||||||
|
if m[:field] == "Broadcast"
|
||||||
|
packet.broadcast = true
|
||||||
|
t = UnixTime(1970,1,1,0,0,0,0, something(tryparse(Int, m[1]), 0))
|
||||||
|
elseif m[:field] == "Unicast"
|
||||||
|
packet.broadcast = false
|
||||||
|
t = UnixTime(1970,1,1,0,0,0,0, something(tryparse(Int, m[1]), 0))
|
||||||
|
elseif m[:field] == "Master"
|
||||||
|
packet.controller_addr = tryparse(UInt16, m[:hex])
|
||||||
|
elseif m[:field] == "Slave"
|
||||||
|
packet.peripheral_addr = tryparse(UInt16, m[:hex])
|
||||||
|
elseif m[:field] == "Data"
|
||||||
|
if !isnothing(m[:length])
|
||||||
|
packet.length = convert(UInt8, tryparse(Int, m[:length]))
|
||||||
|
else
|
||||||
|
data = collect(packet.data)
|
||||||
|
data[i] = tryparse(UInt8, m[:hex])
|
||||||
|
packet.data = ntuple(n -> data[n], 32)
|
||||||
|
i += 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if i > packet.length
|
||||||
|
packetcomplete = true
|
||||||
|
end
|
||||||
|
|
||||||
|
if packetcomplete
|
||||||
|
packetcomplete = false
|
||||||
|
i = 1
|
||||||
|
write(outio, t, tobytes(packet))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
close(io)
|
||||||
|
close(outio)
|
||||||
|
|
||||||
|
end
|
45
scripts/packet-analysis/src/pipepackets.jl
Normal file
45
scripts/packet-analysis/src/pipepackets.jl
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
include("AVCLANPipe.jl")
|
||||||
|
|
||||||
|
using .AVCLANPipe, PcapTools, Dates, UnixTimes, LibSerialPort
|
||||||
|
|
||||||
|
serial_port="/dev/ttyUSB0"
|
||||||
|
baud=1200000
|
||||||
|
|
||||||
|
pcapstream = PcapStreamWriter(stdout; snaplen=64, linktype=162)
|
||||||
|
serial = LibSerialPort.open(serial_port, baud)
|
||||||
|
set_flow_control(serial) # Disable flow-control (stops it from eating raw byte 0x11)
|
||||||
|
|
||||||
|
write(serial, 'X')
|
||||||
|
buf = IOBuffer()
|
||||||
|
|
||||||
|
function quit(serialio=serial)
|
||||||
|
close(serialio)
|
||||||
|
exit()
|
||||||
|
end
|
||||||
|
|
||||||
|
while true
|
||||||
|
iswritable(stdout) || isopen(stdout) || quit()
|
||||||
|
if bytesavailable(serial) > 0
|
||||||
|
t = UnixTime(now())
|
||||||
|
line = readline(serial)
|
||||||
|
# allthebytes = Vector{UInt8}(undef, bytesavailable(serial))
|
||||||
|
# readbytes!(serial, allthebytes)
|
||||||
|
# write(buf, allthebytes)
|
||||||
|
# l = findfirst(==('\n'), buf.data)
|
||||||
|
# if !isnothing(l)
|
||||||
|
# println(stderr, "fucku")
|
||||||
|
# bytes = Vector{UInt8}(undef, l)
|
||||||
|
# seekstart(buf)
|
||||||
|
# readbytes!(buf, bytes)
|
||||||
|
# seekend(buf)
|
||||||
|
bytes = Vector{UInt8}(line)
|
||||||
|
if bytes[1] == 0x10 && bytes[end] == 0x17
|
||||||
|
write(pcapstream, t, bytes[2:end-1])
|
||||||
|
else
|
||||||
|
@error line
|
||||||
|
end
|
||||||
|
# end
|
||||||
|
# println(stderr, "wtf")
|
||||||
|
end
|
||||||
|
yield()
|
||||||
|
end
|
Loading…
x
Reference in New Issue
Block a user