diff --git a/.github/update.log b/.github/update.log index 7462871c80..74729b326a 100644 --- a/.github/update.log +++ b/.github/update.log @@ -930,3 +930,4 @@ Update On Thu Feb 27 19:34:57 CET 2025 Update On Fri Feb 28 19:34:20 CET 2025 Update On Sat Mar 1 19:31:26 CET 2025 Update On Sun Mar 2 19:33:02 CET 2025 +Update On Mon Mar 3 19:34:32 CET 2025 diff --git a/clash-meta-android/build.gradle.kts b/clash-meta-android/build.gradle.kts index 6337bf7d11..65fe282c90 100644 --- a/clash-meta-android/build.gradle.kts +++ b/clash-meta-android/build.gradle.kts @@ -46,8 +46,8 @@ subprojects { minSdk = 21 targetSdk = 35 - versionName = "2.11.6" - versionCode = 211006 + versionName = "2.11.7" + versionCode = 211007 resValue("string", "release_name", "v$versionName") resValue("integer", "release_code", "$versionCode") diff --git a/clash-meta-android/core/src/foss/golang/clash/.github/mihomo.service b/clash-meta-android/core/src/foss/golang/clash/.github/mihomo.service index f34b6a6a84..a3793fe369 100644 --- a/clash-meta-android/core/src/foss/golang/clash/.github/mihomo.service +++ b/clash-meta-android/core/src/foss/golang/clash/.github/mihomo.service @@ -1,17 +1,17 @@ [Unit] Description=mihomo Daemon, Another Clash Kernel. -After=network.target NetworkManager.service systemd-networkd.service iwd.service +Documentation=https://wiki.metacubex.one +After=network.target nss-lookup.target network-online.target [Service] Type=simple -LimitNPROC=500 -LimitNOFILE=1000000 -CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_TIME CAP_SYS_PTRACE CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE -AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_TIME CAP_SYS_PTRACE CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE -Restart=always -ExecStartPre=/usr/bin/sleep 2s +CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH +AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH ExecStart=/usr/bin/mihomo -d /etc/mihomo ExecReload=/bin/kill -HUP $MAINPID +Restart=on-failure +RestartSec=10 +LimitNOFILE=infinity [Install] -WantedBy=multi-user.target \ No newline at end of file +WantedBy=multi-user.target diff --git a/clash-meta-android/core/src/foss/golang/clash/.github/mihomo@.service b/clash-meta-android/core/src/foss/golang/clash/.github/mihomo@.service new file mode 100644 index 0000000000..a3793fe369 --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/.github/mihomo@.service @@ -0,0 +1,17 @@ +[Unit] +Description=mihomo Daemon, Another Clash Kernel. +Documentation=https://wiki.metacubex.one +After=network.target nss-lookup.target network-online.target + +[Service] +Type=simple +CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH +AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH +ExecStart=/usr/bin/mihomo -d /etc/mihomo +ExecReload=/bin/kill -HUP $MAINPID +Restart=on-failure +RestartSec=10 +LimitNOFILE=infinity + +[Install] +WantedBy=multi-user.target diff --git a/clash-meta-android/core/src/foss/golang/clash/.github/workflows/build.yml b/clash-meta-android/core/src/foss/golang/clash/.github/workflows/build.yml index ee1266b802..371065cf10 100644 --- a/clash-meta-android/core/src/foss/golang/clash/.github/workflows/build.yml +++ b/clash-meta-android/core/src/foss/golang/clash/.github/workflows/build.yml @@ -276,17 +276,20 @@ jobs: mkdir -p mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/DEBIAN mkdir -p mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/usr/bin - mkdir -p mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/etc/mihomo - mkdir -p mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/etc/systemd/system/ mkdir -p mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/usr/share/licenses/mihomo + mkdir -p mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/etc/mihomo + mkdir -p mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/lib/systemd/system - cp mihomo mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/usr/bin/mihomo + cp mihomo mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/usr/bin/ cp LICENSE mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/usr/share/licenses/mihomo/ - cp .github/mihomo.service mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/etc/systemd/system/ + cp .github/{mihomo.service,mihomo@.service} mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/lib/systemd/system/ cat > mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/etc/mihomo/config.yaml < mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/DEBIAN/conffiles < mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/DEBIAN/control <= r.Start(); i++ { if !f(i) { return } + if i+1 < i { // integer overflow + break + } } } } diff --git a/clash-meta-android/core/src/foss/golang/clash/constant/metadata.go b/clash-meta-android/core/src/foss/golang/clash/constant/metadata.go index ac676b040a..2eea8335ed 100644 --- a/clash-meta-android/core/src/foss/golang/clash/constant/metadata.go +++ b/clash-meta-android/core/src/foss/golang/clash/constant/metadata.go @@ -28,6 +28,7 @@ const ( VLESS REDIR TPROXY + TROJAN TUNNEL TUN TUIC @@ -77,6 +78,8 @@ func (t Type) String() string { return "Redir" case TPROXY: return "TProxy" + case TROJAN: + return "Trojan" case TUNNEL: return "Tunnel" case TUN: @@ -115,6 +118,8 @@ func ParseType(t string) (*Type, error) { res = REDIR case "TPROXY": res = TPROXY + case "TROJAN": + res = TROJAN case "TUNNEL": res = TUNNEL case "TUN": diff --git a/clash-meta-android/core/src/foss/golang/clash/docs/config.yaml b/clash-meta-android/core/src/foss/golang/clash/docs/config.yaml index db66a2b32a..88030a1b60 100644 --- a/clash-meta-android/core/src/foss/golang/clash/docs/config.yaml +++ b/clash-meta-android/core/src/foss/golang/clash/docs/config.yaml @@ -874,6 +874,7 @@ proxies: # socks5 udp: true # idle-session-check-interval: 30 # seconds # idle-session-timeout: 30 # seconds + # min-idle-session: 0 # sni: "example.com" # alpn: # - h2 @@ -1095,7 +1096,7 @@ sub-rules: listeners: - name: socks5-in-1 type: socks - port: 10808 + port: 10808 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503 #listen: 0.0.0.0 # 默认监听 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 @@ -1103,20 +1104,26 @@ listeners: # users: # 如果不填写users项,则遵从全局authentication设置,如果填写会忽略全局设置, 如想跳过该入站的验证可填写 users: [] # - username: aaa # password: aaa + # 下面两项如果填写则开启 tls(需要同时填写) + # certificate: ./server.crt + # private-key: ./server.key - name: http-in-1 type: http - port: 10809 + port: 10809 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) # users: # 如果不填写users项,则遵从全局authentication设置,如果填写会忽略全局设置, 如想跳过该入站的验证可填写 users: [] # - username: aaa # password: aaa + # 下面两项如果填写则开启 tls(需要同时填写) + # certificate: ./server.crt + # private-key: ./server.key - name: mixed-in-1 type: mixed # HTTP(S) 和 SOCKS 代理混合 - port: 10810 + port: 10810 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) @@ -1124,17 +1131,20 @@ listeners: # users: # 如果不填写users项,则遵从全局authentication设置,如果填写会忽略全局设置, 如想跳过该入站的验证可填写 users: [] # - username: aaa # password: aaa + # 下面两项如果填写则开启 tls(需要同时填写) + # certificate: ./server.crt + # private-key: ./server.key - name: reidr-in-1 type: redir - port: 10811 + port: 10811 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) - name: tproxy-in-1 type: tproxy - port: 10812 + port: 10812 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) @@ -1142,7 +1152,7 @@ listeners: - name: shadowsocks-in-1 type: shadowsocks - port: 10813 + port: 10813 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) @@ -1151,7 +1161,7 @@ listeners: - name: vmess-in-1 type: vmess - port: 10814 + port: 10814 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) @@ -1160,6 +1170,7 @@ listeners: uuid: 9d0cb9d0-964f-4ef6-897d-6c6b3ccf9e68 alterId: 1 # ws-path: "/" # 如果不为空则开启 websocket 传输层 + # grpc-service-name: "GunService" # 如果不为空则开启 grpc 传输层 # 下面两项如果填写则开启 tls(需要同时填写) # certificate: ./server.crt # private-key: ./server.key @@ -1174,7 +1185,7 @@ listeners: - name: tuic-in-1 type: tuic - port: 10815 + port: 10815 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) @@ -1194,7 +1205,7 @@ listeners: - name: tunnel-in-1 type: tunnel - port: 10816 + port: 10816 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) @@ -1203,7 +1214,7 @@ listeners: - name: vless-in-1 type: vless - port: 10817 + port: 10817 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) @@ -1212,6 +1223,7 @@ listeners: uuid: 9d0cb9d0-964f-4ef6-897d-6c6b3ccf9e68 flow: xtls-rprx-vision # ws-path: "/" # 如果不为空则开启 websocket 传输层 + # grpc-service-name: "GunService" # 如果不为空则开启 grpc 传输层 # 下面两项如果填写则开启 tls(需要同时填写) # certificate: ./server.crt # private-key: ./server.key @@ -1227,7 +1239,7 @@ listeners: - name: anytls-in-1 type: anytls - port: 10818 + port: 10818 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503 listen: 0.0.0.0 users: username1: password1 @@ -1237,6 +1249,34 @@ listeners: private-key: ./server.key # padding-scheme: "" # https://github.com/anytls/anytls-go/blob/main/docs/protocol.md#cmdupdatepaddingscheme + - name: trojan-in-1 + type: trojan + port: 10819 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503 + listen: 0.0.0.0 + # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules + # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) + users: + - username: 1 + password: 9d0cb9d0-964f-4ef6-897d-6c6b3ccf9e68 + # ws-path: "/" # 如果不为空则开启 websocket 传输层 + # grpc-service-name: "GunService" # 如果不为空则开启 grpc 传输层 + # 下面两项如果填写则开启 tls(需要同时填写) + certificate: ./server.crt + private-key: ./server.key + # 如果填写reality-config则开启reality(注意不可与certificate和private-key同时填写) + # reality-config: + # dest: test.com:443 + # private-key: jNXHt1yRo0vDuchQlIP6Z0ZvjT3KtzVI-T4E7RoLJS0 # 可由 mihomo generate reality-keypair 命令生成 + # short-id: + # - 0123456789abcdef + # server-names: + # - test.com + # ss-option: # like trojan-go's `shadowsocks` config + # enabled: false + # method: aes-128-gcm # aes-128-gcm/aes-256-gcm/chacha20-ietf-poly1305 + # password: "example" + ### 注意,对于trojan listener, 至少需要填写 “certificate和private-key” 或 “reality-config” 或 “ss-option” 的其中一项 ### + - name: tun-in-1 type: tun # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules diff --git a/clash-meta-android/core/src/foss/golang/clash/go.mod b/clash-meta-android/core/src/foss/golang/clash/go.mod index 1eb79004b5..9405a2f1fa 100644 --- a/clash-meta-android/core/src/foss/golang/clash/go.mod +++ b/clash-meta-android/core/src/foss/golang/clash/go.mod @@ -28,7 +28,7 @@ require ( github.com/metacubex/sing-shadowsocks v0.2.8 github.com/metacubex/sing-shadowsocks2 v0.2.2 github.com/metacubex/sing-tun v0.4.5 - github.com/metacubex/sing-vmess v0.1.14-0.20250203033000-f61322b3dbe3 + github.com/metacubex/sing-vmess v0.1.14-0.20250228002636-abc39e113b82 github.com/metacubex/sing-wireguard v0.0.0-20241126021510-0827d417b589 github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422 github.com/metacubex/utls v1.6.6 @@ -41,9 +41,10 @@ require ( github.com/sagernet/cors v1.2.1 github.com/sagernet/fswatch v0.1.1 github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a - github.com/sagernet/sing v0.5.1 + github.com/sagernet/sing v0.5.2 github.com/sagernet/sing-mux v0.2.1 github.com/sagernet/sing-shadowtls v0.1.5 + github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 github.com/samber/lo v1.49.1 github.com/shirou/gopsutil/v4 v4.25.1 github.com/sirupsen/logrus v1.9.3 @@ -98,7 +99,6 @@ require ( github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qtls-go1-20 v0.4.1 // indirect github.com/sagernet/nftables v0.3.0-beta.4 // indirect - github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b // indirect github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c // indirect github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e // indirect @@ -117,4 +117,4 @@ require ( golang.org/x/tools v0.24.0 // indirect ) -replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20241121030428-33b6ebc52000 +replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20250228041610-d94509dc612a diff --git a/clash-meta-android/core/src/foss/golang/clash/go.sum b/clash-meta-android/core/src/foss/golang/clash/go.sum index 7e485eacb1..9660cf30d2 100644 --- a/clash-meta-android/core/src/foss/golang/clash/go.sum +++ b/clash-meta-android/core/src/foss/golang/clash/go.sum @@ -111,8 +111,8 @@ github.com/metacubex/randv2 v0.2.0 h1:uP38uBvV2SxYfLj53kuvAjbND4RUDfFJjwr4UigMiL github.com/metacubex/randv2 v0.2.0/go.mod h1:kFi2SzrQ5WuneuoLLCMkABtiBu6VRrMrWFqSPyj2cxY= github.com/metacubex/reality v0.0.0-20250219003814-74e8d7850629 h1:aHsYiTvubfgMa3JMTDY//hDXVvFWrHg6ARckR52ttZs= github.com/metacubex/reality v0.0.0-20250219003814-74e8d7850629/go.mod h1:TTeIOZLdGmzc07Oedn++vWUUfkZoXLF4sEMxWuhBFr8= -github.com/metacubex/sing v0.0.0-20241121030428-33b6ebc52000 h1:gUbMXcQXhXGj0vCpCVFTUyIH7TMpD1dpTcNv/MCS+ok= -github.com/metacubex/sing v0.0.0-20241121030428-33b6ebc52000/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= +github.com/metacubex/sing v0.0.0-20250228041610-d94509dc612a h1:xjPXdDTlIKq4U/KnKpoCtkxD03T8GimtQrvHy/3dN00= +github.com/metacubex/sing v0.0.0-20250228041610-d94509dc612a/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/metacubex/sing-quic v0.0.0-20250119013740-2a19cce83925 h1:UkPoRAnoBQMn7IK5qpoIV3OejU15q+rqel3NrbSCFKA= github.com/metacubex/sing-quic v0.0.0-20250119013740-2a19cce83925/go.mod h1:g7Mxj7b7zm7YVqD975mk/hSmrb0A0G4bVvIMr2MMzn8= github.com/metacubex/sing-shadowsocks v0.2.8 h1:wIhlaigswzjPw4hej75sEvWte3QR0+AJRafgwBHO5B4= @@ -121,8 +121,8 @@ github.com/metacubex/sing-shadowsocks2 v0.2.2 h1:eaf42uVx4Lr21S6MDYs0ZdTvGA0GEhD github.com/metacubex/sing-shadowsocks2 v0.2.2/go.mod h1:BhOug03a/RbI7y6hp6q+6ITM1dXjnLTmeWBHSTwvv2Q= github.com/metacubex/sing-tun v0.4.5 h1:kWSyQzuzHI40r50OFBczfWIDvMBMy1RIk+JsXeBPRB0= github.com/metacubex/sing-tun v0.4.5/go.mod h1:V0N4rr0dWPBEE20ESkTXdbtx2riQYcb6YtwC5w/9wl0= -github.com/metacubex/sing-vmess v0.1.14-0.20250203033000-f61322b3dbe3 h1:2kq6azIvsTjTnyw66xXDl5zMzIJqF7GTbvLpkroHssg= -github.com/metacubex/sing-vmess v0.1.14-0.20250203033000-f61322b3dbe3/go.mod h1:nE7Mdzj/QUDwgRi/8BASPtsxtIFZTHA4Yst5GgwbGCQ= +github.com/metacubex/sing-vmess v0.1.14-0.20250228002636-abc39e113b82 h1:zZp5uct9+/0Hb1jKGyqDjCU4/72t43rs7qOq3Rc9oU8= +github.com/metacubex/sing-vmess v0.1.14-0.20250228002636-abc39e113b82/go.mod h1:nE7Mdzj/QUDwgRi/8BASPtsxtIFZTHA4Yst5GgwbGCQ= github.com/metacubex/sing-wireguard v0.0.0-20241126021510-0827d417b589 h1:Z6bNy0HLTjx6BKIkV48sV/yia/GP8Bnyb5JQuGgSGzg= github.com/metacubex/sing-wireguard v0.0.0-20241126021510-0827d417b589/go.mod h1:4NclTLIZuk+QkHVCGrP87rHi/y8YjgPytxTgApJNMhc= github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422 h1:zGeQt3UyNydIVrMRB97AA5WsYEau/TyCnRtTf1yUmJY= diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/config/auth.go b/clash-meta-android/core/src/foss/golang/clash/listener/config/auth.go new file mode 100644 index 0000000000..a99f87fb2d --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/listener/config/auth.go @@ -0,0 +1,16 @@ +package config + +import ( + "github.com/metacubex/mihomo/component/auth" + "github.com/metacubex/mihomo/listener/reality" +) + +// AuthServer for http/socks/mixed server +type AuthServer struct { + Enable bool + Listen string + AuthStore auth.AuthStore + Certificate string + PrivateKey string + RealityConfig reality.Config +} diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/config/trojan.go b/clash-meta-android/core/src/foss/golang/clash/listener/config/trojan.go new file mode 100644 index 0000000000..28b6fe7c32 --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/listener/config/trojan.go @@ -0,0 +1,38 @@ +package config + +import ( + "encoding/json" + + "github.com/metacubex/mihomo/listener/reality" + "github.com/metacubex/mihomo/listener/sing" +) + +type TrojanUser struct { + Username string + Password string +} + +type TrojanServer struct { + Enable bool + Listen string + Users []TrojanUser + WsPath string + GrpcServiceName string + Certificate string + PrivateKey string + RealityConfig reality.Config + MuxOption sing.MuxOption + TrojanSSOption TrojanSSOption +} + +// TrojanSSOption from https://github.com/p4gefau1t/trojan-go/blob/v0.10.6/tunnel/shadowsocks/config.go#L5 +type TrojanSSOption struct { + Enabled bool + Method string + Password string +} + +func (t TrojanServer) String() string { + b, _ := json.Marshal(t) + return string(b) +} diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/config/vless.go b/clash-meta-android/core/src/foss/golang/clash/listener/config/vless.go index 2f88c1c406..d656db9fdc 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/config/vless.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/config/vless.go @@ -14,14 +14,15 @@ type VlessUser struct { } type VlessServer struct { - Enable bool - Listen string - Users []VlessUser - WsPath string - Certificate string - PrivateKey string - RealityConfig reality.Config - MuxOption sing.MuxOption `yaml:"mux-option" json:"mux-option,omitempty"` + Enable bool + Listen string + Users []VlessUser + WsPath string + GrpcServiceName string + Certificate string + PrivateKey string + RealityConfig reality.Config + MuxOption sing.MuxOption `yaml:"mux-option" json:"mux-option,omitempty"` } func (t VlessServer) String() string { diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/config/vmess.go b/clash-meta-android/core/src/foss/golang/clash/listener/config/vmess.go index 0d9e9c4a3b..264b772c40 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/config/vmess.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/config/vmess.go @@ -14,14 +14,15 @@ type VmessUser struct { } type VmessServer struct { - Enable bool - Listen string - Users []VmessUser - WsPath string - Certificate string - PrivateKey string - RealityConfig reality.Config - MuxOption sing.MuxOption `yaml:"mux-option" json:"mux-option,omitempty"` + Enable bool + Listen string + Users []VmessUser + WsPath string + GrpcServiceName string + Certificate string + PrivateKey string + RealityConfig reality.Config + MuxOption sing.MuxOption `yaml:"mux-option" json:"mux-option,omitempty"` } func (t VmessServer) String() string { diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/http/server.go b/clash-meta-android/core/src/foss/golang/clash/listener/http/server.go index 24f07e8bd1..e32b55dde3 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/http/server.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/http/server.go @@ -1,12 +1,16 @@ package http import ( + "crypto/tls" + "errors" "net" "github.com/metacubex/mihomo/adapter/inbound" - "github.com/metacubex/mihomo/component/auth" + N "github.com/metacubex/mihomo/common/net" C "github.com/metacubex/mihomo/constant" authStore "github.com/metacubex/mihomo/listener/auth" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/listener/reality" ) type Listener struct { @@ -32,7 +36,7 @@ func (l *Listener) Close() error { } func New(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) { - return NewWithAuthenticator(addr, tunnel, authStore.Default, additions...) + return NewWithConfig(LC.AuthServer{Enable: true, Listen: addr, AuthStore: authStore.Default}, tunnel, additions...) } // NewWithAuthenticate @@ -40,12 +44,12 @@ func New(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener func NewWithAuthenticate(addr string, tunnel C.Tunnel, authenticate bool, additions ...inbound.Addition) (*Listener, error) { store := authStore.Default if !authenticate { - store = authStore.Default + store = authStore.Nil } - return NewWithAuthenticator(addr, tunnel, store, additions...) + return NewWithConfig(LC.AuthServer{Enable: true, Listen: addr, AuthStore: store}, tunnel, additions...) } -func NewWithAuthenticator(addr string, tunnel C.Tunnel, store auth.AuthStore, additions ...inbound.Addition) (*Listener, error) { +func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) { isDefault := false if len(additions) == 0 { isDefault = true @@ -55,15 +59,42 @@ func NewWithAuthenticator(addr string, tunnel C.Tunnel, store auth.AuthStore, ad } } - l, err := inbound.Listen("tcp", addr) + l, err := inbound.Listen("tcp", config.Listen) if err != nil { return nil, err } + tlsConfig := &tls.Config{} + var realityBuilder *reality.Builder + + if config.Certificate != "" && config.PrivateKey != "" { + cert, err := N.ParseCert(config.Certificate, config.PrivateKey, C.Path) + if err != nil { + return nil, err + } + tlsConfig.Certificates = []tls.Certificate{cert} + } + if config.RealityConfig.PrivateKey != "" { + if tlsConfig.Certificates != nil { + return nil, errors.New("certificate is unavailable in reality") + } + realityBuilder, err = config.RealityConfig.Build() + if err != nil { + return nil, err + } + } + + if realityBuilder != nil { + l = realityBuilder.NewListener(l) + } else if len(tlsConfig.Certificates) > 0 { + l = tls.NewListener(l, tlsConfig) + } + hl := &Listener{ listener: l, - addr: addr, + addr: config.Listen, } + go func() { for { conn, err := hl.listener.Accept() @@ -74,7 +105,7 @@ func NewWithAuthenticator(addr string, tunnel C.Tunnel, store auth.AuthStore, ad continue } - store := store + store := config.AuthStore if isDefault || store == authStore.Default { // only apply on default listener if !inbound.IsRemoteAddrDisAllowed(conn.RemoteAddr()) { _ = conn.Close() diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/anytls.go b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/anytls.go index a995bf4f79..6f1e635084 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/anytls.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/anytls.go @@ -1,6 +1,8 @@ package inbound import ( + "strings" + C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/listener/anytls" LC "github.com/metacubex/mihomo/listener/config" @@ -52,12 +54,13 @@ func (v *AnyTLS) Config() C.InboundConfig { // Address implements constant.InboundListener func (v *AnyTLS) Address() string { + var addrList []string if v.l != nil { for _, addr := range v.l.AddrList() { - return addr.String() + addrList = append(addrList, addr.String()) } } - return "" + return strings.Join(addrList, ",") } // Listen implements constant.InboundListener diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/base.go b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/base.go index e8f860a051..d4377986f7 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/base.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/base.go @@ -5,8 +5,10 @@ import ( "net" "net/netip" "strconv" + "strings" "github.com/metacubex/mihomo/adapter/inbound" + "github.com/metacubex/mihomo/common/utils" C "github.com/metacubex/mihomo/constant" ) @@ -15,7 +17,7 @@ type Base struct { name string specialRules string listenAddr netip.Addr - port int + ports utils.IntRanges[uint16] } func NewBase(options *BaseOption) (*Base, error) { @@ -26,11 +28,15 @@ func NewBase(options *BaseOption) (*Base, error) { if err != nil { return nil, err } + ports, err := utils.NewUnsignedRanges[uint16](options.Port) + if err != nil { + return nil, err + } return &Base{ name: options.Name(), listenAddr: addr, specialRules: options.SpecialRules, - port: options.Port, + ports: ports, config: options, }, nil } @@ -57,7 +63,15 @@ func (b *Base) Name() string { // RawAddress implements constant.InboundListener func (b *Base) RawAddress() string { - return net.JoinHostPort(b.listenAddr.String(), strconv.Itoa(int(b.port))) + if len(b.ports) == 0 { + return net.JoinHostPort(b.listenAddr.String(), "0") + } + address := make([]string, 0, len(b.ports)) + b.ports.Range(func(port uint16) bool { + address = append(address, net.JoinHostPort(b.listenAddr.String(), strconv.Itoa(int(port)))) + return true + }) + return strings.Join(address, ",") } // Listen implements constant.InboundListener @@ -74,7 +88,7 @@ var _ C.InboundListener = (*Base)(nil) type BaseOption struct { NameStr string `inbound:"name"` Listen string `inbound:"listen,omitempty"` - Port int `inbound:"port,omitempty"` + Port string `inbound:"port,omitempty"` SpecialRules string `inbound:"rule,omitempty"` SpecialProxy string `inbound:"proxy,omitempty"` } diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/http.go b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/http.go index e20a9a2357..8a4df00813 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/http.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/http.go @@ -1,14 +1,22 @@ package inbound import ( + "errors" + "fmt" + "strings" + C "github.com/metacubex/mihomo/constant" + LC "github.com/metacubex/mihomo/listener/config" "github.com/metacubex/mihomo/listener/http" "github.com/metacubex/mihomo/log" ) type HTTPOption struct { BaseOption - Users AuthUsers `inbound:"users,omitempty"` + Users AuthUsers `inbound:"users,omitempty"` + Certificate string `inbound:"certificate,omitempty"` + PrivateKey string `inbound:"private-key,omitempty"` + RealityConfig RealityConfig `inbound:"reality-config,omitempty"` } func (o HTTPOption) Equal(config C.InboundConfig) bool { @@ -18,7 +26,7 @@ func (o HTTPOption) Equal(config C.InboundConfig) bool { type HTTP struct { *Base config *HTTPOption - l *http.Listener + l []*http.Listener } func NewHTTP(options *HTTPOption) (*HTTP, error) { @@ -39,15 +47,32 @@ func (h *HTTP) Config() C.InboundConfig { // Address implements constant.InboundListener func (h *HTTP) Address() string { - return h.l.Address() + var addrList []string + for _, l := range h.l { + addrList = append(addrList, l.Address()) + } + return strings.Join(addrList, ",") } // Listen implements constant.InboundListener func (h *HTTP) Listen(tunnel C.Tunnel) error { - var err error - h.l, err = http.NewWithAuthenticator(h.RawAddress(), tunnel, h.config.Users.GetAuthStore(), h.Additions()...) - if err != nil { - return err + for _, addr := range strings.Split(h.RawAddress(), ",") { + l, err := http.NewWithConfig( + LC.AuthServer{ + Enable: true, + Listen: addr, + AuthStore: h.config.Users.GetAuthStore(), + Certificate: h.config.Certificate, + PrivateKey: h.config.PrivateKey, + RealityConfig: h.config.RealityConfig.Build(), + }, + tunnel, + h.Additions()..., + ) + if err != nil { + return err + } + h.l = append(h.l, l) } log.Infoln("HTTP[%s] proxy listening at: %s", h.Name(), h.Address()) return nil @@ -55,8 +80,15 @@ func (h *HTTP) Listen(tunnel C.Tunnel) error { // Close implements constant.InboundListener func (h *HTTP) Close() error { - if h.l != nil { - return h.l.Close() + var errs []error + for _, l := range h.l { + err := l.Close() + if err != nil { + errs = append(errs, fmt.Errorf("close tcp listener %s err: %w", l.Address(), err)) + } + } + if len(errs) > 0 { + return errors.Join(errs...) } return nil } diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/hysteria2.go b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/hysteria2.go index 23b2ada372..62d19c829e 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/hysteria2.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/hysteria2.go @@ -1,6 +1,8 @@ package inbound import ( + "strings" + C "github.com/metacubex/mihomo/constant" LC "github.com/metacubex/mihomo/listener/config" "github.com/metacubex/mihomo/listener/sing_hysteria2" @@ -83,12 +85,13 @@ func (t *Hysteria2) Config() C.InboundConfig { // Address implements constant.InboundListener func (t *Hysteria2) Address() string { + var addrList []string if t.l != nil { for _, addr := range t.l.AddrList() { - return addr.String() + addrList = append(addrList, addr.String()) } } - return "" + return strings.Join(addrList, ",") } // Listen implements constant.InboundListener diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/mixed.go b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/mixed.go index 1d79929acc..20c61f2eec 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/mixed.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/mixed.go @@ -1,19 +1,24 @@ package inbound import ( + "errors" "fmt" + "strings" C "github.com/metacubex/mihomo/constant" - "github.com/metacubex/mihomo/log" - + LC "github.com/metacubex/mihomo/listener/config" "github.com/metacubex/mihomo/listener/mixed" "github.com/metacubex/mihomo/listener/socks" + "github.com/metacubex/mihomo/log" ) type MixedOption struct { BaseOption - Users AuthUsers `inbound:"users,omitempty"` - UDP bool `inbound:"udp,omitempty"` + Users AuthUsers `inbound:"users,omitempty"` + UDP bool `inbound:"udp,omitempty"` + Certificate string `inbound:"certificate,omitempty"` + PrivateKey string `inbound:"private-key,omitempty"` + RealityConfig RealityConfig `inbound:"reality-config,omitempty"` } func (o MixedOption) Equal(config C.InboundConfig) bool { @@ -23,8 +28,8 @@ func (o MixedOption) Equal(config C.InboundConfig) bool { type Mixed struct { *Base config *MixedOption - l *mixed.Listener - lUDP *socks.UDPListener + l []*mixed.Listener + lUDP []*socks.UDPListener udp bool } @@ -47,21 +52,39 @@ func (m *Mixed) Config() C.InboundConfig { // Address implements constant.InboundListener func (m *Mixed) Address() string { - return m.l.Address() + var addrList []string + for _, l := range m.l { + addrList = append(addrList, l.Address()) + } + return strings.Join(addrList, ",") } // Listen implements constant.InboundListener func (m *Mixed) Listen(tunnel C.Tunnel) error { - var err error - m.l, err = mixed.NewWithAuthenticator(m.RawAddress(), tunnel, m.config.Users.GetAuthStore(), m.Additions()...) - if err != nil { - return err - } - if m.udp { - m.lUDP, err = socks.NewUDP(m.RawAddress(), tunnel, m.Additions()...) + for _, addr := range strings.Split(m.RawAddress(), ",") { + l, err := mixed.NewWithConfig( + LC.AuthServer{ + Enable: true, + Listen: addr, + AuthStore: m.config.Users.GetAuthStore(), + Certificate: m.config.Certificate, + PrivateKey: m.config.PrivateKey, + RealityConfig: m.config.RealityConfig.Build(), + }, + tunnel, + m.Additions()..., + ) if err != nil { return err } + m.l = append(m.l, l) + if m.udp { + lUDP, err := socks.NewUDP(addr, tunnel, m.Additions()...) + if err != nil { + return err + } + m.lUDP = append(m.lUDP, lUDP) + } } log.Infoln("Mixed(http+socks)[%s] proxy listening at: %s", m.Name(), m.Address()) return nil @@ -69,22 +92,23 @@ func (m *Mixed) Listen(tunnel C.Tunnel) error { // Close implements constant.InboundListener func (m *Mixed) Close() error { - var err error - if m.l != nil { - if tcpErr := m.l.Close(); tcpErr != nil { - err = tcpErr + var errs []error + for _, l := range m.l { + err := l.Close() + if err != nil { + errs = append(errs, fmt.Errorf("close tcp listener %s err: %w", l.Address(), err)) } } - if m.udp && m.lUDP != nil { - if udpErr := m.lUDP.Close(); udpErr != nil { - if err == nil { - err = udpErr - } else { - return fmt.Errorf("close tcp err: %s, close udp err: %s", err.Error(), udpErr.Error()) - } + for _, l := range m.lUDP { + err := l.Close() + if err != nil { + errs = append(errs, fmt.Errorf("close udp listener %s err: %w", l.Address(), err)) } } - return err + if len(errs) > 0 { + return errors.Join(errs...) + } + return nil } var _ C.InboundListener = (*Mixed)(nil) diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/redir.go b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/redir.go index ee090ade0f..2981ddfc01 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/redir.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/redir.go @@ -1,6 +1,10 @@ package inbound import ( + "errors" + "fmt" + "strings" + C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/listener/redir" "github.com/metacubex/mihomo/log" @@ -17,7 +21,7 @@ func (o RedirOption) Equal(config C.InboundConfig) bool { type Redir struct { *Base config *RedirOption - l *redir.Listener + l []*redir.Listener } func NewRedir(options *RedirOption) (*Redir, error) { @@ -38,15 +42,21 @@ func (r *Redir) Config() C.InboundConfig { // Address implements constant.InboundListener func (r *Redir) Address() string { - return r.l.Address() + var addrList []string + for _, l := range r.l { + addrList = append(addrList, l.Address()) + } + return strings.Join(addrList, ",") } // Listen implements constant.InboundListener func (r *Redir) Listen(tunnel C.Tunnel) error { - var err error - r.l, err = redir.New(r.RawAddress(), tunnel, r.Additions()...) - if err != nil { - return err + for _, addr := range strings.Split(r.RawAddress(), ",") { + l, err := redir.New(addr, tunnel, r.Additions()...) + if err != nil { + return err + } + r.l = append(r.l, l) } log.Infoln("Redir[%s] proxy listening at: %s", r.Name(), r.Address()) return nil @@ -54,8 +64,15 @@ func (r *Redir) Listen(tunnel C.Tunnel) error { // Close implements constant.InboundListener func (r *Redir) Close() error { - if r.l != nil { - r.l.Close() + var errs []error + for _, l := range r.l { + err := l.Close() + if err != nil { + errs = append(errs, fmt.Errorf("close redir listener %s err: %w", l.Address(), err)) + } + } + if len(errs) > 0 { + return errors.Join(errs...) } return nil } diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/shadowsocks.go b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/shadowsocks.go index 240e641901..51592ab35f 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/shadowsocks.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/shadowsocks.go @@ -1,6 +1,8 @@ package inbound import ( + "strings" + C "github.com/metacubex/mihomo/constant" LC "github.com/metacubex/mihomo/listener/config" "github.com/metacubex/mihomo/listener/sing_shadowsocks" @@ -52,12 +54,13 @@ func (s *ShadowSocks) Config() C.InboundConfig { // Address implements constant.InboundListener func (s *ShadowSocks) Address() string { + var addrList []string if s.l != nil { for _, addr := range s.l.AddrList() { - return addr.String() + addrList = append(addrList, addr.String()) } } - return "" + return strings.Join(addrList, ",") } // Listen implements constant.InboundListener diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/socks.go b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/socks.go index 119eec8281..6cb9782cf0 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/socks.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/socks.go @@ -1,16 +1,23 @@ package inbound import ( + "errors" "fmt" + "strings" + C "github.com/metacubex/mihomo/constant" + LC "github.com/metacubex/mihomo/listener/config" "github.com/metacubex/mihomo/listener/socks" "github.com/metacubex/mihomo/log" ) type SocksOption struct { BaseOption - Users AuthUsers `inbound:"users,omitempty"` - UDP bool `inbound:"udp,omitempty"` + Users AuthUsers `inbound:"users,omitempty"` + UDP bool `inbound:"udp,omitempty"` + Certificate string `inbound:"certificate,omitempty"` + PrivateKey string `inbound:"private-key,omitempty"` + RealityConfig RealityConfig `inbound:"reality-config,omitempty"` } func (o SocksOption) Equal(config C.InboundConfig) bool { @@ -21,8 +28,8 @@ type Socks struct { *Base config *SocksOption udp bool - stl *socks.Listener - sul *socks.UDPListener + stl []*socks.Listener + sul []*socks.UDPListener } func NewSocks(options *SocksOption) (*Socks, error) { @@ -44,40 +51,60 @@ func (s *Socks) Config() C.InboundConfig { // Close implements constant.InboundListener func (s *Socks) Close() error { - var err error - if s.stl != nil { - if tcpErr := s.stl.Close(); tcpErr != nil { - err = tcpErr + var errs []error + for _, l := range s.stl { + err := l.Close() + if err != nil { + errs = append(errs, fmt.Errorf("close tcp listener %s err: %w", l.Address(), err)) } } - if s.udp && s.sul != nil { - if udpErr := s.sul.Close(); udpErr != nil { - if err == nil { - err = udpErr - } else { - return fmt.Errorf("close tcp err: %s, close udp err: %s", err.Error(), udpErr.Error()) - } + for _, l := range s.sul { + err := l.Close() + if err != nil { + errs = append(errs, fmt.Errorf("close udp listener %s err: %w", l.Address(), err)) } } - - return err + if len(errs) > 0 { + return errors.Join(errs...) + } + return nil } // Address implements constant.InboundListener func (s *Socks) Address() string { - return s.stl.Address() + var addrList []string + for _, l := range s.stl { + addrList = append(addrList, l.Address()) + } + return strings.Join(addrList, ",") } // Listen implements constant.InboundListener func (s *Socks) Listen(tunnel C.Tunnel) error { - var err error - if s.stl, err = socks.NewWithAuthenticator(s.RawAddress(), tunnel, s.config.Users.GetAuthStore(), s.Additions()...); err != nil { - return err - } - if s.udp { - if s.sul, err = socks.NewUDP(s.RawAddress(), tunnel, s.Additions()...); err != nil { + for _, addr := range strings.Split(s.RawAddress(), ",") { + stl, err := socks.NewWithConfig( + LC.AuthServer{ + Enable: true, + Listen: addr, + AuthStore: s.config.Users.GetAuthStore(), + Certificate: s.config.Certificate, + PrivateKey: s.config.PrivateKey, + RealityConfig: s.config.RealityConfig.Build(), + }, + tunnel, + s.Additions()..., + ) + if err != nil { return err } + s.stl = append(s.stl, stl) + if s.udp { + sul, err := socks.NewUDP(addr, tunnel, s.Additions()...) + if err != nil { + return err + } + s.sul = append(s.sul, sul) + } } log.Infoln("SOCKS[%s] proxy listening at: %s", s.Name(), s.Address()) diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/tproxy.go b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/tproxy.go index acc8cb5e8a..66a50f7558 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/tproxy.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/tproxy.go @@ -1,7 +1,9 @@ package inbound import ( + "errors" "fmt" + "strings" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/listener/tproxy" @@ -20,8 +22,8 @@ func (o TProxyOption) Equal(config C.InboundConfig) bool { type TProxy struct { *Base config *TProxyOption - lUDP *tproxy.UDPListener - lTCP *tproxy.Listener + lUDP []*tproxy.UDPListener + lTCP []*tproxy.Listener udp bool } @@ -45,21 +47,28 @@ func (t *TProxy) Config() C.InboundConfig { // Address implements constant.InboundListener func (t *TProxy) Address() string { - return t.lTCP.Address() + var addrList []string + for _, l := range t.lTCP { + addrList = append(addrList, l.Address()) + } + return strings.Join(addrList, ",") } // Listen implements constant.InboundListener func (t *TProxy) Listen(tunnel C.Tunnel) error { - var err error - t.lTCP, err = tproxy.New(t.RawAddress(), tunnel, t.Additions()...) - if err != nil { - return err - } - if t.udp { - t.lUDP, err = tproxy.NewUDP(t.RawAddress(), tunnel, t.Additions()...) + for _, addr := range strings.Split(t.RawAddress(), ",") { + lTCP, err := tproxy.New(addr, tunnel, t.Additions()...) if err != nil { return err } + t.lTCP = append(t.lTCP, lTCP) + if t.udp { + lUDP, err := tproxy.NewUDP(addr, tunnel, t.Additions()...) + if err != nil { + return err + } + t.lUDP = append(t.lUDP, lUDP) + } } log.Infoln("TProxy[%s] proxy listening at: %s", t.Name(), t.Address()) return nil @@ -67,23 +76,21 @@ func (t *TProxy) Listen(tunnel C.Tunnel) error { // Close implements constant.InboundListener func (t *TProxy) Close() error { - var tcpErr error - var udpErr error - if t.lTCP != nil { - tcpErr = t.lTCP.Close() + var errs []error + for _, l := range t.lTCP { + err := l.Close() + if err != nil { + errs = append(errs, fmt.Errorf("close tcp listener %s err: %w", l.Address(), err)) + } } - if t.lUDP != nil { - udpErr = t.lUDP.Close() + for _, l := range t.lUDP { + err := l.Close() + if err != nil { + errs = append(errs, fmt.Errorf("close udp listener %s err: %w", l.Address(), err)) + } } - - if tcpErr != nil && udpErr != nil { - return fmt.Errorf("tcp close err: %s and udp close err: %s", tcpErr, udpErr) - } - if tcpErr != nil { - return tcpErr - } - if udpErr != nil { - return udpErr + if len(errs) > 0 { + return errors.Join(errs...) } return nil } diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/trojan.go b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/trojan.go new file mode 100644 index 0000000000..44c56b0b43 --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/trojan.go @@ -0,0 +1,113 @@ +package inbound + +import ( + "strings" + + C "github.com/metacubex/mihomo/constant" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/listener/trojan" + "github.com/metacubex/mihomo/log" +) + +type TrojanOption struct { + BaseOption + Users []TrojanUser `inbound:"users"` + WsPath string `inbound:"ws-path,omitempty"` + GrpcServiceName string `inbound:"grpc-service-name,omitempty"` + Certificate string `inbound:"certificate,omitempty"` + PrivateKey string `inbound:"private-key,omitempty"` + RealityConfig RealityConfig `inbound:"reality-config,omitempty"` + MuxOption MuxOption `inbound:"mux-option,omitempty"` + SSOption TrojanSSOption `inbound:"ss-option,omitempty"` +} + +type TrojanUser struct { + Username string `inbound:"username,omitempty"` + Password string `inbound:"password"` +} + +// TrojanSSOption from https://github.com/p4gefau1t/trojan-go/blob/v0.10.6/tunnel/shadowsocks/config.go#L5 +type TrojanSSOption struct { + Enabled bool `inbound:"enabled,omitempty"` + Method string `inbound:"method,omitempty"` + Password string `inbound:"password,omitempty"` +} + +func (o TrojanOption) Equal(config C.InboundConfig) bool { + return optionToString(o) == optionToString(config) +} + +type Trojan struct { + *Base + config *TrojanOption + l C.MultiAddrListener + vs LC.TrojanServer +} + +func NewTrojan(options *TrojanOption) (*Trojan, error) { + base, err := NewBase(&options.BaseOption) + if err != nil { + return nil, err + } + users := make([]LC.TrojanUser, len(options.Users)) + for i, v := range options.Users { + users[i] = LC.TrojanUser{ + Username: v.Username, + Password: v.Password, + } + } + return &Trojan{ + Base: base, + config: options, + vs: LC.TrojanServer{ + Enable: true, + Listen: base.RawAddress(), + Users: users, + WsPath: options.WsPath, + GrpcServiceName: options.GrpcServiceName, + Certificate: options.Certificate, + PrivateKey: options.PrivateKey, + RealityConfig: options.RealityConfig.Build(), + MuxOption: options.MuxOption.Build(), + TrojanSSOption: LC.TrojanSSOption{ + Enabled: options.SSOption.Enabled, + Method: options.SSOption.Method, + Password: options.SSOption.Password, + }, + }, + }, nil +} + +// Config implements constant.InboundListener +func (v *Trojan) Config() C.InboundConfig { + return v.config +} + +// Address implements constant.InboundListener +func (v *Trojan) Address() string { + var addrList []string + if v.l != nil { + for _, addr := range v.l.AddrList() { + addrList = append(addrList, addr.String()) + } + } + return strings.Join(addrList, ",") +} + +// Listen implements constant.InboundListener +func (v *Trojan) Listen(tunnel C.Tunnel) error { + var err error + v.l, err = trojan.New(v.vs, tunnel, v.Additions()...) + if err != nil { + return err + } + log.Infoln("Trojan[%s] proxy listening at: %s", v.Name(), v.Address()) + return nil +} + +// Close implements constant.InboundListener +func (v *Trojan) Close() error { + return v.l.Close() +} + +var _ C.InboundListener = (*Trojan)(nil) diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/tuic.go b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/tuic.go index 562228eefb..e9c2f21bc1 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/tuic.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/tuic.go @@ -1,6 +1,8 @@ package inbound import ( + "strings" + C "github.com/metacubex/mihomo/constant" LC "github.com/metacubex/mihomo/listener/config" "github.com/metacubex/mihomo/listener/tuic" @@ -66,12 +68,13 @@ func (t *Tuic) Config() C.InboundConfig { // Address implements constant.InboundListener func (t *Tuic) Address() string { + var addrList []string if t.l != nil { for _, addr := range t.l.AddrList() { - return addr.String() + addrList = append(addrList, addr.String()) } } - return "" + return strings.Join(addrList, ",") } // Listen implements constant.InboundListener diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/tunnel.go b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/tunnel.go index 2dfaac743f..0b3d5b230e 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/tunnel.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/tunnel.go @@ -1,7 +1,9 @@ package inbound import ( + "errors" "fmt" + "strings" C "github.com/metacubex/mihomo/constant" LT "github.com/metacubex/mihomo/listener/tunnel" @@ -21,8 +23,8 @@ func (o TunnelOption) Equal(config C.InboundConfig) bool { type Tunnel struct { *Base config *TunnelOption - ttl *LT.Listener - tul *LT.PacketConn + ttl []*LT.Listener + tul []*LT.PacketConn } func NewTunnel(options *TunnelOption) (*Tunnel, error) { @@ -43,56 +45,62 @@ func (t *Tunnel) Config() C.InboundConfig { // Close implements constant.InboundListener func (t *Tunnel) Close() error { - var err error - if t.ttl != nil { - if tcpErr := t.ttl.Close(); tcpErr != nil { - err = tcpErr + var errs []error + for _, l := range t.ttl { + err := l.Close() + if err != nil { + errs = append(errs, fmt.Errorf("close tcp listener %s err: %w", l.Address(), err)) } } - if t.tul != nil { - if udpErr := t.tul.Close(); udpErr != nil { - if err == nil { - err = udpErr - } else { - return fmt.Errorf("close tcp err: %s, close udp err: %s", err.Error(), udpErr.Error()) - } + for _, l := range t.tul { + err := l.Close() + if err != nil { + errs = append(errs, fmt.Errorf("close udp listener %s err: %w", l.Address(), err)) } } - - return err -} - -// Address implements constant.InboundListener -func (t *Tunnel) Address() string { - if t.ttl != nil { - return t.ttl.Address() - } - if t.tul != nil { - return t.tul.Address() - } - return "" -} - -// Listen implements constant.InboundListener -func (t *Tunnel) Listen(tunnel C.Tunnel) error { - var err error - for _, network := range t.config.Network { - switch network { - case "tcp": - if t.ttl, err = LT.New(t.RawAddress(), t.config.Target, t.config.SpecialProxy, tunnel, t.Additions()...); err != nil { - return err - } - case "udp": - if t.tul, err = LT.NewUDP(t.RawAddress(), t.config.Target, t.config.SpecialProxy, tunnel, t.Additions()...); err != nil { - return err - } - default: - log.Warnln("unknown network type: %s, passed", network) - continue - } - log.Infoln("Tunnel[%s](%s/%s)proxy listening at: %s", t.Name(), network, t.config.Target, t.Address()) + if len(errs) > 0 { + return errors.Join(errs...) } return nil } +// Address implements constant.InboundListener +func (t *Tunnel) Address() string { + var addrList []string + for _, l := range t.ttl { + addrList = append(addrList, "tcp://"+l.Address()) + } + for _, l := range t.tul { + addrList = append(addrList, "udp://"+l.Address()) + } + return strings.Join(addrList, ",") +} + +// Listen implements constant.InboundListener +func (t *Tunnel) Listen(tunnel C.Tunnel) error { + for _, addr := range strings.Split(t.RawAddress(), ",") { + for _, network := range t.config.Network { + switch network { + case "tcp": + ttl, err := LT.New(addr, t.config.Target, t.config.SpecialProxy, tunnel, t.Additions()...) + if err != nil { + return err + } + t.ttl = append(t.ttl, ttl) + case "udp": + tul, err := LT.NewUDP(addr, t.config.Target, t.config.SpecialProxy, tunnel, t.Additions()...) + if err != nil { + return err + } + t.tul = append(t.tul, tul) + default: + log.Warnln("unknown network type: %s, passed", network) + continue + } + } + } + log.Infoln("Tunnel[%s](%s)proxy listening at: %s", t.Name(), t.config.Target, t.Address()) + return nil +} + var _ C.InboundListener = (*Tunnel)(nil) diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/vless.go b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/vless.go index eb3b3c5a42..0cbf214fb5 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/vless.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/vless.go @@ -1,6 +1,8 @@ package inbound import ( + "strings" + C "github.com/metacubex/mihomo/constant" LC "github.com/metacubex/mihomo/listener/config" "github.com/metacubex/mihomo/listener/sing_vless" @@ -9,12 +11,13 @@ import ( type VlessOption struct { BaseOption - Users []VlessUser `inbound:"users"` - WsPath string `inbound:"ws-path,omitempty"` - Certificate string `inbound:"certificate,omitempty"` - PrivateKey string `inbound:"private-key,omitempty"` - RealityConfig RealityConfig `inbound:"reality-config,omitempty"` - MuxOption MuxOption `inbound:"mux-option,omitempty"` + Users []VlessUser `inbound:"users"` + WsPath string `inbound:"ws-path,omitempty"` + GrpcServiceName string `inbound:"grpc-service-name,omitempty"` + Certificate string `inbound:"certificate,omitempty"` + PrivateKey string `inbound:"private-key,omitempty"` + RealityConfig RealityConfig `inbound:"reality-config,omitempty"` + MuxOption MuxOption `inbound:"mux-option,omitempty"` } type VlessUser struct { @@ -51,14 +54,15 @@ func NewVless(options *VlessOption) (*Vless, error) { Base: base, config: options, vs: LC.VlessServer{ - Enable: true, - Listen: base.RawAddress(), - Users: users, - WsPath: options.WsPath, - Certificate: options.Certificate, - PrivateKey: options.PrivateKey, - RealityConfig: options.RealityConfig.Build(), - MuxOption: options.MuxOption.Build(), + Enable: true, + Listen: base.RawAddress(), + Users: users, + WsPath: options.WsPath, + GrpcServiceName: options.GrpcServiceName, + Certificate: options.Certificate, + PrivateKey: options.PrivateKey, + RealityConfig: options.RealityConfig.Build(), + MuxOption: options.MuxOption.Build(), }, }, nil } @@ -70,25 +74,18 @@ func (v *Vless) Config() C.InboundConfig { // Address implements constant.InboundListener func (v *Vless) Address() string { + var addrList []string if v.l != nil { for _, addr := range v.l.AddrList() { - return addr.String() + addrList = append(addrList, addr.String()) } } - return "" + return strings.Join(addrList, ",") } // Listen implements constant.InboundListener func (v *Vless) Listen(tunnel C.Tunnel) error { var err error - users := make([]LC.VlessUser, len(v.config.Users)) - for i, v := range v.config.Users { - users[i] = LC.VlessUser{ - Username: v.Username, - UUID: v.UUID, - Flow: v.Flow, - } - } v.l, err = sing_vless.New(v.vs, tunnel, v.Additions()...) if err != nil { return err diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/vmess.go b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/vmess.go index cf2379e107..2212a75db7 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/vmess.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/vmess.go @@ -1,6 +1,8 @@ package inbound import ( + "strings" + C "github.com/metacubex/mihomo/constant" LC "github.com/metacubex/mihomo/listener/config" "github.com/metacubex/mihomo/listener/sing_vmess" @@ -9,12 +11,13 @@ import ( type VmessOption struct { BaseOption - Users []VmessUser `inbound:"users"` - WsPath string `inbound:"ws-path,omitempty"` - Certificate string `inbound:"certificate,omitempty"` - PrivateKey string `inbound:"private-key,omitempty"` - RealityConfig RealityConfig `inbound:"reality-config,omitempty"` - MuxOption MuxOption `inbound:"mux-option,omitempty"` + Users []VmessUser `inbound:"users"` + WsPath string `inbound:"ws-path,omitempty"` + GrpcServiceName string `inbound:"grpc-service-name,omitempty"` + Certificate string `inbound:"certificate,omitempty"` + PrivateKey string `inbound:"private-key,omitempty"` + RealityConfig RealityConfig `inbound:"reality-config,omitempty"` + MuxOption MuxOption `inbound:"mux-option,omitempty"` } type VmessUser struct { @@ -51,14 +54,15 @@ func NewVmess(options *VmessOption) (*Vmess, error) { Base: base, config: options, vs: LC.VmessServer{ - Enable: true, - Listen: base.RawAddress(), - Users: users, - WsPath: options.WsPath, - Certificate: options.Certificate, - PrivateKey: options.PrivateKey, - RealityConfig: options.RealityConfig.Build(), - MuxOption: options.MuxOption.Build(), + Enable: true, + Listen: base.RawAddress(), + Users: users, + WsPath: options.WsPath, + GrpcServiceName: options.GrpcServiceName, + Certificate: options.Certificate, + PrivateKey: options.PrivateKey, + RealityConfig: options.RealityConfig.Build(), + MuxOption: options.MuxOption.Build(), }, }, nil } @@ -70,25 +74,18 @@ func (v *Vmess) Config() C.InboundConfig { // Address implements constant.InboundListener func (v *Vmess) Address() string { + var addrList []string if v.l != nil { for _, addr := range v.l.AddrList() { - return addr.String() + addrList = append(addrList, addr.String()) } } - return "" + return strings.Join(addrList, ",") } // Listen implements constant.InboundListener func (v *Vmess) Listen(tunnel C.Tunnel) error { var err error - users := make([]LC.VmessUser, len(v.config.Users)) - for i, v := range v.config.Users { - users[i] = LC.VmessUser{ - Username: v.Username, - UUID: v.UUID, - AlterID: v.AlterID, - } - } v.l, err = sing_vmess.New(v.vs, tunnel, v.Additions()...) if err != nil { return err diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/mixed/mixed.go b/clash-meta-android/core/src/foss/golang/clash/listener/mixed/mixed.go index 5ac6301153..6785b7fe5b 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/mixed/mixed.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/mixed/mixed.go @@ -1,6 +1,8 @@ package mixed import ( + "crypto/tls" + "errors" "net" "github.com/metacubex/mihomo/adapter/inbound" @@ -8,7 +10,9 @@ import ( "github.com/metacubex/mihomo/component/auth" C "github.com/metacubex/mihomo/constant" authStore "github.com/metacubex/mihomo/listener/auth" + LC "github.com/metacubex/mihomo/listener/config" "github.com/metacubex/mihomo/listener/http" + "github.com/metacubex/mihomo/listener/reality" "github.com/metacubex/mihomo/listener/socks" "github.com/metacubex/mihomo/transport/socks4" "github.com/metacubex/mihomo/transport/socks5" @@ -37,10 +41,10 @@ func (l *Listener) Close() error { } func New(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) { - return NewWithAuthenticator(addr, tunnel, authStore.Default, additions...) + return NewWithConfig(LC.AuthServer{Enable: true, Listen: addr, AuthStore: authStore.Default}, tunnel, additions...) } -func NewWithAuthenticator(addr string, tunnel C.Tunnel, store auth.AuthStore, additions ...inbound.Addition) (*Listener, error) { +func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) { isDefault := false if len(additions) == 0 { isDefault = true @@ -50,14 +54,40 @@ func NewWithAuthenticator(addr string, tunnel C.Tunnel, store auth.AuthStore, ad } } - l, err := inbound.Listen("tcp", addr) + l, err := inbound.Listen("tcp", config.Listen) if err != nil { return nil, err } + tlsConfig := &tls.Config{} + var realityBuilder *reality.Builder + + if config.Certificate != "" && config.PrivateKey != "" { + cert, err := N.ParseCert(config.Certificate, config.PrivateKey, C.Path) + if err != nil { + return nil, err + } + tlsConfig.Certificates = []tls.Certificate{cert} + } + if config.RealityConfig.PrivateKey != "" { + if tlsConfig.Certificates != nil { + return nil, errors.New("certificate is unavailable in reality") + } + realityBuilder, err = config.RealityConfig.Build() + if err != nil { + return nil, err + } + } + + if realityBuilder != nil { + l = realityBuilder.NewListener(l) + } else if len(tlsConfig.Certificates) > 0 { + l = tls.NewListener(l, tlsConfig) + } + ml := &Listener{ listener: l, - addr: addr, + addr: config.Listen, } go func() { for { @@ -68,7 +98,7 @@ func NewWithAuthenticator(addr string, tunnel C.Tunnel, store auth.AuthStore, ad } continue } - store := store + store := config.AuthStore if isDefault || store == authStore.Default { // only apply on default listener if !inbound.IsRemoteAddrDisAllowed(c.RemoteAddr()) { _ = c.Close() diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/parse.go b/clash-meta-android/core/src/foss/golang/clash/listener/parse.go index 5c5d6c7e48..adc206c10c 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/parse.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/parse.go @@ -93,6 +93,13 @@ func ParseListener(mapping map[string]any) (C.InboundListener, error) { return nil, err } listener, err = IN.NewVless(vlessOption) + case "trojan": + trojanOption := &IN.TrojanOption{} + err = decoder.Decode(mapping, trojanOption) + if err != nil { + return nil, err + } + listener, err = IN.NewTrojan(trojanOption) case "hysteria2": hysteria2Option := &IN.Hysteria2Option{} err = decoder.Decode(mapping, hysteria2Option) diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/shadowsocks/tcp.go b/clash-meta-android/core/src/foss/golang/clash/listener/shadowsocks/tcp.go index b150e4cbc1..8ae269ed9d 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/shadowsocks/tcp.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/shadowsocks/tcp.go @@ -8,6 +8,7 @@ import ( N "github.com/metacubex/mihomo/common/net" C "github.com/metacubex/mihomo/constant" LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/listener/sing" "github.com/metacubex/mihomo/transport/shadowsocks/core" "github.com/metacubex/mihomo/transport/socks5" ) @@ -18,6 +19,7 @@ type Listener struct { listeners []net.Listener udpListeners []*UDPListener pickCipher core.Cipher + handler *sing.ListenerHandler } var _listener *Listener @@ -28,7 +30,17 @@ func New(config LC.ShadowsocksServer, tunnel C.Tunnel, additions ...inbound.Addi return nil, err } - sl := &Listener{false, config, nil, nil, pickCipher} + h, err := sing.NewListenerHandler(sing.ListenerConfig{ + Tunnel: tunnel, + Type: C.SHADOWSOCKS, + Additions: additions, + MuxOption: config.MuxOption, + }) + if err != nil { + return nil, err + } + + sl := &Listener{false, config, nil, nil, pickCipher, h} _listener = sl for _, addr := range strings.Split(config.Listen, ",") { @@ -107,7 +119,8 @@ func (l *Listener) HandleConn(conn net.Conn, tunnel C.Tunnel, additions ...inbou _ = conn.Close() return } - tunnel.HandleTCPConn(inbound.NewSocket(target, conn, C.SHADOWSOCKS, additions...)) + l.handler.HandleSocket(target, conn, additions...) + //tunnel.HandleTCPConn(inbound.NewSocket(target, conn, C.SHADOWSOCKS, additions...)) } func HandleShadowSocks(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) bool { diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/sing/sing.go b/clash-meta-android/core/src/foss/golang/clash/listener/sing/sing.go index 0d4bb92657..eb13e6c94d 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/sing/sing.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/sing/sing.go @@ -136,8 +136,8 @@ func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, meta cMetadata.RawDstAddr = metadata.Destination.Unwrap().TCPAddr() } inbound.ApplyAdditions(cMetadata, inbound.WithDstAddr(metadata.Destination), inbound.WithSrcAddr(metadata.Source), inbound.WithInAddr(conn.LocalAddr())) - inbound.ApplyAdditions(cMetadata, getAdditions(ctx)...) inbound.ApplyAdditions(cMetadata, h.Additions...) + inbound.ApplyAdditions(cMetadata, getAdditions(ctx)...) h.Tunnel.HandleTCPConn(conn, cMetadata) // this goroutine must exit after conn unused return nil @@ -198,8 +198,8 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. cMetadata.RawDstAddr = dest.Unwrap().UDPAddr() } inbound.ApplyAdditions(cMetadata, inbound.WithDstAddr(dest), inbound.WithSrcAddr(metadata.Source), inbound.WithInAddr(conn.LocalAddr())) - inbound.ApplyAdditions(cMetadata, getAdditions(ctx)...) inbound.ApplyAdditions(cMetadata, h.Additions...) + inbound.ApplyAdditions(cMetadata, getAdditions(ctx)...) h.Tunnel.HandleUDPPacket(cPacket, cMetadata) } diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/sing/util.go b/clash-meta-android/core/src/foss/golang/clash/listener/sing/util.go new file mode 100644 index 0000000000..306301621b --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/listener/sing/util.go @@ -0,0 +1,24 @@ +package sing + +import ( + "context" + "net" + + "github.com/metacubex/mihomo/adapter/inbound" + "github.com/metacubex/mihomo/transport/socks5" +) + +// HandleSocket like inbound.NewSocket combine with Tunnel.HandleTCPConn but also handel specialFqdn +func (h *ListenerHandler) HandleSocket(target socks5.Addr, conn net.Conn, _additions ...inbound.Addition) { + conn, metadata := inbound.NewSocket(target, conn, h.Type, h.Additions...) + if h.IsSpecialFqdn(metadata.Host) { + _ = h.ParseSpecialFqdn( + WithAdditions(context.Background(), _additions...), + conn, + ConvertMetadata(metadata), + ) + } else { + inbound.ApplyAdditions(metadata, _additions...) + h.Tunnel.HandleTCPConn(conn, metadata) + } +} diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/sing_vless/server.go b/clash-meta-android/core/src/foss/golang/clash/listener/sing_vless/server.go index 2377ff62b6..f1d5a8f956 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/sing_vless/server.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/sing_vless/server.go @@ -18,6 +18,7 @@ import ( "github.com/metacubex/mihomo/listener/reality" "github.com/metacubex/mihomo/listener/sing" "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/transport/gun" mihomoVMess "github.com/metacubex/mihomo/transport/vmess" "github.com/metacubex/sing-vmess/vless" @@ -92,7 +93,7 @@ func New(config LC.VlessServer, tunnel C.Tunnel, additions ...inbound.Addition) tlsConfig := &tls.Config{} var realityBuilder *reality.Builder - var httpMux *http.ServeMux + var httpHandler http.Handler if config.Certificate != "" && config.PrivateKey != "" { cert, err := N.ParseCert(config.Certificate, config.PrivateKey, C.Path) @@ -111,17 +112,28 @@ func New(config LC.VlessServer, tunnel C.Tunnel, additions ...inbound.Addition) } } if config.WsPath != "" { - httpMux = http.NewServeMux() + httpMux := http.NewServeMux() httpMux.HandleFunc(config.WsPath, func(w http.ResponseWriter, r *http.Request) { conn, err := mihomoVMess.StreamUpgradedWebsocketConn(w, r) if err != nil { http.Error(w, err.Error(), 500) return } - sl.HandleConn(conn, tunnel) + sl.HandleConn(conn, tunnel, additions...) }) + httpHandler = httpMux tlsConfig.NextProtos = append(tlsConfig.NextProtos, "http/1.1") } + if config.GrpcServiceName != "" { + httpHandler = gun.NewServerHandler(gun.ServerOption{ + ServiceName: config.GrpcServiceName, + ConnHandler: func(conn net.Conn) { + sl.HandleConn(conn, tunnel, additions...) + }, + HttpHandler: httpHandler, + }) + tlsConfig.NextProtos = append([]string{"h2"}, tlsConfig.NextProtos...) // h2 must before http/1.1 + } for _, addr := range strings.Split(config.Listen, ",") { addr := addr @@ -141,8 +153,8 @@ func New(config LC.VlessServer, tunnel C.Tunnel, additions ...inbound.Addition) sl.listeners = append(sl.listeners, l) go func() { - if httpMux != nil { - _ = http.Serve(l, httpMux) + if httpHandler != nil { + _ = http.Serve(l, httpHandler) return } for { diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/sing_vmess/server.go b/clash-meta-android/core/src/foss/golang/clash/listener/sing_vmess/server.go index b344fcb476..4e887a119a 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/sing_vmess/server.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/sing_vmess/server.go @@ -16,6 +16,7 @@ import ( "github.com/metacubex/mihomo/listener/reality" "github.com/metacubex/mihomo/listener/sing" "github.com/metacubex/mihomo/ntp" + "github.com/metacubex/mihomo/transport/gun" mihomoVMess "github.com/metacubex/mihomo/transport/vmess" vmess "github.com/metacubex/sing-vmess" @@ -76,7 +77,7 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition) tlsConfig := &tls.Config{} var realityBuilder *reality.Builder - var httpMux *http.ServeMux + var httpHandler http.Handler if config.Certificate != "" && config.PrivateKey != "" { cert, err := N.ParseCert(config.Certificate, config.PrivateKey, C.Path) @@ -95,17 +96,28 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition) } } if config.WsPath != "" { - httpMux = http.NewServeMux() + httpMux := http.NewServeMux() httpMux.HandleFunc(config.WsPath, func(w http.ResponseWriter, r *http.Request) { conn, err := mihomoVMess.StreamUpgradedWebsocketConn(w, r) if err != nil { http.Error(w, err.Error(), 500) return } - sl.HandleConn(conn, tunnel) + sl.HandleConn(conn, tunnel, additions...) }) + httpHandler = httpMux tlsConfig.NextProtos = append(tlsConfig.NextProtos, "http/1.1") } + if config.GrpcServiceName != "" { + httpHandler = gun.NewServerHandler(gun.ServerOption{ + ServiceName: config.GrpcServiceName, + ConnHandler: func(conn net.Conn) { + sl.HandleConn(conn, tunnel, additions...) + }, + HttpHandler: httpHandler, + }) + tlsConfig.NextProtos = append([]string{"h2"}, tlsConfig.NextProtos...) // h2 must before http/1.1 + } for _, addr := range strings.Split(config.Listen, ",") { addr := addr @@ -123,8 +135,8 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition) sl.listeners = append(sl.listeners, l) go func() { - if httpMux != nil { - _ = http.Serve(l, httpMux) + if httpHandler != nil { + _ = http.Serve(l, httpHandler) return } for { diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/socks/tcp.go b/clash-meta-android/core/src/foss/golang/clash/listener/socks/tcp.go index cc66613e2a..5515360772 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/socks/tcp.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/socks/tcp.go @@ -1,6 +1,8 @@ package socks import ( + "crypto/tls" + "errors" "io" "net" @@ -9,6 +11,8 @@ import ( "github.com/metacubex/mihomo/component/auth" C "github.com/metacubex/mihomo/constant" authStore "github.com/metacubex/mihomo/listener/auth" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/listener/reality" "github.com/metacubex/mihomo/transport/socks4" "github.com/metacubex/mihomo/transport/socks5" ) @@ -36,10 +40,10 @@ func (l *Listener) Close() error { } func New(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) { - return NewWithAuthenticator(addr, tunnel, authStore.Default, additions...) + return NewWithConfig(LC.AuthServer{Enable: true, Listen: addr, AuthStore: authStore.Default}, tunnel, additions...) } -func NewWithAuthenticator(addr string, tunnel C.Tunnel, store auth.AuthStore, additions ...inbound.Addition) (*Listener, error) { +func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) { isDefault := false if len(additions) == 0 { isDefault = true @@ -49,14 +53,40 @@ func NewWithAuthenticator(addr string, tunnel C.Tunnel, store auth.AuthStore, ad } } - l, err := inbound.Listen("tcp", addr) + l, err := inbound.Listen("tcp", config.Listen) if err != nil { return nil, err } + tlsConfig := &tls.Config{} + var realityBuilder *reality.Builder + + if config.Certificate != "" && config.PrivateKey != "" { + cert, err := N.ParseCert(config.Certificate, config.PrivateKey, C.Path) + if err != nil { + return nil, err + } + tlsConfig.Certificates = []tls.Certificate{cert} + } + if config.RealityConfig.PrivateKey != "" { + if tlsConfig.Certificates != nil { + return nil, errors.New("certificate is unavailable in reality") + } + realityBuilder, err = config.RealityConfig.Build() + if err != nil { + return nil, err + } + } + + if realityBuilder != nil { + l = realityBuilder.NewListener(l) + } else if len(tlsConfig.Certificates) > 0 { + l = tls.NewListener(l, tlsConfig) + } + sl := &Listener{ listener: l, - addr: addr, + addr: config.Listen, } go func() { for { @@ -67,7 +97,7 @@ func NewWithAuthenticator(addr string, tunnel C.Tunnel, store auth.AuthStore, ad } continue } - store := store + store := config.AuthStore if isDefault || store == authStore.Default { // only apply on default listener if !inbound.IsRemoteAddrDisAllowed(c.RemoteAddr()) { _ = c.Close() diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/trojan/packet.go b/clash-meta-android/core/src/foss/golang/clash/listener/trojan/packet.go new file mode 100644 index 0000000000..5111242ebd --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/listener/trojan/packet.go @@ -0,0 +1,43 @@ +package trojan + +import ( + "errors" + "net" +) + +type packet struct { + pc net.PacketConn + rAddr net.Addr + payload []byte + put func() +} + +func (c *packet) Data() []byte { + return c.payload +} + +// WriteBack wirtes UDP packet with source(ip, port) = `addr` +func (c *packet) WriteBack(b []byte, addr net.Addr) (n int, err error) { + if addr == nil { + err = errors.New("address is invalid") + return + } + return c.pc.WriteTo(b, addr) +} + +// LocalAddr returns the source IP/Port of UDP Packet +func (c *packet) LocalAddr() net.Addr { + return c.rAddr +} + +func (c *packet) Drop() { + if c.put != nil { + c.put() + c.put = nil + } + c.payload = nil +} + +func (c *packet) InAddr() net.Addr { + return c.pc.LocalAddr() +} diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/trojan/server.go b/clash-meta-android/core/src/foss/golang/clash/listener/trojan/server.go new file mode 100644 index 0000000000..3141ab0b91 --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/listener/trojan/server.go @@ -0,0 +1,283 @@ +package trojan + +import ( + "crypto/tls" + "errors" + "io" + "net" + "net/http" + "strings" + + "github.com/metacubex/mihomo/adapter/inbound" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/listener/reality" + "github.com/metacubex/mihomo/listener/sing" + "github.com/metacubex/mihomo/transport/gun" + "github.com/metacubex/mihomo/transport/shadowsocks/core" + "github.com/metacubex/mihomo/transport/socks5" + "github.com/metacubex/mihomo/transport/trojan" + mihomoVMess "github.com/metacubex/mihomo/transport/vmess" + + "github.com/sagernet/smux" +) + +type Listener struct { + closed bool + config LC.TrojanServer + listeners []net.Listener + keys map[[trojan.KeyLength]byte]string + pickCipher core.Cipher + handler *sing.ListenerHandler +} + +func New(config LC.TrojanServer, tunnel C.Tunnel, additions ...inbound.Addition) (sl *Listener, err error) { + if len(additions) == 0 { + additions = []inbound.Addition{ + inbound.WithInName("DEFAULT-TROJAN"), + inbound.WithSpecialRules(""), + } + } + h, err := sing.NewListenerHandler(sing.ListenerConfig{ + Tunnel: tunnel, + Type: C.TROJAN, + Additions: additions, + MuxOption: config.MuxOption, + }) + if err != nil { + return nil, err + } + + keys := make(map[[trojan.KeyLength]byte]string) + for _, user := range config.Users { + keys[trojan.Key(user.Password)] = user.Username + } + + var pickCipher core.Cipher + if config.TrojanSSOption.Enabled { + if config.TrojanSSOption.Password == "" { + return nil, errors.New("empty password") + } + if config.TrojanSSOption.Method == "" { + config.TrojanSSOption.Method = "AES-128-GCM" + } + pickCipher, err = core.PickCipher(config.TrojanSSOption.Method, nil, config.TrojanSSOption.Password) + if err != nil { + return nil, err + } + } + sl = &Listener{false, config, nil, keys, pickCipher, h} + + tlsConfig := &tls.Config{} + var realityBuilder *reality.Builder + var httpHandler http.Handler + + if config.Certificate != "" && config.PrivateKey != "" { + cert, err := N.ParseCert(config.Certificate, config.PrivateKey, C.Path) + if err != nil { + return nil, err + } + tlsConfig.Certificates = []tls.Certificate{cert} + } + if config.RealityConfig.PrivateKey != "" { + if tlsConfig.Certificates != nil { + return nil, errors.New("certificate is unavailable in reality") + } + realityBuilder, err = config.RealityConfig.Build() + if err != nil { + return nil, err + } + } + if config.WsPath != "" { + httpMux := http.NewServeMux() + httpMux.HandleFunc(config.WsPath, func(w http.ResponseWriter, r *http.Request) { + conn, err := mihomoVMess.StreamUpgradedWebsocketConn(w, r) + if err != nil { + http.Error(w, err.Error(), 500) + return + } + sl.HandleConn(conn, tunnel, additions...) + }) + httpHandler = httpMux + tlsConfig.NextProtos = append(tlsConfig.NextProtos, "http/1.1") + } + if config.GrpcServiceName != "" { + httpHandler = gun.NewServerHandler(gun.ServerOption{ + ServiceName: config.GrpcServiceName, + ConnHandler: func(conn net.Conn) { + sl.HandleConn(conn, tunnel, additions...) + }, + HttpHandler: httpHandler, + }) + tlsConfig.NextProtos = append([]string{"h2"}, tlsConfig.NextProtos...) // h2 must before http/1.1 + } + + for _, addr := range strings.Split(config.Listen, ",") { + addr := addr + + //TCP + l, err := inbound.Listen("tcp", addr) + if err != nil { + return nil, err + } + if realityBuilder != nil { + l = realityBuilder.NewListener(l) + } else if len(tlsConfig.Certificates) > 0 { + l = tls.NewListener(l, tlsConfig) + } else if !config.TrojanSSOption.Enabled { + return nil, errors.New("disallow using Trojan without both certificates/reality/ss config") + } + sl.listeners = append(sl.listeners, l) + + go func() { + if httpHandler != nil { + _ = http.Serve(l, httpHandler) + return + } + for { + c, err := l.Accept() + if err != nil { + if sl.closed { + break + } + continue + } + + go sl.HandleConn(c, tunnel, additions...) + } + }() + } + + return sl, nil +} + +func (l *Listener) Close() error { + l.closed = true + var retErr error + for _, lis := range l.listeners { + err := lis.Close() + if err != nil { + retErr = err + } + } + return retErr +} + +func (l *Listener) Config() string { + return l.config.String() +} + +func (l *Listener) AddrList() (addrList []net.Addr) { + for _, lis := range l.listeners { + addrList = append(addrList, lis.Addr()) + } + return +} + +func (l *Listener) HandleConn(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) { + defer conn.Close() + + if l.pickCipher != nil { + conn = l.pickCipher.StreamConn(conn) + } + + var key [trojan.KeyLength]byte + if _, err := io.ReadFull(conn, key[:]); err != nil { + //log.Warnln("read key error: %s", err.Error()) + return + } + + if user, ok := l.keys[key]; ok { + additions = append(additions, inbound.WithInUser(user)) + } else { + //log.Warnln("no such key") + return + } + + var crlf [2]byte + if _, err := io.ReadFull(conn, crlf[:]); err != nil { + //log.Warnln("read crlf error: %s", err.Error()) + return + } + + l.handleConn(false, conn, tunnel, additions...) +} + +func (l *Listener) handleConn(inMux bool, conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) { + if inMux { + defer conn.Close() + } + + command, err := socks5.ReadByte(conn) + if err != nil { + //log.Warnln("read command error: %s", err.Error()) + return + } + + switch command { + case trojan.CommandTCP, trojan.CommandUDP, trojan.CommandMux: + default: + //log.Warnln("unknown command: %d", command) + return + } + + target, err := socks5.ReadAddr0(conn) + if err != nil { + //log.Warnln("read target error: %s", err.Error()) + return + } + + if !inMux { + var crlf [2]byte + if _, err := io.ReadFull(conn, crlf[:]); err != nil { + //log.Warnln("read crlf error: %s", err.Error()) + return + } + } + + switch command { + case trojan.CommandTCP: + //tunnel.HandleTCPConn(inbound.NewSocket(target, conn, C.TROJAN, additions...)) + l.handler.HandleSocket(target, conn, additions...) + case trojan.CommandUDP: + pc := trojan.NewPacketConn(conn) + for { + data, put, remoteAddr, err := pc.WaitReadFrom() + if err != nil { + if put != nil { + put() + } + break + } + cPacket := &packet{ + pc: pc, + rAddr: remoteAddr, + payload: data, + put: put, + } + + tunnel.HandleUDPPacket(inbound.NewPacket(target, cPacket, C.TROJAN, additions...)) + } + case trojan.CommandMux: + if inMux { + //log.Warnln("invalid command: %d", command) + return + } + smuxConfig := smux.DefaultConfig() + smuxConfig.KeepAliveDisabled = true + session, err := smux.Server(conn, smuxConfig) + if err != nil { + //log.Warnln("smux server error: %s", err.Error()) + return + } + defer session.Close() + for { + stream, err := session.AcceptStream() + if err != nil { + return + } + go l.handleConn(true, stream, tunnel, additions...) + } + } +} diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/tuic/server.go b/clash-meta-android/core/src/foss/golang/clash/listener/tuic/server.go index 837c1d10f9..3425cb04aa 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/tuic/server.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/tuic/server.go @@ -1,7 +1,6 @@ package tuic import ( - "context" "crypto/tls" "net" "strings" @@ -93,23 +92,14 @@ func New(config LC.TuicServer, tunnel C.Tunnel, additions ...inbound.Addition) ( quicConfig.MaxDatagramFrameSize = int64(maxDatagramFrameSize) handleTcpFn := func(conn net.Conn, addr socks5.Addr, _additions ...inbound.Addition) error { - newAdditions := additions - if len(_additions) > 0 { - newAdditions = slices.Clone(additions) - newAdditions = append(newAdditions, _additions...) - } - conn, metadata := inbound.NewSocket(addr, conn, C.TUIC, newAdditions...) - if h.IsSpecialFqdn(metadata.Host) { - go func() { // ParseSpecialFqdn will block, so open a new goroutine - _ = h.ParseSpecialFqdn( - sing.WithAdditions(context.Background(), newAdditions...), - conn, - sing.ConvertMetadata(metadata), - ) - }() - return nil - } - go tunnel.HandleTCPConn(conn, metadata) + //newAdditions := additions + //if len(_additions) > 0 { + // newAdditions = slices.Clone(additions) + // newAdditions = append(newAdditions, _additions...) + //} + //conn, metadata := inbound.NewSocket(addr, conn, C.TUIC, newAdditions...) + //go tunnel.HandleTCPConn(conn, metadata) + go h.HandleSocket(addr, conn, _additions...) // h.HandleSocket will block, so open a new goroutine return nil } handleUdpFn := func(addr socks5.Addr, packet C.UDPPacket, _additions ...inbound.Addition) error { diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/anytls/client.go b/clash-meta-android/core/src/foss/golang/clash/transport/anytls/client.go index 19776df97c..ea99b43883 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/anytls/client.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/anytls/client.go @@ -22,19 +22,19 @@ type ClientConfig struct { Password string IdleSessionCheckInterval time.Duration IdleSessionTimeout time.Duration + MinIdleSession int Server M.Socksaddr Dialer N.Dialer TLSConfig *vmess.TLSConfig } type Client struct { - passwordSha256 []byte - tlsConfig *vmess.TLSConfig - clientFingerprint string - dialer N.Dialer - server M.Socksaddr - sessionClient *session.Client - padding atomic.TypedValue[*padding.PaddingFactory] + passwordSha256 []byte + tlsConfig *vmess.TLSConfig + dialer N.Dialer + server M.Socksaddr + sessionClient *session.Client + padding atomic.TypedValue[*padding.PaddingFactory] } func NewClient(ctx context.Context, config ClientConfig) *Client { @@ -47,7 +47,7 @@ func NewClient(ctx context.Context, config ClientConfig) *Client { } // Initialize the padding state of this client padding.UpdatePaddingScheme(padding.DefaultPaddingScheme, &c.padding) - c.sessionClient = session.NewClient(ctx, c.CreateOutboundTLSConnection, &c.padding, config.IdleSessionCheckInterval, config.IdleSessionTimeout) + c.sessionClient = session.NewClient(ctx, c.CreateOutboundTLSConnection, &c.padding, config.IdleSessionCheckInterval, config.IdleSessionTimeout, config.MinIdleSession) return c } diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/anytls/session/client.go b/clash-meta-android/core/src/foss/golang/clash/transport/anytls/session/client.go index 2312a6ff56..5e99f13562 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/anytls/session/client.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/anytls/session/client.go @@ -19,22 +19,29 @@ type Client struct { die context.Context dieCancel context.CancelFunc - dialOut func(ctx context.Context) (net.Conn, error) + dialOut util.DialOutFunc + + sessionCounter atomic.Uint64 - sessionCounter atomic.Uint64 idleSession *skiplist.SkipList[uint64, *Session] idleSessionLock sync.Mutex + sessions map[uint64]*Session + sessionsLock sync.Mutex + padding *atomic.TypedValue[*padding.PaddingFactory] idleSessionTimeout time.Duration + minIdleSession int } -func NewClient(ctx context.Context, dialOut func(ctx context.Context) (net.Conn, error), _padding *atomic.TypedValue[*padding.PaddingFactory], idleSessionCheckInterval, idleSessionTimeout time.Duration) *Client { +func NewClient(ctx context.Context, dialOut util.DialOutFunc, _padding *atomic.TypedValue[*padding.PaddingFactory], idleSessionCheckInterval, idleSessionTimeout time.Duration, minIdleSession int) *Client { c := &Client{ + sessions: make(map[uint64]*Session), dialOut: dialOut, padding: _padding, idleSessionTimeout: idleSessionTimeout, + minIdleSession: minIdleSession, } if idleSessionCheckInterval <= time.Second*5 { idleSessionCheckInterval = time.Second * 30 @@ -81,10 +88,16 @@ func (c *Client) CreateStream(ctx context.Context) (net.Conn, error) { session.dieHook() } } else { - c.idleSessionLock.Lock() - session.idleSince = time.Now() - c.idleSession.Insert(math.MaxUint64-session.seq, session) - c.idleSessionLock.Unlock() + select { + case <-c.die.Done(): + // Now client has been closed + go session.Close() + default: + c.idleSessionLock.Lock() + session.idleSince = time.Now() + c.idleSession.Insert(math.MaxUint64-session.seq, session) + c.idleSessionLock.Unlock() + } } } @@ -122,14 +135,35 @@ func (c *Client) createSession(ctx context.Context) (*Session, error) { c.idleSessionLock.Lock() c.idleSession.Remove(math.MaxUint64 - session.seq) c.idleSessionLock.Unlock() + + c.sessionsLock.Lock() + delete(c.sessions, session.seq) + c.sessionsLock.Unlock() } + + c.sessionsLock.Lock() + c.sessions[session.seq] = session + c.sessionsLock.Unlock() + session.Run() return session, nil } func (c *Client) Close() error { c.dieCancel() - go c.idleCleanupExpTime(time.Now()) + + c.sessionsLock.Lock() + sessionToClose := make([]*Session, 0, len(c.sessions)) + for seq, session := range c.sessions { + sessionToClose = append(sessionToClose, session) + delete(c.sessions, seq) + } + c.sessionsLock.Unlock() + + for _, session := range sessionToClose { + session.Close() + } + return nil } @@ -138,17 +172,30 @@ func (c *Client) idleCleanup() { } func (c *Client) idleCleanupExpTime(expTime time.Time) { - var sessionToRemove = make([]*Session, 0) + sessionToRemove := make([]*Session, 0, c.idleSession.Len()) c.idleSessionLock.Lock() it := c.idleSession.Iterate() + + activeCount := 0 for it.IsNotEnd() { session := it.Value() - if session.idleSince.Before(expTime) { - sessionToRemove = append(sessionToRemove, session) - c.idleSession.Remove(it.Key()) - } + key := it.Key() it.MoveToNext() + + if !session.idleSince.Before(expTime) { + activeCount++ + continue + } + + if activeCount < c.minIdleSession { + session.idleSince = time.Now() + activeCount++ + continue + } + + sessionToRemove = append(sessionToRemove, session) + c.idleSession.Remove(key) } c.idleSessionLock.Unlock() diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/anytls/util/type.go b/clash-meta-android/core/src/foss/golang/clash/transport/anytls/util/type.go new file mode 100644 index 0000000000..4f28d4890e --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/transport/anytls/util/type.go @@ -0,0 +1,8 @@ +package util + +import ( + "context" + "net" +) + +type DialOutFunc func(ctx context.Context) (net.Conn, error) diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/gun/gun.go b/clash-meta-android/core/src/foss/golang/clash/transport/gun/gun.go index cf986c8e54..c28a16e8bf 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/gun/gun.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/gun/gun.go @@ -38,15 +38,17 @@ var defaultHeader = http.Header{ type DialFn = func(network, addr string) (net.Conn, error) type Conn struct { - response *http.Response - request *http.Request - transport *TransportWrap - writer *io.PipeWriter - once sync.Once - close atomic.Bool - err error - remain int - br *bufio.Reader + initFn func() (io.ReadCloser, error) + writer io.Writer + flusher http.Flusher + netAddr + + reader io.ReadCloser + once sync.Once + close atomic.Bool + err error + remain int + br *bufio.Reader // deadlines deadline *time.Timer } @@ -57,26 +59,32 @@ type Config struct { ClientFingerprint string } -func (g *Conn) initRequest() { - response, err := g.transport.RoundTrip(g.request) +func (g *Conn) initReader() { + reader, err := g.initFn() if err != nil { g.err = err - g.writer.Close() + if closer, ok := g.writer.(io.Closer); ok { + closer.Close() + } return } if !g.close.Load() { - g.response = response - g.br = bufio.NewReader(response.Body) + g.reader = reader + g.br = bufio.NewReader(reader) } else { - response.Body.Close() + reader.Close() } } +func (g *Conn) Init() error { + g.once.Do(g.initReader) + return g.err +} + func (g *Conn) Read(b []byte) (n int, err error) { - g.once.Do(g.initRequest) - if g.err != nil { - return 0, g.err + if err = g.Init(); err != nil { + return } if g.remain > 0 { @@ -88,7 +96,7 @@ func (g *Conn) Read(b []byte) (n int, err error) { n, err = io.ReadFull(g.br, b[:size]) g.remain -= n return - } else if g.response == nil { + } else if g.reader == nil { return 0, net.ErrClosed } @@ -139,6 +147,10 @@ func (g *Conn) Write(b []byte) (n int, err error) { err = g.err } + if g.flusher != nil { + g.flusher.Flush() + } + return len(b), err } @@ -158,6 +170,10 @@ func (g *Conn) WriteBuffer(buffer *buf.Buffer) error { err = g.err } + if g.flusher != nil { + g.flusher.Flush() + } + return err } @@ -167,15 +183,16 @@ func (g *Conn) FrontHeadroom() int { func (g *Conn) Close() error { g.close.Store(true) - if r := g.response; r != nil { - r.Body.Close() + if reader := g.reader; reader != nil { + reader.Close() } - return g.writer.Close() + if closer, ok := g.writer.(io.Closer); ok { + return closer.Close() + } + return nil } -func (g *Conn) LocalAddr() net.Addr { return g.transport.LocalAddr() } -func (g *Conn) RemoteAddr() net.Addr { return g.transport.RemoteAddr() } func (g *Conn) SetReadDeadline(t time.Time) error { return g.SetDeadline(t) } func (g *Conn) SetWriteDeadline(t time.Time) error { return g.SetDeadline(t) } @@ -200,6 +217,7 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, Fingerprint string, re return nil, err } wrap.remoteAddr = pconn.RemoteAddr() + wrap.localAddr = pconn.LocalAddr() if tlsConfig == nil { return pconn, nil @@ -286,13 +304,18 @@ func StreamGunWithTransport(transport *TransportWrap, cfg *Config) (net.Conn, er } conn := &Conn{ - request: request, - transport: transport, - writer: writer, - close: atomic.NewBool(false), + initFn: func() (io.ReadCloser, error) { + response, err := transport.RoundTrip(request) + if err != nil { + return nil, err + } + return response.Body, nil + }, + writer: writer, + netAddr: transport.netAddr, } - go conn.once.Do(conn.initRequest) + go conn.Init() return conn, nil } diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/gun/server.go b/clash-meta-android/core/src/foss/golang/clash/transport/gun/server.go new file mode 100644 index 0000000000..33fabc9822 --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/transport/gun/server.go @@ -0,0 +1,117 @@ +package gun + +import ( + "io" + "net" + "net/http" + "strings" + "sync" + "time" + + "github.com/metacubex/mihomo/common/buf" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" + + "golang.org/x/net/http2" + "golang.org/x/net/http2/h2c" +) + +const idleTimeout = 30 * time.Second + +type ServerOption struct { + ServiceName string + ConnHandler func(conn net.Conn) + HttpHandler http.Handler +} + +func NewServerHandler(options ServerOption) http.Handler { + path := "/" + options.ServiceName + "/Tun" + connHandler := options.ConnHandler + httpHandler := options.HttpHandler + if httpHandler == nil { + httpHandler = http.NewServeMux() + } + // using h2c.NewHandler to ensure we can work in plain http2 + // and some tls conn is not *tls.Conn (like *reality.Conn) + return h2c.NewHandler(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { + if request.URL.Path == path && + request.Method == http.MethodPost && + strings.HasPrefix(request.Header.Get("Content-Type"), "application/grpc") { + + writer.Header().Set("Content-Type", "application/grpc") + writer.Header().Set("TE", "trailers") + writer.WriteHeader(http.StatusOK) + + conn := &Conn{ + initFn: func() (io.ReadCloser, error) { + return request.Body, nil + }, + writer: writer, + flusher: writer.(http.Flusher), + } + if request.RemoteAddr != "" { + metadata := C.Metadata{} + if err := metadata.SetRemoteAddress(request.RemoteAddr); err == nil { + conn.remoteAddr = net.TCPAddrFromAddrPort(metadata.AddrPort()) + } + } + if addr, ok := request.Context().Value(http.LocalAddrContextKey).(net.Addr); ok { + conn.localAddr = addr + } + + wrapper := &h2ConnWrapper{ + // gun.Conn can't correct handle ReadDeadline + // so call N.NewDeadlineConn to add a safe wrapper + ExtendedConn: N.NewDeadlineConn(conn), + } + connHandler(wrapper) + wrapper.CloseWrapper() + + return + } + + httpHandler.ServeHTTP(writer, request) + }), &http2.Server{ + IdleTimeout: idleTimeout, + }) +} + +// h2ConnWrapper used to avoid "panic: Write called after Handler finished" for gun.Conn +type h2ConnWrapper struct { + N.ExtendedConn + access sync.Mutex + closed bool +} + +func (w *h2ConnWrapper) Write(p []byte) (n int, err error) { + w.access.Lock() + defer w.access.Unlock() + if w.closed { + return 0, net.ErrClosed + } + return w.ExtendedConn.Write(p) +} + +func (w *h2ConnWrapper) WriteBuffer(buffer *buf.Buffer) error { + w.access.Lock() + defer w.access.Unlock() + if w.closed { + return net.ErrClosed + } + return w.ExtendedConn.WriteBuffer(buffer) +} + +func (w *h2ConnWrapper) CloseWrapper() { + w.access.Lock() + defer w.access.Unlock() + w.closed = true +} + +func (w *h2ConnWrapper) Close() error { + w.CloseWrapper() + return w.ExtendedConn.Close() +} + +func (w *h2ConnWrapper) Upstream() any { + return w.ExtendedConn +} diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/gun/transport.go b/clash-meta-android/core/src/foss/golang/clash/transport/gun/transport.go index 12ccfd5c21..c74aec466c 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/gun/transport.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/gun/transport.go @@ -7,8 +7,7 @@ import ( type TransportWrap struct { *http2.Transport - remoteAddr net.Addr - localAddr net.Addr + netAddr } func (tw *TransportWrap) RemoteAddr() net.Addr { @@ -18,3 +17,16 @@ func (tw *TransportWrap) RemoteAddr() net.Addr { func (tw *TransportWrap) LocalAddr() net.Addr { return tw.localAddr } + +type netAddr struct { + remoteAddr net.Addr + localAddr net.Addr +} + +func (addr *netAddr) RemoteAddr() net.Addr { + return addr.remoteAddr +} + +func (addr *netAddr) LocalAddr() net.Addr { + return addr.localAddr +} diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/trojan/trojan.go b/clash-meta-android/core/src/foss/golang/clash/transport/trojan/trojan.go index c1ebb8da25..e500050238 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/trojan/trojan.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/trojan/trojan.go @@ -38,10 +38,9 @@ type Command = byte const ( CommandTCP byte = 1 CommandUDP byte = 3 + CommandMux byte = 0x7f - // deprecated XTLS commands, as souvenirs - commandXRD byte = 0xf0 // XTLS direct mode - commandXRO byte = 0xf1 // XTLS origin mode + KeyLength = 56 ) type Option struct { @@ -65,7 +64,7 @@ type WebsocketOption struct { type Trojan struct { option *Option - hexPassword []byte + hexPassword [KeyLength]byte } func (t *Trojan) StreamConn(ctx context.Context, conn net.Conn) (net.Conn, error) { @@ -152,7 +151,7 @@ func (t *Trojan) WriteHeader(w io.Writer, command Command, socks5Addr []byte) er buf := pool.GetBuffer() defer pool.PutBuffer(buf) - buf.Write(t.hexPassword) + buf.Write(t.hexPassword[:]) buf.Write(crlf) buf.WriteByte(command) @@ -245,7 +244,7 @@ func ReadPacket(r io.Reader, payload []byte) (net.Addr, int, int, error) { } func New(option *Option) *Trojan { - return &Trojan{option, hexSha224([]byte(option.Password))} + return &Trojan{option, Key(option.Password)} } var _ N.EnhancePacketConn = (*PacketConn)(nil) @@ -340,9 +339,12 @@ func (pc *PacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, er return } -func hexSha224(data []byte) []byte { - buf := make([]byte, 56) - hash := sha256.Sum224(data) - hex.Encode(buf, hash[:]) - return buf +func NewPacketConn(conn net.Conn) *PacketConn { + return &PacketConn{Conn: conn} +} + +func Key(password string) (key [56]byte) { + hash := sha256.Sum224([]byte(password)) + hex.Encode(key[:], hash[:]) + return } diff --git a/clash-meta-android/core/src/foss/golang/go.mod b/clash-meta-android/core/src/foss/golang/go.mod index 696fc5c479..ad74fcafb4 100644 --- a/clash-meta-android/core/src/foss/golang/go.mod +++ b/clash-meta-android/core/src/foss/golang/go.mod @@ -57,7 +57,7 @@ require ( github.com/metacubex/sing-shadowsocks v0.2.8 // indirect github.com/metacubex/sing-shadowsocks2 v0.2.2 // indirect github.com/metacubex/sing-tun v0.4.5 // indirect - github.com/metacubex/sing-vmess v0.1.14-0.20250203033000-f61322b3dbe3 // indirect + github.com/metacubex/sing-vmess v0.1.14-0.20250228002636-abc39e113b82 // indirect github.com/metacubex/sing-wireguard v0.0.0-20241126021510-0827d417b589 // indirect github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422 // indirect github.com/metacubex/utls v1.6.6 // indirect @@ -77,7 +77,7 @@ require ( github.com/sagernet/fswatch v0.1.1 // indirect github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect github.com/sagernet/nftables v0.3.0-beta.4 // indirect - github.com/sagernet/sing v0.5.1 // indirect + github.com/sagernet/sing v0.5.2 // indirect github.com/sagernet/sing-mux v0.2.1 // indirect github.com/sagernet/sing-shadowtls v0.1.5 // indirect github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect @@ -113,7 +113,7 @@ require ( lukechampine.com/blake3 v1.3.0 // indirect ) -replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20241121030428-33b6ebc52000 +replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20250228041610-d94509dc612a replace cfa => ../../main/golang diff --git a/clash-meta-android/core/src/foss/golang/go.sum b/clash-meta-android/core/src/foss/golang/go.sum index 09c3105c28..febaa65ca3 100644 --- a/clash-meta-android/core/src/foss/golang/go.sum +++ b/clash-meta-android/core/src/foss/golang/go.sum @@ -111,8 +111,8 @@ github.com/metacubex/randv2 v0.2.0 h1:uP38uBvV2SxYfLj53kuvAjbND4RUDfFJjwr4UigMiL github.com/metacubex/randv2 v0.2.0/go.mod h1:kFi2SzrQ5WuneuoLLCMkABtiBu6VRrMrWFqSPyj2cxY= github.com/metacubex/reality v0.0.0-20250219003814-74e8d7850629 h1:aHsYiTvubfgMa3JMTDY//hDXVvFWrHg6ARckR52ttZs= github.com/metacubex/reality v0.0.0-20250219003814-74e8d7850629/go.mod h1:TTeIOZLdGmzc07Oedn++vWUUfkZoXLF4sEMxWuhBFr8= -github.com/metacubex/sing v0.0.0-20241121030428-33b6ebc52000 h1:gUbMXcQXhXGj0vCpCVFTUyIH7TMpD1dpTcNv/MCS+ok= -github.com/metacubex/sing v0.0.0-20241121030428-33b6ebc52000/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= +github.com/metacubex/sing v0.0.0-20250228041610-d94509dc612a h1:xjPXdDTlIKq4U/KnKpoCtkxD03T8GimtQrvHy/3dN00= +github.com/metacubex/sing v0.0.0-20250228041610-d94509dc612a/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/metacubex/sing-quic v0.0.0-20250119013740-2a19cce83925 h1:UkPoRAnoBQMn7IK5qpoIV3OejU15q+rqel3NrbSCFKA= github.com/metacubex/sing-quic v0.0.0-20250119013740-2a19cce83925/go.mod h1:g7Mxj7b7zm7YVqD975mk/hSmrb0A0G4bVvIMr2MMzn8= github.com/metacubex/sing-shadowsocks v0.2.8 h1:wIhlaigswzjPw4hej75sEvWte3QR0+AJRafgwBHO5B4= @@ -121,8 +121,8 @@ github.com/metacubex/sing-shadowsocks2 v0.2.2 h1:eaf42uVx4Lr21S6MDYs0ZdTvGA0GEhD github.com/metacubex/sing-shadowsocks2 v0.2.2/go.mod h1:BhOug03a/RbI7y6hp6q+6ITM1dXjnLTmeWBHSTwvv2Q= github.com/metacubex/sing-tun v0.4.5 h1:kWSyQzuzHI40r50OFBczfWIDvMBMy1RIk+JsXeBPRB0= github.com/metacubex/sing-tun v0.4.5/go.mod h1:V0N4rr0dWPBEE20ESkTXdbtx2riQYcb6YtwC5w/9wl0= -github.com/metacubex/sing-vmess v0.1.14-0.20250203033000-f61322b3dbe3 h1:2kq6azIvsTjTnyw66xXDl5zMzIJqF7GTbvLpkroHssg= -github.com/metacubex/sing-vmess v0.1.14-0.20250203033000-f61322b3dbe3/go.mod h1:nE7Mdzj/QUDwgRi/8BASPtsxtIFZTHA4Yst5GgwbGCQ= +github.com/metacubex/sing-vmess v0.1.14-0.20250228002636-abc39e113b82 h1:zZp5uct9+/0Hb1jKGyqDjCU4/72t43rs7qOq3Rc9oU8= +github.com/metacubex/sing-vmess v0.1.14-0.20250228002636-abc39e113b82/go.mod h1:nE7Mdzj/QUDwgRi/8BASPtsxtIFZTHA4Yst5GgwbGCQ= github.com/metacubex/sing-wireguard v0.0.0-20241126021510-0827d417b589 h1:Z6bNy0HLTjx6BKIkV48sV/yia/GP8Bnyb5JQuGgSGzg= github.com/metacubex/sing-wireguard v0.0.0-20241126021510-0827d417b589/go.mod h1:4NclTLIZuk+QkHVCGrP87rHi/y8YjgPytxTgApJNMhc= github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422 h1:zGeQt3UyNydIVrMRB97AA5WsYEau/TyCnRtTf1yUmJY= diff --git a/clash-meta-android/core/src/main/golang/go.mod b/clash-meta-android/core/src/main/golang/go.mod index f3f69112f0..1274bab6ff 100644 --- a/clash-meta-android/core/src/main/golang/go.mod +++ b/clash-meta-android/core/src/main/golang/go.mod @@ -11,7 +11,7 @@ require ( replace github.com/metacubex/mihomo => ../../foss/golang/clash -replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20241121030428-33b6ebc52000 +replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20250228041610-d94509dc612a require ( github.com/3andne/restls-client-go v0.1.6 // indirect @@ -65,7 +65,7 @@ require ( github.com/metacubex/sing-shadowsocks v0.2.8 // indirect github.com/metacubex/sing-shadowsocks2 v0.2.2 // indirect github.com/metacubex/sing-tun v0.4.5 // indirect - github.com/metacubex/sing-vmess v0.1.14-0.20250203033000-f61322b3dbe3 // indirect + github.com/metacubex/sing-vmess v0.1.14-0.20250228002636-abc39e113b82 // indirect github.com/metacubex/sing-wireguard v0.0.0-20241126021510-0827d417b589 // indirect github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422 // indirect github.com/metacubex/utls v1.6.6 // indirect @@ -85,7 +85,7 @@ require ( github.com/sagernet/fswatch v0.1.1 // indirect github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect github.com/sagernet/nftables v0.3.0-beta.4 // indirect - github.com/sagernet/sing v0.5.1 // indirect + github.com/sagernet/sing v0.5.2 // indirect github.com/sagernet/sing-mux v0.2.1 // indirect github.com/sagernet/sing-shadowtls v0.1.5 // indirect github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect diff --git a/clash-meta-android/core/src/main/golang/go.sum b/clash-meta-android/core/src/main/golang/go.sum index e3627af5f9..5288bf6298 100644 --- a/clash-meta-android/core/src/main/golang/go.sum +++ b/clash-meta-android/core/src/main/golang/go.sum @@ -112,8 +112,8 @@ github.com/metacubex/randv2 v0.2.0 h1:uP38uBvV2SxYfLj53kuvAjbND4RUDfFJjwr4UigMiL github.com/metacubex/randv2 v0.2.0/go.mod h1:kFi2SzrQ5WuneuoLLCMkABtiBu6VRrMrWFqSPyj2cxY= github.com/metacubex/reality v0.0.0-20250219003814-74e8d7850629 h1:aHsYiTvubfgMa3JMTDY//hDXVvFWrHg6ARckR52ttZs= github.com/metacubex/reality v0.0.0-20250219003814-74e8d7850629/go.mod h1:TTeIOZLdGmzc07Oedn++vWUUfkZoXLF4sEMxWuhBFr8= -github.com/metacubex/sing v0.0.0-20241121030428-33b6ebc52000 h1:gUbMXcQXhXGj0vCpCVFTUyIH7TMpD1dpTcNv/MCS+ok= -github.com/metacubex/sing v0.0.0-20241121030428-33b6ebc52000/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= +github.com/metacubex/sing v0.0.0-20250228041610-d94509dc612a h1:xjPXdDTlIKq4U/KnKpoCtkxD03T8GimtQrvHy/3dN00= +github.com/metacubex/sing v0.0.0-20250228041610-d94509dc612a/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/metacubex/sing-quic v0.0.0-20250119013740-2a19cce83925 h1:UkPoRAnoBQMn7IK5qpoIV3OejU15q+rqel3NrbSCFKA= github.com/metacubex/sing-quic v0.0.0-20250119013740-2a19cce83925/go.mod h1:g7Mxj7b7zm7YVqD975mk/hSmrb0A0G4bVvIMr2MMzn8= github.com/metacubex/sing-shadowsocks v0.2.8 h1:wIhlaigswzjPw4hej75sEvWte3QR0+AJRafgwBHO5B4= @@ -122,8 +122,8 @@ github.com/metacubex/sing-shadowsocks2 v0.2.2 h1:eaf42uVx4Lr21S6MDYs0ZdTvGA0GEhD github.com/metacubex/sing-shadowsocks2 v0.2.2/go.mod h1:BhOug03a/RbI7y6hp6q+6ITM1dXjnLTmeWBHSTwvv2Q= github.com/metacubex/sing-tun v0.4.5 h1:kWSyQzuzHI40r50OFBczfWIDvMBMy1RIk+JsXeBPRB0= github.com/metacubex/sing-tun v0.4.5/go.mod h1:V0N4rr0dWPBEE20ESkTXdbtx2riQYcb6YtwC5w/9wl0= -github.com/metacubex/sing-vmess v0.1.14-0.20250203033000-f61322b3dbe3 h1:2kq6azIvsTjTnyw66xXDl5zMzIJqF7GTbvLpkroHssg= -github.com/metacubex/sing-vmess v0.1.14-0.20250203033000-f61322b3dbe3/go.mod h1:nE7Mdzj/QUDwgRi/8BASPtsxtIFZTHA4Yst5GgwbGCQ= +github.com/metacubex/sing-vmess v0.1.14-0.20250228002636-abc39e113b82 h1:zZp5uct9+/0Hb1jKGyqDjCU4/72t43rs7qOq3Rc9oU8= +github.com/metacubex/sing-vmess v0.1.14-0.20250228002636-abc39e113b82/go.mod h1:nE7Mdzj/QUDwgRi/8BASPtsxtIFZTHA4Yst5GgwbGCQ= github.com/metacubex/sing-wireguard v0.0.0-20241126021510-0827d417b589 h1:Z6bNy0HLTjx6BKIkV48sV/yia/GP8Bnyb5JQuGgSGzg= github.com/metacubex/sing-wireguard v0.0.0-20241126021510-0827d417b589/go.mod h1:4NclTLIZuk+QkHVCGrP87rHi/y8YjgPytxTgApJNMhc= github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422 h1:zGeQt3UyNydIVrMRB97AA5WsYEau/TyCnRtTf1yUmJY= diff --git a/clash-meta/.github/mihomo.service b/clash-meta/.github/mihomo.service index f34b6a6a84..a3793fe369 100644 --- a/clash-meta/.github/mihomo.service +++ b/clash-meta/.github/mihomo.service @@ -1,17 +1,17 @@ [Unit] Description=mihomo Daemon, Another Clash Kernel. -After=network.target NetworkManager.service systemd-networkd.service iwd.service +Documentation=https://wiki.metacubex.one +After=network.target nss-lookup.target network-online.target [Service] Type=simple -LimitNPROC=500 -LimitNOFILE=1000000 -CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_TIME CAP_SYS_PTRACE CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE -AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_TIME CAP_SYS_PTRACE CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE -Restart=always -ExecStartPre=/usr/bin/sleep 2s +CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH +AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH ExecStart=/usr/bin/mihomo -d /etc/mihomo ExecReload=/bin/kill -HUP $MAINPID +Restart=on-failure +RestartSec=10 +LimitNOFILE=infinity [Install] -WantedBy=multi-user.target \ No newline at end of file +WantedBy=multi-user.target diff --git a/clash-meta/.github/mihomo@.service b/clash-meta/.github/mihomo@.service new file mode 100644 index 0000000000..a3793fe369 --- /dev/null +++ b/clash-meta/.github/mihomo@.service @@ -0,0 +1,17 @@ +[Unit] +Description=mihomo Daemon, Another Clash Kernel. +Documentation=https://wiki.metacubex.one +After=network.target nss-lookup.target network-online.target + +[Service] +Type=simple +CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH +AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH +ExecStart=/usr/bin/mihomo -d /etc/mihomo +ExecReload=/bin/kill -HUP $MAINPID +Restart=on-failure +RestartSec=10 +LimitNOFILE=infinity + +[Install] +WantedBy=multi-user.target diff --git a/clash-meta/.github/workflows/build.yml b/clash-meta/.github/workflows/build.yml index ee1266b802..371065cf10 100644 --- a/clash-meta/.github/workflows/build.yml +++ b/clash-meta/.github/workflows/build.yml @@ -276,17 +276,20 @@ jobs: mkdir -p mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/DEBIAN mkdir -p mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/usr/bin - mkdir -p mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/etc/mihomo - mkdir -p mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/etc/systemd/system/ mkdir -p mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/usr/share/licenses/mihomo + mkdir -p mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/etc/mihomo + mkdir -p mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/lib/systemd/system - cp mihomo mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/usr/bin/mihomo + cp mihomo mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/usr/bin/ cp LICENSE mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/usr/share/licenses/mihomo/ - cp .github/mihomo.service mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/etc/systemd/system/ + cp .github/{mihomo.service,mihomo@.service} mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/lib/systemd/system/ cat > mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/etc/mihomo/config.yaml < mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/DEBIAN/conffiles < mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/DEBIAN/control < + github.event_name != 'pull_request' || + contains(github.event.pull_request.title, 'crate') runs-on: ${{ matrix.targets.os }} needs: lint steps: @@ -175,77 +178,103 @@ jobs: - name: Prepare sidecar and resources run: pnpm check - - name: Build Tauri - run: pnpm tauri build + - name: Prepare frontend + run: pnpm -r build env: NODE_OPTIONS: '--max_old_space_size=4096' - # 以后完善了新的测试套件后再添加 - # test_unit: - # name: Unit Test - # needs: lint - # # we want to run on the latest linux environment - # runs-on: ubuntu-latest - # # the steps our job runs **in order** - # steps: - # # checkout the code on the workflow runner - # - uses: actions/checkout@v4 + - name: Build Backend + run: cargo build --release --manifest-path backend/Cargo.toml - # # install system dependencies that Tauri needs to compile on Linux. - # # note the extra dependencies for `tauri-driver` to run which are: `webkit2gtk-driver` and `xvfb` - # - name: Tauri dependencies - # run: >- - # sudo apt-get update && - # sudo apt-get install -y - # libgtk-3-dev - # libayatana-appindicator3-dev - # libwebkit2gtk-4.0-dev - # webkit2gtk-driver - # xvfb + test_unit: + name: Unit Test + needs: lint + if: > + github.event_name != 'pull_request' || + contains(github.event.pull_request.title, 'crate') - # # install the latest Rust stable - # - name: Rust stable - # run: rustup toolchain install stable --profile minimal && rustup default stable - # - uses: Swatinem/rust-cache@v2 - # with: - # workspaces: "./backend/" - # prefix-key: "rust-stable" - # shared-key: "ci" - # save-if: ${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev' }} + # we want to run on the latest linux environment + strategy: + matrix: + os: + - ubuntu-latest + - macos-latest + - windows-latest + fail-fast: false + runs-on: ${{ matrix.os }} - # - name: Install Node.js - # uses: actions/setup-node@v4 - # with: - # node-version: 20 + # the steps our job runs **in order** + steps: + # checkout the code on the workflow runner + - uses: actions/checkout@v4 - # - uses: pnpm/action-setup@v2 - # name: Install pnpm - # with: - # version: 8 - # run_install: false + # install system dependencies that Tauri needs to compile on Linux. + # note the extra dependencies for `tauri-driver` to run which are: `webkit2gtk-driver` and `xvfb` + - name: Tauri dependencies + if: startsWith(matrix.os, 'ubuntu-') + run: >- + sudo apt-get update && + sudo apt-get install -y + libgtk-3-dev + libayatana-appindicator3-dev + libwebkit2gtk-4.1-dev + librsvg2-dev + libxdo-dev + webkit2gtk-driver + xvfb - # - name: Get pnpm store directory - # shell: bash - # run: | - # echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + - uses: maxim-lobanov/setup-xcode@v1 + if: startsWith(matrix.os, 'macos-') + with: + xcode-version: 'latest-stable' - # - uses: actions/cache@v4 - # name: Setup pnpm cache - # with: - # path: ${{ env.STORE_PATH }} - # key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} - # restore-keys: | - # ${{ runner.os }}-pnpm-store- + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: 22 - # - name: Install dependencies - # run: pnpm install - # - name: Prepare fronend - # run: pnpm web:build # Build frontend - # - name: Prepare sidecar and resources - # run: pnpm check - # - name: Test - # # run: pnpm test:unit && pnpm test:backend - # run: pnpm test:backend + - uses: actions/cache@v4 + name: Cache Rust dependencies + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + + - uses: pnpm/action-setup@v4 + name: Install pnpm + with: + run_install: false + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v4 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + run: pnpm install --no-frozen-lockfile + + - name: Prepare sidecar and resources + run: pnpm check + + - name: Prepare frontend + run: pnpm -r build + env: + NODE_OPTIONS: '--max_old_space_size=4096' + + - name: Test + run: pnpm test # test_e2e: # # the display name of the test job diff --git a/clash-nyanpasu/.github/workflows/deps-build-macos.yaml b/clash-nyanpasu/.github/workflows/deps-build-macos.yaml index fa8c500f93..05c827d8b6 100644 --- a/clash-nyanpasu/.github/workflows/deps-build-macos.yaml +++ b/clash-nyanpasu/.github/workflows/deps-build-macos.yaml @@ -41,7 +41,7 @@ on: jobs: build: - runs-on: 'macos-13' + runs-on: macos-latest steps: - name: Checkout repository @@ -49,7 +49,7 @@ jobs: - uses: maxim-lobanov/setup-xcode@v1 with: - xcode-version: 14 + xcode-version: 15 - name: install Rust stable run: | @@ -69,6 +69,9 @@ jobs: uses: actions/setup-node@v4 with: node-version: latest + - uses: denoland/setup-deno@v2 + with: + deno-version: v2.x - uses: pnpm/action-setup@v4 name: Install pnpm @@ -114,15 +117,12 @@ jobs: NODE_OPTIONS: '--max_old_space_size=4096' - name: Upload to release - shell: bash run: | - find ./backend/target \( -name "*.dmg" -o -name "*.sig" -o -name "*.tar.gz" \) | while read file; do - echo "Uploading $file to release" - gh release upload ${{ inputs.tag }} "$file" --clobber - done + deno run -A scripts/deno/upload-macos-updater.ts env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TAG: ${{ inputs.tag }} + TARGET_ARCH: ${{ inputs.aarch64 == true && 'aarch64' || 'x86_64' }} - name: Upload to Github Artifact uses: actions/upload-artifact@v4 diff --git a/clash-nyanpasu/backend/Cargo.lock b/clash-nyanpasu/backend/Cargo.lock index 9a8ccc2eba..371992e63e 100644 --- a/clash-nyanpasu/backend/Cargo.lock +++ b/clash-nyanpasu/backend/Cargo.lock @@ -767,9 +767,9 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.86" +version = "0.1.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d" +checksum = "d556ec1359574147ec0c4fc5eb525f3f23263a592b1a9c07e0a75b427de55c97" dependencies = [ "proc-macro2", "quote", @@ -810,6 +810,15 @@ dependencies = [ "system-deps", ] +[[package]] +name = "atomic-polyfill" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" +dependencies = [ + "critical-section", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -884,7 +893,7 @@ version = "0.5.0" source = "git+https://github.com/libnyanpasu/auto-launch.git#729d5429dd689067047489af4a0a32f7013854c8" dependencies = [ "dirs 5.0.1", - "thiserror 2.0.11", + "thiserror 2.0.12", "windows-registry 0.3.0", "windows-result 0.2.0", ] @@ -1297,7 +1306,7 @@ dependencies = [ "static_assertions", "tap", "thin-vec", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", ] @@ -1384,6 +1393,8 @@ dependencies = [ name = "boa_utils" version = "0.1.0" dependencies = [ + "anyhow", + "async-fs", "boa_engine", "boa_gc", "boa_parser", @@ -1392,8 +1403,13 @@ dependencies = [ "indoc", "isahc", "log", + "mime", + "postcard", "rustc-hash 2.1.1", + "serde", + "serde_json", "smol", + "tempfile", "test-log", "textwrap", "tracing", @@ -1631,7 +1647,7 @@ dependencies = [ "semver 1.0.25", "serde", "serde_json", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -1910,7 +1926,7 @@ dependencies = [ "chrono", "clap", "colored", - "convert_case 0.7.1", + "convert_case 0.8.0", "ctrlc", "dashmap 6.1.0", "deelevate", @@ -1999,7 +2015,7 @@ dependencies = [ "tauri-specta", "tempfile", "test-log", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "timeago", "tokio", @@ -2018,7 +2034,7 @@ dependencies = [ "webview2-com", "which 7.0.2", "whoami", - "window-vibrancy 0.5.3", + "window-vibrancy", "windows-core 0.60.1", "windows-registry 0.5.0", "windows-sys 0.59.0", @@ -2036,6 +2052,12 @@ dependencies = [ "error-code", ] +[[package]] +name = "cobs" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" + [[package]] name = "codespan-reporting" version = "0.11.1" @@ -2130,9 +2152,9 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] name = "convert_case" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7" +checksum = "baaaa0ecca5b51987b9423ccdc971514dd8b0bb7b4060b983d3664dad3f1f89f" dependencies = [ "unicode-segmentation", ] @@ -2279,6 +2301,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + [[package]] name = "cron_clock" version = "0.8.0" @@ -2743,7 +2771,7 @@ version = "0.1.0" source = "git+https://github.com/libnyanpasu/nyanpasu-utils.git#757e46139a3710fb26a89724e24cdb7f2fe83885" dependencies = [ "dirs 6.0.0", - "thiserror 2.0.11", + "thiserror 2.0.12", "tracing", "windows 0.59.0", ] @@ -2769,7 +2797,7 @@ dependencies = [ "objc2-foundation 0.3.0", "scopeguard", "smithay-client-toolkit", - "thiserror 2.0.11", + "thiserror 2.0.12", "widestring 1.1.0", "windows 0.59.0", "xcb", @@ -3086,6 +3114,18 @@ version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + [[package]] name = "ena" version = "0.14.3" @@ -4057,7 +4097,7 @@ dependencies = [ "objc2-app-kit 0.3.0", "once_cell", "serde", - "thiserror 2.0.11", + "thiserror 2.0.12", "windows-sys 0.59.0", "x11-dl", ] @@ -4331,6 +4371,15 @@ dependencies = [ "serde_json", ] +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + [[package]] name = "hash32" version = "0.3.1" @@ -4370,13 +4419,27 @@ dependencies = [ "foldhash", ] +[[package]] +name = "heapless" +version = "0.7.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" +dependencies = [ + "atomic-polyfill", + "hash32 0.2.1", + "rustc_version", + "serde", + "spin", + "stable_deref_trait", +] + [[package]] name = "heapless" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" dependencies = [ - "hash32", + "hash32 0.3.1", "stable_deref_trait", ] @@ -5938,7 +6001,7 @@ dependencies = [ "once_cell", "png", "serde", - "thiserror 2.0.11", + "thiserror 2.0.12", "windows-sys 0.59.0", ] @@ -5977,7 +6040,7 @@ dependencies = [ "spirv", "strum 0.26.3", "termcolor", - "thiserror 2.0.11", + "thiserror 2.0.12", "unicode-xid", ] @@ -6443,7 +6506,7 @@ dependencies = [ "serde_json", "simd-json", "specta", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tokio-util", "tracing", @@ -6478,7 +6541,7 @@ dependencies = [ "shared_child", "specta", "sysinfo", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tracing", "tracing-attributes", @@ -7096,7 +7159,7 @@ dependencies = [ "objc2-osa-kit", "serde", "serde_json", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -7426,7 +7489,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" dependencies = [ "memchr", - "thiserror 2.0.11", + "thiserror 2.0.12", "ucd-trie", ] @@ -7760,6 +7823,19 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" +[[package]] +name = "postcard" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "170a2601f67cc9dba8edd8c4870b15f71a6a2dc196daec8c83f72b59dff628a8" +dependencies = [ + "cobs", + "embedded-io 0.4.0", + "embedded-io 0.6.1", + "heapless 0.7.17", + "serde", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -7861,9 +7937,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.93" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" dependencies = [ "unicode-ident", ] @@ -8011,7 +8087,7 @@ dependencies = [ "rustc-hash 2.1.1", "rustls", "socket2", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tracing", ] @@ -8030,7 +8106,7 @@ dependencies = [ "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.11", + "thiserror 2.0.12", "tinyvec", "tracing", "web-time", @@ -8333,7 +8409,7 @@ checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" dependencies = [ "getrandom 0.2.15", "libredox", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -8704,7 +8780,7 @@ version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "421400d13ccfd26dfa5858199c30a5d76f9c54e0dba7575273025b43c5175dbb" dependencies = [ - "heapless", + "heapless 0.8.0", "num-traits", "smallvec", ] @@ -9460,7 +9536,7 @@ checksum = "297f631f50729c8c99b84667867963997ec0b50f32b2a7dbcab828ef0541e8bb" dependencies = [ "num-bigint", "num-traits", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", ] @@ -9754,6 +9830,9 @@ name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] [[package]] name = "spirv" @@ -10315,14 +10394,14 @@ dependencies = [ "tauri-runtime", "tauri-runtime-wry", "tauri-utils", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tray-icon", "url", "urlpattern", "webkit2gtk", "webview2-com", - "window-vibrancy 0.6.0", + "window-vibrancy", "windows 0.60.0", ] @@ -10368,7 +10447,7 @@ dependencies = [ "sha2 0.10.8", "syn 2.0.98", "tauri-utils", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "url", "uuid", @@ -10418,7 +10497,7 @@ dependencies = [ "serde_json", "tauri", "tauri-plugin", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -10450,7 +10529,7 @@ dependencies = [ "tauri", "tauri-plugin", "tauri-plugin-fs", - "thiserror 2.0.11", + "thiserror 2.0.12", "url", ] @@ -10471,7 +10550,7 @@ dependencies = [ "tauri", "tauri-plugin", "tauri-utils", - "thiserror 2.0.11", + "thiserror 2.0.12", "toml", "url", "uuid", @@ -10489,7 +10568,7 @@ dependencies = [ "serde_json", "tauri", "tauri-plugin", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -10506,7 +10585,7 @@ dependencies = [ "serde_repr", "tauri", "tauri-plugin", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "url", ] @@ -10526,7 +10605,7 @@ dependencies = [ "sys-locale", "tauri", "tauri-plugin", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -10556,7 +10635,7 @@ dependencies = [ "shared_child", "tauri", "tauri-plugin", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", ] @@ -10583,7 +10662,7 @@ dependencies = [ "tauri", "tauri-plugin", "tempfile", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", "url", @@ -10605,7 +10684,7 @@ dependencies = [ "serde", "serde_json", "tauri-utils", - "thiserror 2.0.11", + "thiserror 2.0.12", "url", "windows 0.60.0", ] @@ -10650,7 +10729,7 @@ dependencies = [ "specta-typescript", "tauri", "tauri-specta-macros", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -10694,7 +10773,7 @@ dependencies = [ "serde_json", "serde_with", "swift-rs", - "thiserror 2.0.11", + "thiserror 2.0.12", "toml", "url", "urlpattern", @@ -10878,11 +10957,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.11" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ - "thiserror-impl 2.0.11", + "thiserror-impl 2.0.12", ] [[package]] @@ -10898,9 +10977,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.11" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", @@ -11348,7 +11427,7 @@ dependencies = [ "once_cell", "png", "serde", - "thiserror 2.0.11", + "thiserror 2.0.12", "windows-sys 0.59.0", ] @@ -11429,7 +11508,7 @@ dependencies = [ "log", "rand 0.9.0", "sha1", - "thiserror 2.0.11", + "thiserror 2.0.12", "utf-8", ] @@ -12269,7 +12348,7 @@ version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfb27fccd3c27f68e9a6af1bcf48c2d82534b8675b83608a4d81446d095a17ac" dependencies = [ - "thiserror 2.0.11", + "thiserror 2.0.12", "windows 0.60.0", "windows-core 0.60.1", ] @@ -12325,7 +12404,7 @@ dependencies = [ "raw-window-handle", "rustc-hash 1.1.0", "smallvec", - "thiserror 2.0.11", + "thiserror 2.0.12", "wgpu-hal", "wgpu-types", ] @@ -12364,7 +12443,7 @@ dependencies = [ "renderdoc-sys", "rustc-hash 1.1.0", "smallvec", - "thiserror 2.0.11", + "thiserror 2.0.12", "wasm-bindgen", "web-sys", "wgpu-types", @@ -12461,20 +12540,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "window-vibrancy" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "831ad7678290beae36be6f9fad9234139c7f00f3b536347de7745621716be82d" -dependencies = [ - "objc2 0.5.2", - "objc2-app-kit 0.2.2", - "objc2-foundation 0.2.2", - "raw-window-handle", - "windows-sys 0.59.0", - "windows-version", -] - [[package]] name = "window-vibrancy" version = "0.6.0" @@ -13282,7 +13347,7 @@ dependencies = [ "sha2 0.10.8", "soup3", "tao-macros", - "thiserror 2.0.11", + "thiserror 2.0.12", "url", "webkit2gtk", "webkit2gtk-sys", @@ -13757,7 +13822,7 @@ dependencies = [ "pbkdf2", "rand 0.8.5", "sha1", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "zeroize", "zopfli", diff --git a/clash-nyanpasu/backend/Cargo.toml b/clash-nyanpasu/backend/Cargo.toml index 66df15dccf..6207f30689 100644 --- a/clash-nyanpasu/backend/Cargo.toml +++ b/clash-nyanpasu/backend/Cargo.toml @@ -11,7 +11,7 @@ authors = ["zzzgydi", "keiko233"] [workspace.dependencies] thiserror = "2" tracing = "0.1" -boa_engine = { version = "0.20" } +boa_engine = { version = "0.20", features = ["annex-b"] } [profile.release] panic = "unwind" diff --git a/clash-nyanpasu/backend/boa_utils/Cargo.toml b/clash-nyanpasu/backend/boa_utils/Cargo.toml index 7daf138fd8..dd721d1eab 100644 --- a/clash-nyanpasu/backend/boa_utils/Cargo.toml +++ b/clash-nyanpasu/backend/boa_utils/Cargo.toml @@ -6,11 +6,14 @@ edition.workspace = true license.workspace = true authors.workspace = true +[lib] +doctest = false + [dependencies] rustc-hash = { version = "2", features = ["std"] } -boa_engine.workspace = true +boa_engine = { workspace = true, features = ["annex-b"] } boa_gc = { version = "0.20" } -boa_parser = { version = "0.20" } +boa_parser = { version = "0.20", features = ["annex-b"] } isahc = "1.7" futures-util = "0.3" futures-concurrency = "7" @@ -18,8 +21,19 @@ smol = "2" tracing = "0.1" url = "2" log = "0.4" +anyhow = "1.0" + +# for cacheing +mime = "0.3.17" +async-fs = "2.1.2" + +# for encoding/decoding +serde = { version = "1.0", features = ["derive"] } +postcard = { version = "1.1.1", features = ["use-std"] } +serde_json = { version = "1.0", features = ["preserve_order"] } [dev-dependencies] indoc = "2" textwrap = "0.16" test-log = "0.2" +tempfile = "3.17" diff --git a/clash-nyanpasu/backend/boa_utils/src/console/mod.rs b/clash-nyanpasu/backend/boa_utils/src/console/mod.rs index ef439ee3ab..88cacba9f1 100644 --- a/clash-nyanpasu/backend/boa_utils/src/console/mod.rs +++ b/clash-nyanpasu/backend/boa_utils/src/console/mod.rs @@ -15,20 +15,14 @@ mod tests; use boa_engine::{ - Context, JsArgs, JsData, JsResult, JsStr, JsString, js_str, js_string, + Context, JsArgs, JsData, JsError, JsResult, JsStr, JsString, js_str, js_string, native_function::NativeFunction, object::{JsObject, ObjectInitializer}, value::{JsValue, Numeric}, }; use boa_gc::{Finalize, Trace}; use rustc_hash::FxHashMap; -use std::{ - cell::RefCell, - collections::hash_map::Entry, - rc::Rc, - sync::{Arc, Mutex, OnceLock}, - time::SystemTime, -}; +use std::{cell::RefCell, collections::hash_map::Entry, rc::Rc, sync::Arc, time::SystemTime}; /// This represents the different types of log messages. #[derive(Debug)] @@ -54,38 +48,37 @@ fn logger(msg: LogMessage, console_state: &Console) { } pub trait Logger { - fn log(&self, msg: LogMessage, console_state: &Console); + type Item; + fn log(&mut self, msg: LogMessage, console_state: &Console); + fn take(&mut self) -> Vec; } -trait LoggerBox = Logger + Sync + Send + 'static; +pub trait LoggerBox = Logger + Sync + Send + 'static; struct ConsoleLogger; impl Logger for ConsoleLogger { - fn log(&self, msg: LogMessage, console_state: &Console) { + type Item = LogMessage; + fn log(&mut self, msg: LogMessage, console_state: &Console) { logger(msg, console_state); } -} - -pub static LOGGER: OnceLock>> = OnceLock::new(); - -fn default_logger() -> Mutex> { - Mutex::new(Arc::new(ConsoleLogger)) -} - -impl Logger for OnceLock>> { - fn log(&self, msg: LogMessage, console_state: &Console) { - let guard = self.get_or_init(default_logger); - guard - .lock() - .expect("failed to lock") - .log(msg, console_state); + fn take(&mut self) -> Vec { + vec![] } } -pub fn set_logger(logger: Arc) { - let guard = LOGGER.get_or_init(default_logger); - *guard.lock().expect("failed to lock") = logger; +thread_local! { + static LOGGER: RefCell> = RefCell::new(Box::new(ConsoleLogger)); +} + +pub fn inspect_logger(f: impl FnOnce(&mut dyn LoggerBox) -> R) -> R { + LOGGER.with(|cell| f(cell.borrow_mut().as_mut())) +} + +pub fn set_logger(logger: Box) { + LOGGER.with(|cell| { + *cell.borrow_mut() = logger; + }); } /// This represents the `console` formatter. @@ -323,7 +316,12 @@ impl Console { args[0] = JsValue::new(concat); } - LOGGER.log(LogMessage::Error(formatter(&args, context)?), console); + LOGGER.with(|logger| { + logger + .borrow_mut() + .log(LogMessage::Error(formatter(&args, context)?), console); + Ok::<_, JsError>(()) + })?; } Ok(JsValue::undefined()) @@ -361,7 +359,12 @@ impl Console { console: &Self, context: &mut Context, ) -> JsResult { - LOGGER.log(LogMessage::Log(formatter(args, context)?), console); + LOGGER.with(|logger| { + logger + .borrow_mut() + .log(LogMessage::Log(formatter(args, context)?), console); + Ok::<_, JsError>(()) + })?; Ok(JsValue::undefined()) } @@ -381,7 +384,12 @@ impl Console { console: &Self, context: &mut Context, ) -> JsResult { - LOGGER.log(LogMessage::Error(formatter(args, context)?), console); + LOGGER.with(|logger| { + logger + .borrow_mut() + .log(LogMessage::Error(formatter(args, context)?), console); + Ok::<_, JsError>(()) + })?; Ok(JsValue::undefined()) } @@ -401,7 +409,12 @@ impl Console { console: &Self, context: &mut Context, ) -> JsResult { - LOGGER.log(LogMessage::Info(formatter(args, context)?), console); + LOGGER.with(|logger| { + logger + .borrow_mut() + .log(LogMessage::Info(formatter(args, context)?), console); + Ok::<_, JsError>(()) + })?; Ok(JsValue::undefined()) } @@ -421,7 +434,12 @@ impl Console { console: &Self, context: &mut Context, ) -> JsResult { - LOGGER.log(LogMessage::Log(formatter(args, context)?), console); + LOGGER.with(|logger| { + logger + .borrow_mut() + .log(LogMessage::Log(formatter(args, context)?), console); + Ok::<_, JsError>(()) + })?; Ok(JsValue::undefined()) } @@ -442,7 +460,12 @@ impl Console { context: &mut Context, ) -> JsResult { if !args.is_empty() { - LOGGER.log(LogMessage::Log(formatter(args, context)?), console); + LOGGER.with(|logger| { + logger + .borrow_mut() + .log(LogMessage::Log(formatter(args, context)?), console); + Ok::<_, JsError>(()) + })?; } let stack_trace_dump = context @@ -453,7 +476,12 @@ impl Console { .map(JsString::to_std_string_escaped) .collect::>() .join("\n"); - LOGGER.log(LogMessage::Log(stack_trace_dump), console); + LOGGER.with(|logger| { + logger + .borrow_mut() + .log(LogMessage::Log(stack_trace_dump), console); + Ok::<_, JsError>(()) + })?; Ok(JsValue::undefined()) } @@ -474,7 +502,12 @@ impl Console { console: &Self, context: &mut Context, ) -> JsResult { - LOGGER.log(LogMessage::Warn(formatter(args, context)?), console); + LOGGER.with(|logger| { + logger + .borrow_mut() + .log(LogMessage::Warn(formatter(args, context)?), console); + Ok::<_, JsError>(()) + })?; Ok(JsValue::undefined()) } @@ -503,7 +536,12 @@ impl Console { let c = console.count_map.entry(label).or_insert(0); *c += 1; - LOGGER.log(LogMessage::Info(format!("{msg} {c}")), console); + let msg = format!("{msg} {c}"); + + LOGGER.with(|logger| { + logger.borrow_mut().log(LogMessage::Info(msg), console); + Ok::<_, JsError>(()) + })?; Ok(JsValue::undefined()) } @@ -620,7 +658,9 @@ impl Console { for msg in args.iter().skip(1) { concat = concat + " " + &msg.display().to_string(); } - LOGGER.log(LogMessage::Log(concat), console); + LOGGER.with(|logger| { + logger.borrow_mut().log(LogMessage::Log(concat), console); + }); }, ); @@ -692,7 +732,12 @@ impl Console { ) -> JsResult { let group_label = formatter(args, context)?; - LOGGER.log(LogMessage::Info(format!("group: {group_label}")), console); + LOGGER.with(|logger| { + logger + .borrow_mut() + .log(LogMessage::Info(format!("group: {group_label}")), console); + Ok::<_, JsError>(()) + })?; console.groups.push(group_label); Ok(JsValue::undefined()) diff --git a/clash-nyanpasu/backend/boa_utils/src/lib.rs b/clash-nyanpasu/backend/boa_utils/src/lib.rs index 7e3a4d6748..ba542e3375 100644 --- a/clash-nyanpasu/backend/boa_utils/src/lib.rs +++ b/clash-nyanpasu/backend/boa_utils/src/lib.rs @@ -1,6 +1,7 @@ #![feature(trait_alias)] #![feature(auto_traits)] #![feature(negative_impls)] +#![feature(let_chains)] //! Boa's **boa_runtime** crate contains an example runtime and basic runtime features and //! functionality for the `boa_engine` crate for runtime implementors. @@ -9,7 +10,7 @@ //! //! 1. Add **boa_runtime** as a dependency to your project along with **boa_engine**. //! -//! ``` +//! ```no_run //! use boa_engine::{js_string, property::Attribute, Context, Source}; //! use boa_runtime::Console; //! @@ -58,7 +59,7 @@ mod console; pub mod module; #[doc(inline)] pub use console::Console; -pub use console::{LogMessage, Logger, set_logger}; +pub use console::{LogMessage, Logger, LoggerBox, inspect_logger, set_logger}; #[cfg(test)] pub(crate) mod test { diff --git a/clash-nyanpasu/backend/boa_utils/src/module/http.rs b/clash-nyanpasu/backend/boa_utils/src/module/http.rs index 3dd662819f..fd1bab833e 100644 --- a/clash-nyanpasu/backend/boa_utils/src/module/http.rs +++ b/clash-nyanpasu/backend/boa_utils/src/module/http.rs @@ -1,14 +1,15 @@ use std::{ cell::{Cell, RefCell}, collections::VecDeque, - rc::Rc, + path::PathBuf, + str::FromStr, + time::{Duration, SystemTime}, }; +use async_fs::create_dir_all; use boa_engine::{ Context, JsNativeError, JsResult, JsString, JsValue, Module, - builtins::promise::PromiseState, job::{FutureJob, JobQueue, NativeJob}, - js_string, module::ModuleLoader, }; use boa_parser::Source; @@ -17,13 +18,94 @@ use isahc::{ AsyncReadResponseExt, Request, RequestExt, config::{Configurable, RedirectPolicy}, }; +use mime::Mime; use smol::{LocalExecutor, future}; +use url::Url; // Most of the boilerplate is taken from the `futures.rs` example. // This file only explains what is exclusive of async module loading. #[derive(Debug, Default)] -pub struct HttpModuleLoader; +pub struct HttpModuleLoader { + cache_dir: PathBuf, + max_age: Duration, +} + +#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)] +pub struct CachedItem { + pub mime: String, + /// raw string content + /// We have no plan for now to support binary content, + /// so we just use `String` to store the content. + pub content: String, +} + +impl HttpModuleLoader { + pub fn new(cache_dir: PathBuf, max_age: Duration) -> Self { + Self { cache_dir, max_age } + } + + fn mapping_cache_dir(&self, url: &url::Url) -> PathBuf { + let mut buf = self.cache_dir.clone(); + let host = match url.host() { + Some(host) => host.to_string().replace('.', "--"), + None => "unknown".to_string(), + }; + let port = match url.port() { + Some(port) => format!("__{port}"), + None => "".to_string(), + }; + buf.push(format!("{}_{}{}", url.scheme(), host, port)); + buf.push(url.path().replace('/', "_").replace(".", "--")); + buf + } + + #[tracing::instrument(skip(finish_load, context))] + fn handle_cached_item( + item: CachedItem, + finish_load: Box, &mut Context)>, + context: &mut Context, + ) { + let Ok(mime) = Mime::from_str(item.mime.as_str()) else { + log::error!("failed to parse mime type `{}`", item.mime); + finish_load( + Err(JsNativeError::typ() + .with_message("failed to parse mime type") + .into()), + context, + ); + return; + }; + let source_str = match (mime.type_(), mime.subtype()) { + (mime::APPLICATION, mime::JAVASCRIPT) => item.content.clone(), + (mime::APPLICATION, mime::JSON) => { + format!("export default {};", item.content) + } + _ => { + let Ok(escaped_str) = serde_json::to_string(&item.content) else { + log::error!("failed to serialize content."); + finish_load( + Err(JsNativeError::typ() + .with_message("failed to serialize content") + .into()), + context, + ); + return; + }; + format!("export const text = {escaped_str};") + } + }; + + // Could also add a path if needed. + let source = Source::from_bytes(source_str.as_bytes()); + + let module = Module::parse(source, None, context); + // TODO: rm cache or create cache after judge module is ok + + // We don't do any error handling, `finish_load` takes care of that for us. + finish_load(module, context); + } +} impl ModuleLoader for HttpModuleLoader { fn load_imported_module( @@ -34,30 +116,119 @@ impl ModuleLoader for HttpModuleLoader { context: &mut Context, ) { let url = specifier.to_std_string_escaped(); + let url = Url::from_str(&url).expect("invalid url"); // SAFETY: `url` is a valid URL, if it's not, its caller side issue + let cache_path = self.mapping_cache_dir(&url); + let parent_dir = match cache_path.parent() { + Some(parent) => parent.to_path_buf(), + None => { + log::error!("failed to get parent directory for `{url}`"); + finish_load( + Err(JsNativeError::typ() + .with_message(format!( + "failed to get cache parent directory for `{url}`; path: `{}`", + cache_path.display() + )) + .into()), + context, + ); + return; + } + }; + let max_age = self.max_age; let fetch = async move { + log::debug!("checking cache for `{url}`..."); + + let now = SystemTime::now(); + let should_use_cached_content = match async_fs::metadata(&cache_path).await { + Ok(metadata) + if metadata + .modified() + .is_ok_and(|modified| modified > now - max_age) => + { + true + } + Err(err) => { + // create dir if not exists + if err.kind() == std::io::ErrorKind::NotFound + && let Err(e) = async_fs::metadata(&parent_dir).await + && e.kind() == std::io::ErrorKind::NotFound + { + if let Err(err) = create_dir_all(parent_dir).await { + log::error!( + "failed to create cache directory for `{url}`; path: `{}`. error: `{}`", + cache_path.display(), + err + ); + } + } + false + } + _ => false, + }; + // Adding some prints to show the non-deterministic nature of the async fetches. // Try to run the example several times to see how sometimes the fetches start in order // but finish in disorder. - log::debug!("fetching `{url}`..."); - // This could also retry fetching in case there's an error while requesting the module. - let body: Result<_, isahc::Error> = async { - let mut response = Request::get(&url) - .redirect_policy(RedirectPolicy::Limit(5)) - .body(())? - .send_async() - .await?; - Ok(response.text().await?) + // This could also retry fetching in case there's an error while requesting the module. + let item: anyhow::Result = if should_use_cached_content { + async { + log::debug!("fetching `{url}` from cache..."); + let item = async_fs::read(&cache_path).await?; + let item = postcard::from_bytes(&item)?; + log::debug!("finished fetching `{url}` from cache"); + Ok(item) + } + .await + } else { + async { + log::debug!("fetching `{url}`..."); + let mut response = Request::get(url.as_str()) + .redirect_policy(RedirectPolicy::Limit(5)) + .body(())? + .send_async() + .await?; + + let mime = response + .headers() + .get("content-type") + .and_then(|v| v.to_str().ok()) + .map(|v| v.to_string()) + .unwrap_or(mime::TEXT_PLAIN.to_string()); + let body = response.text().await?; + + log::debug!("finished fetching `{url}`"); + Ok(CachedItem { + mime, + content: body, + }) + } + .await + }; + + if let Ok(item) = &item { + match postcard::to_stdvec(&item) { + Ok(item) => { + if let Err(err) = async_fs::write(&cache_path, &item).await { + log::error!( + "failed to write cache for `{url}`; path: `{}`. error: `{}`", + cache_path.display(), + err + ); + } + } + Err(err) => { + log::error!("failed to serialize content: {err}"); + } + } } - .await; - log::debug!("finished fetching `{url}`"); // Since the async context cannot take the `context` by ref, we have to continue // parsing inside a new `NativeJob` that will be enqueued into the promise job queue. NativeJob::new(move |context| -> JsResult { - let body = match body { - Ok(body) => body, + let item = match item { + Ok(item) => item, Err(err) => { // On error we always call `finish_load` to notify the load promise about the // error. @@ -70,15 +241,7 @@ impl ModuleLoader for HttpModuleLoader { return Ok(JsValue::undefined()); } }; - - // Could also add a path if needed. - let source = Source::from_bytes(body.as_bytes()); - - let module = Module::parse(source, None, context); - - // We don't do any error handling, `finish_load` takes care of that for us. - finish_load(module, context); - + Self::handle_cached_item(item, finish_load, context); // Also needed to match `NativeJob::new`. Ok(JsValue::undefined()) }) @@ -94,6 +257,9 @@ impl ModuleLoader for HttpModuleLoader { #[test] fn test_http_module_loader() -> JsResult<()> { + use boa_engine::{builtins::promise::PromiseState, js_string}; + use std::rc::Rc; + let temp_dir = tempfile::tempdir().unwrap(); // A simple snippet that imports modules from the web instead of the file system. const SRC: &str = r#" import YAML from 'https://esm.run/yaml@2.3.4'; @@ -120,7 +286,10 @@ fn test_http_module_loader() -> JsResult<()> { let context = &mut Context::builder() .job_queue(queue) // NEW: sets the context module loader to our custom loader - .module_loader(Rc::new(HttpModuleLoader)) + .module_loader(Rc::new(HttpModuleLoader::new( + temp_dir.path().to_path_buf(), + Duration::from_secs(10), + ))) .build()?; let module = Module::parse(Source::from_bytes(SRC.as_bytes()), None, context)?; diff --git a/clash-nyanpasu/backend/tauri-plugin-deep-link/Cargo.toml b/clash-nyanpasu/backend/tauri-plugin-deep-link/Cargo.toml index 8cde96433e..ec8ad39607 100644 --- a/clash-nyanpasu/backend/tauri-plugin-deep-link/Cargo.toml +++ b/clash-nyanpasu/backend/tauri-plugin-deep-link/Cargo.toml @@ -10,6 +10,9 @@ license = "MIT OR Apache-2.0" readme = "README.md" include = ["src/**", "Cargo.toml", "LICENSE_*"] +[lib] +doctest = false + [dependencies] dirs = "6" log = "0.4" diff --git a/clash-nyanpasu/backend/tauri/Cargo.toml b/clash-nyanpasu/backend/tauri/Cargo.toml index 6ad0c9d58f..483b125837 100644 --- a/clash-nyanpasu/backend/tauri/Cargo.toml +++ b/clash-nyanpasu/backend/tauri/Cargo.toml @@ -12,6 +12,7 @@ build = "build.rs" [lib] name = "clash_nyanpasu_lib" crate-type = ["staticlib", "cdylib", "rlib"] +doctest = false [build-dependencies] tauri-build = { version = "2.0.1", features = [] } @@ -42,7 +43,7 @@ futures-util = "0.3" glob = "0.3.1" timeago = "0.4" humansize = "2.1.3" -convert_case = "0.7.0" +convert_case = "0.8.0" anyhow = "1.0" pretty_assertions = "1.4.0" chrono = "0.4.31" @@ -182,8 +183,8 @@ mlua = { version = "0.10", features = [ ] } # JavaScript Integration -boa_utils = { path = "../boa_utils" } # should be removed when boa support console customize -boa_engine.workspace = true +boa_utils = { path = "../boa_utils" } # should be removed when boa support console customize +boa_engine = { workspace = true, features = ["annex-b"] } # Tauri Dependencies tauri = { version = "2.2", features = ["tray-icon", "image-png", "image-ico"] } @@ -196,7 +197,7 @@ tauri-plugin-process = "2.2" tauri-plugin-updater = "2.2" tauri-plugin-shell = "2.2" tauri-plugin-notification = "2.2" -window-vibrancy = { version = "0.5.2" } +window-vibrancy = { version = "0.6.0" } # Strong typed api binding between typescript and rust specta-typescript = "0.0.9" diff --git a/clash-nyanpasu/backend/tauri/src/enhance/script/js.rs b/clash-nyanpasu/backend/tauri/src/enhance/script/js.rs index ab91ce1309..817cca774f 100644 --- a/clash-nyanpasu/backend/tauri/src/enhance/script/js.rs +++ b/clash-nyanpasu/backend/tauri/src/enhance/script/js.rs @@ -1,12 +1,12 @@ use super::runner::{ProcessOutput, Runner, wrap_result}; -use crate::enhance::utils::{Logs, LogsExt, take_logs}; +use crate::enhance::utils::{LogSpan, Logs, LogsExt, take_logs}; use anyhow::Context as _; use async_trait::async_trait; use boa_engine::{ Context, JsError, JsNativeError, JsValue, Source, builtins::promise::PromiseState, js_string, - module::{Module, ModuleLoader as BoaModuleLoader, SimpleModuleLoader}, + module::{Module, SimpleModuleLoader}, property::Attribute, }; use boa_utils::{ @@ -17,13 +17,12 @@ use boa_utils::{ }, }; use once_cell::sync::Lazy; -use parking_lot::Mutex; use serde_yaml::Mapping; use std::{ cell::RefCell, path::{Path, PathBuf}, rc::Rc, - sync::Arc, + time::Duration, }; use tracing_attributes::instrument; use utils::wrap_script_if_not_esm; @@ -55,16 +54,49 @@ pub enum JsRunnerError { Other(String), } -pub struct BoaConsoleLogger(Arc>>); +pub struct BoaConsoleLogger(Logs); impl boa_utils::Logger for BoaConsoleLogger { - fn log(&self, msg: boa_utils::LogMessage, _: &Console) { + type Item = boa_utils::LogMessage; + fn log(&mut self, msg: boa_utils::LogMessage, _: &Console) { match msg { - boa_utils::LogMessage::Log(msg) => self.0.lock().as_mut().unwrap().log(msg), - boa_utils::LogMessage::Info(msg) => self.0.lock().as_mut().unwrap().info(msg), - boa_utils::LogMessage::Warn(msg) => self.0.lock().as_mut().unwrap().warn(msg), - boa_utils::LogMessage::Error(msg) => self.0.lock().as_mut().unwrap().error(msg), + boa_utils::LogMessage::Log(msg) => self.0.log(msg), + boa_utils::LogMessage::Info(msg) => self.0.info(msg), + boa_utils::LogMessage::Warn(msg) => self.0.warn(msg), + boa_utils::LogMessage::Error(msg) => self.0.error(msg), } } + + #[inline] + fn take(&mut self) -> Vec { + std::mem::take(&mut self.0) + .into_iter() + .map(|(span, msg)| match span { + LogSpan::Log => boa_utils::LogMessage::Log(msg), + LogSpan::Info => boa_utils::LogMessage::Info(msg), + LogSpan::Warn => boa_utils::LogMessage::Warn(msg), + LogSpan::Error => boa_utils::LogMessage::Error(msg), + }) + .collect() + } +} + +impl BoaConsoleLogger { + pub fn take(&mut self) -> Logs { + std::mem::take(&mut self.0) + } +} + +#[inline] +fn take_console_logs() -> Logs { + let logs = boa_utils::inspect_logger(|logger| logger.take()); + logs.into_iter() + .map(|msg| match msg { + boa_utils::LogMessage::Log(msg) => (LogSpan::Log, msg), + boa_utils::LogMessage::Info(msg) => (LogSpan::Info, msg), + boa_utils::LogMessage::Warn(msg) => (LogSpan::Warn, msg), + boa_utils::LogMessage::Error(msg) => (LogSpan::Error, msg), + }) + .collect() } pub struct JSRunner; @@ -77,9 +109,10 @@ pub struct BoaRunner { impl BoaRunner { pub fn try_new() -> Result { + let cache_dir = crate::utils::dirs::cache_dir().unwrap(); let loader = Rc::new(CombineModuleLoader::new( SimpleModuleLoader::new(CUSTOM_SCRIPTS_DIR.as_path())?, - HttpModuleLoader::default(), + HttpModuleLoader::new(cache_dir, Duration::from_secs(60 * 60 * 24 * 30)), )); let simple_loader = loader.clone_simple(); let queue = Rc::new(Queue::default()); @@ -96,7 +129,7 @@ impl BoaRunner { pub fn setup_console(&self, logger: BoaConsoleLogger) -> Result<()> { let ctx = &mut self.ctx.borrow_mut(); // it not concurrency safe. we should move to new boa_runtime console when it is ready for custom logger - boa_utils::set_logger(Arc::new(logger)); + boa_utils::set_logger(Box::new(logger) as Box); let console = Console::init(ctx); ctx.register_global_property(js_string!(Console::NAME), console, Attribute::all())?; Ok(()) @@ -180,14 +213,13 @@ impl Runner for JSRunner { // boa engine is single-thread runner so that we can use it in tokio::task::spawn_blocking let res = tokio::task::spawn_blocking(move || { let wrapped_fn = move || { - let logs = Arc::new(Mutex::new(Some(Logs::new()))); - let logger = BoaConsoleLogger(logs.clone()); - let boa_runner = wrap_result!(BoaRunner::try_new(), take_logs(logs)); - wrap_result!(boa_runner.setup_console(logger), take_logs(logs)); + let mut logger = BoaConsoleLogger(Logs::new()); + let boa_runner = wrap_result!(BoaRunner::try_new(), logger.take()); + wrap_result!(boa_runner.setup_console(logger), take_console_logs()); let config = wrap_result!( serde_json::to_string(&mapping) .map_err(|e| { std::io::Error::new(std::io::ErrorKind::InvalidData, e) }), - take_logs(logs) + take_console_logs() ); let config = serde_json::to_string(&config).unwrap(); // escape the string let execute_module = format!( @@ -206,28 +238,28 @@ impl Runner for JSRunner { // wrap_result!(boa_runner.execute_module(&process_module)); let main_module = wrap_result!( boa_runner.parse_module(&execute_module, "main"), - take_logs(logs) + take_console_logs() ); wrap_result!(boa_runner.execute_module(&main_module)); let ctx = boa_runner.get_ctx(); let namespace = main_module.namespace(&mut ctx.borrow_mut()); let result = wrap_result!( namespace.get(js_string!("result"), &mut ctx.borrow_mut()), - take_logs(logs) + take_console_logs() ); - let mut result = wrap_result!( + let result = wrap_result!( result .as_string() .ok_or_else(|| JsNativeError::typ().with_message("Expected string")) .map(|str| str.to_std_string_escaped()), - take_logs(logs) + take_console_logs() ); let mapping = wrap_result!( serde_json::from_str(&result) .map_err(|e| { std::io::Error::new(std::io::ErrorKind::InvalidData, e) }), - take_logs(logs) + take_console_logs() ); - (Ok::(mapping), take_logs(logs)) + (Ok::(mapping), take_console_logs()) }; let (res, logs) = wrapped_fn(); match res { @@ -517,7 +549,9 @@ const foreignNameservers = [ serde_yaml::Value::Sequence(vec![ serde_yaml::Value::String("RULE-SET,custom-reject,REJECT".to_string()), serde_yaml::Value::String("RULE-SET,custom-direct,DIRECT".to_string()), - serde_yaml::Value::String("RULE-SET,custom-proxy,🚀".to_string()) + serde_yaml::Value::String("RULE-SET,custom-proxy,🚀".to_string()), + serde_yaml::Value::String("aGVsbG8=".to_string()), + serde_yaml::Value::String("d29ybGQ=".to_string()), ]) ); let outs = serde_json::to_string(&logs).unwrap(); diff --git a/clash-nyanpasu/backend/tauri/src/utils/dirs.rs b/clash-nyanpasu/backend/tauri/src/utils/dirs.rs index acfa1e7777..bb0f0a2631 100644 --- a/clash-nyanpasu/backend/tauri/src/utils/dirs.rs +++ b/clash-nyanpasu/backend/tauri/src/utils/dirs.rs @@ -324,6 +324,7 @@ pub fn check_core_permission(core: &nyanpasu_utils::core::CoreType) -> anyhow::R mod test { #[test] + #[ignore] fn test_dir_placeholder() { let placeholder = super::APP_DIR_PLACEHOLDER.clone(); if cfg!(windows) { diff --git a/clash-nyanpasu/frontend/nyanpasu/package.json b/clash-nyanpasu/frontend/nyanpasu/package.json index da0db5b512..a445944a28 100644 --- a/clash-nyanpasu/frontend/nyanpasu/package.json +++ b/clash-nyanpasu/frontend/nyanpasu/package.json @@ -53,12 +53,12 @@ "@csstools/normalize.css": "12.1.1", "@emotion/babel-plugin": "11.13.5", "@emotion/react": "11.14.0", - "@iconify/json": "2.2.311", + "@iconify/json": "2.2.312", "@monaco-editor/react": "4.7.0", "@tanstack/react-query": "5.66.11", "@tanstack/react-router": "1.112.0", - "@tanstack/router-devtools": "1.112.0", - "@tanstack/router-plugin": "1.112.0", + "@tanstack/router-devtools": "1.112.6", + "@tanstack/router-plugin": "1.112.3", "@tauri-apps/plugin-clipboard-manager": "2.2.1", "@tauri-apps/plugin-dialog": "2.2.0", "@tauri-apps/plugin-fs": "2.2.0", @@ -75,7 +75,7 @@ "@vitejs/plugin-react-swc": "3.8.0", "change-case": "5.4.4", "clsx": "2.1.1", - "core-js": "3.40.0", + "core-js": "3.41.0", "filesize": "10.1.6", "meta-json-schema": "1.19.1", "monaco-yaml": "5.3.1", diff --git a/clash-nyanpasu/frontend/ui/package.json b/clash-nyanpasu/frontend/ui/package.json index ee21f47a82..3161e9caff 100644 --- a/clash-nyanpasu/frontend/ui/package.json +++ b/clash-nyanpasu/frontend/ui/package.json @@ -46,6 +46,6 @@ "sass-embedded": "1.85.1", "tailwind-merge": "3.0.2", "typescript-plugin-css-modules": "5.1.0", - "vite-plugin-dts": "4.5.1" + "vite-plugin-dts": "4.5.3" } } diff --git a/clash-nyanpasu/manifest/version.json b/clash-nyanpasu/manifest/version.json index c35ecb867b..bf317f31c8 100644 --- a/clash-nyanpasu/manifest/version.json +++ b/clash-nyanpasu/manifest/version.json @@ -2,7 +2,7 @@ "manifest_version": 1, "latest": { "mihomo": "v1.19.2", - "mihomo_alpha": "alpha-05e8f13", + "mihomo_alpha": "alpha-a7e56f1", "clash_rs": "v0.7.6", "clash_premium": "2023-09-05-gdcc8d87", "clash_rs_alpha": "0.7.6-alpha+sha.14e7d32" @@ -69,5 +69,5 @@ "linux-armv7hf": "clash-armv7-unknown-linux-gnueabihf" } }, - "updated_at": "2025-02-28T22:20:51.050Z" + "updated_at": "2025-03-02T22:21:03.218Z" } diff --git a/clash-nyanpasu/pnpm-lock.yaml b/clash-nyanpasu/pnpm-lock.yaml index 147a991a2c..9f3b6dd612 100644 --- a/clash-nyanpasu/pnpm-lock.yaml +++ b/clash-nyanpasu/pnpm-lock.yaml @@ -333,8 +333,8 @@ importers: specifier: 11.14.0 version: 11.14.0(@types/react@19.0.10)(react@19.0.0) '@iconify/json': - specifier: 2.2.311 - version: 2.2.311 + specifier: 2.2.312 + version: 2.2.312 '@monaco-editor/react': specifier: 4.7.0 version: 4.7.0(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -345,11 +345,11 @@ importers: specifier: 1.112.0 version: 1.112.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@tanstack/router-devtools': - specifier: 1.112.0 - version: 1.112.0(@tanstack/react-router@1.112.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(csstype@3.1.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: 1.112.6 + version: 1.112.6(@tanstack/react-router@1.112.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(csstype@3.1.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@tanstack/router-plugin': - specifier: 1.112.0 - version: 1.112.0(@tanstack/react-router@1.112.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(vite@6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)) + specifier: 1.112.3 + version: 1.112.3(@tanstack/react-router@1.112.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(vite@6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)) '@tauri-apps/plugin-clipboard-manager': specifier: 2.2.1 version: 2.2.1 @@ -399,8 +399,8 @@ importers: specifier: 2.1.1 version: 2.1.1 core-js: - specifier: 3.40.0 - version: 3.40.0 + specifier: 3.41.0 + version: 3.41.0 filesize: specifier: 10.1.6 version: 10.1.6 @@ -535,8 +535,8 @@ importers: specifier: 5.1.0 version: 5.1.0(typescript@5.8.2) vite-plugin-dts: - specifier: 4.5.1 - version: 4.5.1(@types/node@22.13.8)(rollup@4.34.3)(typescript@5.8.2)(vite@6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)) + specifier: 4.5.3 + version: 4.5.3(@types/node@22.13.8)(rollup@4.34.3)(typescript@5.8.2)(vite@6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)) scripts: dependencies: @@ -605,8 +605,8 @@ importers: specifier: 2.26.22 version: 2.26.22 undici: - specifier: 7.3.0 - version: 7.3.0 + specifier: 7.4.0 + version: 7.4.0 yargs: specifier: 17.7.2 version: 17.7.2 @@ -1666,8 +1666,8 @@ packages: '@vue/compiler-sfc': optional: true - '@iconify/json@2.2.311': - resolution: {integrity: sha512-Qt9Q9MuyEfKpd+3027fzbCMhEkhNpUTc9mnUQImbVYr5BiyFxgAxwGcTl+oD6WEblzdnGU3KIXqH/Laekud35w==} + '@iconify/json@2.2.312': + resolution: {integrity: sha512-sujKsprCACPMVZHeNaxvc7HyONW916tUVw4zfEK+GmT7PkH73PdplmW1w2UWC07IC6oUYPZ2EE0pfdWHhWHjpQ==} '@iconify/types@2.0.0': resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} @@ -2768,8 +2768,8 @@ packages: resolution: {integrity: sha512-kmpMiBuz17Hxyl+ZO+B6/F98p07NSEmgr2JlZkKXcdupLIBAWqcXw+bjowFXNcTEwe9RWsS/WjAC/bBTftr0rA==} engines: {node: '>=12'} - '@tanstack/router-devtools@1.112.0': - resolution: {integrity: sha512-kbCvkY8y6vDnF09At9Q9q0yitXBFpO/BEuvMtLTkAKWwoZqPoEp7981AiWZeN62sphtdREn/1sTxvMNY8bBW2Q==} + '@tanstack/router-devtools@1.112.6': + resolution: {integrity: sha512-OhLZsDnrItA+8BiVdmyyWB2VgQyoCZAjSRshQJpbZdeAV69OvT2rqN2TtiLJsbSAJWmqL4/UcY/13DI9Iv+k3Q==} engines: {node: '>=12'} peerDependencies: '@tanstack/react-router': ^1.112.0 @@ -2780,8 +2780,8 @@ packages: csstype: optional: true - '@tanstack/router-generator@1.112.0': - resolution: {integrity: sha512-c1wA2TMfmL1igw6OFKdOZVrFqAJ/PB3ZJE0+upofmwVydUMH7tipvmztWGiRmcxGd66sl6o1l1X39308ObwAGQ==} + '@tanstack/router-generator@1.112.3': + resolution: {integrity: sha512-RUT+O/j7YIjbemVJjkP4qM8MYaaOltKYhyp9VGtcWxWGS8U2QDwC9UsskjBVOj7QV7aq3UcnExicABwK/AMCCQ==} engines: {node: '>=12'} peerDependencies: '@tanstack/react-router': ^1.112.0 @@ -2789,8 +2789,8 @@ packages: '@tanstack/react-router': optional: true - '@tanstack/router-plugin@1.112.0': - resolution: {integrity: sha512-0ZFbHqAHtvbJzdDlIuxuJiOcbR5oue9IVA5OR93gS7sPCueZI1uZQB/hdtC+kcpdnYQKDcxjeNranhqbcaZZnQ==} + '@tanstack/router-plugin@1.112.3': + resolution: {integrity: sha512-XhKXFoJ7eajqghAPwHXfggyB8khopr5yVXiYQRiL+9Gek2q5M8N4z9+Uh2MM31KjTuiaJ72lZpUgT5FDj1m6Tg==} engines: {node: '>=12'} peerDependencies: '@rsbuild/core': '>=1.0.2' @@ -3288,8 +3288,8 @@ packages: '@vue/compiler-vue2@2.7.16': resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==} - '@vue/language-core@2.2.4': - resolution: {integrity: sha512-eGGdw7eWUwdIn9Fy/irJ7uavCGfgemuHQABgJ/hU1UgZFnbTg9VWeXvHQdhY+2SPQZWJqWXvRWIg67t4iWEa+Q==} + '@vue/language-core@2.2.0': + resolution: {integrity: sha512-O1ZZFaaBGkKbsRfnVH1ifOK1/1BUkyK+3SQsfnh6PmMmD4qJcTU8godCeA96jjDRTL6zgnK7YzCHfaUlH2r0Mw==} peerDependencies: typescript: '*' peerDependenciesMeta: @@ -3362,8 +3362,8 @@ packages: ajv@8.17.1: resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} - alien-signals@1.0.4: - resolution: {integrity: sha512-DJqqQD3XcsaQcQ1s+iE2jDUZmmQpXwHiR6fCAim/w87luaW+vmLY8fMlrdkmRwzaFXhkxf3rqPCR59tKVv1MDw==} + alien-signals@0.4.14: + resolution: {integrity: sha512-itUAVzhczTmP2U5yX67xVpsbbOiquusbWVyA9N+sy6+r6YVbFkahXvNCeEPWEOMhwDYwbVbGHFkVL03N9I5g+Q==} allotment@1.20.3: resolution: {integrity: sha512-JCnklt7j0OsyDjD7A9AdT6wqJ3FSoo1ASV6w02Am02lo6NwO25yhG1DcWW8ueBV38ppXQmvrXBXuzX7iVkq6Tw==} @@ -3842,8 +3842,8 @@ packages: core-js-compat@3.40.0: resolution: {integrity: sha512-0XEDpr5y5mijvw8Lbc6E5AkjrHfp7eEoPlu36SWeAbcL8fn1G1ANe8DBlo2XoNN89oVpxWwOjYIPVzR4ZvsKCQ==} - core-js@3.40.0: - resolution: {integrity: sha512-7vsMc/Lty6AGnn7uFpYT56QesI5D2Y/UkgKounk87OP9Z2H9Z8kj6jzcSGAxFmUtDOS0ntK6lbQz+Nsa0Jj6mQ==} + core-js@3.41.0: + resolution: {integrity: sha512-SJ4/EHwS36QMJd6h/Rg+GyR4A5xE0FSI3eZ+iBVpfqf1x0eTSg1smWLHrA+2jQThZSh97fmSgFSU8B61nxosxA==} cosmiconfig-typescript-loader@6.1.0: resolution: {integrity: sha512-tJ1w35ZRUiM5FeTzT7DtYWAFFv37ZLqSRkGi2oeCK1gPhvaWjkAtfXvLmvE1pRfxxp9aQo6ba/Pvg1dKj05D4g==} @@ -7672,8 +7672,8 @@ packages: resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==} engines: {node: '>=14.0'} - undici@7.3.0: - resolution: {integrity: sha512-Qy96NND4Dou5jKoSJ2gm8ax8AJM/Ey9o9mz7KN1bb9GP+G0l20Zw8afxTnY2f4b7hmhn/z8aC2kfArVQlAhFBw==} + undici@7.4.0: + resolution: {integrity: sha512-PUQM3/es3noM24oUn10u3kNNap0AbxESOmnssmW+dOi9yGwlUSi5nTNYl3bNbTkWOF8YZDkx2tCmj9OtQ3iGGw==} engines: {node: '>=20.18.1'} unicode-canonical-property-names-ecmascript@2.0.1: @@ -7868,8 +7868,8 @@ packages: engines: {node: ^18.19.0 || >=20.6.0} hasBin: true - vite-plugin-dts@4.5.1: - resolution: {integrity: sha512-Yo1dHT05B2nD47AVB7b0+wK1FPFpJJnUf/muRF7+tP+sbPFRhLs70TTRGwJw7NDBwAUAmSwhrD+ZPTe4P6Wv9w==} + vite-plugin-dts@4.5.3: + resolution: {integrity: sha512-P64VnD00dR+e8S26ESoFELqc17+w7pKkwlBpgXteOljFyT0zDwD8hH4zXp49M/kciy//7ZbVXIwQCekBJjfWzA==} peerDependencies: typescript: '*' vite: '*' @@ -9426,7 +9426,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@iconify/json@2.2.311': + '@iconify/json@2.2.312': dependencies: '@iconify/types': 2.0.0 pathe: 1.1.2 @@ -10500,7 +10500,7 @@ snapshots: '@tanstack/history': 1.99.13 '@tanstack/store': 0.7.0 - '@tanstack/router-devtools@1.112.0(@tanstack/react-router@1.112.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(csstype@3.1.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@tanstack/router-devtools@1.112.6(@tanstack/react-router@1.112.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(csstype@3.1.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@tanstack/react-router': 1.112.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) clsx: 2.1.1 @@ -10510,7 +10510,7 @@ snapshots: optionalDependencies: csstype: 3.1.3 - '@tanstack/router-generator@1.112.0(@tanstack/react-router@1.112.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))': + '@tanstack/router-generator@1.112.3(@tanstack/react-router@1.112.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))': dependencies: '@tanstack/virtual-file-routes': 1.99.0 prettier: 3.5.2 @@ -10519,7 +10519,7 @@ snapshots: optionalDependencies: '@tanstack/react-router': 1.112.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tanstack/router-plugin@1.112.0(@tanstack/react-router@1.112.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(vite@6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))': + '@tanstack/router-plugin@1.112.3(@tanstack/react-router@1.112.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(vite@6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))': dependencies: '@babel/core': 7.26.9 '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.9) @@ -10528,7 +10528,7 @@ snapshots: '@babel/traverse': 7.26.9 '@babel/types': 7.26.9 '@tanstack/router-core': 1.112.0 - '@tanstack/router-generator': 1.112.0(@tanstack/react-router@1.112.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)) + '@tanstack/router-generator': 1.112.3(@tanstack/react-router@1.112.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)) '@tanstack/router-utils': 1.102.2 '@tanstack/virtual-file-routes': 1.99.0 '@types/babel__core': 7.20.5 @@ -11051,7 +11051,7 @@ snapshots: '@babel/preset-env': 7.26.9(@babel/core@7.26.9) browserslist: 4.24.4 browserslist-to-esbuild: 2.1.1(browserslist@4.24.4) - core-js: 3.40.0 + core-js: 3.41.0 magic-string: 0.30.17 regenerator-runtime: 0.14.1 systemjs: 6.15.1 @@ -11108,13 +11108,13 @@ snapshots: de-indent: 1.0.2 he: 1.2.0 - '@vue/language-core@2.2.4(typescript@5.8.2)': + '@vue/language-core@2.2.0(typescript@5.8.2)': dependencies: '@volar/language-core': 2.4.11 '@vue/compiler-dom': 3.5.13 '@vue/compiler-vue2': 2.7.16 '@vue/shared': 3.5.13 - alien-signals: 1.0.4 + alien-signals: 0.4.14 minimatch: 9.0.5 muggle-string: 0.4.1 path-browserify: 1.0.1 @@ -11198,7 +11198,7 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - alien-signals@1.0.4: {} + alien-signals@0.4.14: {} allotment@1.20.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: @@ -11715,7 +11715,7 @@ snapshots: dependencies: browserslist: 4.24.4 - core-js@3.40.0: {} + core-js@3.41.0: {} cosmiconfig-typescript-loader@6.1.0(@types/node@22.13.8)(cosmiconfig@9.0.0(typescript@5.8.2))(typescript@5.8.2): dependencies: @@ -16010,7 +16010,7 @@ snapshots: dependencies: '@fastify/busboy': 2.1.1 - undici@7.3.0: {} + undici@7.4.0: {} unicode-canonical-property-names-ecmascript@2.0.1: {} @@ -16206,12 +16206,12 @@ snapshots: - rollup - supports-color - vite-plugin-dts@4.5.1(@types/node@22.13.8)(rollup@4.34.3)(typescript@5.8.2)(vite@6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)): + vite-plugin-dts@4.5.3(@types/node@22.13.8)(rollup@4.34.3)(typescript@5.8.2)(vite@6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)): dependencies: '@microsoft/api-extractor': 7.51.0(@types/node@22.13.8) '@rollup/pluginutils': 5.1.4(rollup@4.34.3) '@volar/typescript': 2.4.11 - '@vue/language-core': 2.2.4(typescript@5.8.2) + '@vue/language-core': 2.2.0(typescript@5.8.2) compare-versions: 6.1.1 debug: 4.4.0 kolorist: 1.8.0 diff --git a/clash-nyanpasu/scripts/.gitignore b/clash-nyanpasu/scripts/.gitignore new file mode 100644 index 0000000000..70dc3b5575 --- /dev/null +++ b/clash-nyanpasu/scripts/.gitignore @@ -0,0 +1,2 @@ +!.vscode/settings.json +!.vscode/ diff --git a/clash-nyanpasu/scripts/.vscode/settings.json b/clash-nyanpasu/scripts/.vscode/settings.json new file mode 100644 index 0000000000..93c3ffd7d2 --- /dev/null +++ b/clash-nyanpasu/scripts/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "deno.enable": true, + "deno.enablePaths": ["./deno"] +} diff --git a/clash-nyanpasu/scripts/deno/README.md b/clash-nyanpasu/scripts/deno/README.md new file mode 100644 index 0000000000..f87574ac8e --- /dev/null +++ b/clash-nyanpasu/scripts/deno/README.md @@ -0,0 +1,3 @@ +# Deno scripts + +When we migrated all the scripts to Deno, let's move them to outer directory. diff --git a/clash-nyanpasu/scripts/deno/deno.jsonc b/clash-nyanpasu/scripts/deno/deno.jsonc new file mode 100644 index 0000000000..1cdc8bf6cd --- /dev/null +++ b/clash-nyanpasu/scripts/deno/deno.jsonc @@ -0,0 +1,8 @@ +{ + "tasks": { + "upload-macos-updater": { + "description": "Upload macOS updater to GitHub Releases", + "command": "deno run -A upload-macos-updater.ts", + }, + }, +} diff --git a/clash-nyanpasu/scripts/deno/deno.lock b/clash-nyanpasu/scripts/deno/deno.lock new file mode 100644 index 0000000000..ee5112b84d --- /dev/null +++ b/clash-nyanpasu/scripts/deno/deno.lock @@ -0,0 +1,146 @@ +{ + "version": "4", + "specifiers": { + "jsr:@std/path@*": "1.0.8", + "npm:colorize-template@*": "1.0.0", + "npm:consola@*": "3.4.0", + "npm:globby@*": "14.1.0", + "npm:picocolors@*": "1.1.1" + }, + "jsr": { + "@std/path@1.0.8": { + "integrity": "548fa456bb6a04d3c1a1e7477986b6cffbce95102d0bb447c67c4ee70e0364be" + } + }, + "npm": { + "@nodelib/fs.scandir@2.1.5": { + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": [ + "@nodelib/fs.stat", + "run-parallel" + ] + }, + "@nodelib/fs.stat@2.0.5": { + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" + }, + "@nodelib/fs.walk@1.2.8": { + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": [ + "@nodelib/fs.scandir", + "fastq" + ] + }, + "@sindresorhus/merge-streams@2.3.0": { + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==" + }, + "braces@3.0.3": { + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dependencies": [ + "fill-range" + ] + }, + "colorize-template@1.0.0": { + "integrity": "sha512-beJ9v9RjpbYZ8OdwJgIRZD3YUkZPXmi1MK+yX0J24UupKVHa9yk0jiARgt2i6MBX6AKjYA0SNsBn65bUPuVQiw==" + }, + "consola@3.4.0": { + "integrity": "sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA==" + }, + "fast-glob@3.3.3": { + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dependencies": [ + "@nodelib/fs.stat", + "@nodelib/fs.walk", + "glob-parent", + "merge2", + "micromatch" + ] + }, + "fastq@1.19.1": { + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dependencies": [ + "reusify" + ] + }, + "fill-range@7.1.1": { + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dependencies": [ + "to-regex-range" + ] + }, + "glob-parent@5.1.2": { + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": [ + "is-glob" + ] + }, + "globby@14.1.0": { + "integrity": "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==", + "dependencies": [ + "@sindresorhus/merge-streams", + "fast-glob", + "ignore", + "path-type", + "slash", + "unicorn-magic" + ] + }, + "ignore@7.0.3": { + "integrity": "sha512-bAH5jbK/F3T3Jls4I0SO1hmPR0dKU0a7+SY6n1yzRtG54FLO8d6w/nxLFX2Nb7dBu6cCWXPaAME6cYqFUMmuCA==" + }, + "is-extglob@2.1.1": { + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" + }, + "is-glob@4.0.3": { + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": [ + "is-extglob" + ] + }, + "is-number@7.0.0": { + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "merge2@1.4.1": { + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" + }, + "micromatch@4.0.8": { + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dependencies": [ + "braces", + "picomatch" + ] + }, + "path-type@6.0.0": { + "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==" + }, + "picocolors@1.1.1": { + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" + }, + "picomatch@2.3.1": { + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + }, + "queue-microtask@1.2.3": { + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" + }, + "reusify@1.1.0": { + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==" + }, + "run-parallel@1.2.0": { + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dependencies": [ + "queue-microtask" + ] + }, + "slash@5.1.0": { + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==" + }, + "to-regex-range@5.0.1": { + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": [ + "is-number" + ] + }, + "unicorn-magic@0.3.0": { + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==" + } + } +} diff --git a/clash-nyanpasu/scripts/deno/upload-macos-updater.ts b/clash-nyanpasu/scripts/deno/upload-macos-updater.ts new file mode 100644 index 0000000000..c87ac8f279 --- /dev/null +++ b/clash-nyanpasu/scripts/deno/upload-macos-updater.ts @@ -0,0 +1,58 @@ +import * as path from 'jsr:@std/path' +import { globby } from 'npm:globby' +import { consola } from './utils/logger.ts' + +const WORKSPACE_ROOT = path.join(Deno.cwd(), '../..') +consola.info(`WORKSPACE_ROOT: ${WORKSPACE_ROOT}`) + +const GITHUB_TOKEN = Deno.env.get('GITHUB_TOKEN') || Deno.env.get('GH_TOKEN') +const GITHUB_TAG = Deno.env.get('GITHUB_TAG') +const TARGET_ARCH = Deno.env.get('TARGET_ARCH') || Deno.build.arch + +if (!GITHUB_TOKEN) { + consola.fatal('GITHUB_TOKEN is not set') + Deno.exit(1) +} + +if (!GITHUB_TAG) { + consola.fatal('GITHUB_TAG is not set') + Deno.exit(1) +} + +const BACKEND_BUILD_DIR = path.join(WORKSPACE_ROOT, 'backend/target') + +const files = await globby(['**/*.tar.gz', '**/*.sig', '**/*.dmg'], { + cwd: BACKEND_BUILD_DIR, +}) + +for (let file of files) { + file = path.join(BACKEND_BUILD_DIR, file) + const p = path.parse(file) + consola.info(`Found file: ${p.base}`) + if (p.base.endsWith('.app.tar.gz')) { + const newName = p.name.split('.')[0] + `.${TARGET_ARCH}.app.tar.gz` + const newPath = path.join(p.dir, newName) + consola.info(`Renaming ${file} to ${newPath}`) + await Deno.rename(file, newPath) + file = newPath + } + consola.info(`Uploading ${file}...`) + const cmd = new Deno.Command('gh', { + args: ['release', 'upload', GITHUB_TAG, file, '--clobber'], + stdout: 'piped', + stderr: 'piped', + env: { + GH_TOKEN: GITHUB_TOKEN, + GITHUB_TOKEN, + }, + }) + + const output = await cmd.output() + if (output.code !== 0) { + consola.error(output.stderr) + consola.error(`Failed to upload ${file}`) + Deno.exit(1) + } +} + +consola.success('Uploaded all files') diff --git a/clash-nyanpasu/scripts/deno/utils/logger.ts b/clash-nyanpasu/scripts/deno/utils/logger.ts new file mode 100644 index 0000000000..be7559d3d8 --- /dev/null +++ b/clash-nyanpasu/scripts/deno/utils/logger.ts @@ -0,0 +1,21 @@ +import { createColorize } from 'npm:colorize-template' +import { createConsola } from 'npm:consola' +import pc from 'npm:picocolors' + +const logLevelStr = Deno.env.get('LOG_LEVEL') + +export const consola = createConsola({ + level: logLevelStr ? Number.parseInt(logLevelStr) : 5, + fancy: true, + formatOptions: { + colors: true, + compact: false, + date: true, + }, +}) + +export const colorize = createColorize({ + ...pc, + success: pc.green, + error: pc.red, +}) diff --git a/clash-nyanpasu/scripts/package.json b/clash-nyanpasu/scripts/package.json index 110fe419ff..508e89185b 100644 --- a/clash-nyanpasu/scripts/package.json +++ b/clash-nyanpasu/scripts/package.json @@ -26,7 +26,7 @@ "picocolors": "1.1.1", "tar": "7.4.3", "telegram": "2.26.22", - "undici": "7.3.0", + "undici": "7.4.0", "yargs": "17.7.2" } } diff --git a/clash-nyanpasu/scripts/tsconfig.json b/clash-nyanpasu/scripts/tsconfig.json index 27b39c5f47..d5a37a20fa 100644 --- a/clash-nyanpasu/scripts/tsconfig.json +++ b/clash-nyanpasu/scripts/tsconfig.json @@ -17,4 +17,5 @@ "composite": true, }, "include": ["./"], + "exclude": ["deno"], } diff --git a/clash-verge-rev/src-tauri/Cargo.lock b/clash-verge-rev/src-tauri/Cargo.lock index c03ed2e612..c3e605b801 100644 --- a/clash-verge-rev/src-tauri/Cargo.lock +++ b/clash-verge-rev/src-tauri/Cargo.lock @@ -116,6 +116,56 @@ dependencies = [ "libc", ] +[[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +dependencies = [ + "anstyle", + "once_cell", + "windows-sys 0.59.0", +] + [[package]] name = "anyhow" version = "1.0.95" @@ -191,6 +241,16 @@ dependencies = [ "zbus", ] +[[package]] +name = "assert-json-diff" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "async-broadcast" version = "0.7.2" @@ -1003,6 +1063,7 @@ version = "2.1.2" dependencies = [ "aes-gcm", "anyhow", + "async-trait", "base64 0.22.1", "boa_engine", "chrono", @@ -1010,12 +1071,14 @@ dependencies = [ "delay_timer", "dirs 6.0.0", "dunce", + "env_logger", "futures", "getrandom 0.2.15", "image 0.24.9", "imageproc", "log", "log4rs", + "mockito", "nanoid", "network-interface", "once_cell", @@ -1047,6 +1110,7 @@ dependencies = [ "tauri-plugin-shell", "tauri-plugin-updater", "tauri-plugin-window-state", + "tempfile", "tokio", "tokio-tungstenite 0.26.1", "url", @@ -1132,6 +1196,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + [[package]] name = "colored" version = "2.2.0" @@ -1927,6 +1997,29 @@ dependencies = [ "syn 2.0.98", ] +[[package]] +name = "env_filter" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -2924,6 +3017,7 @@ dependencies = [ "http 1.2.0", "http-body 1.0.1", "httparse", + "httpdate", "itoa 1.0.14", "pin-project-lite", "smallvec", @@ -3344,6 +3438,12 @@ dependencies = [ "once_cell", ] +[[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" @@ -3845,6 +3945,30 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "mockito" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "652cd6d169a36eaf9d1e6bce1a221130439a966d7f27858af66a33a66e9c4ee2" +dependencies = [ + "assert-json-diff", + "bytes", + "colored", + "futures-util", + "http 1.2.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.6.0", + "hyper-util", + "log", + "rand 0.8.5", + "regex", + "serde_json", + "serde_urlencoded", + "similar", + "tokio", +] + [[package]] name = "muda" version = "0.15.3" @@ -6161,6 +6285,12 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +[[package]] +name = "similar" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" + [[package]] name = "siphasher" version = "0.3.11" @@ -7002,9 +7132,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.16.0" +version = "3.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91" +checksum = "22e5a0acb1f3f55f65cc4a866c361b2fb2a0ff6366785ae6fbb5f85df07ba230" dependencies = [ "cfg-if", "fastrand 2.3.0", diff --git a/clash-verge-rev/src-tauri/Cargo.toml b/clash-verge-rev/src-tauri/Cargo.toml index 8d5de16e95..24808a490d 100755 --- a/clash-verge-rev/src-tauri/Cargo.toml +++ b/clash-verge-rev/src-tauri/Cargo.toml @@ -67,6 +67,7 @@ getrandom = "0.2" tokio-tungstenite = "0.26.1" futures = "0.3" sys-locale = "0.3.1" +async-trait = "0.1.86" [target.'cfg(windows)'.dependencies] runas = "=1.2.0" @@ -120,3 +121,8 @@ strip = false # 不剥离符号,保留调试信息 [lib] name = "app_lib" crate-type = ["staticlib", "cdylib", "rlib"] + +[dev-dependencies] +env_logger = "0.11.0" +mockito = "1.2.0" +tempfile = "3.17.1" diff --git a/clash-verge-rev/src-tauri/src/cmd/mod.rs b/clash-verge-rev/src-tauri/src/cmd/mod.rs index e0c2b91dd0..c4fd72cfd6 100644 --- a/clash-verge-rev/src-tauri/src/cmd/mod.rs +++ b/clash-verge-rev/src-tauri/src/cmd/mod.rs @@ -14,6 +14,8 @@ pub mod clash; pub mod verge; pub mod runtime; pub mod save_profile; +pub mod system; +pub mod proxy; // Re-export all command functions for backwards compatibility pub use profile::*; @@ -25,4 +27,6 @@ pub use network::*; pub use clash::*; pub use verge::*; pub use runtime::*; -pub use save_profile::*; \ No newline at end of file +pub use save_profile::*; +pub use system::*; +pub use proxy::*; \ No newline at end of file diff --git a/clash-verge-rev/src-tauri/src/cmd/proxy.rs b/clash-verge-rev/src-tauri/src/cmd/proxy.rs new file mode 100644 index 0000000000..e2ddf7713d --- /dev/null +++ b/clash-verge-rev/src-tauri/src/cmd/proxy.rs @@ -0,0 +1,35 @@ +use super::CmdResult; +use crate::module::mihomo::MihomoManager; +use tauri::async_runtime; + +#[tauri::command] +pub async fn get_proxies() -> CmdResult { + let proxies = async_runtime::spawn_blocking(|| { + let rt = tokio::runtime::Runtime::new().unwrap(); + let manager = MihomoManager::new(); + { + let mut write_guard = manager.write(); + rt.block_on(write_guard.refresh_proxies()); + } + let read_guard = manager.read(); + read_guard.fetch_proxies().clone() + }) + .await.map_err(|e| e.to_string())?; + Ok(proxies) +} + +#[tauri::command] +pub async fn get_providers_proxies() -> CmdResult { + let providers_proxies = async_runtime::spawn_blocking(|| { + let rt = tokio::runtime::Runtime::new().unwrap(); + let manager = MihomoManager::new(); + { + let mut write_guard = manager.write(); + rt.block_on(write_guard.refresh_providers_proxies()); + } + let read_guard = manager.read(); + read_guard.fetch_providers_proxies().clone() + }) + .await.map_err(|e| e.to_string())?; + Ok(providers_proxies) +} \ No newline at end of file diff --git a/clash-verge-rev/src-tauri/src/cmd/system.rs b/clash-verge-rev/src-tauri/src/cmd/system.rs new file mode 100644 index 0000000000..2c875e77b4 --- /dev/null +++ b/clash-verge-rev/src-tauri/src/cmd/system.rs @@ -0,0 +1,34 @@ +use super::CmdResult; +use crate::{core::handle, model::sysinfo::PlatformSpecification}; +use tauri_plugin_clipboard_manager::ClipboardExt; +use crate::{core::{self, CoreManager, service}, wrap_err}; + +#[tauri::command] +pub async fn export_diagnostic_info() -> CmdResult<()> { + let sysinfo = PlatformSpecification::new(); + let info = format!("{:?}", sysinfo); + + let app_handle = handle::Handle::global().app_handle().unwrap(); + let cliboard = app_handle.clipboard(); + + if let Err(_) = cliboard.write_text(info) { + log::error!(target: "app", "Failed to write to clipboard"); + } + Ok(()) +} + +/// 获取当前内核运行模式 +#[tauri::command] +pub async fn get_running_mode() -> Result { + match CoreManager::global().get_running_mode().await { + core::RunningMode::Service => Ok("service".to_string()), + core::RunningMode::Sidecar => Ok("sidecar".to_string()), + core::RunningMode::NotRunning => Ok("not_running".to_string()), + } +} + +/// 安装/重装系统服务 +#[tauri::command] +pub async fn install_service() -> CmdResult { + wrap_err!(service::reinstall_service().await) +} diff --git a/clash-verge-rev/src-tauri/src/config/api/mihomo.rs b/clash-verge-rev/src-tauri/src/config/api/mihomo.rs new file mode 100644 index 0000000000..46873b9654 --- /dev/null +++ b/clash-verge-rev/src-tauri/src/config/api/mihomo.rs @@ -0,0 +1 @@ +pub const MIHOMO_URL: &str = concat!("http://", "127.0.0.1", ":", "9097"); diff --git a/clash-verge-rev/src-tauri/src/config/api/mod.rs b/clash-verge-rev/src-tauri/src/config/api/mod.rs new file mode 100644 index 0000000000..0f3c805716 --- /dev/null +++ b/clash-verge-rev/src-tauri/src/config/api/mod.rs @@ -0,0 +1 @@ +pub mod mihomo; diff --git a/clash-verge-rev/src-tauri/src/config/mod.rs b/clash-verge-rev/src-tauri/src/config/mod.rs index 69b1b1236d..a3ddace0cc 100644 --- a/clash-verge-rev/src-tauri/src/config/mod.rs +++ b/clash-verge-rev/src-tauri/src/config/mod.rs @@ -21,3 +21,6 @@ pub const DEFAULT_PAC: &str = r#"function FindProxyForURL(url, host) { return "PROXY 127.0.0.1:%mixed-port%; SOCKS5 127.0.0.1:%mixed-port%; DIRECT;"; } "#; + + +pub mod api; \ No newline at end of file diff --git a/clash-verge-rev/src-tauri/src/core/core.rs b/clash-verge-rev/src-tauri/src/core/core.rs index ff0fc87a74..77cd9704c2 100644 --- a/clash-verge-rev/src-tauri/src/core/core.rs +++ b/clash-verge-rev/src-tauri/src/core/core.rs @@ -7,7 +7,7 @@ use crate::utils::{dirs, help}; use anyhow::{bail, Result}; use once_cell::sync::OnceCell; use serde_yaml::Mapping; -use std::{sync::Arc, time::Duration}; +use std::{sync::Arc, time::Duration, path::PathBuf}; use tauri_plugin_shell::ShellExt; use tokio::sync::Mutex; use tokio::time::sleep; @@ -17,6 +17,17 @@ pub struct CoreManager { running: Arc>, } +/// 内核运行模式 +#[derive(Debug, Clone, serde::Serialize)] +pub enum RunningMode { + /// 服务模式运行 + Service, + /// Sidecar模式运行 + Sidecar, + /// 未运行 + NotRunning, +} + impl CoreManager { pub fn global() -> &'static CoreManager { static CORE_MANAGER: OnceCell = OnceCell::new(); @@ -53,12 +64,37 @@ impl CoreManager { // 服务模式 if service::check_service().await.is_ok() { log::info!(target: "app", "stop the core by service"); - service::stop_core_by_service().await?; + match service::stop_core_by_service().await { + Ok(_) => { + log::info!(target: "app", "core stopped successfully by service"); + } + Err(err) => { + log::warn!(target: "app", "failed to stop core by service: {}", err); + // 服务停止失败,尝试停止可能的sidecar进程 + self.stop_sidecar_process(); + } + } + } else { + // 如果没有使用服务,尝试停止sidecar进程 + self.stop_sidecar_process(); } + *running = false; Ok(()) } + /// 停止通过sidecar启动的进程 + fn stop_sidecar_process(&self) { + if let Some(process) = handle::Handle::global().take_core_process() { + log::info!(target: "app", "stopping core process in sidecar mode"); + if let Err(e) = process.kill() { + log::warn!(target: "app", "failed to kill core process: {}", e); + } else { + log::info!(target: "app", "core process stopped successfully"); + } + } + } + /// 启动核心 pub async fn start_core(&self) -> Result<()> { let mut running = self.running.lock().await; @@ -69,11 +105,26 @@ impl CoreManager { let config_path = Config::generate_file(ConfigType::Run)?; - // 服务模式 + // 先尝试服务模式 if service::check_service().await.is_ok() { log::info!(target: "app", "try to run core in service mode"); - service::run_core_by_service(&config_path).await?; + match service::run_core_by_service(&config_path).await { + Ok(_) => { + log::info!(target: "app", "core started successfully in service mode"); + }, + Err(err) => { + // 服务启动失败,尝试sidecar模式 + log::warn!(target: "app", "failed to start core in service mode: {}", err); + log::info!(target: "app", "trying to run core in sidecar mode"); + self.run_core_by_sidecar(&config_path).await?; + } + } + } else { + // 服务不可用,直接使用sidecar模式 + log::info!(target: "app", "service not available, running core in sidecar mode"); + self.run_core_by_sidecar(&config_path).await?; } + // 流量订阅 #[cfg(target_os = "macos")] log_err!(Tray::global().subscribe_traffic().await); @@ -83,11 +134,43 @@ impl CoreManager { Ok(()) } + /// 通过sidecar启动内核 + async fn run_core_by_sidecar(&self, config_path: &PathBuf) -> Result<()> { + let clash_core = { Config::verge().latest().clash_core.clone() }; + let clash_core = clash_core.unwrap_or("verge-mihomo".into()); + + log::info!(target: "app", "starting core {} in sidecar mode", clash_core); + + let app_handle = handle::Handle::global().app_handle().ok_or(anyhow::anyhow!("failed to get app handle"))?; + + // 获取配置目录 + let config_dir = dirs::app_home_dir()?; + let config_path_str = dirs::path_to_str(config_path)?; + + // 启动核心进程并转入后台运行 + let (_, child) = app_handle + .shell() + .sidecar(clash_core)? + .args(["-d", dirs::path_to_str(&config_dir)?, "-f", config_path_str]) + .spawn()?; + + // 保存进程ID以便后续管理 + handle::Handle::global().set_core_process(child); + + // 等待短暂时间确保启动成功 + sleep(Duration::from_millis(300)).await; + + log::info!(target: "app", "core started in sidecar mode"); + Ok(()) + } + /// 重启内核 pub async fn restart_core(&self) -> Result<()> { // 重新启动app + log::info!(target: "app", "restarting core"); self.stop_core().await?; self.start_core().await?; + log::info!(target: "app", "core restarted successfully"); Ok(()) } @@ -139,9 +222,11 @@ impl CoreManager { } Err(err) => { println!("[切换内核] 内核切换失败: {}", err); - Config::verge().discard(); - Config::runtime().discard(); - Err(err) + // 即使使用服务失败,我们也尝试使用sidecar模式启动 + log::info!(target: "app", "trying sidecar mode after service failure"); + self.start_core().await?; + Config::runtime().apply(); + Ok(()) } } } @@ -159,8 +244,10 @@ impl CoreManager { } Err(err) => { println!("[切换内核] 内核切换失败: {}", err); - Config::verge().discard(); - Err(err) + // 即使使用服务失败,我们也尝试使用sidecar模式启动 + log::info!(target: "app", "trying sidecar mode after service failure with default config"); + self.start_core().await?; + Ok(()) } } } @@ -495,4 +582,38 @@ impl CoreManager { } } } + + /// 获取当前内核运行模式 + pub async fn get_running_mode(&self) -> RunningMode { + let running = self.running.lock().await; + if !*running { + return RunningMode::NotRunning; + } + + // 检查服务状态 + match service::check_service().await { + Ok(_) => { + // 检查服务是否实际运行核心 + match service::is_service_running().await { + Ok(true) => RunningMode::Service, + _ => { + // 服务存在但可能没有运行,检查是否有sidecar进程 + if handle::Handle::global().has_core_process() { + RunningMode::Sidecar + } else { + RunningMode::NotRunning + } + } + } + }, + Err(_) => { + // 服务不可用,检查是否有sidecar进程 + if handle::Handle::global().has_core_process() { + RunningMode::Sidecar + } else { + RunningMode::NotRunning + } + } + } + } } \ No newline at end of file diff --git a/clash-verge-rev/src-tauri/src/core/handle.rs b/clash-verge-rev/src-tauri/src/core/handle.rs index eef12f0c17..4fabfaba86 100644 --- a/clash-verge-rev/src-tauri/src/core/handle.rs +++ b/clash-verge-rev/src-tauri/src/core/handle.rs @@ -3,11 +3,13 @@ use once_cell::sync::OnceCell; use parking_lot::RwLock; use std::sync::Arc; use tauri::{AppHandle, Emitter, Manager, WebviewWindow}; +use tauri_plugin_shell::process::CommandChild; #[derive(Debug, Default, Clone)] pub struct Handle { pub app_handle: Arc>>, pub is_exiting: Arc>, + pub core_process: Arc>>, } impl Handle { @@ -17,6 +19,7 @@ impl Handle { HANDLE.get_or_init(|| Handle { app_handle: Arc::new(RwLock::new(None)), is_exiting: Arc::new(RwLock::new(false)), + core_process: Arc::new(RwLock::new(None)), }) } @@ -68,6 +71,21 @@ impl Handle { *is_exiting = true; } + pub fn set_core_process(&self, process: CommandChild) { + let mut core_process = self.core_process.write(); + *core_process = Some(process); + } + + pub fn take_core_process(&self) -> Option { + let mut core_process = self.core_process.write(); + core_process.take() + } + + /// 检查是否有运行中的核心进程 + pub fn has_core_process(&self) -> bool { + self.core_process.read().is_some() + } + pub fn is_exiting(&self) -> bool { *self.is_exiting.read() } diff --git a/clash-verge-rev/src-tauri/src/core/service.rs b/clash-verge-rev/src-tauri/src/core/service.rs index 32d9b77b99..2426c081bc 100644 --- a/clash-verge-rev/src-tauri/src/core/service.rs +++ b/clash-verge-rev/src-tauri/src/core/service.rs @@ -279,3 +279,15 @@ pub(super) async fn stop_core_by_service() -> Result<()> { Ok(()) } + +/// 检查服务是否正在运行 +pub async fn is_service_running() -> Result { + let resp = check_service().await?; + + // 检查服务状态码和消息 + if resp.code == 200 && resp.msg == "success" && resp.data.is_some() { + Ok(true) + } else { + Ok(false) + } +} diff --git a/clash-verge-rev/src-tauri/src/enhance/seq.rs b/clash-verge-rev/src-tauri/src/enhance/seq.rs index 396b1969ea..82672c93b9 100644 --- a/clash-verge-rev/src-tauri/src/enhance/seq.rs +++ b/clash-verge-rev/src-tauri/src/enhance/seq.rs @@ -85,6 +85,7 @@ pub fn use_seq(seq: SeqMap, mut config: Mapping, field: &str) -> Mapping { #[cfg(test)] mod tests { use super::*; + #[allow(unused_imports)] use serde_yaml::Value; #[test] diff --git a/clash-verge-rev/src-tauri/src/lib.rs b/clash-verge-rev/src-tauri/src/lib.rs index a199cf1e34..ccfddebe63 100644 --- a/clash-verge-rev/src-tauri/src/lib.rs +++ b/clash-verge-rev/src-tauri/src/lib.rs @@ -4,6 +4,8 @@ mod core; mod enhance; mod feat; mod utils; +mod model; +mod module; use crate::core::hotkey; use crate::utils::{resolve, resolve::resolve_scheme, server}; use config::Config; @@ -146,6 +148,9 @@ pub fn run() { cmd::get_network_interfaces, cmd::restart_core, cmd::restart_app, + // 添加新的命令 + cmd::get_running_mode, + cmd::install_service, // clash cmd::get_clash_info, cmd::patch_clash_config, @@ -157,6 +162,8 @@ pub fn run() { cmd::get_runtime_logs, cmd::invoke_uwp_tool, cmd::copy_clash_env, + cmd::get_proxies, + cmd::get_providers_proxies, // verge cmd::get_verge_config, cmd::patch_verge_config, @@ -191,6 +198,8 @@ pub fn run() { cmd::list_webdav_backup, cmd::delete_webdav_backup, cmd::restore_webdav_backup, + // export diagnostic info for issue reporting + cmd::export_diagnostic_info, ]); #[cfg(debug_assertions)] diff --git a/clash-verge-rev/src-tauri/src/model/api/common.rs b/clash-verge-rev/src-tauri/src/model/api/common.rs new file mode 100644 index 0000000000..cd83945cbe --- /dev/null +++ b/clash-verge-rev/src-tauri/src/model/api/common.rs @@ -0,0 +1,20 @@ +use reqwest::Client; + +#[allow(unused)] +pub(crate) struct ApiCaller<'a> { + pub(crate) url: &'a str, + pub(crate) client: Client, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_api_caller() { + let _api_caller = ApiCaller { + url: "https://example.com", + client: Client::new(), + }; + } +} diff --git a/clash-verge-rev/src-tauri/src/model/api/mihomo.rs b/clash-verge-rev/src-tauri/src/model/api/mihomo.rs new file mode 100644 index 0000000000..ad14be62f5 --- /dev/null +++ b/clash-verge-rev/src-tauri/src/model/api/mihomo.rs @@ -0,0 +1,5 @@ +use super::common::ApiCaller; + +pub struct MihomoAPICaller { + pub(crate) caller: ApiCaller<'static>, +} diff --git a/clash-verge-rev/src-tauri/src/model/api/mod.rs b/clash-verge-rev/src-tauri/src/model/api/mod.rs new file mode 100644 index 0000000000..bee8fa981c --- /dev/null +++ b/clash-verge-rev/src-tauri/src/model/api/mod.rs @@ -0,0 +1,2 @@ +pub mod common; +pub mod mihomo; diff --git a/clash-verge-rev/src-tauri/src/model/mod.rs b/clash-verge-rev/src-tauri/src/model/mod.rs new file mode 100644 index 0000000000..e11af71e02 --- /dev/null +++ b/clash-verge-rev/src-tauri/src/model/mod.rs @@ -0,0 +1,2 @@ +pub mod api; +pub mod sysinfo; diff --git a/clash-verge-rev/src-tauri/src/model/sysinfo.rs b/clash-verge-rev/src-tauri/src/model/sysinfo.rs new file mode 100644 index 0000000000..b626181d2c --- /dev/null +++ b/clash-verge-rev/src-tauri/src/model/sysinfo.rs @@ -0,0 +1,18 @@ +use std::fmt::{self, Debug, Formatter}; + +pub struct PlatformSpecification { + pub system_name: String, + pub system_version: String, + pub system_kernel_version: String, + pub system_arch: String, +} + +impl Debug for PlatformSpecification { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!( + f, + "System Name: {}\nSystem Version: {}\nSystem kernel Version: {}\nSystem Arch: {}", + self.system_name, self.system_version, self.system_kernel_version, self.system_arch + ) + } +} \ No newline at end of file diff --git a/clash-verge-rev/src-tauri/src/module/api/common.rs b/clash-verge-rev/src-tauri/src/module/api/common.rs new file mode 100644 index 0000000000..dab4cc6966 --- /dev/null +++ b/clash-verge-rev/src-tauri/src/module/api/common.rs @@ -0,0 +1,70 @@ +use crate::model::api::common::ApiCaller; +use async_trait::async_trait; +use reqwest::{ + header::{HeaderMap, HeaderName, HeaderValue}, + RequestBuilder, +}; +use serde::de::DeserializeOwned; + +impl<'a> ApiCaller<'a> { + pub async fn send_request( + &self, + method: &str, + path: &str, + body: Option<&str>, + headers: Option>, + ) -> Result { + let full_url = format!("{}{}", self.url, path); // 拼接完整 URL + let mut request: RequestBuilder = match method { + "GET" => self.client.get(&full_url), + "POST" => self + .client + .post(&full_url) + .body(body.unwrap_or("").to_string()), + "PUT" => self + .client + .put(&full_url) + .body(body.unwrap_or("").to_string()), + "DELETE" => self.client.delete(&full_url), + _ => return Err("Unsupported HTTP method".to_string()), + }; + + // 处理 headers + if let Some(hdrs) = headers { + let mut header_map = HeaderMap::new(); + for (key, value) in hdrs { + if let (Ok(header_name), Ok(header_value)) = ( + HeaderName::from_bytes(key.as_bytes()), + HeaderValue::from_str(value), + ) { + header_map.insert(header_name, header_value); + } + } + request = request.headers(header_map); + } + + let response = request.send().await.map_err(|e| e.to_string())?; + response.text().await.map_err(|e| e.to_string()) + } +} + +#[allow(unused)] +#[async_trait] +pub trait ApiCallerTrait: Send + Sync { + async fn call_api( + &self, + method: &str, + path: &str, + body: Option<&str>, + headers: Option> + ) -> Result + where + T: DeserializeOwned + Send + Sync; + + fn parse_json_response(json_str: &str) -> Result + where + T: DeserializeOwned, + { + serde_json::from_str(json_str).map_err(|e| e.to_string()) + } +} diff --git a/clash-verge-rev/src-tauri/src/module/api/mihomo.rs b/clash-verge-rev/src-tauri/src/module/api/mihomo.rs new file mode 100644 index 0000000000..09b6d0faed --- /dev/null +++ b/clash-verge-rev/src-tauri/src/module/api/mihomo.rs @@ -0,0 +1,108 @@ +use super::common::ApiCallerTrait; +use crate::config::api::mihomo::MIHOMO_URL; +use crate::model::api::common::ApiCaller; +use crate::model::api::mihomo::MihomoAPICaller; + +use async_trait::async_trait; +use once_cell::sync::OnceCell; +use parking_lot::RwLock; +use reqwest::Client; +use serde::de::DeserializeOwned; +use std::sync::Arc; + +impl MihomoAPICaller { + #[allow(dead_code)] + pub fn new() -> Arc> { + static INSTANCE: OnceCell>> = OnceCell::new(); + INSTANCE + .get_or_init(|| { + let client = Client::new(); + Arc::new(RwLock::new(MihomoAPICaller { + caller: ApiCaller { + url: MIHOMO_URL, + client, + }, + })) + }) + .clone() + } +} + +#[async_trait] +impl ApiCallerTrait for MihomoAPICaller { + async fn call_api( + &self, + method: &str, + path: &str, + body: Option<&str>, + headers: Option>, + ) -> Result + where + T: DeserializeOwned + Send + Sync, + { + let response = self + .caller + .send_request(method, path, body, headers) + .await + .map_err(|e| e.to_string())?; + Self::parse_json_response::(&response) + } +} + +#[allow(unused)] +impl MihomoAPICaller { + pub async fn get_proxies() -> Result { + Self::new() + .read() + .call_api("GET", "/proxies", None, None) + .await + } + + pub async fn get_providers_proxies() -> Result { + Self::new() + .read() + .call_api("GET", "/providers/proxies", None, None) + .await + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + async fn test_mihomo_api_singleton() { + let mihomo_api_caller1 = MihomoAPICaller::new(); + let mihomo_api_caller2 = MihomoAPICaller::new(); + assert!(Arc::ptr_eq(&mihomo_api_caller1, &mihomo_api_caller2)); + } + + #[tokio::test] + async fn test_mihomo_api_version() { + let mihomo_caller = MihomoAPICaller::new(); + let response: Result = mihomo_caller + .read() + .call_api("GET", "/version", None, None) + .await; + assert!(response.is_ok()); + } + + #[tokio::test] + async fn test_mihomo_get_proxies() { + let response = MihomoAPICaller::get_proxies().await; + assert!(response.is_ok()); + if let Ok(proxies) = &response { + assert!(!proxies.get("proxies").is_none()); + } + } + + #[tokio::test] + async fn test_mihomo_get_providers_proxies() { + let response = MihomoAPICaller::get_providers_proxies().await; + println!("{:?}", response); + assert!(response.is_ok()); + if let Ok(providers_proxies) = &response { + assert!(!providers_proxies.get("providers").is_none()); + } + } +} diff --git a/clash-verge-rev/src-tauri/src/module/api/mod.rs b/clash-verge-rev/src-tauri/src/module/api/mod.rs new file mode 100644 index 0000000000..bee8fa981c --- /dev/null +++ b/clash-verge-rev/src-tauri/src/module/api/mod.rs @@ -0,0 +1,2 @@ +pub mod common; +pub mod mihomo; diff --git a/clash-verge-rev/src-tauri/src/module/mihomo.rs b/clash-verge-rev/src-tauri/src/module/mihomo.rs new file mode 100644 index 0000000000..c1201d91ce --- /dev/null +++ b/clash-verge-rev/src-tauri/src/module/mihomo.rs @@ -0,0 +1,158 @@ +use crate::model::api::mihomo::MihomoAPICaller; +use once_cell::sync::OnceCell; +use parking_lot::RwLock; +use std::sync::Arc; + +#[allow(unused)] +pub struct MihomoManager { + proxies: serde_json::Value, + providers_proxies: serde_json::Value, +} + +#[allow(unused)] +impl MihomoManager { + pub fn new() -> Arc> { + static INSTANCE: OnceCell>> = OnceCell::new(); + INSTANCE + .get_or_init(|| { + Arc::new(RwLock::new(MihomoManager { + proxies: serde_json::Value::Null, + providers_proxies: serde_json::Value::Null, + })) + }) + .clone() + } + + pub fn fetch_proxies(&self) -> &serde_json::Value { + &self.proxies + } + + pub fn fetch_providers_proxies(&self) -> &serde_json::Value { + &self.providers_proxies + } + + pub async fn refresh_proxies(&mut self) { + match MihomoAPICaller::get_proxies().await { + Ok(proxies) => { + self.proxies = proxies; + } + Err(e) => { + log::error!("Failed to get proxies: {}", e); + } + } + } + + pub async fn refresh_providers_proxies(&mut self) { + match MihomoAPICaller::get_providers_proxies().await { + Ok(providers_proxies) => { + self.providers_proxies = providers_proxies; + }, + Err(e) => { + log::error!("Failed to get providers proxies: {}", e); + }, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + #[tokio::test] + async fn test_mihomo_manager_singleton() { + let manager1 = MihomoManager::new(); + let manager2 = MihomoManager::new(); + + assert!( + Arc::ptr_eq(&manager1, &manager2), + "Should return same instance" + ); + + let manager = manager1.read(); + assert!(manager.proxies.is_null()); + assert!(manager.providers_proxies.is_null()); + } + + #[tokio::test] + async fn test_refresh_proxies() { + let manager = MihomoManager::new(); + + // Test initial state + { + let data = manager.read(); + assert!(data.proxies.is_null()); + } + + // Test refresh + { + let mut data = manager.write(); + data.refresh_proxies().await; + // Note: Since this depends on external API call, + // we can only verify that the refresh call completes + // without panicking. For more thorough testing, + // we would need to mock the API caller. + } + } + + #[tokio::test] + async fn test_refresh_providers_proxies() { + let manager = MihomoManager::new(); + + // Test initial state + { + let data = manager.read(); + assert!(data.providers_proxies.is_null()); + } + + // Test refresh + { + let mut data = manager.write(); + data.refresh_providers_proxies().await; + // Note: Since this depends on external API call, + // we can only verify that the refresh call completes + // without panicking. For more thorough testing, + // we would need to mock the API caller. + } + } + + #[tokio::test] + async fn test_fetch_proxies() { + let manager = MihomoManager::new(); + + // Test initial state + { + let data = manager.read(); + let proxies = data.fetch_proxies(); + assert!(proxies.is_null()); + } + + // Test after refresh + { + let mut data = manager.write(); + data.refresh_proxies().await; + let _proxies = data.fetch_proxies(); + // Can only verify the method returns without panicking + // Would need API mocking for more thorough testing + } + } + + #[tokio::test] + async fn test_fetch_providers_proxies() { + let manager = MihomoManager::new(); + + // Test initial state + { + let data = manager.read(); + let providers_proxies = data.fetch_providers_proxies(); + assert!(providers_proxies.is_null()); + } + + // Test after refresh + { + let mut data = manager.write(); + data.refresh_providers_proxies().await; + let _providers_proxies = data.fetch_providers_proxies(); + // Can only verify the method returns without panicking + // Would need API mocking for more thorough testing + } + } +} diff --git a/clash-verge-rev/src-tauri/src/module/mod.rs b/clash-verge-rev/src-tauri/src/module/mod.rs new file mode 100644 index 0000000000..0692611ce4 --- /dev/null +++ b/clash-verge-rev/src-tauri/src/module/mod.rs @@ -0,0 +1,3 @@ +pub mod api; +pub mod sysinfo; +pub mod mihomo; \ No newline at end of file diff --git a/clash-verge-rev/src-tauri/src/module/sysinfo.rs b/clash-verge-rev/src-tauri/src/module/sysinfo.rs new file mode 100644 index 0000000000..9908f6ccb1 --- /dev/null +++ b/clash-verge-rev/src-tauri/src/module/sysinfo.rs @@ -0,0 +1,19 @@ +use crate::model::sysinfo::PlatformSpecification; + +use sysinfo::System; + +impl PlatformSpecification { + pub fn new() -> Self { + let system_name = System::name().unwrap_or("Null".into()); + let system_version = System::long_os_version().unwrap_or("Null".into()); + let system_kernel_version = System::kernel_version().unwrap_or("Null".into()); + let system_arch = std::env::consts::ARCH.to_string(); + + Self { + system_name, + system_version, + system_kernel_version, + system_arch + } + } +} diff --git a/clash-verge-rev/src-tauri/src/utils/help.rs b/clash-verge-rev/src-tauri/src/utils/help.rs index 439aca931c..adb9b69c01 100644 --- a/clash-verge-rev/src-tauri/src/utils/help.rs +++ b/clash-verge-rev/src-tauri/src/utils/help.rs @@ -205,10 +205,11 @@ macro_rules! t { /// 支持 B/s、KB/s、MB/s、GB/s 的自动转换 /// /// # Examples +/// ```not_run +/// format_bytes_speed(1000) // returns "1000B/s" +/// format_bytes_speed(1024) // returns "1.0KB/s" +/// format_bytes_speed(1024 * 1024) // returns "1.0MB/s" /// ``` -/// assert_eq!(format_bytes_speed(1000), "1000B/s"); -/// assert_eq!(format_bytes_speed(1024), "1.0KB/s"); -/// assert_eq!(format_bytes_speed(1024 * 1024), "1.0MB/s"); /// ``` #[cfg(target_os = "macos")] pub fn format_bytes_speed(speed: u64) -> String { diff --git a/clash-verge-rev/src-tauri/src/utils/resolve.rs b/clash-verge-rev/src-tauri/src/utils/resolve.rs index 88844c77ed..f8b6fe34a8 100644 --- a/clash-verge-rev/src-tauri/src/utils/resolve.rs +++ b/clash-verge-rev/src-tauri/src/utils/resolve.rs @@ -77,14 +77,12 @@ pub async fn resolve_setup(app: &mut App) { } } if !service_runing { - log::error!(target: "app", "service not runing. exit"); - app.app_handle().exit(-2); + log::warn!(target: "app", "service not running, will fallback to user mode"); } } } Err(e) => { - log::error!(target: "app", "{e:?}"); - app.app_handle().exit(-1); + log::warn!(target: "app", "failed to install service: {e:?}, will fallback to user mode"); } } } diff --git a/clash-verge-rev/src/components/proxy/proxy-groups.tsx b/clash-verge-rev/src/components/proxy/proxy-groups.tsx index b0f78bbd84..adec9da745 100644 --- a/clash-verge-rev/src/components/proxy/proxy-groups.tsx +++ b/clash-verge-rev/src/components/proxy/proxy-groups.tsx @@ -508,13 +508,8 @@ export const ProxyGroups = (props: Props) => { )} /> - + +
{groupFirstLetters.map((name) => ( diff --git a/clash-verge-rev/src/components/proxy/proxy-render.tsx b/clash-verge-rev/src/components/proxy/proxy-render.tsx index 57190129b5..7a18b01d10 100644 --- a/clash-verge-rev/src/components/proxy/proxy-render.tsx +++ b/clash-verge-rev/src/components/proxy/proxy-render.tsx @@ -66,8 +66,8 @@ export const ProxyRender = (props: RenderProps) => { style={{ background: itembackgroundcolor, height: "100%", - margin: "10px 16px", - borderRadius: "10px", + margin: "8px 8px", + borderRadius: "8px", }} onClick={() => onHeadState(group.name, { open: !headState?.open })} > @@ -131,7 +131,7 @@ export const ProxyRender = (props: RenderProps) => { if (type === 1) { return ( { sx={{ height: 56, display: "grid", - gap: 1.5, - pl: 3, - pr: 3.5, - pb: 1.25, + gap: 1, + pl: 2, + pr: 2, + pb: 1, gridTemplateColumns: `repeat(${item.col! || 2}, 1fr)`, }} > diff --git a/clash-verge-rev/src/components/setting/setting-system.tsx b/clash-verge-rev/src/components/setting/setting-system.tsx index 3e13b14403..fdb4325b40 100644 --- a/clash-verge-rev/src/components/setting/setting-system.tsx +++ b/clash-verge-rev/src/components/setting/setting-system.tsx @@ -5,6 +5,8 @@ import { SettingsRounded, PlayArrowRounded, PauseRounded, + WarningRounded, + BuildRounded, } from "@mui/icons-material"; import { useVerge } from "@/hooks/use-verge"; import { DialogRef, Notice, Switch } from "@/components/base"; @@ -13,7 +15,14 @@ import { GuardState } from "./mods/guard-state"; import { SysproxyViewer } from "./mods/sysproxy-viewer"; import { TunViewer } from "./mods/tun-viewer"; import { TooltipIcon } from "@/components/base/base-tooltip-icon"; -import { getSystemProxy, getAutotemProxy } from "@/services/cmds"; +import { + getSystemProxy, + getAutotemProxy, + getRunningMode, + installService, +} from "@/services/cmds"; +import { useLockFn } from "ahooks"; +import { Box, Button, Tooltip } from "@mui/material"; interface Props { onError?: (err: Error) => void; @@ -26,6 +35,13 @@ const SettingSystem = ({ onError }: Props) => { const { data: sysproxy } = useSWR("getSystemProxy", getSystemProxy); const { data: autoproxy } = useSWR("getAutotemProxy", getAutotemProxy); + const { data: runningMode, mutate: mutateRunningMode } = useSWR( + "getRunningMode", + getRunningMode, + ); + + // 是否以sidecar模式运行 + const isSidecarMode = runningMode === "sidecar"; const sysproxyRef = useRef(null); const tunRef = useRef(null); @@ -54,6 +70,19 @@ const SettingSystem = ({ onError }: Props) => { await mutate("getAutotemProxy"); }; + // 安装系统服务 + const onInstallService = useLockFn(async () => { + try { + Notice.info(t("Installing Service..."), 1000); + await installService(); + Notice.success(t("Service Installed Successfully"), 2000); + // 重新获取运行模式 + await mutateRunningMode(); + } catch (err: any) { + Notice.error(err.message || err.toString(), 3000); + } + }); + return ( @@ -62,11 +91,31 @@ const SettingSystem = ({ onError }: Props) => { tunRef.current?.open()} - /> + <> + tunRef.current?.open()} + /> + {isSidecarMode && ( + + + + )} + {isSidecarMode && ( + + + + )} + } > { onCatch={onError} onFormat={onSwitchFormat} onChange={(e) => { + // 当在sidecar模式下禁用切换 + if (isSidecarMode) return; onChangeData({ enable_tun_mode: e }); }} onGuard={(e) => { + // 当在sidecar模式下禁用切换 + if (isSidecarMode) { + Notice.error(t("TUN requires Service Mode"), 2000); + return Promise.reject(new Error(t("TUN requires Service Mode"))); + } return patchVerge({ enable_tun_mode: e }); }} > - + void; @@ -51,6 +53,11 @@ const SettingVergeAdvanced = ({ onError }: Props) => { } }; + const onExportDiagnosticInfo = useCallback(async () => { + await exportDiagnosticInfo(); + Notice.success(t("Copy Success"), 1000); + }, []); + return ( @@ -111,6 +118,16 @@ const SettingVergeAdvanced = ({ onError }: Props) => { label={t("Exit")} /> + + } + > + v{version} diff --git a/clash-verge-rev/src/locales/en.json b/clash-verge-rev/src/locales/en.json index e5e1ff6b72..a9ef453285 100644 --- a/clash-verge-rev/src/locales/en.json +++ b/clash-verge-rev/src/locales/en.json @@ -195,6 +195,8 @@ "Settings": "Settings", "System Setting": "System Setting", "Tun Mode": "Tun (Virtual NIC) Mode", + "TUN requires Service Mode": "TUN mode requires service", + "Install Service": "Install Service", "Reset to Default": "Reset to Default", "Tun Mode Info": "Tun (Virtual NIC) mode: Captures all system traffic, when enabled, there is no need to enable system proxy.", "Stack": "Tun Stack", @@ -349,6 +351,8 @@ "Portable Updater Error": "The portable version does not support in-app updates. Please manually download and replace it", "Break Change Update Error": "This version is a major update and does not support in-app updates. Please uninstall it and manually download and install the new version", "Open Dev Tools": "Dev Tools", + "Export Diagnostic Info": "Export Diagnostic Info", + "Export Diagnostic Info For Issue Reporting": "Export Diagnostic Info For Issue Reporting", "Exit": "Exit", "Verge Version": "Verge Version", "ReadOnly": "ReadOnly", @@ -363,6 +367,7 @@ "Profile Reactivated": "Profile Reactivated", "Only YAML Files Supported": "Only YAML Files Supported", "Settings Applied": "Settings Applied", + "Installing Service...": "Installing Service...", "Service Installed Successfully": "Service Installed Successfully", "Service Uninstalled Successfully": "Service Uninstalled Successfully", "Proxy Daemon Duration Cannot be Less than 1 Second": "Proxy Daemon Duration Cannot be Less than 1 Second", diff --git a/clash-verge-rev/src/locales/zh.json b/clash-verge-rev/src/locales/zh.json index b0e3472f63..288b5df6ab 100644 --- a/clash-verge-rev/src/locales/zh.json +++ b/clash-verge-rev/src/locales/zh.json @@ -195,6 +195,8 @@ "Settings": "设置", "System Setting": "系统设置", "Tun Mode": "TUN(虚拟网卡)模式", + "TUN requires Service Mode": "TUN 模式需要服务", + "Install Service": "安装服务", "Reset to Default": "重置为默认值", "Tun Mode Info": "TUN(虚拟网卡)模式接管系统所有流量,启用时无须打开系统代理", "Stack": "TUN 模式堆栈", @@ -362,6 +364,7 @@ "Profile Reactivated": "订阅已激活", "Only YAML Files Supported": "仅支持 YAML 文件", "Settings Applied": "设置已应用", + "Installing Service...": "安装服务中...", "Service Installed Successfully": "已成功安装服务", "Service Uninstalled Successfully": "已成功卸载服务", "Proxy Daemon Duration Cannot be Less than 1 Second": "代理守护间隔时间不得低于 1 秒", diff --git a/clash-verge-rev/src/services/api.ts b/clash-verge-rev/src/services/api.ts index 2eec99d9cc..328849a774 100644 --- a/clash-verge-rev/src/services/api.ts +++ b/clash-verge-rev/src/services/api.ts @@ -1,5 +1,7 @@ import axios, { AxiosInstance } from "axios"; import { getClashInfo } from "./cmds"; +import { invoke } from "@tauri-apps/api/core"; +import { useLockFn } from "ahooks"; let axiosIns: AxiosInstance = null!; @@ -94,13 +96,20 @@ export const updateProxy = async (group: string, proxy: string) => { // get proxy export const getProxiesInner = async () => { - const instance = await getAxios(); - const response = await instance.get("/proxies"); - return (response?.proxies || {}) as Record; + const response = await invoke<{ proxies: Record }>( + "get_proxies", + ); + return response.proxies as Record; }; /// Get the Proxy information -export const getProxies = async () => { +export const getProxies = async (): Promise<{ + global: IProxyGroupItem; + direct: IProxyItem; + groups: IProxyGroupItem[]; + records: Record; + proxies: IProxyItem[]; +}> => { const [proxyRecord, providerRecord] = await Promise.all([ getProxiesInner(), getProxyProviders(), @@ -181,13 +190,10 @@ export const getProxies = async () => { // get proxy providers export const getProxyProviders = async () => { - const instance = await getAxios(); - const response = await instance.get("/providers/proxies"); - - const providers = (response.providers || {}) as Record< - string, - IProxyProviderItem - >; + const response = await invoke<{ + providers: Record; + }>("get_providers_proxies"); + const providers = response.providers as Record; return Object.fromEntries( Object.entries(providers).filter(([key, item]) => { diff --git a/clash-verge-rev/src/services/cmds.ts b/clash-verge-rev/src/services/cmds.ts index f0ce4c1425..3104183f0e 100644 --- a/clash-verge-rev/src/services/cmds.ts +++ b/clash-verge-rev/src/services/cmds.ts @@ -191,6 +191,10 @@ export async function exitApp() { return invoke("exit_app"); } +export async function exportDiagnosticInfo() { + return invoke("export_diagnostic_info"); +} + export async function copyIconFile( path: string, name: "common" | "sysproxy" | "tun", @@ -249,3 +253,13 @@ export async function scriptValidateNotice(status: string, msg: string) { export async function validateScriptFile(filePath: string) { return invoke("validate_script_file", { filePath }); } + +// 获取当前运行模式 +export const getRunningMode = async () => { + return invoke("get_running_mode"); +}; + +// 安装/重装系统服务 +export const installService = async () => { + return invoke("install_service"); +}; diff --git a/lede/package/boot/uboot-rockchip/Makefile b/lede/package/boot/uboot-rockchip/Makefile index d026290117..ff9a80fb32 100644 --- a/lede/package/boot/uboot-rockchip/Makefile +++ b/lede/package/boot/uboot-rockchip/Makefile @@ -183,6 +183,35 @@ define U-Boot/sv901-eaio-rk3399 USE_RKBIN:=1 endef +# RK3528 boards + +define U-Boot/rk3528/Default + BUILD_SUBTARGET:=armv8 + DEPENDS:=+PACKAGE_u-boot-$(1):rkbin-rk3528 + ATF:=rk3528_bl31_v1.17.elf + TPL:=rk3528_ddr_1056MHz_v1.10.bin +endef + +define U-Boot/generic-rk3528 + $(U-Boot/rk3528/Default) + NAME:=GENERIC RK3528 + BUILD_DEVICES:= \ + armsom_sige1 \ + hinlink_opc-h28k \ + hinlink_opc-h29k \ + hinlink_opc-ht2 \ + widora_mangopi-m28c \ + widora_mangopi-m28k \ + widora_mangopi-m28k-pro +endef + +define U-Boot/radxa-e20c-rk3528 + $(U-Boot/rk3528/Default) + NAME:=Radxa E20C + BUILD_DEVICES:= \ + radxa_e20c +endef + # RK3566 boards define U-Boot/rk3566/Default @@ -384,6 +413,8 @@ define U-Boot/rock5a-rk3588s endef UBOOT_TARGETS := \ + generic-rk3528 \ + radxa-e20c-rk3528 \ nanopi-r3s-rk3566 \ panther-x2-rk3566 \ rock-3c-rk3566 \ diff --git a/lede/package/boot/uboot-rockchip/patches/400-arm64-dts-rockchip-Add-base-DT-for-rk3528-SoC.patch b/lede/package/boot/uboot-rockchip/patches/400-arm64-dts-rockchip-Add-base-DT-for-rk3528-SoC.patch new file mode 100644 index 0000000000..4958b3c0e8 --- /dev/null +++ b/lede/package/boot/uboot-rockchip/patches/400-arm64-dts-rockchip-Add-base-DT-for-rk3528-SoC.patch @@ -0,0 +1,210 @@ +From 7983e6c379a917c500eff31f5f9c646cc408e030 Mon Sep 17 00:00:00 2001 +From: Yao Zi +Date: Thu, 29 Aug 2024 09:27:04 +0000 +Subject: [PATCH] arm64: dts: rockchip: Add base DT for rk3528 SoC + +This initial device tree describes CPU, interrupts and UART on the chip +and is able to boot into basic kernel with only UART. Cache information +is omitted for now as there is no precise documentation. Support for +other features will be added later. + +Signed-off-by: Yao Zi +Link: https://lore.kernel.org/r/20240829092705.6241-4-ziyao@disroot.org +Signed-off-by: Heiko Stuebner +--- + arch/arm64/boot/dts/rockchip/rk3528.dtsi | 189 +++++++++++++++++++++++ + 1 file changed, 189 insertions(+) + create mode 100644 arch/arm64/boot/dts/rockchip/rk3528.dtsi + +--- /dev/null ++++ b/dts/upstream/src/arm64/rockchip/rk3528.dtsi +@@ -0,0 +1,189 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright (c) 2022 Rockchip Electronics Co., Ltd. ++ * Copyright (c) 2024 Yao Zi ++ */ ++ ++#include ++#include ++ ++/ { ++ compatible = "rockchip,rk3528"; ++ ++ interrupt-parent = <&gic>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ aliases { ++ serial0 = &uart0; ++ serial1 = &uart1; ++ serial2 = &uart2; ++ serial3 = &uart3; ++ serial4 = &uart4; ++ serial5 = &uart5; ++ serial6 = &uart6; ++ serial7 = &uart7; ++ }; ++ ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cpu-map { ++ cluster0 { ++ core0 { ++ cpu = <&cpu0>; ++ }; ++ core1 { ++ cpu = <&cpu1>; ++ }; ++ core2 { ++ cpu = <&cpu2>; ++ }; ++ core3 { ++ cpu = <&cpu3>; ++ }; ++ }; ++ }; ++ ++ cpu0: cpu@0 { ++ compatible = "arm,cortex-a53"; ++ reg = <0x0>; ++ device_type = "cpu"; ++ enable-method = "psci"; ++ }; ++ ++ cpu1: cpu@1 { ++ compatible = "arm,cortex-a53"; ++ reg = <0x1>; ++ device_type = "cpu"; ++ enable-method = "psci"; ++ }; ++ ++ cpu2: cpu@2 { ++ compatible = "arm,cortex-a53"; ++ reg = <0x2>; ++ device_type = "cpu"; ++ enable-method = "psci"; ++ }; ++ ++ cpu3: cpu@3 { ++ compatible = "arm,cortex-a53"; ++ reg = <0x3>; ++ device_type = "cpu"; ++ enable-method = "psci"; ++ }; ++ }; ++ ++ psci { ++ compatible = "arm,psci-1.0", "arm,psci-0.2"; ++ method = "smc"; ++ }; ++ ++ timer { ++ compatible = "arm,armv8-timer"; ++ interrupts = , ++ , ++ , ++ ; ++ }; ++ ++ xin24m: clock-xin24m { ++ compatible = "fixed-clock"; ++ clock-frequency = <24000000>; ++ clock-output-names = "xin24m"; ++ #clock-cells = <0>; ++ }; ++ ++ soc { ++ compatible = "simple-bus"; ++ ranges = <0x0 0xfe000000 0x0 0xfe000000 0x0 0x2000000>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ gic: interrupt-controller@fed01000 { ++ compatible = "arm,gic-400"; ++ reg = <0x0 0xfed01000 0 0x1000>, ++ <0x0 0xfed02000 0 0x2000>, ++ <0x0 0xfed04000 0 0x2000>, ++ <0x0 0xfed06000 0 0x2000>; ++ interrupts = ; ++ interrupt-controller; ++ #address-cells = <0>; ++ #interrupt-cells = <3>; ++ }; ++ ++ uart0: serial@ff9f0000 { ++ compatible = "rockchip,rk3528-uart", "snps,dw-apb-uart"; ++ reg = <0x0 0xff9f0000 0x0 0x100>; ++ clock-frequency = <24000000>; ++ interrupts = ; ++ reg-io-width = <4>; ++ reg-shift = <2>; ++ status = "disabled"; ++ }; ++ ++ uart1: serial@ff9f8000 { ++ compatible = "rockchip,rk3528-uart", "snps,dw-apb-uart"; ++ reg = <0x0 0xff9f8000 0x0 0x100>; ++ interrupts = ; ++ reg-io-width = <4>; ++ reg-shift = <2>; ++ status = "disabled"; ++ }; ++ ++ uart2: serial@ffa00000 { ++ compatible = "rockchip,rk3528-uart", "snps,dw-apb-uart"; ++ reg = <0x0 0xffa00000 0x0 0x100>; ++ interrupts = ; ++ reg-io-width = <4>; ++ reg-shift = <2>; ++ status = "disabled"; ++ }; ++ ++ uart3: serial@ffa08000 { ++ compatible = "rockchip,rk3528-uart", "snps,dw-apb-uart"; ++ reg = <0x0 0xffa08000 0x0 0x100>; ++ reg-io-width = <4>; ++ reg-shift = <2>; ++ status = "disabled"; ++ }; ++ ++ uart4: serial@ffa10000 { ++ compatible = "rockchip,rk3528-uart", "snps,dw-apb-uart"; ++ reg = <0x0 0xffa10000 0x0 0x100>; ++ interrupts = ; ++ reg-io-width = <4>; ++ reg-shift = <2>; ++ status = "disabled"; ++ }; ++ ++ uart5: serial@ffa18000 { ++ compatible = "rockchip,rk3528-uart", "snps,dw-apb-uart"; ++ reg = <0x0 0xffa18000 0x0 0x100>; ++ interrupts = ; ++ reg-io-width = <4>; ++ reg-shift = <2>; ++ status = "disabled"; ++ }; ++ ++ uart6: serial@ffa20000 { ++ compatible = "rockchip,rk3528-uart", "snps,dw-apb-uart"; ++ reg = <0x0 0xffa20000 0x0 0x100>; ++ interrupts = ; ++ reg-io-width = <4>; ++ reg-shift = <2>; ++ status = "disabled"; ++ }; ++ ++ uart7: serial@ffa28000 { ++ compatible = "rockchip,rk3528-uart", "snps,dw-apb-uart"; ++ reg = <0x0 0xffa28000 0x0 0x100>; ++ interrupts = ; ++ reg-io-width = <4>; ++ reg-shift = <2>; ++ status = "disabled"; ++ }; ++ }; ++}; diff --git a/lede/package/boot/uboot-rockchip/patches/401-rockchip-mkimage-Add-support-for-RK3528.patch b/lede/package/boot/uboot-rockchip/patches/401-rockchip-mkimage-Add-support-for-RK3528.patch new file mode 100644 index 0000000000..16598df0b4 --- /dev/null +++ b/lede/package/boot/uboot-rockchip/patches/401-rockchip-mkimage-Add-support-for-RK3528.patch @@ -0,0 +1,26 @@ +From 37a4c7f5fb6e75e248e84500f27d3945c502e381 Mon Sep 17 00:00:00 2001 +From: Yifeng Zhao +Date: Thu, 23 Jan 2025 22:48:13 +0000 +Subject: [PATCH 1/9] rockchip: mkimage: Add support for RK3528 + +Add support for generating Rockchip Boot Image for RK3528. + +Similar to RK3568, the RK3528 has 64 KiB SRAM and 4 KiB of it is +reserved for BootROM. + +Signed-off-by: Yifeng Zhao +Signed-off-by: Jonas Karlman +--- + tools/rkcommon.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/tools/rkcommon.c ++++ b/tools/rkcommon.c +@@ -134,6 +134,7 @@ static struct spl_info spl_infos[] = { + { "rk3399", "RK33", 0x30000 - 0x2000, false, RK_HEADER_V1 }, + { "rv1108", "RK11", 0x1800, false, RK_HEADER_V1 }, + { "rv1126", "110B", 0x10000 - 0x1000, false, RK_HEADER_V1 }, ++ { "rk3528", "RK35", 0x10000 - 0x1000, false, RK_HEADER_V2 }, + { "rk3568", "RK35", 0x10000 - 0x1000, false, RK_HEADER_V2 }, + { "rk3588", "RK35", 0x100000 - 0x1000, false, RK_HEADER_V2 }, + }; diff --git a/lede/package/boot/uboot-rockchip/patches/402-arch-arm-rockchip-Add-initial-support-for-RK3528.patch b/lede/package/boot/uboot-rockchip/patches/402-arch-arm-rockchip-Add-initial-support-for-RK3528.patch new file mode 100644 index 0000000000..97d71c6ef3 --- /dev/null +++ b/lede/package/boot/uboot-rockchip/patches/402-arch-arm-rockchip-Add-initial-support-for-RK3528.patch @@ -0,0 +1,372 @@ +From f6c7b9632a51e6c29a8be4e4e6d137a511fbf3fb Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Thu, 23 Jan 2025 22:48:14 +0000 +Subject: [PATCH 2/9] arch: arm: rockchip: Add initial support for RK3528 + +Rockchip RK3528 is a ARM-based SoC with quad-core Cortex-A53. + +Add initial arch support for the RK3528 SoC. + +Signed-off-by: Jonas Karlman +--- + arch/arm/include/asm/arch-rk3528/boot0.h | 9 ++ + arch/arm/include/asm/arch-rk3528/gpio.h | 9 ++ + arch/arm/mach-rockchip/Kconfig | 50 +++++++ + arch/arm/mach-rockchip/Makefile | 1 + + arch/arm/mach-rockchip/rk3528/Kconfig | 15 ++ + arch/arm/mach-rockchip/rk3528/Makefile | 4 + + arch/arm/mach-rockchip/rk3528/rk3528.c | 137 ++++++++++++++++++ + arch/arm/mach-rockchip/rk3528/syscon_rk3528.c | 19 +++ + drivers/usb/gadget/Kconfig | 1 + + include/configs/rk3528_common.h | 42 ++++++ + 10 files changed, 287 insertions(+) + create mode 100644 arch/arm/include/asm/arch-rk3528/boot0.h + create mode 100644 arch/arm/include/asm/arch-rk3528/gpio.h + create mode 100644 arch/arm/mach-rockchip/rk3528/Kconfig + create mode 100644 arch/arm/mach-rockchip/rk3528/Makefile + create mode 100644 arch/arm/mach-rockchip/rk3528/rk3528.c + create mode 100644 arch/arm/mach-rockchip/rk3528/syscon_rk3528.c + create mode 100644 include/configs/rk3528_common.h + +--- /dev/null ++++ b/arch/arm/include/asm/arch-rk3528/boot0.h +@@ -0,0 +1,9 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* Copyright Contributors to the U-Boot project. */ ++ ++#ifndef __ASM_ARCH_BOOT0_H__ ++#define __ASM_ARCH_BOOT0_H__ ++ ++#include ++ ++#endif +--- /dev/null ++++ b/arch/arm/include/asm/arch-rk3528/gpio.h +@@ -0,0 +1,9 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* Copyright Contributors to the U-Boot project. */ ++ ++#ifndef __ASM_ARCH_GPIO_H__ ++#define __ASM_ARCH_GPIO_H__ ++ ++#include ++ ++#endif +--- a/arch/arm/mach-rockchip/Kconfig ++++ b/arch/arm/mach-rockchip/Kconfig +@@ -309,6 +309,55 @@ config ROCKCHIP_RK3399 + and video codec support. Peripherals include Gigabit Ethernet, + USB2 host and OTG, SDIO, I2S, UARTs, SPI, I2C and PWMs. + ++config ROCKCHIP_RK3528 ++ bool "Support Rockchip RK3528" ++ select ARM64 ++ select SUPPORT_SPL ++ select SPL ++ select CLK ++ select PINCTRL ++ select RAM ++ select REGMAP ++ select SYSCON ++ select BOARD_LATE_INIT ++ select DM_REGULATOR_FIXED ++ select DM_RESET ++ imply ARMV8_CRYPTO ++ imply ARMV8_SET_SMPEN ++ imply BOOTSTD_FULL ++ imply DM_RNG ++ imply FIT ++ imply LEGACY_IMAGE_FORMAT ++ imply MISC ++ imply MISC_INIT_R ++ imply MMC_HS200_SUPPORT if MMC_SDHCI_ROCKCHIP ++ imply OF_LIBFDT_OVERLAY ++ imply OF_LIVE ++ imply OF_UPSTREAM ++ imply PHY_GIGE if DWC_ETH_QOS_ROCKCHIP ++ imply RNG_ROCKCHIP ++ imply ROCKCHIP_COMMON_BOARD ++ imply ROCKCHIP_COMMON_STACK_ADDR ++ imply ROCKCHIP_EXTERNAL_TPL ++ imply ROCKCHIP_OTP ++ imply SPL_ATF ++ imply SPL_ATF_NO_PLATFORM_PARAM if SPL_ATF ++ imply SPL_CLK ++ imply SPL_DM_SEQ_ALIAS ++ imply SPL_FIT_SIGNATURE ++ imply SPL_LOAD_FIT ++ imply SPL_MMC_HS200_SUPPORT if SPL_MMC && MMC_HS200_SUPPORT ++ imply SPL_OF_CONTROL ++ imply SPL_PINCTRL ++ imply SPL_RAM ++ imply SPL_REGMAP ++ imply SPL_SERIAL ++ imply SPL_SYSCON ++ imply SYS_RELOC_GD_ENV_ADDR ++ imply SYSRESET ++ help ++ The Rockchip RK3528 is a ARM-based SoC with quad-core Cortex-A53. ++ + config ROCKCHIP_RK3568 + bool "Support Rockchip RK3568" + select ARM64 +@@ -626,6 +675,7 @@ source "arch/arm/mach-rockchip/rk3308/Kc + source "arch/arm/mach-rockchip/rk3328/Kconfig" + source "arch/arm/mach-rockchip/rk3368/Kconfig" + source "arch/arm/mach-rockchip/rk3399/Kconfig" ++source "arch/arm/mach-rockchip/rk3528/Kconfig" + source "arch/arm/mach-rockchip/rk3568/Kconfig" + source "arch/arm/mach-rockchip/rk3588/Kconfig" + source "arch/arm/mach-rockchip/rv1108/Kconfig" +--- a/arch/arm/mach-rockchip/Makefile ++++ b/arch/arm/mach-rockchip/Makefile +@@ -42,6 +42,7 @@ obj-$(CONFIG_ROCKCHIP_RK3308) += rk3308/ + obj-$(CONFIG_ROCKCHIP_RK3328) += rk3328/ + obj-$(CONFIG_ROCKCHIP_RK3368) += rk3368/ + obj-$(CONFIG_ROCKCHIP_RK3399) += rk3399/ ++obj-$(CONFIG_ROCKCHIP_RK3528) += rk3528/ + obj-$(CONFIG_ROCKCHIP_RK3568) += rk3568/ + obj-$(CONFIG_ROCKCHIP_RK3588) += rk3588/ + obj-$(CONFIG_ROCKCHIP_RV1108) += rv1108/ +--- /dev/null ++++ b/arch/arm/mach-rockchip/rk3528/Kconfig +@@ -0,0 +1,15 @@ ++if ROCKCHIP_RK3528 ++ ++config ROCKCHIP_BOOT_MODE_REG ++ default 0xff370200 ++ ++config ROCKCHIP_STIMER_BASE ++ default 0xff620000 ++ ++config SYS_SOC ++ default "rk3528" ++ ++config SYS_CONFIG_NAME ++ default "rk3528_common" ++ ++endif +--- /dev/null ++++ b/arch/arm/mach-rockchip/rk3528/Makefile +@@ -0,0 +1,4 @@ ++# SPDX-License-Identifier: GPL-2.0-or-later ++ ++obj-y += rk3528.o ++obj-y += syscon_rk3528.o +--- /dev/null ++++ b/arch/arm/mach-rockchip/rk3528/rk3528.c +@@ -0,0 +1,137 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++// Copyright Contributors to the U-Boot project. ++ ++#define LOG_CATEGORY LOGC_ARCH ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define FIREWALL_DDR_BASE 0xff2e0000 ++#define FW_DDR_MST6_REG 0x58 ++#define FW_DDR_MST7_REG 0x5c ++#define FW_DDR_MST14_REG 0x78 ++#define FW_DDR_MST16_REG 0x80 ++ ++const char * const boot_devices[BROM_LAST_BOOTSOURCE + 1] = { ++ [BROM_BOOTSOURCE_EMMC] = "/soc/mmc@ffbf0000", ++ [BROM_BOOTSOURCE_SD] = "/soc/mmc@ffc30000", ++}; ++ ++static struct mm_region rk3528_mem_map[] = { ++ { ++ .virt = 0x0UL, ++ .phys = 0x0UL, ++ .size = 0xfc000000UL, ++ .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | ++ PTE_BLOCK_INNER_SHARE ++ }, { ++ .virt = 0xfc000000UL, ++ .phys = 0xfc000000UL, ++ .size = 0x04000000UL, ++ .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | ++ PTE_BLOCK_NON_SHARE | ++ PTE_BLOCK_PXN | PTE_BLOCK_UXN ++ }, { ++ /* List terminator */ ++ 0, ++ } ++}; ++ ++struct mm_region *mem_map = rk3528_mem_map; ++ ++void board_debug_uart_init(void) ++{ ++} ++ ++int arch_cpu_init(void) ++{ ++ u32 val; ++ ++ if (!IS_ENABLED(CONFIG_SPL_BUILD)) ++ return 0; ++ ++ /* Set the emmc to access ddr memory */ ++ val = readl(FIREWALL_DDR_BASE + FW_DDR_MST6_REG); ++ writel(val & 0x0000ffff, FIREWALL_DDR_BASE + FW_DDR_MST6_REG); ++ ++ /* Set the fspi to access ddr memory */ ++ val = readl(FIREWALL_DDR_BASE + FW_DDR_MST7_REG); ++ writel(val & 0xffff0000, FIREWALL_DDR_BASE + FW_DDR_MST7_REG); ++ ++ /* Set the sdmmc to access ddr memory */ ++ val = readl(FIREWALL_DDR_BASE + FW_DDR_MST14_REG); ++ writel(val & 0x0000ffff, FIREWALL_DDR_BASE + FW_DDR_MST14_REG); ++ ++ /* Set the usb to access ddr memory */ ++ val = readl(FIREWALL_DDR_BASE + FW_DDR_MST16_REG); ++ writel(val & 0xffff0000, FIREWALL_DDR_BASE + FW_DDR_MST16_REG); ++ ++ return 0; ++} ++ ++#define HP_TIMER_BASE CONFIG_ROCKCHIP_STIMER_BASE ++#define HP_CTRL_REG 0x04 ++#define TIMER_EN BIT(0) ++#define HP_LOAD_COUNT0_REG 0x14 ++#define HP_LOAD_COUNT1_REG 0x18 ++ ++void rockchip_stimer_init(void) ++{ ++ u32 reg; ++ ++ if (!IS_ENABLED(CONFIG_XPL_BUILD)) ++ return; ++ ++ reg = readl(HP_TIMER_BASE + HP_CTRL_REG); ++ if (reg & TIMER_EN) ++ return; ++ ++ asm volatile("msr cntfrq_el0, %0" : : "r" (CONFIG_COUNTER_FREQUENCY)); ++ writel(0xffffffff, HP_TIMER_BASE + HP_LOAD_COUNT0_REG); ++ writel(0xffffffff, HP_TIMER_BASE + HP_LOAD_COUNT1_REG); ++ writel(TIMER_EN, HP_TIMER_BASE + HP_CTRL_REG); ++} ++ ++#define RK3528_OTP_CPU_CODE_OFFSET 0x02 ++#define RK3528_OTP_CPU_CHIP_TYPE_OFFSET 0x28 ++ ++int checkboard(void) ++{ ++ u8 cpu_code[2], chip_type; ++ struct udevice *dev; ++ char suffix[2]; ++ int ret; ++ ++ if (!IS_ENABLED(CONFIG_ROCKCHIP_OTP) || !CONFIG_IS_ENABLED(MISC)) ++ return 0; ++ ++ ret = uclass_get_device_by_driver(UCLASS_MISC, ++ DM_DRIVER_GET(rockchip_otp), &dev); ++ if (ret) { ++ log_debug("Could not find otp device, ret=%d\n", ret); ++ return 0; ++ } ++ ++ /* cpu-code: SoC model, e.g. 0x35 0x28 */ ++ ret = misc_read(dev, RK3528_OTP_CPU_CODE_OFFSET, cpu_code, 2); ++ if (ret < 0) { ++ log_debug("Could not read cpu-code, ret=%d\n", ret); ++ return 0; ++ } ++ ++ ret = misc_read(dev, RK3528_OTP_CPU_CHIP_TYPE_OFFSET, &chip_type, 1); ++ if (ret < 0) { ++ log_debug("Could not read chip type, ret=%d\n", ret); ++ return 0; ++ } ++ ++ suffix[0] = chip_type != 0x1 ? 'A' : '\0'; ++ suffix[1] = '\0'; ++ ++ printf("SoC: RK%02x%02x%s\n", cpu_code[0], cpu_code[1], suffix); ++ ++ return 0; ++} +--- /dev/null ++++ b/arch/arm/mach-rockchip/rk3528/syscon_rk3528.c +@@ -0,0 +1,19 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++// Copyright Contributors to the U-Boot project. ++ ++#include ++#include ++ ++static const struct udevice_id rk3528_syscon_ids[] = { ++ { .compatible = "rockchip,rk3528-grf", .data = ROCKCHIP_SYSCON_GRF }, ++ { } ++}; ++ ++U_BOOT_DRIVER(rockchip_rk3528_syscon) = { ++ .name = "rockchip_rk3528_syscon", ++ .id = UCLASS_SYSCON, ++ .of_match = rk3528_syscon_ids, ++#if CONFIG_IS_ENABLED(OF_REAL) ++ .bind = dm_scan_fdt_dev, ++#endif ++}; +--- a/drivers/usb/gadget/Kconfig ++++ b/drivers/usb/gadget/Kconfig +@@ -85,6 +85,7 @@ config USB_GADGET_PRODUCT_NUM + default 0x330e if ROCKCHIP_RK3308 + default 0x350a if ROCKCHIP_RK3568 + default 0x350b if ROCKCHIP_RK3588 ++ default 0x350c if ROCKCHIP_RK3528 + default 0x0 + help + Product ID of the USB device emulated, reported to the host device. +--- /dev/null ++++ b/include/configs/rk3528_common.h +@@ -0,0 +1,42 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* Copyright Contributors to the U-Boot project. */ ++ ++#ifndef __CONFIG_RK3528_COMMON_H ++#define __CONFIG_RK3528_COMMON_H ++ ++#define CFG_CPUID_OFFSET 0xa ++ ++#include "rockchip-common.h" ++ ++#define CFG_IRAM_BASE 0xfe480000 ++ ++#define CFG_SYS_SDRAM_BASE 0 ++#define SDRAM_MAX_SIZE 0xfc000000 ++ ++#ifndef CONFIG_XPL_BUILD ++ ++#ifndef ROCKCHIP_DEVICE_SETTINGS ++#define ROCKCHIP_DEVICE_SETTINGS ++#endif ++ ++#define ENV_MEM_LAYOUT_SETTINGS \ ++ "scriptaddr=0x00c00000\0" \ ++ "script_offset_f=0xffe000\0" \ ++ "script_size_f=0x2000\0" \ ++ "pxefile_addr_r=0x00e00000\0" \ ++ "kernel_addr_r=0x02000000\0" \ ++ "kernel_comp_addr_r=0x0a000000\0" \ ++ "fdt_addr_r=0x12000000\0" \ ++ "fdtoverlay_addr_r=0x12100000\0" \ ++ "ramdisk_addr_r=0x12180000\0" \ ++ "kernel_comp_size=0x8000000\0" ++ ++#define CFG_EXTRA_ENV_SETTINGS \ ++ "fdtfile=" CONFIG_DEFAULT_FDT_FILE "\0" \ ++ ENV_MEM_LAYOUT_SETTINGS \ ++ ROCKCHIP_DEVICE_SETTINGS \ ++ "boot_targets=" BOOT_TARGETS "\0" ++ ++#endif /* CONFIG_XPL_BUILD */ ++ ++#endif /* __CONFIG_RK3528_COMMON_H */ diff --git a/lede/package/boot/uboot-rockchip/patches/403-ram-rockchip-Add-basic-support-for-RK3528.patch b/lede/package/boot/uboot-rockchip/patches/403-ram-rockchip-Add-basic-support-for-RK3528.patch new file mode 100644 index 0000000000..193a7b5bcb --- /dev/null +++ b/lede/package/boot/uboot-rockchip/patches/403-ram-rockchip-Add-basic-support-for-RK3528.patch @@ -0,0 +1,76 @@ +From 62e99c283ab507f93e7dadda1b05e5c459f0e60d Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Thu, 23 Jan 2025 22:48:15 +0000 +Subject: [PATCH 3/9] ram: rockchip: Add basic support for RK3528 + +Add support for reading DRAM size information from PMUGRF os_reg18 reg. + +Compared to most Rockchip SoCs the RK3528 use os_reg18 for DRAM info, +instead of os_reg2. + +Signed-off-by: Jonas Karlman +--- + arch/arm/mach-rockchip/sdram.c | 3 ++- + drivers/ram/rockchip/Makefile | 1 + + drivers/ram/rockchip/sdram_rk3528.c | 33 +++++++++++++++++++++++++++++ + 3 files changed, 36 insertions(+), 1 deletion(-) + create mode 100644 drivers/ram/rockchip/sdram_rk3528.c + +--- a/arch/arm/mach-rockchip/sdram.c ++++ b/arch/arm/mach-rockchip/sdram.c +@@ -110,7 +110,8 @@ static int rockchip_dram_init_banksize(v + u8 i, j; + + if (!IS_ENABLED(CONFIG_ROCKCHIP_RK3588) && +- !IS_ENABLED(CONFIG_ROCKCHIP_RK3568)) ++ !IS_ENABLED(CONFIG_ROCKCHIP_RK3568) && ++ !IS_ENABLED(CONFIG_ROCKCHIP_RK3528)) + return -ENOTSUPP; + + if (!IS_ENABLED(CONFIG_ROCKCHIP_EXTERNAL_TPL)) +--- a/drivers/ram/rockchip/Makefile ++++ b/drivers/ram/rockchip/Makefile +@@ -13,6 +13,7 @@ obj-$(CONFIG_ROCKCHIP_RK3288) = sdram_rk + obj-$(CONFIG_ROCKCHIP_RK3308) = sdram_rk3308.o + obj-$(CONFIG_ROCKCHIP_RK3328) = sdram_rk3328.o sdram_pctl_px30.o sdram_phy_px30.o + obj-$(CONFIG_ROCKCHIP_RK3399) += sdram_rk3399.o ++obj-$(CONFIG_ROCKCHIP_RK3528) += sdram_rk3528.o + obj-$(CONFIG_ROCKCHIP_RK3568) += sdram_rk3568.o + obj-$(CONFIG_ROCKCHIP_RK3588) += sdram_rk3588.o + obj-$(CONFIG_ROCKCHIP_RV1126) += sdram_rv1126.o sdram_pctl_px30.o +--- /dev/null ++++ b/drivers/ram/rockchip/sdram_rk3528.c +@@ -0,0 +1,33 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++// Copyright Contributors to the U-Boot project. ++ ++#include ++#include ++#include ++ ++#define PMUGRF_BASE 0xff370000 ++#define OS_REG18_REG 0x248 ++ ++static int rk3528_dmc_get_info(struct udevice *dev, struct ram_info *info) ++{ ++ info->base = CFG_SYS_SDRAM_BASE; ++ info->size = rockchip_sdram_size(PMUGRF_BASE + OS_REG18_REG); ++ ++ return 0; ++} ++ ++static struct ram_ops rk3528_dmc_ops = { ++ .get_info = rk3528_dmc_get_info, ++}; ++ ++static const struct udevice_id rk3528_dmc_ids[] = { ++ { .compatible = "rockchip,rk3528-dmc" }, ++ { } ++}; ++ ++U_BOOT_DRIVER(rockchip_rk3528_dmc) = { ++ .name = "rockchip_rk3528_dmc", ++ .id = UCLASS_RAM, ++ .of_match = rk3528_dmc_ids, ++ .ops = &rk3528_dmc_ops, ++}; diff --git a/lede/package/boot/uboot-rockchip/patches/404-clk-rockchip-Add-support-for-RK3528.patch b/lede/package/boot/uboot-rockchip/patches/404-clk-rockchip-Add-support-for-RK3528.patch new file mode 100644 index 0000000000..0bda1e08ff --- /dev/null +++ b/lede/package/boot/uboot-rockchip/patches/404-clk-rockchip-Add-support-for-RK3528.patch @@ -0,0 +1,3024 @@ +From f589cfb79c124649a74f09ec6e8534153dda176e Mon Sep 17 00:00:00 2001 +From: Joseph Chen +Date: Thu, 23 Jan 2025 22:48:16 +0000 +Subject: [PATCH 4/9] clk: rockchip: Add support for RK3528 + +Add clock driver for RK3528. + +Imported from vendor U-Boot linux-6.1-stan-rkr5 tag with minor +adjustments and fixes for mainline. + +Signed-off-by: Joseph Chen +Signed-off-by: Finley Xiao +Signed-off-by: Jonas Karlman +--- + arch/arm/include/asm/arch-rockchip/clock.h | 7 + + .../include/asm/arch-rockchip/cru_rk3528.h | 388 ++++ + arch/arm/mach-rockchip/rk3528/Makefile | 1 + + arch/arm/mach-rockchip/rk3528/clk_rk3528.c | 16 + + drivers/clk/rockchip/Makefile | 1 + + drivers/clk/rockchip/clk_pll.c | 23 +- + drivers/clk/rockchip/clk_rk3528.c | 1744 +++++++++++++++++ + include/dt-bindings/clock/rk3528-cru.h | 751 +++++++ + 8 files changed, 2925 insertions(+), 6 deletions(-) + create mode 100644 arch/arm/include/asm/arch-rockchip/cru_rk3528.h + create mode 100644 arch/arm/mach-rockchip/rk3528/clk_rk3528.c + create mode 100644 drivers/clk/rockchip/clk_rk3528.c + create mode 100644 include/dt-bindings/clock/rk3528-cru.h + +--- a/arch/arm/include/asm/arch-rockchip/clock.h ++++ b/arch/arm/include/asm/arch-rockchip/clock.h +@@ -15,6 +15,13 @@ struct udevice; + #define RKCLK_PLL_MODE_NORMAL 1 + #define RKCLK_PLL_MODE_DEEP 2 + ++/* ++ * PLL flags ++ */ ++#define ROCKCHIP_PLL_SYNC_RATE BIT(0) ++/* normal mode only. now only for pll_rk3036, pll_rk3328 type */ ++#define ROCKCHIP_PLL_FIXED_MODE BIT(1) ++ + enum { + ROCKCHIP_SYSCON_NOC, + ROCKCHIP_SYSCON_GRF, +--- /dev/null ++++ b/arch/arm/include/asm/arch-rockchip/cru_rk3528.h +@@ -0,0 +1,388 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (c) 2022 Rockchip Electronics Co., Ltd. ++ * Author: Joseph Chen ++ */ ++ ++#ifndef _ASM_ARCH_CRU_RK3528_H ++#define _ASM_ARCH_CRU_RK3528_H ++ ++#define MHz 1000000 ++#define KHz 1000 ++#define OSC_HZ (24 * MHz) ++ ++#define CPU_PVTPLL_HZ (1200 * MHz) ++#define APLL_HZ (600 * MHz) ++#define GPLL_HZ (1188 * MHz) ++#define CPLL_HZ (996 * MHz) ++#define PPLL_HZ (1000 * MHz) ++ ++/* RK3528 pll id */ ++enum rk3528_pll_id { ++ APLL, ++ CPLL, ++ GPLL, ++ PPLL, ++ DPLL, ++ PLL_COUNT, ++}; ++ ++struct rk3528_clk_priv { ++ struct rk3528_cru *cru; ++ unsigned long ppll_hz; ++ unsigned long gpll_hz; ++ unsigned long cpll_hz; ++ unsigned long armclk_hz; ++ unsigned long armclk_enter_hz; ++ unsigned long armclk_init_hz; ++ bool sync_kernel; ++}; ++ ++struct rk3528_pll { ++ unsigned int con0; ++ unsigned int con1; ++ unsigned int con2; ++ unsigned int con3; ++ unsigned int con4; ++ unsigned int reserved0[3]; ++}; ++ ++#define RK3528_CRU_BASE ((struct rk3528_cru *)0xff4a0000) ++ ++struct rk3528_cru { ++ unsigned int apll_con[5]; ++ unsigned int reserved0014[3]; ++ unsigned int cpll_con[5]; ++ unsigned int reserved0034[11]; ++ unsigned int gpll_con[5]; ++ unsigned int reserved0074[51 + 32]; ++ unsigned int reserved01c0[48]; ++ unsigned int mode_con[1]; ++ unsigned int reserved0284[31]; ++ unsigned int clksel_con[91]; ++ unsigned int reserved046c[229]; ++ unsigned int gate_con[46]; ++ unsigned int reserved08b8[82]; ++ unsigned int softrst_con[47]; ++ unsigned int reserved0abc[81]; ++ unsigned int glb_cnt_th; ++ unsigned int glb_rst_st; ++ unsigned int glb_srst_fst; ++ unsigned int glb_srst_snd; ++ unsigned int glb_rst_con; ++ unsigned int reserved0c14[6]; ++ unsigned int corewfi_con; ++ unsigned int reserved0c30[15604]; ++ ++ /* pmucru */ ++ unsigned int reserved10000[192]; ++ unsigned int pmuclksel_con[3]; ++ unsigned int reserved1030c[317]; ++ unsigned int pmugate_con[3]; ++ unsigned int reserved1080c[125]; ++ unsigned int pmusoftrst_con[3]; ++ unsigned int reserved10a08[7550 + 8191]; ++ ++ /* pciecru */ ++ unsigned int reserved20000[32]; ++ unsigned int ppll_con[5]; ++ unsigned int reserved20094[155]; ++ unsigned int pcieclksel_con[2]; ++ unsigned int reserved20308[318]; ++ unsigned int pciegate_con; ++}; ++ ++check_member(rk3528_cru, pciegate_con, 0x20800); ++ ++struct pll_rate_table { ++ unsigned long rate; ++ unsigned int fbdiv; ++ unsigned int postdiv1; ++ unsigned int refdiv; ++ unsigned int postdiv2; ++ unsigned int dsmpd; ++ unsigned int frac; ++}; ++ ++#define RK3528_PMU_CRU_BASE 0x10000 ++#define RK3528_PCIE_CRU_BASE 0x20000 ++#define RK3528_DDRPHY_CRU_BASE 0x28000 ++#define RK3528_PLL_CON(x) ((x) * 0x4) ++#define RK3528_PCIE_PLL_CON(x) ((x) * 0x4 + RK3528_PCIE_CRU_BASE) ++#define RK3528_DDRPHY_PLL_CON(x) ((x) * 0x4 + RK3528_DDRPHY_CRU_BASE) ++#define RK3528_MODE_CON 0x280 ++#define RK3528_CLKSEL_CON(x) ((x) * 0x4 + 0x300) ++#define RK3528_PMU_CLKSEL_CON(x) ((x) * 0x4 + 0x300 + RK3528_PMU_CRU_BASE) ++#define RK3528_PCIE_CLKSEL_CON(x) ((x) * 0x4 + 0x300 + RK3528_PCIE_CRU_BASE) ++#define RK3528_DDRPHY_MODE_CON (0x280 + RK3528_DDRPHY_CRU_BASE) ++ ++#define RK3528_DIV_ACLK_M_CORE_SHIFT 11 ++#define RK3528_DIV_ACLK_M_CORE_MASK (0x1f << RK3528_DIV_ACLK_M_CORE_SHIFT) ++#define RK3528_DIV_PCLK_DBG_SHIFT 1 ++#define RK3528_DIV_PCLK_DBG_MASK (0x1f << RK3528_DIV_PCLK_DBG_SHIFT) ++ ++enum { ++ /* CRU_CLKSEL_CON00 */ ++ CLK_MATRIX_50M_SRC_DIV_SHIFT = 2, ++ CLK_MATRIX_50M_SRC_DIV_MASK = 0x1F << CLK_MATRIX_50M_SRC_DIV_SHIFT, ++ CLK_MATRIX_100M_SRC_DIV_SHIFT = 7, ++ CLK_MATRIX_100M_SRC_DIV_MASK = 0x1F << CLK_MATRIX_100M_SRC_DIV_SHIFT, ++ ++ /* CRU_CLKSEL_CON01 */ ++ CLK_MATRIX_150M_SRC_DIV_SHIFT = 0, ++ CLK_MATRIX_150M_SRC_DIV_MASK = 0x1F << CLK_MATRIX_150M_SRC_DIV_SHIFT, ++ CLK_MATRIX_200M_SRC_DIV_SHIFT = 5, ++ CLK_MATRIX_200M_SRC_DIV_MASK = 0x1F << CLK_MATRIX_200M_SRC_DIV_SHIFT, ++ CLK_MATRIX_250M_SRC_DIV_SHIFT = 10, ++ CLK_MATRIX_250M_SRC_DIV_MASK = 0x1F << CLK_MATRIX_250M_SRC_DIV_SHIFT, ++ CLK_MATRIX_250M_SRC_SEL_SHIFT = 15, ++ CLK_MATRIX_250M_SRC_SEL_MASK = 0x1 << CLK_MATRIX_250M_SRC_SEL_SHIFT, ++ ++ /* CRU_CLKSEL_CON02 */ ++ CLK_MATRIX_300M_SRC_DIV_SHIFT = 0, ++ CLK_MATRIX_300M_SRC_DIV_MASK = 0x1F << CLK_MATRIX_300M_SRC_DIV_SHIFT, ++ CLK_MATRIX_339M_SRC_DIV_SHIFT = 5, ++ CLK_MATRIX_339M_SRC_DIV_MASK = 0x1F << CLK_MATRIX_339M_SRC_DIV_SHIFT, ++ CLK_MATRIX_400M_SRC_DIV_SHIFT = 10, ++ CLK_MATRIX_400M_SRC_DIV_MASK = 0x1F << CLK_MATRIX_400M_SRC_DIV_SHIFT, ++ ++ /* CRU_CLKSEL_CON03 */ ++ CLK_MATRIX_500M_SRC_DIV_SHIFT = 6, ++ CLK_MATRIX_500M_SRC_DIV_MASK = 0x1F << CLK_MATRIX_500M_SRC_DIV_SHIFT, ++ CLK_MATRIX_500M_SRC_SEL_SHIFT = 11, ++ CLK_MATRIX_500M_SRC_SEL_MASK = 0x1 << CLK_MATRIX_500M_SRC_SEL_SHIFT, ++ ++ /* CRU_CLKSEL_CON04 */ ++ CLK_MATRIX_600M_SRC_DIV_SHIFT = 0, ++ CLK_MATRIX_600M_SRC_DIV_MASK = 0x1F << CLK_MATRIX_600M_SRC_DIV_SHIFT, ++ CLK_MATRIX_250M_SRC_SEL_CLK_GPLL_MUX = 0U, ++ CLK_MATRIX_250M_SRC_SEL_CLK_CPLL_MUX = 1U, ++ CLK_MATRIX_500M_SRC_SEL_CLK_GPLL_MUX = 0U, ++ CLK_MATRIX_500M_SRC_SEL_CLK_CPLL_MUX = 1U, ++ ++ /* PMUCRU_CLKSEL_CON00 */ ++ CLK_I2C2_SEL_SHIFT = 0, ++ CLK_I2C2_SEL_MASK = 0x3 << CLK_I2C2_SEL_SHIFT, ++ ++ /* PCIE_CRU_CLKSEL_CON01 */ ++ PCIE_CLK_MATRIX_50M_SRC_DIV_SHIFT = 7, ++ PCIE_CLK_MATRIX_50M_SRC_DIV_MASK = 0x1f << PCIE_CLK_MATRIX_50M_SRC_DIV_SHIFT, ++ PCIE_CLK_MATRIX_100M_SRC_DIV_SHIFT = 11, ++ PCIE_CLK_MATRIX_100M_SRC_DIV_MASK = 0x1f << PCIE_CLK_MATRIX_100M_SRC_DIV_SHIFT, ++ ++ /* CRU_CLKSEL_CON32 */ ++ DCLK_VOP_SRC0_SEL_SHIFT = 10, ++ DCLK_VOP_SRC0_SEL_MASK = 0x1 << DCLK_VOP_SRC0_SEL_SHIFT, ++ DCLK_VOP_SRC0_DIV_SHIFT = 2, ++ DCLK_VOP_SRC0_DIV_MASK = 0xFF << DCLK_VOP_SRC0_DIV_SHIFT, ++ ++ /* CRU_CLKSEL_CON33 */ ++ DCLK_VOP_SRC1_SEL_SHIFT = 8, ++ DCLK_VOP_SRC1_SEL_MASK = 0x1 << DCLK_VOP_SRC1_SEL_SHIFT, ++ DCLK_VOP_SRC1_DIV_SHIFT = 0, ++ DCLK_VOP_SRC1_DIV_MASK = 0xFF << DCLK_VOP_SRC1_DIV_SHIFT, ++ ++ /* CRU_CLKSEL_CON43 */ ++ CLK_CORE_CRYPTO_SEL_SHIFT = 14, ++ CLK_CORE_CRYPTO_SEL_MASK = 0x3 << CLK_CORE_CRYPTO_SEL_SHIFT, ++ ACLK_BUS_VOPGL_ROOT_DIV_SHIFT = 0U, ++ ACLK_BUS_VOPGL_ROOT_DIV_MASK = 0x7U << ACLK_BUS_VOPGL_ROOT_DIV_SHIFT, ++ ++ /* CRU_CLKSEL_CON44 */ ++ CLK_PWM0_SEL_SHIFT = 6, ++ CLK_PWM0_SEL_MASK = 0x3 << CLK_PWM0_SEL_SHIFT, ++ CLK_PWM1_SEL_SHIFT = 8, ++ CLK_PWM1_SEL_MASK = 0x3 << CLK_PWM1_SEL_SHIFT, ++ CLK_PWM0_SEL_CLK_MATRIX_100M_SRC = 0U, ++ CLK_PWM0_SEL_CLK_MATRIX_50M_SRC = 1U, ++ CLK_PWM0_SEL_XIN_OSC0_FUNC = 2U, ++ CLK_PWM1_SEL_CLK_MATRIX_100M_SRC = 0U, ++ CLK_PWM1_SEL_CLK_MATRIX_50M_SRC = 1U, ++ CLK_PWM1_SEL_XIN_OSC0_FUNC = 2U, ++ CLK_PKA_CRYPTO_SEL_SHIFT = 0, ++ CLK_PKA_CRYPTO_SEL_MASK = 0x3 << CLK_PKA_CRYPTO_SEL_SHIFT, ++ CLK_CORE_CRYPTO_SEL_CLK_MATRIX_300M_SRC = 0U, ++ CLK_CORE_CRYPTO_SEL_CLK_MATRIX_200M_SRC = 1U, ++ CLK_CORE_CRYPTO_SEL_CLK_MATRIX_100M_SRC = 2U, ++ CLK_CORE_CRYPTO_SEL_XIN_OSC0_FUNC = 3U, ++ CLK_PKA_CRYPTO_SEL_CLK_MATRIX_300M_SRC = 0U, ++ CLK_PKA_CRYPTO_SEL_CLK_MATRIX_200M_SRC = 1U, ++ CLK_PKA_CRYPTO_SEL_CLK_MATRIX_100M_SRC = 2U, ++ CLK_PKA_CRYPTO_SEL_XIN_OSC0_FUNC = 3U, ++ ++ /* CRU_CLKSEL_CON60 */ ++ CLK_MATRIX_25M_SRC_DIV_SHIFT = 2, ++ CLK_MATRIX_25M_SRC_DIV_MASK = 0xff << CLK_MATRIX_25M_SRC_DIV_SHIFT, ++ CLK_MATRIX_125M_SRC_DIV_SHIFT = 10, ++ CLK_MATRIX_125M_SRC_DIV_MASK = 0x1f << CLK_MATRIX_125M_SRC_DIV_SHIFT, ++ ++ /* CRU_CLKSEL_CON61 */ ++ SCLK_SFC_DIV_SHIFT = 6, ++ SCLK_SFC_DIV_MASK = 0x3F << SCLK_SFC_DIV_SHIFT, ++ SCLK_SFC_SEL_SHIFT = 12, ++ SCLK_SFC_SEL_MASK = 0x3 << SCLK_SFC_SEL_SHIFT, ++ SCLK_SFC_SEL_CLK_GPLL_MUX = 0U, ++ SCLK_SFC_SEL_CLK_CPLL_MUX = 1U, ++ SCLK_SFC_SEL_XIN_OSC0_FUNC = 2U, ++ ++ /* CRU_CLKSEL_CON62 */ ++ CCLK_SRC_EMMC_DIV_SHIFT = 0, ++ CCLK_SRC_EMMC_DIV_MASK = 0x3F << CCLK_SRC_EMMC_DIV_SHIFT, ++ CCLK_SRC_EMMC_SEL_SHIFT = 6, ++ CCLK_SRC_EMMC_SEL_MASK = 0x3 << CCLK_SRC_EMMC_SEL_SHIFT, ++ BCLK_EMMC_SEL_SHIFT = 8, ++ BCLK_EMMC_SEL_MASK = 0x3 << BCLK_EMMC_SEL_SHIFT, ++ ++ /* CRU_CLKSEL_CON63 */ ++ CLK_I2C3_SEL_SHIFT = 12, ++ CLK_I2C3_SEL_MASK = 0x3 << CLK_I2C3_SEL_SHIFT, ++ CLK_I2C5_SEL_SHIFT = 14, ++ CLK_I2C5_SEL_MASK = 0x3 << CLK_I2C5_SEL_SHIFT, ++ CLK_SPI1_SEL_SHIFT = 10, ++ CLK_SPI1_SEL_MASK = 0x3 << CLK_SPI1_SEL_SHIFT, ++ ++ /* CRU_CLKSEL_CON64 */ ++ CLK_I2C6_SEL_SHIFT = 0, ++ CLK_I2C6_SEL_MASK = 0x3 << CLK_I2C6_SEL_SHIFT, ++ ++ /* CRU_CLKSEL_CON74 */ ++ CLK_SARADC_DIV_SHIFT = 0, ++ CLK_SARADC_DIV_MASK = 0x7 << CLK_SARADC_DIV_SHIFT, ++ CLK_TSADC_DIV_SHIFT = 3, ++ CLK_TSADC_DIV_MASK = 0x1F << CLK_TSADC_DIV_SHIFT, ++ CLK_TSADC_TSEN_DIV_SHIFT = 8, ++ CLK_TSADC_TSEN_DIV_MASK = 0x1F << CLK_TSADC_TSEN_DIV_SHIFT, ++ ++ /* CRU_CLKSEL_CON79 */ ++ CLK_I2C1_SEL_SHIFT = 9, ++ CLK_I2C1_SEL_MASK = 0x3 << CLK_I2C1_SEL_SHIFT, ++ CLK_I2C0_SEL_SHIFT = 11, ++ CLK_I2C0_SEL_MASK = 0x3 << CLK_I2C0_SEL_SHIFT, ++ CLK_SPI0_SEL_SHIFT = 13, ++ CLK_SPI0_SEL_MASK = 0x3 << CLK_SPI0_SEL_SHIFT, ++ ++ /* CRU_CLKSEL_CON83 */ ++ ACLK_VOP_ROOT_DIV_SHIFT = 12, ++ ACLK_VOP_ROOT_DIV_MASK = 0x7 << ACLK_VOP_ROOT_DIV_SHIFT, ++ ACLK_VOP_ROOT_SEL_SHIFT = 15, ++ ACLK_VOP_ROOT_SEL_MASK = 0x1 << ACLK_VOP_ROOT_SEL_SHIFT, ++ ++ /* CRU_CLKSEL_CON84 */ ++ DCLK_VOP0_SEL_SHIFT = 0, ++ DCLK_VOP0_SEL_MASK = 0x1 << DCLK_VOP0_SEL_SHIFT, ++ DCLK_VOP_SRC_SEL_CLK_GPLL_MUX = 0U, ++ DCLK_VOP_SRC_SEL_CLK_CPLL_MUX = 1U, ++ ACLK_VOP_ROOT_SEL_CLK_GPLL_MUX = 0U, ++ ACLK_VOP_ROOT_SEL_CLK_CPLL_MUX = 1U, ++ DCLK_VOP0_SEL_DCLK_VOP_SRC0 = 0U, ++ DCLK_VOP0_SEL_CLK_HDMIPHY_PIXEL_IO = 1U, ++ ++ /* CRU_CLKSEL_CON85 */ ++ CLK_I2C4_SEL_SHIFT = 13, ++ CLK_I2C4_SEL_MASK = 0x3 << CLK_I2C4_SEL_SHIFT, ++ CLK_I2C7_SEL_SHIFT = 0, ++ CLK_I2C7_SEL_MASK = 0x3 << CLK_I2C7_SEL_SHIFT, ++ CLK_I2C3_SEL_CLK_MATRIX_200M_SRC = 0U, ++ CLK_I2C3_SEL_CLK_MATRIX_100M_SRC = 1U, ++ CLK_I2C3_SEL_CLK_MATRIX_50M_SRC = 2U, ++ CLK_I2C3_SEL_XIN_OSC0_FUNC = 3U, ++ CLK_SPI1_SEL_CLK_MATRIX_200M_SRC = 0U, ++ CLK_SPI1_SEL_CLK_MATRIX_100M_SRC = 1U, ++ CLK_SPI1_SEL_CLK_MATRIX_50M_SRC = 2U, ++ CLK_SPI1_SEL_XIN_OSC0_FUNC = 3U, ++ CCLK_SRC_SDMMC0_DIV_SHIFT = 0, ++ CCLK_SRC_SDMMC0_DIV_MASK = 0x3F << CCLK_SRC_SDMMC0_DIV_SHIFT, ++ CCLK_SRC_SDMMC0_SEL_SHIFT = 6, ++ CCLK_SRC_SDMMC0_SEL_MASK = 0x3 << CCLK_SRC_SDMMC0_SEL_SHIFT, ++ CCLK_SRC_EMMC_SEL_CLK_GPLL_MUX = 0U, ++ CCLK_SRC_EMMC_SEL_CLK_CPLL_MUX = 1U, ++ CCLK_SRC_EMMC_SEL_XIN_OSC0_FUNC = 2U, ++ BCLK_EMMC_SEL_CLK_MATRIX_200M_SRC = 0U, ++ BCLK_EMMC_SEL_CLK_MATRIX_100M_SRC = 1U, ++ BCLK_EMMC_SEL_CLK_MATRIX_50M_SRC = 2U, ++ BCLK_EMMC_SEL_XIN_OSC0_FUNC = 3U, ++ CCLK_SRC_SDMMC0_SEL_CLK_GPLL_MUX = 0U, ++ CCLK_SRC_SDMMC0_SEL_CLK_CPLL_MUX = 1U, ++ CCLK_SRC_SDMMC0_SEL_XIN_OSC0_FUNC = 2U, ++ ++ /* CRU_CLKSEL_CON04 */ ++ CLK_UART0_SRC_DIV_SHIFT = 5, ++ CLK_UART0_SRC_DIV_MASK = 0x1F << CLK_UART0_SRC_DIV_SHIFT, ++ /* CRU_CLKSEL_CON05 */ ++ CLK_UART0_FRAC_DIV_SHIFT = 0, ++ CLK_UART0_FRAC_DIV_MASK = 0xFFFFFFFF << CLK_UART0_FRAC_DIV_SHIFT, ++ /* CRU_CLKSEL_CON06 */ ++ SCLK_UART0_SRC_SEL_SHIFT = 0, ++ SCLK_UART0_SRC_SEL_MASK = 0x3 << SCLK_UART0_SRC_SEL_SHIFT, ++ CLK_UART1_SRC_DIV_SHIFT = 2, ++ CLK_UART1_SRC_DIV_MASK = 0x1F << CLK_UART1_SRC_DIV_SHIFT, ++ /* CRU_CLKSEL_CON07 */ ++ CLK_UART1_FRAC_DIV_SHIFT = 0, ++ CLK_UART1_FRAC_DIV_MASK = 0xFFFFFFFF << CLK_UART1_FRAC_DIV_SHIFT, ++ /* CRU_CLKSEL_CON08 */ ++ SCLK_UART1_SRC_SEL_SHIFT = 0, ++ SCLK_UART1_SRC_SEL_MASK = 0x3 << SCLK_UART1_SRC_SEL_SHIFT, ++ CLK_UART2_SRC_DIV_SHIFT = 2, ++ CLK_UART2_SRC_DIV_MASK = 0x1F << CLK_UART2_SRC_DIV_SHIFT, ++ /* CRU_CLKSEL_CON09 */ ++ CLK_UART2_FRAC_DIV_SHIFT = 0, ++ CLK_UART2_FRAC_DIV_MASK = 0xFFFFFFFF << CLK_UART2_FRAC_DIV_SHIFT, ++ /* CRU_CLKSEL_CON10 */ ++ SCLK_UART2_SRC_SEL_SHIFT = 0, ++ SCLK_UART2_SRC_SEL_MASK = 0x3 << SCLK_UART2_SRC_SEL_SHIFT, ++ CLK_UART3_SRC_DIV_SHIFT = 2, ++ CLK_UART3_SRC_DIV_MASK = 0x1F << CLK_UART3_SRC_DIV_SHIFT, ++ /* CRU_CLKSEL_CON11 */ ++ CLK_UART3_FRAC_DIV_SHIFT = 0, ++ CLK_UART3_FRAC_DIV_MASK = 0xFFFFFFFF << CLK_UART3_FRAC_DIV_SHIFT, ++ /* CRU_CLKSEL_CON12 */ ++ SCLK_UART3_SRC_SEL_SHIFT = 0, ++ SCLK_UART3_SRC_SEL_MASK = 0x3 << SCLK_UART3_SRC_SEL_SHIFT, ++ CLK_UART4_SRC_DIV_SHIFT = 2, ++ CLK_UART4_SRC_DIV_MASK = 0x1F << CLK_UART4_SRC_DIV_SHIFT, ++ /* CRU_CLKSEL_CON13 */ ++ CLK_UART4_FRAC_DIV_SHIFT = 0, ++ CLK_UART4_FRAC_DIV_MASK = 0xFFFFFFFF << CLK_UART4_FRAC_DIV_SHIFT, ++ /* CRU_CLKSEL_CON14 */ ++ SCLK_UART4_SRC_SEL_SHIFT = 0, ++ SCLK_UART4_SRC_SEL_MASK = 0x3 << SCLK_UART4_SRC_SEL_SHIFT, ++ CLK_UART5_SRC_DIV_SHIFT = 2, ++ CLK_UART5_SRC_DIV_MASK = 0x1F << CLK_UART5_SRC_DIV_SHIFT, ++ /* CRU_CLKSEL_CON15 */ ++ CLK_UART5_FRAC_DIV_SHIFT = 0, ++ CLK_UART5_FRAC_DIV_MASK = 0xFFFFFFFF << CLK_UART5_FRAC_DIV_SHIFT, ++ /* CRU_CLKSEL_CON16 */ ++ SCLK_UART5_SRC_SEL_SHIFT = 0, ++ SCLK_UART5_SRC_SEL_MASK = 0x3 << SCLK_UART5_SRC_SEL_SHIFT, ++ CLK_UART6_SRC_DIV_SHIFT = 2, ++ CLK_UART6_SRC_DIV_MASK = 0x1F << CLK_UART6_SRC_DIV_SHIFT, ++ /* CRU_CLKSEL_CON17 */ ++ CLK_UART6_FRAC_DIV_SHIFT = 0, ++ CLK_UART6_FRAC_DIV_MASK = 0xFFFFFFFF << CLK_UART6_FRAC_DIV_SHIFT, ++ /* CRU_CLKSEL_CON18 */ ++ SCLK_UART6_SRC_SEL_SHIFT = 0, ++ SCLK_UART6_SRC_SEL_MASK = 0x3 << SCLK_UART6_SRC_SEL_SHIFT, ++ CLK_UART7_SRC_DIV_SHIFT = 2, ++ CLK_UART7_SRC_DIV_MASK = 0x1F << CLK_UART7_SRC_DIV_SHIFT, ++ /* CRU_CLKSEL_CON19 */ ++ CLK_UART7_FRAC_DIV_SHIFT = 0, ++ CLK_UART7_FRAC_DIV_MASK = 0xFFFFFFFF << CLK_UART7_FRAC_DIV_SHIFT, ++ /* CRU_CLKSEL_CON20 */ ++ SCLK_UART7_SRC_SEL_SHIFT = 0, ++ SCLK_UART7_SRC_SEL_MASK = 0x3 << SCLK_UART7_SRC_SEL_SHIFT, ++ SCLK_UART0_SRC_SEL_CLK_UART0_SRC = 0U, ++ SCLK_UART0_SRC_SEL_CLK_UART0_FRAC = 1U, ++ SCLK_UART0_SRC_SEL_XIN_OSC0_FUNC = 2U, ++ ++ /* CRU_CLKSEL_CON60 */ ++ CLK_GMAC1_VPU_25M_DIV_SHIFT = 2, ++ CLK_GMAC1_VPU_25M_DIV_MASK = 0xFF << CLK_GMAC1_VPU_25M_DIV_SHIFT, ++ /* CRU_CLKSEL_CON66 */ ++ CLK_GMAC1_SRC_VPU_DIV_SHIFT = 0, ++ CLK_GMAC1_SRC_VPU_DIV_MASK = 0x3F << CLK_GMAC1_SRC_VPU_DIV_SHIFT, ++ /* CRU_CLKSEL_CON84 */ ++ CLK_GMAC0_SRC_DIV_SHIFT = 3, ++ CLK_GMAC0_SRC_DIV_MASK = 0x3F << CLK_GMAC0_SRC_DIV_SHIFT, ++}; ++ ++#endif /* _ASM_ARCH_CRU_RK3528_H */ +--- a/arch/arm/mach-rockchip/rk3528/Makefile ++++ b/arch/arm/mach-rockchip/rk3528/Makefile +@@ -1,4 +1,5 @@ + # SPDX-License-Identifier: GPL-2.0-or-later + + obj-y += rk3528.o ++obj-y += clk_rk3528.o + obj-y += syscon_rk3528.o +--- /dev/null ++++ b/arch/arm/mach-rockchip/rk3528/clk_rk3528.c +@@ -0,0 +1,16 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++// Copyright Contributors to the U-Boot project. ++ ++#include ++#include ++ ++int rockchip_get_clk(struct udevice **devp) ++{ ++ return uclass_get_device_by_driver(UCLASS_CLK, ++ DM_DRIVER_GET(rockchip_rk3528_cru), devp); ++} ++ ++void *rockchip_get_cru(void) ++{ ++ return RK3528_CRU_BASE; ++} +--- a/drivers/clk/rockchip/Makefile ++++ b/drivers/clk/rockchip/Makefile +@@ -15,6 +15,7 @@ obj-$(CONFIG_ROCKCHIP_RK3308) += clk_rk3 + obj-$(CONFIG_ROCKCHIP_RK3328) += clk_rk3328.o + obj-$(CONFIG_ROCKCHIP_RK3368) += clk_rk3368.o + obj-$(CONFIG_ROCKCHIP_RK3399) += clk_rk3399.o ++obj-$(CONFIG_ROCKCHIP_RK3528) += clk_rk3528.o + obj-$(CONFIG_ROCKCHIP_RK3568) += clk_rk3568.o + obj-$(CONFIG_ROCKCHIP_RK3588) += clk_rk3588.o + obj-$(CONFIG_ROCKCHIP_RV1108) += clk_rv1108.o +--- a/drivers/clk/rockchip/clk_pll.c ++++ b/drivers/clk/rockchip/clk_pll.c +@@ -309,9 +309,11 @@ static int rk3036_pll_set_rate(struct ro + * When power on or changing PLL setting, + * we must force PLL into slow mode to ensure output stable clock. + */ +- rk_clrsetreg(base + pll->mode_offset, +- pll->mode_mask << pll->mode_shift, +- RKCLK_PLL_MODE_SLOW << pll->mode_shift); ++ if (!(pll->pll_flags & ROCKCHIP_PLL_FIXED_MODE)) { ++ rk_clrsetreg(base + pll->mode_offset, ++ pll->mode_mask << pll->mode_shift, ++ RKCLK_PLL_MODE_SLOW << pll->mode_shift); ++ } + + /* Power down */ + rk_setreg(base + pll->con_offset + 0x4, +@@ -345,8 +347,11 @@ static int rk3036_pll_set_rate(struct ro + while (!(readl(base + pll->con_offset + 0x4) & (1 << pll->lock_shift))) + udelay(1); + +- rk_clrsetreg(base + pll->mode_offset, pll->mode_mask << pll->mode_shift, +- RKCLK_PLL_MODE_NORMAL << pll->mode_shift); ++ if (!(pll->pll_flags & ROCKCHIP_PLL_FIXED_MODE)) { ++ rk_clrsetreg(base + pll->mode_offset, ++ pll->mode_mask << pll->mode_shift, ++ RKCLK_PLL_MODE_NORMAL << pll->mode_shift); ++ } + debug("PLL at %p: con0=%x con1= %x con2= %x mode= %x\n", + pll, readl(base + pll->con_offset), + readl(base + pll->con_offset + 0x4), +@@ -362,12 +367,18 @@ static ulong rk3036_pll_get_rate(struct + u32 refdiv, fbdiv, postdiv1, postdiv2, dsmpd, frac; + u32 con = 0, shift, mask; + ulong rate; ++ int mode; + + con = readl(base + pll->mode_offset); + shift = pll->mode_shift; + mask = pll->mode_mask << shift; + +- switch ((con & mask) >> shift) { ++ if (!(pll->pll_flags & ROCKCHIP_PLL_FIXED_MODE)) ++ mode = (con & mask) >> shift; ++ else ++ mode = RKCLK_PLL_MODE_NORMAL; ++ ++ switch (mode) { + case RKCLK_PLL_MODE_SLOW: + return OSC_HZ; + case RKCLK_PLL_MODE_NORMAL: +--- /dev/null ++++ b/drivers/clk/rockchip/clk_rk3528.c +@@ -0,0 +1,1744 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (c) 2022 Rockchip Electronics Co., Ltd. ++ * Author: Joseph Chen ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++DECLARE_GLOBAL_DATA_PTR; ++ ++#define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1)) ++ ++/* ++ * PLL attention. ++ * ++ * [FRAC PLL]: GPLL, PPLL, DPLL ++ * - frac mode: refdiv can be 1 or 2 only ++ * - int mode: refdiv has no special limit ++ * - VCO range: [950, 3800] MHZ ++ * ++ * [INT PLL]: CPLL, APLL ++ * - int mode: refdiv can be 1 or 2 only ++ * - VCO range: [475, 1900] MHZ ++ * ++ * [PPLL]: normal mode only. ++ * ++ */ ++static struct rockchip_pll_rate_table rk3528_pll_rates[] = { ++ /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */ ++ RK3036_PLL_RATE(1896000000, 1, 79, 1, 1, 1, 0), ++ RK3036_PLL_RATE(1800000000, 1, 75, 1, 1, 1, 0), ++ RK3036_PLL_RATE(1704000000, 1, 71, 1, 1, 1, 0), ++ RK3036_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0), ++ RK3036_PLL_RATE(1512000000, 1, 63, 1, 1, 1, 0), ++ RK3036_PLL_RATE(1416000000, 1, 59, 1, 1, 1, 0), ++ RK3036_PLL_RATE(1296000000, 1, 54, 1, 1, 1, 0), ++ RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0), ++ RK3036_PLL_RATE(1188000000, 1, 99, 2, 1, 1, 0), /* GPLL */ ++ RK3036_PLL_RATE(1092000000, 2, 91, 1, 1, 1, 0), ++ RK3036_PLL_RATE(1008000000, 1, 42, 1, 1, 1, 0), ++ RK3036_PLL_RATE(1000000000, 1, 125, 3, 1, 1, 0), /* PPLL */ ++ RK3036_PLL_RATE(996000000, 2, 83, 1, 1, 1, 0), /* CPLL */ ++ RK3036_PLL_RATE(960000000, 1, 40, 1, 1, 1, 0), ++ RK3036_PLL_RATE(912000000, 1, 76, 2, 1, 1, 0), ++ RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0), ++ RK3036_PLL_RATE(600000000, 1, 50, 2, 1, 1, 0), ++ RK3036_PLL_RATE(594000000, 2, 99, 2, 1, 1, 0), ++ RK3036_PLL_RATE(408000000, 1, 68, 2, 2, 1, 0), ++ RK3036_PLL_RATE(312000000, 1, 78, 6, 1, 1, 0), ++ RK3036_PLL_RATE(216000000, 1, 72, 4, 2, 1, 0), ++ RK3036_PLL_RATE(96000000, 1, 24, 3, 2, 1, 0), ++ { /* sentinel */ }, ++}; ++ ++static struct rockchip_pll_clock rk3528_pll_clks[] = { ++ [APLL] = PLL(pll_rk3328, PLL_APLL, RK3528_PLL_CON(0), ++ RK3528_MODE_CON, 0, 10, 0, rk3528_pll_rates), ++ ++ [CPLL] = PLL(pll_rk3328, PLL_CPLL, RK3528_PLL_CON(8), ++ RK3528_MODE_CON, 2, 10, 0, rk3528_pll_rates), ++ ++ [GPLL] = PLL(pll_rk3328, PLL_GPLL, RK3528_PLL_CON(24), ++ RK3528_MODE_CON, 4, 10, 0, rk3528_pll_rates), ++ ++ [PPLL] = PLL(pll_rk3328, PLL_PPLL, RK3528_PCIE_PLL_CON(32), ++ RK3528_MODE_CON, 6, 10, ROCKCHIP_PLL_FIXED_MODE, rk3528_pll_rates), ++ ++ [DPLL] = PLL(pll_rk3328, PLL_DPLL, RK3528_DDRPHY_PLL_CON(16), ++ RK3528_DDRPHY_MODE_CON, 0, 10, 0, rk3528_pll_rates), ++}; ++ ++#define RK3528_CPUCLK_RATE(_rate, _aclk_m_core, _pclk_dbg) \ ++{ \ ++ .rate = _rate##U, \ ++ .aclk_div = (_aclk_m_core), \ ++ .pclk_div = (_pclk_dbg), \ ++} ++ ++/* sign-off: _aclk_m_core: 550M, _pclk_dbg: 137.5M, */ ++static struct rockchip_cpu_rate_table rk3528_cpu_rates[] = { ++ RK3528_CPUCLK_RATE(1896000000, 1, 13), ++ RK3528_CPUCLK_RATE(1800000000, 1, 12), ++ RK3528_CPUCLK_RATE(1704000000, 1, 11), ++ RK3528_CPUCLK_RATE(1608000000, 1, 11), ++ RK3528_CPUCLK_RATE(1512000000, 1, 11), ++ RK3528_CPUCLK_RATE(1416000000, 1, 9), ++ RK3528_CPUCLK_RATE(1296000000, 1, 8), ++ RK3528_CPUCLK_RATE(1200000000, 1, 8), ++ RK3528_CPUCLK_RATE(1188000000, 1, 8), ++ RK3528_CPUCLK_RATE(1092000000, 1, 7), ++ RK3528_CPUCLK_RATE(1008000000, 1, 6), ++ RK3528_CPUCLK_RATE(1000000000, 1, 6), ++ RK3528_CPUCLK_RATE(996000000, 1, 6), ++ RK3528_CPUCLK_RATE(960000000, 1, 6), ++ RK3528_CPUCLK_RATE(912000000, 1, 6), ++ RK3528_CPUCLK_RATE(816000000, 1, 5), ++ RK3528_CPUCLK_RATE(600000000, 1, 3), ++ RK3528_CPUCLK_RATE(594000000, 1, 3), ++ RK3528_CPUCLK_RATE(408000000, 1, 2), ++ RK3528_CPUCLK_RATE(312000000, 1, 2), ++ RK3528_CPUCLK_RATE(216000000, 1, 1), ++ RK3528_CPUCLK_RATE(96000000, 1, 0), ++}; ++ ++/* ++ * ++ * rational_best_approximation(31415, 10000, ++ * (1 << 8) - 1, (1 << 5) - 1, &n, &d); ++ * ++ * you may look at given_numerator as a fixed point number, ++ * with the fractional part size described in given_denominator. ++ * ++ * for theoretical background, see: ++ * http://en.wikipedia.org/wiki/Continued_fraction ++ */ ++static void rational_best_approximation(unsigned long given_numerator, ++ unsigned long given_denominator, ++ unsigned long max_numerator, ++ unsigned long max_denominator, ++ unsigned long *best_numerator, ++ unsigned long *best_denominator) ++{ ++ unsigned long n, d, n0, d0, n1, d1; ++ ++ n = given_numerator; ++ d = given_denominator; ++ n0 = 0; ++ d1 = 0; ++ n1 = 1; ++ d0 = 1; ++ for (;;) { ++ unsigned long t, a; ++ ++ if (n1 > max_numerator || d1 > max_denominator) { ++ n1 = n0; ++ d1 = d0; ++ break; ++ } ++ if (d == 0) ++ break; ++ t = d; ++ a = n / d; ++ d = n % d; ++ n = t; ++ t = n0 + a * n1; ++ n0 = n1; ++ n1 = t; ++ t = d0 + a * d1; ++ d0 = d1; ++ d1 = t; ++ } ++ *best_numerator = n1; ++ *best_denominator = d1; ++} ++ ++static int rk3528_armclk_set_clk(struct rk3528_clk_priv *priv, ulong new_rate) ++{ ++ const struct rockchip_cpu_rate_table *rate; ++ struct rk3528_cru *cru = priv->cru; ++ ulong old_rate; ++ ++ rate = rockchip_get_cpu_settings(rk3528_cpu_rates, new_rate); ++ if (!rate) { ++ printf("%s unsupported rate\n", __func__); ++ return -EINVAL; ++ } ++ ++ /* ++ * set up dependent divisors for DBG and ACLK clocks. ++ */ ++ old_rate = rockchip_pll_get_rate(&rk3528_pll_clks[APLL], priv->cru, APLL); ++ if (old_rate > new_rate) { ++ if (rockchip_pll_set_rate(&rk3528_pll_clks[APLL], ++ priv->cru, APLL, new_rate)) ++ return -EINVAL; ++ ++ rk_clrsetreg(&cru->clksel_con[40], RK3528_DIV_PCLK_DBG_MASK, ++ rate->pclk_div << RK3528_DIV_PCLK_DBG_SHIFT); ++ ++ rk_clrsetreg(&cru->clksel_con[39], RK3528_DIV_ACLK_M_CORE_MASK, ++ rate->aclk_div << RK3528_DIV_ACLK_M_CORE_SHIFT); ++ } else if (old_rate < new_rate) { ++ rk_clrsetreg(&cru->clksel_con[40], RK3528_DIV_PCLK_DBG_MASK, ++ rate->pclk_div << RK3528_DIV_PCLK_DBG_SHIFT); ++ ++ rk_clrsetreg(&cru->clksel_con[39], RK3528_DIV_ACLK_M_CORE_MASK, ++ rate->aclk_div << RK3528_DIV_ACLK_M_CORE_SHIFT); ++ ++ if (rockchip_pll_set_rate(&rk3528_pll_clks[APLL], ++ priv->cru, APLL, new_rate)) ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static ulong rk3528_ppll_matrix_get_rate(struct rk3528_clk_priv *priv, ++ ulong clk_id) ++{ ++ struct rk3528_cru *cru = priv->cru; ++ u32 div, mask, shift; ++ void *reg; ++ ++ switch (clk_id) { ++ case CLK_PPLL_50M_MATRIX: ++ case CLK_GMAC1_RMII_VPU: ++ mask = PCIE_CLK_MATRIX_50M_SRC_DIV_MASK; ++ shift = PCIE_CLK_MATRIX_50M_SRC_DIV_SHIFT; ++ reg = &cru->pcieclksel_con[1]; ++ break; ++ ++ case CLK_PPLL_100M_MATRIX: ++ mask = PCIE_CLK_MATRIX_100M_SRC_DIV_MASK; ++ shift = PCIE_CLK_MATRIX_100M_SRC_DIV_SHIFT; ++ reg = &cru->pcieclksel_con[1]; ++ break; ++ ++ case CLK_PPLL_125M_MATRIX: ++ case CLK_GMAC1_SRC_VPU: ++ mask = CLK_MATRIX_125M_SRC_DIV_MASK; ++ shift = CLK_MATRIX_125M_SRC_DIV_SHIFT; ++ reg = &cru->clksel_con[60]; ++ break; ++ ++ case CLK_GMAC1_VPU_25M: ++ mask = CLK_MATRIX_25M_SRC_DIV_MASK; ++ shift = CLK_MATRIX_25M_SRC_DIV_SHIFT; ++ reg = &cru->clksel_con[60]; ++ break; ++ default: ++ return -ENOENT; ++ } ++ ++ div = (readl(reg) & mask) >> shift; ++ ++ return DIV_TO_RATE(priv->ppll_hz, div); ++} ++ ++static ulong rk3528_ppll_matrix_set_rate(struct rk3528_clk_priv *priv, ++ ulong clk_id, ulong rate) ++{ ++ struct rk3528_cru *cru = priv->cru; ++ u32 id, div, mask, shift; ++ u8 is_pciecru = 0; ++ ++ switch (clk_id) { ++ case CLK_PPLL_50M_MATRIX: ++ id = 1; ++ mask = PCIE_CLK_MATRIX_50M_SRC_DIV_MASK; ++ shift = PCIE_CLK_MATRIX_50M_SRC_DIV_SHIFT; ++ is_pciecru = 1; ++ break; ++ ++ case CLK_PPLL_100M_MATRIX: ++ id = 1; ++ mask = PCIE_CLK_MATRIX_100M_SRC_DIV_MASK; ++ shift = PCIE_CLK_MATRIX_100M_SRC_DIV_SHIFT; ++ is_pciecru = 1; ++ break; ++ ++ case CLK_PPLL_125M_MATRIX: ++ id = 60; ++ mask = CLK_MATRIX_125M_SRC_DIV_MASK; ++ shift = CLK_MATRIX_125M_SRC_DIV_SHIFT; ++ break; ++ case CLK_GMAC1_VPU_25M: ++ id = 60; ++ mask = CLK_MATRIX_25M_SRC_DIV_MASK; ++ shift = CLK_MATRIX_25M_SRC_DIV_SHIFT; ++ break; ++ default: ++ return -ENOENT; ++ } ++ ++ div = DIV_ROUND_UP(priv->ppll_hz, rate); ++ if (is_pciecru) ++ rk_clrsetreg(&cru->pcieclksel_con[id], mask, (div - 1) << shift); ++ else ++ rk_clrsetreg(&cru->clksel_con[id], mask, (div - 1) << shift); ++ ++ return rk3528_ppll_matrix_get_rate(priv, clk_id); ++} ++ ++static ulong rk3528_cgpll_matrix_get_rate(struct rk3528_clk_priv *priv, ++ ulong clk_id) ++{ ++ struct rk3528_cru *cru = priv->cru; ++ u32 sel, div, mask, shift, con; ++ u32 sel_mask = 0, sel_shift; ++ u8 is_gpll_parent = 1; ++ u8 is_halfdiv = 0; ++ ulong prate; ++ ++ switch (clk_id) { ++ case CLK_MATRIX_50M_SRC: ++ con = 0; ++ mask = CLK_MATRIX_50M_SRC_DIV_MASK; ++ shift = CLK_MATRIX_50M_SRC_DIV_SHIFT; ++ is_gpll_parent = 0; ++ break; ++ ++ case CLK_MATRIX_100M_SRC: ++ con = 0; ++ mask = CLK_MATRIX_100M_SRC_DIV_MASK; ++ shift = CLK_MATRIX_100M_SRC_DIV_SHIFT; ++ is_gpll_parent = 0; ++ break; ++ ++ case CLK_MATRIX_150M_SRC: ++ con = 1; ++ mask = CLK_MATRIX_150M_SRC_DIV_MASK; ++ shift = CLK_MATRIX_150M_SRC_DIV_SHIFT; ++ break; ++ ++ case CLK_MATRIX_200M_SRC: ++ con = 1; ++ mask = CLK_MATRIX_200M_SRC_DIV_MASK; ++ shift = CLK_MATRIX_200M_SRC_DIV_SHIFT; ++ break; ++ ++ case CLK_MATRIX_250M_SRC: ++ con = 1; ++ mask = CLK_MATRIX_250M_SRC_DIV_MASK; ++ shift = CLK_MATRIX_250M_SRC_DIV_SHIFT; ++ sel_mask = CLK_MATRIX_250M_SRC_SEL_MASK; ++ sel_shift = CLK_MATRIX_250M_SRC_SEL_SHIFT; ++ break; ++ ++ case CLK_MATRIX_300M_SRC: ++ con = 2; ++ mask = CLK_MATRIX_300M_SRC_DIV_MASK; ++ shift = CLK_MATRIX_300M_SRC_DIV_SHIFT; ++ break; ++ ++ case CLK_MATRIX_339M_SRC: ++ con = 2; ++ mask = CLK_MATRIX_339M_SRC_DIV_MASK; ++ shift = CLK_MATRIX_339M_SRC_DIV_SHIFT; ++ is_halfdiv = 1; ++ break; ++ ++ case CLK_MATRIX_400M_SRC: ++ con = 2; ++ mask = CLK_MATRIX_400M_SRC_DIV_MASK; ++ shift = CLK_MATRIX_400M_SRC_DIV_SHIFT; ++ break; ++ ++ case CLK_MATRIX_500M_SRC: ++ con = 3; ++ mask = CLK_MATRIX_500M_SRC_DIV_MASK; ++ shift = CLK_MATRIX_500M_SRC_DIV_SHIFT; ++ sel_mask = CLK_MATRIX_500M_SRC_SEL_MASK; ++ sel_shift = CLK_MATRIX_500M_SRC_SEL_SHIFT; ++ break; ++ ++ case CLK_MATRIX_600M_SRC: ++ con = 4; ++ mask = CLK_MATRIX_600M_SRC_DIV_MASK; ++ shift = CLK_MATRIX_600M_SRC_DIV_SHIFT; ++ break; ++ ++ case ACLK_BUS_VOPGL_ROOT: ++ case ACLK_BUS_VOPGL_BIU: ++ con = 43; ++ mask = ACLK_BUS_VOPGL_ROOT_DIV_MASK; ++ shift = ACLK_BUS_VOPGL_ROOT_DIV_SHIFT; ++ break; ++ ++ default: ++ return -ENOENT; ++ } ++ ++ if (sel_mask) { ++ sel = (readl(&cru->clksel_con[con]) & sel_mask) >> sel_shift; ++ if (sel == CLK_MATRIX_250M_SRC_SEL_CLK_GPLL_MUX) // TODO ++ prate = priv->gpll_hz; ++ else ++ prate = priv->cpll_hz; ++ } else { ++ if (is_gpll_parent) ++ prate = priv->gpll_hz; ++ else ++ prate = priv->cpll_hz; ++ } ++ ++ div = (readl(&cru->clksel_con[con]) & mask) >> shift; ++ ++ /* NOTE: '-1' to balance the DIV_TO_RATE() 'div+1' */ ++ return is_halfdiv ? DIV_TO_RATE(prate * 2, (3 + 2 * div) - 1) : DIV_TO_RATE(prate, div); ++} ++ ++static ulong rk3528_cgpll_matrix_set_rate(struct rk3528_clk_priv *priv, ++ ulong clk_id, ulong rate) ++{ ++ struct rk3528_cru *cru = priv->cru; ++ u32 sel, div, mask, shift, con; ++ u32 sel_mask = 0, sel_shift; ++ u8 is_gpll_parent = 1; ++ u8 is_halfdiv = 0; ++ ulong prate = 0; ++ ++ switch (clk_id) { ++ case CLK_MATRIX_50M_SRC: ++ con = 0; ++ mask = CLK_MATRIX_50M_SRC_DIV_MASK; ++ shift = CLK_MATRIX_50M_SRC_DIV_SHIFT; ++ is_gpll_parent = 0; ++ break; ++ ++ case CLK_MATRIX_100M_SRC: ++ con = 0; ++ mask = CLK_MATRIX_100M_SRC_DIV_MASK; ++ shift = CLK_MATRIX_100M_SRC_DIV_SHIFT; ++ is_gpll_parent = 0; ++ break; ++ ++ case CLK_MATRIX_150M_SRC: ++ con = 1; ++ mask = CLK_MATRIX_150M_SRC_DIV_MASK; ++ shift = CLK_MATRIX_150M_SRC_DIV_SHIFT; ++ break; ++ ++ case CLK_MATRIX_200M_SRC: ++ con = 1; ++ mask = CLK_MATRIX_200M_SRC_DIV_MASK; ++ shift = CLK_MATRIX_200M_SRC_DIV_SHIFT; ++ break; ++ ++ case CLK_MATRIX_250M_SRC: ++ con = 1; ++ mask = CLK_MATRIX_250M_SRC_DIV_MASK; ++ shift = CLK_MATRIX_250M_SRC_DIV_SHIFT; ++ sel_mask = CLK_MATRIX_250M_SRC_SEL_MASK; ++ sel_shift = CLK_MATRIX_250M_SRC_SEL_SHIFT; ++ break; ++ ++ case CLK_MATRIX_300M_SRC: ++ con = 2; ++ mask = CLK_MATRIX_300M_SRC_DIV_MASK; ++ shift = CLK_MATRIX_300M_SRC_DIV_SHIFT; ++ break; ++ ++ case CLK_MATRIX_339M_SRC: ++ con = 2; ++ mask = CLK_MATRIX_339M_SRC_DIV_MASK; ++ shift = CLK_MATRIX_339M_SRC_DIV_SHIFT; ++ is_halfdiv = 1; ++ break; ++ ++ case CLK_MATRIX_400M_SRC: ++ con = 2; ++ mask = CLK_MATRIX_400M_SRC_DIV_MASK; ++ shift = CLK_MATRIX_400M_SRC_DIV_SHIFT; ++ break; ++ ++ case CLK_MATRIX_500M_SRC: ++ con = 3; ++ mask = CLK_MATRIX_500M_SRC_DIV_MASK; ++ shift = CLK_MATRIX_500M_SRC_DIV_SHIFT; ++ sel_mask = CLK_MATRIX_500M_SRC_SEL_MASK; ++ sel_shift = CLK_MATRIX_500M_SRC_SEL_SHIFT; ++ break; ++ ++ case CLK_MATRIX_600M_SRC: ++ con = 4; ++ mask = CLK_MATRIX_600M_SRC_DIV_MASK; ++ shift = CLK_MATRIX_600M_SRC_DIV_SHIFT; ++ break; ++ ++ case ACLK_BUS_VOPGL_ROOT: ++ case ACLK_BUS_VOPGL_BIU: ++ con = 43; ++ mask = ACLK_BUS_VOPGL_ROOT_DIV_MASK; ++ shift = ACLK_BUS_VOPGL_ROOT_DIV_SHIFT; ++ break; ++ ++ default: ++ return -ENOENT; ++ } ++ ++ if (sel_mask) { ++ if (priv->gpll_hz % rate == 0) { ++ sel = CLK_MATRIX_250M_SRC_SEL_CLK_GPLL_MUX; // TODO ++ prate = priv->gpll_hz; ++ } else { ++ sel = CLK_MATRIX_250M_SRC_SEL_CLK_CPLL_MUX; ++ prate = priv->cpll_hz; ++ } ++ } else { ++ if (is_gpll_parent) ++ prate = priv->gpll_hz; ++ else ++ prate = priv->cpll_hz; ++ } ++ ++ if (is_halfdiv) ++ /* NOTE: '+1' to balance the following rk_clrsetreg() 'div-1' */ ++ div = DIV_ROUND_UP((prate * 2) - (3 * rate), 2 * rate) + 1; ++ else ++ div = DIV_ROUND_UP(prate, rate); ++ ++ rk_clrsetreg(&cru->clksel_con[con], mask, (div - 1) << shift); ++ if (sel_mask) ++ rk_clrsetreg(&cru->clksel_con[con], sel_mask, sel << sel_shift); ++ ++ return rk3528_cgpll_matrix_get_rate(priv, clk_id); ++} ++ ++static ulong rk3528_i2c_get_clk(struct rk3528_clk_priv *priv, ulong clk_id) ++{ ++ struct rk3528_cru *cru = priv->cru; ++ u32 id, sel, con, mask, shift; ++ u8 is_pmucru = 0; ++ ulong rate; ++ ++ switch (clk_id) { ++ case CLK_I2C0: ++ id = 79; ++ mask = CLK_I2C0_SEL_MASK; ++ shift = CLK_I2C0_SEL_SHIFT; ++ break; ++ ++ case CLK_I2C1: ++ id = 79; ++ mask = CLK_I2C1_SEL_MASK; ++ shift = CLK_I2C1_SEL_SHIFT; ++ break; ++ ++ case CLK_I2C2: ++ id = 0; ++ mask = CLK_I2C2_SEL_MASK; ++ shift = CLK_I2C2_SEL_SHIFT; ++ is_pmucru = 1; ++ break; ++ ++ case CLK_I2C3: ++ id = 63; ++ mask = CLK_I2C3_SEL_MASK; ++ shift = CLK_I2C3_SEL_SHIFT; ++ break; ++ ++ case CLK_I2C4: ++ id = 85; ++ mask = CLK_I2C4_SEL_MASK; ++ shift = CLK_I2C4_SEL_SHIFT; ++ break; ++ ++ case CLK_I2C5: ++ id = 63; ++ mask = CLK_I2C5_SEL_MASK; ++ shift = CLK_I2C5_SEL_SHIFT; ++ break; ++ ++ case CLK_I2C6: ++ id = 64; ++ mask = CLK_I2C6_SEL_MASK; ++ shift = CLK_I2C6_SEL_SHIFT; ++ break; ++ ++ case CLK_I2C7: ++ id = 86; ++ mask = CLK_I2C7_SEL_MASK; ++ shift = CLK_I2C7_SEL_SHIFT; ++ break; ++ ++ default: ++ return -ENOENT; ++ } ++ ++ if (is_pmucru) ++ con = readl(&cru->pmuclksel_con[id]); ++ else ++ con = readl(&cru->clksel_con[id]); ++ sel = (con & mask) >> shift; ++ if (sel == CLK_I2C3_SEL_CLK_MATRIX_200M_SRC) ++ rate = 200 * MHz; ++ else if (sel == CLK_I2C3_SEL_CLK_MATRIX_100M_SRC) ++ rate = 100 * MHz; ++ else if (sel == CLK_I2C3_SEL_CLK_MATRIX_50M_SRC) ++ rate = 50 * MHz; ++ else ++ rate = OSC_HZ; ++ ++ return rate; ++} ++ ++static ulong rk3528_i2c_set_clk(struct rk3528_clk_priv *priv, ulong clk_id, ++ ulong rate) ++{ ++ struct rk3528_cru *cru = priv->cru; ++ u32 id, sel, mask, shift; ++ u8 is_pmucru = 0; ++ ++ if (rate >= 198 * MHz) ++ sel = CLK_I2C3_SEL_CLK_MATRIX_200M_SRC; ++ else if (rate >= 99 * MHz) ++ sel = CLK_I2C3_SEL_CLK_MATRIX_100M_SRC; ++ else if (rate >= 50 * MHz) ++ sel = CLK_I2C3_SEL_CLK_MATRIX_50M_SRC; ++ else ++ sel = CLK_I2C3_SEL_XIN_OSC0_FUNC; ++ ++ switch (clk_id) { ++ case CLK_I2C0: ++ id = 79; ++ mask = CLK_I2C0_SEL_MASK; ++ shift = CLK_I2C0_SEL_SHIFT; ++ break; ++ ++ case CLK_I2C1: ++ id = 79; ++ mask = CLK_I2C1_SEL_MASK; ++ shift = CLK_I2C1_SEL_SHIFT; ++ break; ++ ++ case CLK_I2C2: ++ id = 0; ++ mask = CLK_I2C2_SEL_MASK; ++ shift = CLK_I2C2_SEL_SHIFT; ++ is_pmucru = 1; ++ break; ++ ++ case CLK_I2C3: ++ id = 63; ++ mask = CLK_I2C3_SEL_MASK; ++ shift = CLK_I2C3_SEL_SHIFT; ++ break; ++ ++ case CLK_I2C4: ++ id = 85; ++ mask = CLK_I2C4_SEL_MASK; ++ shift = CLK_I2C4_SEL_SHIFT; ++ break; ++ ++ case CLK_I2C5: ++ id = 63; ++ mask = CLK_I2C5_SEL_MASK; ++ shift = CLK_I2C5_SEL_SHIFT; ++ ++ case CLK_I2C6: ++ id = 64; ++ mask = CLK_I2C6_SEL_MASK; ++ shift = CLK_I2C6_SEL_SHIFT; ++ break; ++ ++ case CLK_I2C7: ++ id = 86; ++ mask = CLK_I2C7_SEL_MASK; ++ shift = CLK_I2C7_SEL_SHIFT; ++ break; ++ ++ default: ++ return -ENOENT; ++ } ++ ++ if (is_pmucru) ++ rk_clrsetreg(&cru->pmuclksel_con[id], mask, sel << shift); ++ else ++ rk_clrsetreg(&cru->clksel_con[id], mask, sel << shift); ++ ++ return rk3528_i2c_get_clk(priv, clk_id); ++} ++ ++static ulong rk3528_spi_get_clk(struct rk3528_clk_priv *priv, ulong clk_id) ++{ ++ struct rk3528_cru *cru = priv->cru; ++ u32 id, sel, con, mask, shift; ++ ulong rate; ++ ++ switch (clk_id) { ++ case CLK_SPI0: ++ id = 79; ++ mask = CLK_SPI0_SEL_MASK; ++ shift = CLK_SPI0_SEL_SHIFT; ++ break; ++ ++ case CLK_SPI1: ++ id = 63; ++ mask = CLK_SPI1_SEL_MASK; ++ shift = CLK_SPI1_SEL_SHIFT; ++ break; ++ default: ++ return -ENOENT; ++ } ++ ++ con = readl(&cru->clksel_con[id]); ++ sel = (con & mask) >> shift; ++ if (sel == CLK_SPI1_SEL_CLK_MATRIX_200M_SRC) ++ rate = 200 * MHz; ++ else if (sel == CLK_SPI1_SEL_CLK_MATRIX_100M_SRC) ++ rate = 100 * MHz; ++ else if (sel == CLK_SPI1_SEL_CLK_MATRIX_50M_SRC) ++ rate = 50 * MHz; ++ else ++ rate = OSC_HZ; ++ ++ return rate; ++} ++ ++static ulong rk3528_spi_set_clk(struct rk3528_clk_priv *priv, ++ ulong clk_id, ulong rate) ++{ ++ struct rk3528_cru *cru = priv->cru; ++ u32 id, sel, mask, shift; ++ ++ if (rate >= 198 * MHz) ++ sel = CLK_SPI1_SEL_CLK_MATRIX_200M_SRC; ++ else if (rate >= 99 * MHz) ++ sel = CLK_SPI1_SEL_CLK_MATRIX_100M_SRC; ++ else if (rate >= 50 * MHz) ++ sel = CLK_SPI1_SEL_CLK_MATRIX_50M_SRC; ++ else ++ sel = CLK_SPI1_SEL_XIN_OSC0_FUNC; ++ ++ switch (clk_id) { ++ case CLK_SPI0: ++ id = 79; ++ mask = CLK_SPI0_SEL_MASK; ++ shift = CLK_SPI0_SEL_SHIFT; ++ break; ++ ++ case CLK_SPI1: ++ id = 63; ++ mask = CLK_SPI1_SEL_MASK; ++ shift = CLK_SPI1_SEL_SHIFT; ++ break; ++ default: ++ return -ENOENT; ++ } ++ ++ rk_clrsetreg(&cru->clksel_con[id], mask, sel << shift); ++ ++ return rk3528_spi_get_clk(priv, clk_id); ++} ++ ++static ulong rk3528_pwm_get_clk(struct rk3528_clk_priv *priv, ulong clk_id) ++{ ++ struct rk3528_cru *cru = priv->cru; ++ u32 id, sel, con, mask, shift; ++ ulong rate; ++ ++ switch (clk_id) { ++ case CLK_PWM0: ++ id = 44; ++ mask = CLK_PWM0_SEL_MASK; ++ shift = CLK_PWM0_SEL_SHIFT; ++ break; ++ ++ case CLK_PWM1: ++ id = 44; ++ mask = CLK_PWM1_SEL_MASK; ++ shift = CLK_PWM1_SEL_SHIFT; ++ break; ++ ++ default: ++ return -ENOENT; ++ } ++ ++ con = readl(&cru->clksel_con[id]); ++ sel = (con & mask) >> shift; ++ if (sel == CLK_PWM0_SEL_CLK_MATRIX_100M_SRC) ++ rate = 100 * MHz; ++ if (sel == CLK_PWM0_SEL_CLK_MATRIX_50M_SRC) ++ rate = 50 * MHz; ++ else ++ rate = OSC_HZ; ++ ++ return rate; ++} ++ ++static ulong rk3528_pwm_set_clk(struct rk3528_clk_priv *priv, ++ ulong clk_id, ulong rate) ++{ ++ struct rk3528_cru *cru = priv->cru; ++ u32 id, sel, mask, shift; ++ ++ if (rate >= 99 * MHz) ++ sel = CLK_PWM0_SEL_CLK_MATRIX_100M_SRC; ++ else if (rate >= 50 * MHz) ++ sel = CLK_PWM0_SEL_CLK_MATRIX_50M_SRC; ++ else ++ sel = CLK_PWM0_SEL_XIN_OSC0_FUNC; ++ ++ switch (clk_id) { ++ case CLK_PWM0: ++ id = 44; ++ mask = CLK_PWM0_SEL_MASK; ++ shift = CLK_PWM0_SEL_SHIFT; ++ break; ++ ++ case CLK_PWM1: ++ id = 44; ++ mask = CLK_PWM1_SEL_MASK; ++ shift = CLK_PWM1_SEL_SHIFT; ++ break; ++ ++ default: ++ return -ENOENT; ++ } ++ ++ rk_clrsetreg(&cru->clksel_con[id], mask, sel << shift); ++ ++ return rk3528_pwm_get_clk(priv, clk_id); ++} ++ ++static ulong rk3528_adc_get_clk(struct rk3528_clk_priv *priv, ulong clk_id) ++{ ++ struct rk3528_cru *cru = priv->cru; ++ u32 div, con; ++ ++ con = readl(&cru->clksel_con[74]); ++ switch (clk_id) { ++ case CLK_SARADC: ++ div = (con & CLK_SARADC_DIV_MASK) >> ++ CLK_SARADC_DIV_SHIFT; ++ break; ++ ++ case CLK_TSADC_TSEN: ++ div = (con & CLK_TSADC_TSEN_DIV_MASK) >> ++ CLK_TSADC_TSEN_DIV_SHIFT; ++ break; ++ ++ case CLK_TSADC: ++ div = (con & CLK_TSADC_DIV_MASK) >> ++ CLK_TSADC_DIV_SHIFT; ++ break; ++ ++ default: ++ return -ENOENT; ++ } ++ ++ return DIV_TO_RATE(OSC_HZ, div); ++} ++ ++static ulong rk3528_adc_set_clk(struct rk3528_clk_priv *priv, ++ ulong clk_id, ulong rate) ++{ ++ struct rk3528_cru *cru = priv->cru; ++ u32 div, mask, shift; ++ ++ switch (clk_id) { ++ case CLK_SARADC: ++ mask = CLK_SARADC_DIV_MASK; ++ shift = CLK_SARADC_DIV_SHIFT; ++ break; ++ ++ case CLK_TSADC_TSEN: ++ mask = CLK_TSADC_TSEN_DIV_MASK; ++ shift = CLK_TSADC_TSEN_DIV_SHIFT; ++ break; ++ ++ case CLK_TSADC: ++ mask = CLK_TSADC_DIV_MASK; ++ shift = CLK_TSADC_DIV_SHIFT; ++ break; ++ ++ default: ++ return -ENOENT; ++ } ++ ++ div = DIV_ROUND_UP(OSC_HZ, rate); ++ rk_clrsetreg(&cru->clksel_con[74], mask, (div - 1) << shift); ++ ++ return rk3528_adc_get_clk(priv, clk_id); ++} ++ ++static ulong rk3528_sdmmc_get_clk(struct rk3528_clk_priv *priv, ulong clk_id) ++{ ++ struct rk3528_cru *cru = priv->cru; ++ u32 div, sel, con; ++ ulong prate; ++ ++ con = readl(&cru->clksel_con[85]); ++ div = (con & CCLK_SRC_SDMMC0_DIV_MASK) >> ++ CCLK_SRC_SDMMC0_DIV_SHIFT; ++ sel = (con & CCLK_SRC_SDMMC0_SEL_MASK) >> ++ CCLK_SRC_SDMMC0_SEL_SHIFT; ++ ++ if (sel == CCLK_SRC_SDMMC0_SEL_CLK_GPLL_MUX) ++ prate = priv->gpll_hz; ++ else if (sel == CCLK_SRC_SDMMC0_SEL_CLK_CPLL_MUX) ++ prate = priv->cpll_hz; ++ else ++ prate = OSC_HZ; ++ ++ return DIV_TO_RATE(prate, div); ++} ++ ++static ulong rk3528_sdmmc_set_clk(struct rk3528_clk_priv *priv, ++ ulong clk_id, ulong rate) ++{ ++ struct rk3528_cru *cru = priv->cru; ++ u32 div, sel; ++ ++ if (OSC_HZ % rate == 0) { ++ div = DIV_ROUND_UP(OSC_HZ, rate); ++ sel = CCLK_SRC_SDMMC0_SEL_XIN_OSC0_FUNC; ++ } else if ((priv->cpll_hz % rate) == 0) { ++ div = DIV_ROUND_UP(priv->cpll_hz, rate); ++ sel = CCLK_SRC_SDMMC0_SEL_CLK_CPLL_MUX; ++ } else { ++ div = DIV_ROUND_UP(priv->gpll_hz, rate); ++ sel = CCLK_SRC_SDMMC0_SEL_CLK_GPLL_MUX; ++ } ++ ++ assert(div - 1 <= 63); ++ rk_clrsetreg(&cru->clksel_con[85], ++ CCLK_SRC_SDMMC0_SEL_MASK | ++ CCLK_SRC_SDMMC0_DIV_MASK, ++ sel << CCLK_SRC_SDMMC0_SEL_SHIFT | ++ (div - 1) << CCLK_SRC_SDMMC0_DIV_SHIFT); ++ ++ return rk3528_sdmmc_get_clk(priv, clk_id); ++} ++ ++static ulong rk3528_sfc_get_clk(struct rk3528_clk_priv *priv) ++{ ++ struct rk3528_cru *cru = priv->cru; ++ u32 div, sel, con, parent; ++ ++ con = readl(&cru->clksel_con[61]); ++ div = (con & SCLK_SFC_DIV_MASK) >> ++ SCLK_SFC_DIV_SHIFT; ++ sel = (con & SCLK_SFC_SEL_MASK) >> ++ SCLK_SFC_SEL_SHIFT; ++ if (sel == SCLK_SFC_SEL_CLK_GPLL_MUX) ++ parent = priv->gpll_hz; ++ else if (sel == SCLK_SFC_SEL_CLK_CPLL_MUX) ++ parent = priv->cpll_hz; ++ else ++ parent = OSC_HZ; ++ ++ return DIV_TO_RATE(parent, div); ++} ++ ++static ulong rk3528_sfc_set_clk(struct rk3528_clk_priv *priv, ulong rate) ++{ ++ struct rk3528_cru *cru = priv->cru; ++ int div, sel; ++ ++ if (OSC_HZ % rate == 0) { ++ div = DIV_ROUND_UP(OSC_HZ, rate); ++ sel = SCLK_SFC_SEL_XIN_OSC0_FUNC; ++ } else if ((priv->cpll_hz % rate) == 0) { ++ div = DIV_ROUND_UP(priv->cpll_hz, rate); ++ sel = SCLK_SFC_SEL_CLK_CPLL_MUX; ++ } else { ++ div = DIV_ROUND_UP(priv->gpll_hz, rate); ++ sel = SCLK_SFC_SEL_CLK_GPLL_MUX; ++ } ++ ++ assert(div - 1 <= 63); ++ rk_clrsetreg(&cru->clksel_con[61], ++ SCLK_SFC_SEL_MASK | ++ SCLK_SFC_DIV_MASK, ++ sel << SCLK_SFC_SEL_SHIFT | ++ (div - 1) << SCLK_SFC_DIV_SHIFT); ++ ++ return rk3528_sfc_get_clk(priv); ++} ++ ++static ulong rk3528_emmc_get_clk(struct rk3528_clk_priv *priv) ++{ ++ struct rk3528_cru *cru = priv->cru; ++ u32 div, sel, con, parent; ++ ++ con = readl(&cru->clksel_con[62]); ++ div = (con & CCLK_SRC_EMMC_DIV_MASK) >> ++ CCLK_SRC_EMMC_DIV_SHIFT; ++ sel = (con & CCLK_SRC_EMMC_SEL_MASK) >> ++ CCLK_SRC_EMMC_SEL_SHIFT; ++ ++ if (sel == CCLK_SRC_EMMC_SEL_CLK_GPLL_MUX) ++ parent = priv->gpll_hz; ++ else if (sel == CCLK_SRC_EMMC_SEL_CLK_CPLL_MUX) ++ parent = priv->cpll_hz; ++ else ++ parent = OSC_HZ; ++ ++ return DIV_TO_RATE(parent, div); ++} ++ ++static ulong rk3528_emmc_set_clk(struct rk3528_clk_priv *priv, ulong rate) ++{ ++ struct rk3528_cru *cru = priv->cru; ++ u32 div, sel; ++ ++ if (OSC_HZ % rate == 0) { ++ div = DIV_ROUND_UP(OSC_HZ, rate); ++ sel = CCLK_SRC_EMMC_SEL_XIN_OSC0_FUNC; ++ } else if ((priv->cpll_hz % rate) == 0) { ++ div = DIV_ROUND_UP(priv->cpll_hz, rate); ++ sel = CCLK_SRC_EMMC_SEL_CLK_CPLL_MUX; ++ } else { ++ div = DIV_ROUND_UP(priv->gpll_hz, rate); ++ sel = CCLK_SRC_EMMC_SEL_CLK_GPLL_MUX; ++ } ++ ++ assert(div - 1 <= 63); ++ rk_clrsetreg(&cru->clksel_con[62], ++ CCLK_SRC_EMMC_SEL_MASK | ++ CCLK_SRC_EMMC_DIV_MASK, ++ sel << CCLK_SRC_EMMC_SEL_SHIFT | ++ (div - 1) << CCLK_SRC_EMMC_DIV_SHIFT); ++ ++ return rk3528_emmc_get_clk(priv); ++} ++ ++static ulong rk3528_dclk_vop_get_clk(struct rk3528_clk_priv *priv, ulong clk_id) ++{ ++ struct rk3528_cru *cru = priv->cru; ++ u32 div_mask, div_shift; ++ u32 sel_mask, sel_shift; ++ u32 id, con, sel, div; ++ ulong prate; ++ ++ switch (clk_id) { ++ case DCLK_VOP0: ++ id = 32; ++ sel_mask = DCLK_VOP_SRC0_SEL_MASK; ++ sel_shift = DCLK_VOP_SRC0_SEL_SHIFT; ++ /* FIXME if need src: clk_hdmiphy_pixel_io */ ++ div_mask = DCLK_VOP_SRC0_DIV_MASK; ++ div_shift = DCLK_VOP_SRC0_DIV_SHIFT; ++ break; ++ ++ case DCLK_VOP1: ++ id = 33; ++ sel_mask = DCLK_VOP_SRC1_SEL_MASK; ++ sel_shift = DCLK_VOP_SRC1_SEL_SHIFT; ++ div_mask = DCLK_VOP_SRC1_DIV_MASK; ++ div_shift = DCLK_VOP_SRC1_DIV_SHIFT; ++ break; ++ ++ default: ++ return -ENOENT; ++ } ++ ++ con = readl(&cru->clksel_con[id]); ++ div = (con & div_mask) >> div_shift; ++ sel = (con & sel_mask) >> sel_shift; ++ if (sel == DCLK_VOP_SRC_SEL_CLK_GPLL_MUX) ++ prate = priv->gpll_hz; ++ else ++ prate = priv->cpll_hz; ++ ++ return DIV_TO_RATE(prate, div); ++} ++ ++static ulong rk3528_dclk_vop_set_clk(struct rk3528_clk_priv *priv, ++ ulong clk_id, ulong rate) ++{ ++ struct rk3528_cru *cru = priv->cru; ++ u32 div_mask, div_shift; ++ u32 sel_mask, sel_shift; ++ u32 id, sel, div; ++ ulong prate; ++ ++ switch (clk_id) { ++ case DCLK_VOP0: ++ id = 32; ++ sel_mask = DCLK_VOP_SRC0_SEL_MASK; ++ sel_shift = DCLK_VOP_SRC0_SEL_SHIFT; ++ /* FIXME if need src: clk_hdmiphy_pixel_io */ ++ div_mask = DCLK_VOP_SRC0_DIV_MASK; ++ div_shift = DCLK_VOP_SRC0_DIV_SHIFT; ++ break; ++ ++ case DCLK_VOP1: ++ id = 33; ++ sel_mask = DCLK_VOP_SRC1_SEL_MASK; ++ sel_shift = DCLK_VOP_SRC1_SEL_SHIFT; ++ div_mask = DCLK_VOP_SRC1_DIV_MASK; ++ div_shift = DCLK_VOP_SRC1_DIV_SHIFT; ++ break; ++ ++ default: ++ return -ENOENT; ++ } ++ ++ if ((priv->gpll_hz % rate) == 0) { ++ prate = priv->gpll_hz; ++ sel = (DCLK_VOP_SRC_SEL_CLK_GPLL_MUX << sel_shift) & sel_mask; ++ } else { ++ prate = priv->cpll_hz; ++ sel = (DCLK_VOP_SRC_SEL_CLK_CPLL_MUX << sel_shift) & sel_mask; ++ } ++ ++ div = ((DIV_ROUND_UP(prate, rate) - 1) << div_shift) & div_mask; ++ rk_clrsetreg(&cru->clksel_con[id], sel, div); ++ ++ return rk3528_dclk_vop_get_clk(priv, clk_id); ++} ++ ++static ulong rk3528_uart_get_rate(struct rk3528_clk_priv *priv, ulong clk_id) ++{ ++ struct rk3528_cru *cru = priv->cru; ++ u32 sel_shift, sel_mask, div_shift, div_mask; ++ u32 sel, id, con, frac_div, div; ++ ulong m, n, rate; ++ ++ switch (clk_id) { ++ case SCLK_UART0: ++ id = 6; ++ sel_shift = SCLK_UART0_SRC_SEL_SHIFT; ++ sel_mask = SCLK_UART0_SRC_SEL_MASK; ++ div_shift = CLK_UART0_SRC_DIV_SHIFT; ++ div_mask = CLK_UART0_SRC_DIV_MASK; ++ break; ++ ++ case SCLK_UART1: ++ id = 8; ++ sel_shift = SCLK_UART1_SRC_SEL_SHIFT; ++ sel_mask = SCLK_UART1_SRC_SEL_MASK; ++ div_shift = CLK_UART1_SRC_DIV_SHIFT; ++ div_mask = CLK_UART1_SRC_DIV_MASK; ++ break; ++ ++ case SCLK_UART2: ++ id = 10; ++ sel_shift = SCLK_UART2_SRC_SEL_SHIFT; ++ sel_mask = SCLK_UART2_SRC_SEL_MASK; ++ div_shift = CLK_UART2_SRC_DIV_SHIFT; ++ div_mask = CLK_UART2_SRC_DIV_MASK; ++ break; ++ ++ case SCLK_UART3: ++ id = 12; ++ sel_shift = SCLK_UART3_SRC_SEL_SHIFT; ++ sel_mask = SCLK_UART3_SRC_SEL_MASK; ++ div_shift = CLK_UART3_SRC_DIV_SHIFT; ++ div_mask = CLK_UART3_SRC_DIV_MASK; ++ break; ++ ++ case SCLK_UART4: ++ id = 14; ++ sel_shift = SCLK_UART4_SRC_SEL_SHIFT; ++ sel_mask = SCLK_UART4_SRC_SEL_MASK; ++ div_shift = CLK_UART4_SRC_DIV_SHIFT; ++ div_mask = CLK_UART4_SRC_DIV_MASK; ++ break; ++ ++ case SCLK_UART5: ++ id = 16; ++ sel_shift = SCLK_UART5_SRC_SEL_SHIFT; ++ sel_mask = SCLK_UART5_SRC_SEL_MASK; ++ div_shift = CLK_UART5_SRC_DIV_SHIFT; ++ div_mask = CLK_UART5_SRC_DIV_MASK; ++ break; ++ ++ case SCLK_UART6: ++ id = 18; ++ sel_shift = SCLK_UART6_SRC_SEL_SHIFT; ++ sel_mask = SCLK_UART6_SRC_SEL_MASK; ++ div_shift = CLK_UART6_SRC_DIV_SHIFT; ++ div_mask = CLK_UART6_SRC_DIV_MASK; ++ break; ++ ++ case SCLK_UART7: ++ id = 20; ++ sel_shift = SCLK_UART7_SRC_SEL_SHIFT; ++ sel_mask = SCLK_UART7_SRC_SEL_MASK; ++ div_shift = CLK_UART7_SRC_DIV_SHIFT; ++ div_mask = CLK_UART7_SRC_DIV_MASK; ++ break; ++ ++ default: ++ return -ENOENT; ++ } ++ ++ con = readl(&cru->clksel_con[id - 2]); ++ div = (con & div_mask) >> div_shift; ++ ++ con = readl(&cru->clksel_con[id]); ++ sel = (con & sel_mask) >> sel_shift; ++ ++ if (sel == SCLK_UART0_SRC_SEL_CLK_UART0_SRC) { ++ rate = DIV_TO_RATE(priv->gpll_hz, div); ++ } else if (sel == SCLK_UART0_SRC_SEL_CLK_UART0_FRAC) { ++ frac_div = readl(&cru->clksel_con[id - 1]); ++ n = (frac_div & 0xffff0000) >> 16; ++ m = frac_div & 0x0000ffff; ++ rate = DIV_TO_RATE(priv->gpll_hz, div) * n / m; ++ } else { ++ rate = OSC_HZ; ++ } ++ ++ return rate; ++} ++ ++static ulong rk3528_uart_set_rate(struct rk3528_clk_priv *priv, ++ ulong clk_id, ulong rate) ++{ ++ struct rk3528_cru *cru = priv->cru; ++ u32 sel_shift, sel_mask, div_shift, div_mask; ++ u32 sel, id, div; ++ ulong m = 0, n = 0, val; ++ ++ if (rate == OSC_HZ) { ++ sel = SCLK_UART0_SRC_SEL_XIN_OSC0_FUNC; ++ div = DIV_ROUND_UP(OSC_HZ, rate); ++ } else if (priv->gpll_hz % rate == 0) { ++ sel = SCLK_UART0_SRC_SEL_CLK_UART0_SRC; ++ div = DIV_ROUND_UP(priv->gpll_hz, rate); ++ } else { ++ sel = SCLK_UART0_SRC_SEL_CLK_UART0_FRAC; ++ div = 2; ++ rational_best_approximation(rate, priv->gpll_hz / div, ++ GENMASK(16 - 1, 0), ++ GENMASK(16 - 1, 0), ++ &n, &m); ++ } ++ ++ switch (clk_id) { ++ case SCLK_UART0: ++ id = 6; ++ sel_shift = SCLK_UART0_SRC_SEL_SHIFT; ++ sel_mask = SCLK_UART0_SRC_SEL_MASK; ++ div_shift = CLK_UART0_SRC_DIV_SHIFT; ++ div_mask = CLK_UART0_SRC_DIV_MASK; ++ break; ++ ++ case SCLK_UART1: ++ id = 8; ++ sel_shift = SCLK_UART1_SRC_SEL_SHIFT; ++ sel_mask = SCLK_UART1_SRC_SEL_MASK; ++ div_shift = CLK_UART1_SRC_DIV_SHIFT; ++ div_mask = CLK_UART1_SRC_DIV_MASK; ++ break; ++ ++ case SCLK_UART2: ++ id = 10; ++ sel_shift = SCLK_UART2_SRC_SEL_SHIFT; ++ sel_mask = SCLK_UART2_SRC_SEL_MASK; ++ div_shift = CLK_UART2_SRC_DIV_SHIFT; ++ div_mask = CLK_UART2_SRC_DIV_MASK; ++ break; ++ ++ case SCLK_UART3: ++ id = 12; ++ sel_shift = SCLK_UART3_SRC_SEL_SHIFT; ++ sel_mask = SCLK_UART3_SRC_SEL_MASK; ++ div_shift = CLK_UART3_SRC_DIV_SHIFT; ++ div_mask = CLK_UART3_SRC_DIV_MASK; ++ break; ++ ++ case SCLK_UART4: ++ id = 14; ++ sel_shift = SCLK_UART4_SRC_SEL_SHIFT; ++ sel_mask = SCLK_UART4_SRC_SEL_MASK; ++ div_shift = CLK_UART4_SRC_DIV_SHIFT; ++ div_mask = CLK_UART4_SRC_DIV_MASK; ++ break; ++ ++ case SCLK_UART5: ++ id = 16; ++ sel_shift = SCLK_UART5_SRC_SEL_SHIFT; ++ sel_mask = SCLK_UART5_SRC_SEL_MASK; ++ div_shift = CLK_UART5_SRC_DIV_SHIFT; ++ div_mask = CLK_UART5_SRC_DIV_MASK; ++ break; ++ ++ case SCLK_UART6: ++ id = 18; ++ sel_shift = SCLK_UART6_SRC_SEL_SHIFT; ++ sel_mask = SCLK_UART6_SRC_SEL_MASK; ++ div_shift = CLK_UART6_SRC_DIV_SHIFT; ++ div_mask = CLK_UART6_SRC_DIV_MASK; ++ break; ++ ++ case SCLK_UART7: ++ id = 20; ++ sel_shift = SCLK_UART7_SRC_SEL_SHIFT; ++ sel_mask = SCLK_UART7_SRC_SEL_MASK; ++ div_shift = CLK_UART7_SRC_DIV_SHIFT; ++ div_mask = CLK_UART7_SRC_DIV_MASK; ++ break; ++ ++ default: ++ return -ENOENT; ++ } ++ ++ rk_clrsetreg(&cru->clksel_con[id - 2], div_mask, (div - 1) << div_shift); ++ rk_clrsetreg(&cru->clksel_con[id], sel_mask, sel << sel_shift); ++ if (m && n) { ++ val = n << 16 | m; ++ writel(val, &cru->clksel_con[id - 1]); ++ } ++ ++ return rk3528_uart_get_rate(priv, clk_id); ++} ++ ++static ulong rk3528_clk_get_rate(struct clk *clk) ++{ ++ struct rk3528_clk_priv *priv = dev_get_priv(clk->dev); ++ ulong rate = 0; ++ ++ if (!priv->gpll_hz || !priv->cpll_hz) { ++ printf("%s: gpll=%lu, cpll=%ld\n", ++ __func__, priv->gpll_hz, priv->cpll_hz); ++ return -ENOENT; ++ } ++ ++ switch (clk->id) { ++ case PLL_APLL: ++ case ARMCLK: ++ rate = rockchip_pll_get_rate(&rk3528_pll_clks[APLL], priv->cru, ++ APLL); ++ break; ++ case PLL_CPLL: ++ rate = rockchip_pll_get_rate(&rk3528_pll_clks[CPLL], priv->cru, ++ CPLL); ++ break; ++ case PLL_GPLL: ++ rate = rockchip_pll_get_rate(&rk3528_pll_clks[GPLL], priv->cru, ++ GPLL); ++ break; ++ ++ case PLL_PPLL: ++ rate = rockchip_pll_get_rate(&rk3528_pll_clks[PPLL], priv->cru, ++ PPLL); ++ break; ++ case PLL_DPLL: ++ rate = rockchip_pll_get_rate(&rk3528_pll_clks[DPLL], priv->cru, ++ DPLL); ++ break; ++ ++ case TCLK_WDT_NS: ++ rate = OSC_HZ; ++ break; ++ case CLK_I2C0: ++ case CLK_I2C1: ++ case CLK_I2C2: ++ case CLK_I2C3: ++ case CLK_I2C4: ++ case CLK_I2C5: ++ case CLK_I2C6: ++ case CLK_I2C7: ++ rate = rk3528_i2c_get_clk(priv, clk->id); ++ break; ++ case CLK_SPI0: ++ case CLK_SPI1: ++ rate = rk3528_spi_get_clk(priv, clk->id); ++ break; ++ case CLK_PWM0: ++ case CLK_PWM1: ++ rate = rk3528_pwm_get_clk(priv, clk->id); ++ break; ++ case CLK_SARADC: ++ case CLK_TSADC: ++ case CLK_TSADC_TSEN: ++ rate = rk3528_adc_get_clk(priv, clk->id); ++ break; ++ case CCLK_SRC_EMMC: ++ rate = rk3528_emmc_get_clk(priv); ++ break; ++ case HCLK_SDMMC0: ++ case CCLK_SRC_SDMMC0: ++ rate = rk3528_sdmmc_get_clk(priv, clk->id); ++ break; ++ case SCLK_SFC: ++ rate = rk3528_sfc_get_clk(priv); ++ break; ++ case DCLK_VOP0: ++ case DCLK_VOP1: ++ rate = rk3528_dclk_vop_get_clk(priv, clk->id); ++ break; ++ case DCLK_CVBS: ++ rate = rk3528_dclk_vop_get_clk(priv, DCLK_VOP1) / 4; ++ break; ++ case DCLK_4X_CVBS: ++ rate = rk3528_dclk_vop_get_clk(priv, DCLK_VOP1); ++ break; ++ case SCLK_UART0: ++ case SCLK_UART1: ++ case SCLK_UART2: ++ case SCLK_UART3: ++ case SCLK_UART4: ++ case SCLK_UART5: ++ case SCLK_UART6: ++ case SCLK_UART7: ++ rate = rk3528_uart_get_rate(priv, clk->id); ++ break; ++ case CLK_MATRIX_50M_SRC: ++ case CLK_MATRIX_100M_SRC: ++ case CLK_MATRIX_150M_SRC: ++ case CLK_MATRIX_200M_SRC: ++ case CLK_MATRIX_250M_SRC: ++ case CLK_MATRIX_300M_SRC: ++ case CLK_MATRIX_339M_SRC: ++ case CLK_MATRIX_400M_SRC: ++ case CLK_MATRIX_500M_SRC: ++ case CLK_MATRIX_600M_SRC: ++ case ACLK_BUS_VOPGL_BIU: ++ rate = rk3528_cgpll_matrix_get_rate(priv, clk->id); ++ break; ++ case CLK_PPLL_50M_MATRIX: ++ case CLK_PPLL_100M_MATRIX: ++ case CLK_PPLL_125M_MATRIX: ++ case CLK_GMAC1_VPU_25M: ++ case CLK_GMAC1_RMII_VPU: ++ case CLK_GMAC1_SRC_VPU: ++ rate = rk3528_ppll_matrix_get_rate(priv, clk->id); ++ break; ++ default: ++ return -ENOENT; ++ } ++ ++ return rate; ++}; ++ ++static ulong rk3528_clk_set_rate(struct clk *clk, ulong rate) ++{ ++ struct rk3528_clk_priv *priv = dev_get_priv(clk->dev); ++ ulong ret = 0; ++ ++ if (!priv->gpll_hz) { ++ printf("%s gpll=%lu\n", __func__, priv->gpll_hz); ++ return -ENOENT; ++ } ++ ++ switch (clk->id) { ++ case PLL_APLL: ++ case ARMCLK: ++ if (priv->armclk_hz) ++ rk3528_armclk_set_clk(priv, rate); ++ priv->armclk_hz = rate; ++ break; ++ case PLL_CPLL: ++ ret = rockchip_pll_set_rate(&rk3528_pll_clks[CPLL], priv->cru, ++ CPLL, rate); ++ priv->cpll_hz = rockchip_pll_get_rate(&rk3528_pll_clks[CPLL], ++ priv->cru, CPLL); ++ break; ++ case PLL_GPLL: ++ ret = rockchip_pll_set_rate(&rk3528_pll_clks[GPLL], priv->cru, ++ GPLL, rate); ++ priv->gpll_hz = rockchip_pll_get_rate(&rk3528_pll_clks[GPLL], ++ priv->cru, GPLL); ++ break; ++ case PLL_PPLL: ++ ret = rockchip_pll_set_rate(&rk3528_pll_clks[PPLL], priv->cru, ++ PPLL, rate); ++ priv->ppll_hz = rockchip_pll_get_rate(&rk3528_pll_clks[PPLL], ++ priv->cru, PPLL); ++ break; ++ case TCLK_WDT_NS: ++ return (rate == OSC_HZ) ? 0 : -EINVAL; ++ case CLK_I2C0: ++ case CLK_I2C1: ++ case CLK_I2C2: ++ case CLK_I2C3: ++ case CLK_I2C4: ++ case CLK_I2C5: ++ case CLK_I2C6: ++ case CLK_I2C7: ++ ret = rk3528_i2c_set_clk(priv, clk->id, rate); ++ break; ++ case CLK_SPI0: ++ case CLK_SPI1: ++ ret = rk3528_spi_set_clk(priv, clk->id, rate); ++ break; ++ case CLK_PWM0: ++ case CLK_PWM1: ++ ret = rk3528_pwm_set_clk(priv, clk->id, rate); ++ break; ++ case CLK_SARADC: ++ case CLK_TSADC: ++ case CLK_TSADC_TSEN: ++ ret = rk3528_adc_set_clk(priv, clk->id, rate); ++ break; ++ case HCLK_SDMMC0: ++ case CCLK_SRC_SDMMC0: ++ ret = rk3528_sdmmc_set_clk(priv, clk->id, rate); ++ break; ++ case SCLK_SFC: ++ ret = rk3528_sfc_set_clk(priv, rate); ++ break; ++ case CCLK_SRC_EMMC: ++ ret = rk3528_emmc_set_clk(priv, rate); ++ break; ++ case DCLK_VOP0: ++ case DCLK_VOP1: ++ ret = rk3528_dclk_vop_set_clk(priv, clk->id, rate); ++ break; ++ case SCLK_UART0: ++ case SCLK_UART1: ++ case SCLK_UART2: ++ case SCLK_UART3: ++ case SCLK_UART4: ++ case SCLK_UART5: ++ case SCLK_UART6: ++ case SCLK_UART7: ++ ret = rk3528_uart_set_rate(priv, clk->id, rate); ++ break; ++ case CLK_MATRIX_50M_SRC: ++ case CLK_MATRIX_100M_SRC: ++ case CLK_MATRIX_150M_SRC: ++ case CLK_MATRIX_200M_SRC: ++ case CLK_MATRIX_250M_SRC: ++ case CLK_MATRIX_300M_SRC: ++ case CLK_MATRIX_339M_SRC: ++ case CLK_MATRIX_400M_SRC: ++ case CLK_MATRIX_500M_SRC: ++ case CLK_MATRIX_600M_SRC: ++ case ACLK_BUS_VOPGL_BIU: ++ ret = rk3528_cgpll_matrix_set_rate(priv, clk->id, rate); ++ break; ++ case CLK_PPLL_50M_MATRIX: ++ case CLK_PPLL_100M_MATRIX: ++ case CLK_PPLL_125M_MATRIX: ++ case CLK_GMAC1_VPU_25M: ++ ret = rk3528_ppll_matrix_set_rate(priv, clk->id, rate); ++ break; ++ case CLK_GMAC1_RMII_VPU: ++ case CLK_GMAC1_SRC_VPU: ++ /* dummy set */ ++ ret = rk3528_ppll_matrix_get_rate(priv, clk->id); ++ break; ++ default: ++ return -ENOENT; ++ } ++ ++ return ret; ++}; ++ ++static struct clk_ops rk3528_clk_ops = { ++ .get_rate = rk3528_clk_get_rate, ++ .set_rate = rk3528_clk_set_rate, ++}; ++ ++#ifdef CONFIG_XPL_BUILD ++ ++#define COREGRF_BASE 0xff300000 ++#define PVTPLL_CON0_L 0x0 ++#define PVTPLL_CON0_H 0x4 ++ ++static int rk3528_cpu_pvtpll_set_rate(struct rk3528_clk_priv *priv, ulong rate) ++{ ++ struct rk3528_cru *cru = priv->cru; ++ u32 length; ++ ++ if (rate >= 1200000000) ++ length = 8; ++ else if (rate >= 1008000000) ++ length = 11; ++ else ++ length = 17; ++ ++ /* set pclk dbg div to 9 */ ++ rk_clrsetreg(&cru->clksel_con[40], RK3528_DIV_PCLK_DBG_MASK, ++ 9 << RK3528_DIV_PCLK_DBG_SHIFT); ++ /* set aclk_m_core div to 1 */ ++ rk_clrsetreg(&cru->clksel_con[39], RK3528_DIV_ACLK_M_CORE_MASK, ++ 1 << RK3528_DIV_ACLK_M_CORE_SHIFT); ++ ++ /* set ring sel = 1 */ ++ writel(0x07000000 | (1 << 8), COREGRF_BASE + PVTPLL_CON0_L); ++ /* set length */ ++ writel(0x007f0000 | length, COREGRF_BASE + PVTPLL_CON0_H); ++ /* enable pvtpll */ ++ writel(0x00020002, COREGRF_BASE + PVTPLL_CON0_L); ++ /* start monitor */ ++ writel(0x00010001, COREGRF_BASE + PVTPLL_CON0_L); ++ ++ /* set core mux pvtpll */ ++ writel(0x00010001, &cru->clksel_con[40]); ++ writel(0x00100010, &cru->clksel_con[39]); ++ ++ /* set pclk dbg div to 8 */ ++ rk_clrsetreg(&cru->clksel_con[40], RK3528_DIV_PCLK_DBG_MASK, ++ 8 << RK3528_DIV_PCLK_DBG_SHIFT); ++ ++ return 0; ++} ++#endif ++ ++static int rk3528_clk_init(struct rk3528_clk_priv *priv) ++{ ++ int ret; ++ ++ priv->sync_kernel = false; ++ ++#ifdef CONFIG_XPL_BUILD ++ /* ++ * BOOTROM: ++ * CPU 1902/2(postdiv1)=546M ++ * CPLL 996/2(postdiv1)=498M ++ * GPLL 1188/2(postdiv1)=594M ++ * |-- clk_matrix_200m_src_div=1 => rate: 300M ++ * |-- clk_matrix_300m_src_div=2 => rate: 200M ++ * ++ * Avoid overclocking when change GPLL rate: ++ * Change clk_matrix_200m_src_div to 5. ++ * Change clk_matrix_300m_src_div to 3. ++ */ ++ writel(0x01200120, &priv->cru->clksel_con[1]); ++ writel(0x00030003, &priv->cru->clksel_con[2]); ++ ++ if (!priv->armclk_enter_hz) { ++ priv->armclk_enter_hz = ++ rockchip_pll_get_rate(&rk3528_pll_clks[APLL], ++ priv->cru, APLL); ++ priv->armclk_init_hz = priv->armclk_enter_hz; ++ } ++ ++ if (priv->armclk_init_hz != APLL_HZ) { ++ ret = rk3528_armclk_set_clk(priv, APLL_HZ); ++ if (!ret) ++ priv->armclk_init_hz = APLL_HZ; ++ } ++ ++ if (!rk3528_cpu_pvtpll_set_rate(priv, CPU_PVTPLL_HZ)) { ++ debug("cpu pvtpll %d KHz\n", CPU_PVTPLL_HZ / 1000); ++ priv->armclk_init_hz = CPU_PVTPLL_HZ; ++ } ++#endif ++ ++ if (priv->cpll_hz != CPLL_HZ) { ++ ret = rockchip_pll_set_rate(&rk3528_pll_clks[CPLL], priv->cru, ++ CPLL, CPLL_HZ); ++ if (!ret) ++ priv->cpll_hz = CPLL_HZ; ++ } ++ ++ if (priv->gpll_hz != GPLL_HZ) { ++ ret = rockchip_pll_set_rate(&rk3528_pll_clks[GPLL], priv->cru, ++ GPLL, GPLL_HZ); ++ if (!ret) ++ priv->gpll_hz = GPLL_HZ; ++ } ++ ++ if (priv->ppll_hz != PPLL_HZ) { ++ ret = rockchip_pll_set_rate(&rk3528_pll_clks[PPLL], priv->cru, ++ PPLL, PPLL_HZ); ++ if (!ret) ++ priv->ppll_hz = PPLL_HZ; ++ } ++ ++#ifdef CONFIG_XPL_BUILD ++ /* Init to override bootrom config */ ++ rk3528_cgpll_matrix_set_rate(priv, CLK_MATRIX_50M_SRC, 50000000); ++ rk3528_cgpll_matrix_set_rate(priv, CLK_MATRIX_100M_SRC, 100000000); ++ rk3528_cgpll_matrix_set_rate(priv, CLK_MATRIX_150M_SRC, 150000000); ++ rk3528_cgpll_matrix_set_rate(priv, CLK_MATRIX_200M_SRC, 200000000); ++ rk3528_cgpll_matrix_set_rate(priv, CLK_MATRIX_250M_SRC, 250000000); ++ rk3528_cgpll_matrix_set_rate(priv, CLK_MATRIX_300M_SRC, 300000000); ++ rk3528_cgpll_matrix_set_rate(priv, CLK_MATRIX_339M_SRC, 340000000); ++ rk3528_cgpll_matrix_set_rate(priv, CLK_MATRIX_400M_SRC, 400000000); ++ rk3528_cgpll_matrix_set_rate(priv, CLK_MATRIX_500M_SRC, 500000000); ++ rk3528_cgpll_matrix_set_rate(priv, CLK_MATRIX_600M_SRC, 600000000); ++ rk3528_cgpll_matrix_set_rate(priv, ACLK_BUS_VOPGL_BIU, 500000000); ++ ++ /* The default rate is 100Mhz, it's not friendly for remote IR module */ ++ rk3528_pwm_set_clk(priv, CLK_PWM0, 24000000); ++ rk3528_pwm_set_clk(priv, CLK_PWM1, 24000000); ++#endif ++ return 0; ++} ++ ++static int rk3528_clk_probe(struct udevice *dev) ++{ ++ struct rk3528_clk_priv *priv = dev_get_priv(dev); ++ int ret; ++ ++ ret = rk3528_clk_init(priv); ++ if (ret) ++ return ret; ++ ++ /* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */ ++ ret = clk_set_defaults(dev, 1); ++ if (ret) ++ debug("%s clk_set_defaults failed %d\n", __func__, ret); ++ else ++ priv->sync_kernel = true; ++ ++ return 0; ++} ++ ++static int rk3528_clk_ofdata_to_platdata(struct udevice *dev) ++{ ++ struct rk3528_clk_priv *priv = dev_get_priv(dev); ++ ++ priv->cru = dev_read_addr_ptr(dev); ++ ++ return 0; ++} ++ ++static int rk3528_clk_bind(struct udevice *dev) ++{ ++ struct udevice *sys_child; ++ struct sysreset_reg *priv; ++ int ret; ++ ++ /* The reset driver does not have a device node, so bind it here */ ++ ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset", ++ &sys_child); ++ if (ret) { ++ debug("Warning: No sysreset driver: ret=%d\n", ret); ++ } else { ++ priv = malloc(sizeof(struct sysreset_reg)); ++ priv->glb_srst_fst_value = offsetof(struct rk3528_cru, ++ glb_srst_fst); ++ priv->glb_srst_snd_value = offsetof(struct rk3528_cru, ++ glb_srst_snd); ++ dev_set_priv(sys_child, priv); ++ } ++ ++#if CONFIG_IS_ENABLED(RESET_ROCKCHIP) ++ ret = offsetof(struct rk3528_cru, softrst_con[0]); ++ ret = rockchip_reset_bind(dev, ret, 47); ++ if (ret) ++ debug("Warning: software reset driver bind failed\n"); ++#endif ++ ++ return 0; ++} ++ ++static const struct udevice_id rk3528_clk_ids[] = { ++ { .compatible = "rockchip,rk3528-cru" }, ++ { } ++}; ++ ++U_BOOT_DRIVER(rockchip_rk3528_cru) = { ++ .name = "rockchip_rk3528_cru", ++ .id = UCLASS_CLK, ++ .of_match = rk3528_clk_ids, ++ .priv_auto = sizeof(struct rk3528_clk_priv), ++ .of_to_plat = rk3528_clk_ofdata_to_platdata, ++ .ops = &rk3528_clk_ops, ++ .bind = rk3528_clk_bind, ++ .probe = rk3528_clk_probe, ++}; +--- /dev/null ++++ b/include/dt-bindings/clock/rk3528-cru.h +@@ -0,0 +1,751 @@ ++/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ ++/* ++ * Copyright (c) 2022 Rockchip Electronics Co. Ltd. ++ * Author: Joseph Chen ++ */ ++ ++#ifndef _DT_BINDINGS_CLK_ROCKCHIP_RK3528_H ++#define _DT_BINDINGS_CLK_ROCKCHIP_RK3528_H ++ ++/* cru-clocks indices */ ++ ++/* core clocks */ ++#define PLL_APLL 1 ++#define PLL_CPLL 2 ++#define PLL_GPLL 3 ++#define PLL_PPLL 4 ++#define PLL_DPLL 5 ++#define ARMCLK 6 ++ ++#define XIN_OSC0_HALF 8 ++#define CLK_MATRIX_50M_SRC 9 ++#define CLK_MATRIX_100M_SRC 10 ++#define CLK_MATRIX_150M_SRC 11 ++#define CLK_MATRIX_200M_SRC 12 ++#define CLK_MATRIX_250M_SRC 13 ++#define CLK_MATRIX_300M_SRC 14 ++#define CLK_MATRIX_339M_SRC 15 ++#define CLK_MATRIX_400M_SRC 16 ++#define CLK_MATRIX_500M_SRC 17 ++#define CLK_MATRIX_600M_SRC 18 ++#define CLK_UART0_SRC 19 ++#define CLK_UART0_FRAC 20 ++#define SCLK_UART0 21 ++#define CLK_UART1_SRC 22 ++#define CLK_UART1_FRAC 23 ++#define SCLK_UART1 24 ++#define CLK_UART2_SRC 25 ++#define CLK_UART2_FRAC 26 ++#define SCLK_UART2 27 ++#define CLK_UART3_SRC 28 ++#define CLK_UART3_FRAC 29 ++#define SCLK_UART3 30 ++#define CLK_UART4_SRC 31 ++#define CLK_UART4_FRAC 32 ++#define SCLK_UART4 33 ++#define CLK_UART5_SRC 34 ++#define CLK_UART5_FRAC 35 ++#define SCLK_UART5 36 ++#define CLK_UART6_SRC 37 ++#define CLK_UART6_FRAC 38 ++#define SCLK_UART6 39 ++#define CLK_UART7_SRC 40 ++#define CLK_UART7_FRAC 41 ++#define SCLK_UART7 42 ++#define CLK_I2S0_2CH_SRC 43 ++#define CLK_I2S0_2CH_FRAC 44 ++#define MCLK_I2S0_2CH_SAI_SRC 45 ++#define CLK_I2S3_8CH_SRC 46 ++#define CLK_I2S3_8CH_FRAC 47 ++#define MCLK_I2S3_8CH_SAI_SRC 48 ++#define CLK_I2S1_8CH_SRC 49 ++#define CLK_I2S1_8CH_FRAC 50 ++#define MCLK_I2S1_8CH_SAI_SRC 51 ++#define CLK_I2S2_2CH_SRC 52 ++#define CLK_I2S2_2CH_FRAC 53 ++#define MCLK_I2S2_2CH_SAI_SRC 54 ++#define CLK_SPDIF_SRC 55 ++#define CLK_SPDIF_FRAC 56 ++#define MCLK_SPDIF_SRC 57 ++#define DCLK_VOP_SRC0 58 ++#define DCLK_VOP_SRC1 59 ++#define CLK_HSM 60 ++#define CLK_CORE_SRC_ACS 63 ++#define CLK_CORE_SRC_PVTMUX 65 ++#define CLK_CORE_SRC 66 ++#define CLK_CORE 67 ++#define ACLK_M_CORE_BIU 68 ++#define CLK_CORE_PVTPLL_SRC 69 ++#define PCLK_DBG 70 ++#define SWCLKTCK 71 ++#define CLK_SCANHS_CORE 72 ++#define CLK_SCANHS_ACLKM_CORE 73 ++#define CLK_SCANHS_PCLK_DBG 74 ++#define CLK_SCANHS_PCLK_CPU_BIU 76 ++#define PCLK_CPU_ROOT 77 ++#define PCLK_CORE_GRF 78 ++#define PCLK_DAPLITE_BIU 79 ++#define PCLK_CPU_BIU 80 ++#define CLK_REF_PVTPLL_CORE 81 ++#define ACLK_BUS_VOPGL_ROOT 85 ++#define ACLK_BUS_VOPGL_BIU 86 ++#define ACLK_BUS_H_ROOT 87 ++#define ACLK_BUS_H_BIU 88 ++#define ACLK_BUS_ROOT 89 ++#define HCLK_BUS_ROOT 90 ++#define PCLK_BUS_ROOT 91 ++#define ACLK_BUS_M_ROOT 92 ++#define ACLK_SYSMEM_BIU 93 ++#define CLK_TIMER_ROOT 95 ++#define ACLK_BUS_BIU 96 ++#define HCLK_BUS_BIU 97 ++#define PCLK_BUS_BIU 98 ++#define PCLK_DFT2APB 99 ++#define PCLK_BUS_GRF 100 ++#define ACLK_BUS_M_BIU 101 ++#define ACLK_GIC 102 ++#define ACLK_SPINLOCK 103 ++#define ACLK_DMAC 104 ++#define PCLK_TIMER 105 ++#define CLK_TIMER0 106 ++#define CLK_TIMER1 107 ++#define CLK_TIMER2 108 ++#define CLK_TIMER3 109 ++#define CLK_TIMER4 110 ++#define CLK_TIMER5 111 ++#define PCLK_JDBCK_DAP 112 ++#define CLK_JDBCK_DAP 113 ++#define PCLK_WDT_NS 114 ++#define TCLK_WDT_NS 115 ++#define HCLK_TRNG_NS 116 ++#define PCLK_UART0 117 ++#define CLK_CORE_CRYPTO 119 ++#define CLK_PKA_CRYPTO 120 ++#define ACLK_CRYPTO 121 ++#define HCLK_CRYPTO 122 ++#define PCLK_DMA2DDR 123 ++#define ACLK_DMA2DDR 124 ++#define PCLK_PWM0 126 ++#define CLK_PWM0 127 ++#define CLK_CAPTURE_PWM0 128 ++#define PCLK_PWM1 129 ++#define CLK_PWM1 130 ++#define CLK_CAPTURE_PWM1 131 ++#define PCLK_SCR 134 ++#define ACLK_DCF 135 ++#define PCLK_INTMUX 138 ++#define CLK_PPLL_I 141 ++#define CLK_PPLL_MUX 142 ++#define CLK_PPLL_100M_MATRIX 143 ++#define CLK_PPLL_50M_MATRIX 144 ++#define CLK_REF_PCIE_INNER_PHY 145 ++#define CLK_REF_PCIE_100M_PHY 146 ++#define ACLK_VPU_L_ROOT 147 ++#define CLK_GMAC1_VPU_25M 148 ++#define CLK_PPLL_125M_MATRIX 149 ++#define ACLK_VPU_ROOT 150 ++#define HCLK_VPU_ROOT 151 ++#define PCLK_VPU_ROOT 152 ++#define ACLK_VPU_BIU 153 ++#define HCLK_VPU_BIU 154 ++#define PCLK_VPU_BIU 155 ++#define ACLK_VPU 156 ++#define HCLK_VPU 157 ++#define PCLK_CRU_PCIE 158 ++#define PCLK_VPU_GRF 159 ++#define HCLK_SFC 160 ++#define SCLK_SFC 161 ++#define CCLK_SRC_EMMC 163 ++#define HCLK_EMMC 164 ++#define ACLK_EMMC 165 ++#define BCLK_EMMC 166 ++#define TCLK_EMMC 167 ++#define PCLK_GPIO1 168 ++#define DBCLK_GPIO1 169 ++#define ACLK_VPU_L_BIU 172 ++#define PCLK_VPU_IOC 173 ++#define HCLK_SAI_I2S0 174 ++#define MCLK_SAI_I2S0 175 ++#define HCLK_SAI_I2S2 176 ++#define MCLK_SAI_I2S2 177 ++#define PCLK_ACODEC 178 ++#define MCLK_ACODEC_TX 179 ++#define PCLK_GPIO3 186 ++#define DBCLK_GPIO3 187 ++#define PCLK_SPI1 189 ++#define CLK_SPI1 190 ++#define SCLK_IN_SPI1 191 ++#define PCLK_UART2 192 ++#define PCLK_UART5 194 ++#define PCLK_UART6 196 ++#define PCLK_UART7 198 ++#define PCLK_I2C3 200 ++#define CLK_I2C3 201 ++#define PCLK_I2C5 202 ++#define CLK_I2C5 203 ++#define PCLK_I2C6 204 ++#define CLK_I2C6 205 ++#define ACLK_MAC_VPU 206 ++#define PCLK_MAC_VPU 207 ++#define CLK_GMAC1_RMII_VPU 209 ++#define CLK_GMAC1_SRC_VPU 210 ++#define PCLK_PCIE 215 ++#define CLK_PCIE_AUX 216 ++#define ACLK_PCIE 217 ++#define HCLK_PCIE_SLV 218 ++#define HCLK_PCIE_DBI 219 ++#define PCLK_PCIE_PHY 220 ++#define PCLK_PIPE_GRF 221 ++#define CLK_PIPE_USB3OTG_COMBO 230 ++#define CLK_UTMI_USB3OTG 232 ++#define CLK_PCIE_PIPE_PHY 235 ++#define CCLK_SRC_SDIO0 240 ++#define HCLK_SDIO0 241 ++#define CCLK_SRC_SDIO1 244 ++#define HCLK_SDIO1 245 ++#define CLK_TS_0 246 ++#define CLK_TS_1 247 ++#define PCLK_CAN2 250 ++#define CLK_CAN2 251 ++#define PCLK_CAN3 252 ++#define CLK_CAN3 253 ++#define PCLK_SARADC 256 ++#define CLK_SARADC 257 ++#define PCLK_TSADC 258 ++#define CLK_TSADC 259 ++#define CLK_TSADC_TSEN 260 ++#define ACLK_USB3OTG 261 ++#define CLK_REF_USB3OTG 262 ++#define CLK_SUSPEND_USB3OTG 263 ++#define ACLK_GPU_ROOT 269 ++#define PCLK_GPU_ROOT 270 ++#define ACLK_GPU_BIU 271 ++#define PCLK_GPU_BIU 272 ++#define ACLK_GPU 273 ++#define CLK_GPU_PVTPLL_SRC 274 ++#define ACLK_GPU_MALI 275 ++#define HCLK_RKVENC_ROOT 281 ++#define ACLK_RKVENC_ROOT 282 ++#define PCLK_RKVENC_ROOT 283 ++#define HCLK_RKVENC_BIU 284 ++#define ACLK_RKVENC_BIU 285 ++#define PCLK_RKVENC_BIU 286 ++#define HCLK_RKVENC 287 ++#define ACLK_RKVENC 288 ++#define CLK_CORE_RKVENC 289 ++#define HCLK_SAI_I2S1 290 ++#define MCLK_SAI_I2S1 291 ++#define PCLK_I2C1 292 ++#define CLK_I2C1 293 ++#define PCLK_I2C0 294 ++#define CLK_I2C0 295 ++#define CLK_UART_JTAG 296 ++#define PCLK_SPI0 297 ++#define CLK_SPI0 298 ++#define SCLK_IN_SPI0 299 ++#define PCLK_GPIO4 300 ++#define DBCLK_GPIO4 301 ++#define PCLK_RKVENC_IOC 302 ++#define HCLK_SPDIF 308 ++#define MCLK_SPDIF 309 ++#define HCLK_PDM 310 ++#define MCLK_PDM 311 ++#define PCLK_UART1 315 ++#define PCLK_UART3 317 ++#define PCLK_RKVENC_GRF 319 ++#define PCLK_CAN0 320 ++#define CLK_CAN0 321 ++#define PCLK_CAN1 322 ++#define CLK_CAN1 323 ++#define ACLK_VO_ROOT 324 ++#define HCLK_VO_ROOT 325 ++#define PCLK_VO_ROOT 326 ++#define ACLK_VO_BIU 327 ++#define HCLK_VO_BIU 328 ++#define PCLK_VO_BIU 329 ++#define HCLK_RGA2E 330 ++#define ACLK_RGA2E 331 ++#define CLK_CORE_RGA2E 332 ++#define HCLK_VDPP 333 ++#define ACLK_VDPP 334 ++#define CLK_CORE_VDPP 335 ++#define PCLK_VO_GRF 336 ++#define PCLK_CRU 337 ++#define ACLK_VOP_ROOT 338 ++#define ACLK_VOP_BIU 339 ++#define HCLK_VOP 340 ++#define DCLK_VOP0 341 ++#define DCLK_VOP1 342 ++#define ACLK_VOP 343 ++#define PCLK_HDMI 344 ++#define CLK_SFR_HDMI 345 ++#define CLK_CEC_HDMI 346 ++#define CLK_SPDIF_HDMI 347 ++#define CLK_HDMIPHY_TMDSSRC 348 ++#define CLK_HDMIPHY_PREP 349 ++#define PCLK_HDMIPHY 352 ++#define HCLK_HDCP_KEY 354 ++#define ACLK_HDCP 355 ++#define HCLK_HDCP 356 ++#define PCLK_HDCP 357 ++#define HCLK_CVBS 358 ++#define DCLK_CVBS 359 ++#define DCLK_4X_CVBS 360 ++#define ACLK_JPEG_DECODER 361 ++#define HCLK_JPEG_DECODER 362 ++#define ACLK_VO_L_ROOT 375 ++#define ACLK_VO_L_BIU 376 ++#define ACLK_MAC_VO 377 ++#define PCLK_MAC_VO 378 ++#define CLK_GMAC0_SRC 379 ++#define CLK_GMAC0_RMII_50M 380 ++#define CLK_GMAC0_TX 381 ++#define CLK_GMAC0_RX 382 ++#define ACLK_JPEG_ROOT 385 ++#define ACLK_JPEG_BIU 386 ++#define HCLK_SAI_I2S3 387 ++#define MCLK_SAI_I2S3 388 ++#define CLK_MACPHY 398 ++#define PCLK_VCDCPHY 399 ++#define PCLK_GPIO2 404 ++#define DBCLK_GPIO2 405 ++#define PCLK_VO_IOC 406 ++#define CCLK_SRC_SDMMC0 407 ++#define HCLK_SDMMC0 408 ++#define PCLK_OTPC_NS 411 ++#define CLK_SBPI_OTPC_NS 412 ++#define CLK_USER_OTPC_NS 413 ++#define CLK_HDMIHDP0 415 ++#define HCLK_USBHOST 416 ++#define HCLK_USBHOST_ARB 417 ++#define CLK_USBHOST_OHCI 418 ++#define CLK_USBHOST_UTMI 419 ++#define PCLK_UART4 420 ++#define PCLK_I2C4 422 ++#define CLK_I2C4 423 ++#define PCLK_I2C7 424 ++#define CLK_I2C7 425 ++#define PCLK_USBPHY 426 ++#define CLK_REF_USBPHY 427 ++#define HCLK_RKVDEC_ROOT 433 ++#define ACLK_RKVDEC_ROOT_NDFT 434 ++#define PCLK_DDRPHY_CRU 435 ++#define HCLK_RKVDEC_BIU 436 ++#define ACLK_RKVDEC_BIU 437 ++#define ACLK_RKVDEC 439 ++#define HCLK_RKVDEC 440 ++#define CLK_HEVC_CA_RKVDEC 441 ++#define ACLK_RKVDEC_PVTMUX_ROOT 442 ++#define CLK_RKVDEC_PVTPLL_SRC 443 ++#define PCLK_DDR_ROOT 449 ++#define PCLK_DDR_BIU 450 ++#define PCLK_DDRC 451 ++#define PCLK_DDRMON 452 ++#define CLK_TIMER_DDRMON 453 ++#define PCLK_MSCH_BIU 454 ++#define PCLK_DDR_GRF 455 ++#define PCLK_DDR_HWLP 456 ++#define PCLK_DDRPHY 457 ++#define CLK_MSCH_BIU 463 ++#define ACLK_DDR_UPCTL 464 ++#define CLK_DDR_UPCTL 465 ++#define CLK_DDRMON 466 ++#define ACLK_DDR_SCRAMBLE 467 ++#define ACLK_SPLIT 468 ++#define CLK_DDRC_SRC 470 ++#define CLK_DDR_PHY 471 ++#define PCLK_OTPC_S 472 ++#define CLK_SBPI_OTPC_S 473 ++#define CLK_USER_OTPC_S 474 ++#define PCLK_KEYREADER 475 ++#define PCLK_BUS_SGRF 476 ++#define PCLK_STIMER 477 ++#define CLK_STIMER0 478 ++#define CLK_STIMER1 479 ++#define PCLK_WDT_S 480 ++#define TCLK_WDT_S 481 ++#define HCLK_TRNG_S 482 ++#define PCLK_KLAD 483 ++#define HCLK_CRYPTO_S 484 ++#define HCLK_KLAD 485 ++#define HCLK_BOOTROM 486 ++#define PCLK_DCF 487 ++#define ACLK_SYSMEM 488 ++#define HCLK_TSP 489 ++#define ACLK_TSP 490 ++#define CLK_CORE_TSP 491 ++#define CLK_OTPC_ARB 492 ++#define PCLK_OTP_MASK 493 ++#define CLK_PMC_OTP 494 ++#define PCLK_PMU_ROOT 495 ++#define HCLK_PMU_ROOT 496 ++#define PCLK_I2C2 497 ++#define CLK_I2C2 498 ++#define HCLK_PMU_BIU 500 ++#define PCLK_PMU_BIU 501 ++#define FCLK_MCU 502 ++#define RTC_CLK_MCU 504 ++#define PCLK_OSCCHK 505 ++#define CLK_PMU_MCU_JTAG 506 ++#define PCLK_PMU 508 ++#define PCLK_GPIO0 509 ++#define DBCLK_GPIO0 510 ++#define XIN_OSC0_DIV 511 ++#define CLK_DEEPSLOW 512 ++#define CLK_DDR_FAIL_SAFE 513 ++#define PCLK_PMU_HP_TIMER 514 ++#define CLK_PMU_HP_TIMER 515 ++#define CLK_PMU_32K_HP_TIMER 516 ++#define PCLK_PMU_IOC 517 ++#define PCLK_PMU_CRU 518 ++#define PCLK_PMU_GRF 519 ++#define PCLK_PMU_WDT 520 ++#define TCLK_PMU_WDT 521 ++#define PCLK_PMU_MAILBOX 522 ++#define PCLK_SCRKEYGEN 524 ++#define CLK_SCRKEYGEN 525 ++#define CLK_PVTM_OSCCHK 526 ++#define CLK_REFOUT 530 ++#define CLK_PVTM_PMU 532 ++#define PCLK_PVTM_PMU 533 ++#define PCLK_PMU_SGRF 534 ++#define HCLK_PMU_SRAM 535 ++#define CLK_UART0 536 ++#define CLK_UART1 537 ++#define CLK_UART2 538 ++#define CLK_UART3 539 ++#define CLK_UART4 540 ++#define CLK_UART5 541 ++#define CLK_UART6 542 ++#define CLK_UART7 543 ++#define MCLK_I2S0_2CH_SAI_SRC_PRE 544 ++#define MCLK_I2S1_8CH_SAI_SRC_PRE 545 ++#define MCLK_I2S2_2CH_SAI_SRC_PRE 546 ++#define MCLK_I2S3_8CH_SAI_SRC_PRE 547 ++#define MCLK_SDPDIF_SRC_PRE 548 ++ ++/* grf-clocks indices */ ++#define SCLK_SDMMC_DRV 1 ++#define SCLK_SDMMC_SAMPLE 2 ++#define SCLK_SDIO0_DRV 3 ++#define SCLK_SDIO0_SAMPLE 4 ++#define SCLK_SDIO1_DRV 5 ++#define SCLK_SDIO1_SAMPLE 6 ++ ++/* scmi-clocks indices */ ++#define SCMI_PCLK_KEYREADER 0 ++#define SCMI_HCLK_KLAD 1 ++#define SCMI_PCLK_KLAD 2 ++#define SCMI_HCLK_TRNG_S 3 ++#define SCMI_HCLK_CRYPTO_S 4 ++#define SCMI_PCLK_WDT_S 5 ++#define SCMI_TCLK_WDT_S 6 ++#define SCMI_PCLK_STIMER 7 ++#define SCMI_CLK_STIMER0 8 ++#define SCMI_CLK_STIMER1 9 ++#define SCMI_PCLK_OTP_MASK 10 ++#define SCMI_PCLK_OTPC_S 11 ++#define SCMI_CLK_SBPI_OTPC_S 12 ++#define SCMI_CLK_USER_OTPC_S 13 ++#define SCMI_CLK_PMC_OTP 14 ++#define SCMI_CLK_OTPC_ARB 15 ++#define SCMI_CLK_CORE_TSP 16 ++#define SCMI_ACLK_TSP 17 ++#define SCMI_HCLK_TSP 18 ++#define SCMI_PCLK_DCF 19 ++#define SCMI_CLK_DDR 20 ++#define SCMI_CLK_CPU 21 ++#define SCMI_CLK_GPU 22 ++#define SCMI_CORE_CRYPTO 23 ++#define SCMI_ACLK_CRYPTO 24 ++#define SCMI_PKA_CRYPTO 25 ++#define SCMI_HCLK_CRYPTO 26 ++#define SCMI_CORE_CRYPTO_S 27 ++#define SCMI_ACLK_CRYPTO_S 28 ++#define SCMI_PKA_CRYPTO_S 29 ++#define SCMI_CORE_KLAD 30 ++#define SCMI_ACLK_KLAD 31 ++#define SCMI_HCLK_TRNG 32 ++ ++// CRU_SOFTRST_CON03(Offset:0xA0C) ++#define SRST_NCOREPORESET0 0x00000030 ++#define SRST_NCOREPORESET1 0x00000031 ++#define SRST_NCOREPORESET2 0x00000032 ++#define SRST_NCOREPORESET3 0x00000033 ++#define SRST_NCORESET0 0x00000034 ++#define SRST_NCORESET1 0x00000035 ++#define SRST_NCORESET2 0x00000036 ++#define SRST_NCORESET3 0x00000037 ++#define SRST_NL2RESET 0x00000038 ++#define SRST_ARESETN_M_CORE_BIU 0x00000039 ++#define SRST_RESETN_CORE_CRYPTO 0x0000003A ++ ++// CRU_SOFTRST_CON05(Offset:0xA14) ++#define SRST_PRESETN_DBG 0x0000005D ++#define SRST_POTRESETN_DBG 0x0000005E ++#define SRST_NTRESETN_DBG 0x0000005F ++ ++// CRU_SOFTRST_CON06(Offset:0xA18) ++#define SRST_PRESETN_CORE_GRF 0x00000062 ++#define SRST_PRESETN_DAPLITE_BIU 0x00000063 ++#define SRST_PRESETN_CPU_BIU 0x00000064 ++#define SRST_RESETN_REF_PVTPLL_CORE 0x00000067 ++ ++// CRU_SOFTRST_CON08(Offset:0xA20) ++#define SRST_ARESETN_BUS_VOPGL_BIU 0x00000081 ++#define SRST_ARESETN_BUS_H_BIU 0x00000083 ++#define SRST_ARESETN_SYSMEM_BIU 0x00000088 ++#define SRST_ARESETN_BUS_BIU 0x0000008A ++#define SRST_HRESETN_BUS_BIU 0x0000008B ++#define SRST_PRESETN_BUS_BIU 0x0000008C ++#define SRST_PRESETN_DFT2APB 0x0000008D ++#define SRST_PRESETN_BUS_GRF 0x0000008F ++ ++// CRU_SOFTRST_CON09(Offset:0xA24) ++#define SRST_ARESETN_BUS_M_BIU 0x00000090 ++#define SRST_ARESETN_GIC 0x00000091 ++#define SRST_ARESETN_SPINLOCK 0x00000092 ++#define SRST_ARESETN_DMAC 0x00000094 ++#define SRST_PRESETN_TIMER 0x00000095 ++#define SRST_RESETN_TIMER0 0x00000096 ++#define SRST_RESETN_TIMER1 0x00000097 ++#define SRST_RESETN_TIMER2 0x00000098 ++#define SRST_RESETN_TIMER3 0x00000099 ++#define SRST_RESETN_TIMER4 0x0000009A ++#define SRST_RESETN_TIMER5 0x0000009B ++#define SRST_PRESETN_JDBCK_DAP 0x0000009C ++#define SRST_RESETN_JDBCK_DAP 0x0000009D ++#define SRST_PRESETN_WDT_NS 0x0000009F ++ ++// CRU_SOFTRST_CON10(Offset:0xA28) ++#define SRST_TRESETN_WDT_NS 0x000000A0 ++#define SRST_HRESETN_TRNG_NS 0x000000A3 ++#define SRST_PRESETN_UART0 0x000000A7 ++#define SRST_SRESETN_UART0 0x000000A8 ++#define SRST_RESETN_PKA_CRYPTO 0x000000AA ++#define SRST_ARESETN_CRYPTO 0x000000AB ++#define SRST_HRESETN_CRYPTO 0x000000AC ++#define SRST_PRESETN_DMA2DDR 0x000000AD ++#define SRST_ARESETN_DMA2DDR 0x000000AE ++ ++// CRU_SOFTRST_CON11(Offset:0xA2C) ++#define SRST_PRESETN_PWM0 0x000000B4 ++#define SRST_RESETN_PWM0 0x000000B5 ++#define SRST_PRESETN_PWM1 0x000000B7 ++#define SRST_RESETN_PWM1 0x000000B8 ++#define SRST_PRESETN_SCR 0x000000BA ++#define SRST_ARESETN_DCF 0x000000BB ++#define SRST_PRESETN_INTMUX 0x000000BC ++ ++// CRU_SOFTRST_CON25(Offset:0xA64) ++#define SRST_ARESETN_VPU_BIU 0x00000196 ++#define SRST_HRESETN_VPU_BIU 0x00000197 ++#define SRST_PRESETN_VPU_BIU 0x00000198 ++#define SRST_ARESETN_VPU 0x00000199 ++#define SRST_HRESETN_VPU 0x0000019A ++#define SRST_PRESETN_CRU_PCIE 0x0000019B ++#define SRST_PRESETN_VPU_GRF 0x0000019C ++#define SRST_HRESETN_SFC 0x0000019D ++#define SRST_SRESETN_SFC 0x0000019E ++#define SRST_CRESETN_EMMC 0x0000019F ++ ++// CRU_SOFTRST_CON26(Offset:0xA68) ++#define SRST_HRESETN_EMMC 0x000001A0 ++#define SRST_ARESETN_EMMC 0x000001A1 ++#define SRST_BRESETN_EMMC 0x000001A2 ++#define SRST_TRESETN_EMMC 0x000001A3 ++#define SRST_PRESETN_GPIO1 0x000001A4 ++#define SRST_DBRESETN_GPIO1 0x000001A5 ++#define SRST_ARESETN_VPU_L_BIU 0x000001A6 ++#define SRST_PRESETN_VPU_IOC 0x000001A8 ++#define SRST_HRESETN_SAI_I2S0 0x000001A9 ++#define SRST_MRESETN_SAI_I2S0 0x000001AA ++#define SRST_HRESETN_SAI_I2S2 0x000001AB ++#define SRST_MRESETN_SAI_I2S2 0x000001AC ++#define SRST_PRESETN_ACODEC 0x000001AD ++ ++// CRU_SOFTRST_CON27(Offset:0xA6C) ++#define SRST_PRESETN_GPIO3 0x000001B0 ++#define SRST_DBRESETN_GPIO3 0x000001B1 ++#define SRST_PRESETN_SPI1 0x000001B4 ++#define SRST_RESETN_SPI1 0x000001B5 ++#define SRST_PRESETN_UART2 0x000001B7 ++#define SRST_SRESETN_UART2 0x000001B8 ++#define SRST_PRESETN_UART5 0x000001B9 ++#define SRST_SRESETN_UART5 0x000001BA ++#define SRST_PRESETN_UART6 0x000001BB ++#define SRST_SRESETN_UART6 0x000001BC ++#define SRST_PRESETN_UART7 0x000001BD ++#define SRST_SRESETN_UART7 0x000001BE ++#define SRST_PRESETN_I2C3 0x000001BF ++ ++// CRU_SOFTRST_CON28(Offset:0xA70) ++#define SRST_RESETN_I2C3 0x000001C0 ++#define SRST_PRESETN_I2C5 0x000001C1 ++#define SRST_RESETN_I2C5 0x000001C2 ++#define SRST_PRESETN_I2C6 0x000001C3 ++#define SRST_RESETN_I2C6 0x000001C4 ++#define SRST_ARESETN_MAC 0x000001C5 ++ ++// CRU_SOFTRST_CON30(Offset:0xA78) ++#define SRST_PRESETN_PCIE 0x000001E1 ++#define SRST_RESETN_PCIE_PIPE_PHY 0x000001E2 ++#define SRST_RESETN_PCIE_POWER_UP 0x000001E3 ++#define SRST_PRESETN_PCIE_PHY 0x000001E6 ++#define SRST_PRESETN_PIPE_GRF 0x000001E7 ++ ++// CRU_SOFTRST_CON32(Offset:0xA80) ++#define SRST_HRESETN_SDIO0 0x00000202 ++#define SRST_HRESETN_SDIO1 0x00000204 ++#define SRST_RESETN_TS_0 0x00000205 ++#define SRST_RESETN_TS_1 0x00000206 ++#define SRST_PRESETN_CAN2 0x00000207 ++#define SRST_RESETN_CAN2 0x00000208 ++#define SRST_PRESETN_CAN3 0x00000209 ++#define SRST_RESETN_CAN3 0x0000020A ++#define SRST_PRESETN_SARADC 0x0000020B ++#define SRST_RESETN_SARADC 0x0000020C ++#define SRST_RESETN_SARADC_PHY 0x0000020D ++#define SRST_PRESETN_TSADC 0x0000020E ++#define SRST_RESETN_TSADC 0x0000020F ++ ++// CRU_SOFTRST_CON33(Offset:0xA84) ++#define SRST_ARESETN_USB3OTG 0x00000211 ++ ++// CRU_SOFTRST_CON34(Offset:0xA88) ++#define SRST_ARESETN_GPU_BIU 0x00000223 ++#define SRST_PRESETN_GPU_BIU 0x00000225 ++#define SRST_ARESETN_GPU 0x00000228 ++#define SRST_RESETN_REF_PVTPLL_GPU 0x00000229 ++ ++// CRU_SOFTRST_CON36(Offset:0xA90) ++#define SRST_HRESETN_RKVENC_BIU 0x00000243 ++#define SRST_ARESETN_RKVENC_BIU 0x00000244 ++#define SRST_PRESETN_RKVENC_BIU 0x00000245 ++#define SRST_HRESETN_RKVENC 0x00000246 ++#define SRST_ARESETN_RKVENC 0x00000247 ++#define SRST_RESETN_CORE_RKVENC 0x00000248 ++#define SRST_HRESETN_SAI_I2S1 0x00000249 ++#define SRST_MRESETN_SAI_I2S1 0x0000024A ++#define SRST_PRESETN_I2C1 0x0000024B ++#define SRST_RESETN_I2C1 0x0000024C ++#define SRST_PRESETN_I2C0 0x0000024D ++#define SRST_RESETN_I2C0 0x0000024E ++ ++// CRU_SOFTRST_CON37(Offset:0xA94) ++#define SRST_PRESETN_SPI0 0x00000252 ++#define SRST_RESETN_SPI0 0x00000253 ++#define SRST_PRESETN_GPIO4 0x00000258 ++#define SRST_DBRESETN_GPIO4 0x00000259 ++#define SRST_PRESETN_RKVENC_IOC 0x0000025A ++#define SRST_HRESETN_SPDIF 0x0000025E ++#define SRST_MRESETN_SPDIF 0x0000025F ++ ++// CRU_SOFTRST_CON38(Offset:0xA98) ++#define SRST_HRESETN_PDM 0x00000260 ++#define SRST_MRESETN_PDM 0x00000261 ++#define SRST_PRESETN_UART1 0x00000262 ++#define SRST_SRESETN_UART1 0x00000263 ++#define SRST_PRESETN_UART3 0x00000264 ++#define SRST_SRESETN_UART3 0x00000265 ++#define SRST_PRESETN_RKVENC_GRF 0x00000266 ++#define SRST_PRESETN_CAN0 0x00000267 ++#define SRST_RESETN_CAN0 0x00000268 ++#define SRST_PRESETN_CAN1 0x00000269 ++#define SRST_RESETN_CAN1 0x0000026A ++ ++// CRU_SOFTRST_CON39(Offset:0xA9C) ++#define SRST_ARESETN_VO_BIU 0x00000273 ++#define SRST_HRESETN_VO_BIU 0x00000274 ++#define SRST_PRESETN_VO_BIU 0x00000275 ++#define SRST_HRESETN_RGA2E 0x00000277 ++#define SRST_ARESETN_RGA2E 0x00000278 ++#define SRST_RESETN_CORE_RGA2E 0x00000279 ++#define SRST_HRESETN_VDPP 0x0000027A ++#define SRST_ARESETN_VDPP 0x0000027B ++#define SRST_RESETN_CORE_VDPP 0x0000027C ++#define SRST_PRESETN_VO_GRF 0x0000027D ++#define SRST_PRESETN_CRU 0x0000027F ++ ++// CRU_SOFTRST_CON40(Offset:0xAA0) ++#define SRST_ARESETN_VOP_BIU 0x00000281 ++#define SRST_HRESETN_VOP 0x00000282 ++#define SRST_DRESETN_VOP0 0x00000283 ++#define SRST_DRESETN_VOP1 0x00000284 ++#define SRST_ARESETN_VOP 0x00000285 ++#define SRST_PRESETN_HDMI 0x00000286 ++#define SRST_HDMI_RESETN 0x00000287 ++#define SRST_PRESETN_HDMIPHY 0x0000028E ++#define SRST_HRESETN_HDCP_KEY 0x0000028F ++ ++// CRU_SOFTRST_CON41(Offset:0xAA4) ++#define SRST_ARESETN_HDCP 0x00000290 ++#define SRST_HRESETN_HDCP 0x00000291 ++#define SRST_PRESETN_HDCP 0x00000292 ++#define SRST_HRESETN_CVBS 0x00000293 ++#define SRST_DRESETN_CVBS_VOP 0x00000294 ++#define SRST_DRESETN_4X_CVBS_VOP 0x00000295 ++#define SRST_ARESETN_JPEG_DECODER 0x00000296 ++#define SRST_HRESETN_JPEG_DECODER 0x00000297 ++#define SRST_ARESETN_VO_L_BIU 0x00000299 ++#define SRST_ARESETN_MAC_VO 0x0000029A ++ ++// CRU_SOFTRST_CON42(Offset:0xAA8) ++#define SRST_ARESETN_JPEG_BIU 0x000002A0 ++#define SRST_HRESETN_SAI_I2S3 0x000002A1 ++#define SRST_MRESETN_SAI_I2S3 0x000002A2 ++#define SRST_RESETN_MACPHY 0x000002A3 ++#define SRST_PRESETN_VCDCPHY 0x000002A4 ++#define SRST_PRESETN_GPIO2 0x000002A5 ++#define SRST_DBRESETN_GPIO2 0x000002A6 ++#define SRST_PRESETN_VO_IOC 0x000002A7 ++#define SRST_HRESETN_SDMMC0 0x000002A9 ++#define SRST_PRESETN_OTPC_NS 0x000002AB ++#define SRST_RESETN_SBPI_OTPC_NS 0x000002AC ++#define SRST_RESETN_USER_OTPC_NS 0x000002AD ++ ++// CRU_SOFTRST_CON43(Offset:0xAAC) ++#define SRST_RESETN_HDMIHDP0 0x000002B2 ++#define SRST_HRESETN_USBHOST 0x000002B3 ++#define SRST_HRESETN_USBHOST_ARB 0x000002B4 ++#define SRST_RESETN_HOST_UTMI 0x000002B6 ++#define SRST_PRESETN_UART4 0x000002B7 ++#define SRST_SRESETN_UART4 0x000002B8 ++#define SRST_PRESETN_I2C4 0x000002B9 ++#define SRST_RESETN_I2C4 0x000002BA ++#define SRST_PRESETN_I2C7 0x000002BB ++#define SRST_RESETN_I2C7 0x000002BC ++#define SRST_PRESETN_USBPHY 0x000002BD ++#define SRST_RESETN_USBPHY_POR 0x000002BE ++#define SRST_RESETN_USBPHY_OTG 0x000002BF ++ ++// CRU_SOFTRST_CON44(Offset:0xAB0) ++#define SRST_RESETN_USBPHY_HOST 0x000002C0 ++#define SRST_PRESETN_DDRPHY_CRU 0x000002C4 ++#define SRST_HRESETN_RKVDEC_BIU 0x000002C6 ++#define SRST_ARESETN_RKVDEC_BIU 0x000002C7 ++#define SRST_ARESETN_RKVDEC 0x000002C8 ++#define SRST_HRESETN_RKVDEC 0x000002C9 ++#define SRST_RESETN_HEVC_CA_RKVDEC 0x000002CB ++#define SRST_RESETN_REF_PVTPLL_RKVDEC 0x000002CC ++ ++// CRU_SOFTRST_CON45(Offset:0xAB4) ++#define SRST_PRESETN_DDR_BIU 0x000002D1 ++#define SRST_PRESETN_DDRC 0x000002D2 ++#define SRST_PRESETN_DDRMON 0x000002D3 ++#define SRST_RESETN_TIMER_DDRMON 0x000002D4 ++#define SRST_PRESETN_MSCH_BIU 0x000002D5 ++#define SRST_PRESETN_DDR_GRF 0x000002D6 ++#define SRST_PRESETN_DDR_HWLP 0x000002D8 ++#define SRST_PRESETN_DDRPHY 0x000002D9 ++#define SRST_RESETN_MSCH_BIU 0x000002DA ++#define SRST_ARESETN_DDR_UPCTL 0x000002DB ++#define SRST_RESETN_DDR_UPCTL 0x000002DC ++#define SRST_RESETN_DDRMON 0x000002DD ++#define SRST_ARESETN_DDR_SCRAMBLE 0x000002DE ++#define SRST_ARESETN_SPLIT 0x000002DF ++ ++// CRU_SOFTRST_CON46(Offset:0xAB8) ++#define SRST_RESETN_DDR_PHY 0x000002E0 ++ ++#endif diff --git a/lede/package/boot/uboot-rockchip/patches/405-pinctrl-rockchip-Add-support-for-RK3528.patch b/lede/package/boot/uboot-rockchip/patches/405-pinctrl-rockchip-Add-support-for-RK3528.patch new file mode 100644 index 0000000000..3351770d05 --- /dev/null +++ b/lede/package/boot/uboot-rockchip/patches/405-pinctrl-rockchip-Add-support-for-RK3528.patch @@ -0,0 +1,323 @@ +From 62eabfb295366711dfb761ec49bf39432861d45d Mon Sep 17 00:00:00 2001 +From: Steven Liu +Date: Thu, 23 Jan 2025 22:48:17 +0000 +Subject: [PATCH 5/9] pinctrl: rockchip: Add support for RK3528 + +Add pinctrl driver for RK3528. + +Imported from vendor U-Boot linux-6.1-stan-rkr5 tag with adjustments +to use regmap_update_bits(). + +Signed-off-by: Steven Liu +Signed-off-by: Jonas Karlman +--- + drivers/pinctrl/rockchip/Makefile | 1 + + drivers/pinctrl/rockchip/pinctrl-rk3528.c | 292 ++++++++++++++++++++++ + 2 files changed, 293 insertions(+) + create mode 100644 drivers/pinctrl/rockchip/pinctrl-rk3528.c + +--- a/drivers/pinctrl/rockchip/Makefile ++++ b/drivers/pinctrl/rockchip/Makefile +@@ -14,6 +14,7 @@ obj-$(CONFIG_ROCKCHIP_RK3308) += pinctrl + obj-$(CONFIG_ROCKCHIP_RK3328) += pinctrl-rk3328.o + obj-$(CONFIG_ROCKCHIP_RK3368) += pinctrl-rk3368.o + obj-$(CONFIG_ROCKCHIP_RK3399) += pinctrl-rk3399.o ++obj-$(CONFIG_ROCKCHIP_RK3528) += pinctrl-rk3528.o + obj-$(CONFIG_ROCKCHIP_RK3568) += pinctrl-rk3568.o + obj-$(CONFIG_ROCKCHIP_RK3588) += pinctrl-rk3588.o + obj-$(CONFIG_ROCKCHIP_RV1108) += pinctrl-rv1108.o +--- /dev/null ++++ b/drivers/pinctrl/rockchip/pinctrl-rk3528.c +@@ -0,0 +1,292 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2022 Rockchip Electronics Co., Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "pinctrl-rockchip.h" ++#include ++ ++static int rk3528_set_mux(struct rockchip_pin_bank *bank, int pin, int mux) ++{ ++ struct rockchip_pinctrl_priv *priv = bank->priv; ++ int iomux_num = (pin / 8); ++ struct regmap *regmap; ++ int reg, mask; ++ u8 bit; ++ u32 data, rmask; ++ ++ regmap = priv->regmap_base; ++ reg = bank->iomux[iomux_num].offset; ++ if ((pin % 8) >= 4) ++ reg += 0x4; ++ bit = (pin % 4) * 4; ++ mask = 0xf; ++ ++ data = (mask << (bit + 16)); ++ rmask = data | (data >> 16); ++ data |= (mux & mask) << bit; ++ ++ return regmap_update_bits(regmap, reg, rmask, data); ++} ++ ++#define RK3528_DRV_BITS_PER_PIN 8 ++#define RK3528_DRV_PINS_PER_REG 2 ++#define RK3528_DRV_GPIO0_OFFSET 0x100 ++#define RK3528_DRV_GPIO1_OFFSET 0x20120 ++#define RK3528_DRV_GPIO2_OFFSET 0x30160 ++#define RK3528_DRV_GPIO3_OFFSET 0x20190 ++#define RK3528_DRV_GPIO4_OFFSET 0x101C0 ++ ++static void rk3528_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, ++ int pin_num, struct regmap **regmap, ++ int *reg, u8 *bit) ++{ ++ struct rockchip_pinctrl_priv *priv = bank->priv; ++ ++ *regmap = priv->regmap_base; ++ switch (bank->bank_num) { ++ case 0: ++ *reg = RK3528_DRV_GPIO0_OFFSET; ++ break; ++ case 1: ++ *reg = RK3528_DRV_GPIO1_OFFSET; ++ break; ++ case 2: ++ *reg = RK3528_DRV_GPIO2_OFFSET; ++ break; ++ case 3: ++ *reg = RK3528_DRV_GPIO3_OFFSET; ++ break; ++ case 4: ++ *reg = RK3528_DRV_GPIO4_OFFSET; ++ break; ++ default: ++ *reg = 0; ++ debug("unsupported bank_num %d\n", bank->bank_num); ++ break; ++ } ++ ++ *reg += ((pin_num / RK3528_DRV_PINS_PER_REG) * 4); ++ *bit = pin_num % RK3528_DRV_PINS_PER_REG; ++ *bit *= RK3528_DRV_BITS_PER_PIN; ++} ++ ++static int rk3528_set_drive(struct rockchip_pin_bank *bank, ++ int pin_num, int strength) ++{ ++ struct regmap *regmap; ++ int reg; ++ u32 data, rmask; ++ u8 bit; ++ int drv = (1 << (strength + 1)) - 1; ++ ++ rk3528_calc_drv_reg_and_bit(bank, pin_num, ®map, ®, &bit); ++ ++ /* enable the write to the equivalent lower bits */ ++ data = ((1 << RK3528_DRV_BITS_PER_PIN) - 1) << (bit + 16); ++ rmask = data | (data >> 16); ++ data |= (drv << bit); ++ ++ return regmap_update_bits(regmap, reg, rmask, data); ++} ++ ++#define RK3528_PULL_BITS_PER_PIN 2 ++#define RK3528_PULL_PINS_PER_REG 8 ++#define RK3528_PULL_GPIO0_OFFSET 0x200 ++#define RK3528_PULL_GPIO1_OFFSET 0x20210 ++#define RK3528_PULL_GPIO2_OFFSET 0x30220 ++#define RK3528_PULL_GPIO3_OFFSET 0x20230 ++#define RK3528_PULL_GPIO4_OFFSET 0x10240 ++ ++static void rk3528_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, ++ int pin_num, struct regmap **regmap, ++ int *reg, u8 *bit) ++{ ++ struct rockchip_pinctrl_priv *priv = bank->priv; ++ ++ *regmap = priv->regmap_base; ++ switch (bank->bank_num) { ++ case 0: ++ *reg = RK3528_PULL_GPIO0_OFFSET; ++ break; ++ case 1: ++ *reg = RK3528_PULL_GPIO1_OFFSET; ++ break; ++ case 2: ++ *reg = RK3528_PULL_GPIO2_OFFSET; ++ break; ++ case 3: ++ *reg = RK3528_PULL_GPIO3_OFFSET; ++ break; ++ case 4: ++ *reg = RK3528_PULL_GPIO4_OFFSET; ++ break; ++ default: ++ *reg = 0; ++ debug("unsupported bank_num %d\n", bank->bank_num); ++ break; ++ } ++ ++ *reg += ((pin_num / RK3528_PULL_PINS_PER_REG) * 4); ++ *bit = pin_num % RK3528_PULL_PINS_PER_REG; ++ *bit *= RK3528_PULL_BITS_PER_PIN; ++} ++ ++static int rk3528_set_pull(struct rockchip_pin_bank *bank, ++ int pin_num, int pull) ++{ ++ struct regmap *regmap; ++ int reg, ret; ++ u8 bit, type; ++ u32 data, rmask; ++ ++ if (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT) ++ return -EOPNOTSUPP; ++ ++ rk3528_calc_pull_reg_and_bit(bank, pin_num, ®map, ®, &bit); ++ type = bank->pull_type[pin_num / 8]; ++ ret = rockchip_translate_pull_value(type, pull); ++ if (ret < 0) { ++ debug("unsupported pull setting %d\n", pull); ++ return ret; ++ } ++ ++ /* enable the write to the equivalent lower bits */ ++ data = ((1 << RK3528_PULL_BITS_PER_PIN) - 1) << (bit + 16); ++ rmask = data | (data >> 16); ++ data |= (ret << bit); ++ ++ return regmap_update_bits(regmap, reg, rmask, data); ++} ++ ++#define RK3528_SMT_BITS_PER_PIN 1 ++#define RK3528_SMT_PINS_PER_REG 8 ++#define RK3528_SMT_GPIO0_OFFSET 0x400 ++#define RK3528_SMT_GPIO1_OFFSET 0x20410 ++#define RK3528_SMT_GPIO2_OFFSET 0x30420 ++#define RK3528_SMT_GPIO3_OFFSET 0x20430 ++#define RK3528_SMT_GPIO4_OFFSET 0x10440 ++ ++static int rk3528_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank, ++ int pin_num, ++ struct regmap **regmap, ++ int *reg, u8 *bit) ++{ ++ struct rockchip_pinctrl_priv *priv = bank->priv; ++ ++ *regmap = priv->regmap_base; ++ switch (bank->bank_num) { ++ case 0: ++ *reg = RK3528_SMT_GPIO0_OFFSET; ++ break; ++ case 1: ++ *reg = RK3528_SMT_GPIO1_OFFSET; ++ break; ++ case 2: ++ *reg = RK3528_SMT_GPIO2_OFFSET; ++ break; ++ case 3: ++ *reg = RK3528_SMT_GPIO3_OFFSET; ++ break; ++ case 4: ++ *reg = RK3528_SMT_GPIO4_OFFSET; ++ break; ++ default: ++ *reg = 0; ++ debug("unsupported bank_num %d\n", bank->bank_num); ++ break; ++ } ++ ++ *reg += ((pin_num / RK3528_SMT_PINS_PER_REG) * 4); ++ *bit = pin_num % RK3528_SMT_PINS_PER_REG; ++ *bit *= RK3528_SMT_BITS_PER_PIN; ++ ++ return 0; ++} ++ ++static int rk3528_set_schmitt(struct rockchip_pin_bank *bank, ++ int pin_num, int enable) ++{ ++ struct regmap *regmap; ++ int reg; ++ u32 data, rmask; ++ u8 bit; ++ ++ rk3528_calc_schmitt_reg_and_bit(bank, pin_num, ®map, ®, &bit); ++ ++ /* enable the write to the equivalent lower bits */ ++ data = ((1 << RK3528_SMT_BITS_PER_PIN) - 1) << (bit + 16); ++ rmask = data | (data >> 16); ++ data |= (enable << bit); ++ ++ return regmap_update_bits(regmap, reg, rmask, data); ++} ++ ++static struct rockchip_pin_bank rk3528_pin_banks[] = { ++ PIN_BANK_IOMUX_FLAGS_OFFSET(0, 32, "gpio0", ++ IOMUX_WIDTH_4BIT, ++ IOMUX_WIDTH_4BIT, ++ IOMUX_WIDTH_4BIT, ++ IOMUX_WIDTH_4BIT, ++ 0, 0, 0, 0), ++ PIN_BANK_IOMUX_FLAGS_OFFSET(1, 32, "gpio1", ++ IOMUX_WIDTH_4BIT, ++ IOMUX_WIDTH_4BIT, ++ IOMUX_WIDTH_4BIT, ++ IOMUX_WIDTH_4BIT, ++ 0x20020, 0x20028, 0x20030, 0x20038), ++ PIN_BANK_IOMUX_FLAGS_OFFSET(2, 32, "gpio2", ++ IOMUX_WIDTH_4BIT, ++ IOMUX_WIDTH_4BIT, ++ IOMUX_WIDTH_4BIT, ++ IOMUX_WIDTH_4BIT, ++ 0x30040, 0, 0, 0), ++ PIN_BANK_IOMUX_FLAGS_OFFSET(3, 32, "gpio3", ++ IOMUX_WIDTH_4BIT, ++ IOMUX_WIDTH_4BIT, ++ IOMUX_WIDTH_4BIT, ++ IOMUX_WIDTH_4BIT, ++ 0x20060, 0x20068, 0x20070, 0), ++ PIN_BANK_IOMUX_FLAGS_OFFSET(4, 32, "gpio4", ++ IOMUX_WIDTH_4BIT, ++ IOMUX_WIDTH_4BIT, ++ IOMUX_WIDTH_4BIT, ++ IOMUX_WIDTH_4BIT, ++ 0x10080, 0x10088, 0x10090, 0x10098), ++}; ++ ++static const struct rockchip_pin_ctrl rk3528_pin_ctrl = { ++ .pin_banks = rk3528_pin_banks, ++ .nr_banks = ARRAY_SIZE(rk3528_pin_banks), ++ .nr_pins = 160, ++ .grf_mux_offset = 0x0, ++ .set_mux = rk3528_set_mux, ++ .set_pull = rk3528_set_pull, ++ .set_drive = rk3528_set_drive, ++ .set_schmitt = rk3528_set_schmitt, ++}; ++ ++static const struct udevice_id rk3528_pinctrl_ids[] = { ++ { ++ .compatible = "rockchip,rk3528-pinctrl", ++ .data = (ulong)&rk3528_pin_ctrl ++ }, ++ { } ++}; ++ ++U_BOOT_DRIVER(rockchip_rk3528_pinctrl) = { ++ .name = "rockchip_rk3528_pinctrl", ++ .id = UCLASS_PINCTRL, ++ .of_match = rk3528_pinctrl_ids, ++ .priv_auto = sizeof(struct rockchip_pinctrl_priv), ++ .ops = &rockchip_pinctrl_ops, ++#if CONFIG_IS_ENABLED(OF_REAL) ++ .bind = dm_scan_fdt_dev, ++#endif ++ .probe = rockchip_pinctrl_probe, ++}; diff --git a/lede/package/boot/uboot-rockchip/patches/406-mmc-rockchip_sdhci-Extend-variant-configuration.patch b/lede/package/boot/uboot-rockchip/patches/406-mmc-rockchip_sdhci-Extend-variant-configuration.patch new file mode 100644 index 0000000000..e2a4333028 --- /dev/null +++ b/lede/package/boot/uboot-rockchip/patches/406-mmc-rockchip_sdhci-Extend-variant-configuration.patch @@ -0,0 +1,74 @@ +From 81dbef690f2f9734b67a2db9ac5abb773cb4b948 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Thu, 23 Jan 2025 22:48:18 +0000 +Subject: [PATCH 6/9] mmc: rockchip_sdhci: Extend variant configuration + +RK3528 and RK3576 use different tap and delay num for cmdout and strbin. + +Move tap and delay num for cmdout and strbin to driver data to prepare +for adding new SoCs. + +Signed-off-by: Jonas Karlman +--- + drivers/mmc/rockchip_sdhci.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +--- a/drivers/mmc/rockchip_sdhci.c ++++ b/drivers/mmc/rockchip_sdhci.c +@@ -156,6 +156,9 @@ struct sdhci_data { + u32 flags; + u8 hs200_txclk_tapnum; + u8 hs400_txclk_tapnum; ++ u8 hs400_cmdout_tapnum; ++ u8 hs400_strbin_tapnum; ++ u8 ddr50_strbin_delay_num; + }; + + static void rk3399_emmc_phy_power_on(struct rockchip_emmc_phy *phy, u32 clock) +@@ -348,7 +351,7 @@ static int rk3568_sdhci_config_dll(struc + extra = DLL_CMDOUT_SRC_CLK_NEG | + DLL_CMDOUT_BOTH_CLK_EDGE | + DWCMSHC_EMMC_DLL_DLYENA | +- DLL_CMDOUT_TAPNUM_90_DEGREES | ++ data->hs400_cmdout_tapnum | + DLL_CMDOUT_TAPNUM_FROM_SW; + sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_CMDOUT); + } +@@ -360,7 +363,7 @@ static int rk3568_sdhci_config_dll(struc + sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_TXCLK); + + extra = DWCMSHC_EMMC_DLL_DLYENA | +- DLL_STRBIN_TAPNUM_DEFAULT | ++ data->hs400_strbin_tapnum | + DLL_STRBIN_TAPNUM_FROM_SW; + sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN); + } else { +@@ -380,7 +383,7 @@ static int rk3568_sdhci_config_dll(struc + */ + extra = DWCMSHC_EMMC_DLL_DLYENA | + DLL_STRBIN_DELAY_NUM_SEL | +- DLL_STRBIN_DELAY_NUM_DEFAULT << DLL_STRBIN_DELAY_NUM_OFFSET; ++ data->ddr50_strbin_delay_num << DLL_STRBIN_DELAY_NUM_OFFSET; + sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN); + } + +@@ -654,6 +657,9 @@ static const struct sdhci_data rk3568_da + .flags = FLAG_INVERTER_FLAG_IN_RXCLK, + .hs200_txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT, + .hs400_txclk_tapnum = 0x8, ++ .hs400_cmdout_tapnum = DLL_CMDOUT_TAPNUM_90_DEGREES, ++ .hs400_strbin_tapnum = DLL_STRBIN_TAPNUM_DEFAULT, ++ .ddr50_strbin_delay_num = DLL_STRBIN_DELAY_NUM_DEFAULT, + }; + + static const struct sdhci_data rk3588_data = { +@@ -662,6 +668,9 @@ static const struct sdhci_data rk3588_da + .config_dll = rk3568_sdhci_config_dll, + .hs200_txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT, + .hs400_txclk_tapnum = 0x9, ++ .hs400_cmdout_tapnum = DLL_CMDOUT_TAPNUM_90_DEGREES, ++ .hs400_strbin_tapnum = DLL_STRBIN_TAPNUM_DEFAULT, ++ .ddr50_strbin_delay_num = DLL_STRBIN_DELAY_NUM_DEFAULT, + }; + + static const struct udevice_id sdhci_ids[] = { diff --git a/lede/package/boot/uboot-rockchip/patches/407-mmc-rockchip_sdhci-Add-initial-support-for-RK3528.patch b/lede/package/boot/uboot-rockchip/patches/407-mmc-rockchip_sdhci-Add-initial-support-for-RK3528.patch new file mode 100644 index 0000000000..c73b2d8bea --- /dev/null +++ b/lede/package/boot/uboot-rockchip/patches/407-mmc-rockchip_sdhci-Add-initial-support-for-RK3528.patch @@ -0,0 +1,49 @@ +From 1d08efe86fd6756ba2b114ad2a256bea2d0e9b9e Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Thu, 23 Jan 2025 22:48:19 +0000 +Subject: [PATCH 7/9] mmc: rockchip_sdhci: Add initial support for RK3528 + +Add initial support for SDHCI controller in RK3528. + +Only MMC Legacy and MMC High Speed (52MHz) mode is supported after this, +more work is needed to get the faster HS200/HS400/HS400ES modes working. + +Variant tap and delay num is copied from vendor Linux tag +linux-6.1-stan-rkr5. + +Signed-off-by: Jonas Karlman +--- + drivers/mmc/rockchip_sdhci.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +--- a/drivers/mmc/rockchip_sdhci.c ++++ b/drivers/mmc/rockchip_sdhci.c +@@ -650,6 +650,17 @@ static const struct sdhci_data rk3399_da + .set_enhanced_strobe = rk3399_sdhci_set_enhanced_strobe, + }; + ++static const struct sdhci_data rk3528_data = { ++ .set_ios_post = rk3568_sdhci_set_ios_post, ++ .set_clock = rk3568_sdhci_set_clock, ++ .config_dll = rk3568_sdhci_config_dll, ++ .hs200_txclk_tapnum = 0xc, ++ .hs400_txclk_tapnum = 0x6, ++ .hs400_cmdout_tapnum = 0x6, ++ .hs400_strbin_tapnum = 0x3, ++ .ddr50_strbin_delay_num = 0xa, ++}; ++ + static const struct sdhci_data rk3568_data = { + .set_ios_post = rk3568_sdhci_set_ios_post, + .set_clock = rk3568_sdhci_set_clock, +@@ -679,6 +690,10 @@ static const struct udevice_id sdhci_ids + .data = (ulong)&rk3399_data, + }, + { ++ .compatible = "rockchip,rk3528-dwcmshc", ++ .data = (ulong)&rk3528_data, ++ }, ++ { + .compatible = "rockchip,rk3568-dwcmshc", + .data = (ulong)&rk3568_data, + }, diff --git a/lede/package/boot/uboot-rockchip/patches/408-mmc-rockchip_sdhci-Gate-clock-for-glitch-free-phase.patch b/lede/package/boot/uboot-rockchip/patches/408-mmc-rockchip_sdhci-Gate-clock-for-glitch-free-phase.patch new file mode 100644 index 0000000000..8df26f2abb --- /dev/null +++ b/lede/package/boot/uboot-rockchip/patches/408-mmc-rockchip_sdhci-Gate-clock-for-glitch-free-phase.patch @@ -0,0 +1,55 @@ +From ef8c8a638dd459d52d833693b3921010fbd883ff Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Thu, 23 Jan 2025 22:48:20 +0000 +Subject: [PATCH 8/9] mmc: rockchip_sdhci: Gate clock for glitch free phase + switching + +Enable clock stopping to gate clock during phase code change to ensure +glitch free phase switching in auto-tuning circuit. Fixes HS200 mode +on RK3528. + +POST_CHANGE_DLY +Time taken for phase switching and stable clock output. +- Less than 4-cycle latency + +PRE_CHANGE_DLY +Maximum Latency specification between transmit clock and receive clock. +- Less than 4-cycle latency + +TUNE_CLK_STOP_EN +Clock stopping control for Tuning and auto-tuning circuit. When enabled, +clock gate control output is pulled low before changing phase select +codes. This effectively stops the receive clock. Changing phase code +when clocks are stopped ensures glitch free phase switching. +- Clocks stopped during phase code change + +Signed-off-by: Jonas Karlman +--- + drivers/mmc/rockchip_sdhci.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/drivers/mmc/rockchip_sdhci.c ++++ b/drivers/mmc/rockchip_sdhci.c +@@ -50,6 +50,10 @@ + #define DWCMSHC_EMMC_EMMC_CTRL 0x52c + #define DWCMSHC_CARD_IS_EMMC BIT(0) + #define DWCMSHC_ENHANCED_STROBE BIT(8) ++#define DWCMSHC_EMMC_AT_CTRL 0x540 ++#define EMMC_AT_CTRL_TUNE_CLK_STOP_EN BIT(16) ++#define EMMC_AT_CTRL_PRE_CHANGE_DLY 17 ++#define EMMC_AT_CTRL_POST_CHANGE_DLY 19 + #define DWCMSHC_EMMC_DLL_CTRL 0x800 + #define DWCMSHC_EMMC_DLL_CTRL_RESET BIT(1) + #define DWCMSHC_EMMC_DLL_RXCLK 0x804 +@@ -326,6 +330,11 @@ static int rk3568_sdhci_config_dll(struc + udelay(1); + sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL); + ++ extra = 0x3 << EMMC_AT_CTRL_POST_CHANGE_DLY | ++ 0x3 << EMMC_AT_CTRL_PRE_CHANGE_DLY | ++ EMMC_AT_CTRL_TUNE_CLK_STOP_EN; ++ sdhci_writel(host, extra, DWCMSHC_EMMC_AT_CTRL); ++ + /* Init DLL settings */ + extra = DWCMSHC_EMMC_DLL_START_DEFAULT << DWCMSHC_EMMC_DLL_START_POINT | + DWCMSHC_EMMC_DLL_INC_VALUE << DWCMSHC_EMMC_DLL_INC | diff --git a/lede/package/boot/uboot-rockchip/patches/409-rng-rockchip-Add-support-for-rkrng-variant.patch b/lede/package/boot/uboot-rockchip/patches/409-rng-rockchip-Add-support-for-rkrng-variant.patch new file mode 100644 index 0000000000..32441a2492 --- /dev/null +++ b/lede/package/boot/uboot-rockchip/patches/409-rng-rockchip-Add-support-for-rkrng-variant.patch @@ -0,0 +1,119 @@ +From 4e19cd0a572b6a27b82fef84c30fca69914b7798 Mon Sep 17 00:00:00 2001 +From: Lin Jinhan +Date: Thu, 23 Jan 2025 22:48:21 +0000 +Subject: [PATCH 9/9] rng: rockchip: Add support for rkrng variant + +Add support for rkrng variant, used by e.g. RK3528 and RK3576. + +Imported from vendor U-Boot linux-6.1-stan-rkr5 tag with minor +adjustments for mainline. + +Signed-off-by: Lin Jinhan +Signed-off-by: Jonas Karlman +--- + drivers/rng/rockchip_rng.c | 73 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 73 insertions(+) + +--- a/drivers/rng/rockchip_rng.c ++++ b/drivers/rng/rockchip_rng.c +@@ -70,6 +70,27 @@ + #define TRNG_v1_VERSION_CODE 0x46BC + /* end of TRNG V1 register define */ + ++/* start of RKRNG register define */ ++#define RKRNG_CTRL 0x0010 ++#define RKRNG_CTRL_INST_REQ BIT(0) ++#define RKRNG_CTRL_RESEED_REQ BIT(1) ++#define RKRNG_CTRL_TEST_REQ BIT(2) ++#define RKRNG_CTRL_SW_DRNG_REQ BIT(3) ++#define RKRNG_CTRL_SW_TRNG_REQ BIT(4) ++ ++#define RKRNG_STATE 0x0014 ++#define RKRNG_STATE_INST_ACK BIT(0) ++#define RKRNG_STATE_RESEED_ACK BIT(1) ++#define RKRNG_STATE_TEST_ACK BIT(2) ++#define RKRNG_STATE_SW_DRNG_ACK BIT(3) ++#define RKRNG_STATE_SW_TRNG_ACK BIT(4) ++ ++/* DRNG_DATA_0 ~ DNG_DATA_7 */ ++#define RKRNG_DRNG_DATA_0 0x0070 ++#define RKRNG_DRNG_DATA_7 0x008C ++ ++/* end of RKRNG register define */ ++ + #define RK_RNG_TIME_OUT 50000 /* max 50ms */ + + #define trng_write(pdata, pos, val) writel(val, (pdata)->base + (pos)) +@@ -228,6 +249,49 @@ exit: + return retval; + } + ++static int rkrng_init(struct udevice *dev) ++{ ++ struct rk_rng_plat *pdata = dev_get_priv(dev); ++ u32 reg = 0; ++ ++ rk_clrreg(pdata->base + RKRNG_CTRL, 0xffff); ++ ++ reg = trng_read(pdata, RKRNG_STATE); ++ trng_write(pdata, RKRNG_STATE, reg); ++ ++ return 0; ++} ++ ++static int rkrng_rng_read(struct udevice *dev, void *data, size_t len) ++{ ++ struct rk_rng_plat *pdata = dev_get_priv(dev); ++ u32 reg = 0; ++ int retval; ++ ++ if (len > RK_HW_RNG_MAX) ++ return -EINVAL; ++ ++ reg = RKRNG_CTRL_SW_DRNG_REQ; ++ ++ rk_clrsetreg(pdata->base + RKRNG_CTRL, 0xffff, reg); ++ ++ retval = readl_poll_timeout(pdata->base + RKRNG_STATE, reg, ++ (reg & RKRNG_STATE_SW_DRNG_ACK), ++ RK_RNG_TIME_OUT); ++ if (retval) ++ goto exit; ++ ++ trng_write(pdata, RKRNG_STATE, reg); ++ ++ rk_rng_read_regs(pdata->base + RKRNG_DRNG_DATA_0, data, len); ++ ++exit: ++ /* close TRNG */ ++ rk_clrreg(pdata->base + RKRNG_CTRL, 0xffff); ++ ++ return retval; ++} ++ + static int rockchip_rng_read(struct udevice *dev, void *data, size_t len) + { + unsigned char *buf = data; +@@ -295,6 +359,11 @@ static const struct rk_rng_soc_data rk_t + .rk_rng_read = rk_trngv1_rng_read, + }; + ++static const struct rk_rng_soc_data rkrng_soc_data = { ++ .rk_rng_init = rkrng_init, ++ .rk_rng_read = rkrng_rng_read, ++}; ++ + static const struct dm_rng_ops rockchip_rng_ops = { + .read = rockchip_rng_read, + }; +@@ -320,6 +389,10 @@ static const struct udevice_id rockchip_ + .compatible = "rockchip,trngv1", + .data = (ulong)&rk_trngv1_soc_data, + }, ++ { ++ .compatible = "rockchip,rkrng", ++ .data = (ulong)&rkrng_soc_data, ++ }, + {}, + }; + diff --git a/lede/package/boot/uboot-rockchip/patches/411-arm-dts-rockchip-Add-rk3528-pinctrl.dtsi.patch b/lede/package/boot/uboot-rockchip/patches/411-arm-dts-rockchip-Add-rk3528-pinctrl.dtsi.patch new file mode 100644 index 0000000000..6b134676e4 --- /dev/null +++ b/lede/package/boot/uboot-rockchip/patches/411-arm-dts-rockchip-Add-rk3528-pinctrl.dtsi.patch @@ -0,0 +1,1416 @@ +From fa2055e1249835666241bf30a6f0d9ccbddf22dd Mon Sep 17 00:00:00 2001 +From: Joseph Chen +Date: Thu, 23 Jan 2025 22:48:22 +0000 +Subject: [PATCH 1/4] arm: dts: rockchip: Add rk3528-pinctrl.dtsi + +Import rk3528-pinctrl.dtsi from vendor U-Boot and Linux tag +linux-6.1-stan-rkr5 with the hdmi-pins-idle node removed due to missing +label reference to pcfg_output_low_pull_down. + +Signed-off-by: Joseph Chen +Signed-off-by: Jonas Karlman +--- + arch/arm/dts/rk3528-pinctrl.dtsi | 1397 ++++++++++++++++++++++++++++++ + 1 file changed, 1397 insertions(+) + create mode 100644 arch/arm/dts/rk3528-pinctrl.dtsi + +--- /dev/null ++++ b/arch/arm/dts/rk3528-pinctrl.dtsi +@@ -0,0 +1,1397 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright (c) 2022 Rockchip Electronics Co., Ltd. ++ */ ++ ++#include ++#include "rockchip-pinconf.dtsi" ++ ++/* ++ * This file is auto generated by pin2dts tool, please keep these code ++ * by adding changes at end of this file. ++ */ ++&pinctrl { ++ arm { ++ /omit-if-no-ref/ ++ arm_pins: arm-pins { ++ rockchip,pins = ++ /* arm_avs */ ++ <4 RK_PC4 3 &pcfg_pull_none>; ++ }; ++ }; ++ ++ clk { ++ /omit-if-no-ref/ ++ clkm0_32k_out: clkm0-32k-out { ++ rockchip,pins = ++ /* clkm0_32k_out */ ++ <3 RK_PC3 3 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ clkm1_32k_out: clkm1-32k-out { ++ rockchip,pins = ++ /* clkm1_32k_out */ ++ <1 RK_PC3 1 &pcfg_pull_none>; ++ }; ++ }; ++ ++ emmc { ++ /omit-if-no-ref/ ++ emmc_rstnout: emmc-rstnout { ++ rockchip,pins = ++ /* emmc_rstn */ ++ <1 RK_PD6 1 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ emmc_bus8: emmc-bus8 { ++ rockchip,pins = ++ /* emmc_d0 */ ++ <1 RK_PC4 1 &pcfg_pull_up_drv_level_2>, ++ /* emmc_d1 */ ++ <1 RK_PC5 1 &pcfg_pull_up_drv_level_2>, ++ /* emmc_d2 */ ++ <1 RK_PC6 1 &pcfg_pull_up_drv_level_2>, ++ /* emmc_d3 */ ++ <1 RK_PC7 1 &pcfg_pull_up_drv_level_2>, ++ /* emmc_d4 */ ++ <1 RK_PD0 1 &pcfg_pull_up_drv_level_2>, ++ /* emmc_d5 */ ++ <1 RK_PD1 1 &pcfg_pull_up_drv_level_2>, ++ /* emmc_d6 */ ++ <1 RK_PD2 1 &pcfg_pull_up_drv_level_2>, ++ /* emmc_d7 */ ++ <1 RK_PD3 1 &pcfg_pull_up_drv_level_2>; ++ }; ++ ++ /omit-if-no-ref/ ++ emmc_clk: emmc-clk { ++ rockchip,pins = ++ /* emmc_clk */ ++ <1 RK_PD5 1 &pcfg_pull_up_drv_level_2>; ++ }; ++ ++ /omit-if-no-ref/ ++ emmc_cmd: emmc-cmd { ++ rockchip,pins = ++ /* emmc_cmd */ ++ <1 RK_PD4 1 &pcfg_pull_up_drv_level_2>; ++ }; ++ ++ /omit-if-no-ref/ ++ emmc_strb: emmc-strb { ++ rockchip,pins = ++ /* emmc_strb */ ++ <1 RK_PD7 1 &pcfg_pull_none>; ++ }; ++ }; ++ ++ eth { ++ /omit-if-no-ref/ ++ eth_pins: eth-pins { ++ rockchip,pins = ++ /* eth_clk_25m_out */ ++ <3 RK_PB5 2 &pcfg_pull_none_drv_level_2>; ++ }; ++ }; ++ ++ fephy { ++ /omit-if-no-ref/ ++ fephym0_led_dpx: fephym0-led_dpx { ++ rockchip,pins = ++ /* fephy_led_dpx_m0 */ ++ <4 RK_PB5 2 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ fephym0_led_link: fephym0-led_link { ++ rockchip,pins = ++ /* fephy_led_link_m0 */ ++ <4 RK_PC0 2 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ fephym0_led_spd: fephym0-led_spd { ++ rockchip,pins = ++ /* fephy_led_spd_m0 */ ++ <4 RK_PB7 2 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ fephym1_led_dpx: fephym1-led_dpx { ++ rockchip,pins = ++ /* fephy_led_dpx_m1 */ ++ <2 RK_PA4 5 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ fephym1_led_link: fephym1-led_link { ++ rockchip,pins = ++ /* fephy_led_link_m1 */ ++ <2 RK_PA6 5 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ fephym1_led_spd: fephym1-led_spd { ++ rockchip,pins = ++ /* fephy_led_spd_m1 */ ++ <2 RK_PA5 5 &pcfg_pull_none>; ++ }; ++ }; ++ ++ fspi { ++ /omit-if-no-ref/ ++ fspi_pins: fspi-pins { ++ rockchip,pins = ++ /* fspi_clk */ ++ <1 RK_PD5 2 &pcfg_pull_none>, ++ /* fspi_d0 */ ++ <1 RK_PC4 2 &pcfg_pull_none>, ++ /* fspi_d1 */ ++ <1 RK_PC5 2 &pcfg_pull_none>, ++ /* fspi_d2 */ ++ <1 RK_PC6 2 &pcfg_pull_none>, ++ /* fspi_d3 */ ++ <1 RK_PC7 2 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ fspi_csn0: fspi-csn0 { ++ rockchip,pins = ++ /* fspi_csn0 */ ++ <1 RK_PD0 2 &pcfg_pull_none>; ++ }; ++ /omit-if-no-ref/ ++ fspi_csn1: fspi-csn1 { ++ rockchip,pins = ++ /* fspi_csn1 */ ++ <1 RK_PD1 2 &pcfg_pull_none>; ++ }; ++ }; ++ ++ gpu { ++ /omit-if-no-ref/ ++ gpu_pins: gpu-pins { ++ rockchip,pins = ++ /* gpu_avs */ ++ <4 RK_PC3 3 &pcfg_pull_none>; ++ }; ++ }; ++ ++ hdmi { ++ /omit-if-no-ref/ ++ hdmi_pins: hdmi-pins { ++ rockchip,pins = ++ /* hdmi_tx_cec */ ++ <0 RK_PA3 1 &pcfg_pull_none>, ++ /* hdmi_tx_hpd */ ++ <0 RK_PA2 1 &pcfg_pull_none>, ++ /* hdmi_tx_scl */ ++ <0 RK_PA4 1 &pcfg_pull_none>, ++ /* hdmi_tx_sda */ ++ <0 RK_PA5 1 &pcfg_pull_none>; ++ }; ++ }; ++ ++ hsm { ++ /omit-if-no-ref/ ++ hsmm0_pins: hsmm0-pins { ++ rockchip,pins = ++ /* hsm_clk_out_m0 */ ++ <2 RK_PA2 4 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ hsmm1_pins: hsmm1-pins { ++ rockchip,pins = ++ /* hsm_clk_out_m1 */ ++ <1 RK_PA4 3 &pcfg_pull_none>; ++ }; ++ }; ++ ++ i2c0 { ++ /omit-if-no-ref/ ++ i2c0m0_xfer: i2c0m0-xfer { ++ rockchip,pins = ++ /* i2c0_scl_m0 */ ++ <4 RK_PC4 2 &pcfg_pull_none_smt>, ++ /* i2c0_sda_m0 */ ++ <4 RK_PC3 2 &pcfg_pull_none_smt>; ++ }; ++ ++ /omit-if-no-ref/ ++ i2c0m1_xfer: i2c0m1-xfer { ++ rockchip,pins = ++ /* i2c0_scl_m1 */ ++ <4 RK_PA1 2 &pcfg_pull_none_smt>, ++ /* i2c0_sda_m1 */ ++ <4 RK_PA0 2 &pcfg_pull_none_smt>; ++ }; ++ }; ++ ++ i2c1 { ++ /omit-if-no-ref/ ++ i2c1m0_xfer: i2c1m0-xfer { ++ rockchip,pins = ++ /* i2c1_scl_m0 */ ++ <4 RK_PA3 2 &pcfg_pull_none_smt>, ++ /* i2c1_sda_m0 */ ++ <4 RK_PA2 2 &pcfg_pull_none_smt>; ++ }; ++ ++ /omit-if-no-ref/ ++ i2c1m1_xfer: i2c1m1-xfer { ++ rockchip,pins = ++ /* i2c1_scl_m1 */ ++ <4 RK_PC5 4 &pcfg_pull_none_smt>, ++ /* i2c1_sda_m1 */ ++ <4 RK_PC6 4 &pcfg_pull_none_smt>; ++ }; ++ }; ++ ++ i2c2 { ++ /omit-if-no-ref/ ++ i2c2m0_xfer: i2c2m0-xfer { ++ rockchip,pins = ++ /* i2c2_scl_m0 */ ++ <0 RK_PA4 2 &pcfg_pull_none_smt>, ++ /* i2c2_sda_m0 */ ++ <0 RK_PA5 2 &pcfg_pull_none_smt>; ++ }; ++ ++ /omit-if-no-ref/ ++ i2c2m1_xfer: i2c2m1-xfer { ++ rockchip,pins = ++ /* i2c2_scl_m1 */ ++ <1 RK_PA5 3 &pcfg_pull_none_smt>, ++ /* i2c2_sda_m1 */ ++ <1 RK_PA6 3 &pcfg_pull_none_smt>; ++ }; ++ }; ++ ++ i2c3 { ++ /omit-if-no-ref/ ++ i2c3m0_xfer: i2c3m0-xfer { ++ rockchip,pins = ++ /* i2c3_scl_m0 */ ++ <1 RK_PA0 2 &pcfg_pull_none_smt>, ++ /* i2c3_sda_m0 */ ++ <1 RK_PA1 2 &pcfg_pull_none_smt>; ++ }; ++ ++ /omit-if-no-ref/ ++ i2c3m1_xfer: i2c3m1-xfer { ++ rockchip,pins = ++ /* i2c3_scl_m1 */ ++ <3 RK_PC1 5 &pcfg_pull_none_smt>, ++ /* i2c3_sda_m1 */ ++ <3 RK_PC3 5 &pcfg_pull_none_smt>; ++ }; ++ }; ++ ++ i2c4 { ++ /omit-if-no-ref/ ++ i2c4_xfer: i2c4-xfer { ++ rockchip,pins = ++ /* i2c4_scl */ ++ <2 RK_PA0 4 &pcfg_pull_none_smt>, ++ /* i2c4_sda */ ++ <2 RK_PA1 4 &pcfg_pull_none_smt>; ++ }; ++ }; ++ ++ i2c5 { ++ /omit-if-no-ref/ ++ i2c5m0_xfer: i2c5m0-xfer { ++ rockchip,pins = ++ /* i2c5_scl_m0 */ ++ <1 RK_PB2 3 &pcfg_pull_none_smt>, ++ /* i2c5_sda_m0 */ ++ <1 RK_PB3 3 &pcfg_pull_none_smt>; ++ }; ++ ++ /omit-if-no-ref/ ++ i2c5m1_xfer: i2c5m1-xfer { ++ rockchip,pins = ++ /* i2c5_scl_m1 */ ++ <1 RK_PD2 3 &pcfg_pull_none_smt>, ++ /* i2c5_sda_m1 */ ++ <1 RK_PD3 3 &pcfg_pull_none_smt>; ++ }; ++ }; ++ ++ i2c6 { ++ /omit-if-no-ref/ ++ i2c6m0_xfer: i2c6m0-xfer { ++ rockchip,pins = ++ /* i2c6_scl_m0 */ ++ <3 RK_PB2 5 &pcfg_pull_none_smt>, ++ /* i2c6_sda_m0 */ ++ <3 RK_PB3 5 &pcfg_pull_none_smt>; ++ }; ++ ++ /omit-if-no-ref/ ++ i2c6m1_xfer: i2c6m1-xfer { ++ rockchip,pins = ++ /* i2c6_scl_m1 */ ++ <1 RK_PD4 3 &pcfg_pull_none_smt>, ++ /* i2c6_sda_m1 */ ++ <1 RK_PD7 3 &pcfg_pull_none_smt>; ++ }; ++ }; ++ ++ i2c7 { ++ /omit-if-no-ref/ ++ i2c7_xfer: i2c7-xfer { ++ rockchip,pins = ++ /* i2c7_scl */ ++ <2 RK_PA5 4 &pcfg_pull_none_smt>, ++ /* i2c7_sda */ ++ <2 RK_PA6 4 &pcfg_pull_none_smt>; ++ }; ++ }; ++ ++ i2s0 { ++ /omit-if-no-ref/ ++ i2s0m0_lrck: i2s0m0-lrck { ++ rockchip,pins = ++ /* i2s0_lrck_m0 */ ++ <3 RK_PB6 1 &pcfg_pull_none_smt>; ++ }; ++ ++ /omit-if-no-ref/ ++ i2s0m0_mclk: i2s0m0-mclk { ++ rockchip,pins = ++ /* i2s0_mclk_m0 */ ++ <3 RK_PB4 1 &pcfg_pull_none_smt>; ++ }; ++ ++ /omit-if-no-ref/ ++ i2s0m0_sclk: i2s0m0-sclk { ++ rockchip,pins = ++ /* i2s0_sclk_m0 */ ++ <3 RK_PB5 1 &pcfg_pull_none_smt>; ++ }; ++ ++ /omit-if-no-ref/ ++ i2s0m0_sdi: i2s0m0-sdi { ++ rockchip,pins = ++ /* i2s0m0_sdi */ ++ <3 RK_PB7 1 &pcfg_pull_none>; ++ }; ++ /omit-if-no-ref/ ++ i2s0m0_sdo: i2s0m0-sdo { ++ rockchip,pins = ++ /* i2s0m0_sdo */ ++ <3 RK_PC0 1 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ i2s0m1_lrck: i2s0m1-lrck { ++ rockchip,pins = ++ /* i2s0_lrck_m1 */ ++ <1 RK_PB6 1 &pcfg_pull_none_smt>; ++ }; ++ ++ /omit-if-no-ref/ ++ i2s0m1_mclk: i2s0m1-mclk { ++ rockchip,pins = ++ /* i2s0_mclk_m1 */ ++ <1 RK_PB4 1 &pcfg_pull_none_smt>; ++ }; ++ ++ /omit-if-no-ref/ ++ i2s0m1_sclk: i2s0m1-sclk { ++ rockchip,pins = ++ /* i2s0_sclk_m1 */ ++ <1 RK_PB5 1 &pcfg_pull_none_smt>; ++ }; ++ ++ /omit-if-no-ref/ ++ i2s0m1_sdi: i2s0m1-sdi { ++ rockchip,pins = ++ /* i2s0m1_sdi */ ++ <1 RK_PB7 1 &pcfg_pull_none>; ++ }; ++ /omit-if-no-ref/ ++ i2s0m1_sdo: i2s0m1-sdo { ++ rockchip,pins = ++ /* i2s0m1_sdo */ ++ <1 RK_PC0 1 &pcfg_pull_none>; ++ }; ++ }; ++ ++ i2s1 { ++ /omit-if-no-ref/ ++ i2s1_lrck: i2s1-lrck { ++ rockchip,pins = ++ /* i2s1_lrck */ ++ <4 RK_PA6 1 &pcfg_pull_none_smt>; ++ }; ++ ++ /omit-if-no-ref/ ++ i2s1_mclk: i2s1-mclk { ++ rockchip,pins = ++ /* i2s1_mclk */ ++ <4 RK_PA4 1 &pcfg_pull_none_smt>; ++ }; ++ ++ /omit-if-no-ref/ ++ i2s1_sclk: i2s1-sclk { ++ rockchip,pins = ++ /* i2s1_sclk */ ++ <4 RK_PA5 1 &pcfg_pull_none_smt>; ++ }; ++ ++ /omit-if-no-ref/ ++ i2s1_sdi0: i2s1-sdi0 { ++ rockchip,pins = ++ /* i2s1_sdi0 */ ++ <4 RK_PB4 1 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ i2s1_sdi1: i2s1-sdi1 { ++ rockchip,pins = ++ /* i2s1_sdi1 */ ++ <4 RK_PB3 1 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ i2s1_sdi2: i2s1-sdi2 { ++ rockchip,pins = ++ /* i2s1_sdi2 */ ++ <4 RK_PA3 1 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ i2s1_sdi3: i2s1-sdi3 { ++ rockchip,pins = ++ /* i2s1_sdi3 */ ++ <4 RK_PA2 1 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ i2s1_sdo0: i2s1-sdo0 { ++ rockchip,pins = ++ /* i2s1_sdo0 */ ++ <4 RK_PA7 1 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ i2s1_sdo1: i2s1-sdo1 { ++ rockchip,pins = ++ /* i2s1_sdo1 */ ++ <4 RK_PB0 1 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ i2s1_sdo2: i2s1-sdo2 { ++ rockchip,pins = ++ /* i2s1_sdo2 */ ++ <4 RK_PB1 1 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ i2s1_sdo3: i2s1-sdo3 { ++ rockchip,pins = ++ /* i2s1_sdo3 */ ++ <4 RK_PB2 1 &pcfg_pull_none>; ++ }; ++ }; ++ ++ jtag { ++ /omit-if-no-ref/ ++ jtagm0_pins: jtagm0-pins { ++ rockchip,pins = ++ /* jtag_cpu_tck_m0 */ ++ <2 RK_PA2 2 &pcfg_pull_none>, ++ /* jtag_cpu_tms_m0 */ ++ <2 RK_PA3 2 &pcfg_pull_none>, ++ /* jtag_mcu_tck_m0 */ ++ <2 RK_PA4 2 &pcfg_pull_none>, ++ /* jtag_mcu_tms_m0 */ ++ <2 RK_PA5 2 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ jtagm1_pins: jtagm1-pins { ++ rockchip,pins = ++ /* jtag_cpu_tck_m1 */ ++ <4 RK_PD0 2 &pcfg_pull_none>, ++ /* jtag_cpu_tms_m1 */ ++ <4 RK_PC7 2 &pcfg_pull_none>, ++ /* jtag_mcu_tck_m1 */ ++ <4 RK_PD0 3 &pcfg_pull_none>, ++ /* jtag_mcu_tms_m1 */ ++ <4 RK_PC7 3 &pcfg_pull_none>; ++ }; ++ }; ++ ++ pcie { ++ /omit-if-no-ref/ ++ pciem0_pins: pciem0-pins { ++ rockchip,pins = ++ /* pcie_clkreqn_m0 */ ++ <3 RK_PA6 5 &pcfg_pull_none>, ++ /* pcie_perstn_m0 */ ++ <3 RK_PB0 5 &pcfg_pull_none>, ++ /* pcie_waken_m0 */ ++ <3 RK_PA7 5 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ pciem1_pins: pciem1-pins { ++ rockchip,pins = ++ /* pcie_clkreqn_m1 */ ++ <1 RK_PA0 4 &pcfg_pull_none>, ++ /* pcie_perstn_m1 */ ++ <1 RK_PA2 4 &pcfg_pull_none>, ++ /* pcie_waken_m1 */ ++ <1 RK_PA1 4 &pcfg_pull_none>; ++ }; ++ }; ++ ++ pdm { ++ /omit-if-no-ref/ ++ pdm_clk0: pdm-clk0 { ++ rockchip,pins = ++ /* pdm_clk0 */ ++ <4 RK_PB5 3 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ pdm_clk1: pdm-clk1 { ++ rockchip,pins = ++ /* pdm_clk1 */ ++ <4 RK_PA4 3 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ pdm_sdi0: pdm-sdi0 { ++ rockchip,pins = ++ /* pdm_sdi0 */ ++ <4 RK_PB2 3 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ pdm_sdi1: pdm-sdi1 { ++ rockchip,pins = ++ /* pdm_sdi1 */ ++ <4 RK_PB1 3 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ pdm_sdi2: pdm-sdi2 { ++ rockchip,pins = ++ /* pdm_sdi2 */ ++ <4 RK_PB3 3 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ pdm_sdi3: pdm-sdi3 { ++ rockchip,pins = ++ /* pdm_sdi3 */ ++ <4 RK_PC1 3 &pcfg_pull_none>; ++ }; ++ }; ++ ++ pmu { ++ /omit-if-no-ref/ ++ pmu_pins: pmu-pins { ++ rockchip,pins = ++ /* pmu_debug */ ++ <4 RK_PA0 4 &pcfg_pull_none>; ++ }; ++ }; ++ ++ pwm0 { ++ /omit-if-no-ref/ ++ pwm0m0_pins: pwm0m0-pins { ++ rockchip,pins = ++ /* pwm0_m0 */ ++ <4 RK_PC3 1 &pcfg_pull_none_drv_level_0>; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm0m1_pins: pwm0m1-pins { ++ rockchip,pins = ++ /* pwm0_m1 */ ++ <1 RK_PA2 5 &pcfg_pull_none_drv_level_0>; ++ }; ++ }; ++ ++ pwm1 { ++ /omit-if-no-ref/ ++ pwm1m0_pins: pwm1m0-pins { ++ rockchip,pins = ++ /* pwm1_m0 */ ++ <4 RK_PC4 1 &pcfg_pull_none_drv_level_0>; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm1m1_pins: pwm1m1-pins { ++ rockchip,pins = ++ /* pwm1_m1 */ ++ <1 RK_PA3 4 &pcfg_pull_none_drv_level_0>; ++ }; ++ }; ++ ++ pwm2 { ++ /omit-if-no-ref/ ++ pwm2m0_pins: pwm2m0-pins { ++ rockchip,pins = ++ /* pwm2_m0 */ ++ <4 RK_PC5 1 &pcfg_pull_none_drv_level_0>; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm2m1_pins: pwm2m1-pins { ++ rockchip,pins = ++ /* pwm2_m1 */ ++ <1 RK_PA7 2 &pcfg_pull_none_drv_level_0>; ++ }; ++ }; ++ ++ pwm3 { ++ /omit-if-no-ref/ ++ pwm3m0_pins: pwm3m0-pins { ++ rockchip,pins = ++ /* pwm3_m0 */ ++ <4 RK_PC6 1 &pcfg_pull_none_drv_level_0>; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm3m1_pins: pwm3m1-pins { ++ rockchip,pins = ++ /* pwm3_m1 */ ++ <2 RK_PA4 3 &pcfg_pull_none_drv_level_0>; ++ }; ++ }; ++ ++ pwm4 { ++ /omit-if-no-ref/ ++ pwm4m0_pins: pwm4m0-pins { ++ rockchip,pins = ++ /* pwm4_m0 */ ++ <4 RK_PB7 1 &pcfg_pull_none_drv_level_0>; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm4m1_pins: pwm4m1-pins { ++ rockchip,pins = ++ /* pwm4_m1 */ ++ <1 RK_PA4 2 &pcfg_pull_none_drv_level_0>; ++ }; ++ }; ++ ++ pwm5 { ++ /omit-if-no-ref/ ++ pwm5m0_pins: pwm5m0-pins { ++ rockchip,pins = ++ /* pwm5_m0 */ ++ <4 RK_PC0 1 &pcfg_pull_none_drv_level_0>; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm5m1_pins: pwm5m1-pins { ++ rockchip,pins = ++ /* pwm5_m1 */ ++ <3 RK_PC3 1 &pcfg_pull_none_drv_level_0>; ++ }; ++ }; ++ ++ pwm6 { ++ /omit-if-no-ref/ ++ pwm6m0_pins: pwm6m0-pins { ++ rockchip,pins = ++ /* pwm6_m0 */ ++ <4 RK_PC1 1 &pcfg_pull_none_drv_level_0>; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm6m1_pins: pwm6m1-pins { ++ rockchip,pins = ++ /* pwm6_m1 */ ++ <1 RK_PC3 3 &pcfg_pull_none_drv_level_0>; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm6m2_pins: pwm6m2-pins { ++ rockchip,pins = ++ /* pwm6_m2 */ ++ <3 RK_PC1 1 &pcfg_pull_none_drv_level_0>; ++ }; ++ }; ++ ++ pwm7 { ++ /omit-if-no-ref/ ++ pwm7m0_pins: pwm7m0-pins { ++ rockchip,pins = ++ /* pwm7_m0 */ ++ <4 RK_PC2 1 &pcfg_pull_none_drv_level_0>; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm7m1_pins: pwm7m1-pins { ++ rockchip,pins = ++ /* pwm7_m1 */ ++ <1 RK_PC2 2 &pcfg_pull_none_drv_level_0>; ++ }; ++ }; ++ ++ pwr { ++ /omit-if-no-ref/ ++ pwr_pins: pwr-pins { ++ rockchip,pins = ++ /* pwr_ctrl0 */ ++ <4 RK_PC2 2 &pcfg_pull_none>, ++ /* pwr_ctrl1 */ ++ <4 RK_PB6 1 &pcfg_pull_none>; ++ }; ++ }; ++ ++ ref { ++ /omit-if-no-ref/ ++ refm0_pins: refm0-pins { ++ rockchip,pins = ++ /* ref_clk_out_m0 */ ++ <0 RK_PA1 1 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ refm1_pins: refm1-pins { ++ rockchip,pins = ++ /* ref_clk_out_m1 */ ++ <3 RK_PC3 6 &pcfg_pull_none>; ++ }; ++ }; ++ ++ rgmii { ++ /omit-if-no-ref/ ++ rgmii_miim: rgmii-miim { ++ rockchip,pins = ++ /* rgmii_mdc */ ++ <3 RK_PB6 2 &pcfg_pull_none_drv_level_2>, ++ /* rgmii_mdio */ ++ <3 RK_PB7 2 &pcfg_pull_none_drv_level_2>; ++ }; ++ ++ /omit-if-no-ref/ ++ rgmii_rx_bus2: rgmii-rx_bus2 { ++ rockchip,pins = ++ /* rgmii_rxd0 */ ++ <3 RK_PA3 2 &pcfg_pull_none>, ++ /* rgmii_rxd1 */ ++ <3 RK_PA2 2 &pcfg_pull_none>, ++ /* rgmii_rxdv_crs */ ++ <3 RK_PC2 2 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ rgmii_tx_bus2: rgmii-tx_bus2 { ++ rockchip,pins = ++ /* rgmii_txd0 */ ++ <3 RK_PA1 2 &pcfg_pull_none_drv_level_2>, ++ /* rgmii_txd1 */ ++ <3 RK_PA0 2 &pcfg_pull_none_drv_level_2>, ++ /* rgmii_txen */ ++ <3 RK_PC0 2 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ rgmii_rgmii_clk: rgmii-rgmii_clk { ++ rockchip,pins = ++ /* rgmii_rxclk */ ++ <3 RK_PA5 2 &pcfg_pull_none>, ++ /* rgmii_txclk */ ++ <3 RK_PA4 2 &pcfg_pull_none_drv_level_2>; ++ }; ++ ++ /omit-if-no-ref/ ++ rgmii_rgmii_bus: rgmii-rgmii_bus { ++ rockchip,pins = ++ /* rgmii_rxd2 */ ++ <3 RK_PA7 2 &pcfg_pull_none>, ++ /* rgmii_rxd3 */ ++ <3 RK_PA6 2 &pcfg_pull_none>, ++ /* rgmii_txd2 */ ++ <3 RK_PB1 2 &pcfg_pull_none_drv_level_2>, ++ /* rgmii_txd3 */ ++ <3 RK_PB0 2 &pcfg_pull_none_drv_level_2>; ++ }; ++ ++ /omit-if-no-ref/ ++ rgmii_clk: rgmii-clk { ++ rockchip,pins = ++ /* rgmii_clk */ ++ <3 RK_PB4 2 &pcfg_pull_none>; ++ }; ++ /omit-if-no-ref/ ++ rgmii_txer: rgmii-txer { ++ rockchip,pins = ++ /* rgmii_txer */ ++ <3 RK_PC1 2 &pcfg_pull_none>; ++ }; ++ }; ++ ++ scr { ++ /omit-if-no-ref/ ++ scrm0_pins: scrm0-pins { ++ rockchip,pins = ++ /* scr_clk_m0 */ ++ <1 RK_PA2 3 &pcfg_pull_none>, ++ /* scr_data_m0 */ ++ <1 RK_PA1 3 &pcfg_pull_none>, ++ /* scr_detn_m0 */ ++ <1 RK_PA0 3 &pcfg_pull_none>, ++ /* scr_rstn_m0 */ ++ <1 RK_PA3 3 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ scrm1_pins: scrm1-pins { ++ rockchip,pins = ++ /* scr_clk_m1 */ ++ <2 RK_PA5 3 &pcfg_pull_none>, ++ /* scr_data_m1 */ ++ <2 RK_PA3 4 &pcfg_pull_none>, ++ /* scr_detn_m1 */ ++ <2 RK_PA6 3 &pcfg_pull_none>, ++ /* scr_rstn_m1 */ ++ <2 RK_PA4 4 &pcfg_pull_none>; ++ }; ++ }; ++ ++ sdio0 { ++ /omit-if-no-ref/ ++ sdio0_bus4: sdio0-bus4 { ++ rockchip,pins = ++ /* sdio0_d0 */ ++ <1 RK_PA0 1 &pcfg_pull_up_drv_level_2>, ++ /* sdio0_d1 */ ++ <1 RK_PA1 1 &pcfg_pull_up_drv_level_2>, ++ /* sdio0_d2 */ ++ <1 RK_PA2 1 &pcfg_pull_up_drv_level_2>, ++ /* sdio0_d3 */ ++ <1 RK_PA3 1 &pcfg_pull_up_drv_level_2>; ++ }; ++ ++ /omit-if-no-ref/ ++ sdio0_clk: sdio0-clk { ++ rockchip,pins = ++ /* sdio0_clk */ ++ <1 RK_PA5 1 &pcfg_pull_up_drv_level_2>; ++ }; ++ ++ /omit-if-no-ref/ ++ sdio0_cmd: sdio0-cmd { ++ rockchip,pins = ++ /* sdio0_cmd */ ++ <1 RK_PA4 1 &pcfg_pull_up_drv_level_2>; ++ }; ++ ++ /omit-if-no-ref/ ++ sdio0_det: sdio0-det { ++ rockchip,pins = ++ /* sdio0_det */ ++ <1 RK_PA6 1 &pcfg_pull_up>; ++ }; ++ ++ /omit-if-no-ref/ ++ sdio0_pwren: sdio0-pwren { ++ rockchip,pins = ++ /* sdio0_pwren */ ++ <1 RK_PA7 1 &pcfg_pull_none>; ++ }; ++ }; ++ ++ sdio1 { ++ /omit-if-no-ref/ ++ sdio1_bus4: sdio1-bus4 { ++ rockchip,pins = ++ /* sdio1_d0 */ ++ <3 RK_PA6 1 &pcfg_pull_up_drv_level_2>, ++ /* sdio1_d1 */ ++ <3 RK_PA7 1 &pcfg_pull_up_drv_level_2>, ++ /* sdio1_d2 */ ++ <3 RK_PB0 1 &pcfg_pull_up_drv_level_2>, ++ /* sdio1_d3 */ ++ <3 RK_PB1 1 &pcfg_pull_up_drv_level_2>; ++ }; ++ ++ /omit-if-no-ref/ ++ sdio1_clk: sdio1-clk { ++ rockchip,pins = ++ /* sdio1_clk */ ++ <3 RK_PA4 1 &pcfg_pull_up_drv_level_2>; ++ }; ++ ++ /omit-if-no-ref/ ++ sdio1_cmd: sdio1-cmd { ++ rockchip,pins = ++ /* sdio1_cmd */ ++ <3 RK_PA5 1 &pcfg_pull_up_drv_level_2>; ++ }; ++ ++ /omit-if-no-ref/ ++ sdio1_det: sdio1-det { ++ rockchip,pins = ++ /* sdio1_det */ ++ <3 RK_PB3 1 &pcfg_pull_up>; ++ }; ++ ++ /omit-if-no-ref/ ++ sdio1_pwren: sdio1-pwren { ++ rockchip,pins = ++ /* sdio1_pwren */ ++ <3 RK_PB2 1 &pcfg_pull_none>; ++ }; ++ }; ++ ++ sdmmc { ++ /omit-if-no-ref/ ++ sdmmc_bus4: sdmmc-bus4 { ++ rockchip,pins = ++ /* sdmmc_d0 */ ++ <2 RK_PA0 1 &pcfg_pull_up_drv_level_2>, ++ /* sdmmc_d1 */ ++ <2 RK_PA1 1 &pcfg_pull_up_drv_level_2>, ++ /* sdmmc_d2 */ ++ <2 RK_PA2 1 &pcfg_pull_up_drv_level_2>, ++ /* sdmmc_d3 */ ++ <2 RK_PA3 1 &pcfg_pull_up_drv_level_2>; ++ }; ++ ++ /omit-if-no-ref/ ++ sdmmc_clk: sdmmc-clk { ++ rockchip,pins = ++ /* sdmmc_clk */ ++ <2 RK_PA5 1 &pcfg_pull_up_drv_level_2>; ++ }; ++ ++ /omit-if-no-ref/ ++ sdmmc_cmd: sdmmc-cmd { ++ rockchip,pins = ++ /* sdmmc_cmd */ ++ <2 RK_PA4 1 &pcfg_pull_up_drv_level_2>; ++ }; ++ ++ /omit-if-no-ref/ ++ sdmmc_det: sdmmc-det { ++ rockchip,pins = ++ /* sdmmc_detn */ ++ <2 RK_PA6 1 &pcfg_pull_up>; ++ }; ++ ++ /omit-if-no-ref/ ++ sdmmc_pwren: sdmmc-pwren { ++ rockchip,pins = ++ /* sdmmc_pwren */ ++ <4 RK_PA1 1 &pcfg_pull_none>; ++ }; ++ }; ++ ++ spdif { ++ /omit-if-no-ref/ ++ spdifm0_pins: spdifm0-pins { ++ rockchip,pins = ++ /* spdif_tx_m0 */ ++ <4 RK_PA0 1 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ spdifm1_pins: spdifm1-pins { ++ rockchip,pins = ++ /* spdif_tx_m1 */ ++ <1 RK_PC3 2 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ spdifm2_pins: spdifm2-pins { ++ rockchip,pins = ++ /* spdif_tx_m2 */ ++ <3 RK_PC3 2 &pcfg_pull_none>; ++ }; ++ }; ++ ++ spi0 { ++ /omit-if-no-ref/ ++ spi0_pins: spi0-pins { ++ rockchip,pins = ++ /* spi0_clk */ ++ <4 RK_PB4 2 &pcfg_pull_none_drv_level_2>, ++ /* spi0_miso */ ++ <4 RK_PB3 2 &pcfg_pull_none_drv_level_2>, ++ /* spi0_mosi */ ++ <4 RK_PB2 2 &pcfg_pull_none_drv_level_2>; ++ }; ++ ++ /omit-if-no-ref/ ++ spi0_csn0: spi0-csn0 { ++ rockchip,pins = ++ /* spi0_csn0 */ ++ <4 RK_PB6 2 &pcfg_pull_none_drv_level_2>; ++ }; ++ /omit-if-no-ref/ ++ spi0_csn1: spi0-csn1 { ++ rockchip,pins = ++ /* spi0_csn1 */ ++ <4 RK_PC1 2 &pcfg_pull_none_drv_level_2>; ++ }; ++ }; ++ ++ spi1 { ++ /omit-if-no-ref/ ++ spi1_pins: spi1-pins { ++ rockchip,pins = ++ /* spi1_clk */ ++ <1 RK_PB6 2 &pcfg_pull_none_drv_level_2>, ++ /* spi1_miso */ ++ <1 RK_PC0 2 &pcfg_pull_none_drv_level_2>, ++ /* spi1_mosi */ ++ <1 RK_PB7 2 &pcfg_pull_none_drv_level_2>; ++ }; ++ ++ /omit-if-no-ref/ ++ spi1_csn0: spi1-csn0 { ++ rockchip,pins = ++ /* spi1_csn0 */ ++ <1 RK_PC1 1 &pcfg_pull_none_drv_level_2>; ++ }; ++ /omit-if-no-ref/ ++ spi1_csn1: spi1-csn1 { ++ rockchip,pins = ++ /* spi1_csn1 */ ++ <1 RK_PC2 1 &pcfg_pull_none_drv_level_2>; ++ }; ++ }; ++ ++ tsi0 { ++ /omit-if-no-ref/ ++ tsi0_pins: tsi0-pins { ++ rockchip,pins = ++ /* tsi0_clkin */ ++ <3 RK_PB2 3 &pcfg_pull_none>, ++ /* tsi0_d0 */ ++ <3 RK_PB1 3 &pcfg_pull_none>, ++ /* tsi0_d1 */ ++ <3 RK_PB5 3 &pcfg_pull_none>, ++ /* tsi0_d2 */ ++ <3 RK_PB6 3 &pcfg_pull_none>, ++ /* tsi0_d3 */ ++ <3 RK_PB7 3 &pcfg_pull_none>, ++ /* tsi0_d4 */ ++ <3 RK_PA3 3 &pcfg_pull_none>, ++ /* tsi0_d5 */ ++ <3 RK_PA2 3 &pcfg_pull_none>, ++ /* tsi0_d6 */ ++ <3 RK_PA1 3 &pcfg_pull_none>, ++ /* tsi0_d7 */ ++ <3 RK_PA0 3 &pcfg_pull_none>, ++ /* tsi0_fail */ ++ <3 RK_PC0 3 &pcfg_pull_none>, ++ /* tsi0_sync */ ++ <3 RK_PB4 3 &pcfg_pull_none>, ++ /* tsi0_valid */ ++ <3 RK_PB3 3 &pcfg_pull_none>; ++ }; ++ }; ++ ++ tsi1 { ++ /omit-if-no-ref/ ++ tsi1_pins: tsi1-pins { ++ rockchip,pins = ++ /* tsi1_clkin */ ++ <3 RK_PA5 3 &pcfg_pull_none>, ++ /* tsi1_d0 */ ++ <3 RK_PA4 3 &pcfg_pull_none>, ++ /* tsi1_sync */ ++ <3 RK_PA7 3 &pcfg_pull_none>, ++ /* tsi1_valid */ ++ <3 RK_PA6 3 &pcfg_pull_none>; ++ }; ++ }; ++ ++ uart0 { ++ /omit-if-no-ref/ ++ uart0m0_xfer: uart0m0-xfer { ++ rockchip,pins = ++ /* uart0_rx_m0 */ ++ <4 RK_PC7 1 &pcfg_pull_up>, ++ /* uart0_tx_m0 */ ++ <4 RK_PD0 1 &pcfg_pull_up>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart0m1_xfer: uart0m1-xfer { ++ rockchip,pins = ++ /* uart0_rx_m1 */ ++ <2 RK_PA0 2 &pcfg_pull_up>, ++ /* uart0_tx_m1 */ ++ <2 RK_PA1 2 &pcfg_pull_up>; ++ }; ++ }; ++ ++ uart1 { ++ /omit-if-no-ref/ ++ uart1m0_xfer: uart1m0-xfer { ++ rockchip,pins = ++ /* uart1_rx_m0 */ ++ <4 RK_PA7 2 &pcfg_pull_up>, ++ /* uart1_tx_m0 */ ++ <4 RK_PA6 2 &pcfg_pull_up>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart1m1_xfer: uart1m1-xfer { ++ rockchip,pins = ++ /* uart1_rx_m1 */ ++ <4 RK_PC6 2 &pcfg_pull_up>, ++ /* uart1_tx_m1 */ ++ <4 RK_PC5 2 &pcfg_pull_up>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart1_ctsn: uart1-ctsn { ++ rockchip,pins = ++ /* uart1_ctsn */ ++ <4 RK_PA4 2 &pcfg_pull_none>; ++ }; ++ /omit-if-no-ref/ ++ uart1_rtsn: uart1-rtsn { ++ rockchip,pins = ++ /* uart1_rtsn */ ++ <4 RK_PA5 2 &pcfg_pull_none>; ++ }; ++ }; ++ ++ uart2 { ++ /omit-if-no-ref/ ++ uart2m0_xfer: uart2m0-xfer { ++ rockchip,pins = ++ /* uart2_rx_m0 */ ++ <3 RK_PA0 1 &pcfg_pull_up>, ++ /* uart2_tx_m0 */ ++ <3 RK_PA1 1 &pcfg_pull_up>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart2m0_ctsn: uart2m0-ctsn { ++ rockchip,pins = ++ /* uart2m0_ctsn */ ++ <3 RK_PA3 1 &pcfg_pull_none>; ++ }; ++ /omit-if-no-ref/ ++ uart2m0_rtsn: uart2m0-rtsn { ++ rockchip,pins = ++ /* uart2m0_rtsn */ ++ <3 RK_PA2 1 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart2m1_xfer: uart2m1-xfer { ++ rockchip,pins = ++ /* uart2_rx_m1 */ ++ <1 RK_PB0 1 &pcfg_pull_up>, ++ /* uart2_tx_m1 */ ++ <1 RK_PB1 1 &pcfg_pull_up>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart2m1_ctsn: uart2m1-ctsn { ++ rockchip,pins = ++ /* uart2m1_ctsn */ ++ <1 RK_PB3 1 &pcfg_pull_none>; ++ }; ++ /omit-if-no-ref/ ++ uart2m1_rtsn: uart2m1-rtsn { ++ rockchip,pins = ++ /* uart2m1_rtsn */ ++ <1 RK_PB2 1 &pcfg_pull_none>; ++ }; ++ }; ++ ++ uart3 { ++ /omit-if-no-ref/ ++ uart3m0_xfer: uart3m0-xfer { ++ rockchip,pins = ++ /* uart3_rx_m0 */ ++ <4 RK_PB0 2 &pcfg_pull_up>, ++ /* uart3_tx_m0 */ ++ <4 RK_PB1 2 &pcfg_pull_up>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart3m1_xfer: uart3m1-xfer { ++ rockchip,pins = ++ /* uart3_rx_m1 */ ++ <4 RK_PB7 3 &pcfg_pull_up>, ++ /* uart3_tx_m1 */ ++ <4 RK_PC0 3 &pcfg_pull_up>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart3_ctsn: uart3-ctsn { ++ rockchip,pins = ++ /* uart3_ctsn */ ++ <4 RK_PA3 3 &pcfg_pull_none>; ++ }; ++ /omit-if-no-ref/ ++ uart3_rtsn: uart3-rtsn { ++ rockchip,pins = ++ /* uart3_rtsn */ ++ <4 RK_PA2 3 &pcfg_pull_none>; ++ }; ++ }; ++ ++ uart4 { ++ /omit-if-no-ref/ ++ uart4_xfer: uart4-xfer { ++ rockchip,pins = ++ /* uart4_rx */ ++ <2 RK_PA2 3 &pcfg_pull_up>, ++ /* uart4_tx */ ++ <2 RK_PA3 3 &pcfg_pull_up>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart4_ctsn: uart4-ctsn { ++ rockchip,pins = ++ /* uart4_ctsn */ ++ <2 RK_PA1 3 &pcfg_pull_none>; ++ }; ++ /omit-if-no-ref/ ++ uart4_rtsn: uart4-rtsn { ++ rockchip,pins = ++ /* uart4_rtsn */ ++ <2 RK_PA0 3 &pcfg_pull_none>; ++ }; ++ }; ++ ++ uart5 { ++ /omit-if-no-ref/ ++ uart5m0_xfer: uart5m0-xfer { ++ rockchip,pins = ++ /* uart5_rx_m0 */ ++ <1 RK_PA2 2 &pcfg_pull_up>, ++ /* uart5_tx_m0 */ ++ <1 RK_PA3 2 &pcfg_pull_up>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart5m0_ctsn: uart5m0-ctsn { ++ rockchip,pins = ++ /* uart5m0_ctsn */ ++ <1 RK_PA6 2 &pcfg_pull_none>; ++ }; ++ /omit-if-no-ref/ ++ uart5m0_rtsn: uart5m0-rtsn { ++ rockchip,pins = ++ /* uart5m0_rtsn */ ++ <1 RK_PA5 2 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart5m1_xfer: uart5m1-xfer { ++ rockchip,pins = ++ /* uart5_rx_m1 */ ++ <1 RK_PD4 2 &pcfg_pull_up>, ++ /* uart5_tx_m1 */ ++ <1 RK_PD7 2 &pcfg_pull_up>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart5m1_ctsn: uart5m1-ctsn { ++ rockchip,pins = ++ /* uart5m1_ctsn */ ++ <1 RK_PD3 2 &pcfg_pull_none>; ++ }; ++ /omit-if-no-ref/ ++ uart5m1_rtsn: uart5m1-rtsn { ++ rockchip,pins = ++ /* uart5m1_rtsn */ ++ <1 RK_PD2 2 &pcfg_pull_none>; ++ }; ++ }; ++ ++ uart6 { ++ /omit-if-no-ref/ ++ uart6m0_xfer: uart6m0-xfer { ++ rockchip,pins = ++ /* uart6_rx_m0 */ ++ <3 RK_PA7 4 &pcfg_pull_up>, ++ /* uart6_tx_m0 */ ++ <3 RK_PA6 4 &pcfg_pull_up>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart6m1_xfer: uart6m1-xfer { ++ rockchip,pins = ++ /* uart6_rx_m1 */ ++ <3 RK_PC3 4 &pcfg_pull_up>, ++ /* uart6_tx_m1 */ ++ <3 RK_PC1 4 &pcfg_pull_up>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart6_ctsn: uart6-ctsn { ++ rockchip,pins = ++ /* uart6_ctsn */ ++ <3 RK_PA4 4 &pcfg_pull_none>; ++ }; ++ /omit-if-no-ref/ ++ uart6_rtsn: uart6-rtsn { ++ rockchip,pins = ++ /* uart6_rtsn */ ++ <3 RK_PA5 4 &pcfg_pull_none>; ++ }; ++ }; ++ ++ uart7 { ++ /omit-if-no-ref/ ++ uart7m0_xfer: uart7m0-xfer { ++ rockchip,pins = ++ /* uart7_rx_m0 */ ++ <3 RK_PB3 4 &pcfg_pull_up>, ++ /* uart7_tx_m0 */ ++ <3 RK_PB2 4 &pcfg_pull_up>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart7m0_ctsn: uart7m0-ctsn { ++ rockchip,pins = ++ /* uart7m0_ctsn */ ++ <3 RK_PB0 4 &pcfg_pull_none>; ++ }; ++ /omit-if-no-ref/ ++ uart7m0_rtsn: uart7m0-rtsn { ++ rockchip,pins = ++ /* uart7m0_rtsn */ ++ <3 RK_PB1 4 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart7m1_xfer: uart7m1-xfer { ++ rockchip,pins = ++ /* uart7_rx_m1 */ ++ <1 RK_PB3 4 &pcfg_pull_up>, ++ /* uart7_tx_m1 */ ++ <1 RK_PB2 4 &pcfg_pull_up>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart7m1_ctsn: uart7m1-ctsn { ++ rockchip,pins = ++ /* uart7m1_ctsn */ ++ <1 RK_PB0 4 &pcfg_pull_none>; ++ }; ++ /omit-if-no-ref/ ++ uart7m1_rtsn: uart7m1-rtsn { ++ rockchip,pins = ++ /* uart7m1_rtsn */ ++ <1 RK_PB1 4 &pcfg_pull_none>; ++ }; ++ }; ++}; diff --git a/lede/package/boot/uboot-rockchip/patches/412-arm-dts-rockchip-Add-rk3528-u-boot.dtsi.patch b/lede/package/boot/uboot-rockchip/patches/412-arm-dts-rockchip-Add-rk3528-u-boot.dtsi.patch new file mode 100644 index 0000000000..6572b9f217 --- /dev/null +++ b/lede/package/boot/uboot-rockchip/patches/412-arm-dts-rockchip-Add-rk3528-u-boot.dtsi.patch @@ -0,0 +1,371 @@ +From efd80d2ddee68e1f070396c67a7f76426d065017 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Thu, 23 Jan 2025 22:48:23 +0000 +Subject: [PATCH 2/4] arm: dts: rockchip: Add rk3528-u-boot.dtsi + +Add a rk3528-u-boot.dtsi extending the basic dts/upstream rk3528.dtsi +with bare minimum nodes to have a booting system from eMMC and SD-card. + +Signed-off-by: Jonas Karlman +--- + arch/arm/dts/rk3528-u-boot.dtsi | 354 ++++++++++++++++++++++++++++++++ + 1 file changed, 354 insertions(+) + create mode 100644 arch/arm/dts/rk3528-u-boot.dtsi + +--- /dev/null ++++ b/arch/arm/dts/rk3528-u-boot.dtsi +@@ -0,0 +1,354 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++ ++#include ++#include ++#include "rockchip-u-boot.dtsi" ++ ++/ { ++ aliases { ++ gpio0 = &gpio0; ++ gpio1 = &gpio1; ++ gpio2 = &gpio2; ++ gpio3 = &gpio3; ++ gpio4 = &gpio4; ++ mmc0 = &sdhci; ++ mmc1 = &sdmmc; ++ }; ++ ++ chosen { ++ u-boot,spl-boot-order = "same-as-spl", &sdmmc, &sdhci; ++ }; ++ ++ dmc { ++ compatible = "rockchip,rk3528-dmc"; ++ bootph-all; ++ }; ++ ++ soc { ++ usb_host0_ehci: usb@ff100000 { ++ compatible = "rockchip,rk3528-ehci", "generic-ehci"; ++ reg = <0x0 0xff100000 0x0 0x40000>; ++ interrupts = ; ++ clocks = <&cru HCLK_USBHOST>, <&cru HCLK_USBHOST_ARB>, ++ <&u2phy>; ++ phys = <&u2phy_host>; ++ phy-names = "usb"; ++ status = "disabled"; ++ }; ++ ++ usb_host0_ohci: usb@ff140000 { ++ compatible = "rockchip,rk3528-ohci", "generic-ohci"; ++ reg = <0x0 0xff140000 0x0 0x40000>; ++ interrupts = ; ++ clocks = <&cru HCLK_USBHOST>, <&cru HCLK_USBHOST_ARB>, ++ <&u2phy>; ++ phys = <&u2phy_host>; ++ phy-names = "usb"; ++ status = "disabled"; ++ }; ++ ++ grf: syscon@ff300000 { ++ compatible = "rockchip,rk3528-grf", ++ "syscon", "simple-mfd"; ++ reg = <0x0 0xff300000 0x0 0x90000>; ++ }; ++ ++ cru: clock-controller@ff4a0000 { ++ compatible = "rockchip,rk3528-cru"; ++ reg = <0x0 0xff4a0000 0x0 0x30000>; ++ #clock-cells = <1>; ++ #reset-cells = <1>; ++ }; ++ ++ ioc_grf: syscon@ff540000 { ++ compatible = "rockchip,rk3528-ioc-grf", "syscon"; ++ reg = <0x0 0xff540000 0x0 0x40000>; ++ }; ++ ++ saradc: adc@ffae0000 { ++ compatible = "rockchip,rk3528-saradc"; ++ reg = <0x0 0xffae0000 0x0 0x10000>; ++ interrupts = ; ++ #io-channel-cells = <1>; ++ clocks = <&cru CLK_SARADC>, <&cru PCLK_SARADC>; ++ clock-names = "saradc", "apb_pclk"; ++ resets = <&cru SRST_PRESETN_SARADC>; ++ reset-names = "saradc-apb"; ++ status = "disabled"; ++ }; ++ ++ gmac1: ethernet@ffbe0000 { ++ compatible = "rockchip,rk3528-gmac", "snps,dwmac-4.20a"; ++ reg = <0x0 0xffbe0000 0x0 0x10000>; ++ interrupts = , ++ ; ++ interrupt-names = "macirq", "eth_wake_irq"; ++ clocks = <&cru CLK_GMAC1_SRC_VPU>, <&cru CLK_GMAC1_RMII_VPU>, ++ <&cru PCLK_MAC_VPU>, <&cru ACLK_MAC_VPU>; ++ clock-names = "stmmaceth", "clk_mac_ref", ++ "pclk_mac", "aclk_mac"; ++ resets = <&cru SRST_ARESETN_MAC>; ++ reset-names = "stmmaceth"; ++ rockchip,grf = <&grf>; ++ snps,axi-config = <&gmac1_stmmac_axi_setup>; ++ snps,mixed-burst; ++ snps,mtl-rx-config = <&gmac1_mtl_rx_setup>; ++ snps,mtl-tx-config = <&gmac1_mtl_tx_setup>; ++ snps,tso; ++ status = "disabled"; ++ ++ mdio1: mdio { ++ compatible = "snps,dwmac-mdio"; ++ #address-cells = <0x1>; ++ #size-cells = <0x0>; ++ }; ++ ++ gmac1_stmmac_axi_setup: stmmac-axi-config { ++ snps,blen = <0 0 0 0 16 8 4>; ++ snps,rd_osr_lmt = <8>; ++ snps,wr_osr_lmt = <4>; ++ }; ++ ++ gmac1_mtl_rx_setup: rx-queues-config { ++ snps,rx-queues-to-use = <1>; ++ queue0 {}; ++ }; ++ ++ gmac1_mtl_tx_setup: tx-queues-config { ++ snps,tx-queues-to-use = <1>; ++ queue0 {}; ++ }; ++ }; ++ ++ sdhci: mmc@ffbf0000 { ++ compatible = "rockchip,rk3528-dwcmshc"; ++ reg = <0x0 0xffbf0000 0x0 0x10000>; ++ interrupts = ; ++ clocks = <&cru CCLK_SRC_EMMC>, <&cru HCLK_EMMC>, ++ <&cru ACLK_EMMC>, <&cru BCLK_EMMC>, ++ <&cru TCLK_EMMC>; ++ clock-names = "core", "bus", "axi", "block", "timer"; ++ max-frequency = <200000000>; ++ status = "disabled"; ++ }; ++ ++ sdmmc: mmc@ffc30000 { ++ compatible = "rockchip,rk3528-dw-mshc", ++ "rockchip,rk3288-dw-mshc"; ++ reg = <0x0 0xffc30000 0x0 0x4000>; ++ interrupts = ; ++ max-frequency = <150000000>; ++ clocks = <&cru HCLK_SDMMC0>, <&cru CCLK_SRC_SDMMC0>; ++ clock-names = "biu", "ciu"; ++ fifo-depth = <0x100>; ++ status = "disabled"; ++ }; ++ ++ rng: rng@ffc50000 { ++ compatible = "rockchip,rkrng"; ++ reg = <0x0 0xffc50000 0x0 0x200>; ++ }; ++ ++ otp: otp@ffce0000 { ++ compatible = "rockchip,rk3528-otp", ++ "rockchip,rk3568-otp"; ++ reg = <0x0 0xffce0000 0x0 0x4000>; ++ }; ++ ++ u2phy: usb2phy@ffdf0000 { ++ compatible = "rockchip,rk3528-usb2phy"; ++ reg = <0x0 0xffdf0000 0x0 0x10000>; ++ clocks = <&cru CLK_REF_USBPHY>, <&cru PCLK_USBPHY>; ++ clock-names = "phyclk", "apb_pclk"; ++ #clock-cells = <0>; ++ rockchip,usbgrf = <&grf>; ++ status = "disabled"; ++ ++ u2phy_otg: otg-port { ++ interrupts = , ++ , ++ ; ++ interrupt-names = "otg-bvalid", "otg-id", ++ "linestate"; ++ #phy-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ u2phy_host: host-port { ++ interrupts = ; ++ interrupt-names = "linestate"; ++ #phy-cells = <0>; ++ status = "disabled"; ++ }; ++ }; ++ ++ pinctrl: pinctrl { ++ compatible = "rockchip,rk3528-pinctrl"; ++ rockchip,grf = <&ioc_grf>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ gpio0: gpio@ff610000 { ++ compatible = "rockchip,gpio-bank"; ++ reg = <0x0 0xff610000 0x0 0x200>; ++ clocks = <&cru PCLK_GPIO0>, <&cru DBCLK_GPIO0>; ++ interrupts = ; ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&pinctrl 0 0 32>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio1: gpio@ffaf0000 { ++ compatible = "rockchip,gpio-bank"; ++ reg = <0x0 0xffaf0000 0x0 0x200>; ++ clocks = <&cru PCLK_GPIO1>, <&cru DBCLK_GPIO1>; ++ interrupts = ; ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&pinctrl 0 32 32>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio2: gpio@ffb00000 { ++ compatible = "rockchip,gpio-bank"; ++ reg = <0x0 0xffb00000 0x0 0x200>; ++ clocks = <&cru PCLK_GPIO2>, <&cru DBCLK_GPIO2>; ++ interrupts = ; ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&pinctrl 0 64 32>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio3: gpio@ffb10000 { ++ compatible = "rockchip,gpio-bank"; ++ reg = <0x0 0xffb10000 0x0 0x200>; ++ clocks = <&cru PCLK_GPIO3>, <&cru DBCLK_GPIO3>; ++ interrupts = ; ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&pinctrl 0 96 32>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio4: gpio@ffb20000 { ++ compatible = "rockchip,gpio-bank"; ++ reg = <0x0 0xffb20000 0x0 0x200>; ++ clocks = <&cru PCLK_GPIO4>, <&cru DBCLK_GPIO4>; ++ interrupts = ; ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&pinctrl 0 128 32>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ }; ++ }; ++}; ++ ++#include "rk3528-pinctrl.dtsi" ++ ++&cru { ++ bootph-all; ++}; ++ ++&emmc_bus8 { ++ bootph-pre-ram; ++ bootph-some-ram; ++}; ++ ++&emmc_clk { ++ bootph-pre-ram; ++ bootph-some-ram; ++}; ++ ++&emmc_cmd { ++ bootph-pre-ram; ++ bootph-some-ram; ++}; ++ ++&emmc_strb { ++ bootph-pre-ram; ++ bootph-some-ram; ++}; ++ ++&grf { ++ bootph-all; ++}; ++ ++&ioc_grf { ++ bootph-all; ++}; ++ ++&otp { ++ bootph-some-ram; ++}; ++ ++&pcfg_pull_none { ++ bootph-all; ++}; ++ ++&pcfg_pull_up { ++ bootph-all; ++}; ++ ++&pcfg_pull_up_drv_level_2 { ++ bootph-pre-ram; ++ bootph-some-ram; ++}; ++ ++&pinctrl { ++ bootph-all; ++}; ++ ++&sdhci { ++ bootph-pre-ram; ++ bootph-some-ram; ++ u-boot,spl-fifo-mode; ++}; ++ ++&sdmmc { ++ bootph-pre-ram; ++ bootph-some-ram; ++ u-boot,spl-fifo-mode; ++}; ++ ++&sdmmc_bus4 { ++ bootph-pre-ram; ++ bootph-some-ram; ++}; ++ ++&sdmmc_clk { ++ bootph-pre-ram; ++ bootph-some-ram; ++}; ++ ++&sdmmc_cmd { ++ bootph-pre-ram; ++ bootph-some-ram; ++}; ++ ++&sdmmc_det { ++ bootph-pre-ram; ++ bootph-some-ram; ++}; ++ ++&uart0 { ++ bootph-all; ++ clock-frequency = <24000000>; ++}; ++ ++&uart0m0_xfer { ++ bootph-pre-sram; ++ bootph-pre-ram; ++}; ++ ++&xin24m { ++ bootph-all; ++}; diff --git a/lede/package/boot/uboot-rockchip/patches/413-board-rockchip-Add-minimal-generic-RK3528-board.patch b/lede/package/boot/uboot-rockchip/patches/413-board-rockchip-Add-minimal-generic-RK3528-board.patch new file mode 100644 index 0000000000..041e1ec17b --- /dev/null +++ b/lede/package/boot/uboot-rockchip/patches/413-board-rockchip-Add-minimal-generic-RK3528-board.patch @@ -0,0 +1,159 @@ +From e7f5a4ae16f02ddaf2acf59b07e684c95338937d Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Thu, 23 Jan 2025 22:48:24 +0000 +Subject: [PATCH 3/4] board: rockchip: Add minimal generic RK3528 board + +Add a minimal generic RK3528 board that only have eMMC and SDMMC +enabled. This defconfig can be used to boot from eMMC or SD-card on most +RK3528 boards that follow reference board design. + +Signed-off-by: Jonas Karlman +--- + arch/arm/dts/rk3528-generic-u-boot.dtsi | 31 +++++++++++++++++ + arch/arm/dts/rk3528-generic.dts | 20 +++++++++++ + arch/arm/mach-rockchip/rk3528/MAINTAINERS | 5 +++ + configs/generic-rk3528_defconfig | 41 +++++++++++++++++++++++ + doc/board/rockchip/rockchip.rst | 12 +++++++ + 5 files changed, 109 insertions(+) + create mode 100644 arch/arm/dts/rk3528-generic-u-boot.dtsi + create mode 100644 arch/arm/dts/rk3528-generic.dts + create mode 100644 arch/arm/mach-rockchip/rk3528/MAINTAINERS + create mode 100644 configs/generic-rk3528_defconfig + +--- /dev/null ++++ b/arch/arm/dts/rk3528-generic-u-boot.dtsi +@@ -0,0 +1,31 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++ ++#include "rk3528-u-boot.dtsi" ++ ++&sdhci { ++ bus-width = <8>; ++ cap-mmc-highspeed; ++ mmc-hs200-1_8v; ++ no-sd; ++ no-sdio; ++ non-removable; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&emmc_bus8>, <&emmc_clk>, <&emmc_cmd>, <&emmc_strb>; ++ status = "okay"; ++}; ++ ++&sdmmc { ++ bus-width = <4>; ++ cap-sd-highspeed; ++ disable-wp; ++ no-mmc; ++ no-sdio; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdmmc_bus4>, <&sdmmc_clk>, <&sdmmc_cmd>, <&sdmmc_det>; ++ status = "okay"; ++}; ++ ++&uart0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart0m0_xfer>; ++}; +--- /dev/null ++++ b/arch/arm/dts/rk3528-generic.dts +@@ -0,0 +1,20 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Minimal generic DT for RK3528 with eMMC and SD-card enabled ++ */ ++ ++/dts-v1/; ++#include "rk3528.dtsi" ++ ++/ { ++ model = "Generic RK3528"; ++ compatible = "rockchip,rk3528"; ++ ++ chosen { ++ stdout-path = "serial0:1500000n8"; ++ }; ++}; ++ ++&uart0 { ++ status = "okay"; ++}; +--- /dev/null ++++ b/arch/arm/mach-rockchip/rk3528/MAINTAINERS +@@ -0,0 +1,5 @@ ++GENERIC-RK3528 ++M: Jonas Karlman ++S: Maintained ++F: arch/arm/dts/rk3528-generic* ++F: configs/generic-rk3528_defconfig +--- /dev/null ++++ b/configs/generic-rk3528_defconfig +@@ -0,0 +1,41 @@ ++CONFIG_ARM=y ++CONFIG_SKIP_LOWLEVEL_INIT=y ++CONFIG_COUNTER_FREQUENCY=24000000 ++CONFIG_ARCH_ROCKCHIP=y ++CONFIG_DEFAULT_DEVICE_TREE="rk3528-generic" ++CONFIG_ROCKCHIP_RK3528=y ++CONFIG_SYS_LOAD_ADDR=0xc00800 ++CONFIG_DEBUG_UART_BASE=0xFF9F0000 ++CONFIG_DEBUG_UART_CLOCK=24000000 ++CONFIG_DEBUG_UART=y ++# CONFIG_BOOTMETH_VBE is not set ++CONFIG_DEFAULT_FDT_FILE="rockchip/rk3528-generic.dtb" ++# CONFIG_DISPLAY_CPUINFO is not set ++CONFIG_SPL_MAX_SIZE=0x40000 ++CONFIG_SPL_PAD_TO=0x7f8000 ++# CONFIG_SPL_RAW_IMAGE_SUPPORT is not set ++CONFIG_CMD_MEMINFO=y ++CONFIG_CMD_MEMINFO_MAP=y ++CONFIG_CMD_GPIO=y ++CONFIG_CMD_GPT=y ++CONFIG_CMD_MISC=y ++CONFIG_CMD_MMC=y ++# CONFIG_CMD_SETEXPR is not set ++CONFIG_CMD_RNG=y ++# CONFIG_SPL_DOS_PARTITION is not set ++# CONFIG_OF_UPSTREAM is not set ++CONFIG_OF_SPL_REMOVE_PROPS="clock-names interrupt-parent assigned-clocks assigned-clock-rates assigned-clock-parents" ++CONFIG_NO_NET=y ++# CONFIG_ADC is not set ++CONFIG_ROCKCHIP_GPIO=y ++CONFIG_SUPPORT_EMMC_RPMB=y ++CONFIG_MMC_DW=y ++CONFIG_MMC_DW_ROCKCHIP=y ++CONFIG_MMC_SDHCI=y ++CONFIG_MMC_SDHCI_SDMA=y ++CONFIG_MMC_SDHCI_ROCKCHIP=y ++CONFIG_BAUDRATE=1500000 ++CONFIG_DEBUG_UART_SHIFT=2 ++CONFIG_SYS_NS16550_MEM32=y ++CONFIG_SYSRESET_PSCI=y ++CONFIG_ERRNO_STR=y +--- a/doc/board/rockchip/rockchip.rst ++++ b/doc/board/rockchip/rockchip.rst +@@ -97,6 +97,9 @@ List of mainline supported Rockchip boar + - Rockchip Evb-RK3399 (evb_rk3399) + - Theobroma Systems RK3399-Q7 SoM - Puma (puma_rk3399) + ++* rk3528 ++ - Generic RK3528 (generic-rk3528) ++ + * rk3566 + - Anbernic RGxx3 (anbernic-rgxx3-rk3566) + - Hardkernel ODROID-M1S (odroid-m1s-rk3566) +@@ -255,6 +258,15 @@ To build rk3399 boards: + make evb-rk3399_defconfig + make CROSS_COMPILE=aarch64-linux-gnu- + ++To build rk3528 boards: ++ ++.. code-block:: bash ++ ++ export BL31=../rkbin/bin/rk35/rk3528_bl31_v1.18.elf ++ export ROCKCHIP_TPL=../rkbin/bin/rk35/rk3528_ddr_1056MHz_v1.10.bin ++ make generic-rk3528_defconfig ++ make CROSS_COMPILE=aarch64-linux-gnu- ++ + To build rk3568 boards: + + .. code-block:: bash diff --git a/lede/package/boot/uboot-rockchip/patches/414-board-rockchip-Add-Radxa-E20C.patch b/lede/package/boot/uboot-rockchip/patches/414-board-rockchip-Add-Radxa-E20C.patch new file mode 100644 index 0000000000..16a81336a9 --- /dev/null +++ b/lede/package/boot/uboot-rockchip/patches/414-board-rockchip-Add-Radxa-E20C.patch @@ -0,0 +1,199 @@ +From 66014f06f4b1d0c39e79fdd45201962913ec27a2 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Thu, 23 Jan 2025 22:48:25 +0000 +Subject: [PATCH 4/4] board: rockchip: Add Radxa E20C + +The Radxa E20C is an ultra-compact network computer with a RK3528A SoC +that offers a wide range of networking capabilities. + +Features tested on a Radxa E20C v1.104: +- SD-card boot +- eMMC boot +- Ethernet +- USB host + +Signed-off-by: Jonas Karlman +--- + arch/arm/dts/rk3528-radxa-e20c-u-boot.dtsi | 93 ++++++++++++++++++++++ + arch/arm/mach-rockchip/rk3528/MAINTAINERS | 6 ++ + configs/radxa-e20c-rk3528_defconfig | 54 +++++++++++++ + doc/board/rockchip/rockchip.rst | 1 + + 4 files changed, 154 insertions(+) + create mode 100644 arch/arm/dts/rk3528-radxa-e20c-u-boot.dtsi + create mode 100644 configs/radxa-e20c-rk3528_defconfig + +--- /dev/null ++++ b/arch/arm/dts/rk3528-radxa-e20c-u-boot.dtsi +@@ -0,0 +1,93 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++ ++#include "rk3528-u-boot.dtsi" ++ ++/ { ++ aliases { ++ ethernet0 = &gmac1; ++ }; ++ ++ vcc_1v8: regulator-1v8 { ++ compatible = "regulator-fixed"; ++ regulator-name = "vcc_1v8"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ }; ++ ++ vcc5v0_usb20: regulator-5v0-usb20 { ++ compatible = "regulator-fixed"; ++ enable-active-high; ++ gpios = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>; ++ regulator-name = "vcc5v0_usb20"; ++ regulator-max-microvolt = <5000000>; ++ regulator-min-microvolt = <5000000>; ++ }; ++}; ++ ++&gmac1 { ++ clock_in_out = "output"; ++ phy-handle = <&rgmii_phy>; ++ phy-mode = "rgmii-id"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&rgmii_miim>, <&rgmii_tx_bus2>, <&rgmii_rx_bus2>, ++ <&rgmii_rgmii_clk>, <&rgmii_rgmii_bus>; ++ status = "okay"; ++}; ++ ++&mdio1 { ++ rgmii_phy: ethernet-phy@1 { ++ compatible = "ethernet-phy-ieee802.3-c22"; ++ reg = <0x1>; ++ reset-assert-us = <20000>; ++ reset-deassert-us = <100000>; ++ reset-gpios = <&gpio4 RK_PC2 GPIO_ACTIVE_LOW>; ++ }; ++}; ++ ++&saradc { ++ vref-supply = <&vcc_1v8>; ++ status = "okay"; ++}; ++ ++&sdhci { ++ bus-width = <8>; ++ cap-mmc-highspeed; ++ mmc-hs200-1_8v; ++ no-sd; ++ no-sdio; ++ non-removable; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&emmc_bus8>, <&emmc_clk>, <&emmc_cmd>, <&emmc_strb>; ++ status = "okay"; ++}; ++ ++&sdmmc { ++ bus-width = <4>; ++ cap-sd-highspeed; ++ disable-wp; ++ no-mmc; ++ no-sdio; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdmmc_bus4>, <&sdmmc_clk>, <&sdmmc_cmd>, <&sdmmc_det>; ++ status = "okay"; ++}; ++ ++&u2phy { ++ status = "okay"; ++}; ++ ++&u2phy_host { ++ phy-supply = <&vcc5v0_usb20>; ++ status = "okay"; ++}; ++ ++&uart0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart0m0_xfer>; ++}; ++ ++&usb_host0_ehci { ++ status = "okay"; ++}; +--- a/arch/arm/mach-rockchip/rk3528/MAINTAINERS ++++ b/arch/arm/mach-rockchip/rk3528/MAINTAINERS +@@ -3,3 +3,9 @@ M: Jonas Karlman + S: Maintained + F: arch/arm/dts/rk3528-generic* + F: configs/generic-rk3528_defconfig ++ ++RADXA-E20C ++M: Jonas Karlman ++S: Maintained ++F: arch/arm/dts/rk3528-radxa-e20c* ++F: configs/radxa-e20c-rk3528_defconfig +--- /dev/null ++++ b/configs/radxa-e20c-rk3528_defconfig +@@ -0,0 +1,54 @@ ++CONFIG_ARM=y ++CONFIG_SKIP_LOWLEVEL_INIT=y ++CONFIG_COUNTER_FREQUENCY=24000000 ++CONFIG_ARCH_ROCKCHIP=y ++CONFIG_DEFAULT_DEVICE_TREE="rockchip/rk3528-radxa-e20c" ++CONFIG_ROCKCHIP_RK3528=y ++CONFIG_SYS_LOAD_ADDR=0xc00800 ++CONFIG_DEBUG_UART_BASE=0xFF9F0000 ++CONFIG_DEBUG_UART_CLOCK=24000000 ++CONFIG_DEBUG_UART=y ++CONFIG_DEFAULT_FDT_FILE="rockchip/rk3528-radxa-e20c.dtb" ++# CONFIG_DISPLAY_CPUINFO is not set ++CONFIG_SPL_MAX_SIZE=0x40000 ++CONFIG_SPL_PAD_TO=0x7f8000 ++# CONFIG_SPL_RAW_IMAGE_SUPPORT is not set ++CONFIG_CMD_MEMINFO=y ++CONFIG_CMD_MEMINFO_MAP=y ++CONFIG_CMD_ADC=y ++CONFIG_CMD_GPIO=y ++CONFIG_CMD_GPT=y ++CONFIG_CMD_MISC=y ++CONFIG_CMD_MMC=y ++CONFIG_CMD_USB=y ++# CONFIG_CMD_SETEXPR is not set ++CONFIG_CMD_RNG=y ++CONFIG_CMD_REGULATOR=y ++# CONFIG_SPL_DOS_PARTITION is not set ++CONFIG_OF_SPL_REMOVE_PROPS="clock-names interrupt-parent assigned-clocks assigned-clock-rates assigned-clock-parents" ++CONFIG_BUTTON=y ++CONFIG_BUTTON_ADC=y ++CONFIG_BUTTON_GPIO=y ++CONFIG_ROCKCHIP_GPIO=y ++CONFIG_LED=y ++CONFIG_LED_GPIO=y ++CONFIG_SUPPORT_EMMC_RPMB=y ++CONFIG_MMC_DW=y ++CONFIG_MMC_DW_ROCKCHIP=y ++CONFIG_MMC_SDHCI=y ++CONFIG_MMC_SDHCI_SDMA=y ++CONFIG_MMC_SDHCI_ROCKCHIP=y ++CONFIG_PHY_MOTORCOMM=y ++CONFIG_PHY_REALTEK=y ++CONFIG_DM_MDIO=y ++CONFIG_DWC_ETH_QOS=y ++CONFIG_DWC_ETH_QOS_ROCKCHIP=y ++CONFIG_PHY_ROCKCHIP_INNO_USB2=y ++CONFIG_BAUDRATE=1500000 ++CONFIG_DEBUG_UART_SHIFT=2 ++CONFIG_SYS_NS16550_MEM32=y ++CONFIG_SYSRESET_PSCI=y ++CONFIG_USB=y ++CONFIG_USB_EHCI_HCD=y ++CONFIG_USB_EHCI_GENERIC=y ++CONFIG_ERRNO_STR=y +--- a/doc/board/rockchip/rockchip.rst ++++ b/doc/board/rockchip/rockchip.rst +@@ -99,6 +99,7 @@ List of mainline supported Rockchip boar + + * rk3528 + - Generic RK3528 (generic-rk3528) ++ - Radxa E20C (radxa-e20c-rk3528) + + * rk3566 + - Anbernic RGxx3 (anbernic-rgxx3-rk3566) diff --git a/lede/target/linux/rockchip/armv8/config-6.1 b/lede/target/linux/rockchip/armv8/config-6.1 index d7d94469d3..b1fe9741a1 100644 --- a/lede/target/linux/rockchip/armv8/config-6.1 +++ b/lede/target/linux/rockchip/armv8/config-6.1 @@ -561,7 +561,6 @@ CONFIG_SCSI_SAS_LIBSAS=y # CONFIG_SECURITY_DMESG_RESTRICT is not set # CONFIG_SENSORS_ARM_SCMI is not set CONFIG_SENSORS_ARM_SCPI=y -CONFIG_SENSORS_PWM_FAN=y CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y CONFIG_SERIAL_8250_DW=y CONFIG_SERIAL_8250_DWLIB=y diff --git a/lede/target/linux/rockchip/armv8/config-6.12 b/lede/target/linux/rockchip/armv8/config-6.12 index e805119ed4..3bde696e3a 100644 --- a/lede/target/linux/rockchip/armv8/config-6.12 +++ b/lede/target/linux/rockchip/armv8/config-6.12 @@ -625,7 +625,6 @@ CONFIG_SCSI_SAS_LIBSAS=y # CONFIG_SECURITY_DMESG_RESTRICT is not set # CONFIG_SENSORS_ARM_SCMI is not set CONFIG_SENSORS_ARM_SCPI=y -CONFIG_SENSORS_PWM_FAN=y CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y CONFIG_SERIAL_8250_DW=y CONFIG_SERIAL_8250_DWLIB=y diff --git a/lede/target/linux/rockchip/armv8/config-6.6 b/lede/target/linux/rockchip/armv8/config-6.6 index b1e8c5018c..9ad6720007 100644 --- a/lede/target/linux/rockchip/armv8/config-6.6 +++ b/lede/target/linux/rockchip/armv8/config-6.6 @@ -605,7 +605,6 @@ CONFIG_SCSI_SAS_LIBSAS=y # CONFIG_SECURITY_DMESG_RESTRICT is not set # CONFIG_SENSORS_ARM_SCMI is not set CONFIG_SENSORS_ARM_SCPI=y -CONFIG_SENSORS_PWM_FAN=y CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y CONFIG_SERIAL_8250_DW=y CONFIG_SERIAL_8250_DWLIB=y diff --git a/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3528-mangopi-m28.dtsi b/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3528-mangopi-m28.dtsi index 0d9067945d..30cce07c35 100644 --- a/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3528-mangopi-m28.dtsi +++ b/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3528-mangopi-m28.dtsi @@ -19,13 +19,6 @@ stdout-path = "serial0:1500000n8"; }; - ir-receiver { - compatible = "gpio-ir-receiver"; - gpios = <&gpio4 RK_PC6 GPIO_ACTIVE_LOW>; - pinctrl-names = "default"; - pinctrl-0 = <&ir_int_pin>; - }; - sdio_pwrseq: sdio-pwrseq { compatible = "mmc-pwrseq-simple"; pinctrl-names = "default"; @@ -181,12 +174,6 @@ }; &pinctrl { - ir { - ir_int_pin: ir-int-pin { - rockchip,pins = <4 RK_PC6 RK_FUNC_GPIO &pcfg_pull_up>; - }; - }; - leds { lan_led_en: lan-led-en { rockchip,pins = <4 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; diff --git a/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3528-mangopi-m28c.dts b/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3528-mangopi-m28c.dts index 1be2ad51b7..9ee3d51e89 100644 --- a/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3528-mangopi-m28c.dts +++ b/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3528-mangopi-m28c.dts @@ -57,6 +57,10 @@ }; }; +&pwm3 { + status = "okay"; +}; + &sdhci { status = "disabled"; }; diff --git a/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3528-mangopi-m28k-pro.dts b/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3528-mangopi-m28k-pro.dts index e55b7713da..afde17eb80 100644 --- a/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3528-mangopi-m28k-pro.dts +++ b/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3528-mangopi-m28k-pro.dts @@ -16,12 +16,19 @@ led-upgrade = &led_work; }; - i2c { + i2c-gpio { compatible = "i2c-gpio"; scl-gpios = <&gpio4 RK_PA6 GPIO_ACTIVE_HIGH>; sda-gpios = <&gpio4 RK_PA7 GPIO_ACTIVE_HIGH>; }; + ir-receiver { + compatible = "gpio-ir-receiver"; + gpios = <&gpio4 RK_PC6 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&ir_int_pin>; + }; + leds { compatible = "gpio-leds"; pinctrl-names = "default"; @@ -63,6 +70,14 @@ }; }; +&pinctrl { + ir { + ir_int_pin: ir-int-pin { + rockchip,pins = <4 RK_PC6 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; +}; + &usb_host0_xhci { maximum-speed = "high-speed"; phys = <&usb2phy0_otg>; diff --git a/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3528-mangopi-m28k.dts b/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3528-mangopi-m28k.dts index fcf7db34ee..c8be0edac8 100644 --- a/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3528-mangopi-m28k.dts +++ b/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3528-mangopi-m28k.dts @@ -16,6 +16,13 @@ led-upgrade = &led_work; }; + ir-receiver { + compatible = "gpio-ir-receiver"; + gpios = <&gpio4 RK_PC6 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&ir_int_pin>; + }; + leds { compatible = "gpio-leds"; pinctrl-names = "default"; @@ -64,6 +71,12 @@ }; &pinctrl { + ir { + ir_int_pin: ir-int-pin { + rockchip,pins = <4 RK_PC6 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + pcie { rtl8111_isolate: rtl8111-isolate { rockchip,pins = <4 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>; diff --git a/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3528-opc-h29k.dts b/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3528-opc-h29k.dts index 8edb852c1b..839f68c420 100644 --- a/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3528-opc-h29k.dts +++ b/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3528-opc-h29k.dts @@ -65,6 +65,8 @@ compatible = "mmc-pwrseq-simple"; pinctrl-names = "default"; pinctrl-0 = <&wifi_reg_on>; + post-power-on-delay-ms = <100>; + power-off-delay-us = <5000000>; reset-gpios = <&gpio1 RK_PA6 GPIO_ACTIVE_LOW>; }; @@ -327,7 +329,6 @@ mmc-pwrseq = <&sdio_pwrseq>; pinctrl-names = "default"; pinctrl-0 = <&sdio0_bus4 &sdio0_cmd &sdio0_clk>; - post-power-on-delay-ms = <50>; non-removable; sd-uhs-sdr104; status = "okay"; diff --git a/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3528-opc-ht2.dts b/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3528-opc-ht2.dts index 3aa48b5669..d7583b8b9b 100644 --- a/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3528-opc-ht2.dts +++ b/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3528-opc-ht2.dts @@ -53,6 +53,8 @@ compatible = "mmc-pwrseq-simple"; pinctrl-names = "default"; pinctrl-0 = <&wifi_enable_h>; + post-power-on-delay-ms = <100>; + power-off-delay-us = <5000000>; reset-gpios = <&gpio1 RK_PA6 GPIO_ACTIVE_LOW>; }; @@ -226,12 +228,6 @@ rockchip,pins = <1 RK_PA7 RK_FUNC_GPIO &pcfg_pull_down>; }; }; - - bluetooth { - bt_enable_h: bt-enable-h { - rockchip,pins = <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_down>; - }; - }; }; &pwm1 { @@ -269,9 +265,8 @@ mmc-pwrseq = <&sdio_pwrseq>; pinctrl-names = "default"; pinctrl-0 = <&sdio0_bus4 &sdio0_cmd &sdio0_clk>; - post-power-on-delay-ms = <50>; non-removable; - sd-uhs-sdr104; + sd-uhs-sdr50; status = "okay"; sdio_wifi@1 { diff --git a/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3568-hinlink-opc.dtsi b/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3568-hinlink-opc.dtsi index 8859c43e39..41b580100a 100644 --- a/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3568-hinlink-opc.dtsi +++ b/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3568-hinlink-opc.dtsi @@ -128,7 +128,7 @@ vin-supply = <&vcc5v0_sys>; }; - rk809-sound { + sound { compatible = "simple-audio-card"; simple-audio-card,format = "i2s"; simple-audio-card,name = "Analog RK809"; @@ -141,13 +141,6 @@ sound-dai = <&rk809>; }; }; - - pwm-fan { - compatible = "pwm-fan"; - cooling-levels = <0 100 150 200 255>; - #cooling-cells = <2>; - pwms = <&pwm0 0 50000 0>; - }; }; &combphy0 { @@ -524,11 +517,6 @@ status = "okay"; }; -&pwm0 { - pinctrl-names = "active"; - status = "okay"; -}; - &rng { status = "okay"; }; diff --git a/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3568-mrkaio-m68s.dts b/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3568-mrkaio-m68s.dts index e0e6802fbb..d7b0cc649b 100644 --- a/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3568-mrkaio-m68s.dts +++ b/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3568-mrkaio-m68s.dts @@ -50,8 +50,6 @@ gpio = <&gpio0 RK_PB6 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&sata_pwr_en>; - regulator-always-on; - regulator-boot-on; regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; regulator-name = "vcc5v0_ahci"; @@ -106,6 +104,7 @@ rgmii_phy0: ethernet-phy@0 { compatible = "ethernet-phy-ieee802.3-c22"; reg = <0x0>; + realtek,led-data = <0x6d60>; }; }; @@ -113,6 +112,7 @@ rgmii_phy1: ethernet-phy@0 { compatible = "ethernet-phy-ieee802.3-c22"; reg = <0x0>; + realtek,led-data = <0x6d60>; }; }; diff --git a/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3568-opc-h69k.dts b/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3568-opc-h69k.dts index 2233a12561..474b250960 100644 --- a/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3568-opc-h69k.dts +++ b/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3568-opc-h69k.dts @@ -13,13 +13,19 @@ ethernet0 = &gmac1; }; + fan: pwm-fan { + compatible = "pwm-fan"; + cooling-levels = <0 100 150 200 255>; + #cooling-cells = <2>; + pwms = <&pwm0 0 50000 0>; + }; + vcc5v0_ahci: vcc5v0-ahci { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PC5 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&sata_pwr_en>; - regulator-always-on; regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; regulator-name = "vcc5v0_ahci"; @@ -27,6 +33,56 @@ }; }; +&cpu_thermal { + trips { + cpu_passive: cpu_passive { + temperature = <40000>; + hysteresis = <2000>; + type = "active"; + }; + + cpu_active: cpu_active { + temperature = <50000>; + hysteresis = <2000>; + type = "active"; + }; + + cpu_warm: cpu_warm { + temperature = <60000>; + hysteresis = <2000>; + type = "active"; + }; + + cpu_hot: cpu_hot { + temperature = <70000>; + hysteresis = <2000>; + type = "active"; + }; + }; + + cooling-maps { + map1 { + trip = <&cpu_passive>; + cooling-device = <&fan 0 1>; + }; + + map2 { + trip = <&cpu_active>; + cooling-device = <&fan 1 2>; + }; + + map3 { + trip = <&cpu_warm>; + cooling-device = <&fan 2 3>; + }; + + map4 { + trip = <&cpu_hot>; + cooling-device = <&fan 3 4>; + }; + }; +}; + &gmac1 { assigned-clocks = <&cru SCLK_GMAC1_RX_TX>, <&cru SCLK_GMAC1>; assigned-clock-parents = <&cru SCLK_GMAC1_RGMII_SPEED>; @@ -63,6 +119,10 @@ }; }; +&pwm0 { + status = "okay"; +}; + &sata0 { target-supply = <&vcc5v0_ahci>; }; diff --git a/lede/target/linux/rockchip/image/armv8.mk b/lede/target/linux/rockchip/image/armv8.mk index da7645ba24..3c34c5f379 100644 --- a/lede/target/linux/rockchip/image/armv8.mk +++ b/lede/target/linux/rockchip/image/armv8.mk @@ -26,7 +26,7 @@ define Device/armsom_sige1 DEVICE_VENDOR := ArmSoM DEVICE_MODEL := Sige1 DEVICE_DTS := rockchip/rk3528-armsom-sige1 - UBOOT_DEVICE_NAME := evb-rk3528 + UBOOT_DEVICE_NAME := generic-rk3528 IMAGE/sysupgrade.img.gz := boot-common | boot-script rk3528 | pine64-img | gzip | append-metadata DEVICE_PACKAGES := brcmfmac-firmware-43752-sdio kmod-brcmfmac kmod-r8125 wpad -urngd endef @@ -285,7 +285,7 @@ define Device/hinlink_opc-h28k DEVICE_VENDOR := HINLINK DEVICE_MODEL := OPC-H28K SOC := rk3528 - UBOOT_DEVICE_NAME := evb-rk3528 + UBOOT_DEVICE_NAME := generic-rk3528 IMAGE/sysupgrade.img.gz := boot-common | boot-script rk3528 | pine64-img | gzip | append-metadata DEVICE_PACKAGES := kmod-r8168 -urngd endef @@ -295,9 +295,9 @@ define Device/hinlink_opc-h29k DEVICE_VENDOR := HINLINK DEVICE_MODEL := OPC-H29K SOC := rk3528 - UBOOT_DEVICE_NAME := evb-rk3528 + UBOOT_DEVICE_NAME := generic-rk3528 IMAGE/sysupgrade.img.gz := boot-common | boot-script rk3528 | pine64-img | gzip | append-metadata - DEVICE_PACKAGES := kmod-aic8800 kmod-fb-tft-st7789v wpad-openssl -urngd + DEVICE_PACKAGES := kmod-aic8800s kmod-fb-tft-st7789v wpad-openssl -urngd endef TARGET_DEVICES += hinlink_opc-h29k @@ -327,9 +327,9 @@ define Device/hinlink_opc-ht2 DEVICE_VENDOR := HINLINK DEVICE_MODEL := OPC-HT2 SOC := rk3528 - UBOOT_DEVICE_NAME := evb-rk3528 + UBOOT_DEVICE_NAME := generic-rk3528 IMAGE/sysupgrade.img.gz := boot-common | boot-script rk3528 | pine64-img | gzip | append-metadata - DEVICE_PACKAGES := kmod-aic8800 wpad-openssl -urngd + DEVICE_PACKAGES := kmod-aic8800s wpad-openssl -urngd endef TARGET_DEVICES += hinlink_opc-ht2 @@ -377,7 +377,7 @@ define Device/radxa_e20c DEVICE_VENDOR := Radxa DEVICE_MODEL := E20C DEVICE_DTS := rockchip/rk3528-radxa-e20c - UBOOT_DEVICE_NAME := evb-rk3528 + UBOOT_DEVICE_NAME := radxa-e20c-rk3528 IMAGE/sysupgrade.img.gz := boot-common | boot-script rk3528 | pine64-img | gzip | append-metadata DEVICE_PACKAGES := kmod-gpio-button-hotplug kmod-r8168 -urngd endef @@ -409,7 +409,7 @@ define Device/radxa_rock-3c SOC := rk3566 UBOOT_DEVICE_NAME := rock-3c-rk3566 IMAGE/sysupgrade.img.gz := boot-common | boot-script | pine64-img | gzip | append-metadata - DEVICE_PACKAGES := kmod-aic8800 wpad-openssl + DEVICE_PACKAGES := kmod-aic8800s wpad-openssl endef TARGET_DEVICES += radxa_rock-3c @@ -563,9 +563,9 @@ TARGET_DEVICES += xunlong_orangepi-r1-plus-lts define Device/widora_mangopi-m28 DEVICE_VENDOR := Widora SOC := rk3528 - UBOOT_DEVICE_NAME := evb-rk3528 + UBOOT_DEVICE_NAME := generic-rk3528 IMAGE/sysupgrade.img.gz := boot-common | boot-script rk3528 | pine64-img | gzip | append-metadata - DEVICE_PACKAGES := kmod-aic8800 kmod-r8168 wpad-openssl -urngd + DEVICE_PACKAGES := kmod-aic8800s kmod-r8168 wpad-openssl -urngd endef define Device/widora_mangopi-m28c diff --git a/mieru/README.md b/mieru/README.md index c56e29c467..48858e69f7 100644 --- a/mieru/README.md +++ b/mieru/README.md @@ -11,12 +11,6 @@ mieru is a secure, hard to classify, hard to probe, TCP or UDP protocol-based so The mieru proxy software suite consists of two parts, a client software called mieru, and a proxy server software called mita. -## Protocol - -The principle of mieru is similar to shadowsocks / v2ray etc. It creates an encrypted channel between the client and the proxy server outside the firewall. GFW cannot decrypt the encrypted transmission and cannot determine the destination you end up visiting, so it has no choice but to let you go. - -For an explanation of the mieru protocol, see [mieru Proxy Protocol](./docs/protocol.md). - ## Features 1. Provides socks5, HTTP, and HTTPS proxy interfaces. @@ -41,6 +35,12 @@ For an explanation of the mieru protocol, see [mieru Proxy Protocol](./docs/prot 1. [Security Guide](./docs/security.md) 1. [Compilation](./docs/compile.md) +## Protocol + +The principle of mieru is similar to shadowsocks / v2ray etc. It creates an encrypted channel between the client and the proxy server outside the firewall. GFW cannot decrypt the encrypted transmission and cannot determine the destination you end up visiting, so it has no choice but to let you go. + +For an explanation of the mieru protocol, see [mieru Proxy Protocol](./docs/protocol.md). + ## Share If you think this software is helpful, please share to your friends. Thanks! diff --git a/mieru/README.zh_CN.md b/mieru/README.zh_CN.md index 3d9750fc4f..9c2b53d0d3 100644 --- a/mieru/README.zh_CN.md +++ b/mieru/README.zh_CN.md @@ -9,12 +9,6 @@ mieru【見える】是一款安全的、无流量特征、难以主动探测的 mieru 代理软件由称为 mieru【見える】的客户端软件和称为 mita【見た】的代理服务器软件这两部分组成。 -## 原理和协议 - -mieru 的翻墙原理与 shadowsocks / v2ray 等软件类似,在客户端和墙外的代理服务器之间建立一个加密的通道。GFW 不能破解加密传输的信息,无法判定你最终访问的网址,因此只能选择放行。 - -有关 mieru 协议的讲解,请参阅 [mieru 代理协议](./docs/protocol.zh_CN.md)。 - ## 特性 1. 提供 socks5, HTTP 和 HTTPS 代理接口。 @@ -39,6 +33,12 @@ mieru 的翻墙原理与 shadowsocks / v2ray 等软件类似,在客户端和 1. [翻墙安全指南](./docs/security.zh_CN.md) 1. [编译](./docs/compile.zh_CN.md) +## 原理和协议 + +mieru 的翻墙原理与 shadowsocks / v2ray 等软件类似,在客户端和墙外的代理服务器之间建立一个加密的通道。GFW 不能破解加密传输的信息,无法判定你最终访问的网址,因此只能选择放行。 + +有关 mieru 协议的讲解,请参阅 [mieru 代理协议](./docs/protocol.zh_CN.md)。 + ## 分享 如果你觉得这款软件对你有帮助,请分享给朋友们。谢谢! diff --git a/mihomo/.github/mihomo.service b/mihomo/.github/mihomo.service index f34b6a6a84..a3793fe369 100644 --- a/mihomo/.github/mihomo.service +++ b/mihomo/.github/mihomo.service @@ -1,17 +1,17 @@ [Unit] Description=mihomo Daemon, Another Clash Kernel. -After=network.target NetworkManager.service systemd-networkd.service iwd.service +Documentation=https://wiki.metacubex.one +After=network.target nss-lookup.target network-online.target [Service] Type=simple -LimitNPROC=500 -LimitNOFILE=1000000 -CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_TIME CAP_SYS_PTRACE CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE -AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_TIME CAP_SYS_PTRACE CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE -Restart=always -ExecStartPre=/usr/bin/sleep 2s +CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH +AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH ExecStart=/usr/bin/mihomo -d /etc/mihomo ExecReload=/bin/kill -HUP $MAINPID +Restart=on-failure +RestartSec=10 +LimitNOFILE=infinity [Install] -WantedBy=multi-user.target \ No newline at end of file +WantedBy=multi-user.target diff --git a/mihomo/.github/mihomo@.service b/mihomo/.github/mihomo@.service new file mode 100644 index 0000000000..a3793fe369 --- /dev/null +++ b/mihomo/.github/mihomo@.service @@ -0,0 +1,17 @@ +[Unit] +Description=mihomo Daemon, Another Clash Kernel. +Documentation=https://wiki.metacubex.one +After=network.target nss-lookup.target network-online.target + +[Service] +Type=simple +CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH +AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH +ExecStart=/usr/bin/mihomo -d /etc/mihomo +ExecReload=/bin/kill -HUP $MAINPID +Restart=on-failure +RestartSec=10 +LimitNOFILE=infinity + +[Install] +WantedBy=multi-user.target diff --git a/mihomo/.github/workflows/build.yml b/mihomo/.github/workflows/build.yml index ee1266b802..371065cf10 100644 --- a/mihomo/.github/workflows/build.yml +++ b/mihomo/.github/workflows/build.yml @@ -276,17 +276,20 @@ jobs: mkdir -p mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/DEBIAN mkdir -p mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/usr/bin - mkdir -p mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/etc/mihomo - mkdir -p mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/etc/systemd/system/ mkdir -p mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/usr/share/licenses/mihomo + mkdir -p mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/etc/mihomo + mkdir -p mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/lib/systemd/system - cp mihomo mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/usr/bin/mihomo + cp mihomo mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/usr/bin/ cp LICENSE mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/usr/share/licenses/mihomo/ - cp .github/mihomo.service mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/etc/systemd/system/ + cp .github/{mihomo.service,mihomo@.service} mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/lib/systemd/system/ cat > mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/etc/mihomo/config.yaml < mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/DEBIAN/conffiles < mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/DEBIAN/control < { color = ForegroundColorSpan((0xFF86C166).toInt()) } + line.contains("ERROR[") || line.contains(" [Error]") -> { color = ForegroundColorSpan(Color.RED) } + line.contains("WARN[") || line.contains(" [Warning]") -> { color = ForegroundColorSpan(Color.RED) } @@ -94,12 +100,14 @@ class LogcatFragment : ToolbarFragment(R.layout.layout_logcat), } } + R.id.action_send_logcat -> { val context = requireContext() runOnDefaultDispatcher { SendLog.sendLog(context, "NB4A") } } + R.id.action_refresh -> { reloadSession() } diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/MainActivity.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/MainActivity.kt index 250a2dd594..ed5dd6e094 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/MainActivity.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/MainActivity.kt @@ -4,7 +4,6 @@ import android.Manifest.permission.POST_NOTIFICATIONS import android.annotation.SuppressLint import android.content.Intent import android.content.pm.PackageManager -import android.graphics.Color import android.net.Uri import android.os.Build import android.os.Bundle @@ -15,18 +14,24 @@ import androidx.activity.addCallback import androidx.annotation.IdRes import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat -import androidx.core.view.ViewCompat import androidx.preference.PreferenceDataStore import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.navigation.NavigationView import com.google.android.material.snackbar.Snackbar -import io.nekohasekai.sagernet.* +import io.nekohasekai.sagernet.GroupType +import io.nekohasekai.sagernet.Key +import io.nekohasekai.sagernet.R +import io.nekohasekai.sagernet.SagerNet import io.nekohasekai.sagernet.aidl.ISagerNetService import io.nekohasekai.sagernet.aidl.SpeedDisplayData import io.nekohasekai.sagernet.aidl.TrafficData import io.nekohasekai.sagernet.bg.BaseService import io.nekohasekai.sagernet.bg.SagerConnection -import io.nekohasekai.sagernet.database.* +import io.nekohasekai.sagernet.database.DataStore +import io.nekohasekai.sagernet.database.GroupManager +import io.nekohasekai.sagernet.database.ProfileManager +import io.nekohasekai.sagernet.database.ProxyGroup +import io.nekohasekai.sagernet.database.SubscriptionBean import io.nekohasekai.sagernet.database.preference.OnPreferenceDataStoreChangeListener import io.nekohasekai.sagernet.databinding.LayoutMainBinding import io.nekohasekai.sagernet.fmt.AbstractBean @@ -34,8 +39,13 @@ import io.nekohasekai.sagernet.fmt.KryoConverters import io.nekohasekai.sagernet.fmt.PluginEntry import io.nekohasekai.sagernet.group.GroupInterfaceAdapter import io.nekohasekai.sagernet.group.GroupUpdater -import io.nekohasekai.sagernet.ktx.* -import io.nekohasekai.sagernet.widget.ListHolderListener +import io.nekohasekai.sagernet.ktx.alert +import io.nekohasekai.sagernet.ktx.isPlay +import io.nekohasekai.sagernet.ktx.launchCustomTab +import io.nekohasekai.sagernet.ktx.onMainDispatcher +import io.nekohasekai.sagernet.ktx.parseProxies +import io.nekohasekai.sagernet.ktx.readableMessage +import io.nekohasekai.sagernet.ktx.runOnDefaultDispatcher import moe.matsuri.nb4a.utils.Util class MainActivity : ThemedActivity(), @@ -49,10 +59,6 @@ class MainActivity : ThemedActivity(), override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - window?.apply { - statusBarColor = Color.TRANSPARENT - } - binding = LayoutMainBinding.inflate(layoutInflater) binding.fab.initProgress(binding.fabProgress) if (themeResId !in intArrayOf( @@ -86,7 +92,6 @@ class MainActivity : ThemedActivity(), binding.stats.setOnClickListener { if (DataStore.serviceState.connected) binding.stats.testConnection() } setContentView(binding.root) - ViewCompat.setOnApplyWindowInsetsListener(binding.coordinator, ListHolderListener) changeState(BaseService.State.Idle) connection.connect(this, this) DataStore.configurationStore.registerChangeListener(this) diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/RouteFragment.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/RouteFragment.kt index 312a1226af..9fcf93e4aa 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/RouteFragment.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/RouteFragment.kt @@ -18,7 +18,7 @@ import io.nekohasekai.sagernet.database.SagerDatabase import io.nekohasekai.sagernet.databinding.LayoutEmptyRouteBinding import io.nekohasekai.sagernet.databinding.LayoutRouteItemBinding import io.nekohasekai.sagernet.ktx.* -import io.nekohasekai.sagernet.widget.ListHolderListener +import io.nekohasekai.sagernet.widget.ListListener import io.nekohasekai.sagernet.widget.UndoSnackbarManager class RouteFragment : ToolbarFragment(R.layout.layout_route), Toolbar.OnMenuItemClickListener { @@ -33,7 +33,7 @@ class RouteFragment : ToolbarFragment(R.layout.layout_route), Toolbar.OnMenuItem activity = requireActivity() as MainActivity - ViewCompat.setOnApplyWindowInsetsListener(view, ListHolderListener) + ViewCompat.setOnApplyWindowInsetsListener(view, ListListener) toolbar.setTitle(R.string.menu_route) toolbar.inflateMenu(R.menu.add_route_menu) toolbar.setOnMenuItemClickListener(this) diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/ScannerActivity.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/ScannerActivity.kt index 34998aa3ba..8cda8693c2 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/ScannerActivity.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/ScannerActivity.kt @@ -26,7 +26,6 @@ import io.nekohasekai.sagernet.database.ProfileManager import io.nekohasekai.sagernet.databinding.LayoutScannerBinding import io.nekohasekai.sagernet.group.RawUpdater import io.nekohasekai.sagernet.ktx.* -import io.nekohasekai.sagernet.widget.ListHolderListener import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicInteger @@ -43,7 +42,6 @@ class ScannerActivity : ThemedActivity(), if (Build.VERSION.SDK_INT >= 25) getSystemService()!!.reportShortcutUsed("scan") binding = LayoutScannerBinding.inflate(layoutInflater) setContentView(binding.root) - ListHolderListener.setup(this) setSupportActionBar(findViewById(R.id.toolbar)) supportActionBar?.apply { setDisplayHomeAsUpEnabled(true) diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/SettingsFragment.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/SettingsFragment.kt index 0bc105a5b2..c50f1274f9 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/SettingsFragment.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/SettingsFragment.kt @@ -4,14 +4,14 @@ import android.os.Bundle import android.view.View import androidx.core.view.ViewCompat import io.nekohasekai.sagernet.R -import io.nekohasekai.sagernet.widget.ListHolderListener +import io.nekohasekai.sagernet.widget.ListListener class SettingsFragment : ToolbarFragment(R.layout.layout_config_settings) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - ViewCompat.setOnApplyWindowInsetsListener(view, ListHolderListener) + ViewCompat.setOnApplyWindowInsetsListener(view, ListListener) toolbar.setTitle(R.string.settings) parentFragmentManager.beginTransaction() diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/ThemedActivity.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/ThemedActivity.kt index 7bee75ef92..050c874b76 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/ThemedActivity.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/ThemedActivity.kt @@ -1,6 +1,7 @@ package io.nekohasekai.sagernet.ui import android.content.res.Configuration +import android.os.Build import android.os.Bundle import android.widget.TextView import androidx.annotation.StringRes @@ -9,7 +10,7 @@ import androidx.core.app.ActivityCompat import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat import androidx.core.view.updatePadding -import com.google.android.material.appbar.MaterialToolbar +import com.google.android.material.appbar.AppBarLayout import com.google.android.material.snackbar.Snackbar import io.nekohasekai.sagernet.R import io.nekohasekai.sagernet.utils.Theme @@ -34,11 +35,16 @@ abstract class ThemedActivity : AppCompatActivity { uiMode = resources.configuration.uiMode - findViewById(R.id.toolbar)?.let { - val appbarTopPadding = it.paddingTop - - ViewCompat.setOnApplyWindowInsetsListener(it) { v, insets -> - v.updatePadding(top = appbarTopPadding + insets.getInsets(WindowInsetsCompat.Type.systemBars()).top) + if (Build.VERSION.SDK_INT >= 35) { + ViewCompat.setOnApplyWindowInsetsListener(findViewById(android.R.id.content)) { _, insets -> + val top = insets.getInsets(WindowInsetsCompat.Type.systemBars()).top + findViewById(R.id.appbar)?.apply { + updatePadding(top = top) +// Logs.w("appbar $top") + } +// findViewById(R.id.nav_view)?.apply { +// updatePadding(top = top) +// } insets } } diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/profile/ConfigEditActivity.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/profile/ConfigEditActivity.kt index 9f42740438..faec56e05f 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/profile/ConfigEditActivity.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/profile/ConfigEditActivity.kt @@ -6,6 +6,7 @@ import android.os.Bundle import android.view.Menu import android.view.MenuItem import androidx.appcompat.app.AlertDialog +import androidx.core.view.ViewCompat import androidx.core.widget.addTextChangedListener import com.blacksquircle.ui.editorkit.insert import com.blacksquircle.ui.language.json.JsonLanguage @@ -18,6 +19,7 @@ import io.nekohasekai.sagernet.database.DataStore import io.nekohasekai.sagernet.databinding.LayoutEditConfigBinding import io.nekohasekai.sagernet.ktx.* import io.nekohasekai.sagernet.ui.ThemedActivity +import io.nekohasekai.sagernet.widget.ListListener import moe.matsuri.nb4a.ui.ExtendedKeyboard import org.json.JSONObject @@ -97,6 +99,8 @@ class ConfigEditActivity : ThemedActivity() { extendedKeyboard.setHasFixedSize(true) extendedKeyboard.submitList("{},:_\"".map { it.toString() }) extendedKeyboard.setBackgroundColor(getColorAttr(R.attr.primaryOrTextPrimary)) + + ViewCompat.setOnApplyWindowInsetsListener(binding.root, ListListener) } fun formatText(): String? { diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/profile/StandardV2RaySettingsActivity.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/profile/StandardV2RaySettingsActivity.kt index b8ba4dab24..cc769bbc1f 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/profile/StandardV2RaySettingsActivity.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/profile/StandardV2RaySettingsActivity.kt @@ -114,7 +114,7 @@ abstract class StandardV2RaySettingsActivity : ProfileSettingsActivity(android.R.id.content).let { - ViewCompat.setOnApplyWindowInsetsListener(it, ListHolderListener) - WindowCompat.setDecorFitsSystemWindows(activity.window, false) - } -} - -object MainListListener : OnApplyWindowInsetsListener { - override fun onApplyWindowInsets(view: View, insets: WindowInsetsCompat) = insets.apply { - view.updatePadding(bottom = view.resources.getDimensionPixelOffset(R.dimen.main_list_padding_bottom) + - insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom) - } -} +import androidx.core.view.OnApplyWindowInsetsListener +import androidx.core.view.WindowInsetsCompat +import androidx.core.view.updatePadding object ListListener : OnApplyWindowInsetsListener { override fun onApplyWindowInsets(view: View, insets: WindowInsetsCompat) = insets.apply { diff --git a/nekobox-android/app/src/main/java/moe/matsuri/nb4a/SingBoxOptionsUtil.kt b/nekobox-android/app/src/main/java/moe/matsuri/nb4a/SingBoxOptionsUtil.kt index 811b0c2d20..19f733bddb 100644 --- a/nekobox-android/app/src/main/java/moe/matsuri/nb4a/SingBoxOptionsUtil.kt +++ b/nekobox-android/app/src/main/java/moe/matsuri/nb4a/SingBoxOptionsUtil.kt @@ -108,7 +108,11 @@ fun SingBoxOptions.Rule_DefaultOptions.makeSingBoxRule(list: List, isIP: list.forEach { if (isIP) { if (it.startsWith("geoip:")) { - rule_set.plusAssign(it) + if (it == "geoip:private") { + ip_is_private = true + } else { + rule_set.plusAssign(it) + } } else { ip_cidr.plusAssign(it) } diff --git a/nekobox-android/app/src/main/res/layout/layout_about.xml b/nekobox-android/app/src/main/res/layout/layout_about.xml index 2363c50f1c..7e677577dc 100644 --- a/nekobox-android/app/src/main/res/layout/layout_about.xml +++ b/nekobox-android/app/src/main/res/layout/layout_about.xml @@ -57,8 +57,7 @@ + android:layout_height="match_parent" /> + android:layout_height="wrap_content" + android:background="?attr/colorPrimary"> + android:layout_height="wrap_content" + android:background="?attr/colorPrimary"> \ No newline at end of file +/> \ No newline at end of file diff --git a/nekobox-android/app/src/main/res/layout/layout_group.xml b/nekobox-android/app/src/main/res/layout/layout_group.xml index 0aab4933e5..caf90435b8 100644 --- a/nekobox-android/app/src/main/res/layout/layout_group.xml +++ b/nekobox-android/app/src/main/res/layout/layout_group.xml @@ -9,7 +9,10 @@ android:layout_height="match_parent" android:orientation="vertical"> - + - - - - - - - - \ No newline at end of file diff --git a/nekobox-android/app/src/main/res/layout/layout_main.xml b/nekobox-android/app/src/main/res/layout/layout_main.xml index 216b239479..0d59a387e2 100644 --- a/nekobox-android/app/src/main/res/layout/layout_main.xml +++ b/nekobox-android/app/src/main/res/layout/layout_main.xml @@ -5,21 +5,18 @@ android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent" - android:fitsSystemWindows="true" tools:openDrawer="start"> + android:clipChildren="false"> + android:layout_height="match_parent" /> @@ -121,7 +116,6 @@ android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" - android:fitsSystemWindows="true" app:itemIconTint="@color/navigation_icon" app:itemShapeAppearance="@style/ShapeAppearance.MaterialComponents.MediumComponent" app:itemShapeFillColor="@color/navigation_item" diff --git a/nekobox-android/app/src/main/res/layout/layout_route.xml b/nekobox-android/app/src/main/res/layout/layout_route.xml index fa51d83e82..971231f366 100644 --- a/nekobox-android/app/src/main/res/layout/layout_route.xml +++ b/nekobox-android/app/src/main/res/layout/layout_route.xml @@ -9,7 +9,10 @@ android:layout_height="match_parent" android:orientation="vertical"> - + - + - - - - - - - + android:id="@+id/action_connection_tcp_ping" + android:title="@string/connection_test_tcp_ping" /> + + + diff --git a/nekobox-android/buildScript/lib/core/get_source_env.sh b/nekobox-android/buildScript/lib/core/get_source_env.sh index f3e867471a..96303dde57 100644 --- a/nekobox-android/buildScript/lib/core/get_source_env.sh +++ b/nekobox-android/buildScript/lib/core/get_source_env.sh @@ -1,2 +1,2 @@ -export COMMIT_SING_BOX="c40082fa2ea212c2433f0f99e9db0f0dc38187c1" +export COMMIT_SING_BOX="b217d87d7ae6f1e84f7afd31649cfc09481760a9" export COMMIT_LIBNEKO="1c47a3af71990a7b2192e03292b4d246c308ef0b" diff --git a/nekobox-android/libcore/box.go b/nekobox-android/libcore/box.go index ae29b33e72..9caccdc3c0 100644 --- a/nekobox-android/libcore/box.go +++ b/nekobox-android/libcore/box.go @@ -186,7 +186,7 @@ func (b *BoxInstance) SetV2rayStats(outbounds string) { Enabled: true, Outbounds: strings.Split(outbounds, "\n"), }) - b.Box.Router().SetTracker(b.v2api.StatsService()) + b.Box.Router().SetNekoTracker(b.v2api.StatsService()) } func (b *BoxInstance) QueryStats(tag, direct string) int64 { diff --git a/nekobox-android/libcore/go.mod b/nekobox-android/libcore/go.mod index dcb73ec6c5..e451986ede 100644 --- a/nekobox-android/libcore/go.mod +++ b/nekobox-android/libcore/go.mod @@ -20,7 +20,7 @@ require ( require ( github.com/ajg/form v1.5.1 // indirect github.com/andybalholm/brotli v1.0.6 // indirect - github.com/anytls/sing-anytls v0.0.5 // indirect + github.com/anytls/sing-anytls v0.0.6 // indirect github.com/caddyserver/certmagic v0.20.0 // indirect github.com/cloudflare/circl v1.3.7 // indirect github.com/cretz/bine v0.2.0 // indirect diff --git a/nekobox-android/libcore/go.sum b/nekobox-android/libcore/go.sum index 1f2f99a910..d8c27cae6f 100644 --- a/nekobox-android/libcore/go.sum +++ b/nekobox-android/libcore/go.sum @@ -2,8 +2,8 @@ github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI= github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/anytls/sing-anytls v0.0.5 h1:I1NIh3zKTSXThLG5UgjsOOT/x2DZJqjfBzjuP/wZlDk= -github.com/anytls/sing-anytls v0.0.5/go.mod h1:7rjN6IukwysmdusYsrV51Fgu1uW6vsrdd6ctjnEAln8= +github.com/anytls/sing-anytls v0.0.6 h1:UatIjl/OvzWQGXQ1I2bAIkabL9WtihW0fA7G+DXGBUg= +github.com/anytls/sing-anytls v0.0.6/go.mod h1:7rjN6IukwysmdusYsrV51Fgu1uW6vsrdd6ctjnEAln8= github.com/caddyserver/certmagic v0.20.0 h1:bTw7LcEZAh9ucYCRXyCpIrSAGplplI0vGYJ4BpCQ/Fc= github.com/caddyserver/certmagic v0.20.0/go.mod h1:N4sXgpICQUskEWpj7zVzvWD41p3NYacrNoZYiRM2jTg= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= diff --git a/nekobox-android/nb4a.properties b/nekobox-android/nb4a.properties index 2bde39d008..0535d5c728 100644 --- a/nekobox-android/nb4a.properties +++ b/nekobox-android/nb4a.properties @@ -1,3 +1,3 @@ PACKAGE_NAME=moe.nb4a -VERSION_NAME=1.3.7 -VERSION_CODE=41 +VERSION_NAME=1.3.8 +VERSION_CODE=42 diff --git a/openwrt-packages/smartdns/Makefile b/openwrt-packages/smartdns/Makefile index 37b2e91829..c51c471341 100644 --- a/openwrt-packages/smartdns/Makefile +++ b/openwrt-packages/smartdns/Makefile @@ -5,12 +5,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=smartdns -PKG_VERSION:=46 +PKG_VERSION:=46.1 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/pymumu/smartdns/tar.gz/Release$(PKG_VERSION)? -PKG_HASH:=6594d21c0e354b67d4b5918e11eff21e6314e247b9e6e28be1ece4168c368fc1 +PKG_HASH:=6307503fa409b9c6b87556d1b1f8eaf99c7be5b06a9d479ec3589c875391a6b3 PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-Release$(PKG_VERSION) PKG_MAINTAINER:=Nick Peng diff --git a/openwrt-passwall/luci-app-passwall/Makefile b/openwrt-passwall/luci-app-passwall/Makefile index aca3e70dff..f912cac514 100644 --- a/openwrt-passwall/luci-app-passwall/Makefile +++ b/openwrt-passwall/luci-app-passwall/Makefile @@ -12,7 +12,6 @@ PKG_RELEASE:=1 PKG_CONFIG_DEPENDS:= \ CONFIG_PACKAGE_$(PKG_NAME)_Iptables_Transparent_Proxy \ CONFIG_PACKAGE_$(PKG_NAME)_Nftables_Transparent_Proxy \ - CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Geoview \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Haproxy \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy \ @@ -36,7 +35,7 @@ LUCI_PKGARCH:=all LUCI_DEPENDS:=+coreutils +coreutils-base64 +coreutils-nohup +curl \ +chinadns-ng +dns2socks +dnsmasq-full +ip-full \ +libuci-lua +lua +luci-compat +luci-lib-jsonc \ - +microsocks +resolveip +tcping + +microsocks +resolveip +tcping +geoview define Package/$(PKG_NAME)/config menu "Configuration" @@ -64,11 +63,6 @@ config PACKAGE_$(PKG_NAME)_Nftables_Transparent_Proxy select PACKAGE_kmod-nft-nat default y if PACKAGE_firewall4 -config PACKAGE_$(PKG_NAME)_INCLUDE_Geoview - bool "Include Geoview" - select PACKAGE_geoview - default y if aarch64||arm||i386||x86_64 - config PACKAGE_$(PKG_NAME)_INCLUDE_Haproxy bool "Include Haproxy" select PACKAGE_haproxy diff --git a/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/other.lua b/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/other.lua index ff462fcdf0..87501e9cac 100644 --- a/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/other.lua +++ b/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/other.lua @@ -242,42 +242,6 @@ if has_singbox then o.default = 0 o.rmempty = false o.description = translate("Override the connection destination address with the sniffed domain.
When enabled, traffic will match only by domain, ignoring IP rules.
If using shunt nodes, configure the domain shunt rules correctly.") - - o = s:option(Value, "geoip_path", translate("Custom geoip Path")) - o.default = "/usr/share/singbox/geoip.db" - o.rmempty = false - - o = s:option(Value, "geoip_url", translate("Custom geoip URL")) - o.default = "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.db" - o:value("https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.db") - o:value("https://github.com/1715173329/sing-geoip/releases/latest/download/geoip.db") - o:value("https://github.com/lyc8503/sing-box-rules/releases/latest/download/geoip.db") - o.rmempty = false - - o = s:option(Value, "geosite_path", translate("Custom geosite Path")) - o.default = "/usr/share/singbox/geosite.db" - o.rmempty = false - - o = s:option(Value, "geosite_url", translate("Custom geosite URL")) - o.default = "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.db" - o:value("https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.db") - o:value("https://github.com/1715173329/sing-geosite/releases/latest/download/geosite.db") - o:value("https://github.com/lyc8503/sing-box-rules/releases/latest/download/geosite.db") - o.rmempty = false - - o = s:option(Button, "_remove_resource", translate("Remove resource files")) - o.description = translate("Sing-Box will automatically download resource files when starting, you can use this feature achieve upgrade resource files.") - o.inputstyle = "remove" - function o.write(self, section, value) - local geoip_path = s.fields["geoip_path"] and s.fields["geoip_path"]:formvalue(section) or nil - if geoip_path then - os.remove(geoip_path) - end - local geosite_path = s.fields["geosite_path"] and s.fields["geosite_path"]:formvalue(section) or nil - if geosite_path then - os.remove(geosite_path) - end - end end return m diff --git a/openwrt-passwall/luci-app-passwall/luasrc/passwall/util_sing-box.lua b/openwrt-passwall/luci-app-passwall/luasrc/passwall/util_sing-box.lua index bd3a2688c6..c4a26a7617 100644 --- a/openwrt-passwall/luci-app-passwall/luasrc/passwall/util_sing-box.lua +++ b/openwrt-passwall/luci-app-passwall/luasrc/passwall/util_sing-box.lua @@ -10,6 +10,41 @@ local split = api.split local local_version = api.get_app_version("singbox") local version_ge_1_11_0 = api.compare_versions(local_version:match("[^v]+"), ">=", "1.11.0") +local geosite_all_tag = {} +local geoip_all_tag = {} +local srss_path = "/tmp/etc/" .. appname .."/srss/" + +local function convert_geofile() + local geo_path = uci:get(appname, "@global_rules[0]", "v2ray_location_asset") or "/usr/share/v2ray/" + local geosite_path = geo_path:match("^(.*)/") .. "/geosite.dat" + local geoip_path = geo_path:match("^(.*)/") .. "/geoip.dat" + if not api.is_finded("geoview") then + api.log("* 注意:缺少 geoview 组件,Sing-Box 分流将无法启用!") + return + end + if not fs.access(srss_path) then + fs.mkdir(srss_path) + end + if next(geosite_all_tag) and fs.access(geosite_path) then + for k,v in pairs(geosite_all_tag) do + local srs_file = srss_path .. "geosite-" .. k ..".srs" + if not fs.access(srs_file) then + sys.exec("geoview -type geosite -action convert -input " .. geosite_path .. " -list '" .. k .. "' -output " .. srs_file .. " -lowmem=true") + --api.log("* 转换geosite:" .. k .. " 到 Sing-Box 规则集二进制文件") + end + end + end + if next(geoip_all_tag) and fs.access(geoip_path) then + for k,v in pairs(geoip_all_tag) do + local srs_file = srss_path .. "geoip-" .. k ..".srs" + if not fs.access(srs_file) then + sys.exec("geoview -type geoip -action convert -input " .. geoip_path .. " -list '" .. k .. "' -output " .. srs_file .. " -lowmem=true") + --api.log("* 转换geoip:" .. k .. " 到 Sing-Box 规则集二进制文件") + end + end + end +end + local new_port local function get_new_port() @@ -802,17 +837,7 @@ function gen_config(var) local singbox_settings = uci:get_all(appname, "@global_singbox[0]") or {} local route = { - rules = {}, - geoip = { - path = singbox_settings.geoip_path or "/usr/share/singbox/geoip.db", - download_url = singbox_settings.geoip_url or nil, - download_detour = nil, - }, - geosite = { - path = singbox_settings.geosite_path or "/usr/share/singbox/geosite.db", - download_url = singbox_settings.geosite_url or nil, - download_detour = nil, - }, + rules = {} } local experimental = nil @@ -1183,17 +1208,21 @@ function gen_config(var) end if e.source then - local source_geoip = {} local source_ip_cidr = {} + local is_private = false string.gsub(e.source, '[^' .. " " .. ']+', function(w) if w:find("geoip") == 1 then - table.insert(source_geoip, w) + local _geoip = w:sub(1 + #"geoip:") --适配srs + if _geoip == "private" then + is_private = true + end else table.insert(source_ip_cidr, w) end end) - rule.source_geoip = #source_geoip > 0 and source_geoip or nil + rule.source_ip_is_private = is_private and true or nil rule.source_ip_cidr = #source_ip_cidr > 0 and source_ip_cidr or nil + if is_private or #source_ip_cidr > 0 then rule.rule_set_ip_cidr_match_source = true end end if e.sourcePort then @@ -1224,6 +1253,8 @@ function gen_config(var) rule.port_range = #port_range > 0 and port_range or nil end + local rule_set_tag = {} + if e.domain_list then local domain_table = { outboundTag = outboundTag, @@ -1231,12 +1262,15 @@ function gen_config(var) domain_suffix = {}, domain_keyword = {}, domain_regex = {}, - geosite = {}, + rule_set = {}, } string.gsub(e.domain_list, '[^' .. "\r\n" .. ']+', function(w) if w:find("#") == 1 then return end if w:find("geosite:") == 1 then - table.insert(domain_table.geosite, w:sub(1 + #"geosite:")) + local _geosite = w:sub(1 + #"geosite:") --适配srs + geosite_all_tag[_geosite] = true + table.insert(rule_set_tag, "geosite-" .. _geosite) + table.insert(domain_table.rule_set, "geosite-" .. _geosite) elseif w:find("regexp:") == 1 then table.insert(domain_table.domain_regex, w:sub(1 + #"regexp:")) elseif w:find("full:") == 1 then @@ -1251,7 +1285,6 @@ function gen_config(var) rule.domain_suffix = #domain_table.domain_suffix > 0 and domain_table.domain_suffix or nil rule.domain_keyword = #domain_table.domain_keyword > 0 and domain_table.domain_keyword or nil rule.domain_regex = #domain_table.domain_regex > 0 and domain_table.domain_regex or nil - rule.geosite = #domain_table.geosite > 0 and domain_table.geosite or nil if outboundTag then table.insert(dns_domain_rules, api.clone(domain_table)) @@ -1260,20 +1293,28 @@ function gen_config(var) if e.ip_list then local ip_cidr = {} - local geoip = {} + local is_private = false string.gsub(e.ip_list, '[^' .. "\r\n" .. ']+', function(w) if w:find("#") == 1 then return end if w:find("geoip:") == 1 then - table.insert(geoip, w:sub(1 + #"geoip:")) + local _geoip = w:sub(1 + #"geoip:") --适配srs + if _geoip == "private" then + is_private = true + else + geoip_all_tag[_geoip] = true + table.insert(rule_set_tag, "geoip-" .. _geoip) + end else table.insert(ip_cidr, w) end end) + rule.ip_is_private = is_private and true or nil rule.ip_cidr = #ip_cidr > 0 and ip_cidr or nil - rule.geoip = #geoip > 0 and geoip or nil end + rule.rule_set = #rule_set_tag > 0 and rule_set_tag or nil --适配srs + table.insert(rules, rule) end end) @@ -1281,6 +1322,34 @@ function gen_config(var) for index, value in ipairs(rules) do table.insert(route.rules, rules[index]) end + + local rule_set = {} --适配srs + if next(geosite_all_tag) then + for k,v in pairs(geosite_all_tag) do + local srs_file = srss_path .. "geosite-" .. k ..".srs" + local _rule_set = { + tag = "geosite-" .. k, + type = "local", + format = "binary", + path = srs_file + } + table.insert(rule_set, _rule_set) + end + end + if next(geoip_all_tag) then + for k,v in pairs(geoip_all_tag) do + local srs_file = srss_path .. "geoip-" .. k ..".srs" + local _rule_set = { + tag = "geoip-" .. k, + type = "local", + format = "binary", + path = srs_file + } + table.insert(rule_set, _rule_set) + end + end + route.rule_set = #rule_set >0 and rule_set or nil + elseif node.protocol == "_urltest" then if node.urltest_node then COMMON.default_outbound_tag = gen_urltest(node) @@ -1470,14 +1539,14 @@ function gen_config(var) --按分流顺序DNS if dns_domain_rules and #dns_domain_rules > 0 then for index, value in ipairs(dns_domain_rules) do - if value.outboundTag and (value.domain or value.domain_suffix or value.domain_keyword or value.domain_regex or value.geosite) then + if value.outboundTag and (value.domain or value.domain_suffix or value.domain_keyword or value.domain_regex or value.rule_set) then local dns_rule = { server = value.outboundTag, domain = (value.domain and #value.domain > 0) and value.domain or nil, domain_suffix = (value.domain_suffix and #value.domain_suffix > 0) and value.domain_suffix or nil, domain_keyword = (value.domain_keyword and #value.domain_keyword > 0) and value.domain_keyword or nil, domain_regex = (value.domain_regex and #value.domain_regex > 0) and value.domain_regex or nil, - geosite = (value.geosite and #value.geosite > 0) and value.geosite or nil, + rule_set = (value.rule_set and #value.rule_set > 0) and value.rule_set or nil, --适配srs disable_cache = false, } if value.outboundTag ~= "block" and value.outboundTag ~= "direct" then @@ -1737,5 +1806,8 @@ if arg[1] then local func =_G[arg[1]] if func then print(func(api.get_function_args(arg))) + if next(geosite_all_tag) or next(geoip_all_tag) then + convert_geofile() + end end end diff --git a/openwrt-passwall/luci-app-passwall/po/zh-cn/passwall.po b/openwrt-passwall/luci-app-passwall/po/zh-cn/passwall.po index 4c93e477c0..a831b1842c 100644 --- a/openwrt-passwall/luci-app-passwall/po/zh-cn/passwall.po +++ b/openwrt-passwall/luci-app-passwall/po/zh-cn/passwall.po @@ -1633,24 +1633,6 @@ msgstr "端口跳跃额外端口" msgid "HeartbeatPeriod(second)" msgstr "心跳周期(单位:秒)" -msgid "Custom geoip Path" -msgstr "自定义 geoip 文件路径" - -msgid "Custom geoip URL" -msgstr "自定义 geoip 文件更新链接" - -msgid "Custom geosite Path" -msgstr "自定义 geosite 文件路径" - -msgid "Custom geosite URL" -msgstr "自定义 geosite 文件更新链接" - -msgid "Remove resource files" -msgstr "删除资源文件" - -msgid "Sing-Box will automatically download resource files when starting, you can use this feature achieve upgrade resource files." -msgstr "Sing-Box 会在启动时自动下载资源文件,您可以使用此功能实现升级资源文件。" - msgid "Override the connection destination address" msgstr "覆盖连接目标地址" diff --git a/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/0_default_config b/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/0_default_config index 2d4242e232..a99cf333b6 100644 --- a/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/0_default_config +++ b/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/0_default_config @@ -51,10 +51,6 @@ config global_xray config global_singbox option sniff_override_destination '0' - option geoip_path '/usr/share/singbox/geoip.db' - option geoip_url 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.db' - option geosite_path '/usr/share/singbox/geosite.db' - option geosite_url 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.db' config global_other option auto_detection_time 'tcping' diff --git a/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/app.sh b/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/app.sh index 39d35af288..189754cd06 100755 --- a/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/app.sh +++ b/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/app.sh @@ -777,8 +777,9 @@ run_redir() { sing-box) local protocol=$(config_n_get $node protocol) [ "$protocol" = "_shunt" ] && { - local geoip_path="$(config_t_get global_singbox geoip_path)" - local geosite_path="$(config_t_get global_singbox geosite_path)" + local geo_path="$(config_t_get global_rules v2ray_location_asset)" + local geoip_path="${geo_path%*/}/geoip.dat" + local geosite_path="${geo_path%*/}/geosite.dat" if [ ! -s "$geoip_path" ] || [ ! -s "$geosite_path" ]; then echolog "* 缺少Geo规则文件,UDP Sing-Box分流节点无法正常使用!" fi @@ -895,8 +896,9 @@ run_redir() { } [ "$protocol" = "_shunt" ] && { - local geoip_path="$(config_t_get global_singbox geoip_path)" - local geosite_path="$(config_t_get global_singbox geosite_path)" + local geo_path="$(config_t_get global_rules v2ray_location_asset)" + local geoip_path="${geo_path%*/}/geoip.dat" + local geosite_path="${geo_path%*/}/geosite.dat" if [ ! -s "$geoip_path" ] || [ ! -s "$geosite_path" ]; then echolog "* 缺少Geo规则文件,TCP Sing-Box分流节点无法正常使用!" fi diff --git a/shadowsocks-rust/Cargo.lock b/shadowsocks-rust/Cargo.lock index 35178e1adb..4d64366e03 100644 --- a/shadowsocks-rust/Cargo.lock +++ b/shadowsocks-rust/Cargo.lock @@ -309,16 +309,15 @@ dependencies = [ [[package]] name = "blake3" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1230237285e3e10cde447185e8975408ae24deaa67205ce684805c25bc0c7937" +checksum = "675f87afced0413c9bb02843499dbbd3882a237645883f71a2b59644a6d2f753" dependencies = [ "arrayref", "arrayvec", "cc", "cfg-if", "constant_time_eq", - "memmap2", ] [[package]] @@ -546,18 +545,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.30" +version = "4.5.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92b7b18d71fad5313a1e320fa9897994228ce274b60faa4d694fe0ea89cd9e6d" +checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.30" +version = "4.5.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a35db2071778a7344791a4fb4f95308b5673d219dee3ae348b86642574ecc90c" +checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863" dependencies = [ "anstream", "anstyle", @@ -752,7 +751,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3983b127f13995e68c1e29071e5d115cd96f215ccb5e6812e3728cd6f92653b3" dependencies = [ - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -1372,7 +1371,7 @@ dependencies = [ "rand 0.9.0", "rustls", "serde", - "thiserror 2.0.11", + "thiserror 2.0.12", "tinyvec", "tokio", "tokio-rustls", @@ -1400,7 +1399,7 @@ dependencies = [ "rustls", "serde", "smallvec", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tokio-rustls", "tracing", @@ -1901,7 +1900,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.48.5", ] [[package]] @@ -2046,15 +2045,6 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" -[[package]] -name = "memmap2" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" -dependencies = [ - "libc", -] - [[package]] name = "mimalloc" version = "0.1.43" @@ -2382,7 +2372,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" dependencies = [ "memchr", - "thiserror 2.0.11", + "thiserror 2.0.12", "ucd-trie", ] @@ -2589,7 +2579,7 @@ dependencies = [ "rustc-hash", "rustls", "socket2", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tracing", ] @@ -2608,7 +2598,7 @@ dependencies = [ "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.11", + "thiserror 2.0.12", "tinyvec", "tracing", "web-time", @@ -2730,7 +2720,7 @@ checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" dependencies = [ "getrandom 0.2.15", "libredox", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -2949,9 +2939,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.20" +version = "0.23.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" +checksum = "47796c98c480fce5406ef69d1c76378375492c3b0a0de587be0c1d9feb12f395" dependencies = [ "log", "once_cell", @@ -3151,9 +3141,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.139" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44f86c3acccc9c65b153fe1b85a3be07fe5515274ec9f0653b4a0875731c72a6" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "indexmap", "itoa", @@ -3240,7 +3230,7 @@ dependencies = [ "shadowsocks-crypto", "socket2", "spin", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tokio-tfo", "trait-variant", @@ -3308,7 +3298,7 @@ dependencies = [ "snmalloc-rs", "sysexits", "tcmalloc", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", "tracing", @@ -3358,7 +3348,7 @@ dependencies = [ "smoltcp", "socket2", "spin", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tokio-native-tls", "tokio-rustls", @@ -3658,11 +3648,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.11" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ - "thiserror-impl 2.0.11", + "thiserror-impl 2.0.12", ] [[package]] @@ -3678,9 +3668,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.11" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", @@ -3806,9 +3796,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" dependencies = [ "rustls", "tokio", @@ -3965,7 +3955,7 @@ dependencies = [ "libc", "log", "nix", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tokio-util", "windows-sys 0.59.0", @@ -4246,7 +4236,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.48.0", ] [[package]] @@ -4529,7 +4519,7 @@ dependencies = [ "futures", "libloading", "log", - "thiserror 2.0.11", + "thiserror 2.0.12", "windows-sys 0.59.0", "winreg2", ] diff --git a/small/luci-app-fchomo/htdocs/luci-static/resources/fchomo.js b/small/luci-app-fchomo/htdocs/luci-static/resources/fchomo.js index 6544f14066..9ba7080435 100644 --- a/small/luci-app-fchomo/htdocs/luci-static/resources/fchomo.js +++ b/small/luci-app-fchomo/htdocs/luci-static/resources/fchomo.js @@ -69,6 +69,7 @@ const inbound_type = [ ['shadowsocks', _('Shadowsocks')], ['vmess', _('VMess')], ['vless', _('VLESS')], + ['trojan', _('Trojan')], ['tuic', _('TUIC')], ['hysteria2', _('Hysteria2')], //['tunnel', _('Tunnel')] @@ -195,6 +196,12 @@ const rules_logical_payload_count = { //'SUB-RULE': 0, }; +const trojan_cipher_methods = [ + ['aes-128-gcm', _('aes-128-gcm')], + ['aes-256-gcm', _('aes-256-gcm')], + ['chacha20-ietf-poly1305', _('chacha20-ietf-poly1305')] +]; + const shadowsocks_cipher_methods = [ /* Stream */ ['none', _('none')], @@ -1176,6 +1183,7 @@ return baseclass.extend({ rules_type, rules_logical_type, rules_logical_payload_count, + trojan_cipher_methods, shadowsocks_cipher_methods, shadowsocks_cipher_length, stunserver, diff --git a/small/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/node.js b/small/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/node.js index 4fc914f50a..3ee5907b0d 100644 --- a/small/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/node.js +++ b/small/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/node.js @@ -269,9 +269,10 @@ return view.extend({ so.modalonly = true; so = ss.taboption('field_general', form.ListValue, 'trojan_ss_chipher', _('Shadowsocks chipher')); - so.value('aes-128-gcm', _('aes-128-gcm')); - so.value('aes-256-gcm', _('aes-256-gcm')); - so.value('chacha20-ietf-poly1305', _('chacha20-ietf-poly1305')); + so.default = hm.trojan_cipher_methods[0][0]; + hm.trojan_cipher_methods.forEach((res) => { + so.value.apply(so, res); + }) so.depends({type: 'trojan', trojan_ss_enabled: '1'}); so.modalonly = true; diff --git a/small/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/server.js b/small/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/server.js index 54476089db..ea595a2926 100644 --- a/small/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/server.js +++ b/small/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/server.js @@ -65,30 +65,38 @@ return view.extend({ s.renderSectionAdd = L.bind(hm.renderSectionAdd, s, prefmt, false); s.handleAdd = L.bind(hm.handleAdd, s, prefmt); + s.tab('field_general', _('General fields')); + s.tab('field_tls', _('TLS fields')); + s.tab('field_transport', _('Transport fields')); + s.tab('field_multiplex', _('Multiplex fields')); + s.tab('field_listen', _('Listen fields')); + /* General fields */ - o = s.option(form.Value, 'label', _('Label')); + o = s.taboption('field_general', form.Value, 'label', _('Label')); o.load = L.bind(hm.loadDefaultLabel, o); o.validate = L.bind(hm.validateUniqueValue, o); o.modalonly = true; - o = s.option(form.Flag, 'enabled', _('Enable')); + o = s.taboption('field_general', form.Flag, 'enabled', _('Enable')); o.default = o.enabled; o.editable = true; - o = s.option(form.ListValue, 'type', _('Type')); + o = s.taboption('field_general', form.ListValue, 'type', _('Type')); o.default = hm.inbound_type[0][0]; hm.inbound_type.forEach((res) => { o.value.apply(o, res); }) - o = s.option(form.Value, 'listen', _('Listen address')); + o = s.taboption('field_general', form.Value, 'listen', _('Listen address')); o.datatype = 'ipaddr'; o.placeholder = '::'; o.modalonly = true; - o = s.option(form.Value, 'port', _('Listen port')); - o.datatype = 'port'; + o = s.taboption('field_general', form.Value, 'port', _('Listen port') + ' / ' + _('Ports pool')); + o.datatype = 'or(port, portrange)'; + //o.placeholder = '1080,2079-2080,3080'; // Incompatible with firewall o.rmempty = false; + //o.validate = L.bind(hm.validateCommonPort, o); // Incompatible with firewall // dev: Features under development // rule @@ -96,45 +104,46 @@ return view.extend({ /* HTTP / SOCKS fields */ /* hm.validateAuth */ - o = s.option(form.Value, 'username', _('Username')); + o = s.taboption('field_general', form.Value, 'username', _('Username')); o.validate = L.bind(hm.validateAuthUsername, o); o.depends({type: /^(http|socks|mixed|hysteria2)$/}); o.modalonly = true; - o = s.option(hm.GenValue, 'password', _('Password')); + o = s.taboption('field_general', hm.GenValue, 'password', _('Password')); o.password = true; o.validate = L.bind(hm.validateAuthPassword, o); o.rmempty = false; o.depends({type: /^(http|socks|mixed|hysteria2)$/, username: /.+/}); + o.depends('type', 'trojan'); o.depends({type: /^(tuic)$/, uuid: /.+/}); o.modalonly = true; /* Hysteria2 fields */ - o = s.option(form.Value, 'hysteria_up_mbps', _('Max upload speed'), + o = s.taboption('field_general', form.Value, 'hysteria_up_mbps', _('Max upload speed'), _('In Mbps.')); o.datatype = 'uinteger'; o.depends('type', 'hysteria2'); o.modalonly = true; - o = s.option(form.Value, 'hysteria_down_mbps', _('Max download speed'), + o = s.taboption('field_general', form.Value, 'hysteria_down_mbps', _('Max download speed'), _('In Mbps.')); o.datatype = 'uinteger'; o.depends('type', 'hysteria2'); o.modalonly = true; - o = s.option(form.Flag, 'hysteria_ignore_client_bandwidth', _('Ignore client bandwidth'), + o = s.taboption('field_general', form.Flag, 'hysteria_ignore_client_bandwidth', _('Ignore client bandwidth'), _('Tell the client to use the BBR flow control algorithm instead of Hysteria CC.')); o.default = o.disabled; o.depends({type: 'hysteria2', hysteria_up_mbps: '', hysteria_down_mbps: ''}); o.modalonly = true; - o = s.option(form.ListValue, 'hysteria_obfs_type', _('Obfuscate type')); + o = s.taboption('field_general', form.ListValue, 'hysteria_obfs_type', _('Obfuscate type')); o.value('', _('Disable')); o.value('salamander', _('Salamander')); o.depends('type', 'hysteria2'); o.modalonly = true; - o = s.option(hm.GenValue, 'hysteria_obfs_password', _('Obfuscate password'), + o = s.taboption('field_general', hm.GenValue, 'hysteria_obfs_password', _('Obfuscate password'), _('Enabling obfuscation will make the server incompatible with standard QUIC connections, losing the ability to masquerade with HTTP/3.')); o.password = true; o.rmempty = false; @@ -142,14 +151,14 @@ return view.extend({ o.depends({type: 'hysteria2', hysteria_obfs_type: /.+/}); o.modalonly = true; - o = s.option(form.Value, 'hysteria_masquerade', _('Masquerade'), + o = s.taboption('field_general', form.Value, 'hysteria_masquerade', _('Masquerade'), _('HTTP3 server behavior when authentication fails.
A 404 page will be returned if empty.')); o.placeholder = 'file:///var/www or http://127.0.0.1:8080' o.depends('type', 'hysteria2'); o.modalonly = true; /* Shadowsocks fields */ - o = s.option(form.ListValue, 'shadowsocks_chipher', _('Chipher')); + o = s.taboption('field_general', form.ListValue, 'shadowsocks_chipher', _('Chipher')); o.default = hm.shadowsocks_cipher_methods[1][0]; hm.shadowsocks_cipher_methods.forEach((res) => { o.value.apply(o, res); @@ -157,7 +166,7 @@ return view.extend({ o.depends('type', 'shadowsocks'); o.modalonly = true; - o = s.option(hm.GenValue, 'shadowsocks_password', _('Password')); + o = s.taboption('field_general', hm.GenValue, 'shadowsocks_password', _('Password')); o.password = true; o.validate = function(section_id, value) { const encmode = this.section.getOption('shadowsocks_chipher').formvalue(section_id); @@ -167,13 +176,13 @@ return view.extend({ o.modalonly = true; /* Tuic fields */ - o = s.option(hm.GenValue, 'uuid', _('UUID')); + o = s.taboption('field_general', hm.GenValue, 'uuid', _('UUID')); o.rmempty = false; o.validate = L.bind(hm.validateUUID, o); o.depends('type', 'tuic'); o.modalonly = true; - o = s.option(form.ListValue, 'tuic_congestion_controller', _('Congestion controller'), + o = s.taboption('field_general', form.ListValue, 'tuic_congestion_controller', _('Congestion controller'), _('QUIC congestion controller.')); o.default = 'cubic'; o.value('cubic', _('cubic')); @@ -182,34 +191,57 @@ return view.extend({ o.depends('type', 'tuic'); o.modalonly = true; - o = s.option(form.Value, 'tuic_max_udp_relay_packet_size', _('Max UDP relay packet size')); + o = s.taboption('field_general', form.Value, 'tuic_max_udp_relay_packet_size', _('Max UDP relay packet size')); o.datatype = 'uinteger'; o.default = '1500'; o.depends('type', 'tuic'); o.modalonly = true; - o = s.option(form.Value, 'tuic_max_idle_time', _('Idle timeout'), + o = s.taboption('field_general', form.Value, 'tuic_max_idle_time', _('Idle timeout'), _('In seconds.')); o.default = '15000'; o.validate = L.bind(hm.validateTimeDuration, o); o.depends('type', 'tuic'); o.modalonly = true; - o = s.option(form.Value, 'tuic_authentication_timeout', _('Auth timeout'), + o = s.taboption('field_general', form.Value, 'tuic_authentication_timeout', _('Auth timeout'), _('In seconds.')); o.default = '1000'; o.validate = L.bind(hm.validateTimeDuration, o); o.depends('type', 'tuic'); o.modalonly = true; + /* Trojan fields */ + o = s.taboption('field_general', form.Flag, 'trojan_ss_enabled', _('Shadowsocks encrypt')); + o.default = o.disabled; + o.depends('type', 'trojan'); + o.modalonly = true; + + o = s.taboption('field_general', form.ListValue, 'trojan_ss_chipher', _('Shadowsocks chipher')); + o.default = hm.trojan_cipher_methods[0][0]; + hm.trojan_cipher_methods.forEach((res) => { + o.value.apply(o, res); + }) + o.depends({type: 'trojan', trojan_ss_enabled: '1'}); + o.modalonly = true; + + o = s.taboption('field_general', hm.GenValue, 'trojan_ss_password', _('Shadowsocks password')); + o.password = true; + o.validate = function(section_id, value) { + const encmode = this.section.getOption('trojan_ss_chipher').formvalue(section_id); + return hm.validateShadowsocksPassword.call(this, encmode, section_id, value); + } + o.depends({type: 'trojan', trojan_ss_enabled: '1'}); + o.modalonly = true; + /* VMess / VLESS fields */ - o = s.option(hm.GenValue, 'vmess_uuid', _('UUID')); + o = s.taboption('field_general', hm.GenValue, 'vmess_uuid', _('UUID')); o.rmempty = false; o.validate = L.bind(hm.validateUUID, o); o.depends({type: /^(vmess|vless)$/}); o.modalonly = true; - o = s.option(form.ListValue, 'vless_flow', _('Flow')); + o = s.taboption('field_general', form.ListValue, 'vless_flow', _('Flow')); o.default = hm.vless_flow[0][0]; hm.vless_flow.forEach((res) => { o.value.apply(o, res); @@ -217,15 +249,21 @@ return view.extend({ o.depends('type', 'vless'); o.modalonly = true; - o = s.option(form.Value, 'vmess_alterid', _('Alter ID'), + o = s.taboption('field_general', form.Value, 'vmess_alterid', _('Alter ID'), _('Legacy protocol support (VMess MD5 Authentication) is provided for compatibility purposes only, use of alterId > 1 is not recommended.')); o.datatype = 'uinteger'; o.placeholder = '0'; o.depends('type', 'vmess'); o.modalonly = true; + /* Extra fields */ + o = s.taboption('field_general', form.Flag, 'udp', _('UDP')); + o.default = o.disabled; + o.depends({type: /^(socks|mixed|shadowsocks)$/}); + o.modalonly = true; + /* TLS fields */ - o = s.option(form.Flag, 'tls', _('TLS')); + o = s.taboption('field_general', form.Flag, 'tls', _('TLS')); o.default = o.disabled; o.validate = function(section_id, value) { const type = this.section.getOption('type').formvalue(section_id); @@ -234,7 +272,7 @@ return view.extend({ let tls_reality = this.section.getUIElement(section_id, 'tls_reality').node.querySelector('input'); // Force enabled - if (['vless', 'tuic', 'hysteria2'].includes(type)) { + if (['vless', 'trojan', 'tuic', 'hysteria2'].includes(type)) { tls.checked = true; tls.disabled = true; if (['tuic', 'hysteria2'].includes(type) && !`${tls_alpn.getValue()}`) @@ -244,7 +282,7 @@ return view.extend({ } // Force disabled - if (!['vmess', 'vless'].includes(type)) { + if (!['vmess', 'vless', 'trojan'].includes(type)) { tls_reality.checked = null; tls_reality.disabled = true; } else { @@ -253,22 +291,22 @@ return view.extend({ return true; } - o.depends({type: /^(vmess|vless|tuic|hysteria2)$/}); + o.depends({type: /^(http|socks|mixed|vmess|vless|trojan|tuic|hysteria2)$/}); o.modalonly = true; - o = s.option(form.DynamicList, 'tls_alpn', _('TLS ALPN'), + o = s.taboption('field_tls', form.DynamicList, 'tls_alpn', _('TLS ALPN'), _('List of supported application level protocols, in order of preference.')); o.depends('tls', '1'); o.modalonly = true; - o = s.option(form.Value, 'tls_cert_path', _('Certificate path'), + o = s.taboption('field_tls', form.Value, 'tls_cert_path', _('Certificate path'), _('The server public key, in PEM format.')); o.value('/etc/fchomo/certs/server_publickey.pem'); o.depends({tls: '1', tls_reality: '0'}); o.rmempty = false; o.modalonly = true; - o = s.option(form.Button, '_upload_cert', _('Upload certificate'), + o = s.taboption('field_tls', form.Button, '_upload_cert', _('Upload certificate'), _('Save your configuration before uploading files!')); o.inputstyle = 'action'; o.inputtitle = _('Upload...'); @@ -276,14 +314,14 @@ return view.extend({ o.onclick = L.bind(hm.uploadCertificate, o, _('certificate'), 'server_publickey'); o.modalonly = true; - o = s.option(form.Value, 'tls_key_path', _('Key path'), + o = s.taboption('field_tls', form.Value, 'tls_key_path', _('Key path'), _('The server private key, in PEM format.')); o.value('/etc/fchomo/certs/server_privatekey.pem'); o.rmempty = false; o.depends({tls: '1', tls_cert_path: /.+/}); o.modalonly = true; - o = s.option(form.Button, '_upload_key', _('Upload key'), + o = s.taboption('field_tls', form.Button, '_upload_key', _('Upload key'), _('Save your configuration before uploading files!')); o.inputstyle = 'action'; o.inputtitle = _('Upload...'); @@ -292,19 +330,19 @@ return view.extend({ o.modalonly = true; // uTLS fields - o = s.option(form.Flag, 'tls_reality', _('REALITY')); + o = s.taboption('field_tls', form.Flag, 'tls_reality', _('REALITY')); o.default = o.disabled; o.depends('tls', '1'); o.modalonly = true; - o = s.option(form.Value, 'tls_reality_dest', _('REALITY handshake server')); + o = s.taboption('field_tls', form.Value, 'tls_reality_dest', _('REALITY handshake server')); o.datatype = 'hostport'; - o.placeholder = 'cloud.tencent.com'; + o.placeholder = 'cloud.tencent.com:443'; o.rmempty = false; o.depends('tls_reality', '1'); o.modalonly = true; - o = s.option(hm.GenValue, 'tls_reality_private_key', _('REALITY private key')); + o = s.taboption('field_tls', hm.GenValue, 'tls_reality_private_key', _('REALITY private key')); const tls_reality_public_key = 'tls_reality_public_key'; o.hm_asymmetric = { type: 'reality-keypair', @@ -318,27 +356,69 @@ return view.extend({ o.depends('tls_reality', '1'); o.modalonly = true; - o = s.option(form.Value, tls_reality_public_key, _('REALITY public key')); + o = s.taboption('field_tls', form.Value, tls_reality_public_key, _('REALITY public key')); o.depends('tls_reality', '1'); o.modalonly = true; - o = s.option(form.DynamicList, 'tls_reality_short_id', _('REALITY short ID')); + o = s.taboption('field_tls', form.DynamicList, 'tls_reality_short_id', _('REALITY short ID')); //o.value('', '""'); o.rmempty = false; o.depends('tls_reality', '1'); o.modalonly = true; - o = s.option(form.DynamicList, 'tls_reality_server_names', _('REALITY certificate issued to')); + o = s.taboption('field_tls', form.DynamicList, 'tls_reality_server_names', _('REALITY certificate issued to')); o.datatype = 'list(hostname)'; o.placeholder = 'cloud.tencent.com'; o.rmempty = false; o.depends('tls_reality', '1'); o.modalonly = true; - /* Extra fields */ - o = s.option(form.Flag, 'udp', _('UDP')); + /* Transport fields */ + o = s.taboption('field_general', form.Flag, 'transport_enabled', _('Transport')); o.default = o.disabled; - o.depends({type: /^(socks|mixed|shadowsocks)$/}); + o.depends({type: /^(vmess|vless|trojan)$/}); + o.modalonly = true; + + o = s.taboption('field_transport', form.ListValue, 'transport_type', _('Transport type')); + o.value('grpc', _('gRPC')); + o.value('ws', _('WebSocket')); + o.validate = function(section_id, value) { + const type = this.section.getOption('type').formvalue(section_id); + + switch (type) { + case 'vmess': + case 'vless': + if (!['http', 'h2', 'grpc', 'ws'].includes(value)) + return _('Expecting: only support %s.').format(_('HTTP') + + ' / ' + _('HTTPUpgrade') + + ' / ' + _('gRPC') + + ' / ' + _('WebSocket')); + break; + case 'trojan': + if (!['grpc', 'ws'].includes(value)) + return _('Expecting: only support %s.').format(_('gRPC') + + ' / ' + _('WebSocket')); + break; + default: + break; + } + + return true; + } + o.depends('transport_enabled', '1'); + o.modalonly = true; + + o = s.taboption('field_transport', form.Value, 'transport_path', _('Request path')); + o.placeholder = '/'; + o.default = '/'; + o.rmempty = false; + o.depends({transport_enabled: '1', transport_type: 'ws'}); + o.modalonly = true; + + o = s.taboption('field_transport', form.Value, 'transport_grpc_servicename', _('gRPC service name')); + o.placeholder = 'GunService'; + o.rmempty = false; + o.depends({transport_enabled: '1', transport_type: 'grpc'}); o.modalonly = true; /* Server settings END */ diff --git a/small/luci-app-fchomo/root/usr/share/fchomo/generate_client.uc b/small/luci-app-fchomo/root/usr/share/fchomo/generate_client.uc index 6f027db6f2..041c130466 100644 --- a/small/luci-app-fchomo/root/usr/share/fchomo/generate_client.uc +++ b/small/luci-app-fchomo/root/usr/share/fchomo/generate_client.uc @@ -531,7 +531,7 @@ uci.foreach(uciconf, ucinode, (cfg) => { enabled: true, method: cfg.trojan_ss_chipher, password: cfg.trojan_ss_password - }: null, + } : null, /* VMess / VLESS */ flow: cfg.vless_flow, diff --git a/small/luci-app-fchomo/root/usr/share/fchomo/generate_server.uc b/small/luci-app-fchomo/root/usr/share/fchomo/generate_server.uc index e16b94526c..924f9ddc67 100644 --- a/small/luci-app-fchomo/root/usr/share/fchomo/generate_server.uc +++ b/small/luci-app-fchomo/root/usr/share/fchomo/generate_server.uc @@ -49,9 +49,8 @@ uci.foreach(uciconf, uciserver, (cfg) => { type: cfg.type, listen: cfg.listen || '::', - port: strToInt(cfg.port), + port: cfg.port, proxy: 'DIRECT', - udp: strToBool(cfg.udp), /* Hysteria2 */ up: strToInt(cfg.hysteria_up_mbps), @@ -71,8 +70,15 @@ uci.foreach(uciconf, uciserver, (cfg) => { "authentication-timeout": durationToSecond(cfg.tuic_authentication_timeout), "max-udp-relay-packet-size": strToInt(cfg.tuic_max_udp_relay_packet_size), - /* HTTP / SOCKS / VMess / VLESS / Tuic / Hysteria2 */ - users: (cfg.type in ['http', 'socks', 'mixed', 'vmess', 'vless']) ? [ + /* Trojan */ + "ss-option": cfg.trojan_ss_enabled === '1' ? { + enabled: true, + method: cfg.trojan_ss_chipher, + password: cfg.trojan_ss_password + } : null, + + /* HTTP / SOCKS / VMess / VLESS / Trojan / Tuic / Hysteria2 */ + users: (cfg.type in ['http', 'socks', 'mixed', 'vmess', 'vless', 'trojan']) ? [ { /* HTTP / SOCKS */ username: cfg.username, @@ -93,7 +99,10 @@ uci.foreach(uciconf, uciserver, (cfg) => { ...arrToObj([[cfg.uuid, cfg.password]]) } : null), - /* TLS */ + /* Extra fields */ + udp: strToBool(cfg.udp), + + /* TLS fields */ ...(cfg.tls === '1' ? { alpn: cfg.tls_alpn, ...(cfg.tls_reality === '1' ? { @@ -107,6 +116,12 @@ uci.foreach(uciconf, uciserver, (cfg) => { certificate: cfg.tls_cert_path, "private-key": cfg.tls_key_path }) + } : {}), + + /* Transport fields */ + ...(cfg.transport_enabled === '1' ? { + "grpc-service-name": cfg.transport_grpc_servicename, + "ws-path": cfg.transport_path } : {}) }); }); diff --git a/small/luci-app-nikki/Makefile b/small/luci-app-nikki/Makefile index c1a678cc83..7d0e8c107e 100644 --- a/small/luci-app-nikki/Makefile +++ b/small/luci-app-nikki/Makefile @@ -1,6 +1,6 @@ include $(TOPDIR)/rules.mk -PKG_VERSION:=1.19.5 +PKG_VERSION:=1.20.0 LUCI_TITLE:=LuCI Support for nikki LUCI_DEPENDS:=+luci-base +nikki diff --git a/small/luci-app-nikki/htdocs/luci-static/resources/tools/nikki.js b/small/luci-app-nikki/htdocs/luci-static/resources/tools/nikki.js index 7dc93de674..3ce7104841 100644 --- a/small/luci-app-nikki/htdocs/luci-static/resources/tools/nikki.js +++ b/small/luci-app-nikki/htdocs/luci-static/resources/tools/nikki.js @@ -25,6 +25,12 @@ const callNikkiVersion = rpc.declare({ expect: { '': {} } }); +const callNikkiProfile = rpc.declare({ + object: 'luci.nikki', + method: 'profile', + expect: { '': {} } +}); + const callNikkiUpdateSubscription = rpc.declare({ object: 'luci.nikki', method: 'update_subscription', @@ -84,13 +90,18 @@ return baseclass.extend({ return callNikkiVersion(); }, + profile: function () { + return callNikkiProfile(); + }, + updateSubscription: function (section_id) { return callNikkiUpdateSubscription(section_id); }, api: async function (method, path, query, body) { - const apiPort = uci.get('nikki', 'mixin', 'api_port'); - const apiSecret = uci.get('nikki', 'mixin', 'api_secret'); + const apiListen = uci.get('nikki', 'mixin', 'api_listen'); + const apiSecret = uci.get('nikki', 'mixin', 'api_secret') ?? ''; + const apiPort = apiListen.substring(apiListen.lastIndexOf(':') + 1); const url = `http://${window.location.hostname}:${apiPort}${path}`; return request.request(url, { method: method, @@ -100,10 +111,11 @@ return baseclass.extend({ }) }, - openDashboard: function () { + openDashboard: async function () { const uiName = uci.get('nikki', 'mixin', 'ui_name'); - const apiPort = uci.get('nikki', 'mixin', 'api_port'); - const apiSecret = encodeURIComponent(uci.get('nikki', 'mixin', 'api_secret')); + const apiListen = uci.get('nikki', 'mixin', 'api_listen'); + const apiSecret = encodeURIComponent(uci.get('nikki', 'mixin', 'api_secret') ?? ''); + const apiPort = apiListen.substring(apiListen.lastIndexOf(':') + 1); const params = { host: window.location.hostname, hostname: window.location.hostname, diff --git a/small/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js b/small/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js index 22843df45b..8f3d11f2af 100644 --- a/small/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js +++ b/small/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js @@ -18,103 +18,104 @@ return view.extend({ m = new form.Map('nikki'); - s = m.section(form.NamedSection, 'config', 'config', _('Mixin Config')); - - o = s.option(form.Flag, 'mixin', _('Enable')); - o.rmempty = false; - s = m.section(form.NamedSection, 'mixin', 'mixin', _('Mixin Option')); s.tab('general', _('General Config')); - o = s.taboption('general', form.ListValue, 'log_level', '*' + ' ' + _('Log Level')); + o = s.taboption('general', form.ListValue, 'log_level', _('Log Level')); + o.optional = true; o.value('silent'); o.value('error'); o.value('warning'); o.value('info'); o.value('debug'); - o = s.taboption('general', form.ListValue, 'mode', '*' + ' ' + _('Mode')); + o = s.taboption('general', form.ListValue, 'mode', _('Mode')); + o.optional = true; o.value('global', _('Global Mode')); o.value('rule', _('Rule Mode')); o.value('direct', _('Direct Mode')); - o = s.taboption('general', form.ListValue, 'match_process', '*' + ' ' + _('Match Process')); - o.value('strict', _('Auto')); - o.value('always', _('Enable')); - o.value('off', _('Disable')); + o = s.taboption('general', form.ListValue, 'match_process', _('Match Process')); + o.optional = true; + o.value('off'); + o.value('strict'); + o.value('always'); - o = s.taboption('general', widgets.NetworkSelect, 'outbound_interface', '*' + ' ' + _('Outbound Interface')); + o = s.taboption('general', widgets.NetworkSelect, 'outbound_interface', _('Outbound Interface')); o.optional = true; - o = s.taboption('general', form.Flag, 'ipv6', '*' + ' ' + _('IPv6')); - o.rmempty = false; + o = s.taboption('general', form.ListValue, 'ipv6', _('IPv6')); + o.optional = true; + o.value('0', _('Disable')); + o.value('1', _('Enable')); - o = s.taboption('general', form.Flag, 'unify_delay', _('Unify Delay')); - o.rmempty = false; + o = s.taboption('general', form.ListValue, 'unify_delay', _('Unify Delay')); + o.optional = true; + o.value('0', _('Disable')); + o.value('1', _('Enable')); - o = s.taboption('general', form.Flag, 'tcp_concurrent', _('TCP Concurrent')); - o.rmempty = false; + o = s.taboption('general', form.ListValue, 'tcp_concurrent', _('TCP Concurrent')); + o.optional = true; + o.value('0', _('Disable')); + o.value('1', _('Enable')); o = s.taboption('general', form.Value, 'tcp_keep_alive_idle', _('TCP Keep Alive Idle')); o.datatype = 'uinteger'; - o.placeholder = '600'; o = s.taboption('general', form.Value, 'tcp_keep_alive_interval', _('TCP Keep Alive Interval')); o.datatype = 'uinteger'; - o.placeholder = '15'; s.tab('external_control', _('External Control Config')); o = s.taboption('external_control', form.Value, 'ui_path', '*' + ' ' + _('UI Path')); o.rmempty = false; - o = s.taboption('external_control', form.Value, 'ui_name', '*' + ' ' + _('UI Name')); + o = s.taboption('external_control', form.Value, 'ui_name', _('UI Name')); - o = s.taboption('external_control', form.Value, 'ui_url', '*' + ' ' + _('UI Url')); - o.rmempty = false; + o = s.taboption('external_control', form.Value, 'ui_url', _('UI Url')); o.value('https://github.com/Zephyruso/zashboard/archive/refs/heads/gh-pages.zip', 'Zashboard'); o.value('https://github.com/MetaCubeX/metacubexd/archive/refs/heads/gh-pages.zip', 'MetaCubeXD'); o.value('https://github.com/MetaCubeX/Yacd-meta/archive/refs/heads/gh-pages.zip', 'YACD'); o.value('https://github.com/MetaCubeX/Razord-meta/archive/refs/heads/gh-pages.zip', 'Razord'); - o = s.taboption('external_control', form.Value, 'api_port', '*' + ' ' + _('API Port')); - o.datatype = 'port'; - o.placeholder = '9090'; + o = s.taboption('external_control', form.Value, 'api_listen', '*' + ' ' + _('API Listen')); + o.datatype = 'ipaddrport(1)'; + o.rmempty = false; - o = s.taboption('external_control', form.Value, 'api_secret', '*' + ' ' + _('API Secret')); + o = s.taboption('external_control', form.Value, 'api_secret', _('API Secret')); o.password = true; - o.rmempty = false; - o = s.taboption('external_control', form.Flag, 'selection_cache', '*' + ' ' + _('Save Proxy Selection')); - o.rmempty = false; + o = s.taboption('external_control', form.ListValue, 'selection_cache', _('Save Proxy Selection')); + o.optional = true; + o.value('0', _('Disable')); + o.value('1', _('Enable')); s.tab('inbound', _('Inbound Config')); - o = s.taboption('inbound', form.Flag, 'allow_lan', '*' + ' ' + _('Allow Lan')); - o.rmempty = false; + o = s.taboption('inbound', form.ListValue, 'allow_lan', _('Allow Lan')); + o.optional = true; + o.value('0', _('Disable')); + o.value('1', _('Enable')); - o = s.taboption('inbound', form.Value, 'http_port', '*' + ' ' + _('HTTP Port')); + o = s.taboption('inbound', form.Value, 'http_port', _('HTTP Port')); o.datatype = 'port'; - o.placeholder = '8080'; - o = s.taboption('inbound', form.Value, 'socks_port', '*' + ' ' + _('SOCKS Port')); + o = s.taboption('inbound', form.Value, 'socks_port', _('SOCKS Port')); o.datatype = 'port'; - o.placeholder = '1080'; - o = s.taboption('inbound', form.Value, 'mixed_port', '*' + ' ' + _('Mixed Port')); + o = s.taboption('inbound', form.Value, 'mixed_port', _('Mixed Port')); o.datatype = 'port'; - o.placeholder = '7890'; o = s.taboption('inbound', form.Value, 'redir_port', '*' + ' ' + _('Redirect Port')); o.datatype = 'port'; - o.placeholder = '7891'; + o.rmempty = false; o = s.taboption('inbound', form.Value, 'tproxy_port', '*' + ' ' + _('TPROXY Port')); o.datatype = 'port'; - o.placeholder = '7892'; + o.rmempty = false; - o = s.taboption('inbound', form.Flag, 'authentication', '*' + ' ' + _('Overwrite Authentication')); + o = s.taboption('inbound', form.Flag, 'authentication', _('Overwrite Authentication')); o.rmempty = false; o = s.taboption('inbound', form.SectionValue, '_authentications', form.TableSection, 'authentication', _('Edit Authentications')); @@ -137,90 +138,97 @@ return view.extend({ s.tab('tun', _('TUN Config')); - o = s.taboption('tun', form.Value, 'tun_device', '*' + ' ' + _('Device')); + o = s.taboption('tun', form.Value, 'tun_device', '*' + ' ' + _('Device Name')); o.rmempty = false; - o = s.taboption('tun', form.ListValue, 'tun_stack', '*' + ' ' + _('Stack')); + o = s.taboption('tun', form.ListValue, 'tun_stack', _('Stack')); + o.optional = true; o.value('system', 'System'); o.value('gvisor', 'gVisor'); o.value('mixed', 'Mixed'); - o = s.taboption('tun', form.Value, 'tun_mtu', '*' + ' ' + _('MTU')); + o = s.taboption('tun', form.Value, 'tun_mtu', _('MTU')); o.datatype = 'uinteger'; - o.placeholder = '9000'; - o = s.taboption('tun', form.Flag, 'tun_gso', '*' + ' ' + _('GSO')); - o.rmempty = false; + o = s.taboption('tun', form.ListValue, 'tun_gso', _('GSO')); + o.optional = true; + o.value('0', _('Disable')); + o.value('1', _('Enable')); - o = s.taboption('tun', form.Value, 'tun_gso_max_size', '*' + ' ' + _('GSO Max Size')); + o = s.taboption('tun', form.Value, 'tun_gso_max_size', _('GSO Max Size')); o.datatype = 'uinteger'; - o.placeholder = '65536'; + + o = s.taboption('tun', form.ListValue, 'tun_endpoint_independent_nat', _('Endpoint Independent NAT')); + o.optional = true; + o.value('0', _('Disable')); + o.value('1', _('Enable')); + + o = s.taboption('tun', form.Flag, 'tun_dns_hijack', _('Overwrite DNS Hijack')); + o.rmempty = false; + + o = s.taboption('tun', form.DynamicList, 'tun_dns_hijacks', _('Edit DNS Hijacks')); o.retain = true; - o.depends('tun_gso', '1'); - - o = s.taboption('tun', form.Flag, 'tun_endpoint_independent_nat', '*' + ' ' + _('Endpoint Independent NAT')); - o.rmempty = false; - - o = s.taboption('tun', form.Flag, 'tun_dns_hijack', '*' + ' ' + _('Overwrite DNS Hijack')); - o.rmempty = false; - - o = s.taboption('tun', form.DynamicList, 'tun_dns_hijacks', '*' + ' ' + _('Edit DNS Hijacks')); - o.retain = true; - o.rmempty = false; o.depends('tun_dns_hijack', '1'); o.value('tcp://any:53'); o.value('udp://any:53'); s.tab('dns', _('DNS Config')); - o = s.taboption('dns', form.Value, 'dns_port', '*' + ' ' + _('DNS Port')); - o.datatype = 'port'; - o.placeholder = '1053'; - - o = s.taboption('dns', form.Flag, 'dns_ipv6', '*' + ' ' + _('IPv6')); + o = s.taboption('dns', form.Value, 'dns_listen', '*' + ' ' + _('DNS Listen')); + o.datatype = 'ipaddrport(1)'; o.rmempty = false; + o = s.taboption('dns', form.ListValue, 'dns_ipv6', _('IPv6')); + o.optional = true; + o.value('0', _('Disable')); + o.value('1', _('Enable')); + o = s.taboption('dns', form.ListValue, 'dns_mode', '*' + ' ' + _('DNS Mode')); - o.value('fake-ip', 'Fake-IP'); o.value('redir-host', 'Redir-Host'); + o.value('fake-ip', 'Fake-IP'); o = s.taboption('dns', form.Value, 'fake_ip_range', '*' + ' ' + _('Fake-IP Range')); o.datatype = 'cidr4'; - o.placeholder = '198.18.0.1/16'; o.retain = true; + o.rmempty = false; o.depends('dns_mode', 'fake-ip'); o = s.taboption('dns', form.Flag, 'fake_ip_filter', _('Overwrite Fake-IP Filter')); - o.retain = true; o.rmempty = false; - o.depends('dns_mode', 'fake-ip'); o = s.taboption('dns', form.DynamicList, 'fake_ip_filters', _('Edit Fake-IP Filters')); o.retain = true; - o.depends({ 'dns_mode': 'fake-ip', 'fake_ip_filter': '1' }); + o.depends('fake_ip_filter', '1'); o = s.taboption('dns', form.ListValue, 'fake_ip_filter_mode', _('Fake-IP Filter Mode')); - o.retain = true; + o.optional = true; o.value('blacklist', _('Block Mode')); o.value('whitelist', _('Allow Mode')); - o.depends({ 'dns_mode': 'fake-ip', 'fake_ip_filter': '1' }); - o = s.taboption('dns', form.Flag, 'fake_ip_cache', '*' + ' ' + _('Fake-IP Cache')); - o.retain = true; - o.rmempty = false; - o.depends('dns_mode', 'fake-ip'); + o = s.taboption('dns', form.ListValue, 'fake_ip_cache', _('Fake-IP Cache')); + o.optional = true; + o.value('0', _('Disable')); + o.value('1', _('Enable')); - o = s.taboption('dns', form.Flag, 'dns_respect_rules', _('Respect Rules')); - o.rmempty = false; + o = s.taboption('dns', form.ListValue, 'dns_respect_rules', _('Respect Rules')); + o.optional = true; + o.value('0', _('Disable')); + o.value('1', _('Enable')); - o = s.taboption('dns', form.Flag, 'dns_doh_prefer_http3', _('DoH Prefer HTTP/3')); - o.rmempty = false; + o = s.taboption('dns', form.ListValue, 'dns_doh_prefer_http3', _('DoH Prefer HTTP/3')); + o.optional = true; + o.value('0', _('Disable')); + o.value('1', _('Enable')); - o = s.taboption('dns', form.Flag, 'dns_system_hosts', _('Use System Hosts')); - o.rmempty = false; + o = s.taboption('dns', form.ListValue, 'dns_system_hosts', _('Use System Hosts')); + o.optional = true; + o.value('0', _('Disable')); + o.value('1', _('Enable')); - o = s.taboption('dns', form.Flag, 'dns_hosts', _('Use Hosts')); - o.rmempty = false; + o = s.taboption('dns', form.ListValue, 'dns_hosts', _('Use Hosts')); + o.optional = true; + o.value('0', _('Disable')); + o.value('1', _('Enable')); o = s.taboption('dns', form.Flag, 'hosts', _('Overwrite Hosts')); o.rmempty = false; @@ -285,17 +293,20 @@ return view.extend({ s.tab('sniffer', _('Sniffer Config')); - o = s.taboption('sniffer', form.Flag, 'sniffer', _('Enable')); - o.rmempty = false; + o = s.taboption('sniffer', form.ListValue, 'sniffer', _('Enable')); + o.optional = true; + o.value('0', _('Disable')); + o.value('1', _('Enable')); - o = s.taboption('sniffer', form.Flag, 'sniffer_sniff_dns_mapping', _('Sniff Redir-Host')); - o.rmempty = false; + o = s.taboption('sniffer', form.ListValue, 'sniffer_sniff_dns_mapping', _('Sniff Redir-Host')); + o.optional = true; + o.value('0', _('Disable')); + o.value('1', _('Enable')); - o = s.taboption('sniffer', form.Flag, 'sniffer_sniff_pure_ip', _('Sniff Pure IP')); - o.rmempty = false; - - o = s.taboption('sniffer', form.Flag, 'sniffer_overwrite_destination', _('Overwrite Destination')); - o.rmempty = false; + o = s.taboption('sniffer', form.ListValue, 'sniffer_sniff_pure_ip', _('Sniff Pure IP')); + o.optional = true; + o.value('0', _('Disable')); + o.value('1', _('Enable')); o = s.taboption('sniffer', form.Flag, 'sniffer_force_domain_name', _('Overwrite Force Sniff Domain Name')); o.rmempty = false; @@ -336,7 +347,7 @@ return view.extend({ s.tab('rule', _('Rule Config')); - o = s.taboption('rule', form.Flag, 'rule_provider', '*' + ' ' + _('Append Rule Provider')); + o = s.taboption('rule', form.Flag, 'rule_provider', _('Append Rule Provider')); o.rmempty = false; o = s.taboption('rule', form.SectionValue, '_rule_providers', form.GridSection, 'rule_provider', _('Edit Rule Providers')); @@ -405,7 +416,7 @@ return view.extend({ so.modalonly = true; so.depends('type', 'http'); - o = s.taboption('rule', form.Flag, 'rule', '*' + ' ' + _('Append Rule')); + o = s.taboption('rule', form.Flag, 'rule', _('Append Rule')); o.rmempty = false; o = s.taboption('rule', form.SectionValue, '_rules', form.TableSection, 'rule', _('Edit Rules')); @@ -421,8 +432,7 @@ return view.extend({ so.rmempty = false; so = o.subsection.option(form.Value, 'type', _('Type')); - so.optional = true; - so.rmempty = true; + so.rmempty = false; so.value('RULE-SET', _('Rule Set')); so.value('DOMAIN', _('Domain Name')); so.value('DOMAIN-SUFFIX', _('Domain Name Suffix')); @@ -453,37 +463,34 @@ return view.extend({ s.tab('geox', _('GeoX Config')); o = s.taboption('geox', form.ListValue, 'geoip_format', _('GeoIP Format')); + o.optional = true; o.value('dat', 'DAT'); o.value('mmdb', 'MMDB'); o = s.taboption('geox', form.ListValue, 'geodata_loader', _('GeoData Loader')); + o.optional = true; o.value('standard', _('Standard Loader')); o.value('memconservative', _('Memory Conservative Loader')); o = s.taboption('geox', form.Value, 'geosite_url', _('GeoSite Url')); - o.rmempty = false; o = s.taboption('geox', form.Value, 'geoip_mmdb_url', _('GeoIP(MMDB) Url')); - o.rmempty = false; o = s.taboption('geox', form.Value, 'geoip_dat_url', _('GeoIP(DAT) Url')); - o.rmempty = false; o = s.taboption('geox', form.Value, 'geoip_asn_url', _('GeoIP(ASN) Url')); - o.rmempty = false; - o = s.taboption('geox', form.Flag, 'geox_auto_update', _('GeoX Auto Update')); - o.rmempty = false; + o = s.taboption('geox', form.ListValue, 'geox_auto_update', _('GeoX Auto Update')); + o.optional = true; + o.value('0', _('Disable')); + o.value('1', _('Enable')); o = s.taboption('geox', form.Value, 'geox_update_interval', _('GeoX Update Interval')); o.datatype = 'uinteger'; - o.placeholder = '24'; - o.retain = true; - o.depends('geox_auto_update', '1'); s.tab('mixin_file_content', _('Mixin File Content')); - o = s.taboption('mixin_file_content', form.Flag, 'mixin_file_content', '*' + ' ' + _('Enable'), _('Please go to the editor tab to edit the file for mixin')); + o = s.taboption('mixin_file_content', form.Flag, 'mixin_file_content', _('Enable'), _('Please go to the editor tab to edit the file for mixin')); o.rmempty = false; return m.render(); diff --git a/small/luci-app-nikki/po/templates/nikki.pot b/small/luci-app-nikki/po/templates/nikki.pot index 175f406a0e..0d6b4dcb6a 100644 --- a/small/luci-app-nikki/po/templates/nikki.pot +++ b/small/luci-app-nikki/po/templates/nikki.pot @@ -1,11 +1,11 @@ msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:81 -msgid "API Port" +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:82 +msgid "API Listen" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:85 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:86 msgid "API Secret" msgstr "" @@ -22,11 +22,11 @@ msgstr "" msgid "All Port" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:94 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:96 msgid "Allow Lan" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:203 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:206 #: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/proxy.js:68 msgid "Allow Mode" msgstr "" @@ -44,23 +44,19 @@ msgstr "" msgid "App Version" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:409 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:419 msgid "Append Rule" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:340 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:350 msgid "Append Rule Provider" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:43 -msgid "Auto" -msgstr "" - -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:396 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:406 msgid "Behavior" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:202 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:205 #: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/proxy.js:69 msgid "Block Mode" msgstr "" @@ -123,31 +119,31 @@ msgstr "" msgid "Cron Expression" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:174 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:175 msgid "DNS Config" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:180 -msgid "DNS Mode" +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:177 +msgid "DNS Listen" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:176 -msgid "DNS Port" +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:186 +msgid "DNS Mode" msgstr "" #: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/log.js:93 msgid "Debug Log" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:432 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:441 msgid "Destination IP" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:436 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:445 msgid "Destination IP Geo" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:433 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:442 msgid "Destination Port" msgstr "" @@ -159,15 +155,31 @@ msgstr "" msgid "Destination UDP Port to Proxy" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:140 -msgid "Device" +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:141 +msgid "Device Name" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:40 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:37 msgid "Direct Mode" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:45 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:50 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:55 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:60 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:91 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:98 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:155 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:163 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:183 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:210 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:215 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:220 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:225 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:230 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:298 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:303 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:308 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:485 msgid "Disable" msgstr "" @@ -187,60 +199,60 @@ msgstr "" msgid "Disable Safe Path Check" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:214 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:218 msgid "DoH Prefer HTTP/3" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:240 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:428 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:247 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:437 msgid "Domain Name" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:435 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:444 msgid "Domain Name Geo" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:430 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:439 msgid "Domain Name Keyword" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:431 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:440 msgid "Domain Name Regex" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:429 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:438 msgid "Domain Name Suffix" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:120 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:121 msgid "Edit Authentications" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:164 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:169 msgid "Edit DNS Hijacks" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:196 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:199 msgid "Edit Fake-IP Filters" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:229 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:236 msgid "Edit Hosts" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:271 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:278 msgid "Edit Nameserver Policies" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:248 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:255 msgid "Edit Nameservers" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:343 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:353 msgid "Edit Rule Providers" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:412 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:422 msgid "Edit Rules" msgstr "" @@ -254,22 +266,37 @@ msgid "Editor" msgstr "" #: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/app.js:95 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:23 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:44 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:128 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:237 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:256 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:279 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:289 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:323 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:351 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:420 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:487 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:51 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:56 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:61 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:92 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:99 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:129 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:156 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:164 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:184 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:211 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:216 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:221 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:226 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:231 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:244 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:263 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:286 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:296 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:299 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:304 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:309 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:333 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:361 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:430 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:486 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:493 #: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/proxy.js:31 msgid "Enable" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:171 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:161 msgid "Endpoint Independent NAT" msgstr "" @@ -277,23 +304,23 @@ msgstr "" msgid "Expire At" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:67 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:69 msgid "External Control Config" msgstr "" +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:208 +msgid "Fake-IP Cache" +msgstr "" + +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:203 +msgid "Fake-IP Filter Mode" +msgstr "" + #: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/proxy.js:55 msgid "Fake-IP Ping Hijack" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:206 -msgid "Fake-IP Cache" -msgstr "" - -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:200 -msgid "Fake-IP Filter Mode" -msgstr "" - -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:185 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:190 msgid "Fake-IP Range" msgstr "" @@ -301,15 +328,15 @@ msgstr "" msgid "Fast Reload" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:390 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:400 msgid "File Format" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:384 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:394 msgid "File Path" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:378 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:388 msgid "File Size Limit" msgstr "" @@ -330,19 +357,19 @@ msgstr "" msgid "File:" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:304 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:314 msgid "Force Sniff Domain Name" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:152 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:153 msgid "GSO" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:155 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:158 msgid "GSO Max Size" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:28 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:23 msgid "General Config" msgstr "" @@ -350,43 +377,43 @@ msgstr "" msgid "Generate & Download" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:460 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:470 msgid "GeoData Loader" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:456 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:465 msgid "GeoIP Format" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:473 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:481 msgid "GeoIP(ASN) Url" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:470 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:479 msgid "GeoIP(DAT) Url" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:467 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:477 msgid "GeoIP(MMDB) Url" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:464 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:475 msgid "GeoSite Url" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:476 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:483 msgid "GeoX Auto Update" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:454 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:463 msgid "GeoX Config" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:479 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:488 msgid "GeoX Update Interval" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:38 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:35 msgid "Global Mode" msgstr "" @@ -394,7 +421,7 @@ msgstr "" msgid "Grant access to nikki procedures" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:97 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:101 msgid "HTTP Port" msgstr "" @@ -402,7 +429,7 @@ msgstr "" msgid "How To Use" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:243 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:250 msgid "IP" msgstr "" @@ -414,8 +441,8 @@ msgstr "" msgid "IPv4 Proxy" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:50 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:217 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:48 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:181 msgid "IPv6" msgstr "" @@ -427,11 +454,11 @@ msgstr "" msgid "IPv6 Proxy" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:310 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:320 msgid "Ignore Sniff Domain Name" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:92 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:94 msgid "Inbound Config" msgstr "" @@ -452,55 +479,54 @@ msgstr "" msgid "Log" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:30 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:25 msgid "Log Level" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:148 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:150 msgid "MTU" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:42 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:39 msgid "Match Process" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:282 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:438 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:289 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:447 msgid "Matcher" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:462 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:473 msgid "Memory Conservative Loader" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:105 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:107 msgid "Mixed Port" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:21 #: applications/luci-app-nikki/root/usr/share/luci/menu.d/luci-app-nikki.json:29 msgid "Mixin Config" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:485 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:491 msgid "Mixin File Content" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:26 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:21 msgid "Mixin Option" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:37 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:33 #: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/proxy.js:66 msgid "Mode" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:357 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:367 msgid "Name" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:266 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:285 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:273 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:292 msgid "Nameserver" msgstr "" @@ -509,12 +535,12 @@ msgstr "" msgid "Nikki" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:448 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:457 msgid "No Resolve" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:371 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:441 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:381 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:450 msgid "Node" msgstr "" @@ -526,60 +552,59 @@ msgstr "" msgid "Open Dashboard" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:47 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:45 msgid "Outbound Interface" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:117 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:118 msgid "Overwrite Authentication" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:161 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:166 msgid "Overwrite DNS Hijack" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:298 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:335 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:345 msgid "Overwrite Destination" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:191 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:196 msgid "Overwrite Fake-IP Filter" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:301 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:311 msgid "Overwrite Force Sniff Domain Name" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:226 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:233 msgid "Overwrite Hosts" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:307 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:317 msgid "Overwrite Ignore Sniff Domain Name" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:245 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:252 msgid "Overwrite Nameserver" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:268 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:275 msgid "Overwrite Nameserver Policy" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:313 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:323 msgid "Overwrite Sniff By Protocol" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:134 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:135 msgid "Password" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:487 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:493 msgid "Please go to the editor tab to edit the file for mixin" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:332 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:342 msgid "Port" msgstr "" @@ -587,7 +612,7 @@ msgstr "" msgid "Prefer" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:434 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:443 msgid "Process Name" msgstr "" @@ -600,7 +625,7 @@ msgstr "" msgid "Profile for Startup" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:326 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:336 msgid "Protocol" msgstr "" @@ -617,7 +642,7 @@ msgstr "" msgid "Redirect Mode" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:109 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:110 msgid "Redirect Port" msgstr "" @@ -629,7 +654,7 @@ msgstr "" msgid "Remote" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:211 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:213 msgid "Respect Rules" msgstr "" @@ -641,11 +666,11 @@ msgstr "" msgid "Router Proxy" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:338 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:348 msgid "Rule Config" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:39 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:36 msgid "Rule Mode" msgstr "" @@ -653,7 +678,7 @@ msgstr "" msgid "Rule Provider:" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:427 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:436 msgid "Rule Set" msgstr "" @@ -661,7 +686,7 @@ msgstr "" msgid "Running" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:101 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:104 msgid "SOCKS Port" msgstr "" @@ -678,27 +703,27 @@ msgstr "" msgid "Scroll To Bottom" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:316 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:326 msgid "Sniff By Protocol" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:295 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:306 msgid "Sniff Pure IP" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:292 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:301 msgid "Sniff Redir-Host" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:287 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:294 msgid "Sniffer Config" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:143 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:144 msgid "Stack" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:461 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:472 msgid "Standard Loader" msgstr "" @@ -727,15 +752,15 @@ msgstr "" msgid "Subscription:" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:56 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:58 msgid "TCP Concurrent" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:59 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:63 msgid "TCP Keep Alive Idle" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:63 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:66 msgid "TCP Keep Alive Interval" msgstr "" @@ -748,11 +773,11 @@ msgstr "" msgid "TPROXY Mode" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:113 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:114 msgid "TPROXY Port" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:138 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:139 msgid "TUN Config" msgstr "" @@ -777,9 +802,9 @@ msgstr "" msgid "Transparent Proxy with Mihomo on OpenWrt." msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:259 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:360 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:424 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:266 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:370 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:434 msgid "Type" msgstr "" @@ -787,15 +812,15 @@ msgstr "" msgid "UDP Proxy Mode" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:72 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:74 msgid "UI Name" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:69 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:71 msgid "UI Path" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:74 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:76 msgid "UI Url" msgstr "" @@ -815,7 +840,7 @@ msgstr "" msgid "Update Dashboard" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:403 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:413 msgid "Update Interval" msgstr "" @@ -823,15 +848,15 @@ msgstr "" msgid "Upload Profile" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:366 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:376 msgid "Url" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:223 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:228 msgid "Use Hosts" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:220 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:223 msgid "Use System Hosts" msgstr "" @@ -843,6 +868,6 @@ msgstr "" msgid "User Agent" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:131 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:132 msgid "Username" msgstr "" diff --git a/small/luci-app-nikki/po/zh_Hans/nikki.po b/small/luci-app-nikki/po/zh_Hans/nikki.po index ac148bc7fd..1557a7e5b7 100644 --- a/small/luci-app-nikki/po/zh_Hans/nikki.po +++ b/small/luci-app-nikki/po/zh_Hans/nikki.po @@ -8,11 +8,11 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:81 -msgid "API Port" -msgstr "API 端口" +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:82 +msgid "API Listen" +msgstr "API 监听" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:85 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:86 msgid "API Secret" msgstr "API 密钥" @@ -29,11 +29,11 @@ msgstr "全部模式" msgid "All Port" msgstr "全部端口" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:94 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:96 msgid "Allow Lan" msgstr "允许局域网访问" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:203 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:206 #: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/proxy.js:68 msgid "Allow Mode" msgstr "白名单模式" @@ -51,23 +51,19 @@ msgstr "插件日志" msgid "App Version" msgstr "插件版本" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:409 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:419 msgid "Append Rule" msgstr "追加规则" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:340 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:350 msgid "Append Rule Provider" msgstr "追加规则提供者" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:43 -msgid "Auto" -msgstr "自动" - -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:396 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:406 msgid "Behavior" msgstr "行为" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:202 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:205 #: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/proxy.js:69 msgid "Block Mode" msgstr "黑名单模式" @@ -130,31 +126,31 @@ msgstr "核心版本" msgid "Cron Expression" msgstr "Cron 表达式" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:174 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:175 msgid "DNS Config" msgstr "DNS 配置" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:180 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:177 +msgid "DNS Listen" +msgstr "DNS 监听" + +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:186 msgid "DNS Mode" msgstr "DNS 模式" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:176 -msgid "DNS Port" -msgstr "DNS 端口" - #: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/log.js:93 msgid "Debug Log" msgstr "调试日志" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:432 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:441 msgid "Destination IP" msgstr "目标 IP" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:436 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:445 msgid "Destination IP Geo" msgstr "目标 IP(Geo)" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:433 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:442 msgid "Destination Port" msgstr "目标端口" @@ -166,15 +162,31 @@ msgstr "要代理的 TCP 目标端口" msgid "Destination UDP Port to Proxy" msgstr "要代理的 UDP 目标端口" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:140 -msgid "Device" +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:141 +msgid "Device Name" msgstr "设备名称" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:40 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:37 msgid "Direct Mode" msgstr "直连模式" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:45 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:50 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:55 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:60 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:91 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:98 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:155 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:163 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:183 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:210 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:215 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:220 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:225 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:230 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:298 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:303 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:308 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:485 msgid "Disable" msgstr "禁用" @@ -194,60 +206,60 @@ msgstr "禁用回环检测" msgid "Disable Safe Path Check" msgstr "禁用安全路径检查" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:214 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:218 msgid "DoH Prefer HTTP/3" msgstr "DoH 优先 HTTP/3" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:240 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:428 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:247 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:437 msgid "Domain Name" msgstr "域名" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:435 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:444 msgid "Domain Name Geo" msgstr "域名(Geo)" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:430 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:439 msgid "Domain Name Keyword" msgstr "域名(关键字)" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:431 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:440 msgid "Domain Name Regex" msgstr "域名(正则表达式)" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:429 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:438 msgid "Domain Name Suffix" msgstr "域名(后缀)" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:120 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:121 msgid "Edit Authentications" msgstr "编辑身份验证" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:164 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:169 msgid "Edit DNS Hijacks" msgstr "编辑 DNS 劫持" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:196 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:199 msgid "Edit Fake-IP Filters" msgstr "编辑 Fake-IP 过滤列表" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:229 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:236 msgid "Edit Hosts" msgstr "编辑 Hosts" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:271 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:278 msgid "Edit Nameserver Policies" msgstr "编辑 DNS 服务器查询策略" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:248 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:255 msgid "Edit Nameservers" msgstr "编辑 DNS 服务器" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:343 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:353 msgid "Edit Rule Providers" msgstr "编辑规则提供者" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:412 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:422 msgid "Edit Rules" msgstr "编辑规则" @@ -261,22 +273,37 @@ msgid "Editor" msgstr "编辑器" #: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/app.js:95 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:23 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:44 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:128 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:237 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:256 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:279 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:289 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:323 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:351 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:420 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:487 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:51 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:56 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:61 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:92 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:99 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:129 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:156 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:164 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:184 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:211 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:216 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:221 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:226 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:231 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:244 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:263 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:286 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:296 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:299 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:304 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:309 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:333 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:361 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:430 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:486 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:493 #: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/proxy.js:31 msgid "Enable" msgstr "启用" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:171 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:161 msgid "Endpoint Independent NAT" msgstr "独立于端点的 NAT" @@ -284,23 +311,23 @@ msgstr "独立于端点的 NAT" msgid "Expire At" msgstr "到期时间" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:67 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:69 msgid "External Control Config" msgstr "外部控制配置" +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:208 +msgid "Fake-IP Cache" +msgstr "Fake-IP 缓存" + +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:203 +msgid "Fake-IP Filter Mode" +msgstr "Fake-IP 过滤模式" + #: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/proxy.js:55 msgid "Fake-IP Ping Hijack" msgstr "Fake-IP Ping 劫持" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:206 -msgid "Fake-IP Cache" -msgstr "Fake-IP 缓存" - -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:200 -msgid "Fake-IP Filter Mode" -msgstr "Fake-IP 过滤模式" - -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:185 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:190 msgid "Fake-IP Range" msgstr "Fake-IP 范围" @@ -308,15 +335,15 @@ msgstr "Fake-IP 范围" msgid "Fast Reload" msgstr "快速重载" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:390 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:400 msgid "File Format" msgstr "文件格式" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:384 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:394 msgid "File Path" msgstr "文件路径" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:378 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:388 msgid "File Size Limit" msgstr "文件大小限制" @@ -337,19 +364,19 @@ msgstr "IPv6 保留地址" msgid "File:" msgstr "文件:" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:304 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:314 msgid "Force Sniff Domain Name" msgstr "强制嗅探的域名" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:152 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:153 msgid "GSO" msgstr "通用分段卸载" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:155 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:158 msgid "GSO Max Size" msgstr "分段最大长度" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:28 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:23 msgid "General Config" msgstr "全局配置" @@ -357,43 +384,43 @@ msgstr "全局配置" msgid "Generate & Download" msgstr "生成并下载" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:460 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:470 msgid "GeoData Loader" msgstr "GeoData 加载器" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:456 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:465 msgid "GeoIP Format" msgstr "GeoIP 格式" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:473 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:481 msgid "GeoIP(ASN) Url" msgstr "GeoIP(ASN) 下载地址" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:470 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:479 msgid "GeoIP(DAT) Url" msgstr "GeoIP(DAT) 下载地址" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:467 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:477 msgid "GeoIP(MMDB) Url" msgstr "GeoIP(MMDB) 下载地址" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:464 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:475 msgid "GeoSite Url" msgstr "GeoSite 下载地址" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:476 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:483 msgid "GeoX Auto Update" msgstr "定时更新GeoX文件" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:454 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:463 msgid "GeoX Config" msgstr "GeoX 配置" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:479 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:488 msgid "GeoX Update Interval" msgstr "GeoX 文件更新间隔" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:38 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:35 msgid "Global Mode" msgstr "全局模式" @@ -401,7 +428,7 @@ msgstr "全局模式" msgid "Grant access to nikki procedures" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:97 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:101 msgid "HTTP Port" msgstr "HTTP 端口" @@ -409,7 +436,7 @@ msgstr "HTTP 端口" msgid "How To Use" msgstr "使用说明" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:243 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:250 msgid "IP" msgstr "" @@ -421,8 +448,8 @@ msgstr "IPv4 DNS 劫持" msgid "IPv4 Proxy" msgstr "IPv4 代理" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:50 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:217 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:48 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:181 msgid "IPv6" msgstr "" @@ -434,11 +461,11 @@ msgstr "IPv6 DNS 劫持" msgid "IPv6 Proxy" msgstr "IPv6 代理" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:310 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:320 msgid "Ignore Sniff Domain Name" msgstr "忽略嗅探的域名" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:92 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:94 msgid "Inbound Config" msgstr "入站配置" @@ -459,55 +486,54 @@ msgstr "本地" msgid "Log" msgstr "日志" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:30 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:25 msgid "Log Level" msgstr "日志级别" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:148 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:150 msgid "MTU" msgstr "最大传输单元" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:42 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:39 msgid "Match Process" msgstr "匹配进程" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:282 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:438 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:289 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:447 msgid "Matcher" msgstr "匹配" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:462 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:473 msgid "Memory Conservative Loader" msgstr "为内存受限设备优化的加载器" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:105 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:107 msgid "Mixed Port" msgstr "混合端口" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:21 #: applications/luci-app-nikki/root/usr/share/luci/menu.d/luci-app-nikki.json:29 msgid "Mixin Config" msgstr "混入配置" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:485 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:491 msgid "Mixin File Content" msgstr "混入文件内容" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:26 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:21 msgid "Mixin Option" msgstr "混入选项" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:37 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:33 #: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/proxy.js:66 msgid "Mode" msgstr "模式" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:357 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:367 msgid "Name" msgstr "名称" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:266 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:285 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:273 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:292 msgid "Nameserver" msgstr "DNS 服务器" @@ -516,12 +542,12 @@ msgstr "DNS 服务器" msgid "Nikki" msgstr "" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:448 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:457 msgid "No Resolve" msgstr "不解析" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:371 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:441 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:381 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:450 msgid "Node" msgstr "节点" @@ -533,60 +559,59 @@ msgstr "未在运行" msgid "Open Dashboard" msgstr "打开面板" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:47 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:45 msgid "Outbound Interface" msgstr "出站接口" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:117 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:118 msgid "Overwrite Authentication" msgstr "覆盖身份验证" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:161 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:166 msgid "Overwrite DNS Hijack" msgstr "覆盖 DNS 劫持" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:298 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:335 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:345 msgid "Overwrite Destination" msgstr "将嗅探结果作为连接目标" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:191 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:196 msgid "Overwrite Fake-IP Filter" msgstr "覆盖 Fake-IP 过滤列表" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:301 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:311 msgid "Overwrite Force Sniff Domain Name" msgstr "覆盖强制嗅探的域名" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:226 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:233 msgid "Overwrite Hosts" msgstr "覆盖 Hosts" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:307 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:317 msgid "Overwrite Ignore Sniff Domain Name" msgstr "覆盖忽略嗅探的域名" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:245 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:252 msgid "Overwrite Nameserver" msgstr "覆盖 DNS 服务器" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:268 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:275 msgid "Overwrite Nameserver Policy" msgstr "覆盖 DNS 服务器查询策略" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:313 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:323 msgid "Overwrite Sniff By Protocol" msgstr "覆盖按协议嗅探" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:134 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:135 msgid "Password" msgstr "密码" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:487 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:493 msgid "Please go to the editor tab to edit the file for mixin" msgstr "请前往编辑器标签编辑用于混入的文件" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:332 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:342 msgid "Port" msgstr "端口" @@ -594,7 +619,7 @@ msgstr "端口" msgid "Prefer" msgstr "优先" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:434 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:443 msgid "Process Name" msgstr "进程名" @@ -607,7 +632,7 @@ msgstr "配置文件" msgid "Profile for Startup" msgstr "用于启动的配置文件" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:326 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:336 msgid "Protocol" msgstr "协议" @@ -624,7 +649,7 @@ msgstr "代理提供者:" msgid "Redirect Mode" msgstr "Redirect 模式" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:109 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:110 msgid "Redirect Port" msgstr "Redirect 端口" @@ -636,7 +661,7 @@ msgstr "重载服务" msgid "Remote" msgstr "远程" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:211 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:213 msgid "Respect Rules" msgstr "遵循分流规则" @@ -648,11 +673,11 @@ msgstr "重启服务" msgid "Router Proxy" msgstr "路由器代理" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:338 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:348 msgid "Rule Config" msgstr "规则配置" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:39 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:36 msgid "Rule Mode" msgstr "规则模式" @@ -660,7 +685,7 @@ msgstr "规则模式" msgid "Rule Provider:" msgstr "规则提供者:" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:427 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:436 msgid "Rule Set" msgstr "规则集" @@ -668,7 +693,7 @@ msgstr "规则集" msgid "Running" msgstr "运行中" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:101 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:104 msgid "SOCKS Port" msgstr "SOCKS 端口" @@ -685,27 +710,27 @@ msgstr "定时重启" msgid "Scroll To Bottom" msgstr "滚动到底部" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:316 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:326 msgid "Sniff By Protocol" msgstr "按协议嗅探" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:295 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:306 msgid "Sniff Pure IP" msgstr "嗅探纯 IP 连接" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:292 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:301 msgid "Sniff Redir-Host" msgstr "嗅探 Redir-Host 流量" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:287 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:294 msgid "Sniffer Config" msgstr "嗅探器配置" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:143 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:144 msgid "Stack" msgstr "栈" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:461 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:472 msgid "Standard Loader" msgstr "标准加载器" @@ -734,15 +759,15 @@ msgstr "订阅链接" msgid "Subscription:" msgstr "订阅:" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:56 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:58 msgid "TCP Concurrent" msgstr "TCP 并发" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:59 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:63 msgid "TCP Keep Alive Idle" msgstr "TCP Keep Alive 空闲" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:63 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:66 msgid "TCP Keep Alive Interval" msgstr "TCP Keep Alive 间隔" @@ -755,11 +780,11 @@ msgstr "TCP 代理模式" msgid "TPROXY Mode" msgstr "TPROXY 模式" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:113 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:114 msgid "TPROXY Port" msgstr "TPROXY 端口" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:138 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:139 msgid "TUN Config" msgstr "TUN 配置" @@ -784,9 +809,9 @@ msgstr "透明代理" msgid "Transparent Proxy with Mihomo on OpenWrt." msgstr "在 OpenWrt 上使用 Mihomo 进行透明代理。" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:259 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:360 -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:424 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:266 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:370 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:434 msgid "Type" msgstr "类型" @@ -794,15 +819,15 @@ msgstr "类型" msgid "UDP Proxy Mode" msgstr "UDP 代理模式" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:72 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:74 msgid "UI Name" msgstr "UI 名称" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:69 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:71 msgid "UI Path" msgstr "UI 路径" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:74 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:76 msgid "UI Url" msgstr "UI 下载地址" @@ -822,7 +847,7 @@ msgstr "更新时间" msgid "Update Dashboard" msgstr "更新面板" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:403 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:413 msgid "Update Interval" msgstr "更新间隔" @@ -830,15 +855,15 @@ msgstr "更新间隔" msgid "Upload Profile" msgstr "上传配置文件" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:366 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:376 msgid "Url" msgstr "下载地址" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:223 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:228 msgid "Use Hosts" msgstr "使用 Hosts" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:220 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:223 msgid "Use System Hosts" msgstr "使用系统的 Hosts" @@ -850,6 +875,6 @@ msgstr "已使用" msgid "User Agent" msgstr "用户代理(UA)" -#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:131 +#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:132 msgid "Username" msgstr "用户名" diff --git a/small/luci-app-nikki/root/usr/share/rpcd/ucode/luci.nikki b/small/luci-app-nikki/root/usr/share/rpcd/ucode/luci.nikki index 4099775d6d..d9fac62670 100644 --- a/small/luci-app-nikki/root/usr/share/rpcd/ucode/luci.nikki +++ b/small/luci-app-nikki/root/usr/share/rpcd/ucode/luci.nikki @@ -2,7 +2,7 @@ 'use strict'; -import { popen } from 'fs'; +import { access, popen } from 'fs'; const methods = { version: { @@ -28,15 +28,29 @@ const methods = { core = trim(process.read('all')); process.close(); } - return { success: true, app: app, core: core }; + return { app: app, core: core }; + } + }, + profile: { + call: function() { + let profile = {}; + const filepath = '/etc/nikki/run/config.yaml'; + if (access(filepath, 'r')) { + const process = popen(`yq -p yaml -o json < ${filepath}`); + if (process != null) { + profile = json(process.read('all')); + process.close(); + } + } + return profile; } }, update_subscription: { args: { section_id: 'section_id' }, call: function(req) { let success = false; - if (req.args?.section_id) { - const section_id = req.args?.section_id; + const section_id = req.args?.section_id; + if (section_id) { success = system(['service', 'nikki', 'update_subscription', section_id]) == 0; } return { success: success }; diff --git a/small/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua b/small/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua index 95906fe9bb..1394160e9a 100644 --- a/small/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua +++ b/small/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua @@ -296,9 +296,14 @@ end if is_finded("xray-plugin") then o:value("xray-plugin", translate("xray-plugin")) end +o:value("custom", translate("Custom")) o.rmempty = true o:depends({type = "ss", enable_plugin = true}) +o = s:option(Value, "custom_plugin", translate("Custom Plugin Path")) +o.placeholder = "/path/to/custom-plugin" +o:depends({plugin = "custom"}) + o = s:option(Value, "plugin_opts", translate("Plugin Opts")) o.rmempty = true o:depends({type = "ss", enable_plugin = true}) diff --git a/small/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po b/small/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po index b8580d2879..8d7a2d8307 100644 --- a/small/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po +++ b/small/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po @@ -849,6 +849,12 @@ msgstr "启用插件" msgid "Plugin" msgstr "插件" +msgid "Custom" +msgstr "自定义" + +msgid "Custom Plugin Path" +msgstr "自定义插件路径" + msgid "Plugin Opts" msgstr "插件参数" diff --git a/small/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua b/small/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua index b19ddafaf6..dbb2a1f2bc 100755 --- a/small/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua +++ b/small/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua @@ -580,7 +580,11 @@ function config:handleIndex(index) ss = function() ss.protocol = socks_port if server.enable_plugin == "1" and server.plugin and server.plugin ~= "none" then - ss.plugin = server.plugin + if server.plugin == "custom" then + ss.plugin = server.custom_plugin + else + ss.plugin = server.plugin + end ss.plugin_opts = server.plugin_opts or nil end print(json.stringify(ss, 1)) diff --git a/small/mihomo/Makefile b/small/mihomo/Makefile index b223c18e92..2092ef5bbb 100644 --- a/small/mihomo/Makefile +++ b/small/mihomo/Makefile @@ -5,12 +5,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=mihomo -PKG_VERSION:=1.19.2 +PKG_VERSION:=1.19.3 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/metacubex/mihomo/tar.gz/v$(PKG_VERSION)? -PKG_HASH:=8afa33b5eb9fc20e521a986be5e21908b53858e4b2350b56e0bf3495b740c4dc +PKG_HASH:=47b78ceb8acab5a8c4d7da0b745f06becea4f8d4687d7a5b1985c0b1348e79c2 PKG_MAINTAINER:=Anya Lin PKG_LICENSE:=GPL-2.0 diff --git a/small/nikki/Makefile b/small/nikki/Makefile index 61c6a041c9..49bfc61d1f 100644 --- a/small/nikki/Makefile +++ b/small/nikki/Makefile @@ -1,13 +1,13 @@ include $(TOPDIR)/rules.mk PKG_NAME:=nikki -PKG_RELEASE:=7 +PKG_RELEASE:=1 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL:=https://github.com/MetaCubeX/mihomo.git -PKG_SOURCE_DATE:=2025-02-21 -PKG_SOURCE_VERSION:=5830afcbdeeb6c05a3faa56d33353282b8d1f50c -PKG_MIRROR_HASH:=3f5c8aaad3959f77ab3099e0a3d76ca7329e073e1f877720b7c42360c66954c9 +PKG_SOURCE_DATE:=2025-03-02 +PKG_SOURCE_VERSION:=a7e56f1c431b8f17f98eb4d81bfc784a5f1ebc4c +PKG_MIRROR_HASH:=e6ffc7355fadff8ae93151d016df9b61a618cd4a7125d06f8e1f63f3e70d7b74 PKG_LICENSE:=GPL3.0+ PKG_MAINTAINER:=Joseph Mory @@ -16,7 +16,7 @@ PKG_BUILD_DEPENDS:=golang/host PKG_BUILD_PARALLEL:=1 PKG_BUILD_FLAGS:=no-mips16 -PKG_BUILD_VERSION:=alpha-5830afc +PKG_BUILD_VERSION:=alpha-a7e56f1 PKG_BUILD_TIME:=$(shell date -u -Iseconds) GO_PKG:=github.com/metacubex/mihomo diff --git a/small/nikki/files/nikki.conf b/small/nikki/files/nikki.conf index 3c0eedd654..c0706f85ce 100644 --- a/small/nikki/files/nikki.conf +++ b/small/nikki/files/nikki.conf @@ -8,7 +8,6 @@ config config 'config' option 'scheduled_restart' '0' option 'cron_expression' '0 3 * * *' option 'test_profile' '1' - option 'mixin' '1' config proxy 'proxy' option 'transparent_proxy' '1' @@ -17,8 +16,8 @@ config proxy 'proxy' option 'ipv4_dns_hijack' '1' option 'ipv6_dns_hijack' '1' option 'ipv4_proxy' '1' - option 'ipv6_proxy' '0' - option 'fake_ip_ping_hijack' '0' + option 'ipv6_proxy' '1' + option 'fake_ip_ping_hijack' '1' option 'router_proxy' '1' option 'lan_proxy' '1' option 'access_control_mode' 'all' @@ -55,17 +54,10 @@ config mixin 'mixin' option 'log_level' 'warning' option 'mode' 'rule' option 'match_process' 'off' - option 'outbound_interface' '' - option 'ipv6' '0' - option 'unify_delay' '1' - option 'tcp_concurrent' '1' - option 'tcp_keep_alive_idle' '600' - option 'tcp_keep_alive_interval' '15' + option 'ipv6' '1' option 'ui_path' 'ui' - option 'ui_name' '' option 'ui_url' 'https://github.com/Zephyruso/zashboard/archive/refs/heads/gh-pages.zip' - option 'api_port' '9090' - option 'api_secret' '' + option 'api_listen' '[::]:9090' option 'selection_cache' '1' option 'allow_lan' '1' option 'http_port' '8080' @@ -76,14 +68,10 @@ config mixin 'mixin' option 'authentication' '1' option 'tun_device' 'nikki' option 'tun_stack' 'system' - option 'tun_mtu' '9000' - option 'tun_gso' '1' - option 'tun_gso_max_size' '65536' option 'tun_dns_hijack' '0' list 'tun_dns_hijacks' 'tcp://any:53' list 'tun_dns_hijacks' 'udp://any:53' - option 'tun_endpoint_independent_nat' '0' - option 'dns_port' '1053' + option 'dns_listen' '[::]:1053' option 'dns_ipv6' '1' option 'dns_mode' 'fake-ip' option 'fake_ip_range' '198.18.0.1/16' @@ -91,32 +79,14 @@ config mixin 'mixin' list 'fake_ip_filters' '+.lan' list 'fake_ip_filters' '+.local' option 'fake_ip_cache' '1' - option 'dns_respect_rules' '0' - option 'dns_doh_prefer_http3' '0' - option 'dns_system_hosts' '0' - option 'dns_hosts' '1' option 'hosts' '0' option 'dns_nameserver' '0' option 'dns_nameserver_policy' '0' - option 'sniffer' '0' - option 'sniffer_sniff_dns_mapping' '1' - option 'sniffer_sniff_pure_ip' '1' - option 'sniffer_overwrite_destination' '0' option 'sniffer_force_domain_name' '0' - option 'sniffer_force_domain_names' '' option 'sniffer_ignore_domain_name' '0' - option 'sniffer_ignore_domain_names' '' option 'sniffer_sniff' '0' option 'rule' '0' option 'rule_provider' '0' - option 'geoip_format' 'dat' - option 'geodata_loader' 'memconservative' - option 'geosite_url' 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat' - option 'geoip_mmdb_url' 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip-lite.metadb' - option 'geoip_dat_url' 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip-lite.dat' - option 'geoip_asn_url' 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/GeoLite2-ASN.mmdb' - option 'geox_auto_update' '0' - option 'geox_update_interval' '24' option 'mixin_file_content' '0' config env 'env' diff --git a/small/nikki/files/nikki.init b/small/nikki/files/nikki.init index 58b60c4306..85647e8b38 100644 --- a/small/nikki/files/nikki.init +++ b/small/nikki/files/nikki.init @@ -44,11 +44,10 @@ start_service() { log "App" "Start." # get config ## app config - local scheduled_restart cron_expression profile mixin test_profile fast_reload + local scheduled_restart cron_expression profile test_profile fast_reload config_get_bool scheduled_restart "config" "scheduled_restart" 0 config_get cron_expression "config" "cron_expression" config_get profile "config" "profile" - config_get_bool mixin "config" "mixin" 0 config_get_bool test_profile "config" "test_profile" 0 config_get_bool fast_reload "config" "fast_reload" 0 ## mixin config @@ -94,13 +93,7 @@ start_service() { return fi # mixin - if [ "$mixin" == 0 ]; then - log "Mixin" "Disabled." - log "Mixin" "Mixin neccesary config." - else - log "Mixin" "Enabled." - log "Mixin" "Mixin all config." - fi + log "Mixin" "Mixin config." if [ "$mixin_file_content" == 0 ]; then ucode -S "$MIXIN_UC" | yq -M -p json -o yaml | yq -M -i ea '... comments="" | . as $item ireduce ({}; . * $item ) | .rules = .nikki-rules + .rules | del(.nikki-rules)' "$RUN_PROFILE_PATH" - elif [ "$mixin_file_content" == 1 ]; then @@ -110,9 +103,9 @@ start_service() { if [ "$test_profile" == 1 ]; then log "Profile" "Testing..." if ($PROG -d "$RUN_DIR" -t >> "$CORE_LOG_PATH" 2>&1); then - log "Profile" "Test passed!" + log "Profile" "Test passed." else - log "Profile" "Test failed!" + log "Profile" "Test failed." log "Profile" "Please check the core log to find out the problem." log "App" "Exit." return @@ -166,26 +159,11 @@ service_started() { config_get tun_device "mixin" "tun_device" "nikki" ## proxy config ### transparent proxy - local tcp_transparent_proxy_mode udp_transparent_proxy_mode ipv4_dns_hijack ipv6_dns_hijack ipv4_proxy ipv6_proxy router_proxy lan_proxy + local tcp_transparent_proxy_mode udp_transparent_proxy_mode ipv4_proxy ipv6_proxy config_get tcp_transparent_proxy_mode "proxy" "tcp_transparent_proxy_mode" "redirect" config_get udp_transparent_proxy_mode "proxy" "udp_transparent_proxy_mode" "tun" - config_get_bool ipv4_dns_hijack "proxy" "ipv4_dns_hijack" 0 - config_get_bool ipv6_dns_hijack "proxy" "ipv6_dns_hijack" 0 config_get_bool ipv4_proxy "proxy" "ipv4_proxy" 0 config_get_bool ipv6_proxy "proxy" "ipv6_proxy" 0 - config_get_bool router_proxy "proxy" "router_proxy" 0 - config_get_bool lan_proxy "proxy" "lan_proxy" 0 - ### access control - local access_control_mode - config_get access_control_mode "proxy" "access_control_mode" - ### bypass - local bypass_user bypass_group bypass_china_mainland_ip proxy_tcp_dport proxy_udp_dport bypass_dscp - config_get bypass_user "proxy" "bypass_user" - config_get bypass_group "proxy" "bypass_group" - config_get_bool bypass_china_mainland_ip "proxy" "bypass_china_mainland_ip" 0 - config_get proxy_tcp_dport "proxy" "proxy_tcp_dport" "0-65535" - config_get proxy_udp_dport "proxy" "proxy_udp_dport" "0-65535" - config_get bypass_dscp "proxy" "bypass_dscp" # prepare local tproxy_enable; tproxy_enable=0 if [[ "$tcp_transparent_proxy_mode" == "tproxy" || "$udp_transparent_proxy_mode" == "tproxy" ]]; then @@ -197,12 +175,10 @@ service_started() { fi # transparent proxy log "Transparent Proxy" "Enabled." - log "Transparent Proxy" "TCP Mode: $tcp_transparent_proxy_mode." - log "Transparent Proxy" "UDP Mode: $udp_transparent_proxy_mode." # wait for tun device online if [ "$tun_enable" == 1 ]; then log "Transparent Proxy" "Waiting for tun device online..." - local tun_timeout; tun_timeout=60 + local tun_timeout; tun_timeout=15 local tun_interval; tun_interval=1 while [ "$tun_timeout" -gt 0 ]; do if (ip link show dev "$tun_device" > /dev/null 2>&1); then @@ -242,51 +218,14 @@ service_started() { fi $FIREWALL_INCLUDE_SH fi + # hijack utpl -D nikki_group="$NIKKI_GROUP" -D tproxy_fw_mark="$TPROXY_FW_MARK" -D tun_fw_mark="$TUN_FW_MARK" -S "$HIJACK_UT" | nft -f - - # dns hijack - if [ "$ipv4_dns_hijack" == 1 ]; then - log "Transparent Proxy" "Hijack IPv4 dns request." - fi - if [ "$ipv6_dns_hijack" == 1 ]; then - log "Transparent Proxy" "Hijack IPv6 dns request." - fi - # proxy - if [ "$ipv4_proxy" == 1 ]; then - log "Transparent Proxy" "Proxy IPv4 traffic." - fi - if [ "$ipv6_proxy" == 1 ]; then - log "Transparent Proxy" "Proxy IPv6 traffic." - fi - # bypass - if [ -n "$bypass_user" ]; then - log "Transparent Proxy" "Bypass user: $bypass_user." - fi - if [ -n "$bypass_group" ]; then - log "Transparent Proxy" "Bypass group: $bypass_group." - fi - if [ "$bypass_china_mainland_ip" == 1 ]; then - log "Transparent Proxy" "Bypass china mainland ip." - fi - log "Transparent Proxy" "Destination TCP Port to Proxy: $proxy_tcp_dport." - log "Transparent Proxy" "Destination UDP Port to Proxy: $proxy_udp_dport." - if [ -n "$bypass_dscp" ]; then - log "Transparent Proxy" "Bypass DSCP: $bypass_dscp." - fi - # router proxy - if [ "$router_proxy" == 1 ]; then - log "Transparent Proxy" "Set proxy for router." - fi - # lan proxy - if [ "$lan_proxy" == 1 ]; then - log "Transparent Proxy" "Set proxy for lan." - # access control - if [ "$access_control_mode" == "all" ]; then - log "Transparent Proxy" "Access Control is using all mode, set proxy for all client." - elif [ "$access_control_mode" == "allow" ]; then - log "Transparent Proxy" "Access Control is using allow mode, set proxy for client which is in acl." - elif [ "$access_control_mode" == "block" ]; then - log "Transparent Proxy" "Access Control is using block mode, set proxy for client which is not in acl." - fi + # check hijack + if (nft list tables | grep -q nikki); then + log "Transparent Proxy" "Hijack successful." + else + log "Transparent Proxy" "Hijack failed." + log "App" "Exit." fi # fix compatible between tproxy and dockerd (kmod-br-netfilter) if [ "$tproxy_enable" == 1 ] && (lsmod | grep -q br_netfilter); then diff --git a/small/nikki/files/uci-defaults/migrate.sh b/small/nikki/files/uci-defaults/migrate.sh index 9fda9c933c..88fcc2dbc7 100644 --- a/small/nikki/files/uci-defaults/migrate.sh +++ b/small/nikki/files/uci-defaults/migrate.sh @@ -16,7 +16,52 @@ uci show nikki | grep -E 'nikki.@rule\[[[:digit:]]+\].match=' | sed 's/nikki.@ru # since v1.19.1 -fake_ip_ping_hijack=$(uci -q get nikki.proxy.fake_ip_ping_hijack); [ -z "$fake_ip_ping_hijack" ] && uci set nikki.proxy.fake_ip_ping_hijack=0 +proxy_fake_ip_ping_hijack=$(uci -q get nikki.proxy.fake_ip_ping_hijack); [ -z "$proxy_fake_ip_ping_hijack" ] && uci set nikki.proxy.fake_ip_ping_hijack=0 + +# since v1.20.0 + +mixin=$(uci -q get nikki.config.mixin); [ -n "$mixin" ] && { + uci del nikki.config.mixin + [ "$mixin" == "0" ] && { + uci del nikki.mixin.unify_delay + uci del nikki.mixin.tcp_concurrent + uci del nikki.mixin.tcp_keep_alive_idle + uci del nikki.mixin.tcp_keep_alive_interval + uci set nikki.mixin.fake_ip_filter=0 + uci del nikki.mixin.fake_ip_filter_mode + uci del nikki.mixin.dns_respect_rules + uci del nikki.mixin.dns_doh_prefer_http3 + uci del nikki.mixin.dns_system_hosts + uci del nikki.mixin.dns_hosts + uci set nikki.mixin.hosts=0 + uci set nikki.mixin.dns_nameserver=0 + uci set nikki.mixin.dns_nameserver_policy=0 + uci del nikki.mixin.sniffer + uci del nikki.mixin.sniffer_sniff_dns_mapping + uci del nikki.mixin.sniffer_sniff_pure_ip + uci set nikki.mixin.sniffer_force_domain_name=0 + uci set nikki.mixin.sniffer_ignore_domain_name=0 + uci set nikki.mixin.sniffer_sniff=0 + uci del nikki.mixin.geoip_format + uci del nikki.mixin.geodata_loader + uci del nikki.mixin.geosite_url + uci del nikki.mixin.geoip_mmdb_url + uci del nikki.mixin.geoip_dat_url + uci del nikki.mixin.geoip_asn_url + uci del nikki.mixin.geox_auto_update + uci del nikki.mixin.geox_update_interval + } +} + +mixin_api_port=$(uci -q get nikki.mixin.api_port); [ -n "$mixin_api_port" ] && { + uci del nikki.mixin.api_port + uci set nikki.mixin.api_listen=[::]:$mixin_api_port +} + +mixin_dns_port=$(uci -q get nikki.mixin.dns_port); [ -n "$mixin_dns_port" ] && { + uci del nikki.mixin.dns_port + uci set nikki.mixin.dns_listen=[::]:$mixin_dns_port +} # commit uci commit nikki diff --git a/small/nikki/files/ucode/hijack.ut b/small/nikki/files/ucode/hijack.ut index c33a32be68..afdec5e29f 100644 --- a/small/nikki/files/ucode/hijack.ut +++ b/small/nikki/files/ucode/hijack.ut @@ -8,8 +8,8 @@ import { connect } from 'ubus'; import { uci_bool, uci_array } from '/etc/nikki/ucode/include.uc'; - let users = map(split(readfile('/etc/passwd'), '\n'), (x) => split(x, ':')[0]); - let groups = map(split(readfile('/etc/group'), '\n'), (x) => split(x, ':')[0]); + const users = map(split(readfile('/etc/passwd'), '\n'), (x) => split(x, ':')[0]); + const groups = map(split(readfile('/etc/group'), '\n'), (x) => split(x, ':')[0]); const uci = cursor(); const ubus = connect(); @@ -19,7 +19,8 @@ const redir_port = uci.get('nikki', 'mixin', 'redir_port'); const tproxy_port = uci.get('nikki', 'mixin', 'tproxy_port'); - const dns_port = uci.get('nikki', 'mixin', 'dns_port'); + const dns_listen = uci.get('nikki', 'mixin', 'dns_listen'); + const dns_port = substr(dns_listen, rindex(dns_listen, ':') + 1); const fake_ip_range = uci.get('nikki', 'mixin', 'fake_ip_range'); const tun_device = uci.get('nikki', 'mixin', 'tun_device'); diff --git a/small/nikki/files/ucode/include.uc b/small/nikki/files/ucode/include.uc index 974b36b9f8..7282a457ca 100644 --- a/small/nikki/files/ucode/include.uc +++ b/small/nikki/files/ucode/include.uc @@ -1,5 +1,9 @@ export function uci_bool(obj) { - return obj == '1'; + return obj == null ? null : obj == '1'; +}; + +export function uci_int(obj) { + return obj == null ? null : int(obj); }; export function uci_array(obj) { @@ -36,7 +40,7 @@ export function trim_all(obj) { delete obj[key]; } } - if (length(obj_keys) == 0) { + if (length(keys(obj)) == 0) { return null; } return obj; diff --git a/small/nikki/files/ucode/mixin.uc b/small/nikki/files/ucode/mixin.uc index 1b2be30063..03ecfb3aff 100644 --- a/small/nikki/files/ucode/mixin.uc +++ b/small/nikki/files/ucode/mixin.uc @@ -4,39 +4,35 @@ import { cursor } from 'uci'; import { connect } from 'ubus'; -import { uci_bool, uci_array, trim_all } from '/etc/nikki/ucode/include.uc'; +import { uci_bool, uci_int, uci_array, trim_all } from '/etc/nikki/ucode/include.uc'; const uci = cursor(); const ubus = connect(); const config = {}; -const mixin = uci_bool(uci.get('nikki', 'config', 'mixin')); - -config['log-level'] = uci.get('nikki', 'mixin', 'log_level') ?? 'info'; -config['mode'] = uci.get('nikki', 'mixin', 'mode') ?? 'rule'; -config['find-process-mode'] = uci.get('nikki', 'mixin', 'match_process') ?? 'off'; -config['interface-name'] = ubus.call('network.interface', 'status', {'interface': uci.get('nikki', 'mixin', 'outbound_interface')})?.l3_device ?? ''; +config['log-level'] = uci.get('nikki', 'mixin', 'log_level'); +config['mode'] = uci.get('nikki', 'mixin', 'mode'); +config['find-process-mode'] = uci.get('nikki', 'mixin', 'match_process'); +config['interface-name'] = ubus.call('network.interface', 'status', {'interface': uci.get('nikki', 'mixin', 'outbound_interface')})?.l3_device; config['ipv6'] = uci_bool(uci.get('nikki', 'mixin', 'ipv6')); -if (mixin) { - config['unified-delay'] = uci_bool(uci.get('nikki', 'mixin', 'unify_delay')); - config['tcp-concurrent'] = uci_bool(uci.get('nikki', 'mixin', 'tcp_concurrent')); - config['keep-alive-idle'] = int(uci.get('nikki', 'mixin', 'tcp_keep_alive_idle') ?? '600'); - config['keep-alive-interval'] = int(uci.get('nikki', 'mixin', 'tcp_keep_alive_interval') ?? '15'); -} +config['unified-delay'] = uci_bool(uci.get('nikki', 'mixin', 'unify_delay')); +config['tcp-concurrent'] = uci_bool(uci.get('nikki', 'mixin', 'tcp_concurrent')); +config['keep-alive-idle'] = uci_int(uci.get('nikki', 'mixin', 'tcp_keep_alive_idle')); +config['keep-alive-interval'] = uci_int(uci.get('nikki', 'mixin', 'tcp_keep_alive_interval')); -config['external-ui'] = uci.get('nikki', 'mixin', 'ui_path') ?? 'ui'; -config['external-ui-name'] = uci.get('nikki', 'mixin', 'ui_name') ?? ''; +config['external-ui'] = uci.get('nikki', 'mixin', 'ui_path'); +config['external-ui-name'] = uci.get('nikki', 'mixin', 'ui_name'); config['external-ui-url'] = uci.get('nikki', 'mixin', 'ui_url'); -config['external-controller'] = '0.0.0.0' + ':' + (uci.get('nikki', 'mixin', 'api_port') ?? '9090'); -config['secret'] = uci.get('nikki', 'mixin', 'api_secret') ?? '666666'; +config['external-controller'] = uci.get('nikki', 'mixin', 'api_listen'); +config['secret'] = uci.get('nikki', 'mixin', 'api_secret'); config['allow-lan'] = uci_bool(uci.get('nikki', 'mixin', 'allow_lan')); -config['port'] = int(uci.get('nikki', 'mixin', 'http_port') ?? '8080'); -config['socks-port'] = int(uci.get('nikki', 'mixin', 'socks_port') ?? '1080'); -config['mixed-port'] = int(uci.get('nikki', 'mixin', 'mixed_port') ?? '7890'); -config['redir-port'] = int(uci.get('nikki', 'mixin', 'redir_port') ?? '7891'); -config['tproxy-port'] = int(uci.get('nikki', 'mixin', 'tproxy_port') ?? '7892'); +config['port'] = uci_int(uci.get('nikki', 'mixin', 'http_port')); +config['socks-port'] = uci_int(uci.get('nikki', 'mixin', 'socks_port')); +config['mixed-port'] = uci_int(uci.get('nikki', 'mixin', 'mixed_port')); +config['redir-port'] = uci_int(uci.get('nikki', 'mixin', 'redir_port')); +config['tproxy-port'] = uci_int(uci.get('nikki', 'mixin', 'tproxy_port')); if (uci_bool(uci.get('nikki', 'mixin', 'authentication'))) { config['authentication'] = []; @@ -54,11 +50,11 @@ if (uci.get('nikki', 'proxy', 'tcp_transparent_proxy_mode') == 'tun' || uci.get( config['tun']['auto-route'] = false; config['tun']['auto-redirect'] = false; config['tun']['auto-detect-interface'] = false; - config['tun']['device'] = uci.get('nikki', 'mixin', 'tun_device') ?? 'nikki'; - config['tun']['stack'] = uci.get('nikki', 'mixin', 'tun_stack') ?? 'system'; - config['tun']['mtu'] = int(uci.get('nikki', 'mixin', 'tun_mtu') ?? '9000'); + config['tun']['device'] = uci.get('nikki', 'mixin', 'tun_device'); + config['tun']['stack'] = uci.get('nikki', 'mixin', 'tun_stack'); + config['tun']['mtu'] = uci_int(uci.get('nikki', 'mixin', 'tun_mtu')); config['tun']['gso'] = uci_bool(uci.get('nikki', 'mixin', 'tun_gso')); - config['tun']['gso-max-size'] = int(uci.get('nikki', 'mixin', 'tun_gso_max_size') ?? '65536'); + config['tun']['gso-max-size'] = uci_int(uci.get('nikki', 'mixin', 'tun_gso_max_size')); config['tun']['endpoint-independent-nat'] = uci_bool(uci.get('nikki', 'mixin', 'tun_endpoint_independent_nat')); if (uci_bool(uci.get('nikki', 'mixin', 'tun_dns_hijack'))) { config['tun']['dns-hijack'] = uci_array(uci.get('nikki', 'mixin', 'tun_dns_hijacks')); @@ -69,77 +65,73 @@ if (uci.get('nikki', 'proxy', 'tcp_transparent_proxy_mode') == 'tun' || uci.get( config['dns'] = {}; config['dns']['enable'] = true; -config['dns']['listen'] = '0.0.0.0' + ':' + (uci.get('nikki', 'mixin', 'dns_port') ?? '1053'); +config['dns']['listen'] = uci.get('nikki', 'mixin', 'dns_listen'); config['dns']['ipv6'] = uci_bool(uci.get('nikki', 'mixin', 'dns_ipv6')); -config['dns']['enhanced-mode'] = uci.get('nikki', 'mixin', 'dns_mode') ?? 'redir-host'; -config['dns']['fake-ip-range'] = uci.get('nikki', 'mixin', 'fake_ip_range') ?? '198.18.0.1/16'; +config['dns']['enhanced-mode'] = uci.get('nikki', 'mixin', 'dns_mode'); +config['dns']['fake-ip-range'] = uci.get('nikki', 'mixin', 'fake_ip_range'); if (uci_bool(uci.get('nikki', 'mixin', 'fake_ip_filter'))) { config['dns']['fake-ip-filter'] = uci_array(uci.get('nikki', 'mixin', 'fake_ip_filters')); - config['dns']['fake-ip-filter-mode'] = uci.get('nikki', 'mixin', 'fake_ip_filter_mode') ?? 'blacklist'; } -if (mixin) { - config['dns']['respect-rules'] = uci_bool(uci.get('nikki', 'mixin', 'dns_respect_rules')); - config['dns']['prefer-h3'] = uci_bool(uci.get('nikki', 'mixin', 'dns_doh_prefer_http3')); - config['dns']['use-system-hosts'] = uci_bool(uci.get('nikki', 'mixin', 'dns_system_hosts')); - config['dns']['use-hosts'] = uci_bool(uci.get('nikki', 'mixin', 'dns_hosts')); - if (uci_bool(uci.get('nikki', 'mixin', 'hosts'))) { - config['hosts'] = {}; - uci.foreach('nikki', 'hosts', (section) => { - if (!uci_bool(section.enabled)) { - return; - } - config['hosts'][section.domain_name] = uci_array(section.ip); - }); - } - if (uci_bool(uci.get('nikki', 'mixin', 'dns_nameserver'))) { - config['dns']['default-nameserver'] = []; - config['dns']['proxy-server-nameserver'] = []; - config['dns']['direct-nameserver'] = []; - config['dns']['nameserver'] = []; - config['dns']['fallback'] = []; - uci.foreach('nikki', 'nameserver', (section) => { - if (!uci_bool(section.enabled)) { - return; - } - push(config['dns'][section.type], ...uci_array(section.nameserver)); - }) - } - if (uci_bool(uci.get('nikki', 'mixin', 'dns_nameserver_policy'))) { - config['dns']['nameserver-policy'] = {}; - uci.foreach('nikki', 'nameserver_policy', (section) => { - if (!uci_bool(section.enabled)) { - return; - } - config['dns']['nameserver-policy'][section.matcher] = uci_array(section.nameserver); - }); - } +config['dns']['fake-ip-filter-mode'] = uci.get('nikki', 'mixin', 'fake_ip_filter_mode'); + +config['dns']['respect-rules'] = uci_bool(uci.get('nikki', 'mixin', 'dns_respect_rules')); +config['dns']['prefer-h3'] = uci_bool(uci.get('nikki', 'mixin', 'dns_doh_prefer_http3')); +config['dns']['use-system-hosts'] = uci_bool(uci.get('nikki', 'mixin', 'dns_system_hosts')); +config['dns']['use-hosts'] = uci_bool(uci.get('nikki', 'mixin', 'dns_hosts')); +if (uci_bool(uci.get('nikki', 'mixin', 'hosts'))) { + config['hosts'] = {}; + uci.foreach('nikki', 'hosts', (section) => { + if (!uci_bool(section.enabled)) { + return; + } + config['hosts'][section.domain_name] = uci_array(section.ip); + }); +} +if (uci_bool(uci.get('nikki', 'mixin', 'dns_nameserver'))) { + config['dns']['default-nameserver'] = []; + config['dns']['proxy-server-nameserver'] = []; + config['dns']['direct-nameserver'] = []; + config['dns']['nameserver'] = []; + config['dns']['fallback'] = []; + uci.foreach('nikki', 'nameserver', (section) => { + if (!uci_bool(section.enabled)) { + return; + } + push(config['dns'][section.type], ...uci_array(section.nameserver)); + }) +} +if (uci_bool(uci.get('nikki', 'mixin', 'dns_nameserver_policy'))) { + config['dns']['nameserver-policy'] = {}; + uci.foreach('nikki', 'nameserver_policy', (section) => { + if (!uci_bool(section.enabled)) { + return; + } + config['dns']['nameserver-policy'][section.matcher] = uci_array(section.nameserver); + }); } -if (mixin) { - config['sniffer'] = {}; - config['sniffer']['enable'] = uci_bool(uci.get('nikki', 'mixin', 'sniffer')); - config['sniffer']['force-dns-mapping'] = uci_bool(uci.get('nikki', 'mixin', 'sniffer_sniff_dns_mapping')); - config['sniffer']['parse-pure-ip'] = uci_bool(uci.get('nikki', 'mixin', 'sniffer_sniff_pure_ip')); - config['sniffer']['override-destination'] = uci_bool(uci.get('nikki', 'mixin', 'sniffer_overwrite_destination')); - if (uci_bool(uci.get('nikki', 'mixin', 'sniffer_force_domain_name'))) { - config['sniffer']['force-domain'] = uci_array(uci.get('nikki', 'mixin', 'sniffer_force_domain_names')); - } - if (uci_bool(uci.get('nikki', 'mixin', 'sniffer_ignore_domain_name'))) { - config['sniffer']['skip-domain'] = uci_array(uci.get('nikki', 'mixin', 'sniffer_ignore_domain_names')); - } - if (uci_bool(uci.get('nikki', 'mixin', 'sniffer_sniff'))) { - config['sniffer']['sniff'] = {}; - config['sniffer']['sniff']['HTTP'] = {}; - config['sniffer']['sniff']['TLS'] = {}; - config['sniffer']['sniff']['QUIC'] = {}; - uci.foreach('nikki', 'sniff', (section) => { - if (!uci_bool(section.enabled)) { - return; - } - config['sniffer']['sniff'][section.protocol]['port'] = uci_array(section.port); - config['sniffer']['sniff'][section.protocol]['override-destination'] = uci_bool(section.overwrite_destination); - }); - } +config['sniffer'] = {}; +config['sniffer']['enable'] = uci_bool(uci.get('nikki', 'mixin', 'sniffer')); +config['sniffer']['force-dns-mapping'] = uci_bool(uci.get('nikki', 'mixin', 'sniffer_sniff_dns_mapping')); +config['sniffer']['parse-pure-ip'] = uci_bool(uci.get('nikki', 'mixin', 'sniffer_sniff_pure_ip')); +if (uci_bool(uci.get('nikki', 'mixin', 'sniffer_force_domain_name'))) { + config['sniffer']['force-domain'] = uci_array(uci.get('nikki', 'mixin', 'sniffer_force_domain_names')); +} +if (uci_bool(uci.get('nikki', 'mixin', 'sniffer_ignore_domain_name'))) { + config['sniffer']['skip-domain'] = uci_array(uci.get('nikki', 'mixin', 'sniffer_ignore_domain_names')); +} +if (uci_bool(uci.get('nikki', 'mixin', 'sniffer_sniff'))) { + config['sniffer']['sniff'] = {}; + config['sniffer']['sniff']['HTTP'] = {}; + config['sniffer']['sniff']['TLS'] = {}; + config['sniffer']['sniff']['QUIC'] = {}; + uci.foreach('nikki', 'sniff', (section) => { + if (!uci_bool(section.enabled)) { + return; + } + config['sniffer']['sniff'][section.protocol]['port'] = uci_array(section.port); + config['sniffer']['sniff'][section.protocol]['override-destination'] = uci_bool(section.overwrite_destination); + }); } config['profile'] = {}; @@ -178,29 +170,19 @@ if (uci_bool(uci.get('nikki', 'mixin', 'rule'))) { if (!uci_bool(section.enabled)) { return; } - let rule; - if (length(section.type) > 0) { - rule = `${section.type},${section.matcher},${section.node}`; - } else { - rule = `${section.matcher},${section.node}`; - } - if (uci_bool(section.no_resolve)) { - rule += ',no_resolve'; - } - push(config['nikki-rules'], rule); + push(config['nikki-rules'], `${section.type},${section.matcher},${section.node}` + (uci_bool(section.no_resolve) ? ',no_resolve' : '')); }) } -if (mixin) { - config['geodata-mode'] = uci.get('nikki', 'mixin', 'geoip_format') == 'dat'; - config['geodata-loader'] = uci.get('nikki', 'mixin', 'geodata_loader') ?? 'memconservative'; - config['geox-url'] = {}; - config['geox-url']['geosite'] = uci.get('nikki', 'mixin', 'geosite_url'); - config['geox-url']['mmdb'] = uci.get('nikki', 'mixin', 'geoip_mmdb_url'); - config['geox-url']['geoip'] = uci.get('nikki', 'mixin', 'geoip_dat_url'); - config['geox-url']['asn'] = uci.get('nikki', 'mixin', 'geoip_asn_url'); - config['geo-auto-update'] = uci_bool(uci.get('nikki', 'mixin', 'geox_auto_update')); - config['geo-update-interval'] = int(uci.get('nikki', 'mixin', 'geox_update_interval') ?? '24'); -} +const geoip_format = uci.get('nikki', 'mixin', 'geoip_format'); +config['geodata-mode'] = geoip_format == null ? null : geoip_format == 'dat'; +config['geodata-loader'] = uci.get('nikki', 'mixin', 'geodata_loader'); +config['geox-url'] = {}; +config['geox-url']['geosite'] = uci.get('nikki', 'mixin', 'geosite_url'); +config['geox-url']['mmdb'] = uci.get('nikki', 'mixin', 'geoip_mmdb_url'); +config['geox-url']['geoip'] = uci.get('nikki', 'mixin', 'geoip_dat_url'); +config['geox-url']['asn'] = uci.get('nikki', 'mixin', 'geoip_asn_url'); +config['geo-auto-update'] = uci_bool(uci.get('nikki', 'mixin', 'geox_auto_update')); +config['geo-update-interval'] = uci_int(uci.get('nikki', 'mixin', 'geox_update_interval')); print(trim_all(config)); \ No newline at end of file diff --git a/small/v2ray-geodata/Makefile b/small/v2ray-geodata/Makefile index b0e03836bb..0ce0ae3380 100644 --- a/small/v2ray-geodata/Makefile +++ b/small/v2ray-geodata/Makefile @@ -30,7 +30,7 @@ define Download/geosite HASH:=525dcdd8ac80d473ad128b568d7f3e16d0392872945a9468d18ac2afddd5b253 endef -GEOSITE_IRAN_VER:=202502240036 +GEOSITE_IRAN_VER:=202503030037 GEOSITE_IRAN_FILE:=iran.dat.$(GEOSITE_IRAN_VER) define Download/geosite-ir URL:=https://github.com/bootmortis/iran-hosted-domains/releases/download/$(GEOSITE_IRAN_VER)/ diff --git a/v2rayn/v2rayN/ServiceLib/Handler/AppHandler.cs b/v2rayn/v2rayN/ServiceLib/Handler/AppHandler.cs index cf0f73afe6..8a17932ffe 100644 --- a/v2rayn/v2rayN/ServiceLib/Handler/AppHandler.cs +++ b/v2rayn/v2rayN/ServiceLib/Handler/AppHandler.cs @@ -80,8 +80,6 @@ namespace ServiceLib.Handler Logging.SaveLog($"v2rayN start up | {Utils.GetRuntimeInfo()}"); Logging.LoggingEnabled(_config.GuiItem.EnableLog); - ClearExpiredFiles(); - return true; } @@ -92,16 +90,6 @@ namespace ServiceLib.Handler return true; } - private void ClearExpiredFiles() - { - Task.Run(() => - { - FileManager.DeleteExpiredFiles(Utils.GetLogPath(), DateTime.Now.AddMonths(-1)); - FileManager.DeleteExpiredFiles(Utils.GetTempPath(), DateTime.Now.AddMonths(-1)); - FileManager.DeleteExpiredFiles(Utils.GetBinConfigPath(), DateTime.Now.AddHours(-1)); - }); - } - #endregion Init #region Config diff --git a/v2rayn/v2rayN/ServiceLib/Handler/ClashApiHandler.cs b/v2rayn/v2rayN/ServiceLib/Handler/ClashApiHandler.cs index 7ba0488513..01134e6d10 100644 --- a/v2rayn/v2rayN/ServiceLib/Handler/ClashApiHandler.cs +++ b/v2rayn/v2rayN/ServiceLib/Handler/ClashApiHandler.cs @@ -7,9 +7,9 @@ namespace ServiceLib.Handler private static readonly Lazy instance = new(() => new()); public static ClashApiHandler Instance => instance.Value; + private static readonly string _tag = "ClashApiHandler"; private Dictionary? _proxies; public Dictionary ProfileContent { get; set; } - private static readonly string _tag = "ClashApiHandler"; public async Task?> GetClashProxiesAsync(Config config) { @@ -54,7 +54,7 @@ namespace ServiceLib.Handler return; } lstProxy = new List(); - foreach (KeyValuePair kv in _proxies) + foreach (var kv in _proxies) { if (Global.notAllowTestType.Contains(kv.Value.type.ToLower())) { diff --git a/v2rayn/v2rayN/ServiceLib/Handler/Fmt/Hysteria2Fmt.cs b/v2rayn/v2rayN/ServiceLib/Handler/Fmt/Hysteria2Fmt.cs index b57abe0a5d..be6630e150 100644 --- a/v2rayn/v2rayN/ServiceLib/Handler/Fmt/Hysteria2Fmt.cs +++ b/v2rayn/v2rayN/ServiceLib/Handler/Fmt/Hysteria2Fmt.cs @@ -24,6 +24,8 @@ namespace ServiceLib.Handler.Fmt item.Path = Utils.UrlDecode(query["obfs-password"] ?? ""); item.AllowInsecure = (query["insecure"] ?? "") == "1" ? "true" : "false"; + item.Ports = Utils.UrlDecode(query["mport"] ?? "").Replace('-', ':'); + return item; } @@ -53,6 +55,10 @@ namespace ServiceLib.Handler.Fmt dicQuery.Add("obfs-password", Utils.UrlEncode(item.Path)); } dicQuery.Add("insecure", item.AllowInsecure.ToLower() == "true" ? "1" : "0"); + if (Utils.IsNotEmpty(item.Ports)) + { + dicQuery.Add("mport", Utils.UrlEncode(item.Ports.Replace(':', '-'))); + } return ToUri(EConfigType.Hysteria2, item.Address, item.Port, item.Id, dicQuery, remark); } diff --git a/v2rayn/v2rayN/ServiceLib/Handler/ProfileExHandler.cs b/v2rayn/v2rayN/ServiceLib/Handler/ProfileExHandler.cs index 4743696dae..31a6b56c34 100644 --- a/v2rayn/v2rayN/ServiceLib/Handler/ProfileExHandler.cs +++ b/v2rayn/v2rayN/ServiceLib/Handler/ProfileExHandler.cs @@ -20,14 +20,6 @@ namespace ServiceLib.Handler public async Task Init() { await InitData(); - _ = Task.Run(async () => - { - while (true) - { - await Task.Delay(1000 * 600); - await SaveQueueIndexIds(); - } - }); } public async Task> GetProfileExs() diff --git a/v2rayn/v2rayN/ServiceLib/Handler/TaskHandler.cs b/v2rayn/v2rayN/ServiceLib/Handler/TaskHandler.cs index 3d04a33de2..08c01a4672 100644 --- a/v2rayn/v2rayN/ServiceLib/Handler/TaskHandler.cs +++ b/v2rayn/v2rayN/ServiceLib/Handler/TaskHandler.cs @@ -1,4 +1,4 @@ -namespace ServiceLib.Handler +namespace ServiceLib.Handler { public class TaskHandler { @@ -7,66 +7,92 @@ public void RegUpdateTask(Config config, Action updateFunc) { - Task.Run(() => UpdateTaskRunSubscription(config, updateFunc)); - Task.Run(() => UpdateTaskRunGeo(config, updateFunc)); + Task.Run(() => ScheduledTasks(config, updateFunc)); + } + + private async Task ScheduledTasks(Config config, Action updateFunc) + { + Logging.SaveLog("Setup Scheduled Tasks"); + + var numOfExecuted = 1; + while (true) + { + //1 minute + await Task.Delay(1000 * 60); + + //Execute once 1 minute + await UpdateTaskRunSubscription(config, updateFunc); + + //Execute once 20 minute + if (numOfExecuted % 20 == 0) + { + //Logging.SaveLog("Execute save config"); + + await ConfigHandler.SaveConfig(config); + await ProfileExHandler.Instance.SaveTo(); + } + + //Execute once 1 hour + if (numOfExecuted % 60 == 0) + { + //Logging.SaveLog("Execute delete expired files"); + + FileManager.DeleteExpiredFiles(Utils.GetBinConfigPath(), DateTime.Now.AddHours(-1)); + FileManager.DeleteExpiredFiles(Utils.GetLogPath(), DateTime.Now.AddMonths(-1)); + FileManager.DeleteExpiredFiles(Utils.GetTempPath(), DateTime.Now.AddMonths(-1)); + + //Check once 1 hour + await UpdateTaskRunGeo(config, numOfExecuted / 60, updateFunc); + } + + numOfExecuted++; + } } private async Task UpdateTaskRunSubscription(Config config, Action updateFunc) { - await Task.Delay(60000); - Logging.SaveLog("UpdateTaskRunSubscription"); + var updateTime = ((DateTimeOffset)DateTime.Now).ToUnixTimeSeconds(); + var lstSubs = (await AppHandler.Instance.SubItems())? + .Where(t => t.AutoUpdateInterval > 0) + .Where(t => updateTime - t.UpdateTime >= t.AutoUpdateInterval * 60) + .ToList(); - var updateHandle = new UpdateService(); - while (true) + if (lstSubs is not { Count: > 0 }) { - var updateTime = ((DateTimeOffset)DateTime.Now).ToUnixTimeSeconds(); - var lstSubs = (await AppHandler.Instance.SubItems()) - .Where(t => t.AutoUpdateInterval > 0) - .Where(t => updateTime - t.UpdateTime >= t.AutoUpdateInterval * 60) - .ToList(); + return; + } - foreach (var item in lstSubs) + Logging.SaveLog("Execute update subscription"); + var updateHandle = new UpdateService(); + + foreach (var item in lstSubs) + { + await updateHandle.UpdateSubscriptionProcess(config, item.Id, true, (bool success, string msg) => { - await updateHandle.UpdateSubscriptionProcess(config, item.Id, true, (bool success, string msg) => - { - updateFunc?.Invoke(success, msg); - if (success) - Logging.SaveLog("subscription" + msg); - }); - item.UpdateTime = updateTime; - await ConfigHandler.AddSubItem(config, item); - - await Task.Delay(5000); - } - await Task.Delay(60000); + updateFunc?.Invoke(success, msg); + if (success) + { + Logging.SaveLog($"Update subscription end. {msg}"); + } + }); + item.UpdateTime = updateTime; + await ConfigHandler.AddSubItem(config, item); + await Task.Delay(1000); } } - private async Task UpdateTaskRunGeo(Config config, Action updateFunc) + private async Task UpdateTaskRunGeo(Config config, int hours, Action updateFunc) { - var autoUpdateGeoTime = DateTime.Now; - - //await Task.Delay(1000 * 120); - Logging.SaveLog("UpdateTaskRunGeo"); - - var updateHandle = new UpdateService(); - while (true) + if (config.GuiItem.AutoUpdateInterval > 0 && hours > 0 && hours % config.GuiItem.AutoUpdateInterval == 0) { - await Task.Delay(1000 * 3600); + Logging.SaveLog("Execute update geo files"); - var dtNow = DateTime.Now; - if (config.GuiItem.AutoUpdateInterval > 0) + var updateHandle = new UpdateService(); + await updateHandle.UpdateGeoFileAll(config, (bool success, string msg) => { - if ((dtNow - autoUpdateGeoTime).Hours % config.GuiItem.AutoUpdateInterval == 0) - { - await updateHandle.UpdateGeoFileAll(config, (bool success, string msg) => - { - updateFunc?.Invoke(false, msg); - }); - autoUpdateGeoTime = dtNow; - } - } + updateFunc?.Invoke(false, msg); + }); } } } -} \ No newline at end of file +} diff --git a/v2rayn/v2rayN/ServiceLib/Resx/ResUI.Designer.cs b/v2rayn/v2rayN/ServiceLib/Resx/ResUI.Designer.cs index 1af33d3c19..f50b2e9fc1 100644 --- a/v2rayn/v2rayN/ServiceLib/Resx/ResUI.Designer.cs +++ b/v2rayn/v2rayN/ServiceLib/Resx/ResUI.Designer.cs @@ -2483,7 +2483,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Address(Ip,Ipv6) 的本地化字符串。 + /// 查找类似 Address(Ipv4,Ipv6) 的本地化字符串。 /// public static string TbLocalAddress { get { diff --git a/v2rayn/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx b/v2rayn/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx index 090ebd83d4..aa607f5015 100644 --- a/v2rayn/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx +++ b/v2rayn/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx @@ -1319,7 +1319,7 @@ Previous proxy remarks - آدرس (IP, IPv6) + آدرس (IPv4, IPv6) Reserved(2,3,4) diff --git a/v2rayn/v2rayN/ServiceLib/Resx/ResUI.hu.resx b/v2rayn/v2rayN/ServiceLib/Resx/ResUI.hu.resx index e1741f1223..135ace66fb 100644 --- a/v2rayn/v2rayN/ServiceLib/Resx/ResUI.hu.resx +++ b/v2rayn/v2rayN/ServiceLib/Resx/ResUI.hu.resx @@ -1100,7 +1100,7 @@ Fenntartva (2,3,4) - Cím (Ip,Ipv6) + Cím (Ipv4,Ipv6) obfs jelszó diff --git a/v2rayn/v2rayN/ServiceLib/Resx/ResUI.resx b/v2rayn/v2rayN/ServiceLib/Resx/ResUI.resx index dc599d69a1..4d10c88d65 100644 --- a/v2rayn/v2rayN/ServiceLib/Resx/ResUI.resx +++ b/v2rayn/v2rayN/ServiceLib/Resx/ResUI.resx @@ -1100,7 +1100,7 @@ Reserved(2,3,4) - Address(Ip,Ipv6) + Address(Ipv4,Ipv6) obfs password @@ -1402,4 +1402,4 @@ Will cover the port, separate with commas (,) - \ No newline at end of file + diff --git a/v2rayn/v2rayN/ServiceLib/Resx/ResUI.ru.resx b/v2rayn/v2rayN/ServiceLib/Resx/ResUI.ru.resx index 3e61dc814c..1e997842f5 100644 --- a/v2rayn/v2rayN/ServiceLib/Resx/ResUI.ru.resx +++ b/v2rayn/v2rayN/ServiceLib/Resx/ResUI.ru.resx @@ -1052,7 +1052,7 @@ obfs password - Address(Ip,Ipv6) + Address(Ipv4,Ipv6) Default domain strategy for outbound diff --git a/v2rayn/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx b/v2rayn/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx index 2511fc95de..f1607f4181 100644 --- a/v2rayn/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx +++ b/v2rayn/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx @@ -1097,7 +1097,7 @@ Reserved(2,3,4) - Address(Ip,Ipv6) + Address(Ipv4,Ipv6) 混淆密码(obfs password) diff --git a/v2rayn/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx b/v2rayn/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx index e7b76800bf..5f7d3bff81 100644 --- a/v2rayn/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx +++ b/v2rayn/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx @@ -1326,7 +1326,7 @@ Reserved(2,3,4) - Address(Ip,Ipv6) + Address(Ipv4,Ipv6) 使用系統hosts diff --git a/v2rayn/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs b/v2rayn/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs index 39c6f0fdd7..475eed106c 100644 --- a/v2rayn/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs +++ b/v2rayn/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs @@ -733,7 +733,10 @@ namespace ServiceLib.Services.CoreConfig if (node.Ports.IsNotEmpty()) { outbound.server_port = null; - outbound.server_ports = node.Ports.Split(",").ToList(); + outbound.server_ports = node.Ports.Split(',') + .Where(p => p.Trim().IsNotEmpty()) + .Select(p => p.Replace('-', ':')) + .ToList(); outbound.hop_interval = _config.HysteriaItem.HopInterval > 0 ? $"{_config.HysteriaItem.HopInterval}s" : null; } diff --git a/v2rayn/v2rayN/ServiceLib/Services/SpeedtestService.cs b/v2rayn/v2rayN/ServiceLib/Services/SpeedtestService.cs index 37cb83b392..05de5b0264 100644 --- a/v2rayn/v2rayN/ServiceLib/Services/SpeedtestService.cs +++ b/v2rayn/v2rayN/ServiceLib/Services/SpeedtestService.cs @@ -25,8 +25,6 @@ namespace ServiceLib.Services await RunAsync(actionType, selecteds); await ProfileExHandler.Instance.SaveTo(); UpdateFunc("", ResUI.SpeedtestingCompleted); - - FileManager.DeleteExpiredFiles(Utils.GetBinConfigPath(), DateTime.Now.AddHours(-1)); }); } diff --git a/v2rayn/v2rayN/ServiceLib/ViewModels/ClashConnectionsViewModel.cs b/v2rayn/v2rayN/ServiceLib/ViewModels/ClashConnectionsViewModel.cs index 761fd9b711..166da0ee1d 100644 --- a/v2rayn/v2rayN/ServiceLib/ViewModels/ClashConnectionsViewModel.cs +++ b/v2rayn/v2rayN/ServiceLib/ViewModels/ClashConnectionsViewModel.cs @@ -53,26 +53,31 @@ namespace ServiceLib.ViewModels private async Task Init() { - var lastTime = DateTime.Now; + Task.Run(async () => + { + var numOfExecuted = 1; + while (true) + { + await Task.Delay(1000 * 5); + numOfExecuted++; + if (!(AutoRefresh && _config.UiItem.ShowInTaskbar && _config.IsRunningCore(ECoreType.sing_box))) + { + continue; + } + + if (_config.ClashUIItem.ConnectionsRefreshInterval <= 0) + { + continue; + } + + if (numOfExecuted % _config.ClashUIItem.ConnectionsRefreshInterval != 0) + { + continue; + } + await GetClashConnections(); + } + }); - Observable.Interval(TimeSpan.FromSeconds(5)) - .Subscribe(async x => - { - if (!(AutoRefresh && _config.UiItem.ShowInTaskbar && _config.IsRunningCore(ECoreType.sing_box))) - { - return; - } - var dtNow = DateTime.Now; - if (_config.ClashUIItem.ConnectionsRefreshInterval > 0) - { - if ((dtNow - lastTime).Minutes % _config.ClashUIItem.ConnectionsRefreshInterval == 0) - { - await GetClashConnections(); - lastTime = dtNow; - } - Task.Delay(1000).Wait(); - } - }); await Task.CompletedTask; } diff --git a/v2rayn/v2rayN/ServiceLib/ViewModels/ClashProxiesViewModel.cs b/v2rayn/v2rayN/ServiceLib/ViewModels/ClashProxiesViewModel.cs index 091a42153f..5d8535c48f 100644 --- a/v2rayn/v2rayN/ServiceLib/ViewModels/ClashProxiesViewModel.cs +++ b/v2rayn/v2rayN/ServiceLib/ViewModels/ClashProxiesViewModel.cs @@ -95,8 +95,8 @@ namespace ServiceLib.ViewModels private async Task Init() { - await ProxiesReload(); _ = DelayTestTask(); + await ProxiesReload(); } private async Task DoRulemodeSelected(bool c) @@ -383,8 +383,6 @@ namespace ServiceLib.ViewModels private async Task ProxiesDelayTest(bool blAll) { - //UpdateHandler(false, "Clash Proxies Latency Test"); - ClashApiHandler.Instance.ClashProxiesDelayTest(blAll, _proxyDetails.ToList(), async (item, result) => { if (item == null) @@ -434,13 +432,13 @@ namespace ServiceLib.ViewModels public async Task DelayTestTask() { - var lastTime = DateTime.Now; - _ = Task.Run(async () => + Task.Run(async () => { + var numOfExecuted = 1; while (true) { await Task.Delay(1000 * 60); - + numOfExecuted++; if (!(AutoRefresh && _config.UiItem.ShowInTaskbar && _config.IsRunningCore(ECoreType.sing_box))) { continue; @@ -449,13 +447,11 @@ namespace ServiceLib.ViewModels { continue; } - var dtNow = DateTime.Now; - if ((dtNow - lastTime).Minutes % _config.ClashUIItem.ProxiesAutoDelayTestInterval != 0) + if (numOfExecuted % _config.ClashUIItem.ProxiesAutoDelayTestInterval != 0) { continue; } await ProxiesDelayTest(); - lastTime = dtNow; } }); await Task.CompletedTask; diff --git a/v2rayn/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml b/v2rayn/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml index 187a1289b2..ef1885af96 100644 --- a/v2rayn/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml +++ b/v2rayn/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml @@ -349,7 +349,8 @@ Grid.Row="3" Grid.Column="1" Width="400" - Margin="{StaticResource Margin4}" /> + Margin="{StaticResource Margin4}" + Watermark="1000:2000,3000:4000" /> + Margin="{StaticResource Margin4}" + Watermark="2,3,4" /> + Margin="{StaticResource Margin4}" + Watermark="Ipv4,Ipv6" /> + HorizontalAlignment="Left" + Watermark="1500" /> diff --git a/xray-core/app/dns/nameserver.go b/xray-core/app/dns/nameserver.go index 89f5b25e5e..b23cb18628 100644 --- a/xray-core/app/dns/nameserver.go +++ b/xray-core/app/dns/nameserver.go @@ -45,11 +45,13 @@ func NewServer(ctx context.Context, dest net.Destination, dispatcher routing.Dis case strings.EqualFold(u.String(), "localhost"): return NewLocalNameServer(queryStrategy), nil case strings.EqualFold(u.Scheme, "https"): // DNS-over-HTTPS Remote mode - return NewDoHNameServer(u, dispatcher, queryStrategy, false) + return NewDoHNameServer(u, queryStrategy, dispatcher, false), nil case strings.EqualFold(u.Scheme, "h2c"): // DNS-over-HTTPS h2c Remote mode - return NewDoHNameServer(u, dispatcher, queryStrategy, true) + return NewDoHNameServer(u, queryStrategy, dispatcher, true), nil case strings.EqualFold(u.Scheme, "https+local"): // DNS-over-HTTPS Local mode - return NewDoHLocalNameServer(u, queryStrategy), nil + return NewDoHNameServer(u, queryStrategy, nil, false), nil + case strings.EqualFold(u.Scheme, "h2c+local"): // DNS-over-HTTPS h2c Local mode + return NewDoHNameServer(u, queryStrategy, nil, true), nil case strings.EqualFold(u.Scheme, "quic+local"): // DNS-over-QUIC Local mode return NewQUICNameServer(u, queryStrategy) case strings.EqualFold(u.Scheme, "tcp"): // DNS-over-TCP Remote mode diff --git a/xray-core/app/dns/nameserver_doh.go b/xray-core/app/dns/nameserver_doh.go index f602d80a83..c74b9e53ef 100644 --- a/xray-core/app/dns/nameserver_doh.go +++ b/xray-core/app/dns/nameserver_doh.go @@ -8,10 +8,13 @@ import ( "io" "net/http" "net/url" + "strings" "sync" "time" + utls "github.com/refraction-networking/utls" "github.com/xtls/xray-core/common" + "github.com/xtls/xray-core/common/crypto" "github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/log" "github.com/xtls/xray-core/common/net" @@ -31,7 +34,6 @@ import ( // which is compatible with traditional dns over udp(RFC1035), // thus most of the DOH implementation is copied from udpns.go type DoHNameServer struct { - dispatcher routing.Dispatcher sync.RWMutex ips map[string]*record pub *pubsub.Service @@ -42,108 +44,18 @@ type DoHNameServer struct { queryStrategy QueryStrategy } -// NewDoHNameServer creates DOH server object for remote resolving. -func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher, queryStrategy QueryStrategy, h2c bool) (*DoHNameServer, error) { +// NewDoHNameServer creates DOH/DOHL client object for remote/local resolving. +func NewDoHNameServer(url *url.URL, queryStrategy QueryStrategy, dispatcher routing.Dispatcher, h2c bool) *DoHNameServer { url.Scheme = "https" - errors.LogInfo(context.Background(), "DNS: created Remote DNS-over-HTTPS client for ", url.String(), ", with h2c ", h2c) - s := baseDOHNameServer(url, "DOH", queryStrategy) - - s.dispatcher = dispatcher - dialContext := func(ctx context.Context, network, addr string) (net.Conn, error) { - dest, err := net.ParseDestination(network + ":" + addr) - if err != nil { - return nil, err - } - dnsCtx := toDnsContext(ctx, s.dohURL) - if h2c { - dnsCtx = session.ContextWithMitmAlpn11(dnsCtx, false) // for insurance - dnsCtx = session.ContextWithMitmServerName(dnsCtx, url.Hostname()) - } - link, err := s.dispatcher.Dispatch(dnsCtx, dest) - select { - case <-ctx.Done(): - return nil, ctx.Err() - default: - - } - if err != nil { - return nil, err - } - - cc := common.ChainedClosable{} - if cw, ok := link.Writer.(common.Closable); ok { - cc = append(cc, cw) - } - if cr, ok := link.Reader.(common.Closable); ok { - cc = append(cc, cr) - } - return cnc.NewConnection( - cnc.ConnectionInputMulti(link.Writer), - cnc.ConnectionOutputMulti(link.Reader), - cnc.ConnectionOnClose(cc), - ), nil + mode := "DOH" + if dispatcher == nil { + mode = "DOHL" } - - s.httpClient = &http.Client{ - Timeout: time.Second * 180, - Transport: &http.Transport{ - MaxIdleConns: 30, - IdleConnTimeout: 90 * time.Second, - TLSHandshakeTimeout: 30 * time.Second, - ForceAttemptHTTP2: true, - DialContext: dialContext, - }, - } - if h2c { - s.httpClient.Transport = &http2.Transport{ - IdleConnTimeout: 90 * time.Second, - DialTLSContext: func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) { - return dialContext(ctx, network, addr) - }, - } - } - - return s, nil -} - -// NewDoHLocalNameServer creates DOH client object for local resolving -func NewDoHLocalNameServer(url *url.URL, queryStrategy QueryStrategy) *DoHNameServer { - url.Scheme = "https" - s := baseDOHNameServer(url, "DOHL", queryStrategy) - tr := &http.Transport{ - IdleConnTimeout: 90 * time.Second, - ForceAttemptHTTP2: true, - DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { - dest, err := net.ParseDestination(network + ":" + addr) - if err != nil { - return nil, err - } - conn, err := internet.DialSystem(ctx, dest, nil) - log.Record(&log.AccessMessage{ - From: "DNS", - To: s.dohURL, - Status: log.AccessAccepted, - Detour: "local", - }) - if err != nil { - return nil, err - } - return conn, nil - }, - } - s.httpClient = &http.Client{ - Timeout: time.Second * 180, - Transport: tr, - } - errors.LogInfo(context.Background(), "DNS: created Local DNS-over-HTTPS client for ", url.String()) - return s -} - -func baseDOHNameServer(url *url.URL, prefix string, queryStrategy QueryStrategy) *DoHNameServer { + errors.LogInfo(context.Background(), "DNS: created ", mode, " client for ", url.String(), ", with h2c ", h2c) s := &DoHNameServer{ ips: make(map[string]*record), pub: pubsub.NewService(), - name: prefix + "//" + url.Host, + name: mode + "//" + url.Host, dohURL: url.String(), queryStrategy: queryStrategy, } @@ -151,6 +63,65 @@ func baseDOHNameServer(url *url.URL, prefix string, queryStrategy QueryStrategy) Interval: time.Minute, Execute: s.Cleanup, } + s.httpClient = &http.Client{ + Transport: &http2.Transport{ + IdleConnTimeout: net.ConnIdleTimeout, + ReadIdleTimeout: net.ChromeH2KeepAlivePeriod, + DialTLSContext: func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) { + dest, err := net.ParseDestination(network + ":" + addr) + if err != nil { + return nil, err + } + var conn net.Conn + if dispatcher != nil { + dnsCtx := toDnsContext(ctx, s.dohURL) + if h2c { + dnsCtx = session.ContextWithMitmAlpn11(dnsCtx, false) // for insurance + dnsCtx = session.ContextWithMitmServerName(dnsCtx, url.Hostname()) + } + link, err := dispatcher.Dispatch(dnsCtx, dest) + select { + case <-ctx.Done(): + return nil, ctx.Err() + default: + } + if err != nil { + return nil, err + } + cc := common.ChainedClosable{} + if cw, ok := link.Writer.(common.Closable); ok { + cc = append(cc, cw) + } + if cr, ok := link.Reader.(common.Closable); ok { + cc = append(cc, cr) + } + conn = cnc.NewConnection( + cnc.ConnectionInputMulti(link.Writer), + cnc.ConnectionOutputMulti(link.Reader), + cnc.ConnectionOnClose(cc), + ) + } else { + log.Record(&log.AccessMessage{ + From: "DNS", + To: s.dohURL, + Status: log.AccessAccepted, + Detour: "local", + }) + conn, err = internet.DialSystem(ctx, dest, nil) + if err != nil { + return nil, err + } + } + if !h2c { + conn = utls.UClient(conn, &utls.Config{ServerName: url.Hostname()}, utls.HelloChrome_Auto) + if err := conn.(*utls.UConn).HandshakeContext(ctx); err != nil { + return nil, err + } + } + return conn, nil + }, + }, + } return s } @@ -310,6 +281,8 @@ func (s *DoHNameServer) dohHTTPSContext(ctx context.Context, b []byte) ([]byte, req.Header.Add("Accept", "application/dns-message") req.Header.Add("Content-Type", "application/dns-message") + req.Header.Set("X-Padding", strings.Repeat("X", int(crypto.RandBetween(100, 1000)))) + hc := s.httpClient resp, err := hc.Do(req.WithContext(ctx)) diff --git a/xray-core/app/dns/nameserver_doh_test.go b/xray-core/app/dns/nameserver_doh_test.go index ae4f9cc7d3..3dfcb15cf6 100644 --- a/xray-core/app/dns/nameserver_doh_test.go +++ b/xray-core/app/dns/nameserver_doh_test.go @@ -17,7 +17,7 @@ func TestDOHNameServer(t *testing.T) { url, err := url.Parse("https+local://1.1.1.1/dns-query") common.Must(err) - s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP) + s := NewDoHNameServer(url, QueryStrategy_USE_IP, nil, false) ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{ IPv4Enable: true, @@ -34,7 +34,7 @@ func TestDOHNameServerWithCache(t *testing.T) { url, err := url.Parse("https+local://1.1.1.1/dns-query") common.Must(err) - s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP) + s := NewDoHNameServer(url, QueryStrategy_USE_IP, nil, false) ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{ IPv4Enable: true, @@ -62,7 +62,7 @@ func TestDOHNameServerWithIPv4Override(t *testing.T) { url, err := url.Parse("https+local://1.1.1.1/dns-query") common.Must(err) - s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP4) + s := NewDoHNameServer(url, QueryStrategy_USE_IP4, nil, false) ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{ IPv4Enable: true, @@ -85,7 +85,7 @@ func TestDOHNameServerWithIPv6Override(t *testing.T) { url, err := url.Parse("https+local://1.1.1.1/dns-query") common.Must(err) - s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP6) + s := NewDoHNameServer(url, QueryStrategy_USE_IP6, nil, false) ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{ IPv4Enable: true, diff --git a/xray-core/common/crypto/crypto.go b/xray-core/common/crypto/crypto.go index 4ed7063484..464b4fa714 100644 --- a/xray-core/common/crypto/crypto.go +++ b/xray-core/common/crypto/crypto.go @@ -1,2 +1,15 @@ // Package crypto provides common crypto libraries for Xray. package crypto // import "github.com/xtls/xray-core/common/crypto" + +import ( + "crypto/rand" + "math/big" +) + +func RandBetween(from int64, to int64) int64 { + if from == to { + return from + } + bigInt, _ := rand.Int(rand.Reader, big.NewInt(to-from)) + return from + bigInt.Int64() +} diff --git a/xray-core/common/net/net.go b/xray-core/common/net/net.go index ce321425d6..92431c421f 100644 --- a/xray-core/common/net/net.go +++ b/xray-core/common/net/net.go @@ -1,2 +1,14 @@ // Package net is a drop-in replacement to Golang's net package, with some more functionalities. package net // import "github.com/xtls/xray-core/common/net" + +import "time" + +// defines the maximum time an idle TCP session can survive in the tunnel, so +// it should be consistent across HTTP versions and with other transports. +const ConnIdleTimeout = 300 * time.Second + +// consistent with quic-go +const QuicgoH3KeepAlivePeriod = 10 * time.Second + +// consistent with chrome +const ChromeH2KeepAlivePeriod = 45 * time.Second diff --git a/xray-core/core/core.go b/xray-core/core/core.go index 37e2e8b7d0..e36a90e20b 100644 --- a/xray-core/core/core.go +++ b/xray-core/core/core.go @@ -18,8 +18,8 @@ import ( var ( Version_x byte = 25 - Version_y byte = 2 - Version_z byte = 21 + Version_y byte = 3 + Version_z byte = 3 ) var ( diff --git a/xray-core/proxy/freedom/freedom.go b/xray-core/proxy/freedom/freedom.go index 19bc15aba4..324941ee1e 100644 --- a/xray-core/proxy/freedom/freedom.go +++ b/xray-core/proxy/freedom/freedom.go @@ -4,12 +4,12 @@ import ( "context" "crypto/rand" "io" - "math/big" "time" "github.com/pires/go-proxyproto" "github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common/buf" + "github.com/xtls/xray-core/common/crypto" "github.com/xtls/xray-core/common/dice" "github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/net" @@ -414,7 +414,7 @@ func (w *NoisePacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error { noise = n.Packet } else { //Random noise - noise, err = GenerateRandomBytes(randBetween(int64(n.LengthMin), + noise, err = GenerateRandomBytes(crypto.RandBetween(int64(n.LengthMin), int64(n.LengthMax))) } if err != nil { @@ -423,7 +423,7 @@ func (w *NoisePacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error { w.Writer.WriteMultiBuffer(buf.MultiBuffer{buf.FromBytes(noise)}) if n.DelayMin != 0 || n.DelayMax != 0 { - time.Sleep(time.Duration(randBetween(int64(n.DelayMin), int64(n.DelayMax))) * time.Millisecond) + time.Sleep(time.Duration(crypto.RandBetween(int64(n.DelayMin), int64(n.DelayMax))) * time.Millisecond) } } @@ -452,7 +452,7 @@ func (f *FragmentWriter) Write(b []byte) (int, error) { buf := make([]byte, 1024) var hello []byte for from := 0; ; { - to := from + int(randBetween(int64(f.fragment.LengthMin), int64(f.fragment.LengthMax))) + to := from + int(crypto.RandBetween(int64(f.fragment.LengthMin), int64(f.fragment.LengthMax))) if to > len(data) { to = len(data) } @@ -466,7 +466,7 @@ func (f *FragmentWriter) Write(b []byte) (int, error) { hello = append(hello, buf[:5+l]...) } else { _, err := f.writer.Write(buf[:5+l]) - time.Sleep(time.Duration(randBetween(int64(f.fragment.IntervalMin), int64(f.fragment.IntervalMax))) * time.Millisecond) + time.Sleep(time.Duration(crypto.RandBetween(int64(f.fragment.IntervalMin), int64(f.fragment.IntervalMax))) * time.Millisecond) if err != nil { return 0, err } @@ -493,13 +493,13 @@ func (f *FragmentWriter) Write(b []byte) (int, error) { return f.writer.Write(b) } for from := 0; ; { - to := from + int(randBetween(int64(f.fragment.LengthMin), int64(f.fragment.LengthMax))) + to := from + int(crypto.RandBetween(int64(f.fragment.LengthMin), int64(f.fragment.LengthMax))) if to > len(b) { to = len(b) } n, err := f.writer.Write(b[from:to]) from += n - time.Sleep(time.Duration(randBetween(int64(f.fragment.IntervalMin), int64(f.fragment.IntervalMax))) * time.Millisecond) + time.Sleep(time.Duration(crypto.RandBetween(int64(f.fragment.IntervalMin), int64(f.fragment.IntervalMax))) * time.Millisecond) if err != nil { return from, err } @@ -509,14 +509,6 @@ func (f *FragmentWriter) Write(b []byte) (int, error) { } } -// stolen from github.com/xtls/xray-core/transport/internet/reality -func randBetween(left int64, right int64) int64 { - if left == right { - return left - } - bigInt, _ := rand.Int(rand.Reader, big.NewInt(right-left)) - return left + bigInt.Int64() -} func GenerateRandomBytes(n int64) ([]byte, error) { b := make([]byte, n) _, err := rand.Read(b) diff --git a/xray-core/transport/internet/reality/reality.go b/xray-core/transport/internet/reality/reality.go index 0efcd96e2d..a9352aaf7c 100644 --- a/xray-core/transport/internet/reality/reality.go +++ b/xray-core/transport/internet/reality/reality.go @@ -8,7 +8,6 @@ import ( "crypto/ecdh" "crypto/ed25519" "crypto/hmac" - "crypto/rand" "crypto/sha256" "crypto/sha512" gotls "crypto/tls" @@ -16,7 +15,6 @@ import ( "encoding/binary" "fmt" "io" - "math/big" "net/http" "reflect" "regexp" @@ -27,6 +25,7 @@ import ( utls "github.com/refraction-networking/utls" "github.com/xtls/reality" + "github.com/xtls/xray-core/common/crypto" "github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/core" @@ -213,13 +212,13 @@ func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destinati } times := 1 if !first { - times = int(randBetween(config.SpiderY[4], config.SpiderY[5])) + times = int(crypto.RandBetween(config.SpiderY[4], config.SpiderY[5])) } for j := 0; j < times; j++ { if !first && j == 0 { req.Header.Set("Referer", firstURL) } - req.AddCookie(&http.Cookie{Name: "padding", Value: strings.Repeat("0", int(randBetween(config.SpiderY[0], config.SpiderY[1])))}) + req.AddCookie(&http.Cookie{Name: "padding", Value: strings.Repeat("0", int(crypto.RandBetween(config.SpiderY[0], config.SpiderY[1])))}) if resp, err = client.Do(req); err != nil { break } @@ -243,18 +242,18 @@ func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destinati } maps.Unlock() if !first { - time.Sleep(time.Duration(randBetween(config.SpiderY[6], config.SpiderY[7])) * time.Millisecond) // interval + time.Sleep(time.Duration(crypto.RandBetween(config.SpiderY[6], config.SpiderY[7])) * time.Millisecond) // interval } } } get(true) - concurrency := int(randBetween(config.SpiderY[2], config.SpiderY[3])) + concurrency := int(crypto.RandBetween(config.SpiderY[2], config.SpiderY[3])) for i := 0; i < concurrency; i++ { go get(false) } // Do not close the connection }() - time.Sleep(time.Duration(randBetween(config.SpiderY[8], config.SpiderY[9])) * time.Millisecond) // return + time.Sleep(time.Duration(crypto.RandBetween(config.SpiderY[8], config.SpiderY[9])) * time.Millisecond) // return return nil, errors.New("REALITY: processed invalid connection").AtWarning() } return uConn, nil @@ -271,7 +270,7 @@ var maps struct { } func getPathLocked(paths map[string]struct{}) string { - stopAt := int(randBetween(0, int64(len(paths)-1))) + stopAt := int(crypto.RandBetween(0, int64(len(paths)-1))) i := 0 for s := range paths { if i == stopAt { @@ -281,11 +280,3 @@ func getPathLocked(paths map[string]struct{}) string { } return "/" } - -func randBetween(left int64, right int64) int64 { - if left == right { - return left - } - bigInt, _ := rand.Int(rand.Reader, big.NewInt(right-left)) - return left + bigInt.Int64() -} diff --git a/xray-core/transport/internet/splithttp/config.go b/xray-core/transport/internet/splithttp/config.go index f160db318b..21e81aa18a 100644 --- a/xray-core/transport/internet/splithttp/config.go +++ b/xray-core/transport/internet/splithttp/config.go @@ -1,13 +1,12 @@ package splithttp import ( - "crypto/rand" - "math/big" "net/http" "net/url" "strings" "github.com/xtls/xray-core/common" + "github.com/xtls/xray-core/common/crypto" "github.com/xtls/xray-core/transport/internet" ) @@ -184,9 +183,5 @@ func init() { } func (c RangeConfig) rand() int32 { - if c.From == c.To { - return c.From - } - bigInt, _ := rand.Int(rand.Reader, big.NewInt(int64(c.To-c.From))) - return c.From + int32(bigInt.Int64()) + return int32(crypto.RandBetween(int64(c.From), int64(c.To))) } diff --git a/xray-core/transport/internet/splithttp/dialer.go b/xray-core/transport/internet/splithttp/dialer.go index b97c39e90f..f996a42e5c 100644 --- a/xray-core/transport/internet/splithttp/dialer.go +++ b/xray-core/transport/internet/splithttp/dialer.go @@ -30,16 +30,6 @@ import ( "golang.org/x/net/http2" ) -// defines the maximum time an idle TCP session can survive in the tunnel, so -// it should be consistent across HTTP versions and with other transports. -const connIdleTimeout = 300 * time.Second - -// consistent with quic-go -const quicgoH3KeepAlivePeriod = 10 * time.Second - -// consistent with chrome -const chromeH2KeepAlivePeriod = 45 * time.Second - type dialerConf struct { net.Destination *internet.MemoryStreamConfig @@ -154,13 +144,13 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea if httpVersion == "3" { if keepAlivePeriod == 0 { - keepAlivePeriod = quicgoH3KeepAlivePeriod + keepAlivePeriod = net.QuicgoH3KeepAlivePeriod } if keepAlivePeriod < 0 { keepAlivePeriod = 0 } quicConfig := &quic.Config{ - MaxIdleTimeout: connIdleTimeout, + MaxIdleTimeout: net.ConnIdleTimeout, // these two are defaults of quic-go/http3. the default of quic-go (no // http3) is different, so it is hardcoded here for clarity. @@ -168,7 +158,7 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea MaxIncomingStreams: -1, KeepAlivePeriod: keepAlivePeriod, } - transport = &http3.RoundTripper{ + transport = &http3.Transport{ QUICConfig: quicConfig, TLSClientConfig: gotlsConfig, Dial: func(ctx context.Context, addr string, tlsCfg *gotls.Config, cfg *quic.Config) (quic.EarlyConnection, error) { @@ -198,7 +188,7 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea return nil, err } default: - udpConn = &internet.FakePacketConn{c} + udpConn = &internet.FakePacketConn{Conn: c} udpAddr, err = net.ResolveUDPAddr("udp", c.RemoteAddr().String()) if err != nil { return nil, err @@ -210,7 +200,7 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea } } else if httpVersion == "2" { if keepAlivePeriod == 0 { - keepAlivePeriod = chromeH2KeepAlivePeriod + keepAlivePeriod = net.ChromeH2KeepAlivePeriod } if keepAlivePeriod < 0 { keepAlivePeriod = 0 @@ -219,7 +209,7 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea DialTLSContext: func(ctxInner context.Context, network string, addr string, cfg *gotls.Config) (net.Conn, error) { return dialContext(ctxInner) }, - IdleConnTimeout: connIdleTimeout, + IdleConnTimeout: net.ConnIdleTimeout, ReadIdleTimeout: keepAlivePeriod, } } else { @@ -230,7 +220,7 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea transport = &http.Transport{ DialTLSContext: httpDialContext, DialContext: httpDialContext, - IdleConnTimeout: connIdleTimeout, + IdleConnTimeout: net.ConnIdleTimeout, // chunked transfer download with KeepAlives is buggy with // http.Client and our custom dial context. DisableKeepAlives: true, diff --git a/xray-core/transport/internet/tls/config.pb.go b/xray-core/transport/internet/tls/config.pb.go index 43053c788d..bc45dc4e02 100644 --- a/xray-core/transport/internet/tls/config.pb.go +++ b/xray-core/transport/internet/tls/config.pb.go @@ -207,7 +207,7 @@ type Config struct { // @Critical PinnedPeerCertificateChainSha256 [][]byte `protobuf:"bytes,13,rep,name=pinned_peer_certificate_chain_sha256,json=pinnedPeerCertificateChainSha256,proto3" json:"pinned_peer_certificate_chain_sha256,omitempty"` // @Document Some certificate public key sha256 hashes. - // @Document After normal validation (required), if the verified cert's public key hash does not match any of these values, the connection will be aborted. + // @Document After normal validation (required), if one of certs in verified chain matches one of these values, the connection will be eventually accepted. // @Critical PinnedPeerCertificatePublicKeySha256 [][]byte `protobuf:"bytes,14,rep,name=pinned_peer_certificate_public_key_sha256,json=pinnedPeerCertificatePublicKeySha256,proto3" json:"pinned_peer_certificate_public_key_sha256,omitempty"` MasterKeyLog string `protobuf:"bytes,15,opt,name=master_key_log,json=masterKeyLog,proto3" json:"master_key_log,omitempty"` diff --git a/xray-core/transport/internet/tls/config.proto b/xray-core/transport/internet/tls/config.proto index c52d0be105..3fac25afb2 100644 --- a/xray-core/transport/internet/tls/config.proto +++ b/xray-core/transport/internet/tls/config.proto @@ -76,7 +76,7 @@ message Config { repeated bytes pinned_peer_certificate_chain_sha256 = 13; /* @Document Some certificate public key sha256 hashes. - @Document After normal validation (required), if the verified cert's public key hash does not match any of these values, the connection will be aborted. + @Document After normal validation (required), if one of certs in verified chain matches one of these values, the connection will be eventually accepted. @Critical */ repeated bytes pinned_peer_certificate_public_key_sha256 = 14; diff --git a/yesplaymusic/package.json b/yesplaymusic/package.json index 6285846fad..bb87fdde08 100644 --- a/yesplaymusic/package.json +++ b/yesplaymusic/package.json @@ -1,6 +1,6 @@ { "name": "yesplaymusic", - "version": "0.4.8", + "version": "0.4.9", "private": true, "description": "A third party music player for Netease Music", "author": "qier222", diff --git a/yt-dlp/test/test_networking.py b/yt-dlp/test/test_networking.py index d96624af18..63914bc4ba 100644 --- a/yt-dlp/test/test_networking.py +++ b/yt-dlp/test/test_networking.py @@ -720,6 +720,15 @@ class TestHTTPRequestHandler(TestRequestHandlerBase): rh, Request( f'http://127.0.0.1:{self.http_port}/headers', proxies={'all': 'http://10.255.255.255'})).close() + @pytest.mark.skip_handlers_if(lambda _, handler: handler not in ['Urllib', 'CurlCFFI'], 'handler does not support keep_header_casing') + def test_keep_header_casing(self, handler): + with handler() as rh: + res = validate_and_send( + rh, Request( + f'http://127.0.0.1:{self.http_port}/headers', headers={'X-test-heaDer': 'test'}, extensions={'keep_header_casing': True})).read().decode() + + assert 'X-test-heaDer: test' in res + @pytest.mark.parametrize('handler', ['Urllib', 'Requests', 'CurlCFFI'], indirect=True) class TestClientCertificate: @@ -1289,6 +1298,7 @@ class TestRequestHandlerValidation: ({'legacy_ssl': False}, False), ({'legacy_ssl': True}, False), ({'legacy_ssl': 'notabool'}, AssertionError), + ({'keep_header_casing': True}, UnsupportedRequest), ]), ('Requests', 'http', [ ({'cookiejar': 'notacookiejar'}, AssertionError), @@ -1299,6 +1309,9 @@ class TestRequestHandlerValidation: ({'legacy_ssl': False}, False), ({'legacy_ssl': True}, False), ({'legacy_ssl': 'notabool'}, AssertionError), + ({'keep_header_casing': False}, False), + ({'keep_header_casing': True}, False), + ({'keep_header_casing': 'notabool'}, AssertionError), ]), ('CurlCFFI', 'http', [ ({'cookiejar': 'notacookiejar'}, AssertionError), diff --git a/yt-dlp/test/test_utils.py b/yt-dlp/test/test_utils.py index 8f81d0b1b7..65f28db363 100644 --- a/yt-dlp/test/test_utils.py +++ b/yt-dlp/test/test_utils.py @@ -3,19 +3,20 @@ # Allow direct execution import os import sys -import unittest -import unittest.mock -import warnings -import datetime as dt sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) import contextlib +import datetime as dt import io import itertools import json +import pickle import subprocess +import unittest +import unittest.mock +import warnings import xml.etree.ElementTree from yt_dlp.compat import ( @@ -2087,21 +2088,26 @@ Line 1 headers = HTTPHeaderDict() headers['ytdl-test'] = b'0' self.assertEqual(list(headers.items()), [('Ytdl-Test', '0')]) + self.assertEqual(list(headers.sensitive().items()), [('ytdl-test', '0')]) headers['ytdl-test'] = 1 self.assertEqual(list(headers.items()), [('Ytdl-Test', '1')]) + self.assertEqual(list(headers.sensitive().items()), [('ytdl-test', '1')]) headers['Ytdl-test'] = '2' self.assertEqual(list(headers.items()), [('Ytdl-Test', '2')]) + self.assertEqual(list(headers.sensitive().items()), [('Ytdl-test', '2')]) self.assertTrue('ytDl-Test' in headers) self.assertEqual(str(headers), str(dict(headers))) self.assertEqual(repr(headers), str(dict(headers))) headers.update({'X-dlp': 'data'}) self.assertEqual(set(headers.items()), {('Ytdl-Test', '2'), ('X-Dlp', 'data')}) + self.assertEqual(set(headers.sensitive().items()), {('Ytdl-test', '2'), ('X-dlp', 'data')}) self.assertEqual(dict(headers), {'Ytdl-Test': '2', 'X-Dlp': 'data'}) self.assertEqual(len(headers), 2) self.assertEqual(headers.copy(), headers) - headers2 = HTTPHeaderDict({'X-dlp': 'data3'}, **headers, **{'X-dlp': 'data2'}) + headers2 = HTTPHeaderDict({'X-dlp': 'data3'}, headers, **{'X-dlP': 'data2'}) self.assertEqual(set(headers2.items()), {('Ytdl-Test', '2'), ('X-Dlp', 'data2')}) + self.assertEqual(set(headers2.sensitive().items()), {('Ytdl-test', '2'), ('X-dlP', 'data2')}) self.assertEqual(len(headers2), 2) headers2.clear() self.assertEqual(len(headers2), 0) @@ -2109,16 +2115,23 @@ Line 1 # ensure we prefer latter headers headers3 = HTTPHeaderDict({'Ytdl-TeSt': 1}, {'Ytdl-test': 2}) self.assertEqual(set(headers3.items()), {('Ytdl-Test', '2')}) + self.assertEqual(set(headers3.sensitive().items()), {('Ytdl-test', '2')}) del headers3['ytdl-tesT'] self.assertEqual(dict(headers3), {}) headers4 = HTTPHeaderDict({'ytdl-test': 'data;'}) self.assertEqual(set(headers4.items()), {('Ytdl-Test', 'data;')}) + self.assertEqual(set(headers4.sensitive().items()), {('ytdl-test', 'data;')}) # common mistake: strip whitespace from values # https://github.com/yt-dlp/yt-dlp/issues/8729 headers5 = HTTPHeaderDict({'ytdl-test': ' data; '}) self.assertEqual(set(headers5.items()), {('Ytdl-Test', 'data;')}) + self.assertEqual(set(headers5.sensitive().items()), {('ytdl-test', 'data;')}) + + # test if picklable + headers6 = HTTPHeaderDict(a=1, b=2) + self.assertEqual(pickle.loads(pickle.dumps(headers6)), headers6) def test_extract_basic_auth(self): assert extract_basic_auth('http://:foo.bar') == ('http://:foo.bar', None) diff --git a/yt-dlp/test/test_websockets.py b/yt-dlp/test/test_websockets.py index 06112cc0b8..dead5fe5c5 100644 --- a/yt-dlp/test/test_websockets.py +++ b/yt-dlp/test/test_websockets.py @@ -44,7 +44,7 @@ def websocket_handler(websocket): return websocket.send('2') elif isinstance(message, str): if message == 'headers': - return websocket.send(json.dumps(dict(websocket.request.headers))) + return websocket.send(json.dumps(dict(websocket.request.headers.raw_items()))) elif message == 'path': return websocket.send(websocket.request.path) elif message == 'source_address': @@ -266,18 +266,18 @@ class TestWebsSocketRequestHandlerConformance: with handler(cookiejar=cookiejar) as rh: ws = ws_validate_and_send(rh, Request(self.ws_base_url)) ws.send('headers') - assert json.loads(ws.recv())['cookie'] == 'test=ytdlp' + assert HTTPHeaderDict(json.loads(ws.recv()))['cookie'] == 'test=ytdlp' ws.close() with handler() as rh: ws = ws_validate_and_send(rh, Request(self.ws_base_url)) ws.send('headers') - assert 'cookie' not in json.loads(ws.recv()) + assert 'cookie' not in HTTPHeaderDict(json.loads(ws.recv())) ws.close() ws = ws_validate_and_send(rh, Request(self.ws_base_url, extensions={'cookiejar': cookiejar})) ws.send('headers') - assert json.loads(ws.recv())['cookie'] == 'test=ytdlp' + assert HTTPHeaderDict(json.loads(ws.recv()))['cookie'] == 'test=ytdlp' ws.close() @pytest.mark.skip_handler('Websockets', 'Set-Cookie not supported by websockets') @@ -287,7 +287,7 @@ class TestWebsSocketRequestHandlerConformance: ws_validate_and_send(rh, Request(f'{self.ws_base_url}/get_cookie', extensions={'cookiejar': YoutubeDLCookieJar()})) ws = ws_validate_and_send(rh, Request(self.ws_base_url, extensions={'cookiejar': YoutubeDLCookieJar()})) ws.send('headers') - assert 'cookie' not in json.loads(ws.recv()) + assert 'cookie' not in HTTPHeaderDict(json.loads(ws.recv())) ws.close() @pytest.mark.skip_handler('Websockets', 'Set-Cookie not supported by websockets') @@ -298,12 +298,12 @@ class TestWebsSocketRequestHandlerConformance: ws_validate_and_send(rh, Request(f'{self.ws_base_url}/get_cookie')) ws = ws_validate_and_send(rh, Request(self.ws_base_url)) ws.send('headers') - assert json.loads(ws.recv())['cookie'] == 'test=ytdlp' + assert HTTPHeaderDict(json.loads(ws.recv()))['cookie'] == 'test=ytdlp' ws.close() cookiejar.clear_session_cookies() ws = ws_validate_and_send(rh, Request(self.ws_base_url)) ws.send('headers') - assert 'cookie' not in json.loads(ws.recv()) + assert 'cookie' not in HTTPHeaderDict(json.loads(ws.recv())) ws.close() def test_source_address(self, handler): @@ -341,6 +341,14 @@ class TestWebsSocketRequestHandlerConformance: assert headers['test3'] == 'test3' ws.close() + def test_keep_header_casing(self, handler): + with handler(headers=HTTPHeaderDict({'x-TeSt1': 'test'})) as rh: + ws = ws_validate_and_send(rh, Request(self.ws_base_url, headers={'x-TeSt2': 'test'}, extensions={'keep_header_casing': True})) + ws.send('headers') + headers = json.loads(ws.recv()) + assert 'x-TeSt1' in headers + assert 'x-TeSt2' in headers + @pytest.mark.parametrize('client_cert', ( {'client_certificate': os.path.join(MTLS_CERT_DIR, 'clientwithkey.crt')}, { diff --git a/yt-dlp/yt_dlp/networking/_requests.py b/yt-dlp/yt_dlp/networking/_requests.py index 7de95ab3bf..23775845d6 100644 --- a/yt-dlp/yt_dlp/networking/_requests.py +++ b/yt-dlp/yt_dlp/networking/_requests.py @@ -296,6 +296,7 @@ class RequestsRH(RequestHandler, InstanceStoreMixin): extensions.pop('cookiejar', None) extensions.pop('timeout', None) extensions.pop('legacy_ssl', None) + extensions.pop('keep_header_casing', None) def _create_instance(self, cookiejar, legacy_ssl_support=None): session = RequestsSession() @@ -312,11 +313,12 @@ class RequestsRH(RequestHandler, InstanceStoreMixin): session.trust_env = False # no need, we already load proxies from env return session - def _send(self, request): - - headers = self._merge_headers(request.headers) + def _prepare_headers(self, _, headers): add_accept_encoding_header(headers, SUPPORTED_ENCODINGS) + def _send(self, request): + + headers = self._get_headers(request) max_redirects_exceeded = False session = self._get_instance( diff --git a/yt-dlp/yt_dlp/networking/_urllib.py b/yt-dlp/yt_dlp/networking/_urllib.py index 510bb2a691..a188b35f57 100644 --- a/yt-dlp/yt_dlp/networking/_urllib.py +++ b/yt-dlp/yt_dlp/networking/_urllib.py @@ -379,13 +379,15 @@ class UrllibRH(RequestHandler, InstanceStoreMixin): opener.addheaders = [] return opener - def _send(self, request): - headers = self._merge_headers(request.headers) + def _prepare_headers(self, _, headers): add_accept_encoding_header(headers, SUPPORTED_ENCODINGS) + + def _send(self, request): + headers = self._get_headers(request) urllib_req = urllib.request.Request( url=request.url, data=request.data, - headers=dict(headers), + headers=headers, method=request.method, ) diff --git a/yt-dlp/yt_dlp/networking/_websockets.py b/yt-dlp/yt_dlp/networking/_websockets.py index ec55567dae..7e5ab46004 100644 --- a/yt-dlp/yt_dlp/networking/_websockets.py +++ b/yt-dlp/yt_dlp/networking/_websockets.py @@ -116,6 +116,7 @@ class WebsocketsRH(WebSocketRequestHandler): extensions.pop('timeout', None) extensions.pop('cookiejar', None) extensions.pop('legacy_ssl', None) + extensions.pop('keep_header_casing', None) def close(self): # Remove the logging handler that contains a reference to our logger @@ -123,15 +124,16 @@ class WebsocketsRH(WebSocketRequestHandler): for name, handler in self.__logging_handlers.items(): logging.getLogger(name).removeHandler(handler) - def _send(self, request): - timeout = self._calculate_timeout(request) - headers = self._merge_headers(request.headers) + def _prepare_headers(self, request, headers): if 'cookie' not in headers: cookiejar = self._get_cookiejar(request) cookie_header = cookiejar.get_cookie_header(request.url) if cookie_header: headers['cookie'] = cookie_header + def _send(self, request): + timeout = self._calculate_timeout(request) + headers = self._get_headers(request) wsuri = parse_uri(request.url) create_conn_kwargs = { 'source_address': (self.source_address, 0) if self.source_address else None, diff --git a/yt-dlp/yt_dlp/networking/common.py b/yt-dlp/yt_dlp/networking/common.py index e8951c7e7d..ddceaa9a97 100644 --- a/yt-dlp/yt_dlp/networking/common.py +++ b/yt-dlp/yt_dlp/networking/common.py @@ -206,6 +206,7 @@ class RequestHandler(abc.ABC): - `cookiejar`: Cookiejar to use for this request. - `timeout`: socket timeout to use for this request. - `legacy_ssl`: Enable legacy SSL options for this request. See legacy_ssl_support. + - `keep_header_casing`: Keep the casing of headers when sending the request. To enable these, add extensions.pop('', None) to _check_extensions Apart from the url protocol, proxies dict may contain the following keys: @@ -259,6 +260,23 @@ class RequestHandler(abc.ABC): def _merge_headers(self, request_headers): return HTTPHeaderDict(self.headers, request_headers) + def _prepare_headers(self, request: Request, headers: HTTPHeaderDict) -> None: # noqa: B027 + """Additional operations to prepare headers before building. To be extended by subclasses. + @param request: Request object + @param headers: Merged headers to prepare + """ + + def _get_headers(self, request: Request) -> dict[str, str]: + """ + Get headers for external use. + Subclasses may define a _prepare_headers method to modify headers after merge but before building. + """ + headers = self._merge_headers(request.headers) + self._prepare_headers(request, headers) + if request.extensions.get('keep_header_casing'): + return headers.sensitive() + return dict(headers) + def _calculate_timeout(self, request): return float(request.extensions.get('timeout') or self.timeout) @@ -317,6 +335,7 @@ class RequestHandler(abc.ABC): assert isinstance(extensions.get('cookiejar'), (YoutubeDLCookieJar, NoneType)) assert isinstance(extensions.get('timeout'), (float, int, NoneType)) assert isinstance(extensions.get('legacy_ssl'), (bool, NoneType)) + assert isinstance(extensions.get('keep_header_casing'), (bool, NoneType)) def _validate(self, request): self._check_url_scheme(request) diff --git a/yt-dlp/yt_dlp/networking/impersonate.py b/yt-dlp/yt_dlp/networking/impersonate.py index 0626b3b491..b90d10b760 100644 --- a/yt-dlp/yt_dlp/networking/impersonate.py +++ b/yt-dlp/yt_dlp/networking/impersonate.py @@ -5,11 +5,11 @@ from abc import ABC from dataclasses import dataclass from typing import Any -from .common import RequestHandler, register_preference +from .common import RequestHandler, register_preference, Request from .exceptions import UnsupportedRequest from ..compat.types import NoneType from ..utils import classproperty, join_nonempty -from ..utils.networking import std_headers +from ..utils.networking import std_headers, HTTPHeaderDict @dataclass(order=True, frozen=True) @@ -123,7 +123,17 @@ class ImpersonateRequestHandler(RequestHandler, ABC): """Get the requested target for the request""" return self._resolve_target(request.extensions.get('impersonate') or self.impersonate) - def _get_impersonate_headers(self, request): + def _prepare_impersonate_headers(self, request: Request, headers: HTTPHeaderDict) -> None: # noqa: B027 + """Additional operations to prepare headers before building. To be extended by subclasses. + @param request: Request object + @param headers: Merged headers to prepare + """ + + def _get_impersonate_headers(self, request: Request) -> dict[str, str]: + """ + Get headers for external impersonation use. + Subclasses may define a _prepare_impersonate_headers method to modify headers after merge but before building. + """ headers = self._merge_headers(request.headers) if self._get_request_target(request) is not None: # remove all headers present in std_headers @@ -131,7 +141,11 @@ class ImpersonateRequestHandler(RequestHandler, ABC): for k, v in std_headers.items(): if headers.get(k) == v: headers.pop(k) - return headers + + self._prepare_impersonate_headers(request, headers) + if request.extensions.get('keep_header_casing'): + return headers.sensitive() + return dict(headers) @register_preference(ImpersonateRequestHandler) diff --git a/yt-dlp/yt_dlp/utils/networking.py b/yt-dlp/yt_dlp/utils/networking.py index 933b164be9..542abace87 100644 --- a/yt-dlp/yt_dlp/utils/networking.py +++ b/yt-dlp/yt_dlp/utils/networking.py @@ -1,9 +1,16 @@ +from __future__ import annotations + import collections +import collections.abc import random +import typing import urllib.parse import urllib.request -from ._utils import remove_start +if typing.TYPE_CHECKING: + T = typing.TypeVar('T') + +from ._utils import NO_DEFAULT, remove_start def random_user_agent(): @@ -51,32 +58,141 @@ def random_user_agent(): return _USER_AGENT_TPL % random.choice(_CHROME_VERSIONS) -class HTTPHeaderDict(collections.UserDict, dict): +class HTTPHeaderDict(dict): """ Store and access keys case-insensitively. The constructor can take multiple dicts, in which keys in the latter are prioritised. + + Retains a case sensitive mapping of the headers, which can be accessed via `.sensitive()`. """ + def __new__(cls, *args: typing.Any, **kwargs: typing.Any) -> typing.Self: + obj = dict.__new__(cls, *args, **kwargs) + obj.__sensitive_map = {} + return obj - def __init__(self, *args, **kwargs): + def __init__(self, /, *args, **kwargs): super().__init__() - for dct in args: - if dct is not None: - self.update(dct) - self.update(kwargs) + self.__sensitive_map = {} - def __setitem__(self, key, value): - if isinstance(value, bytes): - value = value.decode('latin-1') - super().__setitem__(key.title(), str(value).strip()) + for dct in filter(None, args): + self.update(dct) + if kwargs: + self.update(kwargs) - def __getitem__(self, key): + def sensitive(self, /) -> dict[str, str]: + return { + self.__sensitive_map[key]: value + for key, value in self.items() + } + + def __contains__(self, key: str, /) -> bool: + return super().__contains__(key.title() if isinstance(key, str) else key) + + def __delitem__(self, key: str, /) -> None: + key = key.title() + del self.__sensitive_map[key] + super().__delitem__(key) + + def __getitem__(self, key, /) -> str: return super().__getitem__(key.title()) - def __delitem__(self, key): - super().__delitem__(key.title()) + def __ior__(self, other, /): + if isinstance(other, type(self)): + other = other.sensitive() + if isinstance(other, dict): + self.update(other) + return + return NotImplemented - def __contains__(self, key): - return super().__contains__(key.title() if isinstance(key, str) else key) + def __or__(self, other, /) -> typing.Self: + if isinstance(other, type(self)): + other = other.sensitive() + if isinstance(other, dict): + return type(self)(self.sensitive(), other) + return NotImplemented + + def __ror__(self, other, /) -> typing.Self: + if isinstance(other, type(self)): + other = other.sensitive() + if isinstance(other, dict): + return type(self)(other, self.sensitive()) + return NotImplemented + + def __setitem__(self, key: str, value, /) -> None: + if isinstance(value, bytes): + value = value.decode('latin-1') + key_title = key.title() + self.__sensitive_map[key_title] = key + super().__setitem__(key_title, str(value).strip()) + + def clear(self, /) -> None: + self.__sensitive_map.clear() + super().clear() + + def copy(self, /) -> typing.Self: + return type(self)(self.sensitive()) + + @typing.overload + def get(self, key: str, /) -> str | None: ... + + @typing.overload + def get(self, key: str, /, default: T) -> str | T: ... + + def get(self, key, /, default=NO_DEFAULT): + key = key.title() + if default is NO_DEFAULT: + return super().get(key) + return super().get(key, default) + + @typing.overload + def pop(self, key: str, /) -> str: ... + + @typing.overload + def pop(self, key: str, /, default: T) -> str | T: ... + + def pop(self, key, /, default=NO_DEFAULT): + key = key.title() + if default is NO_DEFAULT: + self.__sensitive_map.pop(key) + return super().pop(key) + self.__sensitive_map.pop(key, default) + return super().pop(key, default) + + def popitem(self) -> tuple[str, str]: + self.__sensitive_map.popitem() + return super().popitem() + + @typing.overload + def setdefault(self, key: str, /) -> str: ... + + @typing.overload + def setdefault(self, key: str, /, default) -> str: ... + + def setdefault(self, key, /, default=None) -> str: + key = key.title() + if key in self.__sensitive_map: + return super().__getitem__(key) + + self[key] = default or '' + return self[key] + + def update(self, other, /, **kwargs) -> None: + if isinstance(other, type(self)): + other = other.sensitive() + if isinstance(other, collections.abc.Mapping): + for key, value in other.items(): + self[key] = value + + elif hasattr(other, 'keys'): + for key in other.keys(): # noqa: SIM118 + self[key] = other[key] + + else: + for key, value in other: + self[key] = value + + for key, value in kwargs.items(): + self[key] = value std_headers = HTTPHeaderDict({