Update vhost-device-can and align it with rust-vmm implementation 31/30331/4
authorTimos Ampelikiotis <t.ampelikiotis@virtualopensystems.com>
Thu, 3 Oct 2024 08:00:30 +0000 (11:00 +0300)
committerJan-Simon Moeller <jsmoeller@linuxfoundation.org>
Thu, 7 Nov 2024 16:40:10 +0000 (16:40 +0000)
[v2]:
Remove recipe for socketcan-rs lib. Update vhost-device-can recipe
to clone and be built with a selected version of socketcan-rs.

[v1]:
Update vhost-device-can device and align it with the
vhost-device upstream implementation (commit: 42fa1204ec)
- https://github.com/rust-vmm/vhost-device/tree/main/staging/vhost-device-can

Bug-AGL: SPEC-4966
Change-Id: I9b7f5cb5d84c77198bc0c8b8cebc256fb5df6926
Signed-off-by: Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com>
20 files changed:
meta-egvirt/recipes-extended/vhost-device-can/files/vhost-device-can-0.1.0/CHANGELOG.md [moved from meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/CHANGELOG.md with 74% similarity, mode: 0755]
meta-egvirt/recipes-extended/vhost-device-can/files/vhost-device-can-0.1.0/Cargo.lock [new file with mode: 0755]
meta-egvirt/recipes-extended/vhost-device-can/files/vhost-device-can-0.1.0/Cargo.toml [new file with mode: 0755]
meta-egvirt/recipes-extended/vhost-device-can/files/vhost-device-can-0.1.0/LICENSE-APACHE [moved from meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/LICENSE-APACHE with 100% similarity, mode: 0755]
meta-egvirt/recipes-extended/vhost-device-can/files/vhost-device-can-0.1.0/LICENSE-BSD-3-Clause [moved from meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/LICENSE-BSD-3-Clause with 100% similarity, mode: 0755]
meta-egvirt/recipes-extended/vhost-device-can/files/vhost-device-can-0.1.0/README.md [new file with mode: 0755]
meta-egvirt/recipes-extended/vhost-device-can/files/vhost-device-can-0.1.0/src/backend.rs [new file with mode: 0755]
meta-egvirt/recipes-extended/vhost-device-can/files/vhost-device-can-0.1.0/src/can.rs [new file with mode: 0755]
meta-egvirt/recipes-extended/vhost-device-can/files/vhost-device-can-0.1.0/src/main.rs [new file with mode: 0755]
meta-egvirt/recipes-extended/vhost-device-can/files/vhost-device-can-0.1.0/src/vhu_can.rs [new file with mode: 0755]
meta-egvirt/recipes-extended/vhost-device-can/files/vhost-device-can-0.1.0/src/virtio_can.rs [new file with mode: 0755]
meta-egvirt/recipes-extended/vhost-device-can/socketcan-crates.inc [new file with mode: 0755]
meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/Cargo.toml [deleted file]
meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/README.md [deleted file]
meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/src/backend.rs [deleted file]
meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/src/can.rs [deleted file]
meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/src/main.rs [deleted file]
meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/src/vhu_can.rs [deleted file]
meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-crates.inc
meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can_0.1.0.bb

diff --git a/meta-egvirt/recipes-extended/vhost-device-can/files/vhost-device-can-0.1.0/Cargo.lock b/meta-egvirt/recipes-extended/vhost-device-can/files/vhost-device-can-0.1.0/Cargo.lock
new file mode 100755 (executable)
index 0000000..50985ab
--- /dev/null
@@ -0,0 +1,1049 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "anstream"
+version = "0.6.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
+
+[[package]]
+name = "anstyle-parse"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a"
+dependencies = [
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8"
+dependencies = [
+ "anstyle",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.86"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
+
+[[package]]
+name = "arc-swap"
+version = "1.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
+
+[[package]]
+name = "assert_matches"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9"
+
+[[package]]
+name = "autocfg"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bitflags"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
+
+[[package]]
+name = "byte_conv"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "649972315d4931137a26fc2bf3ca95ee257ad796a5b57bdeb04205c91a4b5780"
+
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "clap"
+version = "4.5.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019"
+dependencies = [
+ "clap_builder",
+ "clap_derive",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.5.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "clap_lex",
+ "strsim",
+]
+
+[[package]]
+name = "clap_derive"
+version = "4.5.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.72",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
+
+[[package]]
+name = "colorchoice"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
+
+[[package]]
+name = "either"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
+
+[[package]]
+name = "embedded-can"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e9d2e857f87ac832df68fa498d18ddc679175cf3d2e4aa893988e5601baf9438"
+dependencies = [
+ "nb",
+]
+
+[[package]]
+name = "enumn"
+version = "0.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.72",
+]
+
+[[package]]
+name = "env_filter"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab"
+dependencies = [
+ "log",
+ "regex",
+]
+
+[[package]]
+name = "env_logger"
+version = "0.11.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "env_filter",
+ "humantime",
+ "log",
+]
+
+[[package]]
+name = "epoll"
+version = "4.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74351c3392ea1ff6cd2628e0042d268ac2371cb613252ff383b6dfa50d22fa79"
+dependencies = [
+ "bitflags 2.6.0",
+ "libc",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
+name = "errno"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
+dependencies = [
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "fastrand"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
+
+[[package]]
+name = "futures"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
+
+[[package]]
+name = "futures-executor"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "futures-util",
+ "num_cpus",
+]
+
+[[package]]
+name = "futures-io"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
+
+[[package]]
+name = "futures-macro"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.72",
+]
+
+[[package]]
+name = "futures-sink"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
+
+[[package]]
+name = "futures-task"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
+
+[[package]]
+name = "futures-timer"
+version = "3.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24"
+
+[[package]]
+name = "futures-util"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-macro",
+ "futures-sink",
+ "futures-task",
+ "memchr",
+ "pin-project-lite",
+ "pin-utils",
+ "slab",
+]
+
+[[package]]
+name = "glob"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
+
+[[package]]
+name = "hashbrown"
+version = "0.14.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "hermit-abi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
+
+[[package]]
+name = "hex"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+
+[[package]]
+name = "humantime"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
+
+[[package]]
+name = "indexmap"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
+
+[[package]]
+name = "itertools"
+version = "0.10.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.158"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
+
+[[package]]
+name = "log"
+version = "0.4.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
+
+[[package]]
+name = "memchr"
+version = "2.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+
+[[package]]
+name = "memoffset"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "nb"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d"
+
+[[package]]
+name = "neli"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1100229e06604150b3becd61a4965d5c70f3be1759544ea7274166f4be41ef43"
+dependencies = [
+ "byteorder",
+ "libc",
+ "log",
+ "neli-proc-macros",
+]
+
+[[package]]
+name = "neli-proc-macros"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c168194d373b1e134786274020dae7fc5513d565ea2ebb9bc9ff17ffb69106d4"
+dependencies = [
+ "either",
+ "proc-macro2",
+ "quote",
+ "serde",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "nix"
+version = "0.26.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b"
+dependencies = [
+ "bitflags 1.3.2",
+ "cfg-if",
+ "libc",
+ "memoffset",
+ "pin-utils",
+]
+
+[[package]]
+name = "nix"
+version = "0.27.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
+dependencies = [
+ "bitflags 2.6.0",
+ "cfg-if",
+ "libc",
+]
+
+[[package]]
+name = "num_cpus"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
+dependencies = [
+ "hermit-abi",
+ "libc",
+]
+
+[[package]]
+name = "num_enum"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179"
+dependencies = [
+ "num_enum_derive",
+]
+
+[[package]]
+name = "num_enum_derive"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.72",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
+
+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
+[[package]]
+name = "proc-macro-crate"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284"
+dependencies = [
+ "toml_edit",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.86"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "queues"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1475abae4f8ad4998590fe3acfe20104f0a5d48fc420c817cd2c09c3f56151f0"
+
+[[package]]
+name = "quote"
+version = "1.0.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "regex"
+version = "1.10.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
+
+[[package]]
+name = "relative-path"
+version = "1.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2"
+
+[[package]]
+name = "rstest"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b423f0e62bdd61734b67cd21ff50871dfaeb9cc74f869dcd6af974fbcb19936"
+dependencies = [
+ "futures",
+ "futures-timer",
+ "rstest_macros",
+ "rustc_version",
+]
+
+[[package]]
+name = "rstest_macros"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c5e1711e7d14f74b12a58411c542185ef7fb7f2e7f8ee6e2940a883628522b42"
+dependencies = [
+ "cfg-if",
+ "glob",
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "relative-path",
+ "rustc_version",
+ "syn 2.0.72",
+ "unicode-ident",
+]
+
+[[package]]
+name = "rustc_version"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
+dependencies = [
+ "semver",
+]
+
+[[package]]
+name = "rustix"
+version = "0.38.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
+dependencies = [
+ "bitflags 2.6.0",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "semver"
+version = "1.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
+
+[[package]]
+name = "serde"
+version = "1.0.209"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.209"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.72",
+]
+
+[[package]]
+name = "slab"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "socket2"
+version = "0.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
+dependencies = [
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "socketcan"
+version = "3.4.0-pre.0"
+source = "git+https://github.com/socketcan-rs/socketcan-rs.git?rev=f004ee91e142a37fea36c5d719a57852c7076e87#f004ee91e142a37fea36c5d719a57852c7076e87"
+dependencies = [
+ "bitflags 1.3.2",
+ "byte_conv",
+ "embedded-can",
+ "hex",
+ "itertools",
+ "libc",
+ "log",
+ "nb",
+ "neli",
+ "nix 0.26.4",
+ "socket2",
+ "thiserror",
+]
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.72"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64"
+dependencies = [
+ "cfg-if",
+ "fastrand",
+ "once_cell",
+ "rustix",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "thiserror"
+version = "1.0.63"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.63"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.72",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
+
+[[package]]
+name = "toml_edit"
+version = "0.21.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1"
+dependencies = [
+ "indexmap",
+ "toml_datetime",
+ "winnow",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+
+[[package]]
+name = "utf8parse"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+
+[[package]]
+name = "v4l2r"
+version = "0.0.1"
+source = "git+https://github.com/Gnurou/v4l2r?rev=110fd77#110fd773d15c787cbc6c2ded1bf8459c8df89f72"
+dependencies = [
+ "anyhow",
+ "bitflags 2.6.0",
+ "enumn",
+ "log",
+ "nix 0.27.1",
+ "thiserror",
+]
+
+[[package]]
+name = "vhost"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6be08d1166d41a78861ad50212ab3f9eca0729c349ac3a7a8f557c62406b87cc"
+dependencies = [
+ "bitflags 2.6.0",
+ "libc",
+ "vm-memory",
+ "vmm-sys-util",
+]
+
+[[package]]
+name = "vhost-device-can"
+version = "0.1.0"
+dependencies = [
+ "assert_matches",
+ "clap",
+ "env_logger",
+ "log",
+ "queues",
+ "socketcan",
+ "thiserror",
+ "vhost",
+ "vhost-user-backend",
+ "virtio-bindings",
+ "virtio-queue",
+ "vm-memory",
+ "vmm-sys-util",
+]
+
+[[package]]
+name = "vhost-device-video"
+version = "0.1.0"
+dependencies = [
+ "assert_matches",
+ "bitflags 2.6.0",
+ "clap",
+ "env_logger",
+ "epoll",
+ "futures-executor",
+ "libc",
+ "log",
+ "num_enum",
+ "rstest",
+ "tempfile",
+ "thiserror",
+ "v4l2r",
+ "vhost",
+ "vhost-user-backend",
+ "virtio-bindings",
+ "virtio-queue",
+ "vm-memory",
+ "vmm-sys-util",
+]
+
+[[package]]
+name = "vhost-user-backend"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f0ffb1dd8e00a708a0e2c32d5efec5812953819888591fff9ff68236b8a5096"
+dependencies = [
+ "libc",
+ "log",
+ "vhost",
+ "virtio-bindings",
+ "virtio-queue",
+ "vm-memory",
+ "vmm-sys-util",
+]
+
+[[package]]
+name = "virtio-bindings"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "878bcb1b2812a10c30d53b0ed054999de3d98f25ece91fc173973f9c57aaae86"
+
+[[package]]
+name = "virtio-queue"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07d8406e7250c934462de585d8f2d2781c31819bca1fbb7c5e964ca6bbaabfe8"
+dependencies = [
+ "log",
+ "virtio-bindings",
+ "vm-memory",
+ "vmm-sys-util",
+]
+
+[[package]]
+name = "vm-memory"
+version = "0.14.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c3aba5064cc5f6f7740cddc8dae34d2d9a311cac69b60d942af7f3ab8fc49f4"
+dependencies = [
+ "arc-swap",
+ "bitflags 2.6.0",
+ "libc",
+ "thiserror",
+ "vmm-sys-util",
+ "winapi",
+]
+
+[[package]]
+name = "vmm-sys-util"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d1435039746e20da4f8d507a72ee1b916f7b4b05af7a91c093d2c6561934ede"
+dependencies = [
+ "bitflags 1.3.2",
+ "libc",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "winnow"
+version = "0.5.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
+dependencies = [
+ "memchr",
+]
diff --git a/meta-egvirt/recipes-extended/vhost-device-can/files/vhost-device-can-0.1.0/Cargo.toml b/meta-egvirt/recipes-extended/vhost-device-can/files/vhost-device-can-0.1.0/Cargo.toml
new file mode 100755 (executable)
index 0000000..5890f7e
--- /dev/null
@@ -0,0 +1,41 @@
+[package]
+name = "vhost-device-can"
+version = "0.1.0"
+authors = ["Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com>"]
+description = "vhost can backend device"
+repository = "https://github.com/rust-vmm/vhost-device"
+readme = "README.md"
+keywords = ["can", "vhost", "virt", "backend"]
+license = "Apache-2.0 OR BSD-3-Clause"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[features]
+xen = ["vm-memory/xen", "vhost/xen", "vhost-user-backend/xen"]
+
+[dependencies]
+clap = { version = "4.5",  features = ["derive"] }
+env_logger = "0.11"
+log = "0.4"
+thiserror = "1.0"
+queues = "1.0.2"
+# TODO: Update socketcan to version "v3.4.0" when this is released.
+# Socketcan "v3.3.0" includes the following issue: https://github.com/socketcan-rs/socketcan-rs/pull/61.
+# The version was set to the commit "f004ee91e142a" where that issue has been resolved. As soon as, a
+# newer version is released we need to point socketcan dependency to it.
+# NOTE: If you are using rust version "1.80", the compiler might complain about "std::mem::size_of".
+# The solution to that problem is described in the following link:
+# - https://github.com/socketcan-rs/socketcan-rs/pull/72
+socketcan = { path = "../git/" }
+vhost = { version = "0.11", features = ["vhost-user-backend"] }
+vhost-user-backend = { version = "0.15" }
+virtio-bindings = "0.2.2"
+virtio-queue = "0.12"
+vm-memory = "0.14.1"
+vmm-sys-util = "0.12"
+
+[dev-dependencies]
+assert_matches = "1.5"
+virtio-queue = { version = "0.12", features = ["test-utils"] }
+vm-memory = { version = "0.14.1", features = ["backend-mmap", "backend-atomic"] }
diff --git a/meta-egvirt/recipes-extended/vhost-device-can/files/vhost-device-can-0.1.0/README.md b/meta-egvirt/recipes-extended/vhost-device-can/files/vhost-device-can-0.1.0/README.md
new file mode 100755 (executable)
index 0000000..ade7912
--- /dev/null
@@ -0,0 +1,147 @@
+# vhost-device-can - CAN emulation backend daemon
+
+## Description
+This program is a vhost-user backend that emulates a VirtIO CAN device.
+The device's binary takes two (2) parameters:  a socket, a 'can-devices' list.
+The socket is commonly used across all vhost-devices to communicate with
+the vhost-user frontend device. The 'can-devices' represents a list of
+CAN/FD devices appears in the host system which vhost-device-can will 
+forward messages to and from the frontend side.
+
+This program is tested with QEMU's `vhost-user-device-pci` device.
+Examples' section below.
+
+## Synopsis
+```
+**vhost-device-can** [*OPTIONS*]
+````
+
+## Options
+
+.. program:: vhost-device-can
+
+.. option:: -h, --help
+
+  Print help.
+
+.. option:: -s, --socket-path=PATH
+
+  Location of vhost-user Unix domain sockets, this path will be suffixed with
+  0,1,2..socket_count-1.
+
+.. option:: -c, --socket-count=INT
+
+  Number of guests (sockets) to attach to, default set to 1.
+
+.. option:: -d, --can-devices='CAN/FD interfaces'
+
+  CAN/FD device list at the host OS in the format:
+      <can-_X_0> [<can_in_X_1>] ... [<can_in_X_N-1>]
+
+  Note 1: Where N (the number of CAN/FD interfaces) is equal with the number
+          provided via *socket_count* parameter.
+
+      Example: --can-devices "can0 can1 can2"
+
+## Features
+This device is still work-in-progress (WIP) and on [virtio-spec v1.4](https://github.com/oasis-tcs/virtio-spec/blob/virtio-1.4/device-types/can/) is based
+on virtio-can Linux's driver and QEMU's device presented in the following RFC:
+- https://lwn.net/Articles/934187/ 
+
+Vhost-device-can have be been tested in scenarios with multiple QEMU's VMs using
+host's *CAN/FD* devices.
+
+## Limitations
+
+1) The transmission of a CAN/FD frame to a host interface always is done
+   synchronously. This means that regardless the negotiation or not of the
+   feature *VIRTIO_CAN_F_LATE_TX_ACK*, the backend will always wait for the
+   transmission of the frame and after will mark the transmission request
+   as used.
+2) Does not check for undefined flags in CAN/FD frame when send and receive
+   a CAN/FD frame from the frontend (QEMU device).
+3) The host's CAN/FD devices should be already in *UP* state before staring
+   the vhost-device-can (by using `ip link set can0 [up,down]`).
+   - The control messages does not actually change host's device state
+4) Current version of the device has been tested only with *vcan* device.
+
+## Examples
+
+### Dependencies
+For testing the device the required dependencies are:
+- Linux:
+    - Integrate *virtio-can* driver implemented by OpenSynergy:
+        - https://lwn.net/Articles/934187/
+    - Set `CONFIG_VIRTIO_CAN=y`
+- QEMU
+    - Integrate *virtio-can* device implemented by OpenSynergy:
+        - https://lwn.net/Articles/934187/
+    - Clone vhost-user-can QEMU device (optional):
+        - A new vhost-user-can device has been implemented in the following repo:
+            - https://github.com/virtualopensystems/qemu/tree/vhu-can-rfc
+
+### Test the device
+
+The daemon should be started first:
+```shell
+host# vhost-device-can --socket-path=can.sock --can-devices="vcan0"
+```
+
+The QEMU invocation needs to create a chardev socket the device can
+use to communicate as well as share the guests memory over a memfd.
+
+There are two option for running QEMU with vhost-device-can:
+1) Using `vhost-user-device-pci` available upstream since QEMU `v8.2.0`:
+```text
+host# qemu-system                                                                    \
+    -m 4096                                                                          \
+    -numa node,memdev=mem                                                            \
+    -object memory-backend-memfd,id=mem,size=4G,share=on                             \
+    -chardev socket,id=can0,path=/tmp/can.sock                                       \
+    -device vhost-user-device-pci,chardev=can0,virtio-id=36,num_vqs=3,config_size=16 \
+    ...
+```
+2) Using `vhost-user-can-pci`:
+```text
+host# qemu-system                                         \
+    -m 4096                                               \
+    -numa node,memdev=mem                                 \
+    -object memory-backend-memfd,id=mem,size=4G,share=on  \
+    -chardev socket,path=/tmp/can.sock,id=can0            \
+    -device vhost-user-can-pci,chardev=can0,id=can        \
+    ...
+```
+
+> Note: For testing this scenario the reader needs to clone the QEMU version
+>       from the following repo which implements `vhost-user-can` device:
+> - https://github.com/virtualopensystems/qemu/tree/vhu-can-rfc
+
+### Multi-Guest case
+
+Run vhost-device-can as:
+```text
+./vhost-device-can --socket-path /tmp/can.sock  --socket-count 2 --can-devices "vcan0 vcan1"
+```
+This command will start the device and create two new sockets: */tmp/can.sock0* and */tmp/can.sock1*.
+
+From the other side we run two QEMU instances (VMs) with vhost-user-can:
+```text
+host# qemu-system                                         \
+    -m 4096                                               \
+    -numa node,memdev=mem                                 \
+    -object memory-backend-memfd,id=mem,size=4G,share=on  \
+    -chardev socket,path=<SOCKET_PATH>,id=can0            \
+    -device vhost-user-can-pci,chardev=can0,id=can        \
+    ...
+```
+In the first instance of QEMU *SOCKET_PATH* would be: */tmp/can.sock0*,
+and will use *can0* (host interface) as sender and receiver. The second
+QEMU VM would have: *SOCKET_PATH* = */tmp/can.sock1*, and will use *can1*
+as receiver and *can2* as sender.
+
+## License
+
+This project is licensed under either of
+
+- [Apache License](http://www.apache.org/licenses/LICENSE-2.0), Version 2.0
+- [BSD-3-Clause License](https://opensource.org/licenses/BSD-3-Clause)
diff --git a/meta-egvirt/recipes-extended/vhost-device-can/files/vhost-device-can-0.1.0/src/backend.rs b/meta-egvirt/recipes-extended/vhost-device-can/files/vhost-device-can-0.1.0/src/backend.rs
new file mode 100755 (executable)
index 0000000..ce8d851
--- /dev/null
@@ -0,0 +1,268 @@
+// VIRTIO CAN Emulation via vhost-user
+//
+// Copyright 2023-2024 VIRTUAL OPEN SYSTEMS SAS. All Rights Reserved.
+//          Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com>
+//
+// SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause
+
+use log::{error, info, warn};
+use std::any::Any;
+use std::collections::HashMap;
+use std::path::PathBuf;
+use std::sync::{Arc, RwLock};
+use std::thread;
+
+use thiserror::Error as ThisError;
+use vhost_user_backend::VhostUserDaemon;
+use vm_memory::{GuestMemoryAtomic, GuestMemoryMmap};
+
+use crate::can::CanController;
+use crate::vhu_can::VhostUserCanBackend;
+
+pub(crate) type Result<T> = std::result::Result<T, Error>;
+
+#[derive(Debug, ThisError)]
+/// Errors related to low level CAN helpers
+pub(crate) enum Error {
+    #[error("Invalid socket count: {0}")]
+    SocketCountInvalid(usize),
+    #[error("Could not find can devices")]
+    CouldNotFindCANDevs,
+    #[error("Could not create can controller: {0}")]
+    CouldNotCreateCanController(crate::can::Error),
+    #[error("Could not create can controller output socket: {0}")]
+    FailCreateCanControllerSocket(crate::can::Error),
+    #[error("Could not create can backend: {0}")]
+    CouldNotCreateBackend(crate::vhu_can::Error),
+    #[error("Could not create daemon: {0}")]
+    CouldNotCreateDaemon(vhost_user_backend::Error),
+    #[error("Fatal error: {0}")]
+    ServeFailed(vhost_user_backend::Error),
+    #[error("Thread `{0}` panicked")]
+    ThreadPanic(String, Box<dyn Any + Send>),
+}
+
+#[derive(PartialEq, Debug)]
+pub struct VuCanConfig {
+    pub socket_path: PathBuf,
+    pub socket_count: u32,
+    pub can_devices: Vec<String>,
+}
+
+impl VuCanConfig {
+    pub fn generate_socket_paths(&self) -> Vec<PathBuf> {
+        let socket_file_name = self
+            .socket_path
+            .file_name()
+            .expect("socket_path has no filename.");
+        let socket_file_parent = self
+            .socket_path
+            .parent()
+            .expect("socket_path has no parent directory.");
+
+        let make_socket_path = |i: u32| -> PathBuf {
+            let mut file_name = socket_file_name.to_os_string();
+            file_name.push(std::ffi::OsStr::new(&i.to_string()));
+            socket_file_parent.join(&file_name)
+        };
+
+        (0..self.socket_count).map(make_socket_path).collect()
+    }
+}
+
+/// This is the public API through which an external program starts the
+/// vhost-device-can backend server.
+pub(crate) fn start_backend_server(socket: PathBuf, can_devs: String) -> Result<()> {
+    loop {
+        let controller =
+            CanController::new(can_devs.clone()).map_err(Error::CouldNotCreateCanController)?;
+        let lockable_controller = Arc::new(RwLock::new(controller));
+        let vu_can_backend = Arc::new(RwLock::new(
+            VhostUserCanBackend::new(lockable_controller.clone())
+                .map_err(Error::CouldNotCreateBackend)?,
+        ));
+        lockable_controller
+            .write()
+            .unwrap()
+            .open_can_socket()
+            .map_err(Error::FailCreateCanControllerSocket)?;
+
+        let read_handle = CanController::start_read_thread(lockable_controller.clone());
+
+        let mut daemon = VhostUserDaemon::new(
+            String::from("vhost-device-can-backend"),
+            vu_can_backend.clone(),
+            GuestMemoryAtomic::new(GuestMemoryMmap::new()),
+        )
+        .map_err(Error::CouldNotCreateDaemon)?;
+
+        // Start the read thread -- need to handle it after termination
+        let vring_workers = daemon.get_epoll_handlers();
+        vu_can_backend
+            .read()
+            .unwrap()
+            .set_vring_worker(&vring_workers[0]);
+
+        daemon.serve(&socket).map_err(Error::ServeFailed)?;
+
+        // Terminate the thread which reads CAN messages from "can_devs"
+        lockable_controller.write().unwrap().exit_read_thread();
+
+        // Wait for read thread to exit
+        match read_handle.join() {
+            Ok(_) => info!("The read thread returned successfully"),
+            Err(e) => warn!("The read thread returned the error: {:?}", e),
+        }
+    }
+}
+
+pub fn start_backend(config: VuCanConfig) -> Result<()> {
+    let mut handles = HashMap::new();
+    let (senders, receiver) = std::sync::mpsc::channel();
+
+    for (thread_id, (socket, can_devs)) in config
+        .generate_socket_paths()
+        .into_iter()
+        .zip(config.can_devices.iter().cloned())
+        .map(|(a, b)| (a, b.to_string()))
+        .enumerate()
+    {
+        println!(
+            "thread_id: {}, socket: {:?}, can_devs: {:?}",
+            thread_id, socket, can_devs,
+        );
+
+        let name = format!("vhu-can-{}", can_devs);
+        let sender = senders.clone();
+        let handle = thread::Builder::new()
+            .name(name.clone())
+            .spawn(move || {
+                let result =
+                    std::panic::catch_unwind(move || start_backend_server(socket, can_devs));
+
+                // Notify the main thread that we are done.
+                sender.send(thread_id).unwrap();
+
+                result.map_err(|e| Error::ThreadPanic(name, e))?
+            })
+            .unwrap();
+        handles.insert(thread_id, handle);
+    }
+
+    while !handles.is_empty() {
+        let thread_id = receiver.recv().unwrap();
+        handles
+            .remove(&thread_id)
+            .unwrap()
+            .join()
+            .map_err(std::panic::resume_unwind)
+            .unwrap()?;
+    }
+
+    Ok(())
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::backend::Error::FailCreateCanControllerSocket;
+    use crate::can::Error::SocketOpen;
+    use crate::CanArgs;
+    use assert_matches::assert_matches;
+
+    #[test]
+    fn test_can_valid_configuration() {
+        let valid_args = CanArgs {
+            socket_path: "/tmp/vhost.sock".to_string().into(),
+            can_devices: "can0".to_string(),
+            socket_count: 1,
+        };
+
+        assert_matches!(
+            VuCanConfig::try_from(valid_args),
+            Err(Error::CouldNotFindCANDevs)
+        );
+    }
+
+    #[test]
+    fn test_can_valid_mult_device_configuration() {
+        let valid_args = CanArgs {
+            socket_path: "/tmp/vhost.sock".to_string().into(),
+            can_devices: "can0 can1".to_string(),
+            socket_count: 2,
+        };
+
+        assert_matches!(
+            VuCanConfig::try_from(valid_args),
+            Err(Error::CouldNotFindCANDevs)
+        );
+    }
+
+    #[test]
+    fn test_can_invalid_socket_configuration() {
+        let invalid_args = CanArgs {
+            socket_path: "/tmp/vhost.sock".to_string().into(),
+            can_devices: "can0".to_string(),
+            socket_count: 0,
+        };
+
+        assert_matches!(
+            VuCanConfig::try_from(invalid_args),
+            Err(Error::SocketCountInvalid(0))
+        );
+    }
+
+    #[test]
+    fn test_can_invalid_mult_socket_configuration_1() {
+        let invalid_args = CanArgs {
+            socket_path: "/tmp/vhost.sock".to_string().into(),
+            can_devices: "can0".to_string(),
+            socket_count: 2,
+        };
+
+        assert_matches!(
+            VuCanConfig::try_from(invalid_args),
+            Err(Error::SocketCountInvalid(2))
+        );
+    }
+
+    #[test]
+    fn test_can_invalid_mult_socket_configuration_2() {
+        let invalid_args = CanArgs {
+            socket_path: "/tmp/vhost.sock".to_string().into(),
+            can_devices: "can0 can1".to_string(),
+            socket_count: 1,
+        };
+
+        assert_matches!(
+            VuCanConfig::try_from(invalid_args),
+            Err(Error::SocketCountInvalid(1))
+        );
+    }
+
+    #[test]
+    fn test_can_valid_configuration_start_backend_fail() {
+        // Instantiate the struct with the provided values
+        let config = VuCanConfig {
+            socket_path: PathBuf::from("/tmp/vhost.sock"),
+            socket_count: 1,
+            can_devices: vec!["can0".to_string()],
+        };
+
+        assert_matches!(
+            start_backend(config),
+            Err(FailCreateCanControllerSocket(SocketOpen))
+        );
+    }
+
+    #[test]
+    fn test_can_valid_configuration_start_backend_server_fail() {
+        let socket_path = PathBuf::from("/tmp/vhost.sock");
+        let can_devs = "can0".to_string();
+
+        assert_matches!(
+            start_backend_server(socket_path, can_devs),
+            Err(FailCreateCanControllerSocket(SocketOpen))
+        );
+    }
+}
diff --git a/meta-egvirt/recipes-extended/vhost-device-can/files/vhost-device-can-0.1.0/src/can.rs b/meta-egvirt/recipes-extended/vhost-device-can/files/vhost-device-can-0.1.0/src/can.rs
new file mode 100755 (executable)
index 0000000..6fc0355
--- /dev/null
@@ -0,0 +1,393 @@
+// CAN backend device
+//
+// Copyright 2023-2024 VIRTUAL OPEN SYSTEMS SAS. All Rights Reserved.
+//          Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com>
+//
+// SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause
+
+use log::{error, info, trace, warn};
+use std::sync::{Arc, RwLock};
+
+use std::thread::{spawn, JoinHandle};
+use thiserror::Error as ThisError;
+use vmm_sys_util::eventfd::{EventFd, EFD_NONBLOCK};
+extern crate queues;
+use queues::*;
+extern crate socketcan;
+use crate::virtio_can::{
+    VirtioCanConfig, VirtioCanFrame, CAN_CS_STARTED, CAN_CS_STOPPED, CAN_EFF_FLAG,
+    CAN_FRMF_TYPE_FD, VIRTIO_CAN_RX,
+};
+use socketcan::{
+    CanAnyFrame, CanDataFrame, CanFdFrame, CanFdSocket, EmbeddedFrame, ExtendedId, Frame, Id,
+    Socket, StandardId,
+};
+
+type Result<T> = std::result::Result<T, Error>;
+
+#[derive(Copy, Clone, Debug, PartialEq, ThisError)]
+/// Errors related to low level can helpers
+pub(crate) enum Error {
+    #[error("Can open socket operation failed")]
+    SocketOpen,
+    #[error("Can write socket operation failed")]
+    SocketWrite,
+    #[error("Can read socket operation failed")]
+    SocketRead,
+    #[error("Pop can element operation failed")]
+    PopFailed,
+    #[error("Queue is empty")]
+    QueueEmpty,
+    #[error("Creating Eventfd for CAN events failed")]
+    EventFdFailed,
+    #[error("Push can element operation failed")]
+    PushFailed,
+    #[error("No output interface available")]
+    NoOutputInterface,
+}
+
+#[derive(Debug)]
+pub(crate) struct CanController {
+    pub config: VirtioCanConfig,
+    pub can_name: String,
+    pub can_socket: Option<CanFdSocket>,
+    pub rx_event_fd: EventFd,
+    rx_fifo: Queue<VirtioCanFrame>,
+    pub status: bool,
+    pub ctrl_state: u8,
+}
+
+impl CanController {
+    // Creates a new controller corresponding to `device`.
+    pub(crate) fn new(can_name: String) -> Result<CanController> {
+        let can_name = can_name.to_owned();
+        info!("can_name: {:?}", can_name);
+
+        let rx_fifo = Queue::new();
+        let rx_efd = EventFd::new(EFD_NONBLOCK).map_err(|_| Error::EventFdFailed)?;
+
+        Ok(CanController {
+            config: VirtioCanConfig { status: 0x0.into() },
+            can_name,
+            can_socket: None,
+            rx_event_fd: rx_efd,
+            rx_fifo,
+            status: true,
+            ctrl_state: CAN_CS_STOPPED,
+        })
+    }
+
+    pub fn print_can_frame(canframe: VirtioCanFrame) {
+        trace!("canframe.msg_type 0x{:x}", canframe.msg_type.to_native());
+        trace!("canframe.can_id 0x{:x}", canframe.can_id.to_native());
+        trace!("canframe.length {}", canframe.length.to_native());
+        trace!("canframe.flags 0x{:x}", canframe.flags.to_native());
+        if canframe.length.to_native() == 0 {
+            trace!("[]");
+            return;
+        }
+        trace!("[");
+        let last_elem = canframe.length.to_native() as usize - 1;
+        for (index, sdu) in canframe.sdu.iter().enumerate() {
+            if index == last_elem {
+                trace!("0x{:x}", sdu);
+                break;
+            }
+            trace!("0x{:x}, ", sdu);
+        }
+        trace!("]");
+    }
+
+    pub fn start_read_thread(controller: Arc<RwLock<CanController>>) -> JoinHandle<Result<()>> {
+        spawn(move || CanController::read_can_socket(controller))
+    }
+
+    pub fn push(&mut self, rx_elem: VirtioCanFrame) -> Result<()> {
+        match self.rx_fifo.add(rx_elem) {
+            Ok(_) => Ok(()),
+            _ => Err(Error::PushFailed),
+        }
+    }
+
+    pub fn rx_is_empty(&mut self) -> bool {
+        self.rx_fifo.size() == 0
+    }
+
+    pub fn pop(&mut self) -> Result<VirtioCanFrame> {
+        if self.rx_fifo.size() < 1 {
+            return Err(Error::QueueEmpty);
+        }
+
+        match self.rx_fifo.remove() {
+            Ok(item) => Ok(item),
+            _ => Err(Error::PopFailed),
+        }
+    }
+
+    pub fn open_can_socket(&mut self) -> Result<()> {
+        self.can_socket = match CanFdSocket::open(&self.can_name) {
+            Ok(socket) => Some(socket),
+            Err(_) => {
+                warn!("Error opening CAN socket");
+                return Err(Error::SocketOpen);
+            }
+        };
+        Ok(())
+    }
+
+    // Helper function to process frame
+    fn process_frame<F: Frame>(frame: F, is_fd: bool) -> VirtioCanFrame {
+        VirtioCanFrame {
+            msg_type: VIRTIO_CAN_RX.into(),
+            can_id: frame.id_word().into(),
+            length: (frame.data().len() as u16).into(),
+            reserved: 0.into(),
+            flags: if is_fd {
+                CAN_FRMF_TYPE_FD.into()
+            } else {
+                0.into()
+            },
+            sdu: {
+                let mut sdu_data: [u8; 64] = [0; 64];
+                sdu_data[..frame.data().len()].copy_from_slice(frame.data());
+                sdu_data
+            },
+        }
+    }
+
+    pub fn read_can_socket(controller: Arc<RwLock<CanController>>) -> Result<()> {
+        let can_name = &controller.read().unwrap().can_name.clone();
+        dbg!("Start reading from {} socket!", &can_name);
+        let socket = match CanFdSocket::open(can_name) {
+            Ok(socket) => socket,
+            Err(_) => {
+                warn!("Error opening CAN socket");
+                return Err(Error::SocketOpen);
+            }
+        };
+
+        // Set non-blocking otherwise the device will not restart immediatelly
+        // when the VM closes, and a new canfd message needs to be received for
+        // restart to happen.
+        // This caused by the fact that the thread is stacked in read function
+        // and does not go to the next loop to check the status condition.
+        socket
+            .set_nonblocking(true)
+            .expect("Cannot set nonblocking");
+
+        // Receive CAN messages
+        loop {
+            // If the status variable is false then break and exit.
+            if !controller.read().unwrap().status {
+                dbg!("exit read can thread");
+                return Ok(());
+            }
+
+            if let Ok(frame) = socket.read_frame() {
+                // If ctrl_state is stopped, consume the received CAN/FD frame
+                // and loop till the ctrl_state changes to started or the thread
+                // to exit.
+                if controller.read().unwrap().ctrl_state != CAN_CS_STARTED {
+                    trace!("CAN/FD frame is received but not saved!");
+                    continue;
+                }
+
+                // Match and process frame variants
+                let read_can_frame = match frame {
+                    CanAnyFrame::Normal(frame) => {
+                        trace!("Received CAN frame: {:?}", frame);
+                        Self::process_frame(frame, false)
+                    }
+                    CanAnyFrame::Fd(frame) => {
+                        trace!("Received CAN FD frame: {:?}", frame);
+                        Self::process_frame(frame, true)
+                    }
+                    CanAnyFrame::Remote(frame) => {
+                        trace!("Received Remote CAN frame: {:?}", frame);
+                        Self::process_frame(frame, false)
+                    }
+                    CanAnyFrame::Error(frame) => {
+                        trace!("Received Error frame: {:?}", frame);
+                        Self::process_frame(frame, false)
+                    }
+                };
+
+                match controller.write().unwrap().push(read_can_frame) {
+                    Ok(_) => warn!("New Can frame was received"),
+                    Err(_) => {
+                        warn!("Error read/push CAN frame");
+                        return Err(Error::SocketRead);
+                    }
+                };
+
+                controller
+                    .write()
+                    .unwrap()
+                    .rx_event_fd
+                    .write(1)
+                    .expect("Fail to write on rx_event_fd");
+            }
+        }
+    }
+
+    pub(crate) fn exit_read_thread(&mut self) {
+        trace!("Exit can read thread\n");
+        self.status = false;
+    }
+
+    pub(crate) fn config(&mut self) -> &VirtioCanConfig {
+        &self.config
+    }
+
+    pub(crate) fn can_out(&self, tx_request: VirtioCanFrame) -> Result<()> {
+        // Create a CAN frame with a specific CAN-ID and the data buffer
+        let can_id: Id = if (tx_request.can_id.to_native() & CAN_EFF_FLAG) != 0 {
+            // SAFETY: Use new_unchecked cause checks have been taken place
+            // to prior stage. Also flags have beem already added on can_id
+            // so tnew will fail (can_id + can_flags) > 29 bits
+            unsafe { Id::Extended(ExtendedId::new_unchecked(tx_request.can_id.into())) }
+        } else {
+            // SAFETY: Use new_unchecked cause checks have been taken place
+            // to prior stage. Also flags have beem already added on can_id
+            // so tnew will fail (can_id + can_flags) > 11 bits
+            unsafe {
+                Id::Standard(StandardId::new_unchecked(
+                    tx_request.can_id.to_native() as u16
+                ))
+            }
+        };
+
+        // Grab the data to be tranfered
+        let data_len = tx_request.length.to_native() as usize;
+        let data: Vec<u8> = tx_request.sdu.iter().cloned().take(data_len).collect();
+
+        // Format CAN/FD frame
+        let frame: CanAnyFrame = if (tx_request.flags.to_native() & CAN_FRMF_TYPE_FD) != 0 {
+            CanAnyFrame::Fd(CanFdFrame::new(can_id, &data).expect("Fail to create CanFdFrame"))
+        } else {
+            CanAnyFrame::Normal(CanDataFrame::new(can_id, &data).expect("Fail to create CanFrame"))
+        };
+
+        // Send the CAN/FD frame
+        let socket = self.can_socket.as_ref().ok_or("No available device");
+
+        match socket {
+            Ok(socket) => match socket.write_frame(&frame) {
+                Ok(_) => Ok(()),
+                Err(_) => {
+                    warn!("Error write CAN socket");
+                    Err(Error::SocketWrite)
+                }
+            },
+            Err(_) => Err(Error::NoOutputInterface),
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::vhu_can::VhostUserCanBackend;
+    use std::sync::{Arc, RwLock};
+
+    #[test]
+    fn test_can_controller_creation() {
+        let can_name = "can".to_string();
+
+        let controller = CanController::new(can_name.clone()).unwrap();
+        assert_eq!(controller.can_name, can_name);
+    }
+
+    #[test]
+    fn test_can_controller_push_and_pop() {
+        let can_name = "can".to_string();
+        let mut controller = CanController::new(can_name.clone()).unwrap();
+
+        let frame = VirtioCanFrame {
+            msg_type: VIRTIO_CAN_RX.into(),
+            can_id: 123.into(),
+            length: 64.into(),
+            reserved: 0.into(),
+            flags: 0.into(),
+            sdu: [0; 64],
+        };
+
+        // Test push
+        controller.push(frame).unwrap();
+
+        // Test pop
+        let pop_result = controller.pop().unwrap();
+        assert_eq!(pop_result, frame);
+    }
+
+    #[test]
+    fn test_can_controller_config() {
+        let can_name = "can".to_string();
+        let mut controller = CanController::new(can_name.clone()).unwrap();
+
+        // Test config
+        let config = controller.config();
+        assert_eq!(config.status.to_native(), 0);
+    }
+
+    #[test]
+    fn test_can_controller_operation() {
+        let can_name = "can".to_string();
+        let mut controller = CanController::new(can_name.clone()).unwrap();
+
+        let frame = VirtioCanFrame {
+            msg_type: VIRTIO_CAN_RX.into(),
+            can_id: 123.into(),
+            length: 64.into(),
+            reserved: 0.into(),
+            flags: 0.into(),
+            sdu: [0; 64],
+        };
+
+        match controller.open_can_socket() {
+            Ok(_) => {
+                // Test operation
+                let operation_result = controller.can_out(frame);
+                assert!(operation_result.is_ok());
+            }
+            Err(_) => warn!("There is no CAN interface with {} name", can_name),
+        }
+    }
+
+    #[test]
+    fn test_can_controller_start_read_thread() {
+        let can_name = "can".to_string();
+        let controller = CanController::new(can_name.clone()).unwrap();
+        let arc_controller = Arc::new(RwLock::new(controller));
+
+        // Test start_read_thread
+        let thread_handle = CanController::start_read_thread(arc_controller.clone());
+        assert!(thread_handle.join().is_ok());
+    }
+
+    #[test]
+    fn test_can_open_socket_fail() {
+        let controller =
+            CanController::new("can0".to_string()).expect("Could not build controller");
+        let controller = Arc::new(RwLock::new(controller));
+        VhostUserCanBackend::new(controller.clone()).expect("Could not build vhucan device");
+
+        assert_eq!(
+            controller.write().unwrap().open_can_socket(),
+            Err(Error::SocketOpen)
+        );
+    }
+
+    #[test]
+    fn test_can_read_socket_fail() {
+        let controller =
+            CanController::new("can0".to_string()).expect("Could not build controller");
+        let controller = Arc::new(RwLock::new(controller));
+        VhostUserCanBackend::new(controller.clone()).expect("Could not build vhucan device");
+
+        assert_eq!(
+            CanController::read_can_socket(controller),
+            Err(Error::SocketOpen)
+        );
+    }
+}
diff --git a/meta-egvirt/recipes-extended/vhost-device-can/files/vhost-device-can-0.1.0/src/main.rs b/meta-egvirt/recipes-extended/vhost-device-can/files/vhost-device-can-0.1.0/src/main.rs
new file mode 100755 (executable)
index 0000000..9738688
--- /dev/null
@@ -0,0 +1,96 @@
+// VIRTIO CAN Emulation via vhost-user
+//
+// Copyright 2023-2024 VIRTUAL OPEN SYSTEMS SAS. All Rights Reserved.
+//          Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com>
+//
+// SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause
+
+mod backend;
+mod can;
+mod vhu_can;
+mod virtio_can;
+
+use clap::Parser;
+use log::{error, info};
+use socketcan::{CanSocket, Socket};
+use std::convert::TryFrom;
+use std::path::PathBuf;
+use std::process::exit;
+
+pub(crate) type Result<T> = std::result::Result<T, Error>;
+use crate::backend::{start_backend, Error, VuCanConfig};
+
+#[derive(Parser, Debug)]
+#[clap(author, version, about, long_about = None)]
+struct CanArgs {
+    /// Location of vhost-user Unix domain socket. This is suffixed by 0,1,2..socket_count-1.
+    #[clap(short, long, value_name = "SOCKET")]
+    socket_path: PathBuf,
+
+    /// A can device name to be used for reading (ex. vcan, can0, can1, ... etc.)
+    #[clap(short = 'd', long)]
+    can_devices: String,
+
+    /// Number of guests (sockets) to connect to.
+    #[clap(short = 'c', long, default_value_t = 1)]
+    socket_count: u32,
+}
+
+fn check_can_devices(can_devices: &[String]) -> Result<()> {
+    for can_dev in can_devices {
+        if CanSocket::open(can_dev).is_err() {
+            info!("There is no interface with the following name {}", can_dev);
+            return Err(Error::CouldNotFindCANDevs);
+        }
+    }
+    Ok(())
+}
+
+fn parse_can_devices(input: &CanArgs) -> Result<Vec<String>> {
+    let can_devices_vec: Vec<&str> = input.can_devices.split_whitespace().collect();
+    let can_devices: Vec<_> = can_devices_vec.iter().map(|x| x.to_string()).collect();
+
+    if (can_devices.len() as u32) != input.socket_count {
+        info!(
+            "Number of CAN/FD devices ({}) not equal with socket count {}",
+            input.can_devices, input.socket_count
+        );
+        return Err(Error::SocketCountInvalid(
+            input.socket_count.try_into().unwrap(),
+        ));
+    }
+
+    match check_can_devices(&can_devices) {
+        Ok(_) => Ok(can_devices),
+        Err(_) => Err(Error::CouldNotFindCANDevs),
+    }
+}
+
+impl TryFrom<CanArgs> for VuCanConfig {
+    type Error = Error;
+
+    fn try_from(args: CanArgs) -> Result<Self> {
+        if args.socket_count == 0 {
+            return Err(Self::Error::SocketCountInvalid(0));
+        }
+
+        let can_devices = match parse_can_devices(&args) {
+            Ok(can_devs) => can_devs,
+            Err(e) => return Err(e),
+        };
+
+        Ok(VuCanConfig {
+            socket_path: args.socket_path,
+            socket_count: args.socket_count,
+            can_devices,
+        })
+    }
+}
+
+fn main() {
+    env_logger::init();
+    if let Err(e) = VuCanConfig::try_from(CanArgs::parse()).and_then(start_backend) {
+        error!("{e}");
+        exit(1);
+    }
+}
diff --git a/meta-egvirt/recipes-extended/vhost-device-can/files/vhost-device-can-0.1.0/src/vhu_can.rs b/meta-egvirt/recipes-extended/vhost-device-can/files/vhost-device-can-0.1.0/src/vhu_can.rs
new file mode 100755 (executable)
index 0000000..b53f57d
--- /dev/null
@@ -0,0 +1,2145 @@
+// vhost device can
+//
+// Copyright 2023-2024 VIRTUAL OPEN SYSTEMS SAS. All Rights Reserved.
+//          Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com>
+//
+// SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause
+
+use crate::can::CanController;
+use crate::can::Error::QueueEmpty;
+use crate::virtio_can::{
+    VirtioCanCtrlRequest, VirtioCanFrame, VirtioCanHeader, CANFD_VALID_LENGTHS, CAN_CS_STARTED,
+    CAN_CS_STOPPED, CAN_EFF_FLAG, CAN_EFF_MASK, CAN_ERR_BUSOFF, CAN_ERR_FLAG, CAN_FRMF_TYPE_FD,
+    CAN_RTR_FLAG, CAN_SFF_MASK, VIRTIO_CAN_FLAGS_EXTENDED, VIRTIO_CAN_FLAGS_FD,
+    VIRTIO_CAN_FLAGS_RTR, VIRTIO_CAN_FLAGS_VALID_MASK, VIRTIO_CAN_F_CAN_CLASSIC,
+    VIRTIO_CAN_F_CAN_FD, VIRTIO_CAN_F_RTR_FRAMES, VIRTIO_CAN_RESULT_NOT_OK, VIRTIO_CAN_RESULT_OK,
+    VIRTIO_CAN_RX, VIRTIO_CAN_SET_CTRL_MODE_START, VIRTIO_CAN_SET_CTRL_MODE_STOP,
+    VIRTIO_CAN_S_CTRL_BUSOFF, VIRTIO_CAN_TX,
+};
+use log::{error, trace, warn};
+use std::os::fd::AsRawFd;
+use std::slice::from_raw_parts;
+use std::sync::{Arc, RwLock};
+use std::{
+    convert,
+    io::{self, Result as IoResult},
+};
+use thiserror::Error as ThisError;
+use vhost::vhost_user::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures};
+use vhost_user_backend::VringEpollHandler;
+use vhost_user_backend::{VhostUserBackendMut, VringRwLock, VringT};
+use virtio_bindings::bindings::virtio_config::{VIRTIO_F_NOTIFY_ON_EMPTY, VIRTIO_F_VERSION_1};
+use virtio_bindings::bindings::virtio_ring::{
+    VIRTIO_RING_F_EVENT_IDX, VIRTIO_RING_F_INDIRECT_DESC,
+};
+use virtio_queue::{DescriptorChain, QueueOwnedT};
+use vm_memory::{
+    ByteValued, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryLoadGuard, GuestMemoryMmap,
+};
+use vmm_sys_util::epoll::EventSet;
+use vmm_sys_util::eventfd::{EventFd, EFD_NONBLOCK};
+
+/// Virtio configuration
+const QUEUE_SIZE: usize = 64;
+const NUM_QUEUES: usize = 3;
+
+/// Queues
+const TX_QUEUE: u16 = 0;
+const RX_QUEUE: u16 = 1;
+const CTRL_QUEUE: u16 = 2;
+const BACKEND_EFD: u16 = (NUM_QUEUES + 1) as u16;
+
+type Result<T> = std::result::Result<T, Error>;
+
+#[derive(Copy, Clone, Debug, PartialEq, ThisError)]
+/// Errors related to vhost-device-can-daemon.
+pub(crate) enum Error {
+    #[error("Failed to handle event, didn't match EPOLLIN")]
+    HandleEventNotEpollIn,
+    #[error("Failed to handle unknown event")]
+    HandleEventUnknown,
+    #[error("Descriptor not found")]
+    DescriptorNotFound,
+    #[error("Descriptor read failed")]
+    DescriptorReadFailed,
+    #[error("Descriptor write failed")]
+    DescriptorWriteFailed,
+    #[error("Failed to send notification")]
+    NotificationFailed,
+    #[error("Failed to create new EventFd")]
+    EventFdFailed,
+    #[error("Unknown can message type: {0}")]
+    UnexpectedCanMsgType(u16),
+    #[error("RTR frames not negotiated")]
+    UnexpectedRtrFlag,
+    #[error("Can FD frames not negotiated")]
+    UnexpectedFdFlag,
+    #[error("Unexpected CAN ID bigger than: {0} bits")]
+    UnexpectedCanId(u16),
+    #[error("Invalid CAN flags: {0}")]
+    InvalidCanFlags(u32),
+    #[error("Invalid CAN[FD] length: {0}")]
+    InvalidCanLength(u32),
+    #[error("Classic CAN frames not negotiated")]
+    UnexpectedClassicFlag,
+    #[error("Bus off error received")]
+    BusoffRxFrame,
+    #[error("Rx CAN frame has unknown error")]
+    RxFrameUnknownFail,
+}
+
+impl convert::From<Error> for io::Error {
+    fn from(e: Error) -> Self {
+        io::Error::new(io::ErrorKind::Other, e)
+    }
+}
+
+pub(crate) struct VhostUserCanBackend {
+    controller: Arc<RwLock<CanController>>,
+    acked_features: u64,
+    event_idx: bool,
+    pub(crate) exit_event: EventFd,
+    mem: Option<GuestMemoryAtomic<GuestMemoryMmap>>,
+}
+
+type CanDescriptorChain = DescriptorChain<GuestMemoryLoadGuard<GuestMemoryMmap<()>>>;
+
+impl VhostUserCanBackend {
+    pub(crate) fn new(controller: Arc<RwLock<CanController>>) -> Result<Self> {
+        Ok(VhostUserCanBackend {
+            controller,
+            event_idx: false,
+            acked_features: 0x0,
+            exit_event: EventFd::new(EFD_NONBLOCK).map_err(|_| Error::EventFdFailed)?,
+            mem: None,
+        })
+    }
+
+    fn check_features(&self, features: u16) -> bool {
+        (self.acked_features & (1 << features)) != 0
+    }
+
+    fn check_tx_frame(&self, request: VirtioCanFrame) -> Result<VirtioCanFrame> {
+        let msg_type = request.msg_type.to_native();
+        let mut can_id = request.can_id.to_native();
+        let length = request.length.to_native();
+        let mut flags = 0;
+
+        if msg_type != VIRTIO_CAN_TX {
+            warn!("TX: Message type 0x{:x} unknown\n", msg_type);
+            return Err(Error::UnexpectedCanMsgType(msg_type));
+        }
+
+        // Check for undefined bits in frame's flags
+        let invalid_can_flags: u32 = request.flags.to_native() & !VIRTIO_CAN_FLAGS_VALID_MASK;
+        if invalid_can_flags != 0 {
+            return Err(Error::InvalidCanFlags(invalid_can_flags));
+        }
+
+        // If VIRTIO_CAN_FLAGS_EXTENDED has negotiated then use extended CAN ID
+        if (request.flags.to_native() & VIRTIO_CAN_FLAGS_EXTENDED) != 0 {
+            // If we have a extended frame there is no way to check if
+            // can_id > 29 bits. The reason is that bit 29, 30, 31 are
+            // dedicated to CAN specific flags (EFF, RTR, ERR).
+            if can_id > CAN_EFF_MASK {
+                return Err(Error::UnexpectedCanId(29_u16));
+            }
+            can_id |= CAN_EFF_FLAG;
+        } else {
+            // If we have a standard frame and can_id > 11 bits then fail
+            if can_id > CAN_SFF_MASK {
+                return Err(Error::UnexpectedCanId(11_u16));
+            }
+        }
+
+        // Remote transfer request is used only with classic CAN
+        if (request.flags.to_native() & VIRTIO_CAN_FLAGS_RTR) != 0 {
+            if !self.check_features(VIRTIO_CAN_F_CAN_CLASSIC)
+                || !self.check_features(VIRTIO_CAN_F_RTR_FRAMES)
+            {
+                warn!("TX: RTR frames not negotiated");
+                return Err(Error::UnexpectedRtrFlag);
+            }
+            can_id |= CAN_RTR_FLAG;
+        }
+
+        // One of VIRTIO_CAN_F_CAN_CLASSIC and VIRTIO_CAN_F_CAN_FD must be negotiated
+        // Check if VIRTIO_CAN_F_CAN_FD is negotiated when the frame is CANFD
+        if (request.flags.to_native() & VIRTIO_CAN_FLAGS_FD) != 0 {
+            if !self.check_features(VIRTIO_CAN_F_CAN_FD) {
+                warn!("TX: FD frames not negotiated\n");
+                return Err(Error::UnexpectedFdFlag);
+            }
+            flags = CAN_FRMF_TYPE_FD;
+        } else {
+            // Check if VIRTIO_CAN_F_CAN_CLASSIC is negotiated when the frame is CAN
+            if !self.check_features(VIRTIO_CAN_F_CAN_CLASSIC) {
+                warn!("TX: Classic frames not negotiated\n");
+                return Err(Error::UnexpectedClassicFlag);
+            }
+        }
+
+        // Check if CAN/FD length is out-of-range (based on negotiated features)
+        if (request.flags.to_native() & VIRTIO_CAN_FLAGS_FD) != 0 {
+            if length > 8 && !CANFD_VALID_LENGTHS.contains(&length.into()) {
+                return Err(Error::InvalidCanLength(length.into()));
+            }
+        } else if length > 8 {
+            return Err(Error::InvalidCanLength(length.into()));
+        }
+
+        Ok(VirtioCanFrame {
+            msg_type: msg_type.into(),
+            can_id: can_id.into(),
+            length: length.into(),
+            reserved: 0.into(),
+            flags: flags.into(),
+            sdu: request.sdu[0..64].try_into().unwrap(),
+        })
+    }
+
+    fn check_rx_frame(&self, response: VirtioCanFrame) -> Result<VirtioCanFrame> {
+        CanController::print_can_frame(response);
+
+        let mut can_rx = VirtioCanFrame {
+            msg_type: VIRTIO_CAN_RX.into(),
+            can_id: response.can_id,
+            length: response.length,
+            reserved: 0.into(),
+            flags: response.flags,
+            sdu: [0; 64],
+        };
+        let res_len = response.length.to_native();
+        let res_can_id = response.can_id.to_native();
+        let mut res_flags = response.flags.to_native();
+
+        // If we receive an error message check if that's a busoff.
+        // If no just drop the message, otherwise update config and return.
+        if (res_can_id & CAN_ERR_FLAG) != 0 {
+            if (res_can_id & CAN_ERR_BUSOFF) != 0 {
+                // TODO: Trigger a config_change notification
+                self.controller.write().unwrap().config.status = VIRTIO_CAN_S_CTRL_BUSOFF.into();
+                self.controller.write().unwrap().ctrl_state = CAN_CS_STOPPED;
+                warn!("Got BusOff error frame, device does a local bus off\n");
+                return Err(Error::BusoffRxFrame);
+            } else {
+                trace!("Dropping error frame 0x{:x}\n", response.can_id.to_native());
+                return Err(Error::RxFrameUnknownFail);
+            }
+        }
+
+        // One of VIRTIO_CAN_F_CAN_CLASSIC and VIRTIO_CAN_F_CAN_FD must be negotiated
+        if (res_flags & CAN_FRMF_TYPE_FD) != 0 {
+            if !self.check_features(VIRTIO_CAN_F_CAN_FD) {
+                warn!("Drop non-supported CAN FD frame");
+                return Err(Error::UnexpectedFdFlag);
+            }
+        } else if !self.check_features(VIRTIO_CAN_F_CAN_CLASSIC) {
+            warn!("Drop non-supported CAN classic frame");
+            return Err(Error::UnexpectedClassicFlag);
+        }
+
+        // Add VIRTIO_CAN_FLAGS_EXTENDED in flag if the received frame
+        // had an extended CAN ID.
+        // Based on virtio-spec v1.4, the 3 MSB of can_id should be set to 0.
+        if (res_can_id & CAN_EFF_FLAG) != 0 {
+            can_rx.flags = VIRTIO_CAN_FLAGS_EXTENDED.into();
+            can_rx.can_id = (res_can_id & CAN_EFF_MASK).into();
+        } else {
+            can_rx.flags = 0.into();
+            can_rx.can_id = (res_can_id & CAN_SFF_MASK).into();
+        }
+
+        // Remote transfer request is used only with classic CAN
+        if (res_can_id & CAN_RTR_FLAG) != 0 {
+            if !self.check_features(VIRTIO_CAN_F_RTR_FRAMES)
+                || !self.check_features(VIRTIO_CAN_F_CAN_CLASSIC)
+            {
+                warn!("Drop non-supported RTR frame");
+                return Err(Error::UnexpectedRtrFlag);
+            }
+            // If remote transfer request is enabled add the according flag
+            can_rx.flags = (can_rx.flags.to_native() | VIRTIO_CAN_FLAGS_RTR).into();
+        }
+
+        // Treat Vcan interface as CANFD if MTU is set to 64 bytes.
+        //
+        // Vcan can not be configured as CANFD interface, but it is
+        // possible to configure its MTU to 64 bytes. So if a messages
+        // bigger than 8 bytes is being received we consider it as
+        // CANFD message.
+        let can_name = self.controller.read().unwrap().can_name.clone();
+        if self.check_features(VIRTIO_CAN_F_CAN_FD) && res_len > 8 && can_name == "vcan0" {
+            res_flags |= CAN_FRMF_TYPE_FD;
+            warn!("\n\n\nCANFD VCAN0\n\n");
+        }
+
+        // Check if CAN/FD length is out-of-range (based on negotiated features)
+        if (res_flags & CAN_FRMF_TYPE_FD) != 0 {
+            if res_len > 8 && !CANFD_VALID_LENGTHS.contains(&res_len.into()) {
+                return Err(Error::InvalidCanLength(res_len.into()));
+            }
+            can_rx.flags = (can_rx.flags.to_native() | VIRTIO_CAN_FLAGS_FD).into();
+        } else if res_len > 8 {
+            return Err(Error::InvalidCanLength(res_len.into()));
+        }
+
+        can_rx.sdu.copy_from_slice(&response.sdu[0..64]);
+        CanController::print_can_frame(can_rx);
+
+        Ok(can_rx)
+    }
+
+    fn process_ctrl_requests(
+        &self,
+        requests: Vec<CanDescriptorChain>,
+        vring: &VringRwLock,
+    ) -> Result<bool> {
+        if requests.is_empty() {
+            return Ok(true);
+        }
+
+        for desc_chain in requests {
+            let atomic_mem = self.mem.as_ref().unwrap().memory();
+
+            let mut reader = desc_chain
+                .clone()
+                .reader(&atomic_mem)
+                .map_err(|_| Error::DescriptorReadFailed)?;
+
+            let mut writer = desc_chain
+                .clone()
+                .writer(&atomic_mem)
+                .map_err(|_| Error::DescriptorWriteFailed)?;
+
+            let request = reader
+                .read_obj::<VirtioCanCtrlRequest>()
+                .map_err(|_| Error::DescriptorReadFailed)?;
+
+            // This implementation requires the CAN devices to be already in UP state
+            // before starting. This code does not trigger state changes [UP/DOWN] of
+            // the host CAN devices.
+            let response = match request.msg_type.into() {
+                VIRTIO_CAN_SET_CTRL_MODE_START => {
+                    if self.controller.write().unwrap().ctrl_state == CAN_CS_STARTED {
+                        VIRTIO_CAN_RESULT_NOT_OK
+                    } else {
+                        // TODO: Trigger a config_change notification (optional)
+                        self.controller.write().unwrap().config.status = 0.into();
+                        self.controller.write().unwrap().ctrl_state = CAN_CS_STARTED;
+                        VIRTIO_CAN_RESULT_OK
+                    }
+                }
+                VIRTIO_CAN_SET_CTRL_MODE_STOP => {
+                    if self.controller.write().unwrap().ctrl_state == CAN_CS_STOPPED {
+                        VIRTIO_CAN_RESULT_NOT_OK
+                    } else {
+                        // TODO: Trigger a config_change notification (optional)
+                        self.controller.write().unwrap().config.status = 0.into();
+                        self.controller.write().unwrap().ctrl_state = CAN_CS_STOPPED;
+                        VIRTIO_CAN_RESULT_OK
+                    }
+                }
+                _ => {
+                    trace!("Ctrl queue: msg type 0x{:?} unknown", request.msg_type);
+                    VIRTIO_CAN_RESULT_NOT_OK
+                }
+            };
+
+            writer
+                .write_obj(response)
+                .map_err(|_| Error::DescriptorWriteFailed)?;
+
+            if vring
+                .add_used(desc_chain.head_index(), writer.bytes_written() as u32)
+                .is_err()
+            {
+                warn!("Couldn't return used descriptors to the ring");
+            }
+        }
+
+        Ok(true)
+    }
+
+    fn process_tx_requests(
+        &self,
+        requests: Vec<CanDescriptorChain>,
+        vring: &VringRwLock,
+    ) -> Result<bool> {
+        if requests.is_empty() {
+            return Ok(true);
+        }
+
+        for desc_chain in requests {
+            let atomic_mem = self.mem.as_ref().unwrap().memory();
+
+            let mut reader = desc_chain
+                .clone()
+                .reader(&atomic_mem)
+                .map_err(|_| Error::DescriptorReadFailed)?;
+
+            let mut writer = desc_chain
+                .clone()
+                .writer(&atomic_mem)
+                .map_err(|_| Error::DescriptorWriteFailed)?;
+
+            let request_header = reader
+                .read_obj::<VirtioCanHeader>()
+                .map_err(|_| Error::DescriptorReadFailed)?;
+
+            let data_len = request_header.length.to_native() as usize;
+            let mut request_data: Vec<u8> = Vec::new();
+            for _i in 0..data_len {
+                let data_byte = reader
+                    .read_obj::<u8>()
+                    .map_err(|_| Error::DescriptorReadFailed)?;
+                request_data.push(data_byte);
+            }
+
+            let request = VirtioCanFrame {
+                msg_type: request_header.msg_type,
+                can_id: request_header.can_id,
+                length: request_header.length,
+                reserved: request_header.reserved,
+                flags: request_header.flags,
+                sdu: {
+                    let mut sdu_data: [u8; 64] = [0; 64];
+                    sdu_data[..request_header.length.to_native() as usize]
+                        .copy_from_slice(request_data.as_slice());
+                    sdu_data
+                },
+            };
+            CanController::print_can_frame(request);
+
+            let response = if self.controller.read().unwrap().ctrl_state == CAN_CS_STOPPED {
+                trace!("Device is stopped!");
+                VIRTIO_CAN_RESULT_NOT_OK
+            } else {
+                let _response = match self.check_tx_frame(request) {
+                    Ok(frame) => {
+                        CanController::print_can_frame(frame);
+
+                        // If the VIRTIO_CAN_F_CAN_LATE_TX_ACK is negotiated sent the
+                        // frame and wait for it to be sent.
+                        // TODO: Otherwise send it asynchronously.
+                        match self.controller.write().unwrap().can_out(frame) {
+                            Ok(_) => VIRTIO_CAN_RESULT_OK,
+                            Err(_) => {
+                                warn!("we got an error from controller send func");
+                                VIRTIO_CAN_RESULT_NOT_OK
+                            }
+                        }
+                    }
+                    Err(e) => {
+                        warn!("The tx frame had the following error: {}", e);
+                        VIRTIO_CAN_RESULT_NOT_OK
+                    }
+                };
+
+                // If the device cannot send the frame either because socket does not
+                // exist or the writing the frame fails for another unknown reason
+                // then behave as receiving a busoff error.
+                if _response == VIRTIO_CAN_RESULT_NOT_OK {
+                    trace!("Change controller status to STOPPED and busoff to true");
+                    // TODO: Trigger a config_change notification
+                    self.controller.write().unwrap().config.status =
+                        VIRTIO_CAN_S_CTRL_BUSOFF.into();
+                    self.controller.write().unwrap().ctrl_state = CAN_CS_STOPPED;
+                }
+
+                _response
+            };
+
+            writer
+                .write_obj(response)
+                .map_err(|_| Error::DescriptorWriteFailed)?;
+
+            if vring
+                .add_used(desc_chain.head_index(), writer.bytes_written() as u32)
+                .is_err()
+            {
+                warn!("Couldn't return used descriptors to the ring");
+            }
+        }
+
+        Ok(true)
+    }
+
+    pub fn process_rx_requests(
+        &mut self,
+        requests: Vec<CanDescriptorChain>,
+        vring: &VringRwLock,
+    ) -> Result<bool> {
+        if requests.is_empty() {
+            return Ok(true);
+        }
+
+        // This flag, if true, requests a new tx buffer from the front-end
+        let mut req_rx_buf = false;
+
+        for desc_chain in requests {
+            let atomic_mem = self.mem.as_ref().unwrap().memory();
+            let mut writer = desc_chain
+                .clone()
+                .writer(&atomic_mem)
+                .map_err(|_| Error::DescriptorWriteFailed)?;
+
+            let response = match self.controller.write().unwrap().pop() {
+                Ok(item) => {
+                    // If one or more frames have been received then request
+                    // a new rx buffer.
+                    req_rx_buf = true;
+                    item
+                }
+                Err(QueueEmpty) => {
+                    return Ok(req_rx_buf);
+                }
+                Err(_) => {
+                    return Err(Error::HandleEventUnknown);
+                }
+            };
+
+            let can_rx = match self.check_rx_frame(response) {
+                Ok(frame) => frame,
+                Err(e) => {
+                    warn!("The tx frame had the following error: {}", e);
+                    return Err(e);
+                }
+            };
+
+            writer
+                .write_obj(can_rx)
+                .map_err(|_| Error::DescriptorWriteFailed)?;
+
+            if vring
+                .add_used(desc_chain.head_index(), writer.bytes_written() as u32)
+                .is_err()
+            {
+                warn!("Couldn't return used descriptors to the ring");
+            }
+        }
+
+        Ok(true)
+    }
+
+    /// Process the messages in the vring and dispatch replies
+    fn process_ctrl_queue(&mut self, vring: &VringRwLock) -> Result<()> {
+        let requests: Vec<CanDescriptorChain> = vring
+            .get_mut()
+            .get_queue_mut()
+            .iter(self.mem.as_ref().unwrap().memory())
+            .map_err(|_| Error::DescriptorNotFound)?
+            .collect();
+
+        if self.process_ctrl_requests(requests, vring)? {
+            // Send notification once all the requests are processed
+            vring
+                .signal_used_queue()
+                .map_err(|_| Error::NotificationFailed)?;
+        }
+        Ok(())
+    }
+
+    /// Process the messages in the vring and dispatch replies
+    fn process_tx_queue(&self, vring: &VringRwLock) -> Result<()> {
+        let requests: Vec<CanDescriptorChain> = vring
+            .get_mut()
+            .get_queue_mut()
+            .iter(self.mem.as_ref().unwrap().memory())
+            .map_err(|_| Error::DescriptorNotFound)?
+            .collect();
+
+        if self.process_tx_requests(requests, vring)? {
+            // Send notification once all the requests are processed
+            vring
+                .signal_used_queue()
+                .map_err(|_| Error::NotificationFailed)?;
+        }
+
+        Ok(())
+    }
+
+    /// Process the messages in the vring and dispatch replies
+    fn process_rx_queue(&mut self, vring: &VringRwLock) -> Result<()> {
+        let requests: Vec<CanDescriptorChain> = vring
+            .get_mut()
+            .get_queue_mut()
+            .iter(self.mem.as_ref().unwrap().memory())
+            .map_err(|_| Error::DescriptorNotFound)?
+            .collect();
+
+        if self.process_rx_requests(requests, vring)? {
+            // Send notification once all the requests are processed
+            vring
+                .signal_used_queue()
+                .map_err(|_| Error::NotificationFailed)?;
+        }
+        Ok(())
+    }
+
+    /// Set self's VringWorker.
+    pub(crate) fn set_vring_worker(
+        &self,
+        vring_worker: &Arc<VringEpollHandler<Arc<RwLock<VhostUserCanBackend>>>>,
+    ) {
+        let rx_event_fd = self.controller.read().unwrap().rx_event_fd.as_raw_fd();
+        vring_worker
+            .register_listener(rx_event_fd, EventSet::IN, u64::from(BACKEND_EFD))
+            .expect("Fail to register new handler");
+    }
+}
+
+/// VhostUserBackendMut trait methods
+impl VhostUserBackendMut for VhostUserCanBackend {
+    type Vring = VringRwLock;
+    type Bitmap = ();
+
+    fn num_queues(&self) -> usize {
+        NUM_QUEUES
+    }
+
+    fn max_queue_size(&self) -> usize {
+        QUEUE_SIZE
+    }
+
+    fn features(&self) -> u64 {
+        1 << VIRTIO_F_VERSION_1
+            | 1 << VIRTIO_F_NOTIFY_ON_EMPTY
+            | 1 << VIRTIO_RING_F_EVENT_IDX
+            | 1 << VIRTIO_CAN_F_CAN_CLASSIC
+            | 1 << VIRTIO_CAN_F_CAN_FD
+            | 1 << VIRTIO_RING_F_INDIRECT_DESC
+            | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits()
+    }
+
+    fn acked_features(&mut self, _features: u64) {
+        self.acked_features = _features;
+    }
+
+    fn protocol_features(&self) -> VhostUserProtocolFeatures {
+        VhostUserProtocolFeatures::MQ
+            | VhostUserProtocolFeatures::CONFIG
+            | VhostUserProtocolFeatures::REPLY_ACK
+    }
+
+    fn get_config(&self, offset: u32, size: u32) -> Vec<u8> {
+        // SAFETY: The layout of the structure is fixed and can be initialized by
+        // reading its content from byte array.
+        unsafe {
+            from_raw_parts(
+                self.controller
+                    .write()
+                    .unwrap()
+                    .config()
+                    .as_slice()
+                    .as_ptr()
+                    .offset(offset as isize) as *const _ as *const _,
+                size as usize,
+            )
+            .to_vec()
+        }
+    }
+
+    fn set_event_idx(&mut self, enabled: bool) {
+        self.event_idx = enabled;
+    }
+
+    fn update_memory(&mut self, mem: GuestMemoryAtomic<GuestMemoryMmap>) -> IoResult<()> {
+        self.mem = Some(mem);
+        Ok(())
+    }
+
+    fn handle_event(
+        &mut self,
+        device_event: u16,
+        evset: EventSet,
+        vrings: &[VringRwLock],
+        _thread_id: usize,
+    ) -> IoResult<()> {
+        if evset != EventSet::IN {
+            return Err(Error::HandleEventNotEpollIn.into());
+        }
+
+        // If the device is in STOPPED state only TX and CTRL messages can be handled
+        if (self.controller.read().unwrap().ctrl_state == CAN_CS_STOPPED)
+            && ((device_event == RX_QUEUE) || (device_event == BACKEND_EFD))
+        {
+            trace!("Device is stopped!");
+            if device_event == BACKEND_EFD {
+                let _ = self.controller.write().unwrap().rx_event_fd.read();
+            }
+            return Ok(());
+        }
+
+        if device_event == RX_QUEUE && self.controller.write().unwrap().rx_is_empty() {
+            return Ok(());
+        };
+
+        let vring = if device_event != BACKEND_EFD {
+            &vrings[device_event as usize]
+        } else {
+            let _ = self.controller.write().unwrap().rx_event_fd.read();
+            &vrings[RX_QUEUE as usize]
+        };
+
+        if self.event_idx {
+            // vm-virtio's Queue implementation only checks avail_index
+            // once, so to properly support EVENT_IDX we need to keep
+            // calling process_request_queue() until it stops finding
+            // new requests on the queue.
+            loop {
+                vring.disable_notification().unwrap();
+                match device_event {
+                    CTRL_QUEUE => self.process_ctrl_queue(vring),
+                    TX_QUEUE => self.process_tx_queue(vring),
+                    RX_QUEUE => self.process_rx_queue(vring),
+                    BACKEND_EFD => self.process_rx_queue(vring),
+                    _ => Err(Error::HandleEventUnknown),
+                }?;
+                if !vring.enable_notification().unwrap() {
+                    break;
+                }
+            }
+        } else {
+            // Without EVENT_IDX, a single call is enough.
+            match device_event {
+                CTRL_QUEUE => self.process_ctrl_queue(vring),
+                TX_QUEUE => self.process_tx_queue(vring),
+                RX_QUEUE => self.process_rx_queue(vring),
+                BACKEND_EFD => self.process_rx_queue(vring),
+                _ => Err(Error::HandleEventUnknown),
+            }?;
+        }
+        Ok(())
+    }
+
+    fn exit_event(&self, _thread_index: usize) -> Option<EventFd> {
+        self.exit_event.try_clone().ok()
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::virtio_can::{VirtioCanCtrlResponse, VirtioCanTxResponse};
+    use std::mem::size_of;
+    use virtio_bindings::virtio_ring::{VRING_DESC_F_NEXT, VRING_DESC_F_WRITE};
+    use virtio_queue::{mock::MockSplitQueue, Descriptor, Queue};
+    use vm_memory::{Bytes, GuestAddress, GuestMemoryAtomic, GuestMemoryMmap, Le16, Le32};
+
+    #[test]
+    fn test_virtio_can_tx_response_default() {
+        let response = VirtioCanTxResponse::default();
+        assert_eq!(response.result, 0);
+    }
+
+    #[test]
+    fn test_virtio_can_ctrl_request_default() {
+        let request = VirtioCanCtrlRequest::default();
+        assert_eq!(request.msg_type, Le16::default());
+    }
+
+    #[test]
+    fn test_virtio_can_ctrl_response_default() {
+        let response = VirtioCanCtrlResponse::default();
+        assert_eq!(response.result, 0);
+    }
+
+    #[test]
+    fn test_virtio_can_frame_default() {
+        let frame = VirtioCanFrame::default();
+        assert_eq!(frame.msg_type, Le16::default());
+        assert_eq!(frame.length, Le16::default());
+        assert_eq!(frame.reserved, Le32::default());
+        assert_eq!(frame.flags, Le32::default());
+        assert_eq!(frame.can_id, Le32::default());
+        assert_eq!(frame.sdu, [0; 64]);
+    }
+
+    #[test]
+    fn test_virtio_can_empty_requests() {
+        let controller =
+            CanController::new("can0".to_string()).expect("Could not build controller");
+        let controller = Arc::new(RwLock::new(controller));
+        let mut vu_can_backend =
+            VhostUserCanBackend::new(controller.clone()).expect("Could not build vhucan device");
+        let mem = GuestMemoryAtomic::new(
+            GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x1000)]).unwrap(),
+        );
+        let vring = VringRwLock::new(mem.clone(), 0x1000).unwrap();
+
+        // Empty descriptor chain should be ignored
+        assert!(vu_can_backend
+            .process_rx_requests(Vec::<CanDescriptorChain>::new(), &vring)
+            .expect("Fail to examin empty rx vring"));
+        assert!(vu_can_backend
+            .process_tx_requests(Vec::<CanDescriptorChain>::new(), &vring)
+            .expect("Fail to examin empty tx vring"));
+        assert!(vu_can_backend
+            .process_ctrl_requests(Vec::<CanDescriptorChain>::new(), &vring)
+            .expect("Fail to examin empty ctrl vring"));
+    }
+
+    #[test]
+    fn test_virtio_can_empty_handle_request() {
+        let controller =
+            CanController::new("can0".to_string()).expect("Could not build controller");
+        let controller = Arc::new(RwLock::new(controller));
+        let mut vu_can_backend =
+            VhostUserCanBackend::new(controller.clone()).expect("Could not build vhucan device");
+        let mem = GuestMemoryAtomic::new(
+            GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x1000)]).unwrap(),
+        );
+        vu_can_backend.update_memory(mem.clone()).unwrap();
+
+        let vring = VringRwLock::new(mem, 0x1000).unwrap();
+        vring.set_queue_info(0x100, 0x200, 0x300).unwrap();
+        vring.set_queue_ready(true);
+        let list_vrings = [vring.clone(), vring.clone(), vring.clone(), vring.clone()];
+
+        vu_can_backend
+            .handle_event(RX_QUEUE, EventSet::IN, &list_vrings, 0)
+            .unwrap();
+
+        vu_can_backend
+            .handle_event(TX_QUEUE, EventSet::IN, &list_vrings, 0)
+            .unwrap();
+
+        vu_can_backend
+            .handle_event(CTRL_QUEUE, EventSet::IN, &list_vrings, 0)
+            .unwrap();
+
+        vu_can_backend
+            .handle_event(BACKEND_EFD, EventSet::IN, &list_vrings, 0)
+            .unwrap();
+    }
+
+    fn build_desc_chain_mem(
+        mem: &GuestMemoryMmap,
+        count: u16,
+        flags: Vec<u16>,
+        len: u32,
+    ) -> CanDescriptorChain {
+        let vq = MockSplitQueue::new(mem, 16);
+        let mut desc_vec = Vec::new();
+
+        //Create a descriptor chain with count descriptors.
+        for i in 0..count {
+            let desc_flags = if i < count - 1 {
+                flags[i as usize] | VRING_DESC_F_NEXT as u16
+            } else {
+                flags[i as usize] & !VRING_DESC_F_NEXT as u16
+            };
+
+            let desc = Descriptor::new((0x100 * (i + 1)) as u64, len, desc_flags, i + 1);
+            desc_vec.push(desc);
+        }
+
+        vq.add_desc_chains(&desc_vec, 0).unwrap();
+
+        // Create descriptor chain from pre-filled memory
+        vq.create_queue::<Queue>()
+            .unwrap()
+            .iter(GuestMemoryAtomic::new(mem.clone()).memory())
+            .unwrap()
+            .next()
+            .unwrap()
+    }
+
+    #[test]
+    fn test_virtio_can_ctrl_request() {
+        // Initialize can device and vhost-device-can backend
+        let controller =
+            CanController::new("can0".to_string()).expect("Could not build controller");
+        let controller = Arc::new(RwLock::new(controller));
+        let mut vu_can_backend =
+            VhostUserCanBackend::new(controller.clone()).expect("Could not build vhucan device");
+        let mem = GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x1000)]).unwrap();
+
+        // Test 1: Since we provide only one write only, an error will be trigger
+        //         the reader will have 0 data.
+        let can_mes_len = size_of::<VirtioCanCtrlRequest>();
+        let desc_chain = build_desc_chain_mem(
+            &mem,
+            1,
+            vec![VRING_DESC_F_WRITE as u16],
+            can_mes_len.try_into().unwrap(),
+        );
+        let mem1 = GuestMemoryAtomic::new(mem.clone());
+        let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap();
+        vu_can_backend.update_memory(mem1).unwrap();
+
+        assert_eq!(
+            vu_can_backend
+                .process_ctrl_requests(vec![desc_chain], &vring)
+                .unwrap_err(),
+            Error::DescriptorReadFailed
+        );
+
+        // Test 2: Two write only descriptors are available, so the reader
+        //         will complain for having 0 data
+        let can_mes_len = size_of::<VirtioCanCtrlRequest>();
+        let desc_chain = build_desc_chain_mem(
+            &mem,
+            2,
+            vec![VRING_DESC_F_WRITE as u16, VRING_DESC_F_WRITE as u16],
+            can_mes_len.try_into().unwrap(),
+        );
+        let mem1 = GuestMemoryAtomic::new(mem.clone());
+        let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap();
+        vu_can_backend.update_memory(mem1).unwrap();
+
+        assert_eq!(
+            vu_can_backend
+                .process_ctrl_requests(vec![desc_chain], &vring)
+                .unwrap_err(),
+            Error::DescriptorReadFailed
+        );
+
+        // Test 3: The reader descriptor has two bytes of data
+        //         but are initialized to 0 -> Unknown control message
+        let can_mes_len = size_of::<VirtioCanCtrlRequest>();
+        let desc_chain = build_desc_chain_mem(
+            &mem,
+            2,
+            vec![0, VRING_DESC_F_WRITE as u16],
+            can_mes_len.try_into().unwrap(),
+        );
+        let mem1 = GuestMemoryAtomic::new(mem.clone());
+        let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap();
+        vu_can_backend.update_memory(mem1).unwrap();
+
+        assert!(vu_can_backend
+            .process_ctrl_requests(vec![desc_chain.clone()], &vring)
+            .unwrap());
+
+        let can_frame_res = desc_chain
+            .memory()
+            .read_obj::<u8>(vm_memory::GuestAddress(0x200_u64))
+            .map_err(|_| Error::DescriptorReadFailed)
+            .unwrap();
+
+        assert_eq!(VIRTIO_CAN_RESULT_NOT_OK, can_frame_res);
+
+        // Test 4: Successfull test for VIRTIO_CAN_SET_CTRL_MODE_START
+        let can_mes_len = size_of::<VirtioCanCtrlRequest>();
+        let desc_chain = build_desc_chain_mem(
+            &mem,
+            2,
+            vec![0, VRING_DESC_F_WRITE as u16],
+            can_mes_len.try_into().unwrap(),
+        );
+        let mem1 = GuestMemoryAtomic::new(mem.clone());
+        let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap();
+        vu_can_backend.update_memory(mem1).unwrap();
+
+        let ctrl_msg: u16 = VIRTIO_CAN_SET_CTRL_MODE_START;
+        desc_chain
+            .memory()
+            .write_obj(ctrl_msg, vm_memory::GuestAddress(0x100_u64))
+            .unwrap();
+
+        // Write a value on the writer which does not represent known messages
+        desc_chain
+            .memory()
+            .write_obj(5, vm_memory::GuestAddress(0x200_u64))
+            .unwrap();
+
+        assert!(vu_can_backend
+            .process_ctrl_requests(vec![desc_chain.clone()], &vring)
+            .unwrap());
+
+        let can_frame_res = desc_chain
+            .memory()
+            .read_obj::<u8>(vm_memory::GuestAddress(0x200_u64))
+            .map_err(|_| Error::DescriptorReadFailed)
+            .unwrap();
+
+        assert_eq!(VIRTIO_CAN_RESULT_OK, can_frame_res);
+
+        // Test 5: Successfull test for VIRTIO_CAN_SET_CTRL_MODE_STOP
+        let can_mes_len = size_of::<VirtioCanCtrlRequest>();
+        let desc_chain = build_desc_chain_mem(
+            &mem,
+            2,
+            vec![0, VRING_DESC_F_WRITE as u16],
+            can_mes_len.try_into().unwrap(),
+        );
+        let mem1 = GuestMemoryAtomic::new(mem.clone());
+        let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap();
+        vu_can_backend.update_memory(mem1).unwrap();
+
+        let ctrl_msg: u16 = VIRTIO_CAN_SET_CTRL_MODE_STOP;
+        desc_chain
+            .memory()
+            .write_obj(ctrl_msg, vm_memory::GuestAddress(0x100_u64))
+            .unwrap();
+
+        // Write a value on the writer which does not represent known messages
+        desc_chain
+            .memory()
+            .write_obj(5, vm_memory::GuestAddress(0x200_u64))
+            .unwrap();
+
+        assert!(vu_can_backend
+            .process_ctrl_requests(vec![desc_chain.clone()], &vring)
+            .unwrap());
+
+        let can_frame_res = desc_chain
+            .memory()
+            .read_obj::<u8>(vm_memory::GuestAddress(0x200_u64))
+            .map_err(|_| Error::DescriptorReadFailed)
+            .unwrap();
+
+        assert_eq!(VIRTIO_CAN_RESULT_OK, can_frame_res);
+
+        // Test 6: Since we provide only one read only, an error will be trigger
+        //         about the writer having 0 data
+        let can_mes_len = size_of::<VirtioCanCtrlRequest>();
+        let desc_chain = build_desc_chain_mem(&mem, 1, vec![0], can_mes_len.try_into().unwrap());
+        let mem1 = GuestMemoryAtomic::new(mem.clone());
+        let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap();
+        vu_can_backend.update_memory(mem1).unwrap();
+
+        let ctrl_msg: u16 = VIRTIO_CAN_SET_CTRL_MODE_START;
+        desc_chain
+            .memory()
+            .write_obj(ctrl_msg, vm_memory::GuestAddress(0x100_u64))
+            .unwrap();
+
+        assert_eq!(
+            vu_can_backend
+                .process_ctrl_requests(vec![desc_chain], &vring)
+                .unwrap_err(),
+            Error::DescriptorWriteFailed
+        );
+
+        // Test 7: Two read only descriptors are available, so the writer
+        //         will complain for having 0 data
+        let can_mes_len = size_of::<VirtioCanCtrlRequest>();
+        let desc_chain = build_desc_chain_mem(&mem, 2, vec![0, 0], can_mes_len.try_into().unwrap());
+        let mem1 = GuestMemoryAtomic::new(mem.clone());
+        let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap();
+        vu_can_backend.update_memory(mem1).unwrap();
+
+        let ctrl_msg: u16 = VIRTIO_CAN_SET_CTRL_MODE_STOP;
+        desc_chain
+            .memory()
+            .write_obj(ctrl_msg, vm_memory::GuestAddress(0x100_u64))
+            .unwrap();
+
+        assert_eq!(
+            vu_can_backend
+                .process_ctrl_requests(vec![desc_chain], &vring)
+                .unwrap_err(),
+            Error::DescriptorWriteFailed
+        );
+
+        // Test 8: If we interchange the write read descriptors then
+        //         it will fail!
+
+        let can_mes_len = size_of::<VirtioCanCtrlRequest>();
+        let desc_chain = build_desc_chain_mem(
+            &mem,
+            2,
+            vec![VRING_DESC_F_WRITE as u16, 0],
+            can_mes_len.try_into().unwrap(),
+        );
+        let mem1 = GuestMemoryAtomic::new(mem.clone());
+        let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap();
+        vu_can_backend.update_memory(mem1).unwrap();
+
+        let ctrl_msg: u16 = VIRTIO_CAN_SET_CTRL_MODE_START;
+        desc_chain
+            .memory()
+            .write_obj(ctrl_msg, vm_memory::GuestAddress(0x200_u64))
+            .unwrap();
+
+        // Write a value on the writer which does not represent known messages
+        desc_chain
+            .memory()
+            .write_obj(5, vm_memory::GuestAddress(0x100_u64))
+            .unwrap();
+
+        assert!(vu_can_backend
+            .process_ctrl_requests(vec![desc_chain.clone()], &vring)
+            .unwrap());
+
+        let can_frame_res = desc_chain
+            .memory()
+            .read_obj::<u8>(vm_memory::GuestAddress(0x100_u64))
+            .map_err(|_| Error::DescriptorReadFailed)
+            .unwrap();
+
+        assert_eq!(VIRTIO_CAN_RESULT_OK, can_frame_res);
+    }
+
+    #[test]
+    fn test_virtio_can_check_tx_unknown_frame() {
+        let controller =
+            CanController::new("can0".to_string()).expect("Could not build controller");
+        let controller = Arc::new(RwLock::new(controller));
+        let vu_can_backend =
+            VhostUserCanBackend::new(controller.clone()).expect("Could not build vhucan device");
+
+        let frame = VirtioCanFrame {
+            msg_type: 0.into(),
+            can_id: 0.into(),
+            length: 0.into(),
+            reserved: 0.into(),
+            flags: 0.into(),
+            sdu: [0; 64],
+        };
+
+        assert_eq!(
+            vu_can_backend.check_tx_frame(frame).unwrap_err(),
+            Error::UnexpectedCanMsgType(0)
+        );
+    }
+
+    #[test]
+    fn test_virtio_can_check_tx_can_frame() {
+        let controller =
+            CanController::new("can0".to_string()).expect("Could not build controller");
+        let controller = Arc::new(RwLock::new(controller));
+        let mut vu_can_backend =
+            VhostUserCanBackend::new(controller.clone()).expect("Could not build vhucan device");
+
+        // Test 1: UnexpectedClassicFlag
+        let frame = VirtioCanFrame {
+            msg_type: VIRTIO_CAN_TX.into(),
+            can_id: 0.into(),
+            length: 4.into(),
+            reserved: 0.into(),
+            flags: 0.into(),
+            sdu: [0; 64],
+        };
+
+        assert_eq!(
+            vu_can_backend.check_tx_frame(frame).unwrap_err(),
+            Error::UnexpectedClassicFlag
+        );
+
+        // Test 2: Return the same length
+        vu_can_backend.acked_features(1 << VIRTIO_CAN_F_CAN_CLASSIC);
+
+        assert_eq!(
+            vu_can_backend.check_tx_frame(frame).unwrap().length,
+            frame.length
+        );
+
+        // Test 3: Return Error::InvalidCanLength(frame_length) when length is out-of-range (>8)
+        let frame = VirtioCanFrame {
+            msg_type: VIRTIO_CAN_TX.into(),
+            can_id: 0.into(),
+            length: 40.into(),
+            reserved: 0.into(),
+            flags: 0.into(),
+            sdu: [0; 64],
+        };
+
+        assert_eq!(
+            vu_can_backend.check_tx_frame(frame).unwrap_err(),
+            Error::InvalidCanLength(40)
+        );
+    }
+
+    #[test]
+    fn test_virtio_can_check_tx_canfd_frame() {
+        let controller =
+            CanController::new("can0".to_string()).expect("Could not build controller");
+        let controller = Arc::new(RwLock::new(controller));
+        let mut vu_can_backend =
+            VhostUserCanBackend::new(controller).expect("Could not build vhucan device");
+
+        // Enable VIRTIO_CAN_F_CAN_FD feature
+        vu_can_backend.acked_features(1 << VIRTIO_CAN_F_CAN_FD);
+
+        // Test 1: If no VIRTIO_CAN_FLAGS_FD in flag return UnexpectedClassicFlag
+        let frame = VirtioCanFrame {
+            msg_type: VIRTIO_CAN_TX.into(),
+            can_id: 0.into(),
+            length: 12.into(),
+            reserved: 0.into(),
+            flags: 0.into(),
+            sdu: [0; 64],
+        };
+
+        assert_eq!(
+            vu_can_backend.check_tx_frame(frame).unwrap_err(),
+            Error::UnexpectedClassicFlag
+        );
+
+        // Test 2: If VIRTIO_CAN_FLAGS_FD is in flag check if return message has
+        //         CAN_FRMF_TYPE_FD in flags.
+        let frame = VirtioCanFrame {
+            msg_type: VIRTIO_CAN_TX.into(),
+            can_id: 0.into(),
+            length: 12.into(),
+            reserved: 0.into(),
+            flags: VIRTIO_CAN_FLAGS_FD.into(),
+            sdu: [0; 64],
+        };
+
+        assert_eq!(
+            vu_can_backend
+                .check_tx_frame(frame)
+                .unwrap()
+                .flags
+                .to_native()
+                & CAN_FRMF_TYPE_FD,
+            CAN_FRMF_TYPE_FD
+        );
+
+        // Test 3: If 1 is not a valid CAN flag return InvalidCanFlags(1).
+        let frame = VirtioCanFrame {
+            msg_type: VIRTIO_CAN_TX.into(),
+            can_id: 1.into(),
+            length: 12.into(),
+            reserved: 0.into(),
+            flags: 0x1.into(),
+            sdu: [0; 64],
+        };
+
+        assert_eq!(
+            vu_can_backend.check_tx_frame(frame).unwrap_err(),
+            Error::InvalidCanFlags(1)
+        );
+
+        // Test 4: receive frame with the same length if length is < 64 but not
+        //         one of [12, 16, 20, 24, 32, 48, 64] -> InvalidCanLength(40)]
+        let frame = VirtioCanFrame {
+            msg_type: VIRTIO_CAN_TX.into(),
+            can_id: 0.into(),
+            length: 40.into(),
+            reserved: 0.into(),
+            flags: VIRTIO_CAN_FLAGS_FD.into(),
+            sdu: [0; 64],
+        };
+
+        assert_eq!(
+            vu_can_backend.check_tx_frame(frame).unwrap_err(),
+            Error::InvalidCanLength(40)
+        );
+
+        // Test 5: receive frame with length is > 64
+        //         then -> InvalidCanLength(frame_length).
+        let frame = VirtioCanFrame {
+            msg_type: VIRTIO_CAN_TX.into(),
+            can_id: 0.into(),
+            length: 80.into(),
+            reserved: 0.into(),
+            flags: VIRTIO_CAN_FLAGS_FD.into(),
+            sdu: [0; 64],
+        };
+
+        assert_eq!(
+            vu_can_backend.check_tx_frame(frame).unwrap_err(),
+            Error::InvalidCanLength(80)
+        );
+
+        // Test 6: receive frame with length in [12, 16, 20, 24, 32, 48, 64]
+        let frame = VirtioCanFrame {
+            msg_type: VIRTIO_CAN_TX.into(),
+            can_id: 0.into(),
+            length: 48.into(),
+            reserved: 0.into(),
+            flags: VIRTIO_CAN_FLAGS_FD.into(),
+            sdu: [0; 64],
+        };
+
+        assert_eq!(vu_can_backend.check_tx_frame(frame).unwrap().length, 48);
+    }
+
+    #[test]
+    fn test_virtio_can_check_tx_rtr_frame() {
+        let controller =
+            CanController::new("can0".to_string()).expect("Could not build controller");
+        let controller = Arc::new(RwLock::new(controller));
+        let mut vu_can_backend =
+            VhostUserCanBackend::new(controller.clone()).expect("Could not build vhucan device");
+
+        // Test 1: Take a valid CAN / CANFD message and try to enable RTR in flags.
+        //         the test should fail because VIRTIO_CAN_F_CAN_CLASSIC and
+        //         VIRTIO_CAN_F_RTR_FRAMES are not negotiated.
+        let frame = VirtioCanFrame {
+            msg_type: VIRTIO_CAN_TX.into(),
+            can_id: 0.into(),
+            length: 8.into(),
+            reserved: 0.into(),
+            flags: VIRTIO_CAN_FLAGS_RTR.into(),
+            sdu: [0; 64],
+        };
+
+        assert_eq!(
+            vu_can_backend.check_tx_frame(frame).unwrap_err(),
+            Error::UnexpectedRtrFlag
+        );
+
+        // Test 2: Take a valid CAN / CANFD message and try to enable RTR in flags.
+        //         the test should fail because VIRTIO_CAN_F_CAN_CLASSIC is not negotiated.
+        vu_can_backend.acked_features(1 << VIRTIO_CAN_F_RTR_FRAMES);
+
+        assert_eq!(
+            vu_can_backend.check_tx_frame(frame).unwrap_err(),
+            Error::UnexpectedRtrFlag
+        );
+
+        // Test 3: Take a valid CAN / CANFD message and try to enable RTR in flags.
+        //         the test should succeed because VIRTIO_CAN_F_CAN_CLASSIC is negotiated.
+        vu_can_backend
+            .acked_features((1 << VIRTIO_CAN_F_RTR_FRAMES) | (1 << VIRTIO_CAN_F_CAN_CLASSIC));
+
+        assert_eq!(
+            vu_can_backend
+                .check_tx_frame(frame)
+                .unwrap()
+                .can_id
+                .to_native()
+                & CAN_RTR_FLAG,
+            CAN_RTR_FLAG
+        );
+
+        // Test 4: Take a valid CAN / CANFD message and try to enable RTR in flags.
+        //         the test should fail because VIRTIO_CAN_F_CAN_CLASSIC is not negotiated,
+        //         and RTR does not work with VIRTIO_CAN_F_CAN_FD.
+        vu_can_backend.acked_features((1 << VIRTIO_CAN_F_RTR_FRAMES) | (1 << VIRTIO_CAN_F_CAN_FD));
+
+        assert_eq!(
+            vu_can_backend.check_tx_frame(frame).unwrap_err(),
+            Error::UnexpectedRtrFlag
+        );
+    }
+
+    #[test]
+    fn test_virtio_can_check_tx_eff_frame() {
+        let controller =
+            CanController::new("can0".to_string()).expect("Could not build controller");
+        let controller = Arc::new(RwLock::new(controller));
+        let mut vu_can_backend =
+            VhostUserCanBackend::new(controller.clone()).expect("Could not build vhucan device");
+
+        // This test is valid for both CAN & CANFD messages, so for simplicity
+        // we will check only CAN case.
+        vu_can_backend.acked_features(1 << VIRTIO_CAN_F_CAN_CLASSIC);
+
+        // Test 1: Received message should not have CAN_EFF_FLAG in can_id
+        let mut frame = VirtioCanFrame {
+            msg_type: VIRTIO_CAN_TX.into(),
+            can_id: 0.into(),
+            length: 8.into(),
+            reserved: 0.into(),
+            flags: 0.into(),
+            sdu: [0; 64],
+        };
+
+        assert_eq!(
+            vu_can_backend
+                .check_tx_frame(frame)
+                .unwrap()
+                .can_id
+                .to_native()
+                & CAN_EFF_FLAG,
+            0
+        );
+
+        // Test 2: If VIRTIO_CAN_FLAGS_EXTENDED is NOT enabled, CAN ID should
+        //         be smaller than 11 bits
+        frame.can_id = (CAN_SFF_MASK + 1).into(); // CAN_SFF_MASK = 0x7FFU
+        assert_eq!(
+            vu_can_backend.check_tx_frame(frame).unwrap_err(),
+            Error::UnexpectedCanId(11)
+        );
+
+        // Test 3: Received message should have CAN_EFF_MASK in can_id
+        frame.flags = VIRTIO_CAN_FLAGS_EXTENDED.into();
+        assert_eq!(
+            vu_can_backend
+                .check_tx_frame(frame)
+                .unwrap()
+                .can_id
+                .to_native()
+                & CAN_EFF_FLAG,
+            CAN_EFF_FLAG
+        );
+
+        // Test 4: If VIRTIO_CAN_FLAGS_EXTENDED is enabled, CAN ID should be
+        //         smaller than 29 bits
+        frame.can_id = (CAN_EFF_MASK + 1).into(); // CAN_EFF_MASK = 0x1FFFFFFFU
+        assert_eq!(
+            vu_can_backend.check_tx_frame(frame).unwrap_err(),
+            Error::UnexpectedCanId(29)
+        );
+    }
+
+    #[test]
+    fn test_virtio_can_tx_general_tests() {
+        let controller =
+            CanController::new("can0".to_string()).expect("Could not build controller");
+        let controller = Arc::new(RwLock::new(controller));
+        let mut vu_can_backend =
+            VhostUserCanBackend::new(controller.clone()).expect("Could not build vhucan device");
+        let mem = GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x1000)]).unwrap();
+
+        // Any number of descriptor different than 2 will generate an error
+        let count = 1;
+
+        // Test 1: Provide only write only descriptor -> Fail
+        let desc_chain = build_desc_chain_mem(&mem, count, vec![VRING_DESC_F_WRITE as u16], 0x200);
+        let mem1 = GuestMemoryAtomic::new(mem.clone());
+        let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap();
+        vu_can_backend.update_memory(mem1).unwrap();
+
+        assert_eq!(
+            vu_can_backend
+                .process_tx_requests(vec![desc_chain.clone()], &vring)
+                .unwrap_err(),
+            Error::DescriptorReadFailed
+        );
+
+        // Test 2: Provide only read only descriptor -> Fail
+        let desc_chain = build_desc_chain_mem(&mem, 1, vec![0], 0x200);
+        let mem1 = GuestMemoryAtomic::new(mem.clone());
+        let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap();
+        vu_can_backend.update_memory(mem1).unwrap();
+
+        assert_eq!(
+            vu_can_backend
+                .process_tx_requests(vec![desc_chain.clone()], &vring)
+                .unwrap_err(),
+            Error::DescriptorWriteFailed
+        );
+
+        // Test 3: Provide only write only descriptors -> Fail
+        let desc_chain = build_desc_chain_mem(
+            &mem,
+            2,
+            vec![VRING_DESC_F_WRITE as u16, VRING_DESC_F_WRITE as u16],
+            0x200,
+        );
+        let mem1 = GuestMemoryAtomic::new(mem.clone());
+        let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap();
+        vu_can_backend.update_memory(mem1).unwrap();
+
+        assert_eq!(
+            vu_can_backend
+                .process_tx_requests(vec![desc_chain.clone()], &vring)
+                .unwrap_err(),
+            Error::DescriptorReadFailed
+        );
+
+        // Test 4: Provide only read only descriptors -> Fail
+        let desc_chain = build_desc_chain_mem(&mem, 2, vec![0, 0], 0x200);
+        let mem1 = GuestMemoryAtomic::new(mem.clone());
+        let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap();
+        vu_can_backend.update_memory(mem1).unwrap();
+        assert_eq!(
+            vu_can_backend
+                .process_tx_requests(vec![desc_chain.clone()], &vring)
+                .unwrap_err(),
+            Error::DescriptorWriteFailed
+        );
+
+        // Test 5: Provide correct descriptors but 0 size -> Fail
+        let desc_chain = build_desc_chain_mem(&mem, 2, vec![0, VRING_DESC_F_WRITE as u16], 0x0);
+        let mem1 = GuestMemoryAtomic::new(mem.clone());
+        let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap();
+        vu_can_backend.update_memory(mem1).unwrap();
+
+        assert_eq!(
+            vu_can_backend
+                .process_tx_requests(vec![desc_chain.clone()], &vring)
+                .unwrap_err(),
+            Error::DescriptorReadFailed
+        );
+
+        // Test 6: Provide correct descriptors and size
+        let can_mes_len = size_of::<VirtioCanFrame>();
+        let desc_chain = build_desc_chain_mem(
+            &mem,
+            2,
+            vec![0, VRING_DESC_F_WRITE as u16],
+            can_mes_len.try_into().unwrap(),
+        );
+        let mem1 = GuestMemoryAtomic::new(mem.clone());
+        let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap();
+        vu_can_backend.update_memory(mem1).unwrap();
+        assert!(vu_can_backend
+            .process_tx_requests(vec![desc_chain], &vring)
+            .unwrap());
+    }
+
+    #[test]
+    fn test_virtio_can_tx_device_stopped_test() {
+        let controller =
+            CanController::new("can0".to_string()).expect("Could not build controller");
+        let controller = Arc::new(RwLock::new(controller));
+        let mut vu_can_backend =
+            VhostUserCanBackend::new(controller.clone()).expect("Could not build vhucan device");
+        let mem = GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x1000)]).unwrap();
+
+        // Enable VIRTIO_CAN_F_CAN_CLASSIC feature
+        vu_can_backend.acked_features(1 << VIRTIO_CAN_F_CAN_CLASSIC);
+
+        let can_mes_len = size_of::<VirtioCanFrame>();
+        let desc_chain = build_desc_chain_mem(
+            &mem,
+            2,
+            vec![0, VRING_DESC_F_WRITE as u16],
+            can_mes_len.try_into().unwrap(),
+        );
+        let mem1 = GuestMemoryAtomic::new(mem.clone());
+        let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap();
+        vu_can_backend.update_memory(mem1).unwrap();
+
+        let frame = VirtioCanFrame {
+            msg_type: VIRTIO_CAN_TX.into(),
+            can_id: 123.into(),
+            length: 8.into(),
+            reserved: 0.into(),
+            flags: 0.into(),
+            sdu: [0; 64],
+        };
+
+        desc_chain
+            .memory()
+            .write_obj(frame, vm_memory::GuestAddress(0x100_u64))
+            .unwrap();
+
+        desc_chain
+            .memory()
+            .write_obj(5, vm_memory::GuestAddress(0x200_u64))
+            .unwrap();
+
+        assert!(vu_can_backend
+            .process_tx_requests(vec![desc_chain.clone()], &vring)
+            .unwrap());
+
+        let can_frame_res = desc_chain
+            .memory()
+            .read_obj::<u8>(vm_memory::GuestAddress(0x200_u64))
+            .map_err(|_| Error::DescriptorReadFailed)
+            .unwrap();
+
+        assert_eq!(VIRTIO_CAN_RESULT_NOT_OK, can_frame_res);
+    }
+
+    #[test]
+    fn test_virtio_can_tx_device_started_test_send_fail() {
+        let controller =
+            CanController::new("can0".to_string()).expect("Could not build controller");
+        let controller = Arc::new(RwLock::new(controller));
+        let mut vu_can_backend =
+            VhostUserCanBackend::new(controller.clone()).expect("Could not build vhucan device");
+        let mem = GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x1000)]).unwrap();
+
+        // Enable VIRTIO_CAN_F_CAN_CLASSIC feature
+        vu_can_backend.acked_features(1 << VIRTIO_CAN_F_CAN_CLASSIC);
+
+        // Start the device
+        controller.write().unwrap().ctrl_state = CAN_CS_STARTED;
+
+        let can_mes_len = size_of::<VirtioCanFrame>();
+        let desc_chain = build_desc_chain_mem(
+            &mem,
+            2,
+            vec![0, VRING_DESC_F_WRITE as u16],
+            can_mes_len.try_into().unwrap(),
+        );
+        let mem1 = GuestMemoryAtomic::new(mem.clone());
+        let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap();
+        vu_can_backend.update_memory(mem1).unwrap();
+
+        let frame = VirtioCanFrame {
+            msg_type: VIRTIO_CAN_TX.into(),
+            can_id: 123.into(),
+            length: 8.into(),
+            reserved: 0.into(),
+            flags: 0.into(),
+            sdu: [0; 64],
+        };
+
+        desc_chain
+            .memory()
+            .write_obj(frame, vm_memory::GuestAddress(0x100_u64))
+            .unwrap();
+
+        desc_chain
+            .memory()
+            .write_obj(5, vm_memory::GuestAddress(0x200_u64))
+            .unwrap();
+
+        assert!(vu_can_backend
+            .process_tx_requests(vec![desc_chain.clone()], &vring)
+            .unwrap());
+
+        let can_frame_res = desc_chain
+            .memory()
+            .read_obj::<u8>(vm_memory::GuestAddress(0x200_u64))
+            .map_err(|_| Error::DescriptorReadFailed)
+            .unwrap();
+
+        assert_eq!(VIRTIO_CAN_RESULT_NOT_OK, can_frame_res);
+    }
+
+    #[test]
+    fn test_virtio_can_tx_device_started_check_frame_fail() {
+        let controller =
+            CanController::new("can0".to_string()).expect("Could not build controller");
+        let controller = Arc::new(RwLock::new(controller));
+        let mut vu_can_backend =
+            VhostUserCanBackend::new(controller.clone()).expect("Could not build vhucan device");
+        let mem = GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x1000)]).unwrap();
+
+        // Start the device
+        controller.write().unwrap().ctrl_state = CAN_CS_STARTED;
+
+        let can_mes_len = size_of::<VirtioCanFrame>();
+        let desc_chain = build_desc_chain_mem(
+            &mem,
+            2,
+            vec![0, VRING_DESC_F_WRITE as u16],
+            can_mes_len.try_into().unwrap(),
+        );
+        let mem1 = GuestMemoryAtomic::new(mem.clone());
+        let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap();
+        vu_can_backend.update_memory(mem1).unwrap();
+
+        let frame = VirtioCanFrame {
+            msg_type: 0.into(),
+            can_id: 123.into(),
+            length: 8.into(),
+            reserved: 0.into(),
+            flags: 0.into(),
+            sdu: [0; 64],
+        };
+
+        desc_chain
+            .memory()
+            .write_obj(frame, vm_memory::GuestAddress(0x100_u64))
+            .unwrap();
+
+        desc_chain
+            .memory()
+            .write_obj(5, vm_memory::GuestAddress(0x200_u64))
+            .unwrap();
+
+        assert!(vu_can_backend
+            .process_tx_requests(vec![desc_chain.clone()], &vring)
+            .unwrap());
+
+        let can_frame_res = desc_chain
+            .memory()
+            .read_obj::<u8>(vm_memory::GuestAddress(0x200_u64))
+            .map_err(|_| Error::DescriptorReadFailed)
+            .unwrap();
+
+        assert_eq!(VIRTIO_CAN_RESULT_NOT_OK, can_frame_res);
+    }
+
+    #[test]
+    fn test_virtio_can_check_rx_err_frame() {
+        let controller =
+            CanController::new("can0".to_string()).expect("Could not build controller");
+        let controller = Arc::new(RwLock::new(controller));
+        let vu_can_backend =
+            VhostUserCanBackend::new(controller.clone()).expect("Could not build vhucan device");
+
+        let frame = VirtioCanFrame {
+            msg_type: 0.into(),
+            can_id: CAN_ERR_FLAG.into(),
+            length: 0.into(),
+            reserved: 0.into(),
+            flags: 0.into(),
+            sdu: [0; 64],
+        };
+
+        assert_eq!(
+            vu_can_backend.check_rx_frame(frame).unwrap_err(),
+            Error::RxFrameUnknownFail
+        );
+
+        let frame = VirtioCanFrame {
+            msg_type: 0.into(),
+            can_id: (CAN_ERR_FLAG | CAN_ERR_BUSOFF).into(),
+            length: 0.into(),
+            reserved: 0.into(),
+            flags: 0.into(),
+            sdu: [0; 64],
+        };
+
+        assert_eq!(
+            vu_can_backend.check_rx_frame(frame).unwrap_err(),
+            Error::BusoffRxFrame
+        );
+
+        assert_eq!(
+            controller.read().unwrap().config.status.to_native(),
+            VIRTIO_CAN_S_CTRL_BUSOFF
+        );
+        assert_eq!(controller.read().unwrap().ctrl_state, CAN_CS_STOPPED);
+    }
+
+    #[test]
+    fn test_virtio_can_check_rx_features_not_negotiated() {
+        let controller =
+            CanController::new("can0".to_string()).expect("Could not build controller");
+        let controller = Arc::new(RwLock::new(controller));
+        let vu_can_backend =
+            VhostUserCanBackend::new(controller.clone()).expect("Could not build vhucan device");
+
+        let frame = VirtioCanFrame {
+            msg_type: 0.into(),
+            can_id: 0.into(),
+            length: 0.into(),
+            reserved: 0.into(),
+            flags: CAN_FRMF_TYPE_FD.into(),
+            sdu: [0; 64],
+        };
+
+        assert_eq!(
+            vu_can_backend.check_rx_frame(frame).unwrap_err(),
+            Error::UnexpectedFdFlag
+        );
+
+        let frame = VirtioCanFrame {
+            msg_type: 0.into(),
+            can_id: 0.into(),
+            length: 0.into(),
+            reserved: 0.into(),
+            flags: 0.into(),
+            sdu: [0; 64],
+        };
+
+        assert_eq!(
+            vu_can_backend.check_rx_frame(frame).unwrap_err(),
+            Error::UnexpectedClassicFlag
+        );
+    }
+
+    #[test]
+    fn test_virtio_can_check_rx_eff_frame() {
+        let controller =
+            CanController::new("can0".to_string()).expect("Could not build controller");
+        let controller = Arc::new(RwLock::new(controller));
+        let mut vu_can_backend =
+            VhostUserCanBackend::new(controller.clone()).expect("Could not build vhucan device");
+
+        // This test is valid for both CAN & CANFD messages, so for simplicity
+        // we will check only CAN case.
+        vu_can_backend.acked_features(1 << VIRTIO_CAN_F_CAN_CLASSIC);
+
+        // Test 1: Received message should not have CAN_EFF_FLAG in can_id
+        let mut frame = VirtioCanFrame {
+            msg_type: VIRTIO_CAN_TX.into(),
+            can_id: 0.into(),
+            length: 8.into(),
+            reserved: 0.into(),
+            flags: 0.into(),
+            sdu: [0; 64],
+        };
+
+        assert_eq!(
+            vu_can_backend
+                .check_rx_frame(frame)
+                .unwrap()
+                .can_id
+                .to_native()
+                & CAN_EFF_FLAG,
+            0
+        );
+
+        // Test 2: Received message's can_id should be smaller than CAN_SFF_MASK
+        frame.can_id = (CAN_SFF_MASK + 1).into(); // CAN_SFF_MASK = 0x7FFU
+        assert!(
+            vu_can_backend
+                .check_rx_frame(frame)
+                .unwrap()
+                .can_id
+                .to_native()
+                < CAN_SFF_MASK,
+        );
+
+        // Test 3: Received message should have CAN_EFF_MASK in can_id
+        frame.can_id = CAN_EFF_FLAG.into();
+        assert_eq!(
+            vu_can_backend
+                .check_rx_frame(frame)
+                .unwrap()
+                .flags
+                .to_native()
+                & VIRTIO_CAN_FLAGS_EXTENDED,
+            VIRTIO_CAN_FLAGS_EXTENDED
+        );
+
+        // Test 4: Received message's can_id should be equal to CAN_EFF_MASK,
+        //         since the 3 MSB have been zeroed.
+        frame.can_id = (frame.can_id.to_native() | CAN_EFF_MASK).into(); // CAN_EFF_MASK = 0x1FFFFFFFU
+        assert!(
+            vu_can_backend
+                .check_rx_frame(frame)
+                .unwrap()
+                .can_id
+                .to_native()
+                == CAN_EFF_MASK
+        );
+    }
+
+    #[test]
+    fn test_virtio_can_check_rx_rtr_frame() {
+        let controller =
+            CanController::new("can0".to_string()).expect("Could not build controller");
+        let controller = Arc::new(RwLock::new(controller));
+        let mut vu_can_backend =
+            VhostUserCanBackend::new(controller.clone()).expect("Could not build vhucan device");
+
+        let frame = VirtioCanFrame {
+            msg_type: 0.into(),
+            can_id: CAN_RTR_FLAG.into(),
+            length: 8.into(),
+            reserved: 0.into(),
+            flags: 0.into(),
+            sdu: [0; 64],
+        };
+
+        // Test 1: Take a valid CAN / CANFD message and try to enable RTR in flags.
+        //         the test should fail because VIRTIO_CAN_F_CAN_CLASSIC is not negotiated.
+        vu_can_backend.acked_features(1 << VIRTIO_CAN_F_CAN_CLASSIC);
+
+        assert_eq!(
+            vu_can_backend.check_rx_frame(frame).unwrap_err(),
+            Error::UnexpectedRtrFlag
+        );
+
+        // Test 2: Take a valid CAN / CANFD message and try to enable RTR in flags.
+        //         the test should succeed because VIRTIO_CAN_F_CAN_CLASSIC is negotiated.
+        vu_can_backend
+            .acked_features((1 << VIRTIO_CAN_F_RTR_FRAMES) | (1 << VIRTIO_CAN_F_CAN_CLASSIC));
+
+        assert_eq!(
+            vu_can_backend
+                .check_rx_frame(frame)
+                .unwrap()
+                .flags
+                .to_native()
+                & VIRTIO_CAN_FLAGS_RTR,
+            VIRTIO_CAN_FLAGS_RTR
+        );
+
+        // Test 3: Take a valid CAN / CANFD message and try to enable RTR in flags.
+        //         the test should fail because VIRTIO_CAN_F_CAN_CLASSIC is not negotiated,
+        //         and RTR does not work with VIRTIO_CAN_F_CAN_FD.
+
+        let frame = VirtioCanFrame {
+            msg_type: 0.into(),
+            can_id: CAN_RTR_FLAG.into(),
+            length: 8.into(),
+            reserved: 0.into(),
+            flags: CAN_FRMF_TYPE_FD.into(), // Mark it as CAN FD frame
+            sdu: [0; 64],
+        };
+
+        vu_can_backend.acked_features((1 << VIRTIO_CAN_F_RTR_FRAMES) | (1 << VIRTIO_CAN_F_CAN_FD));
+
+        assert_eq!(
+            vu_can_backend.check_rx_frame(frame).unwrap_err(),
+            Error::UnexpectedRtrFlag
+        );
+    }
+
+    #[test]
+    fn test_virtio_can_check_rx_can_frame() {
+        let controller =
+            CanController::new("can0".to_string()).expect("Could not build controller");
+        let controller = Arc::new(RwLock::new(controller));
+        let mut vu_can_backend =
+            VhostUserCanBackend::new(controller.clone()).expect("Could not build vhucan device");
+
+        // Test 1: UnexpectedClassicFlag
+        let frame = VirtioCanFrame {
+            msg_type: VIRTIO_CAN_TX.into(),
+            can_id: 0.into(),
+            length: 4.into(),
+            reserved: 0.into(),
+            flags: 0.into(),
+            sdu: [0; 64],
+        };
+
+        assert_eq!(
+            vu_can_backend.check_rx_frame(frame).unwrap_err(),
+            Error::UnexpectedClassicFlag
+        );
+
+        // Test 2: Return the same length
+        vu_can_backend.acked_features(1 << VIRTIO_CAN_F_CAN_CLASSIC);
+
+        assert_eq!(
+            vu_can_backend.check_tx_frame(frame).unwrap().length,
+            frame.length
+        );
+
+        // Test 3: Return the length equal to 8
+        let frame = VirtioCanFrame {
+            msg_type: VIRTIO_CAN_TX.into(),
+            can_id: 0.into(),
+            length: 40.into(),
+            reserved: 0.into(),
+            flags: 0.into(),
+            sdu: [0; 64],
+        };
+
+        assert_eq!(
+            vu_can_backend.check_tx_frame(frame).unwrap_err(),
+            Error::InvalidCanLength(40)
+        );
+    }
+
+    #[test]
+    fn test_virtio_can_check_rx_canfd_frame() {
+        let controller =
+            CanController::new("can0".to_string()).expect("Could not build controller");
+        let controller = Arc::new(RwLock::new(controller));
+        let mut vu_can_backend =
+            VhostUserCanBackend::new(controller.clone()).expect("Could not build vhucan device");
+
+        // Enable VIRTIO_CAN_F_CAN_FD feature
+        vu_can_backend.acked_features(1 << VIRTIO_CAN_F_CAN_FD);
+
+        // Test 1: If no CAN_FRMF_TYPE_FD in flags return UnexpectedClassicFlag
+        let frame = VirtioCanFrame {
+            msg_type: 0.into(),
+            can_id: 0.into(),
+            length: 40.into(),
+            reserved: 0.into(),
+            flags: 0.into(),
+            sdu: [0; 64],
+        };
+
+        assert_eq!(
+            vu_can_backend.check_rx_frame(frame).unwrap_err(),
+            Error::UnexpectedClassicFlag
+        );
+
+        // Test 2: If VIRTIO_CAN_FLAGS_FD is in flag check if return message has
+        //         VIRTIO_CAN_FLAGS_FD in flags.
+        let frame = VirtioCanFrame {
+            msg_type: 0.into(),
+            can_id: 0.into(),
+            length: 48.into(),
+            reserved: 0.into(),
+            flags: CAN_FRMF_TYPE_FD.into(),
+            sdu: [0; 64],
+        };
+
+        assert_eq!(
+            vu_can_backend
+                .check_rx_frame(frame)
+                .unwrap()
+                .flags
+                .to_native()
+                & VIRTIO_CAN_FLAGS_FD,
+            VIRTIO_CAN_FLAGS_FD
+        );
+
+        // Test 3: receive frame with the same length if length is < 64
+        assert_eq!(
+            vu_can_backend.check_rx_frame(frame).unwrap().length,
+            frame.length
+        );
+
+        // Test 4: receive frame with length out-of-range: length is > 64
+        let frame = VirtioCanFrame {
+            msg_type: 0.into(),
+            can_id: 0.into(),
+            length: 80.into(),
+            reserved: 0.into(),
+            flags: CAN_FRMF_TYPE_FD.into(),
+            sdu: [0; 64],
+        };
+
+        assert_eq!(
+            vu_can_backend.check_rx_frame(frame).unwrap_err(),
+            Error::InvalidCanLength(80)
+        );
+
+        // Test 5: receive frame with length out-of-range: length no in
+        //         list: [12, 16, 20, 24, 32, 48, 64]
+        let frame = VirtioCanFrame {
+            msg_type: 0.into(),
+            can_id: 0.into(),
+            length: 62.into(),
+            reserved: 0.into(),
+            flags: CAN_FRMF_TYPE_FD.into(),
+            sdu: [0; 64],
+        };
+
+        assert_eq!(
+            vu_can_backend.check_rx_frame(frame).unwrap_err(),
+            Error::InvalidCanLength(62)
+        );
+    }
+
+    #[test]
+    fn test_virtio_can_check_rx_canfd_vcan0() {
+        let controller =
+            CanController::new("vcan0".to_string()).expect("Could not build controller");
+        let controller = Arc::new(RwLock::new(controller));
+        let mut vu_can_backend =
+            VhostUserCanBackend::new(controller.clone()).expect("Could not build vhucan device");
+
+        // Enable VIRTIO_CAN_F_CAN_FD feature
+        vu_can_backend.acked_features((1 << VIRTIO_CAN_F_CAN_FD) | (1 << VIRTIO_CAN_F_CAN_CLASSIC));
+
+        // If VIRTIO_CAN_F_CAN_FD  and VIRTIO_CAN_F_CAN_CLASSIC are negotiated
+        // and interface is "vcan0" check if return message has
+        // VIRTIO_CAN_FLAGS_FD in flags and has been treated as CANFD frame.
+        let frame = VirtioCanFrame {
+            msg_type: 0.into(),
+            can_id: 0.into(),
+            length: 48.into(),
+            reserved: 0.into(),
+            flags: 0.into(),
+            sdu: [0; 64],
+        };
+
+        assert_eq!(
+            vu_can_backend
+                .check_rx_frame(frame)
+                .unwrap()
+                .flags
+                .to_native()
+                & VIRTIO_CAN_FLAGS_FD,
+            VIRTIO_CAN_FLAGS_FD
+        );
+
+        assert_eq!(
+            vu_can_backend.check_rx_frame(frame).unwrap().length,
+            frame.length
+        );
+    }
+
+    #[test]
+    fn test_virtio_can_rx_request() {
+        let controller =
+            CanController::new("can0".to_string()).expect("Could not build controller");
+        let controller = Arc::new(RwLock::new(controller));
+        let mut vu_can_backend =
+            VhostUserCanBackend::new(controller.clone()).expect("Could not build vhucan device");
+        let mem = GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x1000)]).unwrap();
+
+        // Note: The following test are focusing only to simple CAN messages.
+
+        // Test 1: This should succeed because there is no element inserted in the
+        //         CAN/FD frames' queue
+        let desc_chain = build_desc_chain_mem(&mem, 1, vec![VRING_DESC_F_WRITE as u16], 0x200);
+        let mem1 = GuestMemoryAtomic::new(mem.clone());
+        let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap();
+        vu_can_backend.update_memory(mem1).unwrap();
+        assert!(!vu_can_backend
+            .process_rx_requests(vec![desc_chain], &vring)
+            .unwrap(),);
+
+        // Test 2: This should fail because there is a simple CAN frame
+        //         inserted in the CAN/FD frames' queue, but this does not
+        //         pass the checks.
+
+        // Push a new can message into the can.rs queue
+        let frame = VirtioCanFrame {
+            msg_type: 0.into(),
+            can_id: 123.into(),
+            length: 64.into(),
+            reserved: 0.into(),
+            flags: 0.into(),
+            sdu: [0; 64],
+        };
+
+        controller.write().unwrap().push(frame).unwrap();
+
+        let desc_chain = build_desc_chain_mem(&mem, 1, vec![VRING_DESC_F_WRITE as u16], 0x200);
+        let mem1 = GuestMemoryAtomic::new(mem.clone());
+        let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap();
+        vu_can_backend.update_memory(mem1).unwrap();
+        assert_eq!(
+            vu_can_backend
+                .process_rx_requests(vec![desc_chain], &vring)
+                .unwrap_err(),
+            Error::UnexpectedClassicFlag
+        );
+
+        // Test 3: This should succeed because there is a simple CAN frame
+        //         inserted in the CAN/FD frames' queue, and this does
+        //         pass the checks.
+
+        // Enable VIRTIO_CAN_F_CAN_CLASSIC feature
+        vu_can_backend.acked_features(1 << VIRTIO_CAN_F_CAN_CLASSIC);
+
+        // Push a new can message into the can.rs queue
+        let frame = VirtioCanFrame {
+            msg_type: 0.into(),
+            can_id: 123.into(),
+            length: 8.into(),
+            reserved: 0.into(),
+            flags: 0.into(),
+            sdu: [0; 64],
+        };
+
+        controller.write().unwrap().push(frame).unwrap();
+
+        let desc_chain = build_desc_chain_mem(&mem, 1, vec![VRING_DESC_F_WRITE as u16], 0x200);
+        let mem1 = GuestMemoryAtomic::new(mem.clone());
+        let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap();
+        vu_can_backend.update_memory(mem1).unwrap();
+        assert!(vu_can_backend
+            .process_rx_requests(vec![desc_chain], &vring)
+            .unwrap());
+
+        // Test 4: This should fail because the descriptor is read-only
+        let desc_chain = build_desc_chain_mem(&mem, 1, vec![0], 0x200);
+        let mem1 = GuestMemoryAtomic::new(mem.clone());
+        let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap();
+        vu_can_backend.update_memory(mem1).unwrap();
+
+        // Push a new can message into the can.rs queue
+        let frame = VirtioCanFrame {
+            msg_type: 0.into(),
+            can_id: 123.into(),
+            length: 8.into(),
+            reserved: 0.into(),
+            flags: 0.into(),
+            sdu: [0; 64],
+        };
+        controller.write().unwrap().push(frame).unwrap();
+
+        assert_eq!(
+            vu_can_backend
+                .process_rx_requests(vec![desc_chain.clone()], &vring)
+                .unwrap_err(),
+            Error::DescriptorWriteFailed
+        );
+
+        // Test 5: This should fail because the descriptor length is less
+        //         than VirtioCanFrame size.
+        let desc_chain = build_desc_chain_mem(&mem, 1, vec![VRING_DESC_F_WRITE as u16], 0x10);
+        let mem1 = GuestMemoryAtomic::new(mem.clone());
+        let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap();
+        vu_can_backend.update_memory(mem1).unwrap();
+
+        // Push a new can message into the can.rs queue
+        let frame = VirtioCanFrame {
+            msg_type: 0.into(),
+            can_id: 123.into(),
+            length: 8.into(),
+            reserved: 0.into(),
+            flags: 0.into(),
+            sdu: [0; 64],
+        };
+        controller.write().unwrap().push(frame).unwrap();
+
+        assert_eq!(
+            vu_can_backend
+                .process_rx_requests(vec![desc_chain.clone()], &vring)
+                .unwrap_err(),
+            Error::DescriptorWriteFailed
+        );
+    }
+}
diff --git a/meta-egvirt/recipes-extended/vhost-device-can/files/vhost-device-can-0.1.0/src/virtio_can.rs b/meta-egvirt/recipes-extended/vhost-device-can/files/vhost-device-can-0.1.0/src/virtio_can.rs
new file mode 100755 (executable)
index 0000000..768dc12
--- /dev/null
@@ -0,0 +1,144 @@
+// CAN virtio bindings
+//
+// Copyright 2023-2024 VIRTUAL OPEN SYSTEMS SAS. All Rights Reserved.
+//          Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com>
+//
+// SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause
+
+use vm_memory::{ByteValued, Le16, Le32};
+
+/// CAN FRAME Flags and Masks
+pub(crate) const CAN_EFF_FLAG: u32 = 0x80000000; // EFF/SFF is set in the MSB
+pub(crate) const CAN_RTR_FLAG: u32 = 0x40000000; // remote transmission request
+pub(crate) const CAN_ERR_FLAG: u32 = 0x20000000; // error message frame
+pub(crate) const CAN_SFF_MASK: u32 = 0x000007FF; // standard frame format (SFF)
+pub(crate) const CAN_EFF_MASK: u32 = 0x1FFFFFFF; // extended frame format (EFF)
+#[allow(dead_code)]
+pub(crate) const CAN_FRMF_BRS: u32 = 0x01; // bit rate switch (2nd bitrate for data)
+#[allow(dead_code)]
+pub(crate) const CAN_FRMF_ESI: u32 = 0x02; // error state ind. of transmitting node
+pub(crate) const CAN_FRMF_TYPE_FD: u32 = 0x10; // internal bit ind. of CAN FD frame
+pub(crate) const CAN_ERR_BUSOFF: u32 = 0x00000040; // bus off
+
+/// CANFD frame's valid data lengths
+pub(crate) const CANFD_VALID_LENGTHS: [u32; 7] = [12, 16, 20, 24, 32, 48, 64];
+
+/// CAN controller states
+pub(crate) const CAN_CS_STARTED: u8 = 0x01;
+pub(crate) const CAN_CS_STOPPED: u8 = 0x02;
+
+/// CAN flags to determine type of CAN FRAME Id
+pub(crate) const VIRTIO_CAN_FLAGS_EXTENDED: u32 = 0x8000;
+pub(crate) const VIRTIO_CAN_FLAGS_FD: u32 = 0x4000;
+pub(crate) const VIRTIO_CAN_FLAGS_RTR: u32 = 0x2000;
+
+pub(crate) const VIRTIO_CAN_FLAGS_VALID_MASK: u32 =
+    VIRTIO_CAN_FLAGS_EXTENDED | VIRTIO_CAN_FLAGS_FD | VIRTIO_CAN_FLAGS_RTR;
+
+pub(crate) const VIRTIO_CAN_TX: u16 = 0x0001;
+pub(crate) const VIRTIO_CAN_RX: u16 = 0x0101;
+
+/// Feature bit numbers
+pub const VIRTIO_CAN_F_CAN_CLASSIC: u16 = 0;
+pub const VIRTIO_CAN_F_CAN_FD: u16 = 1;
+pub const VIRTIO_CAN_S_CTRL_BUSOFF: u16 = 2; /* Controller BusOff */
+#[allow(dead_code)]
+pub const VIRTIO_CAN_F_LATE_TX_ACK: u16 = 2;
+pub const VIRTIO_CAN_F_RTR_FRAMES: u16 = 3;
+
+/// Possible values of the status field
+pub const VIRTIO_CAN_RESULT_OK: u8 = 0x0;
+pub const VIRTIO_CAN_RESULT_NOT_OK: u8 = 0x1;
+
+/// CAN Control messages
+pub const VIRTIO_CAN_SET_CTRL_MODE_START: u16 = 0x0201;
+pub const VIRTIO_CAN_SET_CTRL_MODE_STOP: u16 = 0x0202;
+
+/// Virtio Can Configuration
+#[derive(Copy, Clone, Debug, Default, PartialEq)]
+#[repr(C)]
+pub(crate) struct VirtioCanConfig {
+    /// CAN controller status
+    pub(crate) status: Le16,
+}
+
+// SAFETY: The layout of the structure is fixed and can be initialized by
+// reading its content from byte array.
+unsafe impl ByteValued for VirtioCanConfig {}
+
+/// Virtio CAN Request / Response messages
+///
+/// The response message is a stream of bytes, where first byte represents the
+/// status, and rest is message specific data.
+
+#[derive(Copy, Clone, Default)]
+#[repr(C)]
+pub struct VirtioCanTxResponse {
+    pub result: i8,
+}
+
+// SAFETY: The layout of the structure is fixed and can be initialized by
+// reading its content from byte array.
+unsafe impl ByteValued for VirtioCanTxResponse {}
+
+#[derive(Copy, Clone, Debug, PartialEq)]
+#[repr(C)]
+pub struct VirtioCanFrame {
+    pub msg_type: Le16,
+    pub length: Le16,   /* 0..8 CC, 0..64 CAN­FD, 0..2048 CAN­XL, 12 bits */
+    pub reserved: Le32, /* May be needed in part for CAN XL priority */
+    pub flags: Le32,
+    pub can_id: Le32,
+    pub sdu: [u8; 64],
+}
+
+// SAFETY: The layout of the structure is fixed and can be initialized by
+// reading its content from byte array.
+unsafe impl ByteValued for VirtioCanFrame {}
+
+impl Default for VirtioCanFrame {
+    fn default() -> Self {
+        VirtioCanFrame {
+            msg_type: Le16::default(),
+            length: Le16::default(),
+            reserved: Le32::default(),
+            flags: Le32::default(),
+            can_id: Le32::default(),
+            sdu: [0; 64], // Initialize "sdu" with default value (0 in this case)
+        }
+    }
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Default)]
+#[repr(C)]
+pub struct VirtioCanHeader {
+    pub msg_type: Le16,
+    pub length: Le16,   /* 0..8 CC, 0..64 CAN­FD, 0..2048 CAN­XL, 12 bits */
+    pub reserved: Le32, /* May be needed in part for CAN XL priority */
+    pub flags: Le32,
+    pub can_id: Le32,
+}
+
+// SAFETY: The layout of the structure is fixed and can be initialized by
+// reading its content from byte array.
+unsafe impl ByteValued for VirtioCanHeader {}
+
+#[derive(Copy, Clone, Default)]
+#[repr(C)]
+pub struct VirtioCanCtrlRequest {
+    pub msg_type: Le16,
+}
+
+// SAFETY: The layout of the structure is fixed and can be initialized by
+// reading its content from byte array.
+unsafe impl ByteValued for VirtioCanCtrlRequest {}
+
+#[derive(Copy, Clone, Default)]
+#[repr(C)]
+pub struct VirtioCanCtrlResponse {
+    pub result: i8,
+}
+
+// SAFETY: The layout of the structure is fixed and can be initialized by
+// reading its content from byte array.
+unsafe impl ByteValued for VirtioCanCtrlResponse {}
diff --git a/meta-egvirt/recipes-extended/vhost-device-can/socketcan-crates.inc b/meta-egvirt/recipes-extended/vhost-device-can/socketcan-crates.inc
new file mode 100755 (executable)
index 0000000..b91d4bc
--- /dev/null
@@ -0,0 +1,352 @@
+# Autogenerated with 'bitbake -c update_crates socketcan'
+
+# from Cargo.lock
+SRC_URI += " \
+    crate://crates.io/addr2line/0.24.1 \
+    crate://crates.io/adler2/2.0.0 \
+    crate://crates.io/anstream/0.6.15 \
+    crate://crates.io/anstyle/1.0.8 \
+    crate://crates.io/anstyle-parse/0.2.5 \
+    crate://crates.io/anstyle-query/1.1.1 \
+    crate://crates.io/anstyle-wincon/3.0.4 \
+    crate://crates.io/anyhow/1.0.87 \
+    crate://crates.io/async-attributes/1.1.2 \
+    crate://crates.io/async-channel/1.9.0 \
+    crate://crates.io/async-channel/2.3.1 \
+    crate://crates.io/async-executor/1.13.1 \
+    crate://crates.io/async-fs/1.6.0 \
+    crate://crates.io/async-global-executor/2.4.1 \
+    crate://crates.io/async-io/1.13.0 \
+    crate://crates.io/async-io/2.3.4 \
+    crate://crates.io/async-lock/2.8.0 \
+    crate://crates.io/async-lock/3.4.0 \
+    crate://crates.io/async-net/1.8.0 \
+    crate://crates.io/async-process/1.8.1 \
+    crate://crates.io/async-signal/0.2.10 \
+    crate://crates.io/async-std/1.13.0 \
+    crate://crates.io/async-task/4.7.1 \
+    crate://crates.io/atomic-waker/1.1.2 \
+    crate://crates.io/autocfg/1.3.0 \
+    crate://crates.io/backtrace/0.3.74 \
+    crate://crates.io/bitflags/1.3.2 \
+    crate://crates.io/bitflags/2.6.0 \
+    crate://crates.io/blocking/1.6.1 \
+    crate://crates.io/bumpalo/3.16.0 \
+    crate://crates.io/byte_conv/0.1.1 \
+    crate://crates.io/byteorder/1.5.0 \
+    crate://crates.io/cfg-if/1.0.0 \
+    crate://crates.io/cfg_aliases/0.2.1 \
+    crate://crates.io/clap/4.5.17 \
+    crate://crates.io/clap_builder/4.5.17 \
+    crate://crates.io/clap_lex/0.7.2 \
+    crate://crates.io/colorchoice/1.0.2 \
+    crate://crates.io/concurrent-queue/2.5.0 \
+    crate://crates.io/crossbeam-utils/0.8.20 \
+    crate://crates.io/ctrlc/3.4.5 \
+    crate://crates.io/dashmap/5.5.3 \
+    crate://crates.io/either/1.13.0 \
+    crate://crates.io/embedded-can/0.4.1 \
+    crate://crates.io/errno/0.3.9 \
+    crate://crates.io/event-listener/2.5.3 \
+    crate://crates.io/event-listener/3.1.0 \
+    crate://crates.io/event-listener/5.3.1 \
+    crate://crates.io/event-listener-strategy/0.5.2 \
+    crate://crates.io/fastrand/1.9.0 \
+    crate://crates.io/fastrand/2.1.1 \
+    crate://crates.io/futures/0.3.30 \
+    crate://crates.io/futures-channel/0.3.30 \
+    crate://crates.io/futures-channel-preview/0.3.0-alpha.19 \
+    crate://crates.io/futures-core/0.3.30 \
+    crate://crates.io/futures-core-preview/0.3.0-alpha.19 \
+    crate://crates.io/futures-executor/0.3.30 \
+    crate://crates.io/futures-executor-preview/0.3.0-alpha.19 \
+    crate://crates.io/futures-io/0.3.30 \
+    crate://crates.io/futures-io-preview/0.3.0-alpha.19 \
+    crate://crates.io/futures-lite/1.13.0 \
+    crate://crates.io/futures-lite/2.3.0 \
+    crate://crates.io/futures-macro/0.3.30 \
+    crate://crates.io/futures-preview/0.3.0-alpha.19 \
+    crate://crates.io/futures-sink/0.3.30 \
+    crate://crates.io/futures-sink-preview/0.3.0-alpha.19 \
+    crate://crates.io/futures-task/0.3.30 \
+    crate://crates.io/futures-timer/0.3.0 \
+    crate://crates.io/futures-util/0.3.30 \
+    crate://crates.io/futures-util-preview/0.3.0-alpha.19 \
+    crate://crates.io/gimli/0.31.0 \
+    crate://crates.io/gloo-timers/0.3.0 \
+    crate://crates.io/hashbrown/0.14.5 \
+    crate://crates.io/hermit-abi/0.3.9 \
+    crate://crates.io/hermit-abi/0.4.0 \
+    crate://crates.io/hex/0.4.3 \
+    crate://crates.io/instant/0.1.13 \
+    crate://crates.io/io-lifetimes/1.0.11 \
+    crate://crates.io/is_terminal_polyfill/1.70.1 \
+    crate://crates.io/itertools/0.10.5 \
+    crate://crates.io/js-sys/0.3.70 \
+    crate://crates.io/kv-log-macro/1.0.7 \
+    crate://crates.io/lazy_static/1.5.0 \
+    crate://crates.io/libc/0.2.158 \
+    crate://crates.io/libudev/0.3.0 \
+    crate://crates.io/libudev-sys/0.1.4 \
+    crate://crates.io/linux-raw-sys/0.3.8 \
+    crate://crates.io/linux-raw-sys/0.4.14 \
+    crate://crates.io/lock_api/0.4.12 \
+    crate://crates.io/log/0.4.22 \
+    crate://crates.io/memchr/2.7.4 \
+    crate://crates.io/memoffset/0.7.1 \
+    crate://crates.io/miniz_oxide/0.8.0 \
+    crate://crates.io/mio/0.8.11 \
+    crate://crates.io/mio/1.0.2 \
+    crate://crates.io/nb/1.1.0 \
+    crate://crates.io/neli/0.6.4 \
+    crate://crates.io/neli-proc-macros/0.1.3 \
+    crate://crates.io/nix/0.26.4 \
+    crate://crates.io/nix/0.29.0 \
+    crate://crates.io/num_cpus/1.16.0 \
+    crate://crates.io/object/0.36.4 \
+    crate://crates.io/once_cell/1.19.0 \
+    crate://crates.io/parking/2.2.1 \
+    crate://crates.io/parking_lot/0.12.3 \
+    crate://crates.io/parking_lot_core/0.9.10 \
+    crate://crates.io/pin-project-lite/0.2.14 \
+    crate://crates.io/pin-utils/0.1.0 \
+    crate://crates.io/piper/0.2.4 \
+    crate://crates.io/pkg-config/0.3.30 \
+    crate://crates.io/polling/2.8.0 \
+    crate://crates.io/polling/3.7.3 \
+    crate://crates.io/proc-macro2/1.0.86 \
+    crate://crates.io/quote/1.0.37 \
+    crate://crates.io/redox_syscall/0.5.3 \
+    crate://crates.io/rustc-demangle/0.1.24 \
+    crate://crates.io/rustix/0.37.27 \
+    crate://crates.io/rustix/0.38.36 \
+    crate://crates.io/scopeguard/1.2.0 \
+    crate://crates.io/serde/1.0.210 \
+    crate://crates.io/serde_derive/1.0.210 \
+    crate://crates.io/serial_test/2.0.0 \
+    crate://crates.io/serial_test_derive/2.0.0 \
+    crate://crates.io/signal-hook-registry/1.4.2 \
+    crate://crates.io/slab/0.4.9 \
+    crate://crates.io/smallvec/1.13.2 \
+    crate://crates.io/smol/1.3.0 \
+    crate://crates.io/socket2/0.4.10 \
+    crate://crates.io/socket2/0.5.7 \
+    crate://crates.io/strsim/0.11.1 \
+    crate://crates.io/syn/1.0.109 \
+    crate://crates.io/syn/2.0.77 \
+    crate://crates.io/thiserror/1.0.63 \
+    crate://crates.io/thiserror-impl/1.0.63 \
+    crate://crates.io/tokio/1.40.0 \
+    crate://crates.io/tokio-macros/2.4.0 \
+    crate://crates.io/tracing/0.1.40 \
+    crate://crates.io/tracing-core/0.1.32 \
+    crate://crates.io/unicode-ident/1.0.12 \
+    crate://crates.io/utf8parse/0.2.2 \
+    crate://crates.io/value-bag/1.9.0 \
+    crate://crates.io/waker-fn/1.2.0 \
+    crate://crates.io/wasi/0.11.0+wasi-snapshot-preview1 \
+    crate://crates.io/wasm-bindgen/0.2.93 \
+    crate://crates.io/wasm-bindgen-backend/0.2.93 \
+    crate://crates.io/wasm-bindgen-futures/0.4.43 \
+    crate://crates.io/wasm-bindgen-macro/0.2.93 \
+    crate://crates.io/wasm-bindgen-macro-support/0.2.93 \
+    crate://crates.io/wasm-bindgen-shared/0.2.93 \
+    crate://crates.io/web-sys/0.3.70 \
+    crate://crates.io/winapi/0.3.9 \
+    crate://crates.io/winapi-i686-pc-windows-gnu/0.4.0 \
+    crate://crates.io/winapi-x86_64-pc-windows-gnu/0.4.0 \
+    crate://crates.io/windows-sys/0.48.0 \
+    crate://crates.io/windows-sys/0.52.0 \
+    crate://crates.io/windows-sys/0.59.0 \
+    crate://crates.io/windows-targets/0.48.5 \
+    crate://crates.io/windows-targets/0.52.6 \
+    crate://crates.io/windows_aarch64_gnullvm/0.48.5 \
+    crate://crates.io/windows_aarch64_gnullvm/0.52.6 \
+    crate://crates.io/windows_aarch64_msvc/0.48.5 \
+    crate://crates.io/windows_aarch64_msvc/0.52.6 \
+    crate://crates.io/windows_i686_gnu/0.48.5 \
+    crate://crates.io/windows_i686_gnu/0.52.6 \
+    crate://crates.io/windows_i686_gnullvm/0.52.6 \
+    crate://crates.io/windows_i686_msvc/0.48.5 \
+    crate://crates.io/windows_i686_msvc/0.52.6 \
+    crate://crates.io/windows_x86_64_gnu/0.48.5 \
+    crate://crates.io/windows_x86_64_gnu/0.52.6 \
+    crate://crates.io/windows_x86_64_gnullvm/0.48.5 \
+    crate://crates.io/windows_x86_64_gnullvm/0.52.6 \
+    crate://crates.io/windows_x86_64_msvc/0.48.5 \
+    crate://crates.io/windows_x86_64_msvc/0.52.6 \
+"
+
+SRC_URI[addr2line-0.24.1.sha256sum] = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375"
+SRC_URI[adler2-2.0.0.sha256sum] = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
+SRC_URI[anstream-0.6.15.sha256sum] = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526"
+SRC_URI[anstyle-1.0.8.sha256sum] = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
+SRC_URI[anstyle-parse-0.2.5.sha256sum] = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb"
+SRC_URI[anstyle-query-1.1.1.sha256sum] = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a"
+SRC_URI[anstyle-wincon-3.0.4.sha256sum] = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8"
+SRC_URI[anyhow-1.0.87.sha256sum] = "10f00e1f6e58a40e807377c75c6a7f97bf9044fab57816f2414e6f5f4499d7b8"
+SRC_URI[async-attributes-1.1.2.sha256sum] = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5"
+SRC_URI[async-channel-1.9.0.sha256sum] = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35"
+SRC_URI[async-channel-2.3.1.sha256sum] = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a"
+SRC_URI[async-executor-1.13.1.sha256sum] = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec"
+SRC_URI[async-fs-1.6.0.sha256sum] = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06"
+SRC_URI[async-global-executor-2.4.1.sha256sum] = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c"
+SRC_URI[async-io-1.13.0.sha256sum] = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af"
+SRC_URI[async-io-2.3.4.sha256sum] = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8"
+SRC_URI[async-lock-2.8.0.sha256sum] = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b"
+SRC_URI[async-lock-3.4.0.sha256sum] = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18"
+SRC_URI[async-net-1.8.0.sha256sum] = "0434b1ed18ce1cf5769b8ac540e33f01fa9471058b5e89da9e06f3c882a8c12f"
+SRC_URI[async-process-1.8.1.sha256sum] = "ea6438ba0a08d81529c69b36700fa2f95837bfe3e776ab39cde9c14d9149da88"
+SRC_URI[async-signal-0.2.10.sha256sum] = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3"
+SRC_URI[async-std-1.13.0.sha256sum] = "c634475f29802fde2b8f0b505b1bd00dfe4df7d4a000f0b36f7671197d5c3615"
+SRC_URI[async-task-4.7.1.sha256sum] = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
+SRC_URI[atomic-waker-1.1.2.sha256sum] = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
+SRC_URI[autocfg-1.3.0.sha256sum] = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
+SRC_URI[backtrace-0.3.74.sha256sum] = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
+SRC_URI[bitflags-1.3.2.sha256sum] = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+SRC_URI[bitflags-2.6.0.sha256sum] = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
+SRC_URI[blocking-1.6.1.sha256sum] = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea"
+SRC_URI[bumpalo-3.16.0.sha256sum] = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
+SRC_URI[byte_conv-0.1.1.sha256sum] = "649972315d4931137a26fc2bf3ca95ee257ad796a5b57bdeb04205c91a4b5780"
+SRC_URI[byteorder-1.5.0.sha256sum] = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+SRC_URI[cfg-if-1.0.0.sha256sum] = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+SRC_URI[cfg_aliases-0.2.1.sha256sum] = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
+SRC_URI[clap-4.5.17.sha256sum] = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac"
+SRC_URI[clap_builder-4.5.17.sha256sum] = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73"
+SRC_URI[clap_lex-0.7.2.sha256sum] = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
+SRC_URI[colorchoice-1.0.2.sha256sum] = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
+SRC_URI[concurrent-queue-2.5.0.sha256sum] = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
+SRC_URI[crossbeam-utils-0.8.20.sha256sum] = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
+SRC_URI[ctrlc-3.4.5.sha256sum] = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3"
+SRC_URI[dashmap-5.5.3.sha256sum] = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
+SRC_URI[either-1.13.0.sha256sum] = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
+SRC_URI[embedded-can-0.4.1.sha256sum] = "e9d2e857f87ac832df68fa498d18ddc679175cf3d2e4aa893988e5601baf9438"
+SRC_URI[errno-0.3.9.sha256sum] = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
+SRC_URI[event-listener-2.5.3.sha256sum] = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
+SRC_URI[event-listener-3.1.0.sha256sum] = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2"
+SRC_URI[event-listener-5.3.1.sha256sum] = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba"
+SRC_URI[event-listener-strategy-0.5.2.sha256sum] = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1"
+SRC_URI[fastrand-1.9.0.sha256sum] = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
+SRC_URI[fastrand-2.1.1.sha256sum] = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
+SRC_URI[futures-0.3.30.sha256sum] = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
+SRC_URI[futures-channel-0.3.30.sha256sum] = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
+SRC_URI[futures-channel-preview-0.3.0-alpha.19.sha256sum] = "d5e5f4df964fa9c1c2f8bddeb5c3611631cacd93baf810fc8bb2fb4b495c263a"
+SRC_URI[futures-core-0.3.30.sha256sum] = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
+SRC_URI[futures-core-preview-0.3.0-alpha.19.sha256sum] = "b35b6263fb1ef523c3056565fa67b1d16f0a8604ff12b11b08c25f28a734c60a"
+SRC_URI[futures-executor-0.3.30.sha256sum] = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
+SRC_URI[futures-executor-preview-0.3.0-alpha.19.sha256sum] = "75236e88bd9fe88e5e8bfcd175b665d0528fe03ca4c5207fabc028c8f9d93e98"
+SRC_URI[futures-io-0.3.30.sha256sum] = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
+SRC_URI[futures-io-preview-0.3.0-alpha.19.sha256sum] = "f4914ae450db1921a56c91bde97a27846287d062087d4a652efc09bb3a01ebda"
+SRC_URI[futures-lite-1.13.0.sha256sum] = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce"
+SRC_URI[futures-lite-2.3.0.sha256sum] = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5"
+SRC_URI[futures-macro-0.3.30.sha256sum] = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
+SRC_URI[futures-preview-0.3.0-alpha.19.sha256sum] = "3b1dce2a0267ada5c6ff75a8ba864b4e679a9e2aa44262af7a3b5516d530d76e"
+SRC_URI[futures-sink-0.3.30.sha256sum] = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
+SRC_URI[futures-sink-preview-0.3.0-alpha.19.sha256sum] = "86f148ef6b69f75bb610d4f9a2336d4fc88c4b5b67129d1a340dd0fd362efeec"
+SRC_URI[futures-task-0.3.30.sha256sum] = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
+SRC_URI[futures-timer-0.3.0.sha256sum] = "8f9eb554aa23143abc64ec4d0016f038caf53bb7cbc3d91490835c54edc96550"
+SRC_URI[futures-util-0.3.30.sha256sum] = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
+SRC_URI[futures-util-preview-0.3.0-alpha.19.sha256sum] = "5ce968633c17e5f97936bd2797b6e38fb56cf16a7422319f7ec2e30d3c470e8d"
+SRC_URI[gimli-0.31.0.sha256sum] = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64"
+SRC_URI[gloo-timers-0.3.0.sha256sum] = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994"
+SRC_URI[hashbrown-0.14.5.sha256sum] = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+SRC_URI[hermit-abi-0.3.9.sha256sum] = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
+SRC_URI[hermit-abi-0.4.0.sha256sum] = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
+SRC_URI[hex-0.4.3.sha256sum] = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+SRC_URI[instant-0.1.13.sha256sum] = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
+SRC_URI[io-lifetimes-1.0.11.sha256sum] = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
+SRC_URI[is_terminal_polyfill-1.70.1.sha256sum] = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
+SRC_URI[itertools-0.10.5.sha256sum] = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
+SRC_URI[js-sys-0.3.70.sha256sum] = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
+SRC_URI[kv-log-macro-1.0.7.sha256sum] = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f"
+SRC_URI[lazy_static-1.5.0.sha256sum] = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+SRC_URI[libc-0.2.158.sha256sum] = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
+SRC_URI[libudev-0.3.0.sha256sum] = "78b324152da65df7bb95acfcaab55e3097ceaab02fb19b228a9eb74d55f135e0"
+SRC_URI[libudev-sys-0.1.4.sha256sum] = "3c8469b4a23b962c1396b9b451dda50ef5b283e8dd309d69033475fa9b334324"
+SRC_URI[linux-raw-sys-0.3.8.sha256sum] = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
+SRC_URI[linux-raw-sys-0.4.14.sha256sum] = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
+SRC_URI[lock_api-0.4.12.sha256sum] = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
+SRC_URI[log-0.4.22.sha256sum] = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
+SRC_URI[memchr-2.7.4.sha256sum] = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+SRC_URI[memoffset-0.7.1.sha256sum] = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
+SRC_URI[miniz_oxide-0.8.0.sha256sum] = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1"
+SRC_URI[mio-0.8.11.sha256sum] = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
+SRC_URI[mio-1.0.2.sha256sum] = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
+SRC_URI[nb-1.1.0.sha256sum] = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d"
+SRC_URI[neli-0.6.4.sha256sum] = "1100229e06604150b3becd61a4965d5c70f3be1759544ea7274166f4be41ef43"
+SRC_URI[neli-proc-macros-0.1.3.sha256sum] = "c168194d373b1e134786274020dae7fc5513d565ea2ebb9bc9ff17ffb69106d4"
+SRC_URI[nix-0.26.4.sha256sum] = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b"
+SRC_URI[nix-0.29.0.sha256sum] = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
+SRC_URI[num_cpus-1.16.0.sha256sum] = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
+SRC_URI[object-0.36.4.sha256sum] = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a"
+SRC_URI[once_cell-1.19.0.sha256sum] = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+SRC_URI[parking-2.2.1.sha256sum] = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba"
+SRC_URI[parking_lot-0.12.3.sha256sum] = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
+SRC_URI[parking_lot_core-0.9.10.sha256sum] = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
+SRC_URI[pin-project-lite-0.2.14.sha256sum] = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
+SRC_URI[pin-utils-0.1.0.sha256sum] = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+SRC_URI[piper-0.2.4.sha256sum] = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066"
+SRC_URI[pkg-config-0.3.30.sha256sum] = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
+SRC_URI[polling-2.8.0.sha256sum] = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce"
+SRC_URI[polling-3.7.3.sha256sum] = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511"
+SRC_URI[proc-macro2-1.0.86.sha256sum] = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
+SRC_URI[quote-1.0.37.sha256sum] = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
+SRC_URI[redox_syscall-0.5.3.sha256sum] = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4"
+SRC_URI[rustc-demangle-0.1.24.sha256sum] = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
+SRC_URI[rustix-0.37.27.sha256sum] = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2"
+SRC_URI[rustix-0.38.36.sha256sum] = "3f55e80d50763938498dd5ebb18647174e0c76dc38c5505294bb224624f30f36"
+SRC_URI[scopeguard-1.2.0.sha256sum] = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+SRC_URI[serde-1.0.210.sha256sum] = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
+SRC_URI[serde_derive-1.0.210.sha256sum] = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
+SRC_URI[serial_test-2.0.0.sha256sum] = "0e56dd856803e253c8f298af3f4d7eb0ae5e23a737252cd90bb4f3b435033b2d"
+SRC_URI[serial_test_derive-2.0.0.sha256sum] = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f"
+SRC_URI[signal-hook-registry-1.4.2.sha256sum] = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
+SRC_URI[slab-0.4.9.sha256sum] = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
+SRC_URI[smallvec-1.13.2.sha256sum] = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
+SRC_URI[smol-1.3.0.sha256sum] = "13f2b548cd8447f8de0fdf1c592929f70f4fc7039a05e47404b0d096ec6987a1"
+SRC_URI[socket2-0.4.10.sha256sum] = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d"
+SRC_URI[socket2-0.5.7.sha256sum] = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
+SRC_URI[strsim-0.11.1.sha256sum] = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+SRC_URI[syn-1.0.109.sha256sum] = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+SRC_URI[syn-2.0.77.sha256sum] = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
+SRC_URI[thiserror-1.0.63.sha256sum] = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
+SRC_URI[thiserror-impl-1.0.63.sha256sum] = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
+SRC_URI[tokio-1.40.0.sha256sum] = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998"
+SRC_URI[tokio-macros-2.4.0.sha256sum] = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
+SRC_URI[tracing-0.1.40.sha256sum] = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
+SRC_URI[tracing-core-0.1.32.sha256sum] = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
+SRC_URI[unicode-ident-1.0.12.sha256sum] = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+SRC_URI[utf8parse-0.2.2.sha256sum] = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+SRC_URI[value-bag-1.9.0.sha256sum] = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101"
+SRC_URI[waker-fn-1.2.0.sha256sum] = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7"
+SRC_URI[wasi-0.11.0+wasi-snapshot-preview1.sha256sum] = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+SRC_URI[wasm-bindgen-0.2.93.sha256sum] = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
+SRC_URI[wasm-bindgen-backend-0.2.93.sha256sum] = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
+SRC_URI[wasm-bindgen-futures-0.4.43.sha256sum] = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed"
+SRC_URI[wasm-bindgen-macro-0.2.93.sha256sum] = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
+SRC_URI[wasm-bindgen-macro-support-0.2.93.sha256sum] = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
+SRC_URI[wasm-bindgen-shared-0.2.93.sha256sum] = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
+SRC_URI[web-sys-0.3.70.sha256sum] = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0"
+SRC_URI[winapi-0.3.9.sha256sum] = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+SRC_URI[winapi-i686-pc-windows-gnu-0.4.0.sha256sum] = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+SRC_URI[winapi-x86_64-pc-windows-gnu-0.4.0.sha256sum] = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+SRC_URI[windows-sys-0.48.0.sha256sum] = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+SRC_URI[windows-sys-0.52.0.sha256sum] = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+SRC_URI[windows-sys-0.59.0.sha256sum] = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+SRC_URI[windows-targets-0.48.5.sha256sum] = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+SRC_URI[windows-targets-0.52.6.sha256sum] = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+SRC_URI[windows_aarch64_gnullvm-0.48.5.sha256sum] = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+SRC_URI[windows_aarch64_gnullvm-0.52.6.sha256sum] = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+SRC_URI[windows_aarch64_msvc-0.48.5.sha256sum] = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+SRC_URI[windows_aarch64_msvc-0.52.6.sha256sum] = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+SRC_URI[windows_i686_gnu-0.48.5.sha256sum] = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+SRC_URI[windows_i686_gnu-0.52.6.sha256sum] = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+SRC_URI[windows_i686_gnullvm-0.52.6.sha256sum] = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+SRC_URI[windows_i686_msvc-0.48.5.sha256sum] = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+SRC_URI[windows_i686_msvc-0.52.6.sha256sum] = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+SRC_URI[windows_x86_64_gnu-0.48.5.sha256sum] = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+SRC_URI[windows_x86_64_gnu-0.52.6.sha256sum] = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+SRC_URI[windows_x86_64_gnullvm-0.48.5.sha256sum] = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+SRC_URI[windows_x86_64_gnullvm-0.52.6.sha256sum] = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+SRC_URI[windows_x86_64_msvc-0.48.5.sha256sum] = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+SRC_URI[windows_x86_64_msvc-0.52.6.sha256sum] = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
diff --git a/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/Cargo.toml b/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/Cargo.toml
deleted file mode 100644 (file)
index 08d012c..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-[package]
-name = "vhost-device-can"
-version = "0.0.1"
-authors = ["Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com>"]
-description = "vhost can backend device"
-repository = "https://github.com/rust-vmm/vhost-device"
-readme = "README.md"
-keywords = ["can", "vhost", "virt", "backend"]
-license = "Apache-2.0 OR BSD-3-Clause"
-edition = "2021"
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[features]
-xen = ["vm-memory/xen", "vhost/xen", "vhost-user-backend/xen"]
-
-[dependencies]
-queues = "1.0.2"
-socketcan = "3.2"
-clap = { version = "4.2.5",  features = ["derive"] }
-env_logger = "0.10"
-libc = "0.2"
-log = "0.4"
-thiserror = "1.0"
-vhost = { version = "0.8", features = ["vhost-user-slave"] }
-vhost-user-backend = "0.10"
-virtio-bindings = "0.2.1"
-virtio-queue = "0.9"
-vm-memory = "0.12"
-vmm-sys-util = "0.11"
-
-[dev-dependencies]
-assert_matches = "1.5"
-virtio-queue = { version = "0.9", features = ["test-utils"] }
-vm-memory = { version = "0.12", features = ["backend-mmap", "backend-atomic"] }
diff --git a/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/README.md b/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/README.md
deleted file mode 100644 (file)
index fd50c27..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-# vhost-device-can - CAN emulation backend daemon
-
-## Description
-This program is a vhost-user backend that emulates a VirtIO CAN device.
-The device's binary takes three (3) parameters:  a socket, a 'can-out' and a
-'can-in' device name. The socket is commonly used across all vhost-devices to
-communicate with the vhost-user frontend device.
-
-The 'can-out' represents
-the actual CAN/FD device appears in the host system which vhost-device-can will
-forward the messages from the frontend side. Finaly, the 'can-in' is again a
-CAN/FD device connected on the host systems and vhost-device-can reads CAN/FD
-frames and sends them to the frontend. The 'can-in' and 'can-out' can be find
-by "ip link show" command. Also, the vhost-device-can may have the same CAN/FD
-device name for both 'can-in' and 'can-out', if the user desires to setup a
-loopback configuration.
-
-
-This program is tested with Virtio-loopback's `-device vhost-user-can`.
-Examples section below.
-
-## Synopsis
-
-**vhost-device-can** [*OPTIONS*]
-
-## Options
-
-.. program:: vhost-device-gpio
-
-.. option:: -h, --help
-
-  Print help.
-
-.. option:: -s, --socket-path=PATH
-
-.. option:: -i, --can-int='CAN/FD interface name'
-
-  The name of the input CAN interface to retrive CAN frames by
-
-.. option:: -o, --can-out='CAN/FD interface name'
-
-  The name of the ouput CAN interface to send the CAN frames
-
-## Examples
-
-The daemon should be started first:
-
-::
-
-  host# vhost-device-can --socket-path=can.sock --can-in="can0" --can-out="can1"
-
-The virtio-looback invocation needs to insert the [virtio-loopback-transport](https://git.virtualopensystems.com/virtio-loopback/loopback_driver/-/tree/epsilon-release) driver
-and then start the [virito-loopback-adapter](https://git.virtualopensystems.com/virtio-loopback/adapter_app/-/tree/epsilon-release) which is the intermediate between
-vhost-device and virtio-loopback-transport driver.
-
-::
-
-  host# sudo insmod loopback_driver.ko
-  host# sudo ./adapter -s /path/to/can.sock0 -d vhucan
-
-## License
-
-This project is licensed under either of
-
-- [Apache License](http://www.apache.org/licenses/LICENSE-2.0), Version 2.0
-- [BSD-3-Clause License](https://opensource.org/licenses/BSD-3-Clause)
diff --git a/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/src/backend.rs b/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/src/backend.rs
deleted file mode 100644 (file)
index 177c76c..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-// VIRTIO CAN Emulation via vhost-user
-//
-// Copyright 2023 VIRTUAL OPEN SYSTEMS SAS. All Rights Reserved.
-//          Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com>
-//
-// SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause
-
-use log::{error, info, warn};
-use std::process::exit;
-use std::sync::{Arc, RwLock};
-use std::thread::{spawn, JoinHandle};
-
-use clap::Parser;
-use thiserror::Error as ThisError;
-use vhost::{vhost_user, vhost_user::Listener};
-use vhost_user_backend::VhostUserDaemon;
-use vm_memory::{GuestMemoryAtomic, GuestMemoryMmap};
-
-use crate::can::{CanController};
-use crate::vhu_can::VhostUserCanBackend;
-
-pub(crate) type Result<T> = std::result::Result<T, Error>;
-
-#[derive(Debug, ThisError)]
-/// Errors related to low level CAN helpers
-pub(crate) enum Error {
-    #[error("Invalid socket count: {0}")]
-    SocketCountInvalid(usize),
-    #[error("Failed to join threads")]
-    FailedJoiningThreads,
-    #[error("Could not create can controller: {0}")]
-    CouldNotCreateCanController(crate::can::Error),
-    #[error("Could not create can backend: {0}")]
-    CouldNotCreateBackend(crate::vhu_can::Error),
-    #[error("Could not create daemon: {0}")]
-    CouldNotCreateDaemon(vhost_user_backend::Error),
-}
-
-#[derive(Parser, Debug)]
-#[clap(author, version, about, long_about = None)]
-struct CanArgs {
-    /// Location of vhost-user Unix domain socket. This is suffixed by 0,1,2..socket_count-1.
-    #[clap(short, long)]
-    socket_path: String,
-
-    /// A can device name to be used for reading (ex. vcan, can0, can1, ... etc.)
-    #[clap(short = 'i', long)]
-    can_in: String,
-
-    /// A can device name to be used for writing (ex. vcan, can0, can1, ... etc.)
-    #[clap(short = 'o', long)]
-    can_out: String,
-
-    /// Number of guests (sockets) to connect to.
-    #[clap(short = 'c', long, default_value_t = 1)]
-    socket_count: u32,
-}
-
-#[derive(PartialEq, Debug)]
-struct CanConfiguration {
-    socket_path: String,
-    socket_count: u32,
-    can_in: String,
-    can_out: String,
-}
-
-impl TryFrom<CanArgs> for CanConfiguration {
-    type Error = Error;
-
-    fn try_from(args: CanArgs) -> Result<Self> {
-
-        if args.socket_count == 0 {
-            return Err(Error::SocketCountInvalid(0));
-        }
-
-               let can_in = args.can_in.trim().to_string();
-               let can_out = args.can_out.trim().to_string();
-
-        Ok(CanConfiguration {
-            socket_path: args.socket_path,
-                       socket_count: args.socket_count,
-            can_in,
-            can_out,
-        })
-    }
-}
-
-fn start_backend(args: CanArgs) -> Result<()> {
-
-       println!("start_backend function!\n");
-
-    let config = CanConfiguration::try_from(args).unwrap();
-    let mut handles = Vec::new();
-
-    for _ in 0..config.socket_count {
-        let socket = config.socket_path.to_owned();
-        let can_in = config.can_in.to_owned();
-        let can_out = config.can_out.to_owned();
-
-        let handle: JoinHandle<Result<()>> = spawn(move || loop {
-            // A separate thread is spawned for each socket and can connect to a separate guest.
-            // These are run in an infinite loop to not require the daemon to be restarted once a
-            // guest exits.
-            //
-            // There isn't much value in complicating code here to return an error from the
-            // threads, and so the code uses unwrap() instead. The panic on a thread won't cause
-            // trouble to other threads/guests or the main() function and should be safe for the
-            // daemon.
-
-            let controller =
-                CanController::new(can_in.clone(), can_out.clone()).map_err(Error::CouldNotCreateCanController)?;
-                       let shared_controller_1 =  Arc::new(RwLock::new(controller));
-                       let shared_controller_2 =  shared_controller_1.clone();
-            let vu_can_backend = Arc::new(RwLock::new(
-                VhostUserCanBackend::new(shared_controller_1).map_err(Error::CouldNotCreateBackend)?,
-            ));
-                       let _read_hanlde = CanController::start_read_thread(shared_controller_2);
-
-            let mut daemon = VhostUserDaemon::new(
-                String::from("vhost-device-can-backend"),
-                vu_can_backend.clone(),
-                GuestMemoryAtomic::new(GuestMemoryMmap::new()),
-            )
-            .map_err(Error::CouldNotCreateDaemon)?;
-
-                       /* Start the read thread -- need to handle it after termination */
-                       let vring_workers = daemon.get_epoll_handlers();
-                       vu_can_backend.read()
-                                                 .unwrap()
-                                                 .set_vring_worker(&vring_workers[0]);
-
-            let listener = Listener::new(socket.clone(), true).unwrap();
-            daemon.start(listener).unwrap();
-
-            match daemon.wait() {
-                Ok(()) => {
-                    info!("Stopping cleanly.");
-                }
-                Err(vhost_user_backend::Error::HandleRequest(
-                    vhost_user::Error::PartialMessage | vhost_user::Error::Disconnected,
-                )) => {
-                    info!("vhost-user connection closed with partial message. If the VM is shutting down, this is expected behavior; otherwise, it might be a bug.");
-                }
-                Err(e) => {
-                    warn!("Error running daemon: {:?}", e);
-                }
-            }
-
-            // No matter the result, we need to shut down the worker thread.
-            vu_can_backend.read().unwrap().exit_event.write(1).unwrap();
-        });
-
-        handles.push(handle);
-    }
-
-    for handle in handles {
-        handle.join().map_err(|_| Error::FailedJoiningThreads)??;
-    }
-
-    Ok(())
-}
-
-pub(crate) fn can_init() {
-    env_logger::init();
-       println!("Can_init function!");
-    if let Err(e) = start_backend(CanArgs::parse()) {
-        error!("{e}");
-        exit(1);
-    }
-}
diff --git a/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/src/can.rs b/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/src/can.rs
deleted file mode 100644 (file)
index 228266f..0000000
+++ /dev/null
@@ -1,264 +0,0 @@
-// CAN backend device
-//
-// Copyright 2023 VIRTUAL OPEN SYSTEMS SAS. All Rights Reserved.
-//          Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com>
-//
-// SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause
-
-use log::{warn, error};
-use std::sync::{Arc, RwLock};
-
-use thiserror::Error as ThisError;
-use vm_memory::{ByteValued, Le16};
-
-extern crate socketcan;
-use socketcan::{
-       CanFdSocket, CanFdFrame, CanAnyFrame, EmbeddedFrame, Socket,
-       Frame, StandardId,
-};
-
-use std::thread::{JoinHandle, spawn};
-use vmm_sys_util::eventfd::{EFD_NONBLOCK, EventFd};
-
-extern crate queues;
-use queues::*;
-
-use crate::vhu_can::{VirtioCanFrame, VIRTIO_CAN_STATUS_OK};
-
-type Result<T> = std::result::Result<T, Error>;
-
-#[derive(Copy, Clone, Debug, PartialEq, ThisError)]
-/// Errors related to low level gpio helpers
-pub(crate) enum Error {
-    //#[error("Can not enabled yet")]
-    //CanNotEnabled,
-    #[error("Can open socket operation failed")]
-    CanSocketFailed,
-    #[error("Can write socket operation failed")]
-    CanSocketWriteFailed,
-    #[error("Can read socket operation failed")]
-    CanSocketReadFailed,
-    #[error("Pop can element operation failed")]
-    CanPopFailed,
-    #[error("Creating Eventfd for CAN events failed")]
-       CanEventFdFailed,
-    #[error("CanQueueFailed")]
-    CanQueueFailed,
-}
-
-/* CAN flags to determine type of CAN Id */
-pub(crate) const VIRTIO_CAN_FLAGS_EXTENDED: u32 = 0x8000;
-pub(crate) const VIRTIO_CAN_FLAGS_FD: u32 = 0x4000;
-pub(crate) const VIRTIO_CAN_FLAGS_RTR: u32 = 0x2000;
-
-pub(crate) const VIRTIO_CAN_TX: u16 = 0x0001;
-pub(crate) const VIRTIO_CAN_RX: u16 = 0x0101;
-
-pub(crate) const CAN_EFF_FLAG: u32 = 0x80000000; /* EFF/SFF is set in the MSB */
-pub(crate) const CAN_RTR_FLAG: u32 = 0x40000000; /* remote transmission request */
-pub(crate) const CAN_ERR_FLAG: u32 = 0x20000000; /* error message frame */
-
-pub(crate) const CAN_SFF_MASK: u32 = 0x000007FF; /* standard frame format (SFF) */
-pub(crate) const CAN_EFF_MASK: u32 = 0x1FFFFFFF; /* extended frame format (EFF) */
-
-//pub(crate) const CAN_FRMF_BRS: u32 = 0x01; /* bit rate switch (2nd bitrate for data) */
-//pub(crate) const CAN_FRMF_ESI: u32 = 0x02; /* error state ind. of transmitting node */
-pub(crate) const CAN_FRMF_TYPE_FD: u32 = 0x10; /* internal bit ind. of CAN FD frame */
-pub(crate) const CAN_ERR_BUSOFF: u32 = 0x00000040; /* bus off */
-
-/// Virtio Can Configuration
-#[derive(Copy, Clone, Debug, Default, PartialEq)]
-#[repr(C)]
-pub(crate) struct VirtioCanConfig {
-       /* CAN controller status */
-    pub(crate) status: Le16,
-}
-
-// SAFETY: The layout of the structure is fixed and can be initialized by
-// reading its content from byte array.
-unsafe impl ByteValued for VirtioCanConfig {}
-
-#[derive(Debug)]
-pub(crate) struct CanController {
-    config: VirtioCanConfig,
-    pub can_in_name: String,
-    pub can_out_name: String,
-       can_out_socket: CanFdSocket,
-       pub rx_event_fd: EventFd,
-       rx_fifo: Queue<VirtioCanFrame>,
-}
-
-impl CanController {
-    // Creates a new controller corresponding to `device`.
-    pub(crate) fn new(can_in_name: String, can_out_name: String) -> Result<CanController> {
-
-        let can_in_name = can_in_name.to_owned();
-               println!("can_in_name: {:?}", can_in_name);
-
-        let can_out_name = can_out_name.to_owned();
-               println!("can_out_name: {:?}", can_out_name);
-
-               let can_out_socket = Self::open_can_sockets(can_out_name.clone());
-
-               let rx_fifo = Queue::new();
-
-               let rx_efd = EventFd::new(EFD_NONBLOCK).map_err(|_| Error::CanEventFdFailed)?;
-
-        Ok(CanController {
-            config: VirtioCanConfig {
-                status: 0x0.into(),
-            },
-            can_in_name,
-            can_out_name,
-                       can_out_socket,
-                       rx_event_fd: rx_efd,
-                       rx_fifo
-        })
-    }
-
-       pub fn print_can_frame (canframe: VirtioCanFrame) {
-               println!("canframe.msg_type 0x{:x}", canframe.msg_type.to_native());
-        println!("canframe.can_id 0x{:x}", canframe.can_id.to_native());
-        println!("canframe.length {}", canframe.length.to_native());
-        println!("canframe.flags 0x{:x}", canframe.flags.to_native());
-               if canframe.length.to_native() == 0 {
-                       println!("[]");
-                       return;
-               }
-        print!("[");
-        let last_elem = canframe.length.to_native() as usize - 1;
-        for (index, sdu) in canframe.sdu.iter().enumerate() {
-            print!("0x{:x}, ", sdu);
-          if index == last_elem {
-              print!("0x{:x}", sdu);
-                         break;
-          }
-        }
-        println!("]");
-       }
-
-       /* FIXME: This thread is not handle after termination */
-       pub fn start_read_thread (controller: Arc<RwLock<CanController>>) -> JoinHandle<Result<()>> {
-               spawn(move || {
-                               CanController::read_can_socket(controller)
-                       }
-               )
-       }
-
-    pub fn push(&mut self, rx_elem: VirtioCanFrame) -> Result<()> {
-               match self.rx_fifo.add(rx_elem) {
-                       Ok(_) => Ok(()), // Successfully added, so return Ok(())
-                       _ => Err(Error::CanQueueFailed), // Handle other errors
-               }
-    }
-
-    pub fn pop(&mut self) -> Result<VirtioCanFrame> {
-               match self.rx_fifo.remove() {
-           Ok(item) => Ok(item),
-           _ => Err(Error::CanPopFailed),
-       }
-    }
-
-       fn open_can_sockets (can_out_name: String) -> CanFdSocket {
-           let can_out_socket = match CanFdSocket::open(&can_out_name) {
-                       Ok(socket) => socket,
-               Err(_) => {
-                   warn!("Error opening CAN socket");
-                   panic!("Failed to open CAN socket.");
-                               //return Err(Error::CanSocketFailed);
-               }
-           };
-
-               can_out_socket
-       }
-
-       pub fn read_can_socket (controller: Arc<RwLock<CanController>>) -> Result<()> {
-               let can_in_name = &controller.read().unwrap().can_in_name.clone();
-               dbg!("Start reading from {} socket!", &can_in_name);
-           let socket = match CanFdSocket::open(&can_in_name) {
-                       Ok(socket) => socket,
-               Err(_) => {
-                   warn!("Error opening CAN socket");
-                               return Err(Error::CanSocketFailed);
-               }
-           };
-
-               // Receive CAN messages
-           loop {
-                       if let Ok(frame) = socket.read_frame() {
-
-                               let mut controller = controller.write().unwrap();
-                           match frame {
-                                       CanAnyFrame::Normal(frame) => {
-                                   // Regular CAN frame
-                                   println!("Received CAN message: {:?}", frame);
-                               }
-                               CanAnyFrame::Fd(frame) => {
-                                   // CAN FD frame
-                                   println!("Received CAN FD message: {:?}", frame);
-
-                                               let read_can_frame = VirtioCanFrame {
-                                                       msg_type: VIRTIO_CAN_RX.into(),
-                                                       can_id: frame.raw_id().into(),
-                                                       length: (frame.data().len() as u16).into(),
-                                                       reserved: 0.into(),
-                                                       flags: frame.id_flags().bits().into(),
-                                                       sdu: {
-                                                               let mut sdu_data: [u8; 64] = [0; 64];
-                                                               for i in 0..frame.data().len() {
-                                                                   sdu_data[i] = frame.data()[i];
-                                                               }
-                                                           sdu_data
-                                                       },
-                                               };
-
-                                               match controller.push(read_can_frame) {
-                                                       Ok(_) => warn!("New Can frame was received"),
-                                           Err(_) => {
-                                               warn!("Error read/push CAN frame");
-                                                               return Err(Error::CanSocketReadFailed);
-                                           }
-                                       }
-                               }
-                               CanAnyFrame::Remote(frame) => {
-                                   // Remote CAN frame
-                                   println!("Received Remote CAN message: {:?}", frame);
-                               }
-                               CanAnyFrame::Error(frame) => {
-                                   // Error frame
-                                   println!("Received Error frame: {:?}", frame);
-                               }
-                           }
-
-                               controller.rx_event_fd.write(1).unwrap();
-               }
-           }
-       }
-
-    pub(crate) fn config(&self) -> &VirtioCanConfig {
-               log::trace!("Get config\n");
-        &self.config
-    }
-
-    pub(crate) fn operation(&self, tx_request: VirtioCanFrame) -> Result<u8> {
-               log::trace!("Can operation\n");
-
-           // Create a CAN frame with a specific CAN-ID and the data buffer
-               let can_id = StandardId::new(tx_request.can_id.to_native().try_into().unwrap()).unwrap();
-               let data_len = tx_request.length.to_native() as usize;
-
-               let data: Vec<u8> = tx_request.sdu.iter().cloned().take(data_len).collect();
-           let frame = CanFdFrame::new(can_id, &data).unwrap();
-
-           // Send the CAN frame
-           let write_result = self.can_out_socket.write_frame(&frame); 
-           match write_result {
-                       Ok(_) => Ok(VIRTIO_CAN_STATUS_OK),
-               Err(_) => {
-                   warn!("Error write CAN socket");
-                               Err(Error::CanSocketWriteFailed)
-               }
-           }
-    }
-}
-
diff --git a/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/src/main.rs b/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/src/main.rs
deleted file mode 100644 (file)
index e89934e..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-// VIRTIO CAN Emulation via vhost-user
-//
-// Copyright 2023 VIRTUAL OPEN SYSTEMS SAS. All Rights Reserved.
-//          Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com>
-//
-// SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause
-
-#[cfg(target_env = "gnu")]
-mod backend;
-#[cfg(target_env = "gnu")]
-mod can;
-#[cfg(target_env = "gnu")]
-mod vhu_can;
-
-#[cfg(target_env = "gnu")]
-fn main() {
-       println!("Hello to main vhost-user-can");
-    backend::can_init()
-}
-
-// Rust vmm container (https://github.com/rust-vmm/rust-vmm-container) doesn't
-// have tools to do a musl build at the moment, and adding that support is
-// tricky as well to the container. Skip musl builds until the time pre-built
-// libgpiod library is available for musl.
-#[cfg(target_env = "musl")]
-fn main() {}
diff --git a/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/src/vhu_can.rs b/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/src/vhu_can.rs
deleted file mode 100644 (file)
index 6aa1248..0000000
+++ /dev/null
@@ -1,732 +0,0 @@
-// vhost device can
-//
-// Copyright 2023 VIRTUAL OPEN SYSTEMS SAS. All Rights Reserved.
-//          Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com>
-//
-// SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause
-
-use log::{warn, error};
-use std::mem::size_of;
-use std::slice::from_raw_parts;
-use std::sync::{Arc, RwLock};
-use std::{
-    convert,
-    io::{self, Result as IoResult},
-};
-use std::os::fd::AsRawFd;
-use thiserror::Error as ThisError;
-use vhost::vhost_user::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures};
-use vhost_user_backend::{VhostUserBackendMut, VringRwLock, VringT};
-use virtio_bindings::bindings::virtio_config::{VIRTIO_F_NOTIFY_ON_EMPTY, VIRTIO_F_VERSION_1};
-use virtio_bindings::bindings::virtio_ring::{
-    VIRTIO_RING_F_EVENT_IDX, VIRTIO_RING_F_INDIRECT_DESC,
-};
-use virtio_queue::{DescriptorChain, QueueOwnedT};
-use vm_memory::{
-    ByteValued, Bytes, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryLoadGuard,
-    GuestMemoryMmap, Le16, Le32,
-};
-use vmm_sys_util::epoll::EventSet;
-use vmm_sys_util::eventfd::{EventFd, EFD_NONBLOCK};
-use crate::can::{
-       CanController, CAN_EFF_FLAG, CAN_RTR_FLAG, CAN_ERR_FLAG, CAN_SFF_MASK,
-       CAN_EFF_MASK, VIRTIO_CAN_FLAGS_FD, VIRTIO_CAN_FLAGS_RTR,
-       VIRTIO_CAN_FLAGS_EXTENDED, VIRTIO_CAN_TX, VIRTIO_CAN_RX,
-       CAN_FRMF_TYPE_FD, CAN_ERR_BUSOFF,
-};
-use vhost_user_backend::VringEpollHandler;
-
-/// Feature bit numbers
-pub const VIRTIO_CAN_F_CAN_CLASSIC: u16 = 0;
-pub const VIRTIO_CAN_F_CAN_FD: u16 = 1;
-//pub const VIRTIO_CAN_F_LATE_TX_ACK: u16 = 2;
-pub const VIRTIO_CAN_F_RTR_FRAMES: u16 = 3;
-
-/// Possible values of the status field
-pub const VIRTIO_CAN_STATUS_OK: u8 = 0x0;
-pub const VIRTIO_CAN_STATUS_ERR: u8 = 0x1;
-
-/// CAN Control messages
-const VIRTIO_CAN_SET_CTRL_MODE_START: u16 = 0x0201;
-const VIRTIO_CAN_SET_CTRL_MODE_STOP: u16 = 0x0202;
-
-/// Virtio configuration
-const QUEUE_SIZE: usize = 64;
-const NUM_QUEUES: usize = 3;
-
-/// Queues
-const TX_QUEUE: u16 = 0;
-const RX_QUEUE: u16 = 1;
-const CTRL_QUEUE: u16 = 2;
-const BACKEND_EFD: u16 = 4;
-
-type Result<T> = std::result::Result<T, Error>;
-
-#[derive(Copy, Clone, Debug, PartialEq, ThisError)]
-/// Errors related to vhost-device-gpio-daemon.
-pub(crate) enum Error {
-    #[error("Failed to handle event, didn't match EPOLLIN")]
-    HandleEventNotEpollIn,
-    #[error("Failed to handle unknown event")]
-    HandleEventUnknown,
-    #[error("Received unexpected write only descriptor at index {0}")]
-    UnexpectedWriteOnlyDescriptor(usize),
-    #[error("Received unexpected readable descriptor at index {0}")]
-    UnexpectedReadableDescriptor(usize),
-    #[error("Invalid descriptor count {0}")]
-    UnexpectedDescriptorCount(usize),
-    #[error("Invalid descriptor size, expected: {0}, found: {1}")]
-    UnexpectedDescriptorSize(usize, u32),
-    #[error("Descriptor not found")]
-    DescriptorNotFound,
-    #[error("Descriptor read failed")]
-    DescriptorReadFailed,
-    #[error("Descriptor write failed")]
-    DescriptorWriteFailed,
-    #[error("Failed to send notification")]
-    NotificationFailed,
-    #[error("Failed to create new EventFd")]
-    EventFdFailed,
-    #[error("Unknown can message type: {0}")]
-       UnexpectedCanMsgType(u16),
-    #[error("RTR frames not negotiated")]
-       UnexpectedRtrFlag,
-    #[error("Can FD frames not negotiated")]
-       UnexpectedFdFlag,
-    #[error("Classic CAN frames not negotiated")]
-       UnexpectedClassicFlag,
-}
-
-impl convert::From<Error> for io::Error {
-    fn from(e: Error) -> Self {
-        io::Error::new(io::ErrorKind::Other, e)
-    }
-}
-
-/// Virtio CAN Request / Response messages
-///
-/// The response message is a stream of bytes, where first byte represents the
-/// status, and rest is message specific data.
-
-#[derive(Copy, Clone, Default)]
-#[repr(C)]
-struct VirtioCanTxResponse {
-    result: i8,
-}
-// SAFETY: The layout of the structure is fixed and can be initialized by
-// reading its content from byte array.
-unsafe impl ByteValued for VirtioCanTxResponse {}
-
-#[derive(Copy, Clone, Debug)]
-#[repr(C)]
-pub struct VirtioCanFrame {
-       pub msg_type: Le16,
-    pub length: Le16,   /* 0..8 CC, 0..64 CAN­FD, 0..2048 CAN­XL, 12 bits */
-       pub reserved: Le32, /* May be needed in part for CAN XL priority */
-    pub flags: Le32,
-    pub can_id: Le32,
-    pub sdu: [u8; 64],
-}
-
-impl Default for VirtioCanFrame {
-    fn default() -> Self {
-        VirtioCanFrame {
-            msg_type: Le16::default(),
-            length: Le16::default(),
-            reserved: Le32::default(),
-            flags: Le32::default(),
-            can_id: Le32::default(),
-            sdu: [0; 64], // Initialize "asd" with default value (0 in this case)
-        }
-    }
-}
-
-// SAFETY: The layout of the structure is fixed and can be initialized by
-// reading its content from byte array.
-unsafe impl ByteValued for VirtioCanFrame {}
-
-#[derive(Copy, Clone, Default)]
-#[repr(C)]
-struct VirtioCanCtrlRequest {
-       msg_type: Le16,
-}
-// SAFETY: The layout of the structure is fixed and can be initialized by
-// reading its content from byte array.
-unsafe impl ByteValued for VirtioCanCtrlRequest {}
-
-#[derive(Copy, Clone, Default)]
-#[repr(C)]
-struct VirtioCanCtrlResponse {
-    result: i8,
-}
-// SAFETY: The layout of the structure is fixed and can be initialized by
-// reading its content from byte array.
-unsafe impl ByteValued for VirtioCanCtrlResponse {}
-
-pub(crate) struct VhostUserCanBackend {
-    controller: Arc<RwLock<CanController>>,
-       acked_features: u64,
-    event_idx: bool,
-    pub(crate) exit_event: EventFd,
-    mem: Option<GuestMemoryAtomic<GuestMemoryMmap>>,
-}
-
-type CanDescriptorChain = DescriptorChain<GuestMemoryLoadGuard<GuestMemoryMmap<()>>>;
-
-impl VhostUserCanBackend {
-    pub(crate) fn new(controller: Arc<RwLock<CanController>>) -> Result<Self> {
-        Ok(VhostUserCanBackend {
-            controller: controller,
-            event_idx: false,
-                       acked_features: 0x0,
-            exit_event: EventFd::new(EFD_NONBLOCK).map_err(|_| Error::EventFdFailed)?,
-            mem: None,
-        })
-    }
-
-       fn check_features (&self, features: u16) -> bool {
-               (self.acked_features & (1 << features)) != 0
-       }
-
-    fn process_ctrl_requests(
-               &self,
-               requests: Vec<CanDescriptorChain>,
-               vring: &VringRwLock
-       ) -> Result<bool> {
-               dbg!("process_ctrl_requests");
-
-        if requests.is_empty() {
-            return Ok(true);
-        }
-
-        for desc_chain in requests {
-                       let descriptors: Vec<_> = desc_chain.clone().collect();
-
-            if descriptors.len() < 1 {
-                               warn!("Error::UnexpectedDescriptorCount");
-                return Err(Error::UnexpectedDescriptorCount(descriptors.len()));
-            }
-
-                       println!("descriptors.len(): {:?}", descriptors.len());
-
-            let desc_request = descriptors[0];
-            if desc_request.is_write_only() {
-                               warn!("Error::UnexpectedWriteOnlyDescriptor");
-                return Err(Error::UnexpectedWriteOnlyDescriptor(0));
-            }
-
-            if desc_request.len() as usize != size_of::<VirtioCanCtrlRequest>() {
-                               println!("UnexpectedDescriptorSize, len = {:?}", desc_request.len());
-                return Err(Error::UnexpectedDescriptorSize(
-                    size_of::<VirtioCanCtrlRequest>(),
-                    desc_request.len(),
-                ));
-            }
-
-            let request = desc_chain
-                .memory()
-                .read_obj::<VirtioCanCtrlRequest>(desc_request.addr())
-                .map_err(|_| Error::DescriptorReadFailed)?;
-
-
-           match request.msg_type.into() {
-                               VIRTIO_CAN_SET_CTRL_MODE_START => {
-                                       println!("VIRTIO_CAN_SET_CTRL_MODE_START");
-                                       //vcan->busoff = false;
-                                       Ok(())
-                               }
-                               VIRTIO_CAN_SET_CTRL_MODE_STOP => {
-                                       println!("VIRTIO_CAN_SET_CTRL_MODE_STOP");
-                       //vcan->busoff = false;
-                                       Ok(())
-                               }
-                               _ => {
-                                       println!("Ctrl queue: msg type 0x{:?} unknown", request.msg_type);
-                                       return Err(Error::HandleEventUnknown.into())
-                               },
-                       }?;
-
-            let desc_response = descriptors[1];
-            if !desc_response.is_write_only() {
-                               println!("This is not wirtable");
-                return Err(Error::UnexpectedReadableDescriptor(1));
-            }
-
-                       let response = VIRTIO_CAN_STATUS_OK;
-
-            desc_chain
-                .memory()
-                .write_slice(response.as_slice(), desc_response.addr())
-                .map_err(|_| Error::DescriptorWriteFailed)?;
-
-            if vring.add_used(desc_chain.head_index(), desc_response.len()).is_err() {
-                println!("Couldn't return used descriptors to the ring");
-                warn!("Couldn't return used descriptors to the ring");
-            }
-        }
-
-        Ok(true)
-    }
-
-    fn process_tx_requests(
-               &self,
-               requests: Vec<CanDescriptorChain>,
-               vring: &VringRwLock
-       ) -> Result<bool> {
-               dbg!("process_tx_requests");
-
-        if requests.is_empty() {
-            return Ok(true);
-        }
-
-               println!("requests.len: {:?}", requests.len());
-        for desc_chain in requests {
-            let descriptors: Vec<_> = desc_chain.clone().collect();
-
-            if descriptors.len() != 2 {
-                               println!("Error::UnexpectedDescriptorCount");
-                return Err(Error::UnexpectedDescriptorCount(descriptors.len()));
-            }
-
-            let desc_request = descriptors[0];
-            if desc_request.is_write_only() {
-                               println!("Error::UnexpectedReadOnlyDescriptor");
-                return Err(Error::UnexpectedWriteOnlyDescriptor(0));
-                       }
-
-            if desc_request.len() as usize != size_of::<VirtioCanFrame>() {
-                           println!("Tx UnexpectedDescriptorSize, len = {:?}", desc_request.len());
-                //return Err(Error::UnexpectedDescriptorSize(
-                //    size_of::<VirtioCanFrame>(),
-                //    desc_request.len(),
-                //));
-            }
-
-            let request = desc_chain
-                .memory()
-                .read_obj::<VirtioCanFrame>(desc_request.addr())
-                .map_err(|_| Error::DescriptorReadFailed)?;
-
-                       CanController::print_can_frame(request);
-
-                       let msg_type = request.msg_type.to_native();
-                       let mut can_id = request.can_id.to_native();
-                       let mut flags = request.flags.to_native();
-                       let mut length = request.length.to_native();
-
-               if msg_type != VIRTIO_CAN_TX {
-                   warn!("TX: Message type 0x{:x} unknown\n", msg_type);
-                return Err(Error::UnexpectedCanMsgType(msg_type));
-               }
-
-               if (flags & VIRTIO_CAN_FLAGS_FD) != 0 {
-                   if length > 64 {
-                       println!("Cut sdu_len from {:?} to 64\n", request.length);
-                       length = 64;
-                   }
-               } else {
-                   if length > 8 {
-                       println!("Cut sdu_len from {:?} to 8\n", request.length);
-                       length = 8;
-                   }
-               }
-
-               /*
-                * Copy Virtio frame structure to qemu frame structure and
-                * check while doing this whether the frame type was negotiated
-                */
-               if (flags & VIRTIO_CAN_FLAGS_EXTENDED) != 0 {
-                   flags &= CAN_EFF_MASK;
-                   flags |= CAN_EFF_FLAG;
-               } else {
-                   flags &= CAN_SFF_MASK;
-               }
-
-               if (flags & VIRTIO_CAN_FLAGS_RTR) != 0 {
-                   if !self.check_features(VIRTIO_CAN_F_CAN_CLASSIC) ||
-                       !self.check_features(VIRTIO_CAN_F_RTR_FRAMES) {
-                       warn!("TX: RTR frames not negotiated");
-                                       return Err(Error::UnexpectedRtrFlag);
-                   }
-                   can_id |= flags | CAN_RTR_FLAG;
-               }
-
-               if (flags & VIRTIO_CAN_FLAGS_FD) != 0 {
-                   if !self.check_features(VIRTIO_CAN_F_CAN_FD) {
-                       warn!("TX: FD frames not negotiated\n");
-                                       return Err(Error::UnexpectedFdFlag);
-                   }
-                   flags |= CAN_FRMF_TYPE_FD;
-               } else {
-                   if !self.check_features(VIRTIO_CAN_F_CAN_CLASSIC) {
-                       warn!("TX: Classic frames not negotiated\n");
-                                       return Err(Error::UnexpectedClassicFlag);
-                   }
-                   flags = 0;
-               }
-
-               let mut corrected_request = VirtioCanFrame::default();
-                       corrected_request.msg_type = msg_type.into();
-                       corrected_request.can_id = can_id.into();
-                       corrected_request.flags = flags.into();
-                       corrected_request.length = length.into();
-                       corrected_request.sdu.copy_from_slice(&request.sdu[0..64]);
-
-            let desc_response = descriptors[1];
-            if !desc_response.is_write_only() {
-                               println!("Error::UnexpectedWriteOnlyDescriptor");
-                return Err(Error::UnexpectedReadableDescriptor(1));
-            }
-
-                       let response = match self.controller.write().unwrap().operation(corrected_request) {
-                               Ok(result) => {
-                                       result
-                       }
-                       Err(_) => {
-                           warn!("We got an error from controller send func");
-                                       VIRTIO_CAN_STATUS_ERR
-                       }
-                       };
-
-            desc_chain
-                .memory()
-                .write_slice(response.as_slice(), desc_response.addr())
-                .map_err(|_| Error::DescriptorWriteFailed)?;
-
-            if vring.add_used(desc_chain.head_index(), desc_response.len()).is_err() {
-                println!("Couldn't return used descriptors to the ring");
-                warn!("Couldn't return used descriptors to the ring");
-            }
-        }
-
-        Ok(true)
-    }
-
-    fn process_rx_requests(
-               &mut self,
-               requests: Vec<CanDescriptorChain>,
-               vring: &VringRwLock
-       ) -> Result<bool> {
-               dbg!("process_rx_requests");
-
-        if requests.is_empty() {
-            return Ok(true);
-        }
-
-        let desc_chain = &requests[0];
-        let descriptors: Vec<_> = desc_chain.clone().collect();
-
-        if descriptors.len() != 1 {
-                       println!("Error::UnexpectedDescriptorCount");
-            return Err(Error::UnexpectedDescriptorCount(descriptors.len()));
-        }
-
-        let desc_response = descriptors[0];
-        if !desc_response.is_write_only() {
-            return Err(Error::UnexpectedReadableDescriptor(1));
-        }
-
-               let mut response = match self.controller.write().unwrap().pop() {
-                   Ok(item) => item,
-                   Err(_) => return Err(Error::HandleEventUnknown),
-               };
-
-               CanController::print_can_frame(response);
-
-        if (response.can_id.to_native() & CAN_ERR_FLAG) != 0 {
-            if (response.can_id.to_native() & CAN_ERR_BUSOFF) != 0 {
-                warn!("Got BusOff error frame, device does a local bus off\n");
-                //vcan->busoff = true;
-            } else {
-                println!("Dropping error frame 0x{:x}\n", response.can_id.to_native());
-            }
-            return Ok(true);
-        }
-
-               let mut can_rx = VirtioCanFrame::default();
-               can_rx.msg_type = VIRTIO_CAN_RX.into();
-               can_rx.can_id = response.can_id;
-               can_rx.length = response.length;
-               can_rx.flags = (can_rx.flags.to_native() | VIRTIO_CAN_FLAGS_FD).into();
-
-        if (response.flags.to_native() & CAN_FRMF_TYPE_FD) != 0 {
-            if !self.check_features(VIRTIO_CAN_F_CAN_FD) {
-                               warn!("Drop non-supported CAN FD frame");
-                               return Err(Error::UnexpectedFdFlag);
-            }
-        } else {
-            if !self.check_features(VIRTIO_CAN_F_CAN_CLASSIC) {
-                               warn!("Drop non-supported CAN classic frame");
-                               return Err(Error::UnexpectedClassicFlag);
-            }
-        }
-        if (response.can_id.to_native() & CAN_RTR_FLAG) != 0 &&
-                       !self.check_features(VIRTIO_CAN_F_RTR_FRAMES) {
-                               warn!("Drop non-supported RTR frame");
-                               return Err(Error::UnexpectedRtrFlag);
-        }
-
-               if (response.can_id.to_native() & CAN_EFF_FLAG) != 0 {
-                   can_rx.flags = VIRTIO_CAN_FLAGS_EXTENDED.into();
-                   can_rx.can_id = (response.can_id.to_native() & CAN_EFF_MASK).into();
-               } else {
-                   can_rx.can_id = (response.can_id.to_native() & CAN_SFF_MASK).into();
-               }
-               if (response.can_id.to_native() & CAN_RTR_FLAG) != 0 {
-                   can_rx.flags = (can_rx.flags.to_native() & VIRTIO_CAN_FLAGS_RTR).into();
-               }
-
-               // HACK AHEAD: Vcan can not be comfigured as CANFD interface, but possible
-               // to configure its MTU to 64 bytes. So if a messages bigger than 8 bytes
-               // is being received we consider it as CANFD message.
-               let can_in_name = self.controller.read().unwrap().can_in_name.clone();
-           if self.check_features(VIRTIO_CAN_F_CAN_FD) &&
-                  response.length.to_native() > 8 && can_in_name == "vcan0" {
-                       response.flags = (response.flags.to_native() | CAN_FRMF_TYPE_FD).into();
-                       warn!("\n\n\nCANFD VCAN0\n\n");
-               }
-
-               if (response.flags.to_native() & CAN_FRMF_TYPE_FD) != 0 {
-                   can_rx.flags = (can_rx.flags.to_native() | VIRTIO_CAN_FLAGS_FD).into();
-                   if response.length.to_native() > 64 {
-                       warn!("%s(): Cut length from {} to 64\n", response.length.to_native());
-                       can_rx.length = 64.into();
-                   }
-               } else {
-                   if response.length.to_native() > 8 {
-                       warn!("%s(): Cut length from {} to 8\n", response.length.to_native());
-                       can_rx.length = 8.into();
-                   }
-               }
-
-               can_rx.sdu.copy_from_slice(&response.sdu[0..64]);
-               CanController::print_can_frame(can_rx);
-
-        desc_chain
-            .memory()
-            .write_slice(can_rx.as_slice(), desc_response.addr())
-            .map_err(|_| Error::DescriptorWriteFailed)?;
-
-        if vring.add_used(desc_chain.head_index(), desc_response.len()).is_err() {
-            warn!("Couldn't return used descriptors to the ring");
-        }
-
-        Ok(true)
-    }
-
-    /// Process the messages in the vring and dispatch replies
-    fn process_ctrl_queue(&mut self, vring: &VringRwLock) -> Result<()> {
-               dbg!("process_ctrl_queue");
-        let requests: Vec<_> = vring
-            .get_mut()
-            .get_queue_mut()
-            .iter(self.mem.as_ref().unwrap().memory())
-            .map_err(|_| Error::DescriptorNotFound)?
-            .collect();
-
-        if self.process_ctrl_requests(requests, vring)? {
-            // Send notification once all the requests are processed
-            vring
-                .signal_used_queue()
-                .map_err(|_| Error::NotificationFailed)?;
-        }
-               Ok(())
-    }
-
-    /// Process the messages in the vring and dispatch replies
-    fn process_tx_queue(&self, vring: &VringRwLock) -> Result<()> {
-               dbg!("process_tx_queue");
-        let requests: Vec<_> = vring
-            .get_mut()
-            .get_queue_mut()
-            .iter(self.mem.as_ref().unwrap().memory())
-            .map_err(|_| Error::DescriptorNotFound)?
-            .collect();
-
-        if self.process_tx_requests(requests, vring)? {
-            // Send notification once all the requests are processed
-            vring
-                .signal_used_queue()
-                .map_err(|_| {
-                                       println!("signal_used_queue error");
-                                       Error::NotificationFailed
-                               })?;
-        }
-
-        Ok(())
-    }
-
-    /// Process the messages in the vring and dispatch replies
-    fn process_rx_queue(&mut self, vring: &VringRwLock) -> Result<()> {
-               dbg!("process_rx_queue");
-        let requests: Vec<_> = vring
-            .get_mut()
-            .get_queue_mut()
-            .iter(self.mem.as_ref().unwrap().memory())
-            .map_err(|_| Error::DescriptorNotFound)?
-            .collect();
-
-        if self.process_rx_requests(requests, vring)? {
-            // Send notification once all the requests are processed
-            vring
-                .signal_used_queue()
-                .map_err(|_| {
-                                       println!("NotificationFailed");
-                                       Error::NotificationFailed
-                               })?;
-        }
-               Ok(())
-    }
-
-    fn process_rx_queue_dump(&mut self, _vring: &VringRwLock) -> Result<()> {
-               dbg!("Do nothing, if you reach that point!");
-               Ok(())
-    }
-
-    /// Set self's VringWorker.
-    pub(crate) fn set_vring_worker(
-               &self,
-        vring_worker: &Arc<VringEpollHandler<Arc<RwLock<VhostUserCanBackend>>, VringRwLock, ()>>,
-    ) {
-               let rx_event_fd = self.controller.read().unwrap().rx_event_fd.as_raw_fd();
-               vring_worker
-            .register_listener(
-                               rx_event_fd,
-                               EventSet::IN,
-                               //u64::from(BACKEND_EFD))
-                               4u64  as u64)
-            .unwrap();
-    }
-}
-
-/// VhostUserBackendMut trait methods
-impl VhostUserBackendMut<VringRwLock, ()>
-    for VhostUserCanBackend
-{
-    fn num_queues(&self) -> usize {
-               println!("num_queues: {:?}", NUM_QUEUES);
-        NUM_QUEUES
-    }
-
-    fn max_queue_size(&self) -> usize {
-               println!("max_queue_size: {:?}", QUEUE_SIZE);
-        QUEUE_SIZE
-    }
-
-    fn features(&self) -> u64 {
-        // this matches the current libvhost defaults except VHOST_F_LOG_ALL
-        let features = 1 << VIRTIO_F_VERSION_1
-            | 1 << VIRTIO_F_NOTIFY_ON_EMPTY
-            | 1 << VIRTIO_RING_F_EVENT_IDX
-                       | 1 << VIRTIO_CAN_F_CAN_CLASSIC
-                       | 1 << VIRTIO_CAN_F_CAN_FD
-            | 1 << VIRTIO_RING_F_INDIRECT_DESC
-            | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits();
-
-               println!("vhu_can->features: {:x}", features);
-               features
-    }
-
-       fn acked_features(&mut self, _features: u64) {
-               println!("\nacked_features: 0x{:x}\n", _features);
-               self.acked_features = _features;
-       }
-
-    fn protocol_features(&self) -> VhostUserProtocolFeatures {
-        let protocol_features = VhostUserProtocolFeatures::MQ
-            | VhostUserProtocolFeatures::CONFIG
-            | VhostUserProtocolFeatures::REPLY_ACK;
-            //| VhostUserProtocolFeatures::STATUS
-
-               println!("protocol_features: {:x}", protocol_features);
-               protocol_features
-    }
-
-    fn get_config(&self, offset: u32, size: u32) -> Vec<u8> {
-        // SAFETY: The layout of the structure is fixed and can be initialized by
-        // reading its content from byte array.
-               dbg!("vhu_can->get_config");
-        unsafe {
-            from_raw_parts(
-                self.controller.write().unwrap()
-                    .config()
-                    .as_slice()
-                    .as_ptr()
-                    .offset(offset as isize) as *const _ as *const _,
-                size as usize,
-            )
-            .to_vec()
-        }
-    }
-
-    fn set_event_idx(&mut self, enabled: bool) {
-        dbg!(self.event_idx = enabled);
-    }
-
-    fn update_memory(&mut self, mem: GuestMemoryAtomic<GuestMemoryMmap>) -> IoResult<()> {
-               dbg!("update_memory\n");
-        self.mem = Some(mem);
-        Ok(())
-    }
-
-    fn handle_event(
-        &mut self,
-        device_event: u16,
-        evset: EventSet,
-        vrings: &[VringRwLock],
-        _thread_id: usize,
-    ) -> IoResult<bool> {
-               dbg!("\nhandle_event:");
-
-        if evset != EventSet::IN {
-            return Err(Error::HandleEventNotEpollIn.into());
-        }
-               if device_event == RX_QUEUE {
-                       println!("RX_QUEUE\n");
-                       return Ok(false);
-               };
-               let vring = if device_event != BACKEND_EFD {
-                       &vrings[device_event as usize]
-               } else {
-                       println!("BACKEND_EFD\n");
-                       let _ = self.controller.write().unwrap().rx_event_fd.read();
-                       &vrings[RX_QUEUE as usize]
-               };
-        if self.event_idx {
-            // vm-virtio's Queue implementation only checks avail_index
-            // once, so to properly support EVENT_IDX we need to keep
-            // calling process_request_queue() until it stops finding
-            // new requests on the queue.
-            loop {
-                vring.disable_notification().unwrap();
-                //match queue_idx {
-                match device_event {
-                    CTRL_QUEUE => self.process_ctrl_queue(vring),
-                    TX_QUEUE => self.process_tx_queue(vring),
-                    RX_QUEUE => self.process_rx_queue_dump(vring),
-                    BACKEND_EFD => self.process_rx_queue(vring),
-                    _ => Err(Error::HandleEventUnknown.into()),
-                }?;
-                if !vring.enable_notification().unwrap() {
-                    break;
-                }
-            }
-        } else {
-            // Without EVENT_IDX, a single call is enough.
-            match device_event {
-                CTRL_QUEUE => self.process_ctrl_queue(vring),
-                TX_QUEUE => self.process_tx_queue(vring),
-                RX_QUEUE => self.process_rx_queue_dump(vring),
-                BACKEND_EFD => self.process_rx_queue(vring),
-                _ => Err(Error::HandleEventUnknown.into()),
-            }?;
-        }
-        Ok(false)
-    }
-
-    fn exit_event(&self, _thread_index: usize) -> Option<EventFd> {
-               dbg!("exit_event\n");
-        self.exit_event.try_clone().ok()
-    }
-}
-
index cf73bc4..cc0fba8 100644 (file)
+# Autogenerated with 'bitbake -c update_crates vhost-device-can'
+
+# from Cargo.lock
 SRC_URI += " \
-    crate://crates.io/serde_derive/1.0.193 \
-    crate://crates.io/autocfg/1.1.0 \
-    crate://crates.io/syn/1.0.109 \
-    crate://crates.io/serde/1.0.193 \
-    crate://crates.io/memoffset/0.7.0 \
-    crate://crates.io/static_assertions/1.1.0 \
-    crate://crates.io/pin-utils/0.1.0 \
-    crate://crates.io/cfg-if/1.0.0 \
-    crate://crates.io/neli-proc-macros/0.1.3 \
-    crate://crates.io/byteorder/1.5.0 \
-    crate://crates.io/either/1.9.0 \
-    crate://crates.io/nix/0.26.0 \
-    crate://crates.io/neli/0.6.4 \
-    crate://crates.io/nb/1.1.0 \
-    crate://crates.io/itertools/0.10.0 \
-    crate://crates.io/hex/0.4.3 \
-    crate://crates.io/embedded-can/0.4.1 \
-    crate://crates.io/byte_conv/0.1.1 \
-    crate://crates.io/queues/1.1.0 \
-    crate://crates.io/socketcan/3.3.0 \
-    crate://crates.io/aho-corasick/1.0.2 \
-    crate://crates.io/anstream/0.3.2 \
-    crate://crates.io/anstyle/1.0.1 \
-    crate://crates.io/anstyle-parse/0.2.1 \
-    crate://crates.io/anstyle-query/1.0.0 \
-    crate://crates.io/anstyle-wincon/1.0.1 \
-    crate://crates.io/arc-swap/1.6.0 \
+    crate://crates.io/aho-corasick/1.1.3 \
+    crate://crates.io/anstream/0.6.15 \
+    crate://crates.io/anstyle/1.0.8 \
+    crate://crates.io/anstyle-parse/0.2.5 \
+    crate://crates.io/anstyle-query/1.1.1 \
+    crate://crates.io/anstyle-wincon/3.0.4 \
+    crate://crates.io/anyhow/1.0.86 \
+    crate://crates.io/arc-swap/1.7.1 \
     crate://crates.io/assert_matches/1.5.0 \
+    crate://crates.io/autocfg/1.3.0 \
     crate://crates.io/bitflags/1.3.2 \
-    crate://crates.io/bitflags/2.3.3 \
-    crate://crates.io/cc/1.0.79 \
-    crate://crates.io/clap/4.2.5 \
-    crate://crates.io/clap_builder/4.2.5 \
-    crate://crates.io/clap_derive/4.2.0 \
-    crate://crates.io/clap_lex/0.4.0 \
-    crate://crates.io/colorchoice/1.0.0 \
-    crate://crates.io/env_logger/0.10.0 \
-    crate://crates.io/errno/0.3.1 \
-    crate://crates.io/errno-dragonfly/0.1.2 \
-    crate://crates.io/heck/0.4.1 \
-    crate://crates.io/hermit-abi/0.3.2 \
+    crate://crates.io/bitflags/2.6.0 \
+    crate://crates.io/byte_conv/0.1.1 \
+    crate://crates.io/byteorder/1.5.0 \
+    crate://crates.io/cfg-if/1.0.0 \
+    crate://crates.io/clap/4.5.16 \
+    crate://crates.io/clap_builder/4.5.15 \
+    crate://crates.io/clap_derive/4.5.13 \
+    crate://crates.io/clap_lex/0.7.2 \
+    crate://crates.io/colorchoice/1.0.2 \
+    crate://crates.io/either/1.13.0 \
+    crate://crates.io/embedded-can/0.4.1 \
+    crate://crates.io/enumn/0.1.14 \
+    crate://crates.io/env_filter/0.1.2 \
+    crate://crates.io/env_logger/0.11.5 \
+    crate://crates.io/epoll/4.3.3 \
+    crate://crates.io/equivalent/1.0.1 \
+    crate://crates.io/errno/0.3.9 \
+    crate://crates.io/fastrand/2.1.1 \
+    crate://crates.io/futures/0.3.30 \
+    crate://crates.io/futures-channel/0.3.30 \
+    crate://crates.io/futures-core/0.3.30 \
+    crate://crates.io/futures-executor/0.3.30 \
+    crate://crates.io/futures-io/0.3.30 \
+    crate://crates.io/futures-macro/0.3.30 \
+    crate://crates.io/futures-sink/0.3.30 \
+    crate://crates.io/futures-task/0.3.30 \
+    crate://crates.io/futures-timer/3.0.3 \
+    crate://crates.io/futures-util/0.3.30 \
+    crate://crates.io/glob/0.3.1 \
+    crate://crates.io/hashbrown/0.14.5 \
+    crate://crates.io/heck/0.5.0 \
+    crate://crates.io/hermit-abi/0.3.9 \
+    crate://crates.io/hex/0.4.3 \
     crate://crates.io/humantime/2.1.0 \
-    crate://crates.io/is-terminal/0.4.9 \
-    crate://crates.io/libc/0.2.147 \
-    crate://crates.io/linux-raw-sys/0.4.3 \
-    crate://crates.io/log/0.4.19 \
-    crate://crates.io/memchr/2.5.0 \
-    crate://crates.io/once_cell/1.18.0 \
-    crate://crates.io/proc-macro2/1.0.67 \
-    crate://crates.io/quote/1.0.29 \
-    crate://crates.io/regex/1.9.1 \
-    crate://crates.io/regex-automata/0.3.2 \
-    crate://crates.io/regex-syntax/0.7.4 \
-    crate://crates.io/rustix/0.38.3 \
-    crate://crates.io/strsim/0.10.0 \
-    crate://crates.io/syn/2.0.28 \
-    crate://crates.io/termcolor/1.2.0 \
-    crate://crates.io/thiserror/1.0.41 \
-    crate://crates.io/thiserror-impl/1.0.41 \
-    crate://crates.io/unicode-ident/1.0.11 \
-    crate://crates.io/utf8parse/0.2.1 \
-    crate://crates.io/vhost/0.8.0 \
-    crate://crates.io/vhost-user-backend/0.10.0 \
-    crate://crates.io/virtio-bindings/0.2.1 \
-    crate://crates.io/virtio-queue/0.9.0 \
-    crate://crates.io/vm-memory/0.12.0 \
-    crate://crates.io/vmm-sys-util/0.11.1 \
+    crate://crates.io/indexmap/2.4.0 \
+    crate://crates.io/is_terminal_polyfill/1.70.1 \
+    crate://crates.io/itertools/0.10.5 \
+    crate://crates.io/libc/0.2.158 \
+    crate://crates.io/linux-raw-sys/0.4.14 \
+    crate://crates.io/log/0.4.22 \
+    crate://crates.io/memchr/2.7.4 \
+    crate://crates.io/memoffset/0.7.1 \
+    crate://crates.io/nb/1.1.0 \
+    crate://crates.io/neli/0.6.4 \
+    crate://crates.io/neli-proc-macros/0.1.3 \
+    crate://crates.io/nix/0.26.4 \
+    crate://crates.io/nix/0.27.1 \
+    crate://crates.io/num_cpus/1.16.0 \
+    crate://crates.io/num_enum/0.7.3 \
+    crate://crates.io/num_enum_derive/0.7.3 \
+    crate://crates.io/once_cell/1.19.0 \
+    crate://crates.io/pin-project-lite/0.2.14 \
+    crate://crates.io/pin-utils/0.1.0 \
+    crate://crates.io/proc-macro-crate/3.1.0 \
+    crate://crates.io/proc-macro2/1.0.86 \
+    crate://crates.io/queues/1.1.0 \
+    crate://crates.io/quote/1.0.37 \
+    crate://crates.io/regex/1.10.6 \
+    crate://crates.io/regex-automata/0.4.7 \
+    crate://crates.io/regex-syntax/0.8.4 \
+    crate://crates.io/relative-path/1.9.3 \
+    crate://crates.io/rstest/0.22.0 \
+    crate://crates.io/rstest_macros/0.22.0 \
+    crate://crates.io/rustc_version/0.4.0 \
+    crate://crates.io/rustix/0.38.34 \
+    crate://crates.io/semver/1.0.23 \
+    crate://crates.io/serde/1.0.209 \
+    crate://crates.io/serde_derive/1.0.209 \
+    crate://crates.io/slab/0.4.9 \
+    crate://crates.io/socket2/0.5.7 \
+    crate://crates.io/strsim/0.11.1 \
+    crate://crates.io/syn/1.0.109 \
+    crate://crates.io/syn/2.0.72 \
+    crate://crates.io/tempfile/3.12.0 \
+    crate://crates.io/thiserror/1.0.63 \
+    crate://crates.io/thiserror-impl/1.0.63 \
+    crate://crates.io/toml_datetime/0.6.8 \
+    crate://crates.io/toml_edit/0.21.1 \
+    crate://crates.io/unicode-ident/1.0.12 \
+    crate://crates.io/utf8parse/0.2.2 \
+    crate://crates.io/vhost/0.11.0 \
+    crate://crates.io/vhost-user-backend/0.15.0 \
+    crate://crates.io/virtio-bindings/0.2.2 \
+    crate://crates.io/virtio-queue/0.12.0 \
+    crate://crates.io/vm-memory/0.14.1 \
+    crate://crates.io/vmm-sys-util/0.12.1 \
     crate://crates.io/winapi/0.3.9 \
     crate://crates.io/winapi-i686-pc-windows-gnu/0.4.0 \
-    crate://crates.io/winapi-util/0.1.5 \
     crate://crates.io/winapi-x86_64-pc-windows-gnu/0.4.0 \
-    crate://crates.io/windows-sys/0.48.0 \
-    crate://crates.io/windows-targets/0.48.1 \
-    crate://crates.io/windows_aarch64_gnullvm/0.48.0 \
-    crate://crates.io/windows_aarch64_msvc/0.48.0 \
-    crate://crates.io/windows_i686_gnu/0.48.0 \
-    crate://crates.io/windows_i686_msvc/0.48.0 \
-    crate://crates.io/windows_x86_64_gnu/0.48.0 \
-    crate://crates.io/windows_x86_64_gnullvm/0.48.0 \
-    crate://crates.io/windows_x86_64_msvc/0.48.0 \
+    crate://crates.io/windows-sys/0.52.0 \
+    crate://crates.io/windows-sys/0.59.0 \
+    crate://crates.io/windows-targets/0.52.6 \
+    crate://crates.io/windows_aarch64_gnullvm/0.52.6 \
+    crate://crates.io/windows_aarch64_msvc/0.52.6 \
+    crate://crates.io/windows_i686_gnu/0.52.6 \
+    crate://crates.io/windows_i686_gnullvm/0.52.6 \
+    crate://crates.io/windows_i686_msvc/0.52.6 \
+    crate://crates.io/windows_x86_64_gnu/0.52.6 \
+    crate://crates.io/windows_x86_64_gnullvm/0.52.6 \
+    crate://crates.io/windows_x86_64_msvc/0.52.6 \
+    crate://crates.io/winnow/0.5.40 \
 "
 
+SRC_URI[aho-corasick-1.1.3.sha256sum] = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
+SRC_URI[anstream-0.6.15.sha256sum] = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526"
+SRC_URI[anstyle-1.0.8.sha256sum] = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
+SRC_URI[anstyle-parse-0.2.5.sha256sum] = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb"
+SRC_URI[anstyle-query-1.1.1.sha256sum] = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a"
+SRC_URI[anstyle-wincon-3.0.4.sha256sum] = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8"
+SRC_URI[anyhow-1.0.86.sha256sum] = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
+SRC_URI[arc-swap-1.7.1.sha256sum] = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
+SRC_URI[assert_matches-1.5.0.sha256sum] = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9"
+SRC_URI[autocfg-1.3.0.sha256sum] = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
+SRC_URI[bitflags-1.3.2.sha256sum] = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+SRC_URI[bitflags-2.6.0.sha256sum] = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
+SRC_URI[byte_conv-0.1.1.sha256sum] = "649972315d4931137a26fc2bf3ca95ee257ad796a5b57bdeb04205c91a4b5780"
+SRC_URI[byteorder-1.5.0.sha256sum] = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+SRC_URI[cfg-if-1.0.0.sha256sum] = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+SRC_URI[clap-4.5.16.sha256sum] = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019"
+SRC_URI[clap_builder-4.5.15.sha256sum] = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6"
+SRC_URI[clap_derive-4.5.13.sha256sum] = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
+SRC_URI[clap_lex-0.7.2.sha256sum] = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
+SRC_URI[colorchoice-1.0.2.sha256sum] = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
+SRC_URI[either-1.13.0.sha256sum] = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
+SRC_URI[embedded-can-0.4.1.sha256sum] = "e9d2e857f87ac832df68fa498d18ddc679175cf3d2e4aa893988e5601baf9438"
+SRC_URI[enumn-0.1.14.sha256sum] = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38"
+SRC_URI[env_filter-0.1.2.sha256sum] = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab"
+SRC_URI[env_logger-0.11.5.sha256sum] = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d"
+SRC_URI[epoll-4.3.3.sha256sum] = "74351c3392ea1ff6cd2628e0042d268ac2371cb613252ff383b6dfa50d22fa79"
+SRC_URI[equivalent-1.0.1.sha256sum] = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+SRC_URI[errno-0.3.9.sha256sum] = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
+SRC_URI[fastrand-2.1.1.sha256sum] = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
+SRC_URI[futures-0.3.30.sha256sum] = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
+SRC_URI[futures-channel-0.3.30.sha256sum] = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
+SRC_URI[futures-core-0.3.30.sha256sum] = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
+SRC_URI[futures-executor-0.3.30.sha256sum] = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
+SRC_URI[futures-io-0.3.30.sha256sum] = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
+SRC_URI[futures-macro-0.3.30.sha256sum] = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
+SRC_URI[futures-sink-0.3.30.sha256sum] = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
+SRC_URI[futures-task-0.3.30.sha256sum] = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
+SRC_URI[futures-timer-3.0.3.sha256sum] = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24"
+SRC_URI[futures-util-0.3.30.sha256sum] = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
+SRC_URI[glob-0.3.1.sha256sum] = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
+SRC_URI[hashbrown-0.14.5.sha256sum] = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+SRC_URI[heck-0.5.0.sha256sum] = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+SRC_URI[hermit-abi-0.3.9.sha256sum] = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
+SRC_URI[hex-0.4.3.sha256sum] = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+SRC_URI[humantime-2.1.0.sha256sum] = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
+SRC_URI[indexmap-2.4.0.sha256sum] = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c"
+SRC_URI[is_terminal_polyfill-1.70.1.sha256sum] = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
+SRC_URI[itertools-0.10.5.sha256sum] = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
+SRC_URI[libc-0.2.158.sha256sum] = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
+SRC_URI[linux-raw-sys-0.4.14.sha256sum] = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
+SRC_URI[log-0.4.22.sha256sum] = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
+SRC_URI[memchr-2.7.4.sha256sum] = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+SRC_URI[memoffset-0.7.1.sha256sum] = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
+SRC_URI[nb-1.1.0.sha256sum] = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d"
+SRC_URI[neli-0.6.4.sha256sum] = "1100229e06604150b3becd61a4965d5c70f3be1759544ea7274166f4be41ef43"
+SRC_URI[neli-proc-macros-0.1.3.sha256sum] = "c168194d373b1e134786274020dae7fc5513d565ea2ebb9bc9ff17ffb69106d4"
+SRC_URI[nix-0.26.4.sha256sum] = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b"
+SRC_URI[nix-0.27.1.sha256sum] = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
+SRC_URI[num_cpus-1.16.0.sha256sum] = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
+SRC_URI[num_enum-0.7.3.sha256sum] = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179"
+SRC_URI[num_enum_derive-0.7.3.sha256sum] = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56"
+SRC_URI[once_cell-1.19.0.sha256sum] = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+SRC_URI[pin-project-lite-0.2.14.sha256sum] = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
+SRC_URI[pin-utils-0.1.0.sha256sum] = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+SRC_URI[proc-macro-crate-3.1.0.sha256sum] = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284"
+SRC_URI[proc-macro2-1.0.86.sha256sum] = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
+SRC_URI[queues-1.1.0.sha256sum] = "1475abae4f8ad4998590fe3acfe20104f0a5d48fc420c817cd2c09c3f56151f0"
+SRC_URI[quote-1.0.37.sha256sum] = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
+SRC_URI[regex-1.10.6.sha256sum] = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
+SRC_URI[regex-automata-0.4.7.sha256sum] = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
+SRC_URI[regex-syntax-0.8.4.sha256sum] = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
+SRC_URI[relative-path-1.9.3.sha256sum] = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2"
+SRC_URI[rstest-0.22.0.sha256sum] = "7b423f0e62bdd61734b67cd21ff50871dfaeb9cc74f869dcd6af974fbcb19936"
+SRC_URI[rstest_macros-0.22.0.sha256sum] = "c5e1711e7d14f74b12a58411c542185ef7fb7f2e7f8ee6e2940a883628522b42"
+SRC_URI[rustc_version-0.4.0.sha256sum] = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
+SRC_URI[rustix-0.38.34.sha256sum] = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
+SRC_URI[semver-1.0.23.sha256sum] = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
+SRC_URI[serde-1.0.209.sha256sum] = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09"
+SRC_URI[serde_derive-1.0.209.sha256sum] = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170"
+SRC_URI[slab-0.4.9.sha256sum] = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
+SRC_URI[socket2-0.5.7.sha256sum] = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
+SRC_URI[strsim-0.11.1.sha256sum] = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+SRC_URI[syn-1.0.109.sha256sum] = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+SRC_URI[syn-2.0.72.sha256sum] = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
+SRC_URI[tempfile-3.12.0.sha256sum] = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64"
+SRC_URI[thiserror-1.0.63.sha256sum] = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
+SRC_URI[thiserror-impl-1.0.63.sha256sum] = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
+SRC_URI[toml_datetime-0.6.8.sha256sum] = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
+SRC_URI[toml_edit-0.21.1.sha256sum] = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1"
+SRC_URI[unicode-ident-1.0.12.sha256sum] = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+SRC_URI[utf8parse-0.2.2.sha256sum] = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+SRC_URI[vhost-0.11.0.sha256sum] = "6be08d1166d41a78861ad50212ab3f9eca0729c349ac3a7a8f557c62406b87cc"
+SRC_URI[vhost-user-backend-0.15.0.sha256sum] = "1f0ffb1dd8e00a708a0e2c32d5efec5812953819888591fff9ff68236b8a5096"
+SRC_URI[virtio-bindings-0.2.2.sha256sum] = "878bcb1b2812a10c30d53b0ed054999de3d98f25ece91fc173973f9c57aaae86"
+SRC_URI[virtio-queue-0.12.0.sha256sum] = "07d8406e7250c934462de585d8f2d2781c31819bca1fbb7c5e964ca6bbaabfe8"
+SRC_URI[vm-memory-0.14.1.sha256sum] = "3c3aba5064cc5f6f7740cddc8dae34d2d9a311cac69b60d942af7f3ab8fc49f4"
+SRC_URI[vmm-sys-util-0.12.1.sha256sum] = "1d1435039746e20da4f8d507a72ee1b916f7b4b05af7a91c093d2c6561934ede"
+SRC_URI[winapi-0.3.9.sha256sum] = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+SRC_URI[winapi-i686-pc-windows-gnu-0.4.0.sha256sum] = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+SRC_URI[winapi-x86_64-pc-windows-gnu-0.4.0.sha256sum] = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+SRC_URI[windows-sys-0.52.0.sha256sum] = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+SRC_URI[windows-sys-0.59.0.sha256sum] = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+SRC_URI[windows-targets-0.52.6.sha256sum] = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+SRC_URI[windows_aarch64_gnullvm-0.52.6.sha256sum] = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+SRC_URI[windows_aarch64_msvc-0.52.6.sha256sum] = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+SRC_URI[windows_i686_gnu-0.52.6.sha256sum] = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+SRC_URI[windows_i686_gnullvm-0.52.6.sha256sum] = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+SRC_URI[windows_i686_msvc-0.52.6.sha256sum] = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+SRC_URI[windows_x86_64_gnu-0.52.6.sha256sum] = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+SRC_URI[windows_x86_64_gnullvm-0.52.6.sha256sum] = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+SRC_URI[windows_x86_64_msvc-0.52.6.sha256sum] = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+SRC_URI[winnow-0.5.40.sha256sum] = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
index 4db8ebe..e54e06f 100644 (file)
@@ -2,10 +2,16 @@ SUMMARY = "vhost CAN backend device"
 DESCRIPTION = "A vhost-user backend that emulates a VirtIO CAN device"
 HOMEPAGE = "https://gerrit.automotivelinux.org"
 
-FILESEXTRAPATHS:prepend := "${THISDIR}:" 
-EXTRAPATHS:prepend := "${THISDIR}:" 
+FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
+EXTRAPATHS:prepend := "${THISDIR}/files:"
 
-SRC_URI = " file://. "
+SRC_URI = "\
+    file://vhost-device-can-0.1.0/ \
+    git://github.com/socketcan-rs/socketcan-rs.git;protocol=https;branch=master \
+"
+SRCREV = "f004ee91e142a37fea36c5d719a57852c7076e87"
+
+SRC_URI[sha256sum] = "f8a0826ee8082e8f6f3549eaa86406ee22187a5d1e3ad940d3788b072cf18991"
 
 LICENSE = "Apache-2.0 | BSD-3-Clause"
 LIC_FILES_CHKSUM = "\
@@ -13,7 +19,15 @@ LIC_FILES_CHKSUM = "\
     file://LICENSE-BSD-3-Clause;md5=2489db1359f496fff34bd393df63947e \
 "
 
+RDEPENDS:${PN}:append = " can-utils"
+
 inherit cargo
 inherit pkgconfig
+inherit cargo-update-recipe-crates
 
 include vhost-device-can-crates.inc
+include socketcan-crates.inc
+
+CARGO_BUILD_FLAGS = "-v --offline --target ${RUST_HOST_SYS} ${BUILD_MODE} --manifest-path=${CARGO_MANIFEST_PATH}"
+
+S = "${WORKDIR}/vhost-device-can-0.1.0"