diff --git a/dae/Makefile b/dae/Makefile
index 56f665cc7..98179fa33 100644
--- a/dae/Makefile
+++ b/dae/Makefile
@@ -5,10 +5,10 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=dae
-PKG_VERSION:=2026.07.30
-PKG_RELEASE:=25
+PKG_VERSION:=2026.07.31
+PKG_RELEASE:=26
-PKG_SOURCE:=dae-src-2026.07.30-305922fc343d.tar.gz
+PKG_SOURCE:=dae-src-2026.07.31-31ea28be65b6.tar.gz
PKG_SOURCE_URL:=https://github.com/kenzok8/openwrt-daede/releases/download/dae-src
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_HASH:=skip
diff --git a/daed/Makefile b/daed/Makefile
index 80abeb8a3..2d95c4d2c 100644
--- a/daed/Makefile
+++ b/daed/Makefile
@@ -5,10 +5,10 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=daed
-PKG_VERSION:=2026.07.30
-PKG_RELEASE:=33
+PKG_VERSION:=2026.07.31
+PKG_RELEASE:=34
-PKG_SOURCE:=daed-src-2026.07.30-6066c5d691b3.tar.gz
+PKG_SOURCE:=daed-src-2026.07.31-fe4d294559c7.tar.gz
PKG_SOURCE_URL:=https://github.com/kenzok8/openwrt-daede/releases/download/daed-src
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_HASH:=skip
diff --git a/luci-app-daede/Makefile b/luci-app-daede/Makefile
index ac0791b61..bba0bb62c 100644
--- a/luci-app-daede/Makefile
+++ b/luci-app-daede/Makefile
@@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-daede
PKG_VERSION:=1.14.7
-PKG_RELEASE:=36
+PKG_RELEASE:=37
PKG_MAINTAINER:=kenzok8
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
diff --git a/luci-app-daede/htdocs/luci-static/resources/view/daede/dae.js b/luci-app-daede/htdocs/luci-static/resources/view/daede/dae.js
index 2eb1e78c1..03e851401 100644
--- a/luci-app-daede/htdocs/luci-static/resources/view/daede/dae.js
+++ b/luci-app-daede/htdocs/luci-static/resources/view/daede/dae.js
@@ -574,6 +574,7 @@ function renderDaeEditor() {
const textarea = E('textarea', {
'class': 'dd-editor dd-editor-hl',
'spellcheck': 'false',
+ 'wrap': 'off',
'placeholder': _('dae config file is empty. Click "Load default config" to start, or paste your config here.')
}, '');
const hlCode = E('code', {});
diff --git a/luci-app-daede/htdocs/luci-static/resources/view/daede/styles.js b/luci-app-daede/htdocs/luci-static/resources/view/daede/styles.js
index 7dd3eac83..954bde6cc 100644
--- a/luci-app-daede/htdocs/luci-static/resources/view/daede/styles.js
+++ b/luci-app-daede/htdocs/luci-static/resources/view/daede/styles.js
@@ -104,7 +104,7 @@ const CSS = [
both share identical box metrics so glyphs line up; the textarea stays the
real editor (caret, selection, insert-at-cursor, jump-to-line all native) */
'.dd-edit-wrap{position:relative}',
- '.dd-edit-wrap .dd-editor,.dd-edit-wrap .dd-hl{margin:0;padding:10px 12px;border-width:1px;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono",monospace;font-size:12px;line-height:1.5;letter-spacing:0;tab-size:4;white-space:pre-wrap;word-break:break-word;box-sizing:border-box}',
+ '.dd-edit-wrap .dd-editor,.dd-edit-wrap .dd-hl{margin:0;padding:10px 12px;border-width:1px;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono",monospace;font-size:12px;line-height:1.5;letter-spacing:0;tab-size:4;white-space:pre;word-break:normal;overflow-x:auto;box-sizing:border-box}',
'.dd-edit-wrap .dd-hl{position:absolute;inset:0;margin:0;overflow:hidden;border:1px solid transparent;border-radius:6px 6px 0 0;pointer-events:none;background:#f6f8fa;color:#3b4252;z-index:1}',
/* reset Argon's code{background:var(--lighter)} so the overlay inherits the
pre background uniformly — otherwise a dark pre shows as side bars.
@@ -117,9 +117,9 @@ const CSS = [
it ghosts over the highlight pre underneath */
'.dd-edit-wrap .dd-editor-hl::selection{background:rgba(56,134,161,.25);color:transparent}',
'@media screen and (max-device-width:600px){.dd-edit-wrap .dd-editor,.dd-edit-wrap .dd-hl,.dd-edit-wrap .dd-hl code{font-size:16px}}',
- '.dh-c{color:#8a919a;font-style:italic}',
+ '.dh-c{color:#8a919a}',
'.dh-s{color:#2a8a4a}',
- '.dh-k{color:#9a3fb5;font-weight:600}',
+ '.dh-k{color:#9a3fb5}',
'.dh-f{color:#2f7288}',
'.dh-o{color:#c2772a}',
'.dh-g{color:#b0226a}',
diff --git a/luci-app-easytier/Makefile b/luci-app-easytier/Makefile
index 11f43369c..24732eefc 100644
--- a/luci-app-easytier/Makefile
+++ b/luci-app-easytier/Makefile
@@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk
-include $(dir $(lastword $(MAKEFILE_LIST)))../version.mk
PKG_VERSION:=$(or $(EASYTIER_VERSION),2.6.4)
-PKG_RELEASE:=12
+PKG_RELEASE:=13
LUCI_TITLE:=LuCI support for EasyTier
LUCI_DEPENDS:=+kmod-tun +easytier +luci-compat
diff --git a/luci-app-easytier/root/etc/init.d/easytier b/luci-app-easytier/root/etc/init.d/easytier
index d0c016ede..86cf72d46 100755
--- a/luci-app-easytier/root/etc/init.d/easytier
+++ b/luci-app-easytier/root/etc/init.d/easytier
@@ -626,17 +626,20 @@ EOF
procd_set_param respawn
procd_close_instance
- if [ ! -z "$socks_port" ] ; then
- echo "$(date '+%Y-%m-%d %H:%M:%S') easytier : 添加防火墙规则 easytier_socks5 放行端口 ${socks_port} " >>/tmp/easytier.log
- uci -q delete firewall.easytier_socks5
- uci set firewall.easytier_socks5=rule
- uci set firewall.easytier_socks5.name="easytier_socks5"
- uci set firewall.easytier_socks5.target="ACCEPT"
- uci set firewall.easytier_socks5.src="wan"
- uci set firewall.easytier_socks5.proto="tcp"
- uci set firewall.easytier_socks5.dest_port="$socks_port"
- uci set firewall.easytier_socks5.enabled="1"
- fi
+ # 不再自动放行 SOCKS5 端口到 WAN —— 无认证 SOCKS5 代理暴露给公网有严重安全风险
+ # 如需公网访问,请手动在 LuCI 防火墙页面添加规则
+ # 如需恢复自动放行,去掉下面各行行首的 # 即可
+ # if [ ! -z "$socks_port" ] ; then
+ # echo "$(date '+%Y-%m-%d %H:%M:%S') easytier : 添加防火墙规则 easytier_socks5 放行端口 ${socks_port} " >>/tmp/easytier.log
+ # uci -q delete firewall.easytier_socks5
+ # uci set firewall.easytier_socks5=rule
+ # uci set firewall.easytier_socks5.name="easytier_socks5"
+ # uci set firewall.easytier_socks5.target="ACCEPT"
+ # uci set firewall.easytier_socks5.src="wan"
+ # uci set firewall.easytier_socks5.proto="tcp"
+ # uci set firewall.easytier_socks5.dest_port="$socks_port"
+ # uci set firewall.easytier_socks5.enabled="1"
+ # fi
if [ "$listenermode" = "ON" ] || [ "$etcmd" = "web" ] ; then
if [ -z "$tcp_port" ] && [ -z "$ws_port" ] && [ -z "$wss_port" ] && [ -z "$wg_port" ] ; then
tcp_port="11010"
diff --git a/luci-app-easytier/root/usr/share/easytier/firewall.sh b/luci-app-easytier/root/usr/share/easytier/firewall.sh
index 3de8bc36d..7758fbdc8 100755
--- a/luci-app-easytier/root/usr/share/easytier/firewall.sh
+++ b/luci-app-easytier/root/usr/share/easytier/firewall.sh
@@ -36,7 +36,9 @@ set_firewall_rules() {
[ -n "$wss_port" ] && add_firewall_rule "easytier_wss" "tcp" "$wss_port" "EasyTier WSS"
[ -n "$wg_port" ] && add_firewall_rule "easytier_wg" "udp" "$wg_port" "EasyTier WG"
[ -n "$quic_port" ] && add_firewall_rule "easytier_quic" "tcp udp" "$quic_port" "EasyTier QUIC"
- [ -n "$socks_port" ] && add_firewall_rule "easytier_socks5" "tcp" "$socks_port" "EasyTier SOCKS5"
+ # 不再自动放行 SOCKS5 端口到 WAN —— 无认证 SOCKS5 代理暴露给公网有严重安全风险
+ # 如需恢复自动放行,去掉下面一行行首的 # 即可
+ # [ -n "$socks_port" ] && add_firewall_rule "easytier_socks5" "tcp" "$socks_port" "EasyTier SOCKS5"
}
# 设置网络接口
diff --git a/luci-app-passwall/Makefile b/luci-app-passwall/Makefile
index 6294fa741..b8c0f4b08 100644
--- a/luci-app-passwall/Makefile
+++ b/luci-app-passwall/Makefile
@@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall
PKG_VERSION:=26.7.24
-PKG_RELEASE:=197
+PKG_RELEASE:=198
PKG_PO_VERSION:=$(PKG_VERSION)
PKG_CONFIG_DEPENDS:= \
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe.lua
index 276f28131..5d8ad73d8 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe.lua
@@ -139,6 +139,9 @@ s.extedit = api.url("node_subscribe_config", "%s")
function s.create(e, t)
m.no_commit = true
local id = TypedSection.create(e, t)
+ uci:set(appname, id, "hysteria_up_mbps", "100")
+ uci:set(appname, id, "hysteria_down_mbps", "100")
+ api.uci_save(uci, appname)
luci.http.redirect(e.extedit:format(id))
end
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe_config.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe_config.lua
index 98e52f7e1..aa8215bc4 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe_config.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe_config.lua
@@ -221,11 +221,9 @@ if #hysteria2_type > 0 then
o = s:option(Value, "hysteria_up_mbps", "Hy/Hy2 " .. translate("Max upload Mbps"))
o.datatype = "uinteger"
- o.default = "100"
o = s:option(Value, "hysteria_down_mbps", "Hy/Hy2 " .. translate("Max download Mbps"))
o.datatype = "uinteger"
- o.default = "100"
end
o = s:option(Flag, "boot_update", translate("Update Once on Boot"), translate("Updates the subscription the first time PassWall runs automatically after each system boot."))
diff --git a/luci-app-passwall/root/usr/share/passwall/clash_subconverter.lua b/luci-app-passwall/root/usr/share/passwall/clash_subconverter.lua
index bc6ec4215..fd85c367b 100644
--- a/luci-app-passwall/root/usr/share/passwall/clash_subconverter.lua
+++ b/luci-app-passwall/root/usr/share/passwall/clash_subconverter.lua
@@ -7,6 +7,8 @@ local urlencode = api.UrlEncode
local base64 = api.base64Encode
local json = api.jsonc
+local domain_redir = {}
+
local function host_format(host)
if not host then return "" end
local str = host:match("%[(.-)%]") or host
@@ -162,7 +164,7 @@ local function build_common(node)
local d = opts["download-settings"]
local ds = {}
- if d.server then ds.address = d.server end
+ if d.server then ds.address = domain_redir[d.server] or d.server end
if d.port then ds.port = d.port end
ds.network = "xhttp"
@@ -507,6 +509,8 @@ local function encode_node(node)
local t = node.type
+ node.server = domain_redir[node.server] or node.server
+
if t == "vless" then return encode_vless(node)
elseif t == "trojan" then return encode_trojan(node)
elseif t == "vmess" then return encode_vmess(node)
@@ -531,6 +535,15 @@ function parseClashNode(raw, remark)
api.log('检测到 Clash 订阅,正在进行转换 ...')
+ -- Some airports use hosts domain redirect to disguise the real node domain name.
+ for k, v in pairs(data.hosts or {}) do
+ if type(k) == "string" and type(v) == "string" then
+ if api.datatypes.hostname(k) and api.datatypes.hostname(v) then
+ domain_redir[k] = v
+ end
+ end
+ end
+
local links = {}
for _, node in ipairs(data.proxies) do
local err, link = encode_node(node)
diff --git a/luci-app-passwall/root/usr/share/passwall/helper_chinadns_add.lua b/luci-app-passwall/root/usr/share/passwall/helper_chinadns_add.lua
index 7ab88d6e3..f26535a60 100644
--- a/luci-app-passwall/root/usr/share/passwall/helper_chinadns_add.lua
+++ b/luci-app-passwall/root/usr/share/passwall/helper_chinadns_add.lua
@@ -330,11 +330,16 @@ end
--中国列表
if CHNLIST ~= "0" and is_file_nonzero(RULES_PATH .. "/chnlist") then
if CHNLIST == "direct" then
+ local sets = {
+ setflag .. "psw_chn",
+ setflag .. "psw_chn6"
+ }
+ local suffix = (NFTFLAG == "1") and "_static" or ""
tmp_lines = {
"chnlist-file " .. RULES_PATH .. "/chnlist",
- "ipset-name4 " .. setflag .. "psw_chn",
- "ipset-name6 " .. setflag .. "psw_chn6",
- "add-tagchn-ip",
+ "ipset-name4 " .. setflag .. "psw_chn" .. suffix,
+ "ipset-name6 " .. setflag .. "psw_chn6" .. suffix,
+ "add-tagchn-ip" .. ((NFTFLAG == "1") and (" " .. table.concat(sets, ",")) or ""),
"chnlist-first"
}
merge_array(config_lines, tmp_lines)
diff --git a/luci-app-qemu-vms/Makefile b/luci-app-qemu-vms/Makefile
index 84e78d698..95b1878df 100644
--- a/luci-app-qemu-vms/Makefile
+++ b/luci-app-qemu-vms/Makefile
@@ -4,7 +4,7 @@ LUCI_TITLE:=Web UI for QEMU Virtual Machine Simple (VMS)
LUCI_DEPENDS:=@TARGET_x86_64 +qemu-vms +ttyd +usbutils +pciutils
PKG_LICENSE:=GPLv3
PKG_VERSION:=0.0.1
-PKG_RELEASE:=8
+PKG_RELEASE:=9
include $(TOPDIR)/feeds/luci/luci.mk
diff --git a/luci-app-qemu-vms/htdocs/luci-static/resources/view/qemu-vms/passthrough.js b/luci-app-qemu-vms/htdocs/luci-static/resources/view/qemu-vms/passthrough.js
index 65e5e67d0..a34e7d4f8 100644
--- a/luci-app-qemu-vms/htdocs/luci-static/resources/view/qemu-vms/passthrough.js
+++ b/luci-app-qemu-vms/htdocs/luci-static/resources/view/qemu-vms/passthrough.js
@@ -11,6 +11,18 @@ var callListHardware = rpc.declare({
params: []
});
+var callReleasePci = rpc.declare({
+ object: 'luci.qemu-vms',
+ method: 'release_pci',
+ params: ['section_name']
+});
+
+var callReleaseUsb = rpc.declare({
+ object: 'luci.qemu-vms',
+ method: 'release_usb',
+ params: ['section_name']
+});
+
return view.extend({
load: function() {
return Promise.all([
@@ -33,7 +45,19 @@ return view.extend({
});
return found;
},
-
+ /*
+ pciOwner: function(addr) {
+ var section = this.findPciSection(addr);
+ if (!section)
+ return null;
+ var owner = null;
+ uci.sections('qemu-vms', 'vm').forEach(function(vm) {
+ if (vm.pci_passthrough === section)
+ owner = vm['.name'];
+ });
+ return owner;
+ },
+ */
pciOwners: function(addr) {
var section = this.findPciSection(addr);
if (!section)
@@ -175,9 +199,14 @@ return view.extend({
E('button', {
'class': 'btn cbi-button-negative',
'click': function() {
- uci.remove('qemu-vms', section);
- self.cleanupVmReferences('pci_passthrough', section);
- return uci.save().then(function() {
+ return callReleasePci(section).catch(function(err) {
+ ui.addNotification(null, E('p',
+ _('Warning: could not rebind device to its original driver: ') + err.message), 'warning');
+ }).then(function() {
+ uci.remove('qemu-vms', section);
+ self.cleanupVmReferences('pci_passthrough', section);
+ return uci.save();
+ }).then(function() {
ui.hideModal();
ui.addNotification(null, E('p', _('Passthrough removed for %s.').format(addr)), 'info');
self.updateView();
@@ -286,9 +315,14 @@ return view.extend({
E('button', {
'class': 'btn cbi-button-negative',
'click': function() {
- uci.remove('qemu-vms', section);
- self.cleanupVmReferences('usb_passthrough', section);
- return uci.save().then(function() {
+ return callReleaseUsb(section).catch(function(err) {
+ ui.addNotification(null, E('p',
+ _('Warning: could not rebind device to its original driver: ') + err.message), 'warning');
+ }).then(function() {
+ uci.remove('qemu-vms', section);
+ self.cleanupVmReferences('usb_passthrough', section);
+ return uci.save();
+ }).then(function() {
ui.hideModal();
ui.addNotification(null, E('p', _('Passthrough removed.')), 'info');
self.updateView();
@@ -305,10 +339,12 @@ return view.extend({
var self = this;
var rows = devices.map(function(dev) {
var section = self.findPciSection(dev.addr);
+ //var owner = self.pciOwner(dev.addr);
var owners = self.pciOwners(dev.addr);
var owner = owners.length ? owners.join(', ') : null;
var passthroughStatus = section ? _('Active
Section: %s').format(section) : _('Not passthrough');
if (owner) passthroughStatus += ' ' + _('
Host: %s').format(owner);
+
var actionButton;
if (section) {
@@ -417,7 +453,7 @@ return view.extend({
renderContent: function(data) {
var hw = data[0];
var self = this;
-
+
var description = E('div', { 'class': 'cbi-section' }, [
E('h2', {}, _('Hardware Passthrough')),
E('p', { 'class': 'cbi-section-descr' },
diff --git a/luci-app-qemu-vms/root/usr/libexec/rpcd/luci.qemu-vms b/luci-app-qemu-vms/root/usr/libexec/rpcd/luci.qemu-vms
index bc8e5fdd2..65cb7917b 100755
--- a/luci-app-qemu-vms/root/usr/libexec/rpcd/luci.qemu-vms
+++ b/luci-app-qemu-vms/root/usr/libexec/rpcd/luci.qemu-vms
@@ -314,6 +314,8 @@ case "$1" in
"list_hardware": { },
"list_machines": { },
"list_net_drivers": { },
+ "release_pci": { "section_name": "" },
+ "release_usb": { "section_name": "" },
"delete_vm": { "vm_name": "" }
}'
;;
@@ -324,6 +326,7 @@ case "$1" in
json_get_var lines lines
json_get_var offset offset
json_get_var data data
+ json_get_var section_name section_name
case "$2" in
status)
@@ -403,6 +406,18 @@ case "$1" in
json_close_array
json_dump
;;
+ release_pci)
+ /etc/init.d/qemu-vms release_pci_passthrough "$section_name" >/dev/null 2>&1
+ json_init
+ json_add_boolean "success" 1
+ json_dump
+ ;;
+ release_usb)
+ /etc/init.d/qemu-vms release_usb_passthrough "$section_name" >/dev/null 2>&1
+ json_init
+ json_add_boolean "success" 1
+ json_dump
+ ;;
delete_vm)
stop_vm_instance "$vm_name"
console_close "$vm_name" >/dev/null
diff --git a/luci-app-qemu-vms/root/usr/share/rpcd/acl.d/luci-app-qemu-vms.json b/luci-app-qemu-vms/root/usr/share/rpcd/acl.d/luci-app-qemu-vms.json
index a85167061..bcf814ad4 100644
--- a/luci-app-qemu-vms/root/usr/share/rpcd/acl.d/luci-app-qemu-vms.json
+++ b/luci-app-qemu-vms/root/usr/share/rpcd/acl.d/luci-app-qemu-vms.json
@@ -22,6 +22,8 @@
"list_machines",
"list_cpus",
"list_net_drivers",
+ "release_pci",
+ "release_usb",
"delete_vm"
]
},
diff --git a/qemu-vms/Makefile b/qemu-vms/Makefile
index 5529ffc2d..293c88c48 100644
--- a/qemu-vms/Makefile
+++ b/qemu-vms/Makefile
@@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=qemu-vms
PKG_VERSION:=0.0.1
-PKG_RELEASE:=8
+PKG_RELEASE:=9
PKG_MAINTAINER:=Konstantine Shevlakov
include $(INCLUDE_DIR)/package.mk
diff --git a/qemu-vms/root/etc/init.d/qemu-vms b/qemu-vms/root/etc/init.d/qemu-vms
index 487672d10..6fbbefd02 100755
--- a/qemu-vms/root/etc/init.d/qemu-vms
+++ b/qemu-vms/root/etc/init.d/qemu-vms
@@ -119,6 +119,8 @@ _add_pci() {
local dev_name="$(basename "$dev")"
local current_driver="$(basename "$(readlink -f "$dev/driver" 2>/dev/null)" 2>/dev/null)"
if [ -n "$current_driver" ] && [ "$current_driver" != "vfio-pci" ]; then
+ local orig_file="$STATUS_DIR/pci-orig-driver-$dev_name"
+ [ -f "$orig_file" ] || echo "$current_driver" > "$orig_file"
echo -n "$dev_name" > "$dev/driver/unbind" 2>/dev/null
host_log "$cfg" "PCI: unbound $dev_name from $current_driver"
fi
@@ -137,26 +139,6 @@ _add_pci() {
fi
}
-#_unbind_usb_host() {
-# local usbcfg="$1"
-# local vendor_id product_id
-# config_get vendor_id "$usbcfg" vendor_id
-# config_get product_id "$usbcfg" product_id
-# [ -n "$vendor_id" ] && [ -n "$product_id" ] || return 0
-# for dev in /sys/bus/usb/devices/*; do
-# if [ -f "$dev/idVendor" ] && [ -f "$dev/idProduct" ]; then
-# local v=$(cat "$dev/idVendor") p=$(cat "$dev/idProduct")
-# if [ "$v" = "$vendor_id" ] && [ "$p" = "$product_id" ]; then
-# if [ -L "$dev/driver" ]; then
-# local driver_path=$(readlink -f "$dev/driver")
-# local driver_name=$(basename "$driver_path")
-# echo -n "$(basename "$dev")" > "$driver_path/unbind" 2>/dev/null
-# fi
-# fi
-# fi
-# done
-#}
-
_unbind_usb_host() {
local usbcfg="$1"
local vendor_id product_id
@@ -190,6 +172,68 @@ _unbind_usb_host() {
done
}
+_release_usb_node() {
+ # Rebind a single sysfs usb node (device or interface) to whatever
+ # driver it was recorded as being on before we ever touched it.
+ local node="$1"
+ local orig_file="$STATUS_DIR/usb-orig-driver-$node"
+
+ [ -f "$orig_file" ] || return 0
+ local orig_driver
+ orig_driver="$(cat "$orig_file")"
+
+ if [ -n "$orig_driver" ] && [ -e "/sys/bus/usb/drivers/$orig_driver" ]; then
+ echo -n "$node" > "/sys/bus/usb/drivers/$orig_driver/bind" 2>/dev/null
+ if [ -L "/sys/bus/usb/devices/$node/driver" ] && \
+ [ "$(basename "$(readlink -f "/sys/bus/usb/devices/$node/driver")")" = "$orig_driver" ]; then
+ logger -t qemu-vms "release_usb: restored $node to $orig_driver"
+ else
+ logger -t qemu-vms "WARNING: release_usb: failed to rebind $node to $orig_driver"
+ fi
+ fi
+ rm -f "$orig_file"
+}
+
+release_usb() {
+ # Usage: release_usb
+ local vendor_id="$1"
+ local product_id="$2"
+
+ [ -n "$vendor_id" ] && [ -n "$product_id" ] || {
+ logger -t qemu-vms "release_usb: vendor_id/product_id required"
+ return 1
+ }
+
+ for dev in /sys/bus/usb/devices/*; do
+ [ -f "$dev/idVendor" ] && [ -f "$dev/idProduct" ] || continue
+ local v=$(cat "$dev/idVendor") p=$(cat "$dev/idProduct")
+ [ "$v" = "$vendor_id" ] && [ "$p" = "$product_id" ] || continue
+
+ local devname=$(basename "$dev")
+ _release_usb_node "$devname"
+
+ for iface in /sys/bus/usb/devices/"$devname":*; do
+ [ -e "$iface" ] || continue
+ _release_usb_node "$(basename "$iface")"
+ done
+ done
+}
+
+release_usb_passthrough() {
+ # Usage: release_usb_passthrough
+ local section="$1"
+ config_load qemu-vms
+ local vendor_id product_id
+ config_get vendor_id "$section" vendor_id
+ config_get product_id "$section" product_id
+ if [ -z "$vendor_id" ] || [ -z "$product_id" ]; then
+ logger -t qemu-vms "release_usb_passthrough: section '$section' has no vendor_id/product_id"
+ return 1
+ fi
+ release_usb "$vendor_id" "$product_id"
+}
+
+
build_customargs() {
local cfg="$1"
custom_opts=""
@@ -288,29 +332,6 @@ start_vm() {
build_customargs "$cfg"
build_diskargs "$cfg" "$image"
- #local pci_id="" vendor_id="" pci_opts=""
- #if [ -n "$pci_passthrough" ]; then
- # config_get pci_id "$pci_passthrough" pci_id
- # config_get vendor_id "$pci_passthrough" vendor_id
- # if [ -n "$vendor_id" ] && [ -n "$pci_id" ]; then
- # if [ -e "/sys/bus/pci/devices/0000:$pci_id/driver" ]; then
- # local current_driver
- # current_driver="$(basename "$(readlink -f "/sys/bus/pci/devices/0000:$pci_id/driver" 2>/dev/null)" 2>/dev/null)"
- # host_log "$cfg" "PCI passthrough: $pci_id already bound to driver '$current_driver'"
- # else
- # echo "$vendor_id" > /sys/bus/pci/drivers/vfio-pci/new_id 2>/dev/null
- # if [ -e "/sys/bus/pci/devices/0000:$pci_id/driver" ]; then
- # host_log "$cfg" "PCI passthrough: bound $pci_id (vendor/device $vendor_id) to vfio-pci"
- # else
- # host_log "$cfg" "WARNING: PCI passthrough: failed to bind $pci_id to vfio-pci - check IOMMU/BIOS settings"
- # fi
- # fi
- # pci_opts="-device vfio-pci,host=$pci_id"
- # else
- # host_log "$cfg" "WARNING: pci_passthrough='$pci_passthrough' is set but its pci_id/vendor_id are incomplete - skipping passthrough"
- # fi
- #fi
-
local pci_opts=""
config_list_foreach "$cfg" pci_passthrough _add_pci
@@ -369,6 +390,74 @@ start_vm() {
# connects for the duration of the minicom session.
}
+release_pci() {
+ # Usage: release_pci
+ local pci_id="$1"
+ [ -n "$pci_id" ] || {
+ logger -t qemu-vms "release_pci: pci_id required"
+ return 1
+ }
+
+ local pci_path="/sys/bus/pci/devices/0000:$pci_id"
+ local iommu_group=""
+ [ -L "$pci_path/iommu_group" ] && iommu_group="$(basename "$(readlink -f "$pci_path/iommu_group")")"
+
+ if [ -z "$iommu_group" ]; then
+ logger -t qemu-vms "release_pci: cannot determine IOMMU group for $pci_id"
+ return 1
+ fi
+
+ for dev in /sys/kernel/iommu_groups/$iommu_group/devices/*; do
+ local dev_name="$(basename "$dev")"
+ local current_driver="$(basename "$(readlink -f "$dev/driver" 2>/dev/null)" 2>/dev/null)"
+
+ if [ "$current_driver" != "vfio-pci" ]; then
+ logger -t qemu-vms "release_pci: $dev_name is not bound to vfio-pci (currently '$current_driver'), skipping"
+ continue
+ fi
+
+ echo -n "" > "$dev/driver_override" 2>/dev/null
+ echo -n "$dev_name" > "$dev/driver/unbind" 2>/dev/null
+
+ local orig_file="$STATUS_DIR/pci-orig-driver-$dev_name"
+ if [ -f "$orig_file" ]; then
+ local orig_driver
+ orig_driver="$(cat "$orig_file")"
+ if [ -n "$orig_driver" ] && [ -e "/sys/bus/pci/drivers/$orig_driver" ]; then
+ echo -n "$dev_name" > "/sys/bus/pci/drivers/$orig_driver/bind" 2>/dev/null
+ if [ -e "$dev/driver" ] && [ "$(basename "$(readlink -f "$dev/driver")")" = "$orig_driver" ]; then
+ logger -t qemu-vms "release_pci: restored $dev_name to $orig_driver"
+ else
+ logger -t qemu-vms "WARNING: release_pci: failed to rebind $dev_name to $orig_driver"
+ logger -t qemu-vms "WARNING: release_pci: will need reoot host to bind original driver $$orig_driver"
+ fi
+ fi
+ rm -f "$orig_file"
+ else
+ logger -t qemu-vms "release_pci: no recorded original driver for $dev_name, left unbound"
+ fi
+ done
+}
+
+release_pci_passthrough() {
+ # Usage: release_pci_passthrough
+ local section="$1"
+ config_load qemu-vms
+ local pci_id
+ config_get pci_id "$section" pci_id
+ if [ -z "$pci_id" ]; then
+ logger -t qemu-vms "release_pci_passthrough: section '$section' has no pci_id"
+ return 1
+ fi
+ release_pci "$pci_id"
+}
+
+
+EXTRA_COMMANDS="release_pci_passthrough release_usb_passthrough"
+EXTRA_HELP=" release_pci_passthrough Unbind a PCI device from vfio-pci and restore its original driver
+ release_usb_passthrough Unbind a USB device from passthrough use and restore its original driver"
+
+
start_service() {
config_load qemu-vms
if [ -n "$1" ]; then
diff --git a/teleproxy/Makefile b/teleproxy/Makefile
index 9d1ac9915..aaaaa9e32 100644
--- a/teleproxy/Makefile
+++ b/teleproxy/Makefile
@@ -1,8 +1,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=teleproxy
-PKG_VERSION:=4.15.0
-PKG_RELEASE:=21
+PKG_VERSION:=4.16.0
+PKG_RELEASE:=22
PKG_MAINTAINER:=Kosntantine Shevlakov
PKG_LICENSE:=GPLv2
@@ -10,7 +10,7 @@ PKG_LICENSE_FILES:=LICENSE
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://github.com/teleproxy/teleproxy.git
-PKG_SOURCE_VERSION:=8cb4c57116dab588de6cd7509e65f8b6b6d31936
+PKG_SOURCE_VERSION:=d5342b5983dee738ee94d66f77ff27ea24932755
PKG_SOURCE_SUBDIR:=$(PKG_NAME)
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz