Update On Sat Nov 2 19:33:11 CET 2024

This commit is contained in:
github-action[bot]
2024-11-02 19:33:11 +01:00
parent 453bb0e96c
commit d668647e75
106 changed files with 8650 additions and 1037 deletions

1
.github/update.log vendored
View File

@@ -812,3 +812,4 @@ Update On Tue Oct 29 19:36:45 CET 2024
Update On Wed Oct 30 19:35:20 CET 2024 Update On Wed Oct 30 19:35:20 CET 2024
Update On Thu Oct 31 19:36:27 CET 2024 Update On Thu Oct 31 19:36:27 CET 2024
Update On Fri Nov 1 19:37:29 CET 2024 Update On Fri Nov 1 19:37:29 CET 2024
Update On Sat Nov 2 19:33:00 CET 2024

View File

@@ -25,7 +25,7 @@ var convertCmd = &cobra.Command{
log.Fatal(err) log.Fatal(err)
} }
if err := instance.Init(configFile); err != nil { if err := instance.InitConfig(configFile); err != nil {
log.Fatal(err) log.Fatal(err)
} }

View File

@@ -5,10 +5,10 @@ go 1.23
toolchain go1.23.2 toolchain go1.23.2
require ( require (
github.com/klauspost/compress v1.17.10 github.com/klauspost/compress v1.17.11
github.com/maxmind/mmdbwriter v1.0.0 github.com/maxmind/mmdbwriter v1.0.0
github.com/oschwald/maxminddb-golang v1.13.1 github.com/oschwald/maxminddb-golang v1.13.1
github.com/sagernet/sing-box v1.9.7 github.com/sagernet/sing-box v1.10.1
github.com/spf13/cobra v1.8.1 github.com/spf13/cobra v1.8.1
github.com/tailscale/hujson v0.0.0-20241010212012-29efb4a0184b github.com/tailscale/hujson v0.0.0-20241010212012-29efb4a0184b
github.com/tidwall/gjson v1.18.0 github.com/tidwall/gjson v1.18.0
@@ -20,15 +20,15 @@ require (
require ( require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/kr/text v0.2.0 // indirect github.com/kr/text v0.2.0 // indirect
github.com/miekg/dns v1.1.59 // indirect github.com/miekg/dns v1.1.62 // indirect
github.com/sagernet/sing v0.4.3 // indirect github.com/sagernet/sing v0.5.0-rc.2 // indirect
github.com/sagernet/sing-dns v0.2.3 // indirect github.com/sagernet/sing-dns v0.3.0-rc.2 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect github.com/tidwall/pretty v1.2.0 // indirect
golang.org/x/mod v0.18.0 // indirect golang.org/x/mod v0.19.0 // indirect
golang.org/x/net v0.25.0 // indirect golang.org/x/net v0.27.0 // indirect
golang.org/x/sync v0.8.0 // indirect golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.25.0 // indirect golang.org/x/sys v0.25.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect golang.org/x/tools v0.23.0 // indirect
) )

View File

@@ -10,14 +10,14 @@ github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a h1:fEBsGL/sjAuJrgah5X
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/klauspost/compress v1.17.10 h1:oXAz+Vh0PMUvJczoi+flxpnBEPxoER1IaAnU/NMPtT0= github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.10/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/maxmind/mmdbwriter v1.0.0 h1:bieL4P6yaYaHvbtLSwnKtEvScUKKD6jcKaLiTM3WSMw= github.com/maxmind/mmdbwriter v1.0.0 h1:bieL4P6yaYaHvbtLSwnKtEvScUKKD6jcKaLiTM3WSMw=
github.com/maxmind/mmdbwriter v1.0.0/go.mod h1:noBMCUtyN5PUQ4H8ikkOvGSHhzhLok51fON2hcrpKj8= github.com/maxmind/mmdbwriter v1.0.0/go.mod h1:noBMCUtyN5PUQ4H8ikkOvGSHhzhLok51fON2hcrpKj8=
github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs= github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ=
github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk= github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss= github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss=
@@ -33,12 +33,12 @@ github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sagernet/quic-go v0.47.0-beta.2 h1:1tCGWFOSaXIeuQaHrwOMJIYvlupjTcaVInGQw5ArULU= github.com/sagernet/quic-go v0.47.0-beta.2 h1:1tCGWFOSaXIeuQaHrwOMJIYvlupjTcaVInGQw5ArULU=
github.com/sagernet/quic-go v0.47.0-beta.2/go.mod h1:bLVKvElSEMNv7pu7SZHscW02TYigzQ5lQu3Nh4wNh8Q= github.com/sagernet/quic-go v0.47.0-beta.2/go.mod h1:bLVKvElSEMNv7pu7SZHscW02TYigzQ5lQu3Nh4wNh8Q=
github.com/sagernet/sing v0.4.3 h1:Ty/NAiNnVd6844k7ujlL5lkzydhcTH5Psc432jXA4Y8= github.com/sagernet/sing v0.5.0-rc.2 h1:tIrs6pRbjJWvI0ITRSg47P1wosY+iSuHpw9t5/hBx+Q=
github.com/sagernet/sing v0.4.3/go.mod h1:ieZHA/+Y9YZfXs2I3WtuwgyCZ6GPsIR7HdKb1SdEnls= github.com/sagernet/sing v0.5.0-rc.2/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing-box v1.9.7 h1:+vA+xjbZuE7drPrkBRPPL/++Jz3ZcL5AExCR9LKAUVM= github.com/sagernet/sing-box v1.10.1 h1:J3H0TzF0LGC4uOR62TpSuAhhHkv3Bx5M5F5kK5JB+WA=
github.com/sagernet/sing-box v1.9.7/go.mod h1:1eZ08ofoql6NdYCkBJXICbqhWr1SzQkrxGy1p6RcY/U= github.com/sagernet/sing-box v1.10.1/go.mod h1:Nk9Ww0M1ulUsbfd5d4dfMBfJ0Audmm6m5+YYdvdpcZQ=
github.com/sagernet/sing-dns v0.2.3 h1:YzeBUn2tR38F7HtvGEQ0kLRLmZWMEgi/+7wqa4Twb1k= github.com/sagernet/sing-dns v0.3.0-rc.2 h1:z1yROBxd/6wik5h53Sz5df1DSmbPTaOu/Z0wAmyXGoQ=
github.com/sagernet/sing-dns v0.2.3/go.mod h1:BJpJv6XLnrUbSyIntOT6DG9FW0f4fETmPAHvNjOprLg= github.com/sagernet/sing-dns v0.3.0-rc.2/go.mod h1:TqLIelI+FAbVEdiTRolhGLOwvhVjY7oT+wezlOJUQ7M=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
@@ -55,22 +55,22 @@ github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@@ -10,6 +10,7 @@ import (
type Container interface { type Container interface {
GetEntry(name string) (*Entry, bool) GetEntry(name string) (*Entry, bool)
Len() int
Add(entry *Entry, opts ...IgnoreIPOption) error Add(entry *Entry, opts ...IgnoreIPOption) error
Remove(entry *Entry, rCase CaseRemove, opts ...IgnoreIPOption) error Remove(entry *Entry, rCase CaseRemove, opts ...IgnoreIPOption) error
Loop() <-chan *Entry Loop() <-chan *Entry
@@ -41,6 +42,13 @@ func (c *container) GetEntry(name string) (*Entry, bool) {
return val, true return val, true
} }
func (c *container) Len() int {
if !c.isValid() {
return 0
}
return len(c.entries)
}
func (c *container) Loop() <-chan *Entry { func (c *container) Loop() <-chan *Entry {
ch := make(chan *Entry, 300) ch := make(chan *Entry, 300)
go func() { go func() {

View File

@@ -9,21 +9,31 @@ import (
"github.com/tailscale/hujson" "github.com/tailscale/hujson"
) )
type Instance struct { type Instance interface {
config *config InitConfig(configFile string) error
InitConfigFromBytes(content []byte) error
AddInput(InputConverter)
AddOutput(OutputConverter)
ResetInput()
ResetOutput()
RunInput(Container) error
RunOutput(Container) error
Run() error
}
type instance struct {
input []InputConverter input []InputConverter
output []OutputConverter output []OutputConverter
} }
func NewInstance() (*Instance, error) { func NewInstance() (Instance, error) {
return &Instance{ return &instance{
config: new(config),
input: make([]InputConverter, 0), input: make([]InputConverter, 0),
output: make([]OutputConverter, 0), output: make([]OutputConverter, 0),
}, nil }, nil
} }
func (i *Instance) Init(configFile string) error { func (i *instance) InitConfig(configFile string) error {
var content []byte var content []byte
var err error var err error
configFile = strings.TrimSpace(configFile) configFile = strings.TrimSpace(configFile)
@@ -36,50 +46,48 @@ func (i *Instance) Init(configFile string) error {
return err return err
} }
return i.InitConfigFromBytes(content)
}
func (i *instance) InitConfigFromBytes(content []byte) error {
config := new(config)
// Support JSON with comments and trailing commas // Support JSON with comments and trailing commas
content, _ = hujson.Standardize(content) content, _ = hujson.Standardize(content)
if err := json.Unmarshal(content, &i.config); err != nil { if err := json.Unmarshal(content, &config); err != nil {
return err return err
} }
for _, input := range i.config.Input { for _, input := range config.Input {
i.input = append(i.input, input.converter) i.input = append(i.input, input.converter)
} }
for _, output := range i.config.Output { for _, output := range config.Output {
i.output = append(i.output, output.converter) i.output = append(i.output, output.converter)
} }
return nil return nil
} }
func (i *Instance) InitFromBytes(content []byte) error { func (i *instance) AddInput(ic InputConverter) {
// Support JSON with comments and trailing commas i.input = append(i.input, ic)
content, _ = hujson.Standardize(content)
if err := json.Unmarshal(content, &i.config); err != nil {
return err
}
for _, input := range i.config.Input {
i.input = append(i.input, input.converter)
}
for _, output := range i.config.Output {
i.output = append(i.output, output.converter)
}
return nil
} }
func (i *Instance) Run() error { func (i *instance) AddOutput(oc OutputConverter) {
if len(i.input) == 0 || len(i.output) == 0 { i.output = append(i.output, oc)
return errors.New("input type and output type must be specified") }
}
func (i *instance) ResetInput() {
i.input = make([]InputConverter, 0)
}
func (i *instance) ResetOutput() {
i.output = make([]OutputConverter, 0)
}
func (i *instance) RunInput(container Container) error {
var err error var err error
container := NewContainer()
for _, ic := range i.input { for _, ic := range i.input {
container, err = ic.Input(container) container, err = ic.Input(container)
if err != nil { if err != nil {
@@ -87,6 +95,10 @@ func (i *Instance) Run() error {
} }
} }
return nil
}
func (i *instance) RunOutput(container Container) error {
for _, oc := range i.output { for _, oc := range i.output {
if err := oc.Output(container); err != nil { if err := oc.Output(container); err != nil {
return err return err
@@ -95,3 +107,21 @@ func (i *Instance) Run() error {
return nil return nil
} }
func (i *instance) Run() error {
if len(i.input) == 0 || len(i.output) == 0 {
return errors.New("input type and output type must be specified")
}
container := NewContainer()
if err := i.RunInput(container); err != nil {
return err
}
if err := i.RunOutput(container); err != nil {
return err
}
return nil
}

View File

@@ -9,6 +9,12 @@ import (
"strings" "strings"
"github.com/Loyalsoldier/geoip/lib" "github.com/Loyalsoldier/geoip/lib"
"github.com/Loyalsoldier/geoip/plugin/maxmind"
"github.com/Loyalsoldier/geoip/plugin/mihomo"
"github.com/Loyalsoldier/geoip/plugin/plaintext"
"github.com/Loyalsoldier/geoip/plugin/singbox"
"github.com/Loyalsoldier/geoip/plugin/special"
"github.com/Loyalsoldier/geoip/plugin/v2ray"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@@ -61,10 +67,6 @@ var lookupCmd = &cobra.Command{
// Get searchlist // Get searchlist
searchList, _ := cmd.Flags().GetStringSlice("searchlist") searchList, _ := cmd.Flags().GetStringSlice("searchlist")
searchListStr := strings.Join(searchList, `", "`)
if searchListStr != "" {
searchListStr = fmt.Sprint(`"`, searchListStr, `"`) // `"cn", "en"`
}
switch len(args) > 0 { switch len(args) > 0 {
case true: // With search arg, run in once mode case true: // With search arg, run in once mode
@@ -74,11 +76,33 @@ var lookupCmd = &cobra.Command{
return return
} }
execute(format, name, uri, dir, search, searchListStr) instance, err := lib.NewInstance()
if err != nil {
log.Fatal(err)
}
instance.AddInput(getInputForLookup(format, name, uri, dir))
instance.AddOutput(getOutputForLookup(search, searchList...))
if err := instance.Run(); err != nil {
log.Fatal(err)
}
case false: // No search arg, run in REPL mode case false: // No search arg, run in REPL mode
instance, err := lib.NewInstance()
if err != nil {
log.Fatal(err)
}
instance.AddInput(getInputForLookup(format, name, uri, dir))
container := lib.NewContainer()
if err := instance.RunInput(container); err != nil {
log.Fatal(err)
}
fmt.Println(`Enter IP or CIDR (type "exit" to quit):`) fmt.Println(`Enter IP or CIDR (type "exit" to quit):`)
fmt.Print(">> ") fmt.Print(">> ")
scanner := bufio.NewScanner(os.Stdin) scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() { for scanner.Scan() {
search := strings.ToLower(strings.TrimSpace(scanner.Text())) search := strings.ToLower(strings.TrimSpace(scanner.Text()))
@@ -98,7 +122,12 @@ var lookupCmd = &cobra.Command{
continue continue
} }
execute(format, name, uri, dir, search, searchListStr) instance.ResetOutput()
instance.AddOutput(getOutputForLookup(search, searchList...))
if err := instance.RunOutput(container); err != nil {
log.Fatal(err)
}
fmt.Println() fmt.Println()
fmt.Print(">> ") fmt.Print(">> ")
@@ -127,47 +156,99 @@ func isValidIPOrCIDR(search string) bool {
return err == nil return err == nil
} }
func execute(format, name, uri, dir, search, searchListStr string) { func getInputForLookup(format, name, uri, dir string) lib.InputConverter {
config := generateConfigForLookup(format, name, uri, dir, search, searchListStr) var input lib.InputConverter
instance, err := lib.NewInstance() switch strings.ToLower(format) {
if err != nil { case strings.ToLower(maxmind.TypeMaxmindMMDBIn):
log.Fatal(err) input = &maxmind.MaxmindMMDBIn{
} Type: maxmind.TypeMaxmindMMDBIn,
Action: lib.ActionAdd,
if err := instance.InitFromBytes([]byte(config)); err != nil { Description: maxmind.DescMaxmindMMDBIn,
log.Fatal(err) URI: uri,
}
if err := instance.Run(); err != nil {
log.Fatal(err)
}
}
func generateConfigForLookup(format, name, uri, dir, search, searchListStr string) string {
return fmt.Sprintf(`
{
"input": [
{
"type": "%s",
"action": "add",
"args": {
"name": "%s",
"uri": "%s",
"inputDir": "%s"
}
} }
],
"output": [ case strings.ToLower(mihomo.TypeMRSIn):
{ input = &mihomo.MRSIn{
"type": "lookup", Type: mihomo.TypeMRSIn,
"action": "output", Action: lib.ActionAdd,
"args": { Description: mihomo.DescMRSIn,
"search": "%s", Name: name,
"searchList": [%s] URI: uri,
} InputDir: dir,
} }
]
case strings.ToLower(singbox.TypeSRSIn):
input = &singbox.SRSIn{
Type: singbox.TypeSRSIn,
Action: lib.ActionAdd,
Description: singbox.DescSRSIn,
Name: name,
URI: uri,
InputDir: dir,
}
case strings.ToLower(v2ray.TypeGeoIPdatIn):
input = &v2ray.GeoIPDatIn{
Type: v2ray.TypeGeoIPdatIn,
Action: lib.ActionAdd,
Description: v2ray.DescGeoIPdatIn,
URI: uri,
}
case strings.ToLower(plaintext.TypeTextIn):
input = &plaintext.TextIn{
Type: plaintext.TypeTextIn,
Action: lib.ActionAdd,
Description: plaintext.DescTextIn,
Name: name,
URI: uri,
InputDir: dir,
}
case strings.ToLower(plaintext.TypeClashRuleSetIPCIDRIn):
input = &plaintext.TextIn{
Type: plaintext.TypeClashRuleSetIPCIDRIn,
Action: lib.ActionAdd,
Description: plaintext.DescClashRuleSetIn,
Name: name,
URI: uri,
InputDir: dir,
}
case strings.ToLower(plaintext.TypeClashRuleSetClassicalIn):
input = &plaintext.TextIn{
Type: plaintext.TypeClashRuleSetClassicalIn,
Action: lib.ActionAdd,
Description: plaintext.DescClashClassicalIn,
Name: name,
URI: uri,
InputDir: dir,
}
case strings.ToLower(plaintext.TypeSurgeRuleSetIn):
input = &plaintext.TextIn{
Type: plaintext.TypeSurgeRuleSetIn,
Action: lib.ActionAdd,
Description: plaintext.DescSurgeRuleSetIn,
Name: name,
URI: uri,
InputDir: dir,
}
default:
log.Fatal("unsupported input format")
}
return input
} }
`, format, name, uri, dir, search, searchListStr)
func getOutputForLookup(search string, searchList ...string) lib.OutputConverter {
return &special.Lookup{
Type: special.TypeLookup,
Action: lib.ActionOutput,
Description: special.DescLookup,
Search: search,
SearchList: searchList,
}
} }

View File

@@ -5,75 +5,10 @@ import (
"strings" "strings"
"github.com/Loyalsoldier/geoip/lib" "github.com/Loyalsoldier/geoip/lib"
"github.com/Loyalsoldier/geoip/plugin/special"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
const tempConfig = `
{
"input": [
{
"type": "stdin",
"action": "add",
"args": {
"name": "temp"
}
}
],
"output": [
{
"type": "stdout",
"action": "output"
}
]
}
`
const tempConfigWithIPv4 = `
{
"input": [
{
"type": "stdin",
"action": "add",
"args": {
"name": "temp"
}
}
],
"output": [
{
"type": "stdout",
"action": "output",
"args": {
"onlyIPType": "ipv4"
}
}
]
}
`
const tempConfigWithIPv6 = `
{
"input": [
{
"type": "stdin",
"action": "add",
"args": {
"name": "temp"
}
}
],
"output": [
{
"type": "stdout",
"action": "output",
"args": {
"onlyIPType": "ipv6"
}
}
]
}
`
func init() { func init() {
rootCmd.AddCommand(mergeCmd) rootCmd.AddCommand(mergeCmd)
mergeCmd.PersistentFlags().StringP("onlyiptype", "t", "", "The only IP type to output, available options: \"ipv4\", \"ipv6\"") mergeCmd.PersistentFlags().StringP("onlyiptype", "t", "", "The only IP type to output, available options: \"ipv4\", \"ipv6\"")
@@ -91,27 +26,53 @@ var mergeCmd = &cobra.Command{
log.Fatal("invalid argument onlyiptype: ", otype) log.Fatal("invalid argument onlyiptype: ", otype)
} }
var configBytes []byte
switch lib.IPType(otype) {
case lib.IPv4:
configBytes = []byte(tempConfigWithIPv4)
case lib.IPv6:
configBytes = []byte(tempConfigWithIPv6)
default:
configBytes = []byte(tempConfig)
}
instance, err := lib.NewInstance() instance, err := lib.NewInstance()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
if err := instance.InitFromBytes(configBytes); err != nil { instance.AddInput(getInputForMerge())
log.Fatal(err) instance.AddOutput(getOutputForMerge(otype))
}
if err := instance.Run(); err != nil { if err := instance.Run(); err != nil {
log.Fatal(err) log.Fatal(err)
} }
}, },
} }
func getInputForMerge() lib.InputConverter {
return &special.Stdin{
Type: special.TypeStdin,
Action: lib.ActionAdd,
Description: special.DescStdin,
Name: "temp",
}
}
func getOutputForMerge(otype string) lib.OutputConverter {
switch lib.IPType(otype) {
case lib.IPv4:
return &special.Stdout{
Type: special.TypeStdout,
Action: lib.ActionOutput,
Description: special.DescStdout,
OnlyIPType: lib.IPv4,
}
case lib.IPv6:
return &special.Stdout{
Type: special.TypeStdout,
Action: lib.ActionOutput,
Description: special.DescStdout,
OnlyIPType: lib.IPv6,
}
default:
return &special.Stdout{
Type: special.TypeStdout,
Action: lib.ActionOutput,
Description: special.DescStdout,
}
}
}

View File

@@ -13,8 +13,8 @@ import (
) )
const ( const (
typeASNCSV = "maxmindGeoLite2ASNCSV" TypeASNCSV = "maxmindGeoLite2ASNCSV"
descASNCSV = "Convert MaxMind GeoLite2 ASN CSV data to other formats" DescASNCSV = "Convert MaxMind GeoLite2 ASN CSV data to other formats"
) )
var ( var (
@@ -23,11 +23,11 @@ var (
) )
func init() { func init() {
lib.RegisterInputConfigCreator(typeASNCSV, func(action lib.Action, data json.RawMessage) (lib.InputConverter, error) { lib.RegisterInputConfigCreator(TypeASNCSV, func(action lib.Action, data json.RawMessage) (lib.InputConverter, error) {
return newGeoLite2ASNCSV(action, data) return newGeoLite2ASNCSV(action, data)
}) })
lib.RegisterInputConverter(typeASNCSV, &geoLite2ASNCSV{ lib.RegisterInputConverter(TypeASNCSV, &GeoLite2ASNCSV{
Description: descASNCSV, Description: DescASNCSV,
}) })
} }
@@ -77,13 +77,13 @@ func newGeoLite2ASNCSV(action lib.Action, data json.RawMessage) (lib.InputConver
} }
if len(wantList) == 0 { if len(wantList) == 0 {
return nil, fmt.Errorf("❌ [type %s | action %s] wantedList must be specified in config", typeASNCSV, action) return nil, fmt.Errorf("❌ [type %s | action %s] wantedList must be specified in config", TypeASNCSV, action)
} }
return &geoLite2ASNCSV{ return &GeoLite2ASNCSV{
Type: typeASNCSV, Type: TypeASNCSV,
Action: action, Action: action,
Description: descASNCSV, Description: DescASNCSV,
IPv4File: tmp.IPv4File, IPv4File: tmp.IPv4File,
IPv6File: tmp.IPv6File, IPv6File: tmp.IPv6File,
Want: wantList, Want: wantList,
@@ -91,7 +91,7 @@ func newGeoLite2ASNCSV(action lib.Action, data json.RawMessage) (lib.InputConver
}, nil }, nil
} }
type geoLite2ASNCSV struct { type GeoLite2ASNCSV struct {
Type string Type string
Action lib.Action Action lib.Action
Description string Description string
@@ -101,19 +101,19 @@ type geoLite2ASNCSV struct {
OnlyIPType lib.IPType OnlyIPType lib.IPType
} }
func (g *geoLite2ASNCSV) GetType() string { func (g *GeoLite2ASNCSV) GetType() string {
return g.Type return g.Type
} }
func (g *geoLite2ASNCSV) GetAction() lib.Action { func (g *GeoLite2ASNCSV) GetAction() lib.Action {
return g.Action return g.Action
} }
func (g *geoLite2ASNCSV) GetDescription() string { func (g *GeoLite2ASNCSV) GetDescription() string {
return g.Description return g.Description
} }
func (g *geoLite2ASNCSV) Input(container lib.Container) (lib.Container, error) { func (g *GeoLite2ASNCSV) Input(container lib.Container) (lib.Container, error) {
entries := make(map[string]*lib.Entry) entries := make(map[string]*lib.Entry)
if g.IPv4File != "" { if g.IPv4File != "" {
@@ -158,7 +158,7 @@ func (g *geoLite2ASNCSV) Input(container lib.Container) (lib.Container, error) {
return container, nil return container, nil
} }
func (g *geoLite2ASNCSV) process(file string, entries map[string]*lib.Entry) error { func (g *GeoLite2ASNCSV) process(file string, entries map[string]*lib.Entry) error {
if entries == nil { if entries == nil {
entries = make(map[string]*lib.Entry) entries = make(map[string]*lib.Entry)
} }

View File

@@ -13,8 +13,8 @@ import (
) )
const ( const (
typeCountryCSV = "maxmindGeoLite2CountryCSV" TypeCountryCSV = "maxmindGeoLite2CountryCSV"
descCountryCSV = "Convert MaxMind GeoLite2 country CSV data to other formats" DescCountryCSV = "Convert MaxMind GeoLite2 country CSV data to other formats"
) )
var ( var (
@@ -24,11 +24,11 @@ var (
) )
func init() { func init() {
lib.RegisterInputConfigCreator(typeCountryCSV, func(action lib.Action, data json.RawMessage) (lib.InputConverter, error) { lib.RegisterInputConfigCreator(TypeCountryCSV, func(action lib.Action, data json.RawMessage) (lib.InputConverter, error) {
return newGeoLite2CountryCSV(action, data) return newGeoLite2CountryCSV(action, data)
}) })
lib.RegisterInputConverter(typeCountryCSV, &geoLite2CountryCSV{ lib.RegisterInputConverter(TypeCountryCSV, &GeoLite2CountryCSV{
Description: descCountryCSV, Description: DescCountryCSV,
}) })
} }
@@ -67,10 +67,10 @@ func newGeoLite2CountryCSV(action lib.Action, data json.RawMessage) (lib.InputCo
} }
} }
return &geoLite2CountryCSV{ return &GeoLite2CountryCSV{
Type: typeCountryCSV, Type: TypeCountryCSV,
Action: action, Action: action,
Description: descCountryCSV, Description: DescCountryCSV,
CountryCodeFile: tmp.CountryCodeFile, CountryCodeFile: tmp.CountryCodeFile,
IPv4File: tmp.IPv4File, IPv4File: tmp.IPv4File,
IPv6File: tmp.IPv6File, IPv6File: tmp.IPv6File,
@@ -79,7 +79,7 @@ func newGeoLite2CountryCSV(action lib.Action, data json.RawMessage) (lib.InputCo
}, nil }, nil
} }
type geoLite2CountryCSV struct { type GeoLite2CountryCSV struct {
Type string Type string
Action lib.Action Action lib.Action
Description string Description string
@@ -90,19 +90,19 @@ type geoLite2CountryCSV struct {
OnlyIPType lib.IPType OnlyIPType lib.IPType
} }
func (g *geoLite2CountryCSV) GetType() string { func (g *GeoLite2CountryCSV) GetType() string {
return g.Type return g.Type
} }
func (g *geoLite2CountryCSV) GetAction() lib.Action { func (g *GeoLite2CountryCSV) GetAction() lib.Action {
return g.Action return g.Action
} }
func (g *geoLite2CountryCSV) GetDescription() string { func (g *GeoLite2CountryCSV) GetDescription() string {
return g.Description return g.Description
} }
func (g *geoLite2CountryCSV) Input(container lib.Container) (lib.Container, error) { func (g *GeoLite2CountryCSV) Input(container lib.Container) (lib.Container, error) {
ccMap, err := g.getCountryCode() ccMap, err := g.getCountryCode()
if err != nil { if err != nil {
return nil, err return nil, err
@@ -152,7 +152,7 @@ func (g *geoLite2CountryCSV) Input(container lib.Container) (lib.Container, erro
return container, nil return container, nil
} }
func (g *geoLite2CountryCSV) getCountryCode() (map[string]string, error) { func (g *GeoLite2CountryCSV) getCountryCode() (map[string]string, error) {
var f io.ReadCloser var f io.ReadCloser
var err error var err error
switch { switch {
@@ -199,7 +199,7 @@ func (g *geoLite2CountryCSV) getCountryCode() (map[string]string, error) {
return ccMap, nil return ccMap, nil
} }
func (g *geoLite2CountryCSV) process(file string, ccMap map[string]string, entries map[string]*lib.Entry) error { func (g *GeoLite2CountryCSV) process(file string, ccMap map[string]string, entries map[string]*lib.Entry) error {
if len(ccMap) == 0 { if len(ccMap) == 0 {
return fmt.Errorf("❌ [type %s | action %s] invalid country code data", g.Type, g.Action) return fmt.Errorf("❌ [type %s | action %s] invalid country code data", g.Type, g.Action)
} }

View File

@@ -12,8 +12,8 @@ import (
) )
const ( const (
typeMaxmindMMDBIn = "maxmindMMDB" TypeMaxmindMMDBIn = "maxmindMMDB"
descMaxmindMMDBIn = "Convert MaxMind mmdb database to other formats" DescMaxmindMMDBIn = "Convert MaxMind mmdb database to other formats"
) )
var ( var (
@@ -21,11 +21,11 @@ var (
) )
func init() { func init() {
lib.RegisterInputConfigCreator(typeMaxmindMMDBIn, func(action lib.Action, data json.RawMessage) (lib.InputConverter, error) { lib.RegisterInputConfigCreator(TypeMaxmindMMDBIn, func(action lib.Action, data json.RawMessage) (lib.InputConverter, error) {
return newMaxmindMMDBIn(action, data) return newMaxmindMMDBIn(action, data)
}) })
lib.RegisterInputConverter(typeMaxmindMMDBIn, &maxmindMMDBIn{ lib.RegisterInputConverter(TypeMaxmindMMDBIn, &MaxmindMMDBIn{
Description: descMaxmindMMDBIn, Description: DescMaxmindMMDBIn,
}) })
} }
@@ -54,17 +54,17 @@ func newMaxmindMMDBIn(action lib.Action, data json.RawMessage) (lib.InputConvert
} }
} }
return &maxmindMMDBIn{ return &MaxmindMMDBIn{
Type: typeMaxmindMMDBIn, Type: TypeMaxmindMMDBIn,
Action: action, Action: action,
Description: descMaxmindMMDBIn, Description: DescMaxmindMMDBIn,
URI: tmp.URI, URI: tmp.URI,
Want: wantList, Want: wantList,
OnlyIPType: tmp.OnlyIPType, OnlyIPType: tmp.OnlyIPType,
}, nil }, nil
} }
type maxmindMMDBIn struct { type MaxmindMMDBIn struct {
Type string Type string
Action lib.Action Action lib.Action
Description string Description string
@@ -73,19 +73,19 @@ type maxmindMMDBIn struct {
OnlyIPType lib.IPType OnlyIPType lib.IPType
} }
func (m *maxmindMMDBIn) GetType() string { func (m *MaxmindMMDBIn) GetType() string {
return m.Type return m.Type
} }
func (m *maxmindMMDBIn) GetAction() lib.Action { func (m *MaxmindMMDBIn) GetAction() lib.Action {
return m.Action return m.Action
} }
func (m *maxmindMMDBIn) GetDescription() string { func (m *MaxmindMMDBIn) GetDescription() string {
return m.Description return m.Description
} }
func (m *maxmindMMDBIn) Input(container lib.Container) (lib.Container, error) { func (m *MaxmindMMDBIn) Input(container lib.Container) (lib.Container, error) {
var content []byte var content []byte
var err error var err error
switch { switch {
@@ -134,7 +134,7 @@ func (m *maxmindMMDBIn) Input(container lib.Container) (lib.Container, error) {
return container, nil return container, nil
} }
func (m *maxmindMMDBIn) generateEntries(content []byte, entries map[string]*lib.Entry) error { func (m *MaxmindMMDBIn) generateEntries(content []byte, entries map[string]*lib.Entry) error {
db, err := maxminddb.FromBytes(content) db, err := maxminddb.FromBytes(content)
if err != nil { if err != nil {
return err return err

View File

@@ -15,8 +15,8 @@ import (
) )
const ( const (
typeMaxmindMMDBOut = "maxmindMMDB" TypeMaxmindMMDBOut = "maxmindMMDB"
descMaxmindMMDBOut = "Convert data to MaxMind mmdb database format" DescMaxmindMMDBOut = "Convert data to MaxMind mmdb database format"
) )
var ( var (
@@ -25,11 +25,11 @@ var (
) )
func init() { func init() {
lib.RegisterOutputConfigCreator(typeMaxmindMMDBOut, func(action lib.Action, data json.RawMessage) (lib.OutputConverter, error) { lib.RegisterOutputConfigCreator(TypeMaxmindMMDBOut, func(action lib.Action, data json.RawMessage) (lib.OutputConverter, error) {
return newMMDBOut(action, data) return newMMDBOut(action, data)
}) })
lib.RegisterOutputConverter(typeMaxmindMMDBOut, &mmdbOut{ lib.RegisterOutputConverter(TypeMaxmindMMDBOut, &MMDBOut{
Description: descMaxmindMMDBOut, Description: DescMaxmindMMDBOut,
}) })
} }
@@ -57,10 +57,10 @@ func newMMDBOut(action lib.Action, data json.RawMessage) (lib.OutputConverter, e
tmp.OutputDir = defaultOutputDir tmp.OutputDir = defaultOutputDir
} }
return &mmdbOut{ return &MMDBOut{
Type: typeMaxmindMMDBOut, Type: TypeMaxmindMMDBOut,
Action: action, Action: action,
Description: descMaxmindMMDBOut, Description: DescMaxmindMMDBOut,
OutputName: tmp.OutputName, OutputName: tmp.OutputName,
OutputDir: tmp.OutputDir, OutputDir: tmp.OutputDir,
Want: tmp.Want, Want: tmp.Want,
@@ -70,7 +70,7 @@ func newMMDBOut(action lib.Action, data json.RawMessage) (lib.OutputConverter, e
}, nil }, nil
} }
type mmdbOut struct { type MMDBOut struct {
Type string Type string
Action lib.Action Action lib.Action
Description string Description string
@@ -82,19 +82,19 @@ type mmdbOut struct {
OnlyIPType lib.IPType OnlyIPType lib.IPType
} }
func (m *mmdbOut) GetType() string { func (m *MMDBOut) GetType() string {
return m.Type return m.Type
} }
func (m *mmdbOut) GetAction() lib.Action { func (m *MMDBOut) GetAction() lib.Action {
return m.Action return m.Action
} }
func (m *mmdbOut) GetDescription() string { func (m *MMDBOut) GetDescription() string {
return m.Description return m.Description
} }
func (m *mmdbOut) Output(container lib.Container) error { func (m *MMDBOut) Output(container lib.Container) error {
writer, err := mmdbwriter.New( writer, err := mmdbwriter.New(
mmdbwriter.Options{ mmdbwriter.Options{
DatabaseType: "GeoLite2-Country", DatabaseType: "GeoLite2-Country",
@@ -129,7 +129,7 @@ func (m *mmdbOut) Output(container lib.Container) error {
return nil return nil
} }
func (m *mmdbOut) filterAndSortList(container lib.Container) []string { func (m *MMDBOut) filterAndSortList(container lib.Container) []string {
/* /*
Note: The IPs and/or CIDRs of the latter list will overwrite those of the former one Note: The IPs and/or CIDRs of the latter list will overwrite those of the former one
when duplicated data found due to MaxMind mmdb file format constraint. when duplicated data found due to MaxMind mmdb file format constraint.
@@ -185,7 +185,7 @@ func (m *mmdbOut) filterAndSortList(container lib.Container) []string {
return list return list
} }
func (m *mmdbOut) marshalData(writer *mmdbwriter.Tree, entry *lib.Entry) error { func (m *MMDBOut) marshalData(writer *mmdbwriter.Tree, entry *lib.Entry) error {
var entryCidr []string var entryCidr []string
var err error var err error
switch m.OnlyIPType { switch m.OnlyIPType {
@@ -219,7 +219,7 @@ func (m *mmdbOut) marshalData(writer *mmdbwriter.Tree, entry *lib.Entry) error {
return nil return nil
} }
func (m *mmdbOut) writeFile(filename string, writer *mmdbwriter.Tree) error { func (m *MMDBOut) writeFile(filename string, writer *mmdbwriter.Tree) error {
if err := os.MkdirAll(m.OutputDir, 0755); err != nil { if err := os.MkdirAll(m.OutputDir, 0755); err != nil {
return err return err
} }

View File

@@ -21,16 +21,16 @@ import (
var mrsMagicBytes = [4]byte{'M', 'R', 'S', 1} // MRSv1 var mrsMagicBytes = [4]byte{'M', 'R', 'S', 1} // MRSv1
const ( const (
typeMRSIn = "mihomoMRS" TypeMRSIn = "mihomoMRS"
descMRSIn = "Convert mihomo MRS data to other formats" DescMRSIn = "Convert mihomo MRS data to other formats"
) )
func init() { func init() {
lib.RegisterInputConfigCreator(typeMRSIn, func(action lib.Action, data json.RawMessage) (lib.InputConverter, error) { lib.RegisterInputConfigCreator(TypeMRSIn, func(action lib.Action, data json.RawMessage) (lib.InputConverter, error) {
return newMRSIn(action, data) return newMRSIn(action, data)
}) })
lib.RegisterInputConverter(typeMRSIn, &mrsIn{ lib.RegisterInputConverter(TypeMRSIn, &MRSIn{
Description: descMRSIn, Description: DescMRSIn,
}) })
} }
@@ -50,11 +50,11 @@ func newMRSIn(action lib.Action, data json.RawMessage) (lib.InputConverter, erro
} }
if tmp.Name == "" && tmp.URI == "" && tmp.InputDir == "" { if tmp.Name == "" && tmp.URI == "" && tmp.InputDir == "" {
return nil, fmt.Errorf("❌ [type %s | action %s] missing inputDir or name or uri", typeMRSIn, action) return nil, fmt.Errorf("❌ [type %s | action %s] missing inputDir or name or uri", TypeMRSIn, action)
} }
if (tmp.Name != "" && tmp.URI == "") || (tmp.Name == "" && tmp.URI != "") { if (tmp.Name != "" && tmp.URI == "") || (tmp.Name == "" && tmp.URI != "") {
return nil, fmt.Errorf("❌ [type %s | action %s] name & uri must be specified together", typeMRSIn, action) return nil, fmt.Errorf("❌ [type %s | action %s] name & uri must be specified together", TypeMRSIn, action)
} }
// Filter want list // Filter want list
@@ -65,10 +65,10 @@ func newMRSIn(action lib.Action, data json.RawMessage) (lib.InputConverter, erro
} }
} }
return &mrsIn{ return &MRSIn{
Type: typeMRSIn, Type: TypeMRSIn,
Action: action, Action: action,
Description: descMRSIn, Description: DescMRSIn,
Name: tmp.Name, Name: tmp.Name,
URI: tmp.URI, URI: tmp.URI,
InputDir: tmp.InputDir, InputDir: tmp.InputDir,
@@ -77,7 +77,7 @@ func newMRSIn(action lib.Action, data json.RawMessage) (lib.InputConverter, erro
}, nil }, nil
} }
type mrsIn struct { type MRSIn struct {
Type string Type string
Action lib.Action Action lib.Action
Description string Description string
@@ -88,19 +88,19 @@ type mrsIn struct {
OnlyIPType lib.IPType OnlyIPType lib.IPType
} }
func (m *mrsIn) GetType() string { func (m *MRSIn) GetType() string {
return m.Type return m.Type
} }
func (m *mrsIn) GetAction() lib.Action { func (m *MRSIn) GetAction() lib.Action {
return m.Action return m.Action
} }
func (m *mrsIn) GetDescription() string { func (m *MRSIn) GetDescription() string {
return m.Description return m.Description
} }
func (m *mrsIn) Input(container lib.Container) (lib.Container, error) { func (m *MRSIn) Input(container lib.Container) (lib.Container, error) {
entries := make(map[string]*lib.Entry) entries := make(map[string]*lib.Entry)
var err error var err error
@@ -152,7 +152,7 @@ func (m *mrsIn) Input(container lib.Container) (lib.Container, error) {
return container, nil return container, nil
} }
func (m *mrsIn) walkDir(dir string, entries map[string]*lib.Entry) error { func (m *MRSIn) walkDir(dir string, entries map[string]*lib.Entry) error {
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil { if err != nil {
return err return err
@@ -171,7 +171,7 @@ func (m *mrsIn) walkDir(dir string, entries map[string]*lib.Entry) error {
return err return err
} }
func (m *mrsIn) walkLocalFile(path, name string, entries map[string]*lib.Entry) error { func (m *MRSIn) walkLocalFile(path, name string, entries map[string]*lib.Entry) error {
entryName := "" entryName := ""
name = strings.TrimSpace(name) name = strings.TrimSpace(name)
if name != "" { if name != "" {
@@ -209,7 +209,7 @@ func (m *mrsIn) walkLocalFile(path, name string, entries map[string]*lib.Entry)
return nil return nil
} }
func (m *mrsIn) walkRemoteFile(url, name string, entries map[string]*lib.Entry) error { func (m *MRSIn) walkRemoteFile(url, name string, entries map[string]*lib.Entry) error {
resp, err := http.Get(url) resp, err := http.Get(url)
if err != nil { if err != nil {
return err return err
@@ -227,7 +227,7 @@ func (m *mrsIn) walkRemoteFile(url, name string, entries map[string]*lib.Entry)
return nil return nil
} }
func (m *mrsIn) generateEntries(name string, reader io.Reader, entries map[string]*lib.Entry) error { func (m *MRSIn) generateEntries(name string, reader io.Reader, entries map[string]*lib.Entry) error {
name = strings.ToUpper(name) name = strings.ToUpper(name)
if len(m.Want) > 0 && !m.Want[name] { if len(m.Want) > 0 && !m.Want[name] {
@@ -253,7 +253,7 @@ func (m *mrsIn) generateEntries(name string, reader io.Reader, entries map[strin
return nil return nil
} }
func (m *mrsIn) parseMRS(data []byte, entry *lib.Entry) error { func (m *MRSIn) parseMRS(data []byte, entry *lib.Entry) error {
reader, err := zstd.NewReader(bytes.NewReader(data)) reader, err := zstd.NewReader(bytes.NewReader(data))
if err != nil { if err != nil {
return err return err

View File

@@ -17,8 +17,8 @@ import (
) )
const ( const (
typeMRSOut = "mihomoMRS" TypeMRSOut = "mihomoMRS"
descMRSOut = "Convert data to mihomo MRS format" DescMRSOut = "Convert data to mihomo MRS format"
) )
var ( var (
@@ -26,11 +26,11 @@ var (
) )
func init() { func init() {
lib.RegisterOutputConfigCreator(typeMRSOut, func(action lib.Action, data json.RawMessage) (lib.OutputConverter, error) { lib.RegisterOutputConfigCreator(TypeMRSOut, func(action lib.Action, data json.RawMessage) (lib.OutputConverter, error) {
return newMRSOut(action, data) return newMRSOut(action, data)
}) })
lib.RegisterOutputConverter(typeMRSOut, &mrsOut{ lib.RegisterOutputConverter(TypeMRSOut, &MRSOut{
Description: descMRSOut, Description: DescMRSOut,
}) })
} }
@@ -52,10 +52,10 @@ func newMRSOut(action lib.Action, data json.RawMessage) (lib.OutputConverter, er
tmp.OutputDir = defaultOutputDir tmp.OutputDir = defaultOutputDir
} }
return &mrsOut{ return &MRSOut{
Type: typeMRSOut, Type: TypeMRSOut,
Action: action, Action: action,
Description: descMRSOut, Description: DescMRSOut,
OutputDir: tmp.OutputDir, OutputDir: tmp.OutputDir,
Want: tmp.Want, Want: tmp.Want,
Exclude: tmp.Exclude, Exclude: tmp.Exclude,
@@ -63,7 +63,7 @@ func newMRSOut(action lib.Action, data json.RawMessage) (lib.OutputConverter, er
}, nil }, nil
} }
type mrsOut struct { type MRSOut struct {
Type string Type string
Action lib.Action Action lib.Action
Description string Description string
@@ -73,19 +73,19 @@ type mrsOut struct {
OnlyIPType lib.IPType OnlyIPType lib.IPType
} }
func (m *mrsOut) GetType() string { func (m *MRSOut) GetType() string {
return m.Type return m.Type
} }
func (m *mrsOut) GetAction() lib.Action { func (m *MRSOut) GetAction() lib.Action {
return m.Action return m.Action
} }
func (m *mrsOut) GetDescription() string { func (m *MRSOut) GetDescription() string {
return m.Description return m.Description
} }
func (m *mrsOut) Output(container lib.Container) error { func (m *MRSOut) Output(container lib.Container) error {
for _, name := range m.filterAndSortList(container) { for _, name := range m.filterAndSortList(container) {
entry, found := container.GetEntry(name) entry, found := container.GetEntry(name)
if !found { if !found {
@@ -101,7 +101,7 @@ func (m *mrsOut) Output(container lib.Container) error {
return nil return nil
} }
func (m *mrsOut) filterAndSortList(container lib.Container) []string { func (m *MRSOut) filterAndSortList(container lib.Container) []string {
excludeMap := make(map[string]bool) excludeMap := make(map[string]bool)
for _, exclude := range m.Exclude { for _, exclude := range m.Exclude {
if exclude = strings.ToUpper(strings.TrimSpace(exclude)); exclude != "" { if exclude = strings.ToUpper(strings.TrimSpace(exclude)); exclude != "" {
@@ -137,7 +137,7 @@ func (m *mrsOut) filterAndSortList(container lib.Container) []string {
return list return list
} }
func (m *mrsOut) generate(entry *lib.Entry) error { func (m *MRSOut) generate(entry *lib.Entry) error {
var ipRanges []netipx.IPRange var ipRanges []netipx.IPRange
var err error var err error
switch m.OnlyIPType { switch m.OnlyIPType {
@@ -164,7 +164,7 @@ func (m *mrsOut) generate(entry *lib.Entry) error {
return nil return nil
} }
func (m *mrsOut) writeFile(filename string, ipRanges []netipx.IPRange) error { func (m *MRSOut) writeFile(filename string, ipRanges []netipx.IPRange) error {
if err := os.MkdirAll(m.OutputDir, 0755); err != nil { if err := os.MkdirAll(m.OutputDir, 0755); err != nil {
return err return err
} }
@@ -185,7 +185,7 @@ func (m *mrsOut) writeFile(filename string, ipRanges []netipx.IPRange) error {
return nil return nil
} }
func (m *mrsOut) convertToMrs(ipRanges []netipx.IPRange, w io.Writer) (err error) { func (m *MRSOut) convertToMrs(ipRanges []netipx.IPRange, w io.Writer) (err error) {
encoder, err := zstd.NewWriter(w) encoder, err := zstd.NewWriter(w)
if err != nil { if err != nil {
return err return err

View File

@@ -12,25 +12,25 @@ which make it possible to support more formats for the project.
*/ */
const ( const (
typeClashRuleSetClassicalIn = "clashRuleSetClassical" TypeClashRuleSetClassicalIn = "clashRuleSetClassical"
descClashClassicalIn = "Convert classical type of Clash RuleSet to other formats (just processing IP & CIDR lines)" DescClashClassicalIn = "Convert classical type of Clash RuleSet to other formats (just processing IP & CIDR lines)"
typeClashRuleSetIPCIDRIn = "clashRuleSet" TypeClashRuleSetIPCIDRIn = "clashRuleSet"
descClashRuleSetIn = "Convert ipcidr type of Clash RuleSet to other formats" DescClashRuleSetIn = "Convert ipcidr type of Clash RuleSet to other formats"
) )
func init() { func init() {
lib.RegisterInputConfigCreator(typeClashRuleSetClassicalIn, func(action lib.Action, data json.RawMessage) (lib.InputConverter, error) { lib.RegisterInputConfigCreator(TypeClashRuleSetClassicalIn, func(action lib.Action, data json.RawMessage) (lib.InputConverter, error) {
return newTextIn(typeClashRuleSetClassicalIn, action, data) return newTextIn(TypeClashRuleSetClassicalIn, action, data)
}) })
lib.RegisterInputConverter(typeClashRuleSetClassicalIn, &textIn{ lib.RegisterInputConverter(TypeClashRuleSetClassicalIn, &TextIn{
Description: descClashClassicalIn, Description: DescClashClassicalIn,
}) })
lib.RegisterInputConfigCreator(typeClashRuleSetIPCIDRIn, func(action lib.Action, data json.RawMessage) (lib.InputConverter, error) { lib.RegisterInputConfigCreator(TypeClashRuleSetIPCIDRIn, func(action lib.Action, data json.RawMessage) (lib.InputConverter, error) {
return newTextIn(typeClashRuleSetIPCIDRIn, action, data) return newTextIn(TypeClashRuleSetIPCIDRIn, action, data)
}) })
lib.RegisterInputConverter(typeClashRuleSetIPCIDRIn, &textIn{ lib.RegisterInputConverter(TypeClashRuleSetIPCIDRIn, &TextIn{
Description: descClashRuleSetIn, Description: DescClashRuleSetIn,
}) })
} }

View File

@@ -12,25 +12,25 @@ which make it possible to support more formats for the project.
*/ */
const ( const (
typeClashRuleSetClassicalOut = "clashRuleSetClassical" TypeClashRuleSetClassicalOut = "clashRuleSetClassical"
descClashClassicalOut = "Convert data to classical type of Clash RuleSet" DescClashClassicalOut = "Convert data to classical type of Clash RuleSet"
typeClashRuleSetIPCIDROut = "clashRuleSet" TypeClashRuleSetIPCIDROut = "clashRuleSet"
descClashRuleSetOut = "Convert data to ipcidr type of Clash RuleSet" DescClashRuleSetOut = "Convert data to ipcidr type of Clash RuleSet"
) )
func init() { func init() {
lib.RegisterOutputConfigCreator(typeClashRuleSetClassicalOut, func(action lib.Action, data json.RawMessage) (lib.OutputConverter, error) { lib.RegisterOutputConfigCreator(TypeClashRuleSetClassicalOut, func(action lib.Action, data json.RawMessage) (lib.OutputConverter, error) {
return newTextOut(typeClashRuleSetClassicalOut, action, data) return newTextOut(TypeClashRuleSetClassicalOut, action, data)
}) })
lib.RegisterOutputConverter(typeClashRuleSetClassicalOut, &textOut{ lib.RegisterOutputConverter(TypeClashRuleSetClassicalOut, &TextOut{
Description: descClashClassicalOut, Description: DescClashClassicalOut,
}) })
lib.RegisterOutputConfigCreator(typeClashRuleSetIPCIDROut, func(action lib.Action, data json.RawMessage) (lib.OutputConverter, error) { lib.RegisterOutputConfigCreator(TypeClashRuleSetIPCIDROut, func(action lib.Action, data json.RawMessage) (lib.OutputConverter, error) {
return newTextOut(typeClashRuleSetIPCIDROut, action, data) return newTextOut(TypeClashRuleSetIPCIDROut, action, data)
}) })
lib.RegisterOutputConverter(typeClashRuleSetIPCIDROut, &textOut{ lib.RegisterOutputConverter(TypeClashRuleSetIPCIDROut, &TextOut{
Description: descClashRuleSetOut, Description: DescClashRuleSetOut,
}) })
} }

View File

@@ -11,7 +11,7 @@ import (
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
) )
type textIn struct { type TextIn struct {
Type string Type string
Action lib.Action Action lib.Action
Description string Description string
@@ -27,18 +27,18 @@ type textIn struct {
RemoveSuffixesInLine []string RemoveSuffixesInLine []string
} }
func (t *textIn) scanFile(reader io.Reader, entry *lib.Entry) error { func (t *TextIn) scanFile(reader io.Reader, entry *lib.Entry) error {
var err error var err error
switch t.Type { switch t.Type {
case typeTextIn: case TypeTextIn:
err = t.scanFileForTextIn(reader, entry) err = t.scanFileForTextIn(reader, entry)
case typeJSONIn: case TypeJSONIn:
err = t.scanFileForJSONIn(reader, entry) err = t.scanFileForJSONIn(reader, entry)
case typeClashRuleSetClassicalIn: case TypeClashRuleSetClassicalIn:
err = t.scanFileForClashClassicalRuleSetIn(reader, entry) err = t.scanFileForClashClassicalRuleSetIn(reader, entry)
case typeClashRuleSetIPCIDRIn: case TypeClashRuleSetIPCIDRIn:
err = t.scanFileForClashIPCIDRRuleSetIn(reader, entry) err = t.scanFileForClashIPCIDRRuleSetIn(reader, entry)
case typeSurgeRuleSetIn: case TypeSurgeRuleSetIn:
err = t.scanFileForSurgeRuleSetIn(reader, entry) err = t.scanFileForSurgeRuleSetIn(reader, entry)
default: default:
return lib.ErrNotSupportedFormat return lib.ErrNotSupportedFormat
@@ -47,7 +47,7 @@ func (t *textIn) scanFile(reader io.Reader, entry *lib.Entry) error {
return err return err
} }
func (t *textIn) scanFileForTextIn(reader io.Reader, entry *lib.Entry) error { func (t *TextIn) scanFileForTextIn(reader io.Reader, entry *lib.Entry) error {
scanner := bufio.NewScanner(reader) scanner := bufio.NewScanner(reader)
for scanner.Scan() { for scanner.Scan() {
line := scanner.Text() line := scanner.Text()
@@ -83,7 +83,7 @@ func (t *textIn) scanFileForTextIn(reader io.Reader, entry *lib.Entry) error {
return nil return nil
} }
func (t *textIn) readClashRuleSetYAMLFile(reader io.Reader) ([]string, error) { func (t *TextIn) readClashRuleSetYAMLFile(reader io.Reader) ([]string, error) {
var payload struct { var payload struct {
Payload []string `yaml:"payload"` Payload []string `yaml:"payload"`
} }
@@ -100,7 +100,7 @@ func (t *textIn) readClashRuleSetYAMLFile(reader io.Reader) ([]string, error) {
return payload.Payload, nil return payload.Payload, nil
} }
func (t *textIn) scanFileForClashIPCIDRRuleSetIn(reader io.Reader, entry *lib.Entry) error { func (t *TextIn) scanFileForClashIPCIDRRuleSetIn(reader io.Reader, entry *lib.Entry) error {
payload, err := t.readClashRuleSetYAMLFile(reader) payload, err := t.readClashRuleSetYAMLFile(reader)
if err != nil { if err != nil {
return err return err
@@ -119,7 +119,7 @@ func (t *textIn) scanFileForClashIPCIDRRuleSetIn(reader io.Reader, entry *lib.En
return nil return nil
} }
func (t *textIn) scanFileForClashClassicalRuleSetIn(reader io.Reader, entry *lib.Entry) error { func (t *TextIn) scanFileForClashClassicalRuleSetIn(reader io.Reader, entry *lib.Entry) error {
payload, err := t.readClashRuleSetYAMLFile(reader) payload, err := t.readClashRuleSetYAMLFile(reader)
if err != nil { if err != nil {
return err return err
@@ -154,7 +154,7 @@ func (t *textIn) scanFileForClashClassicalRuleSetIn(reader io.Reader, entry *lib
return nil return nil
} }
func (t *textIn) scanFileForSurgeRuleSetIn(reader io.Reader, entry *lib.Entry) error { func (t *TextIn) scanFileForSurgeRuleSetIn(reader io.Reader, entry *lib.Entry) error {
scanner := bufio.NewScanner(reader) scanner := bufio.NewScanner(reader)
for scanner.Scan() { for scanner.Scan() {
line := scanner.Text() line := scanner.Text()
@@ -193,7 +193,7 @@ func (t *textIn) scanFileForSurgeRuleSetIn(reader io.Reader, entry *lib.Entry) e
return nil return nil
} }
func (t *textIn) scanFileForJSONIn(reader io.Reader, entry *lib.Entry) error { func (t *TextIn) scanFileForJSONIn(reader io.Reader, entry *lib.Entry) error {
data, err := io.ReadAll(reader) data, err := io.ReadAll(reader)
if err != nil { if err != nil {
return err return err

View File

@@ -18,7 +18,7 @@ var (
defaultOutputDirForSurgeRuleSetOut = filepath.Join("./", "output", "surge") defaultOutputDirForSurgeRuleSetOut = filepath.Join("./", "output", "surge")
) )
type textOut struct { type TextOut struct {
Type string Type string
Action lib.Action Action lib.Action
Description string Description string
@@ -52,13 +52,13 @@ func newTextOut(iType string, action lib.Action, data json.RawMessage) (lib.Outp
if tmp.OutputDir == "" { if tmp.OutputDir == "" {
switch iType { switch iType {
case typeTextOut: case TypeTextOut:
tmp.OutputDir = defaultOutputDirForTextOut tmp.OutputDir = defaultOutputDirForTextOut
case typeClashRuleSetClassicalOut: case TypeClashRuleSetClassicalOut:
tmp.OutputDir = defaultOutputDirForClashRuleSetClassicalOut tmp.OutputDir = defaultOutputDirForClashRuleSetClassicalOut
case typeClashRuleSetIPCIDROut: case TypeClashRuleSetIPCIDROut:
tmp.OutputDir = defaultOutputDirForClashRuleSetIPCIDROut tmp.OutputDir = defaultOutputDirForClashRuleSetIPCIDROut
case typeSurgeRuleSetOut: case TypeSurgeRuleSetOut:
tmp.OutputDir = defaultOutputDirForSurgeRuleSetOut tmp.OutputDir = defaultOutputDirForSurgeRuleSetOut
} }
} }
@@ -67,10 +67,10 @@ func newTextOut(iType string, action lib.Action, data json.RawMessage) (lib.Outp
tmp.OutputExt = ".txt" tmp.OutputExt = ".txt"
} }
return &textOut{ return &TextOut{
Type: iType, Type: iType,
Action: action, Action: action,
Description: descTextOut, Description: DescTextOut,
OutputDir: tmp.OutputDir, OutputDir: tmp.OutputDir,
OutputExt: tmp.OutputExt, OutputExt: tmp.OutputExt,
Want: tmp.Want, Want: tmp.Want,
@@ -82,7 +82,7 @@ func newTextOut(iType string, action lib.Action, data json.RawMessage) (lib.Outp
}, nil }, nil
} }
func (t *textOut) marshalBytes(entry *lib.Entry) ([]byte, error) { func (t *TextOut) marshalBytes(entry *lib.Entry) ([]byte, error) {
var err error var err error
var entryCidr []string var entryCidr []string
@@ -100,13 +100,13 @@ func (t *textOut) marshalBytes(entry *lib.Entry) ([]byte, error) {
var buf bytes.Buffer var buf bytes.Buffer
switch t.Type { switch t.Type {
case typeTextOut: case TypeTextOut:
err = t.marshalBytesForTextOut(&buf, entryCidr) err = t.marshalBytesForTextOut(&buf, entryCidr)
case typeClashRuleSetClassicalOut: case TypeClashRuleSetClassicalOut:
err = t.marshalBytesForClashRuleSetClassicalOut(&buf, entryCidr) err = t.marshalBytesForClashRuleSetClassicalOut(&buf, entryCidr)
case typeClashRuleSetIPCIDROut: case TypeClashRuleSetIPCIDROut:
err = t.marshalBytesForClashRuleSetIPCIDROut(&buf, entryCidr) err = t.marshalBytesForClashRuleSetIPCIDROut(&buf, entryCidr)
case typeSurgeRuleSetOut: case TypeSurgeRuleSetOut:
err = t.marshalBytesForSurgeRuleSetOut(&buf, entryCidr) err = t.marshalBytesForSurgeRuleSetOut(&buf, entryCidr)
default: default:
return nil, lib.ErrNotSupportedFormat return nil, lib.ErrNotSupportedFormat
@@ -118,7 +118,7 @@ func (t *textOut) marshalBytes(entry *lib.Entry) ([]byte, error) {
return buf.Bytes(), nil return buf.Bytes(), nil
} }
func (t *textOut) marshalBytesForTextOut(buf *bytes.Buffer, entryCidr []string) error { func (t *TextOut) marshalBytesForTextOut(buf *bytes.Buffer, entryCidr []string) error {
for _, cidr := range entryCidr { for _, cidr := range entryCidr {
if t.AddPrefixInLine != "" { if t.AddPrefixInLine != "" {
buf.WriteString(t.AddPrefixInLine) buf.WriteString(t.AddPrefixInLine)
@@ -132,7 +132,7 @@ func (t *textOut) marshalBytesForTextOut(buf *bytes.Buffer, entryCidr []string)
return nil return nil
} }
func (t *textOut) marshalBytesForClashRuleSetClassicalOut(buf *bytes.Buffer, entryCidr []string) error { func (t *TextOut) marshalBytesForClashRuleSetClassicalOut(buf *bytes.Buffer, entryCidr []string) error {
buf.WriteString("payload:\n") buf.WriteString("payload:\n")
for _, cidr := range entryCidr { for _, cidr := range entryCidr {
ip, _, err := net.ParseCIDR(cidr) ip, _, err := net.ParseCIDR(cidr)
@@ -151,7 +151,7 @@ func (t *textOut) marshalBytesForClashRuleSetClassicalOut(buf *bytes.Buffer, ent
return nil return nil
} }
func (t *textOut) marshalBytesForClashRuleSetIPCIDROut(buf *bytes.Buffer, entryCidr []string) error { func (t *TextOut) marshalBytesForClashRuleSetIPCIDROut(buf *bytes.Buffer, entryCidr []string) error {
buf.WriteString("payload:\n") buf.WriteString("payload:\n")
for _, cidr := range entryCidr { for _, cidr := range entryCidr {
buf.WriteString(" - '") buf.WriteString(" - '")
@@ -162,7 +162,7 @@ func (t *textOut) marshalBytesForClashRuleSetIPCIDROut(buf *bytes.Buffer, entryC
return nil return nil
} }
func (t *textOut) marshalBytesForSurgeRuleSetOut(buf *bytes.Buffer, entryCidr []string) error { func (t *TextOut) marshalBytesForSurgeRuleSetOut(buf *bytes.Buffer, entryCidr []string) error {
for _, cidr := range entryCidr { for _, cidr := range entryCidr {
ip, _, err := net.ParseCIDR(cidr) ip, _, err := net.ParseCIDR(cidr)
if err != nil { if err != nil {
@@ -183,7 +183,7 @@ func (t *textOut) marshalBytesForSurgeRuleSetOut(buf *bytes.Buffer, entryCidr []
return nil return nil
} }
func (t *textOut) writeFile(filename string, data []byte) error { func (t *TextOut) writeFile(filename string, data []byte) error {
if err := os.MkdirAll(t.OutputDir, 0755); err != nil { if err := os.MkdirAll(t.OutputDir, 0755); err != nil {
return err return err
} }

View File

@@ -7,16 +7,16 @@ import (
) )
const ( const (
typeJSONIn = "json" TypeJSONIn = "json"
descJSONIn = "Convert JSON data to other formats" DescJSONIn = "Convert JSON data to other formats"
) )
func init() { func init() {
lib.RegisterInputConfigCreator(typeJSONIn, func(action lib.Action, data json.RawMessage) (lib.InputConverter, error) { lib.RegisterInputConfigCreator(TypeJSONIn, func(action lib.Action, data json.RawMessage) (lib.InputConverter, error) {
return newTextIn(typeJSONIn, action, data) return newTextIn(TypeJSONIn, action, data)
}) })
lib.RegisterInputConverter(typeJSONIn, &textIn{ lib.RegisterInputConverter(TypeJSONIn, &TextIn{
Description: descJSONIn, Description: DescJSONIn,
}) })
} }

View File

@@ -12,15 +12,15 @@ which make it possible to support more formats for the project.
*/ */
const ( const (
typeSurgeRuleSetIn = "surgeRuleSet" TypeSurgeRuleSetIn = "surgeRuleSet"
descSurgeRuleSetIn = "Convert Surge RuleSet to other formats (just processing IP & CIDR lines)" DescSurgeRuleSetIn = "Convert Surge RuleSet to other formats (just processing IP & CIDR lines)"
) )
func init() { func init() {
lib.RegisterInputConfigCreator(typeSurgeRuleSetIn, func(action lib.Action, data json.RawMessage) (lib.InputConverter, error) { lib.RegisterInputConfigCreator(TypeSurgeRuleSetIn, func(action lib.Action, data json.RawMessage) (lib.InputConverter, error) {
return newTextIn(typeSurgeRuleSetIn, action, data) return newTextIn(TypeSurgeRuleSetIn, action, data)
}) })
lib.RegisterInputConverter(typeSurgeRuleSetIn, &textIn{ lib.RegisterInputConverter(TypeSurgeRuleSetIn, &TextIn{
Description: descSurgeRuleSetIn, Description: DescSurgeRuleSetIn,
}) })
} }

View File

@@ -12,15 +12,15 @@ which make it possible to support more formats for the project.
*/ */
const ( const (
typeSurgeRuleSetOut = "surgeRuleSet" TypeSurgeRuleSetOut = "surgeRuleSet"
descSurgeRuleSetOut = "Convert data to Surge RuleSet" DescSurgeRuleSetOut = "Convert data to Surge RuleSet"
) )
func init() { func init() {
lib.RegisterOutputConfigCreator(typeSurgeRuleSetOut, func(action lib.Action, data json.RawMessage) (lib.OutputConverter, error) { lib.RegisterOutputConfigCreator(TypeSurgeRuleSetOut, func(action lib.Action, data json.RawMessage) (lib.OutputConverter, error) {
return newTextOut(typeSurgeRuleSetOut, action, data) return newTextOut(TypeSurgeRuleSetOut, action, data)
}) })
lib.RegisterOutputConverter(typeSurgeRuleSetOut, &textOut{ lib.RegisterOutputConverter(TypeSurgeRuleSetOut, &TextOut{
Description: descSurgeRuleSetOut, Description: DescSurgeRuleSetOut,
}) })
} }

View File

@@ -13,16 +13,16 @@ import (
) )
const ( const (
typeTextIn = "text" TypeTextIn = "text"
descTextIn = "Convert plaintext IP & CIDR to other formats" DescTextIn = "Convert plaintext IP & CIDR to other formats"
) )
func init() { func init() {
lib.RegisterInputConfigCreator(typeTextIn, func(action lib.Action, data json.RawMessage) (lib.InputConverter, error) { lib.RegisterInputConfigCreator(TypeTextIn, func(action lib.Action, data json.RawMessage) (lib.InputConverter, error) {
return newTextIn(typeTextIn, action, data) return newTextIn(TypeTextIn, action, data)
}) })
lib.RegisterInputConverter(typeTextIn, &textIn{ lib.RegisterInputConverter(TypeTextIn, &TextIn{
Description: descTextIn, Description: DescTextIn,
}) })
} }
@@ -50,11 +50,11 @@ func newTextIn(iType string, action lib.Action, data json.RawMessage) (lib.Input
} }
} }
if iType != typeTextIn && len(tmp.IPOrCIDR) > 0 { if iType != TypeTextIn && len(tmp.IPOrCIDR) > 0 {
return nil, fmt.Errorf("❌ [type %s | action %s] ipOrCIDR is invalid for this input format", iType, action) return nil, fmt.Errorf("❌ [type %s | action %s] ipOrCIDR is invalid for this input format", iType, action)
} }
if iType == typeJSONIn && len(tmp.JSONPath) == 0 { if iType == TypeJSONIn && len(tmp.JSONPath) == 0 {
return nil, fmt.Errorf("❌ [type %s | action %s] missing jsonPath", iType, action) return nil, fmt.Errorf("❌ [type %s | action %s] missing jsonPath", iType, action)
} }
@@ -77,10 +77,10 @@ func newTextIn(iType string, action lib.Action, data json.RawMessage) (lib.Input
} }
} }
return &textIn{ return &TextIn{
Type: iType, Type: iType,
Action: action, Action: action,
Description: descTextIn, Description: DescTextIn,
Name: tmp.Name, Name: tmp.Name,
URI: tmp.URI, URI: tmp.URI,
IPOrCIDR: tmp.IPOrCIDR, IPOrCIDR: tmp.IPOrCIDR,
@@ -94,19 +94,19 @@ func newTextIn(iType string, action lib.Action, data json.RawMessage) (lib.Input
}, nil }, nil
} }
func (t *textIn) GetType() string { func (t *TextIn) GetType() string {
return t.Type return t.Type
} }
func (t *textIn) GetAction() lib.Action { func (t *TextIn) GetAction() lib.Action {
return t.Action return t.Action
} }
func (t *textIn) GetDescription() string { func (t *TextIn) GetDescription() string {
return t.Description return t.Description
} }
func (t *textIn) Input(container lib.Container) (lib.Container, error) { func (t *TextIn) Input(container lib.Container) (lib.Container, error) {
entries := make(map[string]*lib.Entry) entries := make(map[string]*lib.Entry)
var err error var err error
@@ -168,7 +168,7 @@ func (t *textIn) Input(container lib.Container) (lib.Container, error) {
return container, nil return container, nil
} }
func (t *textIn) walkDir(dir string, entries map[string]*lib.Entry) error { func (t *TextIn) walkDir(dir string, entries map[string]*lib.Entry) error {
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil { if err != nil {
return err return err
@@ -187,7 +187,7 @@ func (t *textIn) walkDir(dir string, entries map[string]*lib.Entry) error {
return err return err
} }
func (t *textIn) walkLocalFile(path, name string, entries map[string]*lib.Entry) error { func (t *TextIn) walkLocalFile(path, name string, entries map[string]*lib.Entry) error {
entryName := "" entryName := ""
name = strings.TrimSpace(name) name = strings.TrimSpace(name)
if name != "" { if name != "" {
@@ -231,7 +231,7 @@ func (t *textIn) walkLocalFile(path, name string, entries map[string]*lib.Entry)
return nil return nil
} }
func (t *textIn) walkRemoteFile(url, name string, entries map[string]*lib.Entry) error { func (t *TextIn) walkRemoteFile(url, name string, entries map[string]*lib.Entry) error {
resp, err := http.Get(url) resp, err := http.Get(url)
if err != nil { if err != nil {
return err return err
@@ -258,7 +258,7 @@ func (t *textIn) walkRemoteFile(url, name string, entries map[string]*lib.Entry)
return nil return nil
} }
func (t *textIn) appendIPOrCIDR(ipOrCIDR []string, name string, entries map[string]*lib.Entry) error { func (t *TextIn) appendIPOrCIDR(ipOrCIDR []string, name string, entries map[string]*lib.Entry) error {
name = strings.ToUpper(name) name = strings.ToUpper(name)
entry, found := entries[name] entry, found := entries[name]

View File

@@ -10,32 +10,32 @@ import (
) )
const ( const (
typeTextOut = "text" TypeTextOut = "text"
descTextOut = "Convert data to plaintext CIDR format" DescTextOut = "Convert data to plaintext CIDR format"
) )
func init() { func init() {
lib.RegisterOutputConfigCreator(typeTextOut, func(action lib.Action, data json.RawMessage) (lib.OutputConverter, error) { lib.RegisterOutputConfigCreator(TypeTextOut, func(action lib.Action, data json.RawMessage) (lib.OutputConverter, error) {
return newTextOut(typeTextOut, action, data) return newTextOut(TypeTextOut, action, data)
}) })
lib.RegisterOutputConverter(typeTextOut, &textOut{ lib.RegisterOutputConverter(TypeTextOut, &TextOut{
Description: descTextOut, Description: DescTextOut,
}) })
} }
func (t *textOut) GetType() string { func (t *TextOut) GetType() string {
return t.Type return t.Type
} }
func (t *textOut) GetAction() lib.Action { func (t *TextOut) GetAction() lib.Action {
return t.Action return t.Action
} }
func (t *textOut) GetDescription() string { func (t *TextOut) GetDescription() string {
return t.Description return t.Description
} }
func (t *textOut) Output(container lib.Container) error { func (t *TextOut) Output(container lib.Container) error {
for _, name := range t.filterAndSortList(container) { for _, name := range t.filterAndSortList(container) {
entry, found := container.GetEntry(name) entry, found := container.GetEntry(name)
if !found { if !found {
@@ -57,7 +57,7 @@ func (t *textOut) Output(container lib.Container) error {
return nil return nil
} }
func (t *textOut) filterAndSortList(container lib.Container) []string { func (t *TextOut) filterAndSortList(container lib.Container) []string {
excludeMap := make(map[string]bool) excludeMap := make(map[string]bool)
for _, exclude := range t.Exclude { for _, exclude := range t.Exclude {
if exclude = strings.ToUpper(strings.TrimSpace(exclude)); exclude != "" { if exclude = strings.ToUpper(strings.TrimSpace(exclude)); exclude != "" {

View File

@@ -15,16 +15,16 @@ import (
) )
const ( const (
typeSRSIn = "singboxSRS" TypeSRSIn = "singboxSRS"
descSRSIn = "Convert sing-box SRS data to other formats" DescSRSIn = "Convert sing-box SRS data to other formats"
) )
func init() { func init() {
lib.RegisterInputConfigCreator(typeSRSIn, func(action lib.Action, data json.RawMessage) (lib.InputConverter, error) { lib.RegisterInputConfigCreator(TypeSRSIn, func(action lib.Action, data json.RawMessage) (lib.InputConverter, error) {
return newSRSIn(action, data) return newSRSIn(action, data)
}) })
lib.RegisterInputConverter(typeSRSIn, &srsIn{ lib.RegisterInputConverter(TypeSRSIn, &SRSIn{
Description: descSRSIn, Description: DescSRSIn,
}) })
} }
@@ -44,11 +44,11 @@ func newSRSIn(action lib.Action, data json.RawMessage) (lib.InputConverter, erro
} }
if tmp.Name == "" && tmp.URI == "" && tmp.InputDir == "" { if tmp.Name == "" && tmp.URI == "" && tmp.InputDir == "" {
return nil, fmt.Errorf("❌ [type %s | action %s] missing inputdir or name or uri", typeSRSIn, action) return nil, fmt.Errorf("❌ [type %s | action %s] missing inputdir or name or uri", TypeSRSIn, action)
} }
if (tmp.Name != "" && tmp.URI == "") || (tmp.Name == "" && tmp.URI != "") { if (tmp.Name != "" && tmp.URI == "") || (tmp.Name == "" && tmp.URI != "") {
return nil, fmt.Errorf("❌ [type %s | action %s] name & uri must be specified together", typeSRSIn, action) return nil, fmt.Errorf("❌ [type %s | action %s] name & uri must be specified together", TypeSRSIn, action)
} }
// Filter want list // Filter want list
@@ -59,10 +59,10 @@ func newSRSIn(action lib.Action, data json.RawMessage) (lib.InputConverter, erro
} }
} }
return &srsIn{ return &SRSIn{
Type: typeSRSIn, Type: TypeSRSIn,
Action: action, Action: action,
Description: descSRSIn, Description: DescSRSIn,
Name: tmp.Name, Name: tmp.Name,
URI: tmp.URI, URI: tmp.URI,
InputDir: tmp.InputDir, InputDir: tmp.InputDir,
@@ -71,7 +71,7 @@ func newSRSIn(action lib.Action, data json.RawMessage) (lib.InputConverter, erro
}, nil }, nil
} }
type srsIn struct { type SRSIn struct {
Type string Type string
Action lib.Action Action lib.Action
Description string Description string
@@ -82,19 +82,19 @@ type srsIn struct {
OnlyIPType lib.IPType OnlyIPType lib.IPType
} }
func (s *srsIn) GetType() string { func (s *SRSIn) GetType() string {
return s.Type return s.Type
} }
func (s *srsIn) GetAction() lib.Action { func (s *SRSIn) GetAction() lib.Action {
return s.Action return s.Action
} }
func (s *srsIn) GetDescription() string { func (s *SRSIn) GetDescription() string {
return s.Description return s.Description
} }
func (s *srsIn) Input(container lib.Container) (lib.Container, error) { func (s *SRSIn) Input(container lib.Container) (lib.Container, error) {
entries := make(map[string]*lib.Entry) entries := make(map[string]*lib.Entry)
var err error var err error
@@ -146,7 +146,7 @@ func (s *srsIn) Input(container lib.Container) (lib.Container, error) {
return container, nil return container, nil
} }
func (s *srsIn) walkDir(dir string, entries map[string]*lib.Entry) error { func (s *SRSIn) walkDir(dir string, entries map[string]*lib.Entry) error {
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil { if err != nil {
return err return err
@@ -165,7 +165,7 @@ func (s *srsIn) walkDir(dir string, entries map[string]*lib.Entry) error {
return err return err
} }
func (s *srsIn) walkLocalFile(path, name string, entries map[string]*lib.Entry) error { func (s *SRSIn) walkLocalFile(path, name string, entries map[string]*lib.Entry) error {
entryName := "" entryName := ""
name = strings.TrimSpace(name) name = strings.TrimSpace(name)
if name != "" { if name != "" {
@@ -203,7 +203,7 @@ func (s *srsIn) walkLocalFile(path, name string, entries map[string]*lib.Entry)
return nil return nil
} }
func (s *srsIn) walkRemoteFile(url, name string, entries map[string]*lib.Entry) error { func (s *SRSIn) walkRemoteFile(url, name string, entries map[string]*lib.Entry) error {
resp, err := http.Get(url) resp, err := http.Get(url)
if err != nil { if err != nil {
return err return err
@@ -221,7 +221,7 @@ func (s *srsIn) walkRemoteFile(url, name string, entries map[string]*lib.Entry)
return nil return nil
} }
func (s *srsIn) generateEntries(name string, reader io.Reader, entries map[string]*lib.Entry) error { func (s *SRSIn) generateEntries(name string, reader io.Reader, entries map[string]*lib.Entry) error {
name = strings.ToUpper(name) name = strings.ToUpper(name)
if len(s.Want) > 0 && !s.Want[name] { if len(s.Want) > 0 && !s.Want[name] {

View File

@@ -16,8 +16,8 @@ import (
) )
const ( const (
typeSRSOut = "singboxSRS" TypeSRSOut = "singboxSRS"
descSRSOut = "Convert data to sing-box SRS format" DescSRSOut = "Convert data to sing-box SRS format"
) )
var ( var (
@@ -25,11 +25,11 @@ var (
) )
func init() { func init() {
lib.RegisterOutputConfigCreator(typeSRSOut, func(action lib.Action, data json.RawMessage) (lib.OutputConverter, error) { lib.RegisterOutputConfigCreator(TypeSRSOut, func(action lib.Action, data json.RawMessage) (lib.OutputConverter, error) {
return newSRSOut(action, data) return newSRSOut(action, data)
}) })
lib.RegisterOutputConverter(typeSRSOut, &srsOut{ lib.RegisterOutputConverter(TypeSRSOut, &SRSOut{
Description: descSRSOut, Description: DescSRSOut,
}) })
} }
@@ -51,10 +51,10 @@ func newSRSOut(action lib.Action, data json.RawMessage) (lib.OutputConverter, er
tmp.OutputDir = defaultOutputDir tmp.OutputDir = defaultOutputDir
} }
return &srsOut{ return &SRSOut{
Type: typeSRSOut, Type: TypeSRSOut,
Action: action, Action: action,
Description: descSRSOut, Description: DescSRSOut,
OutputDir: tmp.OutputDir, OutputDir: tmp.OutputDir,
Want: tmp.Want, Want: tmp.Want,
Exclude: tmp.Exclude, Exclude: tmp.Exclude,
@@ -62,7 +62,7 @@ func newSRSOut(action lib.Action, data json.RawMessage) (lib.OutputConverter, er
}, nil }, nil
} }
type srsOut struct { type SRSOut struct {
Type string Type string
Action lib.Action Action lib.Action
Description string Description string
@@ -72,19 +72,19 @@ type srsOut struct {
OnlyIPType lib.IPType OnlyIPType lib.IPType
} }
func (s *srsOut) GetType() string { func (s *SRSOut) GetType() string {
return s.Type return s.Type
} }
func (s *srsOut) GetAction() lib.Action { func (s *SRSOut) GetAction() lib.Action {
return s.Action return s.Action
} }
func (s *srsOut) GetDescription() string { func (s *SRSOut) GetDescription() string {
return s.Description return s.Description
} }
func (s *srsOut) Output(container lib.Container) error { func (s *SRSOut) Output(container lib.Container) error {
for _, name := range s.filterAndSortList(container) { for _, name := range s.filterAndSortList(container) {
entry, found := container.GetEntry(name) entry, found := container.GetEntry(name)
if !found { if !found {
@@ -100,7 +100,7 @@ func (s *srsOut) Output(container lib.Container) error {
return nil return nil
} }
func (s *srsOut) filterAndSortList(container lib.Container) []string { func (s *SRSOut) filterAndSortList(container lib.Container) []string {
excludeMap := make(map[string]bool) excludeMap := make(map[string]bool)
for _, exclude := range s.Exclude { for _, exclude := range s.Exclude {
if exclude = strings.ToUpper(strings.TrimSpace(exclude)); exclude != "" { if exclude = strings.ToUpper(strings.TrimSpace(exclude)); exclude != "" {
@@ -136,7 +136,7 @@ func (s *srsOut) filterAndSortList(container lib.Container) []string {
return list return list
} }
func (s *srsOut) generate(entry *lib.Entry) error { func (s *SRSOut) generate(entry *lib.Entry) error {
ruleset, err := s.marshalRuleSet(entry) ruleset, err := s.marshalRuleSet(entry)
if err != nil { if err != nil {
return err return err
@@ -150,7 +150,7 @@ func (s *srsOut) generate(entry *lib.Entry) error {
return nil return nil
} }
func (s *srsOut) marshalRuleSet(entry *lib.Entry) (*option.PlainRuleSet, error) { func (s *SRSOut) marshalRuleSet(entry *lib.Entry) (*option.PlainRuleSet, error) {
var entryCidr []string var entryCidr []string
var err error var err error
switch s.OnlyIPType { switch s.OnlyIPType {
@@ -183,7 +183,7 @@ func (s *srsOut) marshalRuleSet(entry *lib.Entry) (*option.PlainRuleSet, error)
return nil, fmt.Errorf("❌ [type %s | action %s] entry %s has no CIDR", s.Type, s.Action, entry.GetName()) return nil, fmt.Errorf("❌ [type %s | action %s] entry %s has no CIDR", s.Type, s.Action, entry.GetName())
} }
func (s *srsOut) writeFile(filename string, ruleset *option.PlainRuleSet) error { func (s *SRSOut) writeFile(filename string, ruleset *option.PlainRuleSet) error {
if err := os.MkdirAll(s.OutputDir, 0755); err != nil { if err := os.MkdirAll(s.OutputDir, 0755); err != nil {
return err return err
} }
@@ -194,7 +194,7 @@ func (s *srsOut) writeFile(filename string, ruleset *option.PlainRuleSet) error
} }
defer f.Close() defer f.Close()
err = srs.Write(f, *ruleset) err = srs.Write(f, *ruleset, false)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -9,16 +9,16 @@ import (
) )
const ( const (
typeCutter = "cutter" TypeCutter = "cutter"
descCutter = "Remove data from previous steps" DescCutter = "Remove data from previous steps"
) )
func init() { func init() {
lib.RegisterInputConfigCreator(typeCutter, func(action lib.Action, data json.RawMessage) (lib.InputConverter, error) { lib.RegisterInputConfigCreator(TypeCutter, func(action lib.Action, data json.RawMessage) (lib.InputConverter, error) {
return newCutter(action, data) return newCutter(action, data)
}) })
lib.RegisterInputConverter(typeCutter, &cutter{ lib.RegisterInputConverter(TypeCutter, &Cutter{
Description: descCutter, Description: DescCutter,
}) })
} }
@@ -35,7 +35,7 @@ func newCutter(action lib.Action, data json.RawMessage) (lib.InputConverter, err
} }
if action != lib.ActionRemove { if action != lib.ActionRemove {
return nil, fmt.Errorf("❌ [type %s] only supports `remove` action", typeCutter) return nil, fmt.Errorf("❌ [type %s] only supports `remove` action", TypeCutter)
} }
// Filter want list // Filter want list
@@ -47,19 +47,19 @@ func newCutter(action lib.Action, data json.RawMessage) (lib.InputConverter, err
} }
if len(wantList) == 0 { if len(wantList) == 0 {
return nil, fmt.Errorf("❌ [type %s] wantedList must be specified", typeCutter) return nil, fmt.Errorf("❌ [type %s] wantedList must be specified", TypeCutter)
} }
return &cutter{ return &Cutter{
Type: typeCutter, Type: TypeCutter,
Action: action, Action: action,
Description: descCutter, Description: DescCutter,
Want: wantList, Want: wantList,
OnlyIPType: tmp.OnlyIPType, OnlyIPType: tmp.OnlyIPType,
}, nil }, nil
} }
type cutter struct { type Cutter struct {
Type string Type string
Action lib.Action Action lib.Action
Description string Description string
@@ -67,19 +67,19 @@ type cutter struct {
OnlyIPType lib.IPType OnlyIPType lib.IPType
} }
func (c *cutter) GetType() string { func (c *Cutter) GetType() string {
return c.Type return c.Type
} }
func (c *cutter) GetAction() lib.Action { func (c *Cutter) GetAction() lib.Action {
return c.Action return c.Action
} }
func (c *cutter) GetDescription() string { func (c *Cutter) GetDescription() string {
return c.Description return c.Description
} }
func (c *cutter) Input(container lib.Container) (lib.Container, error) { func (c *Cutter) Input(container lib.Container) (lib.Container, error) {
var ignoreIPType lib.IgnoreIPOption var ignoreIPType lib.IgnoreIPOption
switch c.OnlyIPType { switch c.OnlyIPType {
case lib.IPv4: case lib.IPv4:

View File

@@ -12,16 +12,16 @@ import (
) )
const ( const (
typeLookup = "lookup" TypeLookup = "lookup"
descLookup = "Lookup specified IP or CIDR from various formats of data" DescLookup = "Lookup specified IP or CIDR from various formats of data"
) )
func init() { func init() {
lib.RegisterOutputConfigCreator(typeLookup, func(action lib.Action, data json.RawMessage) (lib.OutputConverter, error) { lib.RegisterOutputConfigCreator(TypeLookup, func(action lib.Action, data json.RawMessage) (lib.OutputConverter, error) {
return newLookup(action, data) return newLookup(action, data)
}) })
lib.RegisterOutputConverter(typeLookup, &lookup{ lib.RegisterOutputConverter(TypeLookup, &Lookup{
Description: descLookup, Description: DescLookup,
}) })
} }
@@ -39,19 +39,19 @@ func newLookup(action lib.Action, data json.RawMessage) (lib.OutputConverter, er
tmp.Search = strings.TrimSpace(tmp.Search) tmp.Search = strings.TrimSpace(tmp.Search)
if tmp.Search == "" { if tmp.Search == "" {
return nil, fmt.Errorf("❌ [type %s | action %s] please specify an IP or a CIDR as search target", typeLookup, action) return nil, fmt.Errorf("❌ [type %s | action %s] please specify an IP or a CIDR as search target", TypeLookup, action)
} }
return &lookup{ return &Lookup{
Type: typeLookup, Type: TypeLookup,
Action: action, Action: action,
Description: descLookup, Description: DescLookup,
Search: tmp.Search, Search: tmp.Search,
SearchList: tmp.SearchList, SearchList: tmp.SearchList,
}, nil }, nil
} }
type lookup struct { type Lookup struct {
Type string Type string
Action lib.Action Action lib.Action
Description string Description string
@@ -59,19 +59,19 @@ type lookup struct {
SearchList []string SearchList []string
} }
func (l *lookup) GetType() string { func (l *Lookup) GetType() string {
return l.Type return l.Type
} }
func (l *lookup) GetAction() lib.Action { func (l *Lookup) GetAction() lib.Action {
return l.Action return l.Action
} }
func (l *lookup) GetDescription() string { func (l *Lookup) GetDescription() string {
return l.Description return l.Description
} }
func (l *lookup) Output(container lib.Container) error { func (l *Lookup) Output(container lib.Container) error {
switch strings.Contains(l.Search, "/") { switch strings.Contains(l.Search, "/") {
case true: // CIDR case true: // CIDR
if _, err := netip.ParsePrefix(l.Search); err != nil { if _, err := netip.ParsePrefix(l.Search); err != nil {

View File

@@ -8,8 +8,8 @@ import (
const ( const (
entryNamePrivate = "private" entryNamePrivate = "private"
typePrivate = "private" TypePrivate = "private"
descPrivate = "Convert LAN and private network CIDR to other formats" DescPrivate = "Convert LAN and private network CIDR to other formats"
) )
var privateCIDRs = []string{ var privateCIDRs = []string{
@@ -37,11 +37,11 @@ var privateCIDRs = []string{
} }
func init() { func init() {
lib.RegisterInputConfigCreator(typePrivate, func(action lib.Action, data json.RawMessage) (lib.InputConverter, error) { lib.RegisterInputConfigCreator(TypePrivate, func(action lib.Action, data json.RawMessage) (lib.InputConverter, error) {
return newPrivate(action, data) return newPrivate(action, data)
}) })
lib.RegisterInputConverter(typePrivate, &private{ lib.RegisterInputConverter(TypePrivate, &Private{
Description: descPrivate, Description: DescPrivate,
}) })
} }
@@ -56,34 +56,34 @@ func newPrivate(action lib.Action, data json.RawMessage) (lib.InputConverter, er
} }
} }
return &private{ return &Private{
Type: typePrivate, Type: TypePrivate,
Action: action, Action: action,
Description: descPrivate, Description: DescPrivate,
OnlyIPType: tmp.OnlyIPType, OnlyIPType: tmp.OnlyIPType,
}, nil }, nil
} }
type private struct { type Private struct {
Type string Type string
Action lib.Action Action lib.Action
Description string Description string
OnlyIPType lib.IPType OnlyIPType lib.IPType
} }
func (p *private) GetType() string { func (p *Private) GetType() string {
return p.Type return p.Type
} }
func (p *private) GetAction() lib.Action { func (p *Private) GetAction() lib.Action {
return p.Action return p.Action
} }
func (p *private) GetDescription() string { func (p *Private) GetDescription() string {
return p.Description return p.Description
} }
func (p *private) Input(container lib.Container) (lib.Container, error) { func (p *Private) Input(container lib.Container) (lib.Container, error) {
entry, found := container.GetEntry(entryNamePrivate) entry, found := container.GetEntry(entryNamePrivate)
if !found { if !found {
entry = lib.NewEntry(entryNamePrivate) entry = lib.NewEntry(entryNamePrivate)

View File

@@ -11,16 +11,16 @@ import (
) )
const ( const (
typeStdin = "stdin" TypeStdin = "stdin"
descStdin = "Accept plaintext IP & CIDR from standard input, separated by newline" DescStdin = "Accept plaintext IP & CIDR from standard input, separated by newline"
) )
func init() { func init() {
lib.RegisterInputConfigCreator(typeStdin, func(action lib.Action, data json.RawMessage) (lib.InputConverter, error) { lib.RegisterInputConfigCreator(TypeStdin, func(action lib.Action, data json.RawMessage) (lib.InputConverter, error) {
return newStdin(action, data) return newStdin(action, data)
}) })
lib.RegisterInputConverter(typeStdin, &stdin{ lib.RegisterInputConverter(TypeStdin, &Stdin{
Description: descStdin, Description: DescStdin,
}) })
} }
@@ -37,19 +37,19 @@ func newStdin(action lib.Action, data json.RawMessage) (lib.InputConverter, erro
} }
if tmp.Name == "" { if tmp.Name == "" {
return nil, fmt.Errorf("❌ [type %s | action %s] missing name", typeStdin, action) return nil, fmt.Errorf("❌ [type %s | action %s] missing name", TypeStdin, action)
} }
return &stdin{ return &Stdin{
Type: typeStdin, Type: TypeStdin,
Action: action, Action: action,
Description: descStdin, Description: DescStdin,
Name: tmp.Name, Name: tmp.Name,
OnlyIPType: tmp.OnlyIPType, OnlyIPType: tmp.OnlyIPType,
}, nil }, nil
} }
type stdin struct { type Stdin struct {
Type string Type string
Action lib.Action Action lib.Action
Description string Description string
@@ -57,19 +57,19 @@ type stdin struct {
OnlyIPType lib.IPType OnlyIPType lib.IPType
} }
func (s *stdin) GetType() string { func (s *Stdin) GetType() string {
return s.Type return s.Type
} }
func (s *stdin) GetAction() lib.Action { func (s *Stdin) GetAction() lib.Action {
return s.Action return s.Action
} }
func (s *stdin) GetDescription() string { func (s *Stdin) GetDescription() string {
return s.Description return s.Description
} }
func (s *stdin) Input(container lib.Container) (lib.Container, error) { func (s *Stdin) Input(container lib.Container) (lib.Container, error) {
entry := lib.NewEntry(s.Name) entry := lib.NewEntry(s.Name)
scanner := bufio.NewScanner(os.Stdin) scanner := bufio.NewScanner(os.Stdin)

View File

@@ -12,16 +12,16 @@ import (
) )
const ( const (
typeStdout = "stdout" TypeStdout = "stdout"
descStdout = "Convert data to plaintext CIDR format and output to standard output" DescStdout = "Convert data to plaintext CIDR format and output to standard output"
) )
func init() { func init() {
lib.RegisterOutputConfigCreator(typeStdout, func(action lib.Action, data json.RawMessage) (lib.OutputConverter, error) { lib.RegisterOutputConfigCreator(TypeStdout, func(action lib.Action, data json.RawMessage) (lib.OutputConverter, error) {
return newStdout(action, data) return newStdout(action, data)
}) })
lib.RegisterOutputConverter(typeStdout, &stdout{ lib.RegisterOutputConverter(TypeStdout, &Stdout{
Description: descStdout, Description: DescStdout,
}) })
} }
@@ -38,17 +38,17 @@ func newStdout(action lib.Action, data json.RawMessage) (lib.OutputConverter, er
} }
} }
return &stdout{ return &Stdout{
Type: typeStdout, Type: TypeStdout,
Action: action, Action: action,
Description: descStdout, Description: DescStdout,
Want: tmp.Want, Want: tmp.Want,
Exclude: tmp.Exclude, Exclude: tmp.Exclude,
OnlyIPType: tmp.OnlyIPType, OnlyIPType: tmp.OnlyIPType,
}, nil }, nil
} }
type stdout struct { type Stdout struct {
Type string Type string
Action lib.Action Action lib.Action
Description string Description string
@@ -57,19 +57,19 @@ type stdout struct {
OnlyIPType lib.IPType OnlyIPType lib.IPType
} }
func (s *stdout) GetType() string { func (s *Stdout) GetType() string {
return s.Type return s.Type
} }
func (s *stdout) GetAction() lib.Action { func (s *Stdout) GetAction() lib.Action {
return s.Action return s.Action
} }
func (s *stdout) GetDescription() string { func (s *Stdout) GetDescription() string {
return s.Description return s.Description
} }
func (s *stdout) Output(container lib.Container) error { func (s *Stdout) Output(container lib.Container) error {
for _, name := range s.filterAndSortList(container) { for _, name := range s.filterAndSortList(container) {
entry, found := container.GetEntry(name) entry, found := container.GetEntry(name)
if !found { if !found {
@@ -89,7 +89,7 @@ func (s *stdout) Output(container lib.Container) error {
return nil return nil
} }
func (s *stdout) filterAndSortList(container lib.Container) []string { func (s *Stdout) filterAndSortList(container lib.Container) []string {
excludeMap := make(map[string]bool) excludeMap := make(map[string]bool)
for _, exclude := range s.Exclude { for _, exclude := range s.Exclude {
if exclude = strings.ToUpper(strings.TrimSpace(exclude)); exclude != "" { if exclude = strings.ToUpper(strings.TrimSpace(exclude)); exclude != "" {
@@ -125,7 +125,7 @@ func (s *stdout) filterAndSortList(container lib.Container) []string {
return list return list
} }
func (s *stdout) generateCIDRList(entry *lib.Entry) ([]string, error) { func (s *Stdout) generateCIDRList(entry *lib.Entry) ([]string, error) {
var entryList []string var entryList []string
var err error var err error
switch s.OnlyIPType { switch s.OnlyIPType {

View File

@@ -14,16 +14,16 @@ import (
) )
const ( const (
typeGeoIPdatIn = "v2rayGeoIPDat" TypeGeoIPdatIn = "v2rayGeoIPDat"
descGeoIPdatIn = "Convert V2Ray GeoIP dat to other formats" DescGeoIPdatIn = "Convert V2Ray GeoIP dat to other formats"
) )
func init() { func init() {
lib.RegisterInputConfigCreator(typeGeoIPdatIn, func(action lib.Action, data json.RawMessage) (lib.InputConverter, error) { lib.RegisterInputConfigCreator(TypeGeoIPdatIn, func(action lib.Action, data json.RawMessage) (lib.InputConverter, error) {
return newGeoIPDatIn(action, data) return newGeoIPDatIn(action, data)
}) })
lib.RegisterInputConverter(typeGeoIPdatIn, &geoIPDatIn{ lib.RegisterInputConverter(TypeGeoIPdatIn, &GeoIPDatIn{
Description: descGeoIPdatIn, Description: DescGeoIPdatIn,
}) })
} }
@@ -41,7 +41,7 @@ func newGeoIPDatIn(action lib.Action, data json.RawMessage) (lib.InputConverter,
} }
if tmp.URI == "" { if tmp.URI == "" {
return nil, fmt.Errorf("❌ [type %s | action %s] uri must be specified in config", typeGeoIPdatIn, action) return nil, fmt.Errorf("❌ [type %s | action %s] uri must be specified in config", TypeGeoIPdatIn, action)
} }
// Filter want list // Filter want list
@@ -52,17 +52,17 @@ func newGeoIPDatIn(action lib.Action, data json.RawMessage) (lib.InputConverter,
} }
} }
return &geoIPDatIn{ return &GeoIPDatIn{
Type: typeGeoIPdatIn, Type: TypeGeoIPdatIn,
Action: action, Action: action,
Description: descGeoIPdatIn, Description: DescGeoIPdatIn,
URI: tmp.URI, URI: tmp.URI,
Want: wantList, Want: wantList,
OnlyIPType: tmp.OnlyIPType, OnlyIPType: tmp.OnlyIPType,
}, nil }, nil
} }
type geoIPDatIn struct { type GeoIPDatIn struct {
Type string Type string
Action lib.Action Action lib.Action
Description string Description string
@@ -71,19 +71,19 @@ type geoIPDatIn struct {
OnlyIPType lib.IPType OnlyIPType lib.IPType
} }
func (g *geoIPDatIn) GetType() string { func (g *GeoIPDatIn) GetType() string {
return g.Type return g.Type
} }
func (g *geoIPDatIn) GetAction() lib.Action { func (g *GeoIPDatIn) GetAction() lib.Action {
return g.Action return g.Action
} }
func (g *geoIPDatIn) GetDescription() string { func (g *GeoIPDatIn) GetDescription() string {
return g.Description return g.Description
} }
func (g *geoIPDatIn) Input(container lib.Container) (lib.Container, error) { func (g *GeoIPDatIn) Input(container lib.Container) (lib.Container, error) {
entries := make(map[string]*lib.Entry) entries := make(map[string]*lib.Entry)
var err error var err error
@@ -128,7 +128,7 @@ func (g *geoIPDatIn) Input(container lib.Container) (lib.Container, error) {
return container, nil return container, nil
} }
func (g *geoIPDatIn) walkLocalFile(path string, entries map[string]*lib.Entry) error { func (g *GeoIPDatIn) walkLocalFile(path string, entries map[string]*lib.Entry) error {
file, err := os.Open(path) file, err := os.Open(path)
if err != nil { if err != nil {
return err return err
@@ -142,7 +142,7 @@ func (g *geoIPDatIn) walkLocalFile(path string, entries map[string]*lib.Entry) e
return nil return nil
} }
func (g *geoIPDatIn) walkRemoteFile(url string, entries map[string]*lib.Entry) error { func (g *GeoIPDatIn) walkRemoteFile(url string, entries map[string]*lib.Entry) error {
resp, err := http.Get(url) resp, err := http.Get(url)
if err != nil { if err != nil {
return err return err
@@ -160,7 +160,7 @@ func (g *geoIPDatIn) walkRemoteFile(url string, entries map[string]*lib.Entry) e
return nil return nil
} }
func (g *geoIPDatIn) generateEntries(reader io.Reader, entries map[string]*lib.Entry) error { func (g *GeoIPDatIn) generateEntries(reader io.Reader, entries map[string]*lib.Entry) error {
geoipBytes, err := io.ReadAll(reader) geoipBytes, err := io.ReadAll(reader)
if err != nil { if err != nil {
return err return err

View File

@@ -16,8 +16,8 @@ import (
) )
const ( const (
typeGeoIPdatOut = "v2rayGeoIPDat" TypeGeoIPdatOut = "v2rayGeoIPDat"
descGeoIPdatOut = "Convert data to V2Ray GeoIP dat format" DescGeoIPdatOut = "Convert data to V2Ray GeoIP dat format"
) )
var ( var (
@@ -26,11 +26,11 @@ var (
) )
func init() { func init() {
lib.RegisterOutputConfigCreator(typeGeoIPdatOut, func(action lib.Action, data json.RawMessage) (lib.OutputConverter, error) { lib.RegisterOutputConfigCreator(TypeGeoIPdatOut, func(action lib.Action, data json.RawMessage) (lib.OutputConverter, error) {
return newGeoIPDat(action, data) return newGeoIPDat(action, data)
}) })
lib.RegisterOutputConverter(typeGeoIPdatOut, &geoIPDatOut{ lib.RegisterOutputConverter(TypeGeoIPdatOut, &GeoIPDatOut{
Description: descGeoIPdatOut, Description: DescGeoIPdatOut,
}) })
} }
@@ -58,10 +58,10 @@ func newGeoIPDat(action lib.Action, data json.RawMessage) (lib.OutputConverter,
tmp.OutputDir = defaultOutputDir tmp.OutputDir = defaultOutputDir
} }
return &geoIPDatOut{ return &GeoIPDatOut{
Type: typeGeoIPdatOut, Type: TypeGeoIPdatOut,
Action: action, Action: action,
Description: descGeoIPdatOut, Description: DescGeoIPdatOut,
OutputName: tmp.OutputName, OutputName: tmp.OutputName,
OutputDir: tmp.OutputDir, OutputDir: tmp.OutputDir,
Want: tmp.Want, Want: tmp.Want,
@@ -71,7 +71,7 @@ func newGeoIPDat(action lib.Action, data json.RawMessage) (lib.OutputConverter,
}, nil }, nil
} }
type geoIPDatOut struct { type GeoIPDatOut struct {
Type string Type string
Action lib.Action Action lib.Action
Description string Description string
@@ -83,19 +83,19 @@ type geoIPDatOut struct {
OnlyIPType lib.IPType OnlyIPType lib.IPType
} }
func (g *geoIPDatOut) GetType() string { func (g *GeoIPDatOut) GetType() string {
return g.Type return g.Type
} }
func (g *geoIPDatOut) GetAction() lib.Action { func (g *GeoIPDatOut) GetAction() lib.Action {
return g.Action return g.Action
} }
func (g *geoIPDatOut) GetDescription() string { func (g *GeoIPDatOut) GetDescription() string {
return g.Description return g.Description
} }
func (g *geoIPDatOut) Output(container lib.Container) error { func (g *GeoIPDatOut) Output(container lib.Container) error {
geoIPList := new(GeoIPList) geoIPList := new(GeoIPList)
geoIPList.Entry = make([]*GeoIP, 0, 300) geoIPList.Entry = make([]*GeoIP, 0, 300)
updated := false updated := false
@@ -145,7 +145,7 @@ func (g *geoIPDatOut) Output(container lib.Container) error {
return nil return nil
} }
func (g *geoIPDatOut) filterAndSortList(container lib.Container) []string { func (g *GeoIPDatOut) filterAndSortList(container lib.Container) []string {
excludeMap := make(map[string]bool) excludeMap := make(map[string]bool)
for _, exclude := range g.Exclude { for _, exclude := range g.Exclude {
if exclude = strings.ToUpper(strings.TrimSpace(exclude)); exclude != "" { if exclude = strings.ToUpper(strings.TrimSpace(exclude)); exclude != "" {
@@ -181,7 +181,7 @@ func (g *geoIPDatOut) filterAndSortList(container lib.Container) []string {
return list return list
} }
func (g *geoIPDatOut) generateGeoIP(entry *lib.Entry) (*GeoIP, error) { func (g *GeoIPDatOut) generateGeoIP(entry *lib.Entry) (*GeoIP, error) {
var entryCidr []netip.Prefix var entryCidr []netip.Prefix
var err error var err error
switch g.OnlyIPType { switch g.OnlyIPType {
@@ -215,13 +215,13 @@ func (g *geoIPDatOut) generateGeoIP(entry *lib.Entry) (*GeoIP, error) {
} }
// Sort by country code to make reproducible builds // Sort by country code to make reproducible builds
func (g *geoIPDatOut) sort(list *GeoIPList) { func (g *GeoIPDatOut) sort(list *GeoIPList) {
sort.SliceStable(list.Entry, func(i, j int) bool { sort.SliceStable(list.Entry, func(i, j int) bool {
return list.Entry[i].CountryCode < list.Entry[j].CountryCode return list.Entry[i].CountryCode < list.Entry[j].CountryCode
}) })
} }
func (g *geoIPDatOut) writeFile(filename string, geoIPBytes []byte) error { func (g *GeoIPDatOut) writeFile(filename string, geoIPBytes []byte) error {
if err := os.MkdirAll(g.OutputDir, 0755); err != nil { if err := os.MkdirAll(g.OutputDir, 0755); err != nil {
return err return err
} }

View File

@@ -656,6 +656,22 @@ endef
$(eval $(call KernelPackage,usb-serial-ch341)) $(eval $(call KernelPackage,usb-serial-ch341))
define KernelPackage/usb-serial-ch348
TITLE:=Support for CH348 devices
KCONFIG:=CONFIG_USB_SERIAL_CH348
FILES:=$(LINUX_DIR)/drivers/usb/serial/ch348.ko
AUTOLOAD:=$(call AutoProbe,ch348)
DEPENDS:=@(LINUX_6_1||LINUX_6_6)
$(call AddDepends/usb-serial)
endef
define KernelPackage/usb-serial-ch348/description
Kernel support for Winchiphead CH348 USB-to-8x-Serial converters
endef
$(eval $(call KernelPackage,usb-serial-ch348))
define KernelPackage/usb-serial-edgeport define KernelPackage/usb-serial-edgeport
TITLE:=Support for Digi Edgeport devices TITLE:=Support for Digi Edgeport devices
KCONFIG:=CONFIG_USB_SERIAL_EDGEPORT KCONFIG:=CONFIG_USB_SERIAL_EDGEPORT

View File

@@ -0,0 +1,783 @@
From df1357358eec062241bddd2995e7ef0ce86cf45a Mon Sep 17 00:00:00 2001
X-Patchwork-Submitter: Corentin Labbe <clabbe@baylibre.com>
X-Patchwork-Id: 13656881
Message-Id: <20240507131522.3546113-2-clabbe@baylibre.com>
X-Mailer: git-send-email 2.25.1
In-Reply-To: <20240507131522.3546113-1-clabbe@baylibre.com>
References: <20240507131522.3546113-1-clabbe@baylibre.com>
Precedence: bulk
X-Mailing-List: linux-usb@vger.kernel.org
List-Id: <linux-usb.vger.kernel.org>
From: Corentin Labbe <clabbe@baylibre.com>
Date: Tue, 7 May 2024 13:15:22 +0000
Subject: [PATCH v7] usb: serial: add support for CH348
The CH348 is an USB octo port serial adapter.
The device multiplexes all 8 ports in the same pair of Bulk endpoints.
Since there is no public datasheet, unfortunately it remains some magic values
Signed-off-by: Corentin Labbe <clabbe@baylibre.com>
Tested-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
drivers/usb/serial/Kconfig | 9 +
drivers/usb/serial/Makefile | 1 +
drivers/usb/serial/ch348.c | 725 ++++++++++++++++++++++++++++++++++++
3 files changed, 735 insertions(+)
create mode 100644 drivers/usb/serial/ch348.c
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -112,6 +112,15 @@ config USB_SERIAL_CH341
To compile this driver as a module, choose M here: the
module will be called ch341.
+config USB_SERIAL_CH348
+ tristate "USB Winchiphead CH348 Octo Port Serial Driver"
+ help
+ Say Y here if you want to use a Winchiphead CH348 octo port
+ USB to serial adapter.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ch348.
+
config USB_SERIAL_WHITEHEAT
tristate "USB ConnectTech WhiteHEAT Serial Driver"
select USB_EZUSB_FX2
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_USB_SERIAL_AIRCABLE) += ai
obj-$(CONFIG_USB_SERIAL_ARK3116) += ark3116.o
obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o
obj-$(CONFIG_USB_SERIAL_CH341) += ch341.o
+obj-$(CONFIG_USB_SERIAL_CH348) += ch348.o
obj-$(CONFIG_USB_SERIAL_CP210X) += cp210x.o
obj-$(CONFIG_USB_SERIAL_CYBERJACK) += cyberjack.o
obj-$(CONFIG_USB_SERIAL_CYPRESS_M8) += cypress_m8.o
--- /dev/null
+++ b/drivers/usb/serial/ch348.c
@@ -0,0 +1,725 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * USB serial driver for USB to Octal UARTs chip ch348.
+ *
+ * Copyright (C) 2022 Corentin Labbe <clabbe@baylibre.com>
+ * With the help of Neil Armstrong <neil.armstrong@linaro.org>
+ * and the help of Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ */
+
+#include <linux/completion.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/overflow.h>
+#include <linux/serial.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+
+#define CH348_CMD_TIMEOUT 2000
+
+#define CH348_CTO_D 0x01
+#define CH348_CTO_R 0x02
+
+#define CH348_CTI_C 0x10
+#define CH348_CTI_DSR 0x20
+#define CH348_CTI_R 0x40
+#define CH348_CTI_DCD 0x80
+
+#define CH348_LO 0x02
+#define CH348_LP 0x04
+#define CH348_LF 0x08
+#define CH348_LB 0x10
+
+#define CMD_W_R 0xC0
+#define CMD_W_BR 0x80
+
+#define CMD_WB_E 0x90
+#define CMD_RB_E 0xC0
+
+#define M_NOR 0x00
+#define M_HF 0x03
+
+#define R_MOD 0x97
+#define R_IO_D 0x98
+#define R_IO_O 0x99
+#define R_IO_I 0x9b
+#define R_TM_O 0x9c
+#define R_INIT 0xa1
+
+#define R_C1 0x01
+#define R_C2 0x02
+#define R_C4 0x04
+#define R_C5 0x06
+
+#define R_II_B1 0x06
+#define R_II_B2 0x02
+#define R_II_B3 0x00
+
+#define CMD_VER 0x96
+
+#define CH348_RX_PORT_CHUNK_LENGTH 32
+#define CH348_RX_PORT_MAX_LENGTH 30
+
+struct ch348_rxbuf {
+ u8 port;
+ u8 length;
+ u8 data[CH348_RX_PORT_MAX_LENGTH];
+} __packed;
+
+struct ch348_txbuf {
+ u8 port;
+ __le16 length;
+ u8 data[];
+} __packed;
+
+#define CH348_TX_HDRSIZE offsetof(struct ch348_txbuf, data)
+
+struct ch348_initbuf {
+ u8 cmd;
+ u8 reg;
+ u8 port;
+ __be32 baudrate;
+ u8 format;
+ u8 paritytype;
+ u8 databits;
+ u8 rate;
+ u8 unknown;
+} __packed;
+
+#define CH348_MAXPORT 8
+
+/*
+ * The CH348 multiplexes rx & tx into a pair of Bulk USB endpoints for
+ * the 8 serial ports, and another pair of Bulk USB endpoints to
+ * set port settings and receive port status events.
+ *
+ * The USB serial cores ties every Bulk endpoints pairs to each ports,
+ * but in our case it will set port 0 with the rx/tx endpoints
+ * and port 1 with the setup/status endpoints.
+ *
+ * To still take advantage of the generic code, we (re-)initialize
+ * the USB serial port structure with the correct USB endpoint
+ * for read and write, and write proper process_read_urb()
+ * and prepare_write_buffer() to correctly (de-)multiplex data.
+ * Also we use a custom write() implementation to wait until the buffer
+ * has been fully transmitted to prevent TX buffer overruns.
+ */
+
+/*
+ * struct ch348_port - per-port information
+ * @uartmode: UART port current mode
+ * @write_completion: completion event when the TX buffer has been written out
+ */
+struct ch348_port {
+ u8 uartmode;
+ struct completion write_completion;
+};
+
+/*
+ * struct ch348 - main container for all this driver information
+ * @udev: pointer to the CH348 USB device
+ * @ports: List of per-port information
+ * @serial: pointer to the serial structure
+ * @write_lock: protect against concurrent writes so we don't lose data
+ * @cmd_ep: endpoint number for configure operations
+ * @status_urb: URB for status
+ * @status_buffer: buffer used by status_urb
+ */
+struct ch348 {
+ struct usb_device *udev;
+ struct ch348_port ports[CH348_MAXPORT];
+ struct usb_serial *serial;
+
+ struct mutex write_lock;
+
+ int cmd_ep;
+
+ struct urb *status_urb;
+ u8 status_buffer[];
+};
+
+struct ch348_magic {
+ u8 action;
+ u8 reg;
+ u8 control;
+} __packed;
+
+struct ch348_status_entry {
+ u8 portnum:4;
+ u8 unused:4;
+ u8 reg_iir;
+ union {
+ u8 lsr_signal;
+ u8 modem_signal;
+ u8 init_data[10];
+ };
+} __packed;
+
+static void ch348_process_status_urb(struct urb *urb)
+{
+ struct ch348_status_entry *status_entry;
+ struct ch348 *ch348 = urb->context;
+ int ret, status = urb->status;
+ struct usb_serial_port *port;
+ unsigned int i, status_len;
+
+ switch (status) {
+ case 0:
+ /* success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+ dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n",
+ __func__, status);
+ return;
+ default:
+ dev_err(&urb->dev->dev, "%s - nonzero urb status received: %d\n",
+ __func__, status);
+ goto exit;
+ }
+
+ if (urb->actual_length < 3) {
+ dev_warn(&ch348->udev->dev,
+ "Received too short status buffer with %u bytes\n",
+ urb->actual_length);
+ goto exit;
+ }
+
+ for (i = 0; i < urb->actual_length;) {
+ status_entry = urb->transfer_buffer + i;
+
+ if (status_entry->portnum >= CH348_MAXPORT) {
+ dev_warn(&ch348->udev->dev,
+ "Invalid port %d in status entry\n",
+ status_entry->portnum);
+ break;
+ }
+
+ port = ch348->serial->port[status_entry->portnum];
+ status_len = 3;
+
+ if (!status_entry->reg_iir) {
+ dev_dbg(&port->dev, "Ignoring status with zero reg_iir\n");
+ } else if (status_entry->reg_iir == R_INIT) {
+ status_len = 12;
+ } else if ((status_entry->reg_iir & 0x0f) == R_II_B1) {
+ if (status_entry->lsr_signal & CH348_LO)
+ port->icount.overrun++;
+ if (status_entry->lsr_signal & CH348_LP)
+ port->icount.parity++;
+ if (status_entry->lsr_signal & CH348_LF)
+ port->icount.frame++;
+ if (status_entry->lsr_signal & CH348_LF)
+ port->icount.brk++;
+ } else if ((status_entry->reg_iir & 0x0f) == R_II_B2) {
+ complete_all(&ch348->ports[status_entry->portnum].write_completion);
+ } else {
+ dev_warn(&port->dev,
+ "Unsupported status with reg_iir 0x%02x\n",
+ status_entry->reg_iir);
+ }
+
+ usb_serial_debug_data(&port->dev, __func__, status_len,
+ urb->transfer_buffer + i);
+
+ i += status_len;
+ }
+
+exit:
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (ret)
+ dev_err(&urb->dev->dev, "%s - usb_submit_urb failed; %d\n",
+ __func__, ret);
+}
+
+/*
+ * Some values came from vendor tree, and we have no meaning for them, this
+ * function simply use them.
+ */
+static int ch348_do_magic(struct ch348 *ch348, int portnum, u8 action, u8 reg, u8 control)
+{
+ struct ch348_magic *buffer;
+ int ret, len;
+
+ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ if (portnum < 4)
+ reg += 0x10 * portnum;
+ else
+ reg += 0x10 * (portnum - 4) + 0x08;
+
+ buffer->action = action;
+ buffer->reg = reg;
+ buffer->control = control;
+
+ ret = usb_bulk_msg(ch348->udev, ch348->cmd_ep, buffer, 3, &len,
+ CH348_CMD_TIMEOUT);
+ if (ret)
+ dev_err(&ch348->udev->dev, "Failed to write magic err=%d\n", ret);
+
+ kfree(buffer);
+
+ return ret;
+}
+
+static int ch348_configure(struct ch348 *ch348, int portnum)
+{
+ int ret;
+
+ ret = ch348_do_magic(ch348, portnum, CMD_W_R, R_C2, 0x87);
+ if (ret)
+ return ret;
+
+ return ch348_do_magic(ch348, portnum, CMD_W_R, R_C4, 0x08);
+}
+
+static void ch348_process_read_urb(struct urb *urb)
+{
+ struct usb_serial_port *port = urb->context;
+ struct ch348 *ch348 = usb_get_serial_data(port->serial);
+ unsigned int portnum, usblen, i;
+ struct ch348_rxbuf *rxb;
+
+ if (urb->actual_length < 2) {
+ dev_dbg(&ch348->udev->dev, "Empty rx buffer\n");
+ return;
+ }
+
+ for (i = 0; i < urb->actual_length; i += CH348_RX_PORT_CHUNK_LENGTH) {
+ rxb = urb->transfer_buffer + i;
+ portnum = rxb->port;
+ if (portnum >= CH348_MAXPORT) {
+ dev_dbg(&ch348->udev->dev, "Invalid port %d\n", portnum);
+ break;
+ }
+
+ port = ch348->serial->port[portnum];
+
+ usblen = rxb->length;
+ if (usblen > CH348_RX_PORT_MAX_LENGTH) {
+ dev_dbg(&port->dev, "Invalid length %d for port %d\n",
+ usblen, portnum);
+ break;
+ }
+
+ tty_insert_flip_string(&port->port, rxb->data, usblen);
+ tty_flip_buffer_push(&port->port);
+ port->icount.rx += usblen;
+ usb_serial_debug_data(&port->dev, __func__, usblen, rxb->data);
+ }
+}
+
+static int ch348_prepare_write_buffer(struct usb_serial_port *port, void *dest, size_t size)
+{
+ struct ch348_txbuf *rxt = dest;
+ int count;
+
+ count = kfifo_out_locked(&port->write_fifo, rxt->data,
+ size - CH348_TX_HDRSIZE, &port->lock);
+
+ rxt->port = port->port_number;
+ rxt->length = cpu_to_le16(count);
+
+ return count + CH348_TX_HDRSIZE;
+}
+
+static int ch348_write(struct tty_struct *tty, struct usb_serial_port *port,
+ const unsigned char *buf, int count)
+{
+ struct ch348 *ch348 = usb_get_serial_data(port->serial);
+ struct ch348_port *ch348_port = &ch348->ports[port->port_number];
+ int ret, max_tx_size;
+
+ if (tty_get_baud_rate(tty) < 9600 && count >= 128)
+ /*
+ * Writing larger buffers can take longer than the hardware
+ * allows before discarding the write buffer. Limit the
+ * transfer size in such cases.
+ * These values have been found by empirical testing.
+ */
+ max_tx_size = 128;
+ else
+ /*
+ * Only ingest as many bytes as we can transfer with one URB at
+ * a time. Once an URB has been written we need to wait for the
+ * R_II_B2 status event before we are allowed to send more data.
+ * If we ingest more data then usb_serial_generic_write() will
+ * internally try to process as much data as possible with any
+ * number of URBs without giving us the chance to wait in
+ * between transfers.
+ */
+ max_tx_size = port->bulk_out_size - CH348_TX_HDRSIZE;
+
+ reinit_completion(&ch348_port->write_completion);
+
+ mutex_lock(&ch348->write_lock);
+
+ /*
+ * For any (remaining) bytes that we did not transfer TTY core will
+ * call us again, with the buffer and count adjusted to the remaining
+ * data.
+ */
+ ret = usb_serial_generic_write(tty, port, buf, min(count, max_tx_size));
+
+ mutex_unlock(&ch348->write_lock);
+
+ if (ret <= 0)
+ return ret;
+
+ if (!wait_for_completion_interruptible_timeout(&ch348_port->write_completion,
+ msecs_to_jiffies(CH348_CMD_TIMEOUT))) {
+ dev_err_console(port, "Failed to wait for TX buffer flush\n");
+ return -ETIMEDOUT;
+ }
+
+ return ret;
+}
+
+static int ch348_set_uartmode(struct ch348 *ch348, int portnum, u8 mode)
+{
+ int ret;
+
+ if (ch348->ports[portnum].uartmode == M_NOR && mode == M_HF) {
+ ret = ch348_do_magic(ch348, portnum, CMD_W_BR, R_C4, 0x51);
+ if (ret)
+ return ret;
+ ch348->ports[portnum].uartmode = M_HF;
+ }
+
+ if (ch348->ports[portnum].uartmode == M_HF && mode == M_NOR) {
+ ret = ch348_do_magic(ch348, portnum, CMD_W_BR, R_C4, 0x50);
+ if (ret)
+ return ret;
+ ch348->ports[portnum].uartmode = M_NOR;
+ }
+ return 0;
+}
+
+static void ch348_set_termios(struct tty_struct *tty, struct usb_serial_port *port,
+ const struct ktermios *termios_old)
+{
+ struct ch348 *ch348 = usb_get_serial_data(port->serial);
+ struct ktermios *termios = &tty->termios;
+ int ret, portnum = port->port_number;
+ struct ch348_initbuf *buffer;
+ speed_t baudrate;
+ u8 format;
+
+ if (termios_old && !tty_termios_hw_change(&tty->termios, termios_old))
+ return;
+
+ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
+ if (!buffer) {
+ if (termios_old)
+ tty->termios = *termios_old;
+ return;
+ }
+
+ /*
+ * The datasheet states that only baud rates in range of 1200..6000000
+ * are supported. Tests however show that even baud rates as low as 50
+ * and as high as 12000000 are working in practice.
+ */
+ baudrate = clamp(tty_get_baud_rate(tty), 50, 12000000);
+
+ format = termios->c_cflag & CSTOPB ? 2 : 1;
+
+ buffer->paritytype = 0;
+ if (termios->c_cflag & PARENB) {
+ if (termios->c_cflag & PARODD)
+ buffer->paritytype += 1;
+ else
+ buffer->paritytype += 2;
+ if (termios->c_cflag & CMSPAR)
+ buffer->paritytype += 2;
+ }
+
+ switch (C_CSIZE(tty)) {
+ case CS5:
+ buffer->databits = 5;
+ break;
+ case CS6:
+ buffer->databits = 6;
+ break;
+ case CS7:
+ buffer->databits = 7;
+ break;
+ case CS8:
+ default:
+ buffer->databits = 8;
+ break;
+ }
+ buffer->cmd = CMD_WB_E | (portnum & 0x0F);
+ buffer->reg = R_INIT;
+ buffer->port = portnum;
+ buffer->baudrate = cpu_to_be32(baudrate);
+
+ if (format == 2)
+ buffer->format = 0x02;
+ else if (format == 1)
+ buffer->format = 0x00;
+
+ buffer->rate = max_t(speed_t, 5, (10000 * 15 / baudrate) + 1);
+
+ ret = usb_bulk_msg(ch348->udev, ch348->cmd_ep, buffer,
+ sizeof(*buffer), NULL, CH348_CMD_TIMEOUT);
+ if (ret < 0) {
+ dev_err(&ch348->udev->dev, "Failed to change line settings: err=%d\n",
+ ret);
+ goto out;
+ }
+
+ ret = ch348_do_magic(ch348, portnum, CMD_W_R, R_C1, 0x0F);
+ if (ret < 0)
+ goto out;
+
+ if (C_CRTSCTS(tty))
+ ret = ch348_set_uartmode(ch348, portnum, M_HF);
+ else
+ ret = ch348_set_uartmode(ch348, portnum, M_NOR);
+
+out:
+ kfree(buffer);
+}
+
+static int ch348_open(struct tty_struct *tty, struct usb_serial_port *port)
+{
+ struct ch348 *ch348 = usb_get_serial_data(port->serial);
+ int ret;
+
+ if (tty)
+ ch348_set_termios(tty, port, NULL);
+
+ ret = ch348_configure(ch348, port->port_number);
+ if (ret) {
+ dev_err(&ch348->udev->dev, "Fail to configure err=%d\n", ret);
+ return ret;
+ }
+
+ return usb_serial_generic_open(tty, port);
+}
+
+static int ch348_attach(struct usb_serial *serial)
+{
+ struct usb_endpoint_descriptor *epcmd, *epstatus;
+ struct usb_serial_port *port0 = serial->port[1];
+ struct usb_device *usb_dev = serial->dev;
+ int status_buffer_size, i, ret;
+ struct usb_interface *intf;
+ struct ch348 *ch348;
+
+ intf = usb_ifnum_to_if(usb_dev, 0);
+ epstatus = &intf->cur_altsetting->endpoint[2].desc;
+ epcmd = &intf->cur_altsetting->endpoint[3].desc;
+
+ status_buffer_size = usb_endpoint_maxp(epstatus);
+
+ ch348 = kzalloc(struct_size(ch348, status_buffer, status_buffer_size),
+ GFP_KERNEL);
+ if (!ch348)
+ return -ENOMEM;
+
+ usb_set_serial_data(serial, ch348);
+
+ ch348->udev = serial->dev;
+ ch348->serial = serial;
+ mutex_init(&ch348->write_lock);
+
+ for (i = 0; i < CH348_MAXPORT; i++)
+ init_completion(&ch348->ports[i].write_completion);
+
+ ch348->status_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!ch348->status_urb) {
+ ret = -ENOMEM;
+ goto err_free_ch348;
+ }
+
+ usb_fill_bulk_urb(ch348->status_urb, ch348->udev,
+ usb_rcvbulkpipe(ch348->udev, epstatus->bEndpointAddress),
+ ch348->status_buffer, status_buffer_size,
+ ch348_process_status_urb, ch348);
+
+ ret = usb_submit_urb(ch348->status_urb, GFP_KERNEL);
+ if (ret) {
+ dev_err(&ch348->udev->dev,
+ "%s - failed to submit status/interrupt urb %i\n",
+ __func__, ret);
+ goto err_free_status_urb;
+ }
+
+ ret = usb_serial_generic_submit_read_urbs(port0, GFP_KERNEL);
+ if (ret)
+ goto err_kill_status_urb;
+
+ ch348->cmd_ep = usb_sndbulkpipe(usb_dev, epcmd->bEndpointAddress);
+
+ return 0;
+
+err_kill_status_urb:
+ usb_kill_urb(ch348->status_urb);
+err_free_status_urb:
+ usb_free_urb(ch348->status_urb);
+err_free_ch348:
+ kfree(ch348);
+ return ret;
+}
+
+static void ch348_release(struct usb_serial *serial)
+{
+ struct ch348 *ch348 = usb_get_serial_data(serial);
+
+ usb_kill_urb(ch348->status_urb);
+ usb_free_urb(ch348->status_urb);
+
+ kfree(ch348);
+}
+
+static void ch348_print_version(struct usb_serial *serial)
+{
+ u8 *version_buf;
+ int ret;
+
+ version_buf = kzalloc(4, GFP_KERNEL);
+ if (!version_buf)
+ return;
+
+ ret = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ CMD_VER,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ 0, 0, version_buf, 4, CH348_CMD_TIMEOUT);
+ if (ret < 0)
+ dev_dbg(&serial->dev->dev, "Failed to read CMD_VER: %d\n", ret);
+ else
+ dev_info(&serial->dev->dev, "Found WCH CH348%s\n",
+ (version_buf[1] & 0x80) ? "Q" : "L");
+
+ kfree(version_buf);
+}
+
+static int ch348_probe(struct usb_serial *serial, const struct usb_device_id *id)
+{
+ struct usb_endpoint_descriptor *epread, *epwrite, *epstatus, *epcmd;
+ struct usb_device *usb_dev = serial->dev;
+ struct usb_interface *intf;
+ int ret;
+
+ intf = usb_ifnum_to_if(usb_dev, 0);
+
+ ret = usb_find_common_endpoints(intf->cur_altsetting, &epread, &epwrite,
+ NULL, NULL);
+ if (ret) {
+ dev_err(&serial->dev->dev, "Failed to find basic endpoints ret=%d\n", ret);
+ return ret;
+ }
+
+ epstatus = &intf->cur_altsetting->endpoint[2].desc;
+ if (!usb_endpoint_is_bulk_in(epstatus)) {
+ dev_err(&serial->dev->dev, "Missing second bulk in (STATUS/INT)\n");
+ return -ENODEV;
+ }
+
+ epcmd = &intf->cur_altsetting->endpoint[3].desc;
+ if (!usb_endpoint_is_bulk_out(epcmd)) {
+ dev_err(&serial->dev->dev, "Missing second bulk out (CMD)\n");
+ return -ENODEV;
+ }
+
+ ch348_print_version(serial);
+
+ return 0;
+}
+
+static int ch348_calc_num_ports(struct usb_serial *serial,
+ struct usb_serial_endpoints *epds)
+{
+ int i;
+
+ for (i = 1; i < CH348_MAXPORT; ++i) {
+ epds->bulk_out[i] = epds->bulk_out[0];
+ epds->bulk_in[i] = epds->bulk_in[0];
+ }
+
+ epds->num_bulk_out = CH348_MAXPORT;
+ epds->num_bulk_in = CH348_MAXPORT;
+
+ return CH348_MAXPORT;
+}
+
+static int ch348_suspend(struct usb_serial *serial, pm_message_t message)
+{
+ struct ch348 *ch348 = usb_get_serial_data(serial);
+
+ usb_kill_urb(ch348->status_urb);
+
+ return 0;
+}
+
+static int ch348_resume(struct usb_serial *serial)
+{
+ struct ch348 *ch348 = usb_get_serial_data(serial);
+ int ret;
+
+ ret = usb_submit_urb(ch348->status_urb, GFP_KERNEL);
+ if (ret) {
+ dev_err(&ch348->udev->dev,
+ "%s - failed to submit status/interrupt urb %i\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = usb_serial_generic_resume(serial);
+ if (ret)
+ usb_kill_urb(ch348->status_urb);
+
+ return ret;
+}
+
+static const struct usb_device_id ch348_ids[] = {
+ { USB_DEVICE(0x1a86, 0x55d9), },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(usb, ch348_ids);
+
+static struct usb_serial_driver ch348_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "ch348",
+ },
+ .id_table = ch348_ids,
+ .num_ports = CH348_MAXPORT,
+ .num_bulk_in = 1,
+ .num_bulk_out = 1,
+ .open = ch348_open,
+ .set_termios = ch348_set_termios,
+ .process_read_urb = ch348_process_read_urb,
+ .prepare_write_buffer = ch348_prepare_write_buffer,
+ .write = ch348_write,
+ .probe = ch348_probe,
+ .calc_num_ports = ch348_calc_num_ports,
+ .attach = ch348_attach,
+ .release = ch348_release,
+ .suspend = ch348_suspend,
+ .resume = ch348_resume,
+};
+
+static struct usb_serial_driver * const serial_drivers[] = {
+ &ch348_device, NULL
+};
+
+module_usb_serial_driver(serial_drivers, ch348_ids);
+
+MODULE_AUTHOR("Corentin Labbe <clabbe@baylibre.com>");
+MODULE_DESCRIPTION("USB CH348 Octo port serial converter driver");
+MODULE_LICENSE("GPL");

View File

@@ -1559,6 +1559,23 @@
compatible = "ethernet-phy-ieee802.3-c45"; compatible = "ethernet-phy-ieee802.3-c45";
reg = <15>; reg = <15>;
phy-mode = "internal"; phy-mode = "internal";
leds {
#address-cells = <1>;
#size-cells = <0>;
i2p5gbe_led0: i2p5gbe-led0@0 {
reg = <0>;
function = LED_FUNCTION_LAN;
status = "disabled";
};
i2p5gbe_led1: i2p5gbe-led1@1 {
reg = <1>;
function = LED_FUNCTION_LAN;
status = "disabled";
};
};
}; };
}; };
}; };

View File

@@ -1,321 +0,0 @@
// SPDX-License-Identifier: GPL-2.0+
#include <linux/bitfield.h>
#include <linux/firmware.h>
#include <linux/module.h>
#include <linux/nvmem-consumer.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/pinctrl/consumer.h>
#include <linux/phy.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#define MT7988_2P5GE_PMB "mediatek/mt7988/i2p5ge-phy-pmb.bin"
#define MD32_EN BIT(0)
#define PMEM_PRIORITY BIT(8)
#define DMEM_PRIORITY BIT(16)
#define BASE100T_STATUS_EXTEND 0x10
#define BASE1000T_STATUS_EXTEND 0x11
#define EXTEND_CTRL_AND_STATUS 0x16
#define PHY_AUX_CTRL_STATUS 0x1d
#define PHY_AUX_DPX_MASK GENMASK(5, 5)
#define PHY_AUX_SPEED_MASK GENMASK(4, 2)
/* Registers on MDIO_MMD_VEND1 */
#define MTK_PHY_LINK_STATUS_MISC 0xa2
#define MTK_PHY_FDX_ENABLE BIT(5)
#define MTK_PHY_LPI_PCS_DSP_CTRL 0x121
#define MTK_PHY_LPI_SIG_EN_LO_THRESH100_MASK GENMASK(12, 8)
/* Registers on MDIO_MMD_VEND2 */
#define MTK_PHY_LED0_ON_CTRL 0x24
#define MTK_PHY_LED0_ON_LINK1000 BIT(0)
#define MTK_PHY_LED0_ON_LINK100 BIT(1)
#define MTK_PHY_LED0_ON_LINK10 BIT(2)
#define MTK_PHY_LED0_ON_LINK2500 BIT(7)
#define MTK_PHY_LED0_POLARITY BIT(14)
#define MTK_PHY_LED1_ON_CTRL 0x26
#define MTK_PHY_LED1_ON_FDX BIT(4)
#define MTK_PHY_LED1_ON_HDX BIT(5)
#define MTK_PHY_LED1_POLARITY BIT(14)
#define MTK_EXT_PAGE_ACCESS 0x1f
#define MTK_PHY_PAGE_STANDARD 0x0000
#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
struct mtk_i2p5ge_phy_priv {
bool fw_loaded;
};
enum {
PHY_AUX_SPD_10 = 0,
PHY_AUX_SPD_100,
PHY_AUX_SPD_1000,
PHY_AUX_SPD_2500,
};
static int mtk_2p5ge_phy_read_page(struct phy_device *phydev)
{
return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
}
static int mtk_2p5ge_phy_write_page(struct phy_device *phydev, int page)
{
return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
}
static int mt7988_2p5ge_phy_probe(struct phy_device *phydev)
{
struct mtk_i2p5ge_phy_priv *phy_priv;
phy_priv = devm_kzalloc(&phydev->mdio.dev,
sizeof(struct mtk_i2p5ge_phy_priv), GFP_KERNEL);
if (!phy_priv)
return -ENOMEM;
phydev->priv = phy_priv;
return 0;
}
static int mt7988_2p5ge_phy_config_init(struct phy_device *phydev)
{
int ret, i;
const struct firmware *fw;
struct device *dev = &phydev->mdio.dev;
struct device_node *np;
void __iomem *pmb_addr;
void __iomem *md32_en_cfg_base;
struct mtk_i2p5ge_phy_priv *phy_priv = phydev->priv;
u16 reg;
struct pinctrl *pinctrl;
if (!phy_priv->fw_loaded) {
np = of_find_compatible_node(NULL, NULL, "mediatek,2p5gphy-fw");
if (!np)
return -ENOENT;
pmb_addr = of_iomap(np, 0);
if (!pmb_addr)
return -ENOMEM;
md32_en_cfg_base = of_iomap(np, 1);
if (!md32_en_cfg_base)
return -ENOMEM;
ret = request_firmware(&fw, MT7988_2P5GE_PMB, dev);
if (ret) {
dev_err(dev, "failed to load firmware: %s, ret: %d\n",
MT7988_2P5GE_PMB, ret);
return ret;
}
reg = readw(md32_en_cfg_base);
if (reg & MD32_EN) {
phy_set_bits(phydev, 0, BIT(15));
usleep_range(10000, 11000);
}
phy_set_bits(phydev, 0, BIT(11));
/* Write magic number to safely stall MCU */
phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x800e, 0x1100);
phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x800f, 0x00df);
for (i = 0; i < fw->size - 1; i += 4)
writel(*((uint32_t *)(fw->data + i)), pmb_addr + i);
release_firmware(fw);
writew(reg & ~MD32_EN, md32_en_cfg_base);
writew(reg | MD32_EN, md32_en_cfg_base);
phy_set_bits(phydev, 0, BIT(15));
dev_info(dev, "Firmware loading/trigger ok.\n");
phy_priv->fw_loaded = true;
}
/* Setup LED */
/* Set polarity of led0 to active-high for BPI-R4 */
phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL,
MTK_PHY_LED0_POLARITY);
phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL,
MTK_PHY_LED0_ON_LINK10 |
MTK_PHY_LED0_ON_LINK100 |
MTK_PHY_LED0_ON_LINK1000 |
MTK_PHY_LED0_ON_LINK2500);
phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED1_ON_CTRL,
MTK_PHY_LED1_ON_FDX | MTK_PHY_LED1_ON_HDX);
pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "i2p5gbe-led");
if (IS_ERR(pinctrl)) {
dev_err(&phydev->mdio.dev, "Fail to set LED pins!\n");
return PTR_ERR(pinctrl);
}
phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LPI_PCS_DSP_CTRL,
MTK_PHY_LPI_SIG_EN_LO_THRESH100_MASK, 0);
/* Enable 16-bit next page exchange bit if 1000-BT isn't advertizing */
phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
__phy_write(phydev, 0x11, 0xfbfa);
__phy_write(phydev, 0x12, 0xc3);
__phy_write(phydev, 0x10, 0x87f8);
phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
return 0;
}
static int mt7988_2p5ge_phy_config_aneg(struct phy_device *phydev)
{
bool changed = false;
u32 adv;
int ret;
if (phydev->autoneg == AUTONEG_DISABLE) {
/* Configure half duplex with genphy_setup_forced,
* because genphy_c45_pma_setup_forced does not support.
*/
return phydev->duplex != DUPLEX_FULL
? genphy_setup_forced(phydev)
: genphy_c45_pma_setup_forced(phydev);
}
ret = genphy_c45_an_config_aneg(phydev);
if (ret < 0)
return ret;
if (ret > 0)
changed = true;
adv = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising);
ret = phy_modify_changed(phydev, MII_CTRL1000,
ADVERTISE_1000FULL | ADVERTISE_1000HALF,
adv);
if (ret < 0)
return ret;
if (ret > 0)
changed = true;
return genphy_c45_check_and_restart_aneg(phydev, changed);
}
static int mt7988_2p5ge_phy_get_features(struct phy_device *phydev)
{
int ret;
ret = genphy_read_abilities(phydev);
if (ret)
return ret;
/* We don't support HDX at MAC layer on mt7988.
* So mask phy's HDX capabilities, too.
*/
linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
phydev->supported);
linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
phydev->supported);
linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
phydev->supported);
linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
phydev->supported);
linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported);
return 0;
}
static int mt7988_2p5ge_phy_read_status(struct phy_device *phydev)
{
int ret;
ret = genphy_update_link(phydev);
if (ret)
return ret;
phydev->speed = SPEED_UNKNOWN;
phydev->duplex = DUPLEX_UNKNOWN;
phydev->pause = 0;
phydev->asym_pause = 0;
if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) {
ret = genphy_c45_read_lpa(phydev);
if (ret < 0)
return ret;
/* Read the link partner's 1G advertisement */
ret = phy_read(phydev, MII_STAT1000);
if (ret < 0)
return ret;
mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, ret);
} else if (phydev->autoneg == AUTONEG_DISABLE) {
linkmode_zero(phydev->lp_advertising);
}
ret = phy_read(phydev, PHY_AUX_CTRL_STATUS);
if (ret < 0)
return ret;
switch (FIELD_GET(PHY_AUX_SPEED_MASK, ret)) {
case PHY_AUX_SPD_10:
phydev->speed = SPEED_10;
break;
case PHY_AUX_SPD_100:
phydev->speed = SPEED_100;
break;
case PHY_AUX_SPD_1000:
phydev->speed = SPEED_1000;
break;
case PHY_AUX_SPD_2500:
phydev->speed = SPEED_2500;
break;
}
ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LINK_STATUS_MISC);
if (ret < 0)
return ret;
phydev->duplex = (ret & MTK_PHY_FDX_ENABLE) ? DUPLEX_FULL : DUPLEX_HALF;
/* FIXME: The current firmware always enables rate adaptation mode. */
phydev->rate_matching = RATE_MATCH_PAUSE;
return 0;
}
static int mt7988_2p5ge_phy_get_rate_matching(struct phy_device *phydev,
phy_interface_t iface)
{
return RATE_MATCH_PAUSE;
}
static struct phy_driver mtk_gephy_driver[] = {
{
PHY_ID_MATCH_MODEL(0x00339c11),
.name = "MediaTek MT798x 2.5GbE PHY",
.probe = mt7988_2p5ge_phy_probe,
.config_init = mt7988_2p5ge_phy_config_init,
.config_aneg = mt7988_2p5ge_phy_config_aneg,
.get_features = mt7988_2p5ge_phy_get_features,
.read_status = mt7988_2p5ge_phy_read_status,
.get_rate_matching = mt7988_2p5ge_phy_get_rate_matching,
.suspend = genphy_suspend,
.resume = genphy_resume,
.read_page = mtk_2p5ge_phy_read_page,
.write_page = mtk_2p5ge_phy_write_page,
},
};
module_phy_driver(mtk_gephy_driver);
static struct mdio_device_id __maybe_unused mtk_2p5ge_phy_tbl[] = {
{ PHY_ID_MATCH_VENDOR(0x00339c00) },
{ }
};
MODULE_DESCRIPTION("MediaTek 2.5Gb Ethernet PHY driver");
MODULE_AUTHOR("SkyLake Huang <SkyLake.Huang@mediatek.com>");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(mdio, mtk_2p5ge_phy_tbl);
MODULE_FIRMWARE(MT7988_2P5GE_PMB);

View File

@@ -240,7 +240,7 @@ CONFIG_MAXLINEAR_GPHY=y
CONFIG_MDIO_BUS=y CONFIG_MDIO_BUS=y
CONFIG_MDIO_DEVICE=y CONFIG_MDIO_DEVICE=y
CONFIG_MDIO_DEVRES=y CONFIG_MDIO_DEVRES=y
CONFIG_MEDIATEK_2P5G_PHY=y CONFIG_MEDIATEK_2P5GE_PHY=y
CONFIG_MEDIATEK_GE_PHY=y CONFIG_MEDIATEK_GE_PHY=y
CONFIG_MEDIATEK_GE_SOC_PHY=y CONFIG_MEDIATEK_GE_SOC_PHY=y
CONFIG_MEDIATEK_WATCHDOG=y CONFIG_MEDIATEK_WATCHDOG=y

View File

@@ -242,7 +242,7 @@ CONFIG_MAXLINEAR_GPHY=y
CONFIG_MDIO_BUS=y CONFIG_MDIO_BUS=y
CONFIG_MDIO_DEVICE=y CONFIG_MDIO_DEVICE=y
CONFIG_MDIO_DEVRES=y CONFIG_MDIO_DEVRES=y
# CONFIG_MEDIATEK_2P5G_PHY is not set # CONFIG_MEDIATEK_2P5GE_PHY is not set
CONFIG_MEDIATEK_GE_PHY=y CONFIG_MEDIATEK_GE_PHY=y
# CONFIG_MEDIATEK_GE_SOC_PHY is not set # CONFIG_MEDIATEK_GE_SOC_PHY is not set
CONFIG_MEDIATEK_WATCHDOG=y CONFIG_MEDIATEK_WATCHDOG=y

View File

@@ -0,0 +1,62 @@
From 12054d38fc55adbfa2b40299ad8af3449d882ee2 Mon Sep 17 00:00:00 2001
From: "SkyLake.Huang" <skylake.huang@mediatek.com>
Date: Mon, 1 Jul 2024 18:54:06 +0800
Subject: [PATCH 02/13] net: phy: mediatek: Fix spelling errors and rearrange
variables
This patch fixes spelling errors which comes from mediatek-ge-soc.c and
rearrange variables with reverse Xmas tree order.
Signed-off-by: SkyLake.Huang <skylake.huang@mediatek.com>
---
drivers/net/phy/mediatek/mtk-ge-soc.c | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)
--- a/drivers/net/phy/mediatek/mtk-ge-soc.c
+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
@@ -408,16 +408,17 @@ static int tx_offset_cal_efuse(struct ph
static int tx_amp_fill_result(struct phy_device *phydev, u16 *buf)
{
- int i;
- int bias[16] = {};
- const int vals_9461[16] = { 7, 1, 4, 7,
- 7, 1, 4, 7,
- 7, 1, 4, 7,
- 7, 1, 4, 7 };
const int vals_9481[16] = { 10, 6, 6, 10,
10, 6, 6, 10,
10, 6, 6, 10,
10, 6, 6, 10 };
+ const int vals_9461[16] = { 7, 1, 4, 7,
+ 7, 1, 4, 7,
+ 7, 1, 4, 7,
+ 7, 1, 4, 7 };
+ int bias[16] = {};
+ int i;
+
switch (phydev->drv->phy_id) {
case MTK_GPHY_ID_MT7981:
/* We add some calibration to efuse values
@@ -1069,10 +1070,10 @@ static int start_cal(struct phy_device *
static int mt798x_phy_calibration(struct phy_device *phydev)
{
+ struct nvmem_cell *cell;
int ret = 0;
- u32 *buf;
size_t len;
- struct nvmem_cell *cell;
+ u32 *buf;
cell = nvmem_cell_get(&phydev->mdio.dev, "phy-cal-data");
if (IS_ERR(cell)) {
@@ -1415,7 +1416,7 @@ static int mt7988_phy_probe_shared(struc
* LED_C and LED_D respectively. At the same time those pins are used to
* bootstrap configuration of the reference clock source (LED_A),
* DRAM DDRx16b x2/x1 (LED_B) and boot device (LED_C, LED_D).
- * In practise this is done using a LED and a resistor pulling the pin
+ * In practice this is done using a LED and a resistor pulling the pin
* either to GND or to VIO.
* The detected value at boot time is accessible at run-time using the
* TPBANK0 register located in the gpio base of the pinctrl, in order

View File

@@ -0,0 +1,742 @@
From 434e41555c45ec10b19320024163bb009da168bc Mon Sep 17 00:00:00 2001
From: "SkyLake.Huang" <skylake.huang@mediatek.com>
Date: Mon, 1 Jul 2024 18:54:07 +0800
Subject: [PATCH 03/13] net: phy: mediatek: Move LED helper functions into mtk
phy lib
This patch creates mtk-phy-lib.c & mtk-phy.h and integrates mtk-ge-soc.c's
LED helper functions so that we can use those helper functions in other
MTK's ethernet phy driver.
Signed-off-by: SkyLake.Huang <skylake.huang@mediatek.com>
---
drivers/net/phy/mediatek/Kconfig | 5 +
drivers/net/phy/mediatek/Makefile | 1 +
drivers/net/phy/mediatek/mtk-ge-soc.c | 262 +++----------------------
drivers/net/phy/mediatek/mtk-phy-lib.c | 251 +++++++++++++++++++++++
drivers/net/phy/mediatek/mtk.h | 82 ++++++++
6 files changed, 368 insertions(+), 235 deletions(-)
create mode 100644 drivers/net/phy/mediatek/mtk-phy-lib.c
create mode 100644 drivers/net/phy/mediatek/mtk.h
--- a/drivers/net/phy/mediatek/Kconfig
+++ b/drivers/net/phy/mediatek/Kconfig
@@ -1,6 +1,10 @@
# SPDX-License-Identifier: GPL-2.0-only
+config MTK_NET_PHYLIB
+ tristate
+
config MEDIATEK_GE_PHY
tristate "MediaTek Gigabit Ethernet PHYs"
+ select MTK_NET_PHYLIB
help
Supports the MediaTek non-built-in Gigabit Ethernet PHYs.
@@ -13,6 +17,7 @@ config MEDIATEK_GE_SOC_PHY
tristate "MediaTek SoC Ethernet PHYs"
depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
select NVMEM_MTK_EFUSE
+ select MTK_NET_PHYLIB
help
Supports MediaTek SoC built-in Gigabit Ethernet PHYs.
--- a/drivers/net/phy/mediatek/Makefile
+++ b/drivers/net/phy/mediatek/Makefile
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_MTK_NET_PHYLIB) += mtk-phy-lib.o
obj-$(CONFIG_MEDIATEK_GE_PHY) += mtk-ge.o
obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mtk-ge-soc.o
--- a/drivers/net/phy/mediatek/mtk-ge-soc.c
+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
@@ -8,6 +8,8 @@
#include <linux/phy.h>
#include <linux/regmap.h>
+#include "mtk.h"
+
#define MTK_GPHY_ID_MT7981 0x03a29461
#define MTK_GPHY_ID_MT7988 0x03a29481
@@ -210,41 +212,6 @@
#define MTK_PHY_DA_TX_R50_PAIR_D 0x540
/* Registers on MDIO_MMD_VEND2 */
-#define MTK_PHY_LED0_ON_CTRL 0x24
-#define MTK_PHY_LED1_ON_CTRL 0x26
-#define MTK_PHY_LED_ON_MASK GENMASK(6, 0)
-#define MTK_PHY_LED_ON_LINK1000 BIT(0)
-#define MTK_PHY_LED_ON_LINK100 BIT(1)
-#define MTK_PHY_LED_ON_LINK10 BIT(2)
-#define MTK_PHY_LED_ON_LINK (MTK_PHY_LED_ON_LINK10 |\
- MTK_PHY_LED_ON_LINK100 |\
- MTK_PHY_LED_ON_LINK1000)
-#define MTK_PHY_LED_ON_LINKDOWN BIT(3)
-#define MTK_PHY_LED_ON_FDX BIT(4) /* Full duplex */
-#define MTK_PHY_LED_ON_HDX BIT(5) /* Half duplex */
-#define MTK_PHY_LED_ON_FORCE_ON BIT(6)
-#define MTK_PHY_LED_ON_POLARITY BIT(14)
-#define MTK_PHY_LED_ON_ENABLE BIT(15)
-
-#define MTK_PHY_LED0_BLINK_CTRL 0x25
-#define MTK_PHY_LED1_BLINK_CTRL 0x27
-#define MTK_PHY_LED_BLINK_1000TX BIT(0)
-#define MTK_PHY_LED_BLINK_1000RX BIT(1)
-#define MTK_PHY_LED_BLINK_100TX BIT(2)
-#define MTK_PHY_LED_BLINK_100RX BIT(3)
-#define MTK_PHY_LED_BLINK_10TX BIT(4)
-#define MTK_PHY_LED_BLINK_10RX BIT(5)
-#define MTK_PHY_LED_BLINK_RX (MTK_PHY_LED_BLINK_10RX |\
- MTK_PHY_LED_BLINK_100RX |\
- MTK_PHY_LED_BLINK_1000RX)
-#define MTK_PHY_LED_BLINK_TX (MTK_PHY_LED_BLINK_10TX |\
- MTK_PHY_LED_BLINK_100TX |\
- MTK_PHY_LED_BLINK_1000TX)
-#define MTK_PHY_LED_BLINK_COLLISION BIT(6)
-#define MTK_PHY_LED_BLINK_RX_CRC_ERR BIT(7)
-#define MTK_PHY_LED_BLINK_RX_IDLE_ERR BIT(8)
-#define MTK_PHY_LED_BLINK_FORCE_BLINK BIT(9)
-
#define MTK_PHY_LED1_DEFAULT_POLARITIES BIT(1)
#define MTK_PHY_RG_BG_RASEL 0x115
@@ -299,10 +266,6 @@ enum CAL_MODE {
SW_M
};
-#define MTK_PHY_LED_STATE_FORCE_ON 0
-#define MTK_PHY_LED_STATE_FORCE_BLINK 1
-#define MTK_PHY_LED_STATE_NETDEV 2
-
struct mtk_socphy_priv {
unsigned long led_state;
};
@@ -1131,84 +1094,39 @@ static int mt798x_phy_config_init(struct
return mt798x_phy_calibration(phydev);
}
-static int mt798x_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
- bool on)
-{
- unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
- struct mtk_socphy_priv *priv = phydev->priv;
- bool changed;
-
- if (on)
- changed = !test_and_set_bit(bit_on, &priv->led_state);
- else
- changed = !!test_and_clear_bit(bit_on, &priv->led_state);
-
- changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
- (index ? 16 : 0), &priv->led_state);
- if (changed)
- return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
- MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
- MTK_PHY_LED_ON_MASK,
- on ? MTK_PHY_LED_ON_FORCE_ON : 0);
- else
- return 0;
-}
-
-static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
- bool blinking)
-{
- unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + (index ? 16 : 0);
- struct mtk_socphy_priv *priv = phydev->priv;
- bool changed;
-
- if (blinking)
- changed = !test_and_set_bit(bit_blink, &priv->led_state);
- else
- changed = !!test_and_clear_bit(bit_blink, &priv->led_state);
-
- changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
- (index ? 16 : 0), &priv->led_state);
- if (changed)
- return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
- MTK_PHY_LED1_BLINK_CTRL : MTK_PHY_LED0_BLINK_CTRL,
- blinking ? MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
- else
- return 0;
-}
-
static int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index,
unsigned long *delay_on,
unsigned long *delay_off)
{
+ struct mtk_socphy_priv *priv = phydev->priv;
bool blinking = false;
int err = 0;
- if (index > 1)
- return -EINVAL;
-
- if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
- blinking = true;
- *delay_on = 50;
- *delay_off = 50;
- }
+ err = mtk_phy_led_num_dly_cfg(index, delay_on, delay_off, &blinking);
+ if (err < 0)
+ return err;
- err = mt798x_phy_hw_led_blink_set(phydev, index, blinking);
+ err = mtk_phy_hw_led_blink_set(phydev, index, &priv->led_state,
+ blinking);
if (err)
return err;
- return mt798x_phy_hw_led_on_set(phydev, index, false);
+ return mtk_phy_hw_led_on_set(phydev, index, &priv->led_state,
+ MTK_GPHY_LED_ON_MASK, false);
}
static int mt798x_phy_led_brightness_set(struct phy_device *phydev,
u8 index, enum led_brightness value)
{
+ struct mtk_socphy_priv *priv = phydev->priv;
int err;
- err = mt798x_phy_hw_led_blink_set(phydev, index, false);
+ err = mtk_phy_hw_led_blink_set(phydev, index, &priv->led_state, false);
if (err)
return err;
- return mt798x_phy_hw_led_on_set(phydev, index, (value != LED_OFF));
+ return mtk_phy_hw_led_on_set(phydev, index, &priv->led_state,
+ MTK_GPHY_LED_ON_MASK, (value != LED_OFF));
}
static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
@@ -1223,148 +1141,30 @@ static const unsigned long supported_tri
static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
unsigned long rules)
{
- if (index > 1)
- return -EINVAL;
-
- /* All combinations of the supported triggers are allowed */
- if (rules & ~supported_triggers)
- return -EOPNOTSUPP;
-
- return 0;
-};
+ return mtk_phy_led_hw_is_supported(phydev, index, rules,
+ supported_triggers);
+}
static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
unsigned long *rules)
{
- unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + (index ? 16 : 0);
- unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
- unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
struct mtk_socphy_priv *priv = phydev->priv;
- int on, blink;
-
- if (index > 1)
- return -EINVAL;
-
- on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
- index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
-
- if (on < 0)
- return -EIO;
-
- blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
- index ? MTK_PHY_LED1_BLINK_CTRL :
- MTK_PHY_LED0_BLINK_CTRL);
- if (blink < 0)
- return -EIO;
-
- if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX |
- MTK_PHY_LED_ON_LINKDOWN)) ||
- (blink & (MTK_PHY_LED_BLINK_RX | MTK_PHY_LED_BLINK_TX)))
- set_bit(bit_netdev, &priv->led_state);
- else
- clear_bit(bit_netdev, &priv->led_state);
-
- if (on & MTK_PHY_LED_ON_FORCE_ON)
- set_bit(bit_on, &priv->led_state);
- else
- clear_bit(bit_on, &priv->led_state);
-
- if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
- set_bit(bit_blink, &priv->led_state);
- else
- clear_bit(bit_blink, &priv->led_state);
-
- if (!rules)
- return 0;
-
- if (on & MTK_PHY_LED_ON_LINK)
- *rules |= BIT(TRIGGER_NETDEV_LINK);
- if (on & MTK_PHY_LED_ON_LINK10)
- *rules |= BIT(TRIGGER_NETDEV_LINK_10);
-
- if (on & MTK_PHY_LED_ON_LINK100)
- *rules |= BIT(TRIGGER_NETDEV_LINK_100);
-
- if (on & MTK_PHY_LED_ON_LINK1000)
- *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
-
- if (on & MTK_PHY_LED_ON_FDX)
- *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
-
- if (on & MTK_PHY_LED_ON_HDX)
- *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
-
- if (blink & MTK_PHY_LED_BLINK_RX)
- *rules |= BIT(TRIGGER_NETDEV_RX);
-
- if (blink & MTK_PHY_LED_BLINK_TX)
- *rules |= BIT(TRIGGER_NETDEV_TX);
-
- return 0;
+ return mtk_phy_led_hw_ctrl_get(phydev, index, rules, &priv->led_state,
+ MTK_GPHY_LED_ON_SET,
+ MTK_GPHY_LED_RX_BLINK_SET,
+ MTK_GPHY_LED_TX_BLINK_SET);
};
static int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
unsigned long rules)
{
- unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
struct mtk_socphy_priv *priv = phydev->priv;
- u16 on = 0, blink = 0;
- int ret;
- if (index > 1)
- return -EINVAL;
-
- if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
- on |= MTK_PHY_LED_ON_FDX;
-
- if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
- on |= MTK_PHY_LED_ON_HDX;
-
- if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
- on |= MTK_PHY_LED_ON_LINK10;
-
- if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
- on |= MTK_PHY_LED_ON_LINK100;
-
- if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
- on |= MTK_PHY_LED_ON_LINK1000;
-
- if (rules & BIT(TRIGGER_NETDEV_RX)) {
- blink |= (on & MTK_PHY_LED_ON_LINK) ?
- (((on & MTK_PHY_LED_ON_LINK10) ? MTK_PHY_LED_BLINK_10RX : 0) |
- ((on & MTK_PHY_LED_ON_LINK100) ? MTK_PHY_LED_BLINK_100RX : 0) |
- ((on & MTK_PHY_LED_ON_LINK1000) ? MTK_PHY_LED_BLINK_1000RX : 0)) :
- MTK_PHY_LED_BLINK_RX;
- }
-
- if (rules & BIT(TRIGGER_NETDEV_TX)) {
- blink |= (on & MTK_PHY_LED_ON_LINK) ?
- (((on & MTK_PHY_LED_ON_LINK10) ? MTK_PHY_LED_BLINK_10TX : 0) |
- ((on & MTK_PHY_LED_ON_LINK100) ? MTK_PHY_LED_BLINK_100TX : 0) |
- ((on & MTK_PHY_LED_ON_LINK1000) ? MTK_PHY_LED_BLINK_1000TX : 0)) :
- MTK_PHY_LED_BLINK_TX;
- }
-
- if (blink || on)
- set_bit(bit_netdev, &priv->led_state);
- else
- clear_bit(bit_netdev, &priv->led_state);
-
- ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
- MTK_PHY_LED1_ON_CTRL :
- MTK_PHY_LED0_ON_CTRL,
- MTK_PHY_LED_ON_FDX |
- MTK_PHY_LED_ON_HDX |
- MTK_PHY_LED_ON_LINK,
- on);
-
- if (ret)
- return ret;
-
- return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
- MTK_PHY_LED1_BLINK_CTRL :
- MTK_PHY_LED0_BLINK_CTRL, blink);
+ return mtk_phy_led_hw_ctrl_set(phydev, index, rules, &priv->led_state,
+ MTK_GPHY_LED_ON_SET,
+ MTK_GPHY_LED_RX_BLINK_SET,
+ MTK_GPHY_LED_TX_BLINK_SET);
};
static bool mt7988_phy_led_get_polarity(struct phy_device *phydev, int led_num)
@@ -1438,14 +1238,6 @@ static int mt7988_phy_probe_shared(struc
return 0;
}
-static void mt798x_phy_leds_state_init(struct phy_device *phydev)
-{
- int i;
-
- for (i = 0; i < 2; ++i)
- mt798x_phy_led_hw_control_get(phydev, i, NULL);
-}
-
static int mt7988_phy_probe(struct phy_device *phydev)
{
struct mtk_socphy_shared *shared;
@@ -1471,7 +1263,7 @@ static int mt7988_phy_probe(struct phy_d
phydev->priv = priv;
- mt798x_phy_leds_state_init(phydev);
+ mtk_phy_leds_state_init(phydev);
err = mt7988_phy_fix_leds_polarities(phydev);
if (err)
@@ -1498,7 +1290,7 @@ static int mt7981_phy_probe(struct phy_d
phydev->priv = priv;
- mt798x_phy_leds_state_init(phydev);
+ mtk_phy_leds_state_init(phydev);
return mt798x_phy_calibration(phydev);
}
--- /dev/null
+++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
@@ -0,0 +1,251 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/phy.h>
+#include <linux/module.h>
+
+#include <linux/netdevice.h>
+
+#include "mtk.h"
+
+int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
+ unsigned long rules,
+ unsigned long supported_triggers)
+{
+ if (index > 1)
+ return -EINVAL;
+
+ /* All combinations of the supported triggers are allowed */
+ if (rules & ~supported_triggers)
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_phy_led_hw_is_supported);
+
+int mtk_phy_led_hw_ctrl_get(struct phy_device *phydev, u8 index,
+ unsigned long *rules, unsigned long *led_state,
+ u16 on_set, u16 rx_blink_set, u16 tx_blink_set)
+{
+ unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
+ (index ? 16 : 0);
+ unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
+ unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
+ int on, blink;
+
+ if (index > 1)
+ return -EINVAL;
+
+ on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
+ index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
+
+ if (on < 0)
+ return -EIO;
+
+ blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
+ index ? MTK_PHY_LED1_BLINK_CTRL :
+ MTK_PHY_LED0_BLINK_CTRL);
+ if (blink < 0)
+ return -EIO;
+
+ if ((on & (on_set | MTK_PHY_LED_ON_FDX |
+ MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) ||
+ (blink & (rx_blink_set | tx_blink_set)))
+ set_bit(bit_netdev, led_state);
+ else
+ clear_bit(bit_netdev, led_state);
+
+ if (on & MTK_PHY_LED_ON_FORCE_ON)
+ set_bit(bit_on, led_state);
+ else
+ clear_bit(bit_on, led_state);
+
+ if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
+ set_bit(bit_blink, led_state);
+ else
+ clear_bit(bit_blink, led_state);
+
+ if (!rules)
+ return 0;
+
+ if (on & on_set)
+ *rules |= BIT(TRIGGER_NETDEV_LINK);
+
+ if (on & MTK_PHY_LED_ON_LINK10)
+ *rules |= BIT(TRIGGER_NETDEV_LINK_10);
+
+ if (on & MTK_PHY_LED_ON_LINK100)
+ *rules |= BIT(TRIGGER_NETDEV_LINK_100);
+
+ if (on & MTK_PHY_LED_ON_LINK1000)
+ *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
+
+ if (on & MTK_PHY_LED_ON_LINK2500)
+ *rules |= BIT(TRIGGER_NETDEV_LINK_2500);
+
+ if (on & MTK_PHY_LED_ON_FDX)
+ *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
+
+ if (on & MTK_PHY_LED_ON_HDX)
+ *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
+
+ if (blink & rx_blink_set)
+ *rules |= BIT(TRIGGER_NETDEV_RX);
+
+ if (blink & tx_blink_set)
+ *rules |= BIT(TRIGGER_NETDEV_TX);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_phy_led_hw_ctrl_get);
+
+int mtk_phy_led_hw_ctrl_set(struct phy_device *phydev, u8 index,
+ unsigned long rules, unsigned long *led_state,
+ u16 on_set, u16 rx_blink_set, u16 tx_blink_set)
+{
+ unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
+ u16 on = 0, blink = 0;
+ int ret;
+
+ if (index > 1)
+ return -EINVAL;
+
+ if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
+ on |= MTK_PHY_LED_ON_FDX;
+
+ if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
+ on |= MTK_PHY_LED_ON_HDX;
+
+ if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
+ on |= MTK_PHY_LED_ON_LINK10;
+
+ if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
+ on |= MTK_PHY_LED_ON_LINK100;
+
+ if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
+ on |= MTK_PHY_LED_ON_LINK1000;
+
+ if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK)))
+ on |= MTK_PHY_LED_ON_LINK2500;
+
+ if (rules & BIT(TRIGGER_NETDEV_RX)) {
+ blink |= (on & on_set) ?
+ (((on & MTK_PHY_LED_ON_LINK10) ?
+ MTK_PHY_LED_BLINK_10RX : 0) |
+ ((on & MTK_PHY_LED_ON_LINK100) ?
+ MTK_PHY_LED_BLINK_100RX : 0) |
+ ((on & MTK_PHY_LED_ON_LINK1000) ?
+ MTK_PHY_LED_BLINK_1000RX : 0) |
+ ((on & MTK_PHY_LED_ON_LINK2500) ?
+ MTK_PHY_LED_BLINK_2500RX : 0)) :
+ rx_blink_set;
+ }
+
+ if (rules & BIT(TRIGGER_NETDEV_TX)) {
+ blink |= (on & on_set) ?
+ (((on & MTK_PHY_LED_ON_LINK10) ?
+ MTK_PHY_LED_BLINK_10TX : 0) |
+ ((on & MTK_PHY_LED_ON_LINK100) ?
+ MTK_PHY_LED_BLINK_100TX : 0) |
+ ((on & MTK_PHY_LED_ON_LINK1000) ?
+ MTK_PHY_LED_BLINK_1000TX : 0) |
+ ((on & MTK_PHY_LED_ON_LINK2500) ?
+ MTK_PHY_LED_BLINK_2500TX : 0)) :
+ tx_blink_set;
+ }
+
+ if (blink || on)
+ set_bit(bit_netdev, led_state);
+ else
+ clear_bit(bit_netdev, led_state);
+
+ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
+ MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
+ MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX | on_set,
+ on);
+
+ if (ret)
+ return ret;
+
+ return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
+ MTK_PHY_LED1_BLINK_CTRL :
+ MTK_PHY_LED0_BLINK_CTRL, blink);
+}
+EXPORT_SYMBOL_GPL(mtk_phy_led_hw_ctrl_set);
+
+int mtk_phy_led_num_dly_cfg(u8 index, unsigned long *delay_on,
+ unsigned long *delay_off, bool *blinking)
+{
+ if (index > 1)
+ return -EINVAL;
+
+ if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
+ *blinking = true;
+ *delay_on = 50;
+ *delay_off = 50;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_phy_led_num_dly_cfg);
+
+int mtk_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
+ unsigned long *led_state, u16 led_on_mask, bool on)
+{
+ unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
+ bool changed;
+
+ if (on)
+ changed = !test_and_set_bit(bit_on, led_state);
+ else
+ changed = !!test_and_clear_bit(bit_on, led_state);
+
+ changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
+ (index ? 16 : 0), led_state);
+ if (changed)
+ return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
+ MTK_PHY_LED1_ON_CTRL :
+ MTK_PHY_LED0_ON_CTRL,
+ led_on_mask,
+ on ? MTK_PHY_LED_ON_FORCE_ON : 0);
+ else
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_phy_hw_led_on_set);
+
+int mtk_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
+ unsigned long *led_state, bool blinking)
+{
+ unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
+ (index ? 16 : 0);
+ bool changed;
+
+ if (blinking)
+ changed = !test_and_set_bit(bit_blink, led_state);
+ else
+ changed = !!test_and_clear_bit(bit_blink, led_state);
+
+ changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
+ (index ? 16 : 0), led_state);
+ if (changed)
+ return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
+ MTK_PHY_LED1_BLINK_CTRL :
+ MTK_PHY_LED0_BLINK_CTRL,
+ blinking ?
+ MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
+ else
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_phy_hw_led_blink_set);
+
+void mtk_phy_leds_state_init(struct phy_device *phydev)
+{
+ int i;
+
+ for (i = 0; i < 2; ++i)
+ phydev->drv->led_hw_control_get(phydev, i, NULL);
+}
+EXPORT_SYMBOL_GPL(mtk_phy_leds_state_init);
+
+MODULE_DESCRIPTION("MediaTek Ethernet PHY driver common");
+MODULE_AUTHOR("Sky Huang <SkyLake.Huang@mediatek.com>");
+MODULE_AUTHOR("Daniel Golle <daniel@makrotopia.org>");
+MODULE_LICENSE("GPL");
--- /dev/null
+++ b/drivers/net/phy/mediatek/mtk.h
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Common definition for Mediatek Ethernet PHYs
+ * Author: SkyLake Huang <SkyLake.Huang@mediatek.com>
+ * Copyright (c) 2024 MediaTek Inc.
+ */
+
+#ifndef _MTK_EPHY_H_
+#define _MTK_EPHY_H_
+
+#define MTK_EXT_PAGE_ACCESS 0x1f
+
+/* Registers on MDIO_MMD_VEND2 */
+#define MTK_PHY_LED0_ON_CTRL 0x24
+#define MTK_PHY_LED1_ON_CTRL 0x26
+#define MTK_GPHY_LED_ON_MASK GENMASK(6, 0)
+#define MTK_2P5GPHY_LED_ON_MASK GENMASK(7, 0)
+#define MTK_PHY_LED_ON_LINK1000 BIT(0)
+#define MTK_PHY_LED_ON_LINK100 BIT(1)
+#define MTK_PHY_LED_ON_LINK10 BIT(2)
+#define MTK_PHY_LED_ON_LINKDOWN BIT(3)
+#define MTK_PHY_LED_ON_FDX BIT(4) /* Full duplex */
+#define MTK_PHY_LED_ON_HDX BIT(5) /* Half duplex */
+#define MTK_PHY_LED_ON_FORCE_ON BIT(6)
+#define MTK_PHY_LED_ON_LINK2500 BIT(7)
+#define MTK_PHY_LED_ON_POLARITY BIT(14)
+#define MTK_PHY_LED_ON_ENABLE BIT(15)
+
+#define MTK_PHY_LED0_BLINK_CTRL 0x25
+#define MTK_PHY_LED1_BLINK_CTRL 0x27
+#define MTK_PHY_LED_BLINK_1000TX BIT(0)
+#define MTK_PHY_LED_BLINK_1000RX BIT(1)
+#define MTK_PHY_LED_BLINK_100TX BIT(2)
+#define MTK_PHY_LED_BLINK_100RX BIT(3)
+#define MTK_PHY_LED_BLINK_10TX BIT(4)
+#define MTK_PHY_LED_BLINK_10RX BIT(5)
+#define MTK_PHY_LED_BLINK_COLLISION BIT(6)
+#define MTK_PHY_LED_BLINK_RX_CRC_ERR BIT(7)
+#define MTK_PHY_LED_BLINK_RX_IDLE_ERR BIT(8)
+#define MTK_PHY_LED_BLINK_FORCE_BLINK BIT(9)
+#define MTK_PHY_LED_BLINK_2500TX BIT(10)
+#define MTK_PHY_LED_BLINK_2500RX BIT(11)
+
+#define MTK_GPHY_LED_ON_SET (MTK_PHY_LED_ON_LINK1000 | \
+ MTK_PHY_LED_ON_LINK100 | \
+ MTK_PHY_LED_ON_LINK10)
+#define MTK_GPHY_LED_RX_BLINK_SET (MTK_PHY_LED_BLINK_1000RX | \
+ MTK_PHY_LED_BLINK_100RX | \
+ MTK_PHY_LED_BLINK_10RX)
+#define MTK_GPHY_LED_TX_BLINK_SET (MTK_PHY_LED_BLINK_1000RX | \
+ MTK_PHY_LED_BLINK_100RX | \
+ MTK_PHY_LED_BLINK_10RX)
+
+#define MTK_2P5GPHY_LED_ON_SET (MTK_PHY_LED_ON_LINK2500 | \
+ MTK_GPHY_LED_ON_SET)
+#define MTK_2P5GPHY_LED_RX_BLINK_SET (MTK_PHY_LED_BLINK_2500RX | \
+ MTK_GPHY_LED_RX_BLINK_SET)
+#define MTK_2P5GPHY_LED_TX_BLINK_SET (MTK_PHY_LED_BLINK_2500RX | \
+ MTK_GPHY_LED_TX_BLINK_SET)
+
+#define MTK_PHY_LED_STATE_FORCE_ON 0
+#define MTK_PHY_LED_STATE_FORCE_BLINK 1
+#define MTK_PHY_LED_STATE_NETDEV 2
+
+int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
+ unsigned long rules,
+ unsigned long supported_triggers);
+int mtk_phy_led_hw_ctrl_set(struct phy_device *phydev, u8 index,
+ unsigned long rules, unsigned long *led_state,
+ u16 on_set, u16 rx_blink_set, u16 tx_blink_set);
+int mtk_phy_led_hw_ctrl_get(struct phy_device *phydev, u8 index,
+ unsigned long *rules, unsigned long *led_state,
+ u16 on_set, u16 rx_blink_set, u16 tx_blink_set);
+int mtk_phy_led_num_dly_cfg(u8 index, unsigned long *delay_on,
+ unsigned long *delay_off, bool *blinking);
+int mtk_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
+ unsigned long *led_state, u16 led_on_mask, bool on);
+int mtk_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
+ unsigned long *led_state, bool blinking);
+void mtk_phy_leds_state_init(struct phy_device *phydev);
+
+#endif /* _MTK_EPHY_H_ */

View File

@@ -0,0 +1,70 @@
From 2783929879854d5750ba82e2e203663313362abb Mon Sep 17 00:00:00 2001
From: "SkyLake.Huang" <skylake.huang@mediatek.com>
Date: Mon, 1 Jul 2024 18:54:08 +0800
Subject: [PATCH 04/13] net: phy: mediatek: Improve readability of
mtk-phy-lib.c's mtk_phy_led_hw_ctrl_set()
This patch removes parens around TRIGGER_NETDEV_RX/TRIGGER_NETDEV_TX in
mtk_phy_led_hw_ctrl_set(), which improves readability.
Signed-off-by: SkyLake.Huang <skylake.huang@mediatek.com>
---
drivers/net/phy/mediatek/mtk-phy-lib.c | 44 ++++++++++++++------------
1 file changed, 24 insertions(+), 20 deletions(-)
--- a/drivers/net/phy/mediatek/mtk-phy-lib.c
+++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
@@ -127,29 +127,33 @@ int mtk_phy_led_hw_ctrl_set(struct phy_d
on |= MTK_PHY_LED_ON_LINK2500;
if (rules & BIT(TRIGGER_NETDEV_RX)) {
- blink |= (on & on_set) ?
- (((on & MTK_PHY_LED_ON_LINK10) ?
- MTK_PHY_LED_BLINK_10RX : 0) |
- ((on & MTK_PHY_LED_ON_LINK100) ?
- MTK_PHY_LED_BLINK_100RX : 0) |
- ((on & MTK_PHY_LED_ON_LINK1000) ?
- MTK_PHY_LED_BLINK_1000RX : 0) |
- ((on & MTK_PHY_LED_ON_LINK2500) ?
- MTK_PHY_LED_BLINK_2500RX : 0)) :
- rx_blink_set;
+ if (on & on_set) {
+ if (on & MTK_PHY_LED_ON_LINK10)
+ blink |= MTK_PHY_LED_BLINK_10RX;
+ if (on & MTK_PHY_LED_ON_LINK100)
+ blink |= MTK_PHY_LED_BLINK_100RX;
+ if (on & MTK_PHY_LED_ON_LINK1000)
+ blink |= MTK_PHY_LED_BLINK_1000RX;
+ if (on & MTK_PHY_LED_ON_LINK2500)
+ blink |= MTK_PHY_LED_BLINK_2500RX;
+ } else {
+ blink |= rx_blink_set;
+ }
}
if (rules & BIT(TRIGGER_NETDEV_TX)) {
- blink |= (on & on_set) ?
- (((on & MTK_PHY_LED_ON_LINK10) ?
- MTK_PHY_LED_BLINK_10TX : 0) |
- ((on & MTK_PHY_LED_ON_LINK100) ?
- MTK_PHY_LED_BLINK_100TX : 0) |
- ((on & MTK_PHY_LED_ON_LINK1000) ?
- MTK_PHY_LED_BLINK_1000TX : 0) |
- ((on & MTK_PHY_LED_ON_LINK2500) ?
- MTK_PHY_LED_BLINK_2500TX : 0)) :
- tx_blink_set;
+ if (on & on_set) {
+ if (on & MTK_PHY_LED_ON_LINK10)
+ blink |= MTK_PHY_LED_BLINK_10TX;
+ if (on & MTK_PHY_LED_ON_LINK100)
+ blink |= MTK_PHY_LED_BLINK_100TX;
+ if (on & MTK_PHY_LED_ON_LINK1000)
+ blink |= MTK_PHY_LED_BLINK_1000TX;
+ if (on & MTK_PHY_LED_ON_LINK2500)
+ blink |= MTK_PHY_LED_BLINK_2500TX;
+ } else {
+ blink |= tx_blink_set;
+ }
}
if (blink || on)

View File

@@ -0,0 +1,141 @@
From 58c1270423ab48464cdc31ef71ffe7f5b2441961 Mon Sep 17 00:00:00 2001
From: "SkyLake.Huang" <skylake.huang@mediatek.com>
Date: Mon, 1 Jul 2024 18:54:09 +0800
Subject: [PATCH 05/13] net: phy: mediatek: Integrate read/write page helper
functions
This patch integrates read/write page helper functions as MTK phy lib.
They are basically the same in mtk-ge.c & mtk-ge-soc.c.
Signed-off-by: SkyLake.Huang <skylake.huang@mediatek.com>
---
drivers/net/phy/mediatek/mtk-ge-soc.c | 18 ++++--------------
drivers/net/phy/mediatek/mtk-ge.c | 20 ++++++--------------
drivers/net/phy/mediatek/mtk-phy-lib.c | 12 ++++++++++++
drivers/net/phy/mediatek/mtk.h | 3 +++
4 files changed, 25 insertions(+), 28 deletions(-)
--- a/drivers/net/phy/mediatek/mtk-ge-soc.c
+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
@@ -275,16 +275,6 @@ struct mtk_socphy_shared {
struct mtk_socphy_priv priv[4];
};
-static int mtk_socphy_read_page(struct phy_device *phydev)
-{
- return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
-}
-
-static int mtk_socphy_write_page(struct phy_device *phydev, int page)
-{
- return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
-}
-
/* One calibration cycle consists of:
* 1.Set DA_CALIN_FLAG high to start calibration. Keep it high
* until AD_CAL_COMP is ready to output calibration result.
@@ -1305,8 +1295,8 @@ static struct phy_driver mtk_socphy_driv
.probe = mt7981_phy_probe,
.suspend = genphy_suspend,
.resume = genphy_resume,
- .read_page = mtk_socphy_read_page,
- .write_page = mtk_socphy_write_page,
+ .read_page = mtk_phy_read_page,
+ .write_page = mtk_phy_write_page,
.led_blink_set = mt798x_phy_led_blink_set,
.led_brightness_set = mt798x_phy_led_brightness_set,
.led_hw_is_supported = mt798x_phy_led_hw_is_supported,
@@ -1322,8 +1312,8 @@ static struct phy_driver mtk_socphy_driv
.probe = mt7988_phy_probe,
.suspend = genphy_suspend,
.resume = genphy_resume,
- .read_page = mtk_socphy_read_page,
- .write_page = mtk_socphy_write_page,
+ .read_page = mtk_phy_read_page,
+ .write_page = mtk_phy_write_page,
.led_blink_set = mt798x_phy_led_blink_set,
.led_brightness_set = mt798x_phy_led_brightness_set,
.led_hw_is_supported = mt798x_phy_led_hw_is_supported,
--- a/drivers/net/phy/mediatek/mtk-ge.c
+++ b/drivers/net/phy/mediatek/mtk-ge.c
@@ -4,6 +4,8 @@
#include <linux/module.h>
#include <linux/phy.h>
+#include "mtk.h"
+
#define MTK_EXT_PAGE_ACCESS 0x1f
#define MTK_PHY_PAGE_STANDARD 0x0000
#define MTK_PHY_PAGE_EXTENDED 0x0001
@@ -12,16 +14,6 @@
#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
-static int mtk_gephy_read_page(struct phy_device *phydev)
-{
- return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
-}
-
-static int mtk_gephy_write_page(struct phy_device *phydev, int page)
-{
- return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
-}
-
static void mtk_gephy_config_init(struct phy_device *phydev)
{
/* Disable EEE */
@@ -114,8 +106,8 @@ static struct phy_driver mtk_gephy_drive
.handle_interrupt = genphy_handle_interrupt_no_ack,
.suspend = genphy_suspend,
.resume = genphy_resume,
- .read_page = mtk_gephy_read_page,
- .write_page = mtk_gephy_write_page,
+ .read_page = mtk_phy_read_page,
+ .write_page = mtk_phy_write_page,
},
{
PHY_ID_MATCH_EXACT(0x03a29441),
@@ -128,8 +120,8 @@ static struct phy_driver mtk_gephy_drive
.handle_interrupt = genphy_handle_interrupt_no_ack,
.suspend = genphy_suspend,
.resume = genphy_resume,
- .read_page = mtk_gephy_read_page,
- .write_page = mtk_gephy_write_page,
+ .read_page = mtk_phy_read_page,
+ .write_page = mtk_phy_write_page,
},
};
--- a/drivers/net/phy/mediatek/mtk-phy-lib.c
+++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
@@ -6,6 +6,18 @@
#include "mtk.h"
+int mtk_phy_read_page(struct phy_device *phydev)
+{
+ return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
+}
+EXPORT_SYMBOL_GPL(mtk_phy_read_page);
+
+int mtk_phy_write_page(struct phy_device *phydev, int page)
+{
+ return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
+}
+EXPORT_SYMBOL_GPL(mtk_phy_write_page);
+
int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
unsigned long rules,
unsigned long supported_triggers)
--- a/drivers/net/phy/mediatek/mtk.h
+++ b/drivers/net/phy/mediatek/mtk.h
@@ -62,6 +62,9 @@
#define MTK_PHY_LED_STATE_FORCE_BLINK 1
#define MTK_PHY_LED_STATE_NETDEV 2
+int mtk_phy_read_page(struct phy_device *phydev);
+int mtk_phy_write_page(struct phy_device *phydev, int page);
+
int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
unsigned long rules,
unsigned long supported_triggers);

View File

@@ -0,0 +1,146 @@
From 9403f1d54598ae56386a8bf47a5b6b34c884e4f5 Mon Sep 17 00:00:00 2001
From: "SkyLake.Huang" <skylake.huang@mediatek.com>
Date: Mon, 1 Jul 2024 18:54:10 +0800
Subject: [PATCH 06/13] net: phy: mediatek: Hook LED helper functions in
mtk-ge.c
We have mtk-phy-lib.c now so that we can use LED helper functions in
mtk-ge.c(mt7531 part). It also means that mt7531/mt7981/mt7988's
Giga ethernet phys share almost the same HW LED controller design.
Also, add probe function for mt7531 so that it can initialize LED state.
Signed-off-by: SkyLake.Huang <skylake.huang@mediatek.com>
---
drivers/net/phy/mediatek/mtk-ge.c | 100 ++++++++++++++++++++++++++++++
1 file changed, 100 insertions(+)
--- a/drivers/net/phy/mediatek/mtk-ge.c
+++ b/drivers/net/phy/mediatek/mtk-ge.c
@@ -14,6 +14,10 @@
#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
+struct mtk_gephy_priv {
+ unsigned long led_state;
+};
+
static void mtk_gephy_config_init(struct phy_device *phydev)
{
/* Disable EEE */
@@ -94,6 +98,96 @@ static int mt7531_phy_config_init(struct
return 0;
}
+static int mt7531_phy_probe(struct phy_device *phydev)
+{
+ struct mtk_gephy_priv *priv;
+
+ priv = devm_kzalloc(&phydev->mdio.dev, sizeof(struct mtk_gephy_priv),
+ GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ phydev->priv = priv;
+
+ mtk_phy_leds_state_init(phydev);
+
+ return 0;
+}
+
+static int mt753x_phy_led_blink_set(struct phy_device *phydev, u8 index,
+ unsigned long *delay_on,
+ unsigned long *delay_off)
+{
+ struct mtk_gephy_priv *priv = phydev->priv;
+ bool blinking = false;
+ int err = 0;
+
+ err = mtk_phy_led_num_dly_cfg(index, delay_on, delay_off, &blinking);
+ if (err < 0)
+ return err;
+
+ err = mtk_phy_hw_led_blink_set(phydev, index, &priv->led_state,
+ blinking);
+ if (err)
+ return err;
+
+ return mtk_phy_hw_led_on_set(phydev, index, &priv->led_state,
+ MTK_GPHY_LED_ON_MASK, false);
+}
+
+static int mt753x_phy_led_brightness_set(struct phy_device *phydev,
+ u8 index, enum led_brightness value)
+{
+ struct mtk_gephy_priv *priv = phydev->priv;
+ int err;
+
+ err = mtk_phy_hw_led_blink_set(phydev, index, &priv->led_state, false);
+ if (err)
+ return err;
+
+ return mtk_phy_hw_led_on_set(phydev, index, &priv->led_state,
+ MTK_GPHY_LED_ON_MASK, (value != LED_OFF));
+}
+
+static const unsigned long supported_triggers =
+ (BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
+ BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
+ BIT(TRIGGER_NETDEV_LINK) |
+ BIT(TRIGGER_NETDEV_LINK_10) |
+ BIT(TRIGGER_NETDEV_LINK_100) |
+ BIT(TRIGGER_NETDEV_LINK_1000) |
+ BIT(TRIGGER_NETDEV_RX) |
+ BIT(TRIGGER_NETDEV_TX));
+
+static int mt753x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
+ unsigned long rules)
+{
+ return mtk_phy_led_hw_is_supported(phydev, index, rules,
+ supported_triggers);
+}
+
+static int mt753x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
+ unsigned long *rules)
+{
+ struct mtk_gephy_priv *priv = phydev->priv;
+
+ return mtk_phy_led_hw_ctrl_get(phydev, index, rules, &priv->led_state,
+ MTK_GPHY_LED_ON_SET,
+ MTK_GPHY_LED_RX_BLINK_SET,
+ MTK_GPHY_LED_TX_BLINK_SET);
+};
+
+static int mt753x_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
+ unsigned long rules)
+{
+ struct mtk_gephy_priv *priv = phydev->priv;
+
+ return mtk_phy_led_hw_ctrl_set(phydev, index, rules, &priv->led_state,
+ MTK_GPHY_LED_ON_SET,
+ MTK_GPHY_LED_RX_BLINK_SET,
+ MTK_GPHY_LED_TX_BLINK_SET);
+};
+
static struct phy_driver mtk_gephy_driver[] = {
{
PHY_ID_MATCH_EXACT(0x03a29412),
@@ -112,6 +206,7 @@ static struct phy_driver mtk_gephy_drive
{
PHY_ID_MATCH_EXACT(0x03a29441),
.name = "MediaTek MT7531 PHY",
+ .probe = mt7531_phy_probe,
.config_init = mt7531_phy_config_init,
/* Interrupts are handled by the switch, not the PHY
* itself.
@@ -122,6 +217,11 @@ static struct phy_driver mtk_gephy_drive
.resume = genphy_resume,
.read_page = mtk_phy_read_page,
.write_page = mtk_phy_write_page,
+ .led_blink_set = mt753x_phy_led_blink_set,
+ .led_brightness_set = mt753x_phy_led_brightness_set,
+ .led_hw_is_supported = mt753x_phy_led_hw_is_supported,
+ .led_hw_control_set = mt753x_phy_led_hw_control_set,
+ .led_hw_control_get = mt753x_phy_led_hw_control_get,
},
};

View File

@@ -0,0 +1,54 @@
From 51ee83602dbb84716180d9b6e43f6bebb0c2d7bd Mon Sep 17 00:00:00 2001
From: "SkyLake.Huang" <skylake.huang@mediatek.com>
Date: Mon, 1 Jul 2024 18:54:11 +0800
Subject: [PATCH 07/13] net: phy: mediatek: add MT7530 & MT7531's PHY ID macros
This patch adds MT7530 & MT7531's PHY ID macros in mtk-ge.c so that
it follows the same rule of mtk-ge-soc.c.
Signed-off-by: SkyLake.Huang <skylake.huang@mediatek.com>
---
drivers/net/phy/mediatek/mtk-ge.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
--- a/drivers/net/phy/mediatek/mtk-ge.c
+++ b/drivers/net/phy/mediatek/mtk-ge.c
@@ -6,6 +6,9 @@
#include "mtk.h"
+#define MTK_GPHY_ID_MT7530 0x03a29412
+#define MTK_GPHY_ID_MT7531 0x03a29441
+
#define MTK_EXT_PAGE_ACCESS 0x1f
#define MTK_PHY_PAGE_STANDARD 0x0000
#define MTK_PHY_PAGE_EXTENDED 0x0001
@@ -190,7 +193,7 @@ static int mt753x_phy_led_hw_control_set
static struct phy_driver mtk_gephy_driver[] = {
{
- PHY_ID_MATCH_EXACT(0x03a29412),
+ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7530),
.name = "MediaTek MT7530 PHY",
.config_init = mt7530_phy_config_init,
/* Interrupts are handled by the switch, not the PHY
@@ -204,7 +207,7 @@ static struct phy_driver mtk_gephy_drive
.write_page = mtk_phy_write_page,
},
{
- PHY_ID_MATCH_EXACT(0x03a29441),
+ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7531),
.name = "MediaTek MT7531 PHY",
.probe = mt7531_phy_probe,
.config_init = mt7531_phy_config_init,
@@ -228,8 +231,8 @@ static struct phy_driver mtk_gephy_drive
module_phy_driver(mtk_gephy_driver);
static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = {
- { PHY_ID_MATCH_EXACT(0x03a29441) },
- { PHY_ID_MATCH_EXACT(0x03a29412) },
+ { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7530) },
+ { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7531) },
{ }
};

View File

@@ -0,0 +1,182 @@
From e73df692396b0d6bdcb2317299fa1e8e547f3446 Mon Sep 17 00:00:00 2001
From: "SkyLake.Huang" <skylake.huang@mediatek.com>
Date: Mon, 1 Jul 2024 18:54:12 +0800
Subject: [PATCH 08/13] net: phy: mediatek: Change mtk-ge-soc.c line wrapping
This patch shrinks mtk-ge-soc.c line wrapping to 80 characters.
Signed-off-by: SkyLake.Huang <skylake.huang@mediatek.com>
---
drivers/net/phy/mediatek/mtk-ge-soc.c | 67 +++++++++++++++++----------
1 file changed, 42 insertions(+), 25 deletions(-)
--- a/drivers/net/phy/mediatek/mtk-ge-soc.c
+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
@@ -295,7 +295,8 @@ static int cal_cycle(struct phy_device *
ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
MTK_PHY_RG_AD_CAL_CLK, reg_val,
reg_val & MTK_PHY_DA_CAL_CLK, 500,
- ANALOG_INTERNAL_OPERATION_MAX_US, false);
+ ANALOG_INTERNAL_OPERATION_MAX_US,
+ false);
if (ret) {
phydev_err(phydev, "Calibration cycle timeout\n");
return ret;
@@ -304,7 +305,7 @@ static int cal_cycle(struct phy_device *
phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
MTK_PHY_DA_CALIN_FLAG);
ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP) >>
- MTK_PHY_AD_CAL_COMP_OUT_SHIFT;
+ MTK_PHY_AD_CAL_COMP_OUT_SHIFT;
phydev_dbg(phydev, "cal_val: 0x%x, ret: %d\n", cal_val, ret);
return ret;
@@ -394,38 +395,46 @@ static int tx_amp_fill_result(struct phy
}
phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
- MTK_PHY_DA_TX_I2MPB_A_GBE_MASK, (buf[0] + bias[0]) << 10);
+ MTK_PHY_DA_TX_I2MPB_A_GBE_MASK,
+ (buf[0] + bias[0]) << 10);
phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
MTK_PHY_DA_TX_I2MPB_A_TBT_MASK, buf[0] + bias[1]);
phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
- MTK_PHY_DA_TX_I2MPB_A_HBT_MASK, (buf[0] + bias[2]) << 10);
+ MTK_PHY_DA_TX_I2MPB_A_HBT_MASK,
+ (buf[0] + bias[2]) << 10);
phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
MTK_PHY_DA_TX_I2MPB_A_TST_MASK, buf[0] + bias[3]);
phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
- MTK_PHY_DA_TX_I2MPB_B_GBE_MASK, (buf[1] + bias[4]) << 8);
+ MTK_PHY_DA_TX_I2MPB_B_GBE_MASK,
+ (buf[1] + bias[4]) << 8);
phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
MTK_PHY_DA_TX_I2MPB_B_TBT_MASK, buf[1] + bias[5]);
phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
- MTK_PHY_DA_TX_I2MPB_B_HBT_MASK, (buf[1] + bias[6]) << 8);
+ MTK_PHY_DA_TX_I2MPB_B_HBT_MASK,
+ (buf[1] + bias[6]) << 8);
phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
MTK_PHY_DA_TX_I2MPB_B_TST_MASK, buf[1] + bias[7]);
phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
- MTK_PHY_DA_TX_I2MPB_C_GBE_MASK, (buf[2] + bias[8]) << 8);
+ MTK_PHY_DA_TX_I2MPB_C_GBE_MASK,
+ (buf[2] + bias[8]) << 8);
phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
MTK_PHY_DA_TX_I2MPB_C_TBT_MASK, buf[2] + bias[9]);
phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
- MTK_PHY_DA_TX_I2MPB_C_HBT_MASK, (buf[2] + bias[10]) << 8);
+ MTK_PHY_DA_TX_I2MPB_C_HBT_MASK,
+ (buf[2] + bias[10]) << 8);
phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
MTK_PHY_DA_TX_I2MPB_C_TST_MASK, buf[2] + bias[11]);
phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
- MTK_PHY_DA_TX_I2MPB_D_GBE_MASK, (buf[3] + bias[12]) << 8);
+ MTK_PHY_DA_TX_I2MPB_D_GBE_MASK,
+ (buf[3] + bias[12]) << 8);
phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
MTK_PHY_DA_TX_I2MPB_D_TBT_MASK, buf[3] + bias[13]);
phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
- MTK_PHY_DA_TX_I2MPB_D_HBT_MASK, (buf[3] + bias[14]) << 8);
+ MTK_PHY_DA_TX_I2MPB_D_HBT_MASK,
+ (buf[3] + bias[14]) << 8);
phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
MTK_PHY_DA_TX_I2MPB_D_TST_MASK, buf[3] + bias[15]);
@@ -616,7 +625,8 @@ static int tx_vcm_cal_sw(struct phy_devi
goto restore;
/* We calibrate TX-VCM in different logic. Check upper index and then
- * lower index. If this calibration is valid, apply lower index's result.
+ * lower index. If this calibration is valid, apply lower index's
+ * result.
*/
ret = upper_ret - lower_ret;
if (ret == 1) {
@@ -645,7 +655,8 @@ static int tx_vcm_cal_sw(struct phy_devi
} else if (upper_idx == TXRESERVE_MAX && upper_ret == 0 &&
lower_ret == 0) {
ret = 0;
- phydev_warn(phydev, "TX-VCM SW cal result at high margin 0x%x\n",
+ phydev_warn(phydev,
+ "TX-VCM SW cal result at high margin 0x%x\n",
upper_idx);
} else {
ret = -EINVAL;
@@ -749,7 +760,8 @@ static void mt7981_phy_finetune(struct p
/* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */
phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
- MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK,
+ MTK_PHY_TR_OPEN_LOOP_EN_MASK |
+ MTK_PHY_LPF_X_AVERAGE_MASK,
BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9));
/* rg_tr_lpf_cnt_val = 512 */
@@ -818,7 +830,8 @@ static void mt7988_phy_finetune(struct p
/* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */
phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
- MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK,
+ MTK_PHY_TR_OPEN_LOOP_EN_MASK |
+ MTK_PHY_LPF_X_AVERAGE_MASK,
BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0xa));
/* rg_tr_lpf_cnt_val = 1023 */
@@ -930,7 +943,8 @@ static void mt798x_phy_eee(struct phy_de
phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3);
- __phy_modify(phydev, MTK_PHY_LPI_REG_14, MTK_PHY_LPI_WAKE_TIMER_1000_MASK,
+ __phy_modify(phydev, MTK_PHY_LPI_REG_14,
+ MTK_PHY_LPI_WAKE_TIMER_1000_MASK,
FIELD_PREP(MTK_PHY_LPI_WAKE_TIMER_1000_MASK, 0x19c));
__phy_modify(phydev, MTK_PHY_LPI_REG_1c, MTK_PHY_SMI_DET_ON_THRESH_MASK,
@@ -940,7 +954,8 @@ static void mt798x_phy_eee(struct phy_de
phy_modify_mmd(phydev, MDIO_MMD_VEND1,
MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122,
MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
- FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK, 0xff));
+ FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
+ 0xff));
}
static int cal_sw(struct phy_device *phydev, enum CAL_ITEM cal_item,
@@ -1119,14 +1134,15 @@ static int mt798x_phy_led_brightness_set
MTK_GPHY_LED_ON_MASK, (value != LED_OFF));
}
-static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
- BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
- BIT(TRIGGER_NETDEV_LINK) |
- BIT(TRIGGER_NETDEV_LINK_10) |
- BIT(TRIGGER_NETDEV_LINK_100) |
- BIT(TRIGGER_NETDEV_LINK_1000) |
- BIT(TRIGGER_NETDEV_RX) |
- BIT(TRIGGER_NETDEV_TX));
+static const unsigned long supported_triggers =
+ (BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
+ BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
+ BIT(TRIGGER_NETDEV_LINK) |
+ BIT(TRIGGER_NETDEV_LINK_10) |
+ BIT(TRIGGER_NETDEV_LINK_100) |
+ BIT(TRIGGER_NETDEV_LINK_1000) |
+ BIT(TRIGGER_NETDEV_RX) |
+ BIT(TRIGGER_NETDEV_TX));
static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
unsigned long rules)
@@ -1189,7 +1205,8 @@ static int mt7988_phy_fix_leds_polaritie
/* Only now setup pinctrl to avoid bogus blinking */
pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led");
if (IS_ERR(pinctrl))
- dev_err(&phydev->mdio.bus->dev, "Failed to setup PHY LED pinctrl\n");
+ dev_err(&phydev->mdio.bus->dev,
+ "Failed to setup PHY LED pinctrl\n");
return 0;
}

View File

@@ -0,0 +1,614 @@
From 60228de48d8bfde62b4db5945314e6a62079f091 Mon Sep 17 00:00:00 2001
From: "SkyLake.Huang" <skylake.huang@mediatek.com>
Date: Mon, 1 Jul 2024 18:54:13 +0800
Subject: [PATCH 09/13] net: phy: mediatek: Add token ring access helper
functions in mtk-phy-lib
This patch adds TR(token ring) manipulations and adds correct
macro names for those magic numbers. TR is a way to access
proprietary registers on page 52b5. Use these helper functions
so we can see which fields we're going to modify/set/clear.
This patch doesn't really change registers' settings but just
enhances readability and maintainability.
Signed-off-by: SkyLake.Huang <skylake.huang@mediatek.com>
---
drivers/net/phy/mediatek/mtk-ge-soc.c | 297 ++++++++++++++++---------
drivers/net/phy/mediatek/mtk-ge.c | 82 +++++--
drivers/net/phy/mediatek/mtk-phy-lib.c | 91 ++++++++
drivers/net/phy/mediatek/mtk.h | 13 ++
4 files changed, 358 insertions(+), 125 deletions(-)
--- a/drivers/net/phy/mediatek/mtk-ge-soc.c
+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
@@ -24,7 +24,108 @@
#define MTK_PHY_SMI_DET_ON_THRESH_MASK GENMASK(13, 8)
#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
-#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
+
+/* Registers on Token Ring debug nodes */
+/* ch_addr = 0x0, node_addr = 0x7, data_addr = 0x15 */
+/* NormMseLoThresh */
+#define NORMAL_MSE_LO_THRESH_MASK GENMASK(15, 8)
+
+/* ch_addr = 0x0, node_addr = 0xf, data_addr = 0x3c */
+/* RemAckCntLimitCtrl */
+#define REMOTE_ACK_COUNT_LIMIT_CTRL_MASK GENMASK(2, 1)
+
+/* ch_addr = 0x1, node_addr = 0xd, data_addr = 0x20 */
+/* VcoSlicerThreshBitsHigh */
+#define VCO_SLICER_THRESH_HIGH_MASK GENMASK(23, 0)
+
+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x0 */
+/* DfeTailEnableVgaThresh1000 */
+#define DFE_TAIL_EANBLE_VGA_TRHESH_1000 GENMASK(5, 1)
+
+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x1 */
+/* MrvlTrFix100Kp */
+#define MRVL_TR_FIX_100KP_MASK GENMASK(22, 20)
+/* MrvlTrFix100Kf */
+#define MRVL_TR_FIX_100KF_MASK GENMASK(19, 17)
+/* MrvlTrFix1000Kp */
+#define MRVL_TR_FIX_1000KP_MASK GENMASK(16, 14)
+/* MrvlTrFix1000Kf */
+#define MRVL_TR_FIX_1000KF_MASK GENMASK(13, 11)
+
+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x12 */
+/* VgaDecRate */
+#define VGA_DECIMATION_RATE_MASK GENMASK(8, 5)
+
+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x17 */
+/* SlvDSPreadyTime */
+#define SLAVE_DSP_READY_TIME_MASK GENMASK(22, 15)
+/* MasDSPreadyTime */
+#define MASTER_DSP_READY_TIME_MASK GENMASK(14, 7)
+
+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x18 */
+/* EnabRandUpdTrig */
+#define ENABLE_RANDOM_UPDOWN_COUNTER_TRIGGER BIT(8)
+
+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x20 */
+/* ResetSyncOffset */
+#define RESET_SYNC_OFFSET_MASK GENMASK(11, 8)
+
+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x0 */
+/* FfeUpdGainForceVal */
+#define FFE_UPDATE_GAIN_FORCE_VAL_MASK GENMASK(9, 7)
+/* FfeUpdGainForce */
+#define FFE_UPDATE_GAIN_FORCE BIT(6)
+
+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x3 */
+/* TrFreeze */
+#define TR_FREEZE_MASK GENMASK(11, 0)
+
+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x6 */
+/* SS: Steady-state, KP: Proportional Gain */
+/* SSTrKp100 */
+#define SS_TR_KP100_MASK GENMASK(21, 19)
+/* SSTrKf100 */
+#define SS_TR_KF100_MASK GENMASK(18, 16)
+/* SSTrKp1000Mas */
+#define SS_TR_KP1000_MASTER_MASK GENMASK(15, 13)
+/* SSTrKf1000Mas */
+#define SS_TR_KF1000_MASTER_MASK GENMASK(12, 10)
+/* SSTrKp1000Slv */
+#define SS_TR_KP1000_SLAVE_MASK GENMASK(9, 7)
+/* SSTrKf1000Slv */
+#define SS_TR_KF1000_SLAVE_MASK GENMASK(6, 4)
+
+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x8 */
+/* clear this bit if wanna select from AFE */
+/* Regsigdet_sel_1000 */
+#define EEE1000_SELECT_SIGNAL_DETECTION_FROM_DFE BIT(4)
+
+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0xd */
+/* RegEEE_st2TrKf1000 */
+#define EEE1000_STAGE2_TR_KF_MASK GENMASK(13, 11)
+
+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0xf */
+/* RegEEE_slv_waketr_timer_tar */
+#define SLAVE_WAKETR_TIMER_MASK GENMASK(20, 11)
+/* RegEEE_slv_remtx_timer_tar */
+#define SLAVE_REMTX_TIMER_MASK GENMASK(10, 1)
+
+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x10 */
+/* RegEEE_slv_wake_int_timer_tar */
+#define SLAVE_WAKEINT_TIMER_MASK GENMASK(10, 1)
+
+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x14 */
+/* RegEEE_trfreeze_timer2 */
+#define TR_FREEZE_TIMER2_MASK GENMASK(9, 0)
+
+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x1c */
+/* RegEEE100Stg1_tar */
+#define EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK GENMASK(8, 0)
+
+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x25 */
+/* REGEEE_wake_slv_tr_wait_dfesigdet_en */
+#define WAKE_SLAVE_TR_WAIT_DFE_DETECTION_EN BIT(11)
+
#define ANALOG_INTERNAL_OPERATION_MAX_US 20
#define TXRESERVE_MIN 0
@@ -679,40 +780,36 @@ restore:
static void mt798x_phy_common_finetune(struct phy_device *phydev)
{
phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
- /* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */
- __phy_write(phydev, 0x11, 0xc71);
- __phy_write(phydev, 0x12, 0xc);
- __phy_write(phydev, 0x10, 0x8fae);
-
- /* EnabRandUpdTrig = 1 */
- __phy_write(phydev, 0x11, 0x2f00);
- __phy_write(phydev, 0x12, 0xe);
- __phy_write(phydev, 0x10, 0x8fb0);
-
- /* NormMseLoThresh = 85 */
- __phy_write(phydev, 0x11, 0x55a0);
- __phy_write(phydev, 0x12, 0x0);
- __phy_write(phydev, 0x10, 0x83aa);
-
- /* FfeUpdGainForce = 1(Enable), FfeUpdGainForceVal = 4 */
- __phy_write(phydev, 0x11, 0x240);
- __phy_write(phydev, 0x12, 0x0);
- __phy_write(phydev, 0x10, 0x9680);
-
- /* TrFreeze = 0 (mt7988 default) */
- __phy_write(phydev, 0x11, 0x0);
- __phy_write(phydev, 0x12, 0x0);
- __phy_write(phydev, 0x10, 0x9686);
-
- /* SSTrKp100 = 5 */
- /* SSTrKf100 = 6 */
- /* SSTrKp1000Mas = 5 */
- /* SSTrKf1000Mas = 6 */
- /* SSTrKp1000Slv = 5 */
- /* SSTrKf1000Slv = 6 */
- __phy_write(phydev, 0x11, 0xbaef);
- __phy_write(phydev, 0x12, 0x2e);
- __phy_write(phydev, 0x10, 0x968c);
+ __mtk_tr_modify(phydev, 0x1, 0xf, 0x17,
+ SLAVE_DSP_READY_TIME_MASK | MASTER_DSP_READY_TIME_MASK,
+ FIELD_PREP(SLAVE_DSP_READY_TIME_MASK, 0x18) |
+ FIELD_PREP(MASTER_DSP_READY_TIME_MASK, 0x18));
+
+ __mtk_tr_set_bits(phydev, 0x1, 0xf, 0x18,
+ ENABLE_RANDOM_UPDOWN_COUNTER_TRIGGER);
+
+ __mtk_tr_modify(phydev, 0x0, 0x7, 0x15,
+ NORMAL_MSE_LO_THRESH_MASK,
+ FIELD_PREP(NORMAL_MSE_LO_THRESH_MASK, 0x55));
+
+ __mtk_tr_modify(phydev, 0x2, 0xd, 0x0,
+ FFE_UPDATE_GAIN_FORCE_VAL_MASK,
+ FIELD_PREP(FFE_UPDATE_GAIN_FORCE_VAL_MASK, 0x4) |
+ FFE_UPDATE_GAIN_FORCE);
+
+ __mtk_tr_clr_bits(phydev, 0x2, 0xd, 0x3, TR_FREEZE_MASK);
+
+ __mtk_tr_modify(phydev, 0x2, 0xd, 0x6,
+ SS_TR_KP100_MASK | SS_TR_KF100_MASK |
+ SS_TR_KP1000_MASTER_MASK | SS_TR_KF1000_MASTER_MASK |
+ SS_TR_KP1000_SLAVE_MASK | SS_TR_KF1000_SLAVE_MASK,
+ FIELD_PREP(SS_TR_KP100_MASK, 0x5) |
+ FIELD_PREP(SS_TR_KF100_MASK, 0x6) |
+ FIELD_PREP(SS_TR_KP1000_MASTER_MASK, 0x5) |
+ FIELD_PREP(SS_TR_KF1000_MASTER_MASK, 0x6) |
+ FIELD_PREP(SS_TR_KP1000_SLAVE_MASK, 0x5) |
+ FIELD_PREP(SS_TR_KF1000_SLAVE_MASK, 0x6));
+
phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
}
@@ -735,27 +832,29 @@ static void mt7981_phy_finetune(struct p
}
phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
- /* ResetSyncOffset = 6 */
- __phy_write(phydev, 0x11, 0x600);
- __phy_write(phydev, 0x12, 0x0);
- __phy_write(phydev, 0x10, 0x8fc0);
-
- /* VgaDecRate = 1 */
- __phy_write(phydev, 0x11, 0x4c2a);
- __phy_write(phydev, 0x12, 0x3e);
- __phy_write(phydev, 0x10, 0x8fa4);
+ __mtk_tr_modify(phydev, 0x1, 0xf, 0x20,
+ RESET_SYNC_OFFSET_MASK,
+ FIELD_PREP(RESET_SYNC_OFFSET_MASK, 0x6));
+
+ __mtk_tr_modify(phydev, 0x1, 0xf, 0x12,
+ VGA_DECIMATION_RATE_MASK,
+ FIELD_PREP(VGA_DECIMATION_RATE_MASK, 0x1));
/* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2,
* MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2
*/
- __phy_write(phydev, 0x11, 0xd10a);
- __phy_write(phydev, 0x12, 0x34);
- __phy_write(phydev, 0x10, 0x8f82);
+ __mtk_tr_modify(phydev, 0x1, 0xf, 0x1,
+ MRVL_TR_FIX_100KP_MASK | MRVL_TR_FIX_100KF_MASK |
+ MRVL_TR_FIX_1000KP_MASK | MRVL_TR_FIX_1000KF_MASK,
+ FIELD_PREP(MRVL_TR_FIX_100KP_MASK, 0x3) |
+ FIELD_PREP(MRVL_TR_FIX_100KF_MASK, 0x2) |
+ FIELD_PREP(MRVL_TR_FIX_1000KP_MASK, 0x3) |
+ FIELD_PREP(MRVL_TR_FIX_1000KF_MASK, 0x2));
/* VcoSlicerThreshBitsHigh */
- __phy_write(phydev, 0x11, 0x5555);
- __phy_write(phydev, 0x12, 0x55);
- __phy_write(phydev, 0x10, 0x8ec0);
+ __mtk_tr_modify(phydev, 0x1, 0xd, 0x20,
+ VCO_SLICER_THRESH_HIGH_MASK,
+ FIELD_PREP(VCO_SLICER_THRESH_HIGH_MASK, 0x555555));
phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
/* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */
@@ -807,25 +906,23 @@ static void mt7988_phy_finetune(struct p
phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_TX_FILTER, 0x5);
phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
- /* ResetSyncOffset = 5 */
- __phy_write(phydev, 0x11, 0x500);
- __phy_write(phydev, 0x12, 0x0);
- __phy_write(phydev, 0x10, 0x8fc0);
+ __mtk_tr_modify(phydev, 0x1, 0xf, 0x20,
+ RESET_SYNC_OFFSET_MASK,
+ FIELD_PREP(RESET_SYNC_OFFSET_MASK, 0x5));
/* VgaDecRate is 1 at default on mt7988 */
- /* MrvlTrFix100Kp = 6, MrvlTrFix100Kf = 7,
- * MrvlTrFix1000Kp = 6, MrvlTrFix1000Kf = 7
- */
- __phy_write(phydev, 0x11, 0xb90a);
- __phy_write(phydev, 0x12, 0x6f);
- __phy_write(phydev, 0x10, 0x8f82);
-
- /* RemAckCntLimitCtrl = 1 */
- __phy_write(phydev, 0x11, 0xfbba);
- __phy_write(phydev, 0x12, 0xc3);
- __phy_write(phydev, 0x10, 0x87f8);
-
+ __mtk_tr_modify(phydev, 0x1, 0xf, 0x1,
+ MRVL_TR_FIX_100KP_MASK | MRVL_TR_FIX_100KF_MASK |
+ MRVL_TR_FIX_1000KP_MASK | MRVL_TR_FIX_1000KF_MASK,
+ FIELD_PREP(MRVL_TR_FIX_100KP_MASK, 0x6) |
+ FIELD_PREP(MRVL_TR_FIX_100KF_MASK, 0x7) |
+ FIELD_PREP(MRVL_TR_FIX_1000KP_MASK, 0x6) |
+ FIELD_PREP(MRVL_TR_FIX_1000KF_MASK, 0x7));
+
+ __mtk_tr_modify(phydev, 0x0, 0xf, 0x3c,
+ REMOTE_ACK_COUNT_LIMIT_CTRL_MASK,
+ FIELD_PREP(REMOTE_ACK_COUNT_LIMIT_CTRL_MASK, 0x1));
phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
/* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */
@@ -901,45 +998,37 @@ static void mt798x_phy_eee(struct phy_de
MTK_PHY_TR_READY_SKIP_AFE_WAKEUP);
phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
- /* Regsigdet_sel_1000 = 0 */
- __phy_write(phydev, 0x11, 0xb);
- __phy_write(phydev, 0x12, 0x0);
- __phy_write(phydev, 0x10, 0x9690);
-
- /* REG_EEE_st2TrKf1000 = 2 */
- __phy_write(phydev, 0x11, 0x114f);
- __phy_write(phydev, 0x12, 0x2);
- __phy_write(phydev, 0x10, 0x969a);
-
- /* RegEEE_slv_wake_tr_timer_tar = 6, RegEEE_slv_remtx_timer_tar = 20 */
- __phy_write(phydev, 0x11, 0x3028);
- __phy_write(phydev, 0x12, 0x0);
- __phy_write(phydev, 0x10, 0x969e);
-
- /* RegEEE_slv_wake_int_timer_tar = 8 */
- __phy_write(phydev, 0x11, 0x5010);
- __phy_write(phydev, 0x12, 0x0);
- __phy_write(phydev, 0x10, 0x96a0);
-
- /* RegEEE_trfreeze_timer2 = 586 */
- __phy_write(phydev, 0x11, 0x24a);
- __phy_write(phydev, 0x12, 0x0);
- __phy_write(phydev, 0x10, 0x96a8);
-
- /* RegEEE100Stg1_tar = 16 */
- __phy_write(phydev, 0x11, 0x3210);
- __phy_write(phydev, 0x12, 0x0);
- __phy_write(phydev, 0x10, 0x96b8);
-
- /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 0 */
- __phy_write(phydev, 0x11, 0x1463);
- __phy_write(phydev, 0x12, 0x0);
- __phy_write(phydev, 0x10, 0x96ca);
-
- /* DfeTailEnableVgaThresh1000 = 27 */
- __phy_write(phydev, 0x11, 0x36);
- __phy_write(phydev, 0x12, 0x0);
- __phy_write(phydev, 0x10, 0x8f80);
+ __mtk_tr_clr_bits(phydev, 0x2, 0xd, 0x8,
+ EEE1000_SELECT_SIGNAL_DETECTION_FROM_DFE);
+
+ __mtk_tr_modify(phydev, 0x2, 0xd, 0xd,
+ EEE1000_STAGE2_TR_KF_MASK,
+ FIELD_PREP(EEE1000_STAGE2_TR_KF_MASK, 0x2));
+
+ __mtk_tr_modify(phydev, 0x2, 0xd, 0xf,
+ SLAVE_WAKETR_TIMER_MASK | SLAVE_REMTX_TIMER_MASK,
+ FIELD_PREP(SLAVE_WAKETR_TIMER_MASK, 0x6) |
+ FIELD_PREP(SLAVE_REMTX_TIMER_MASK, 0x14));
+
+ __mtk_tr_modify(phydev, 0x2, 0xd, 0x10,
+ SLAVE_WAKEINT_TIMER_MASK,
+ FIELD_PREP(SLAVE_WAKEINT_TIMER_MASK, 0x8));
+
+ __mtk_tr_modify(phydev, 0x2, 0xd, 0x14,
+ TR_FREEZE_TIMER2_MASK,
+ FIELD_PREP(TR_FREEZE_TIMER2_MASK, 0x24a));
+
+ __mtk_tr_modify(phydev, 0x2, 0xd, 0x1c,
+ EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK,
+ FIELD_PREP(EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK,
+ 0x10));
+
+ __mtk_tr_clr_bits(phydev, 0x2, 0xd, 0x25,
+ WAKE_SLAVE_TR_WAIT_DFE_DETECTION_EN);
+
+ __mtk_tr_modify(phydev, 0x1, 0xf, 0x0,
+ DFE_TAIL_EANBLE_VGA_TRHESH_1000,
+ FIELD_PREP(DFE_TAIL_EANBLE_VGA_TRHESH_1000, 0x1b));
phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3);
--- a/drivers/net/phy/mediatek/mtk-ge.c
+++ b/drivers/net/phy/mediatek/mtk-ge.c
@@ -9,13 +9,35 @@
#define MTK_GPHY_ID_MT7530 0x03a29412
#define MTK_GPHY_ID_MT7531 0x03a29441
-#define MTK_EXT_PAGE_ACCESS 0x1f
-#define MTK_PHY_PAGE_STANDARD 0x0000
-#define MTK_PHY_PAGE_EXTENDED 0x0001
-#define MTK_PHY_PAGE_EXTENDED_2 0x0002
-#define MTK_PHY_PAGE_EXTENDED_3 0x0003
-#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
-#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
+#define MTK_PHY_PAGE_EXTENDED_1 0x0001
+#define MTK_PHY_AUX_CTRL_AND_STATUS 0x14
+#define MTK_PHY_ENABLE_DOWNSHIFT BIT(4)
+
+#define MTK_PHY_PAGE_EXTENDED_2 0x0002
+#define MTK_PHY_PAGE_EXTENDED_3 0x0003
+#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG11 0x11
+
+#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
+
+/* Registers on Token Ring debug nodes */
+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x17 */
+#define SLAVE_DSP_READY_TIME_MASK GENMASK(22, 15)
+
+/* Registers on MDIO_MMD_VEND1 */
+#define MTK_PHY_GBE_MODE_TX_DELAY_SEL 0x13
+#define MTK_PHY_TEST_MODE_TX_DELAY_SEL 0x14
+#define MTK_TX_DELAY_PAIR_B_MASK GENMASK(10, 8)
+#define MTK_TX_DELAY_PAIR_D_MASK GENMASK(2, 0)
+
+#define MTK_PHY_MCC_CTRL_AND_TX_POWER_CTRL 0xa6
+#define MTK_MCC_NEARECHO_OFFSET_MASK GENMASK(15, 8)
+
+#define MTK_PHY_RXADC_CTRL_RG7 0xc6
+#define MTK_PHY_DA_AD_BUF_BIAS_LP_MASK GENMASK(9, 8)
+
+#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG123 0x123
+#define MTK_PHY_LPI_NORM_MSE_LO_THRESH100_MASK GENMASK(15, 8)
+#define MTK_PHY_LPI_NORM_MSE_HI_THRESH100_MASK GENMASK(7, 0)
struct mtk_gephy_priv {
unsigned long led_state;
@@ -27,20 +49,29 @@ static void mtk_gephy_config_init(struct
phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0);
/* Enable HW auto downshift */
- phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED, 0x14, 0, BIT(4));
+ phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED_1,
+ MTK_PHY_AUX_CTRL_AND_STATUS,
+ 0, MTK_PHY_ENABLE_DOWNSHIFT);
/* Increase SlvDPSready time */
- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
- __phy_write(phydev, 0x10, 0xafae);
- __phy_write(phydev, 0x12, 0x2f);
- __phy_write(phydev, 0x10, 0x8fae);
- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+ mtk_tr_modify(phydev, 0x1, 0xf, 0x17, SLAVE_DSP_READY_TIME_MASK,
+ FIELD_PREP(SLAVE_DSP_READY_TIME_MASK, 0x5e));
/* Adjust 100_mse_threshold */
- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x123, 0xffff);
-
- /* Disable mcc */
- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xa6, 0x300);
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1,
+ MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG123,
+ MTK_PHY_LPI_NORM_MSE_LO_THRESH100_MASK |
+ MTK_PHY_LPI_NORM_MSE_HI_THRESH100_MASK,
+ FIELD_PREP(MTK_PHY_LPI_NORM_MSE_LO_THRESH100_MASK,
+ 0xff) |
+ FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH100_MASK,
+ 0xff));
+
+ /* If echo time is narrower than 0x3, it will be regarded as noise */
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1,
+ MTK_PHY_MCC_CTRL_AND_TX_POWER_CTRL,
+ MTK_MCC_NEARECHO_OFFSET_MASK,
+ FIELD_PREP(MTK_MCC_NEARECHO_OFFSET_MASK, 0x3));
}
static int mt7530_phy_config_init(struct phy_device *phydev)
@@ -48,7 +79,8 @@ static int mt7530_phy_config_init(struct
mtk_gephy_config_init(phydev);
/* Increase post_update_timer */
- phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3, 0x11, 0x4b);
+ phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3,
+ MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG11, 0x4b);
return 0;
}
@@ -89,11 +121,19 @@ static int mt7531_phy_config_init(struct
/* PHY link down power saving enable */
phy_set_bits(phydev, 0x17, BIT(4));
- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 0xc6, 0x300);
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7,
+ MTK_PHY_DA_AD_BUF_BIAS_LP_MASK,
+ FIELD_PREP(MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3));
/* Set TX Pair delay selection */
- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x13, 0x404);
- phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x14, 0x404);
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_GBE_MODE_TX_DELAY_SEL,
+ MTK_TX_DELAY_PAIR_B_MASK | MTK_TX_DELAY_PAIR_D_MASK,
+ FIELD_PREP(MTK_TX_DELAY_PAIR_B_MASK, 0x4) |
+ FIELD_PREP(MTK_TX_DELAY_PAIR_D_MASK, 0x4));
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TEST_MODE_TX_DELAY_SEL,
+ MTK_TX_DELAY_PAIR_B_MASK | MTK_TX_DELAY_PAIR_D_MASK,
+ FIELD_PREP(MTK_TX_DELAY_PAIR_B_MASK, 0x4) |
+ FIELD_PREP(MTK_TX_DELAY_PAIR_D_MASK, 0x4));
/* LED Config*/
mt7530_led_config_of(phydev);
--- a/drivers/net/phy/mediatek/mtk-phy-lib.c
+++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
@@ -6,6 +6,97 @@
#include "mtk.h"
+/* Difference between functions with mtk_tr* and __mtk_tr* prefixes is
+ * mtk_tr* functions: wrapped by page switching operations
+ * __mtk_tr* functions: no page switching operations
+ */
+
+static void __mtk_tr_access(struct phy_device *phydev, bool read, u8 ch_addr,
+ u8 node_addr, u8 data_addr)
+{
+ u16 tr_cmd = BIT(15); /* bit 14 & 0 are reserved */
+
+ if (read)
+ tr_cmd |= BIT(13);
+
+ tr_cmd |= (((ch_addr & 0x3) << 11) |
+ ((node_addr & 0xf) << 7) |
+ ((data_addr & 0x3f) << 1));
+ dev_dbg(&phydev->mdio.dev, "tr_cmd: 0x%x\n", tr_cmd);
+ __phy_write(phydev, 0x10, tr_cmd);
+}
+
+static void __mtk_tr_read(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
+ u8 data_addr, u16 *tr_high, u16 *tr_low)
+{
+ __mtk_tr_access(phydev, true, ch_addr, node_addr, data_addr);
+ *tr_low = __phy_read(phydev, 0x11);
+ *tr_high = __phy_read(phydev, 0x12);
+ dev_dbg(&phydev->mdio.dev, "tr_high read: 0x%x, tr_low read: 0x%x\n",
+ *tr_high, *tr_low);
+}
+
+u32 mtk_tr_read(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
+ u8 data_addr)
+{
+ u16 tr_high;
+ u16 tr_low;
+
+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+ __mtk_tr_read(phydev, ch_addr, node_addr, data_addr, &tr_high, &tr_low);
+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+
+ return (tr_high << 16) | tr_low;
+}
+EXPORT_SYMBOL_GPL(mtk_tr_read);
+
+static void __mtk_tr_write(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
+ u8 data_addr, u32 tr_data)
+{
+ __phy_write(phydev, 0x11, tr_data & 0xffff);
+ __phy_write(phydev, 0x12, tr_data >> 16);
+ dev_dbg(&phydev->mdio.dev, "tr_high write: 0x%x, tr_low write: 0x%x\n",
+ tr_data >> 16, tr_data & 0xffff);
+ __mtk_tr_access(phydev, false, ch_addr, node_addr, data_addr);
+}
+
+void __mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
+ u8 data_addr, u32 mask, u32 set)
+{
+ u32 tr_data;
+ u16 tr_high;
+ u16 tr_low;
+
+ __mtk_tr_read(phydev, ch_addr, node_addr, data_addr, &tr_high, &tr_low);
+ tr_data = (tr_high << 16) | tr_low;
+ tr_data = (tr_data & ~mask) | set;
+ __mtk_tr_write(phydev, ch_addr, node_addr, data_addr, tr_data);
+}
+EXPORT_SYMBOL_GPL(__mtk_tr_modify);
+
+void mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
+ u8 data_addr, u32 mask, u32 set)
+{
+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+ __mtk_tr_modify(phydev, ch_addr, node_addr, data_addr, mask, set);
+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+}
+EXPORT_SYMBOL_GPL(mtk_tr_modify);
+
+void __mtk_tr_set_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
+ u8 data_addr, u32 set)
+{
+ __mtk_tr_modify(phydev, ch_addr, node_addr, data_addr, 0, set);
+}
+EXPORT_SYMBOL_GPL(__mtk_tr_set_bits);
+
+void __mtk_tr_clr_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
+ u8 data_addr, u32 clr)
+{
+ __mtk_tr_modify(phydev, ch_addr, node_addr, data_addr, clr, 0);
+}
+EXPORT_SYMBOL_GPL(__mtk_tr_clr_bits);
+
int mtk_phy_read_page(struct phy_device *phydev)
{
return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
--- a/drivers/net/phy/mediatek/mtk.h
+++ b/drivers/net/phy/mediatek/mtk.h
@@ -9,6 +9,8 @@
#define _MTK_EPHY_H_
#define MTK_EXT_PAGE_ACCESS 0x1f
+#define MTK_PHY_PAGE_STANDARD 0x0000
+#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
/* Registers on MDIO_MMD_VEND2 */
#define MTK_PHY_LED0_ON_CTRL 0x24
@@ -62,6 +64,17 @@
#define MTK_PHY_LED_STATE_FORCE_BLINK 1
#define MTK_PHY_LED_STATE_NETDEV 2
+u32 mtk_tr_read(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
+ u8 data_addr);
+void __mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
+ u8 data_addr, u32 mask, u32 set);
+void mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
+ u8 data_addr, u32 mask, u32 set);
+void __mtk_tr_set_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
+ u8 data_addr, u32 set);
+void __mtk_tr_clr_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
+ u8 data_addr, u32 clr);
+
int mtk_phy_read_page(struct phy_device *phydev);
int mtk_phy_write_page(struct phy_device *phydev, int page);

View File

@@ -0,0 +1,209 @@
From 3c05195fc2c232cd853fc8cebf55310c4605111d Mon Sep 17 00:00:00 2001
From: "SkyLake.Huang" <skylake.huang@mediatek.com>
Date: Mon, 1 Jul 2024 18:54:14 +0800
Subject: [PATCH 10/13] net: phy: mediatek: Extend 1G TX/RX link pulse time
We observe that some 10G devices' (mostly Marvell's chips inside) 1G
training time violates specification, which may last 2230ms and affect
later TX/RX link pulse time. This will invalidate MediaTek series
gigabit Ethernet PHYs' hardware auto downshift mechanism.
Without this patch, if someone is trying to use "4-wire" cable to
connect above devices, MediaTek' gigabit Ethernet PHYs may fail
to downshift to 100Mbps. (If partner 10G devices' downshift mechanism
stops at 1G)
This patch extends our 1G TX/RX link pulse time so that we can still
link up with those 10G devices.
Tested device:
- Netgear GS110EMX's 10G port (Marvell 88X3340P)
- QNAP QSW-M408-4C
Signed-off-by: SkyLake.Huang <skylake.huang@mediatek.com>
---
drivers/net/phy/mediatek/mtk-ge-soc.c | 2 +
drivers/net/phy/mediatek/mtk-ge.c | 5 +-
drivers/net/phy/mediatek/mtk-phy-lib.c | 92 ++++++++++++++++++++++++++
drivers/net/phy/mediatek/mtk.h | 21 ++++++
4 files changed, 116 insertions(+), 4 deletions(-)
--- a/drivers/net/phy/mediatek/mtk-ge-soc.c
+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
@@ -1396,6 +1396,7 @@ static struct phy_driver mtk_socphy_driv
PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981),
.name = "MediaTek MT7981 PHY",
.config_init = mt798x_phy_config_init,
+ .read_status = mtk_gphy_cl22_read_status,
.config_intr = genphy_no_config_intr,
.handle_interrupt = genphy_handle_interrupt_no_ack,
.probe = mt7981_phy_probe,
@@ -1413,6 +1414,7 @@ static struct phy_driver mtk_socphy_driv
PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988),
.name = "MediaTek MT7988 PHY",
.config_init = mt798x_phy_config_init,
+ .read_status = mtk_gphy_cl22_read_status,
.config_intr = genphy_no_config_intr,
.handle_interrupt = genphy_handle_interrupt_no_ack,
.probe = mt7988_phy_probe,
--- a/drivers/net/phy/mediatek/mtk-ge.c
+++ b/drivers/net/phy/mediatek/mtk-ge.c
@@ -9,10 +9,6 @@
#define MTK_GPHY_ID_MT7530 0x03a29412
#define MTK_GPHY_ID_MT7531 0x03a29441
-#define MTK_PHY_PAGE_EXTENDED_1 0x0001
-#define MTK_PHY_AUX_CTRL_AND_STATUS 0x14
-#define MTK_PHY_ENABLE_DOWNSHIFT BIT(4)
-
#define MTK_PHY_PAGE_EXTENDED_2 0x0002
#define MTK_PHY_PAGE_EXTENDED_3 0x0003
#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG11 0x11
@@ -251,6 +247,7 @@ static struct phy_driver mtk_gephy_drive
.name = "MediaTek MT7531 PHY",
.probe = mt7531_phy_probe,
.config_init = mt7531_phy_config_init,
+ .read_status = mtk_gphy_cl22_read_status,
/* Interrupts are handled by the switch, not the PHY
* itself.
*/
--- a/drivers/net/phy/mediatek/mtk-phy-lib.c
+++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
@@ -109,6 +109,98 @@ int mtk_phy_write_page(struct phy_device
}
EXPORT_SYMBOL_GPL(mtk_phy_write_page);
+/* This function deals with the case that 1G AN starts but isn't completed. We
+ * set AN_NEW_LP_CNT_LIMIT with different values time after time to let our
+ * 1G->100Mbps hardware automatic downshift to fit more partner devices.
+ */
+static int extend_an_new_lp_cnt_limit(struct phy_device *phydev)
+{
+ int mmd_read_ret;
+ u32 reg_val;
+ int timeout;
+
+ /* According to table 28-9 & Figure 28-18 in IEEE 802.3,
+ * link_fail_inhibit_timer of 10/100/1000 Mbps devices ranges from 750
+ * to "1000ms". Once MTK_PHY_FINAL_SPEED_1000 is set, it means that we
+ * enter "FLP LINK GOOD CHECK" state, link_fail_inhibit_timer starts and
+ * this PHY's 1G training starts. If 1G training never starts, we do
+ * nothing but leave.
+ */
+ timeout = read_poll_timeout(mmd_read_ret = phy_read_mmd, reg_val,
+ (mmd_read_ret < 0) ||
+ reg_val & MTK_PHY_FINAL_SPEED_1000,
+ 10000, 1000000, false, phydev,
+ MDIO_MMD_VEND1, MTK_PHY_LINK_STATUS_MISC);
+ if (mmd_read_ret < 0)
+ return mmd_read_ret;
+
+ if (!timeout) {
+ /* Once we found MTK_PHY_FINAL_SPEED_1000 is set, no matter 1G
+ * AN is completed or not, we'll set AN_NEW_LP_CNT_LIMIT again
+ * and again.
+ */
+ mtk_tr_modify(phydev, 0x0, 0xf, 0x3c, AN_NEW_LP_CNT_LIMIT_MASK,
+ FIELD_PREP(AN_NEW_LP_CNT_LIMIT_MASK, 0xf));
+ mdelay(1500);
+
+ timeout = read_poll_timeout(mtk_tr_read, reg_val,
+ (reg_val & AN_STATE_MASK) !=
+ (AN_STATE_TX_DISABLE <<
+ AN_STATE_SHIFT),
+ 10000, 1000000, false, phydev,
+ 0x0, 0xf, 0x2);
+ if (!timeout) {
+ mdelay(625);
+ mtk_tr_modify(phydev, 0x0, 0xf, 0x3c,
+ AN_NEW_LP_CNT_LIMIT_MASK,
+ FIELD_PREP(AN_NEW_LP_CNT_LIMIT_MASK,
+ 0x8));
+ mdelay(500);
+ mtk_tr_modify(phydev, 0x0, 0xf, 0x3c,
+ AN_NEW_LP_CNT_LIMIT_MASK,
+ FIELD_PREP(AN_NEW_LP_CNT_LIMIT_MASK,
+ 0xf));
+ } else {
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+int mtk_gphy_cl22_read_status(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = genphy_read_status(phydev);
+ if (ret)
+ return ret;
+
+ if (phydev->autoneg == AUTONEG_ENABLE && !phydev->autoneg_complete) {
+ ret = phy_read_paged(phydev, MTK_PHY_PAGE_EXTENDED_1,
+ MTK_PHY_AUX_CTRL_AND_STATUS);
+ if (ret < 0)
+ return ret;
+
+ /* Once LP_DETECTED is set, it means that"ability_match" in
+ * IEEE 802.3 Figure 28-18 is set. This happens after we plug in
+ * cable. Also, LP_DETECTED will be cleared after AN complete.
+ */
+ if (!FIELD_GET(MTK_PHY_LP_DETECTED_MASK, ret))
+ return 0;
+
+ ret = phy_read(phydev, MII_CTRL1000);
+ if (ret & (ADVERTISE_1000FULL | ADVERTISE_1000HALF)) {
+ ret = extend_an_new_lp_cnt_limit(phydev);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_gphy_cl22_read_status);
+
int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
unsigned long rules,
unsigned long supported_triggers)
--- a/drivers/net/phy/mediatek/mtk.h
+++ b/drivers/net/phy/mediatek/mtk.h
@@ -10,8 +10,28 @@
#define MTK_EXT_PAGE_ACCESS 0x1f
#define MTK_PHY_PAGE_STANDARD 0x0000
+#define MTK_PHY_PAGE_EXTENDED_1 0x0001
+#define MTK_PHY_AUX_CTRL_AND_STATUS 0x14
+/* suprv_media_select_RefClk */
+#define MTK_PHY_LP_DETECTED_MASK GENMASK(7, 6)
+#define MTK_PHY_ENABLE_DOWNSHIFT BIT(4)
+
#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
+/* Registers on Token Ring debug nodes */
+/* ch_addr = 0x0, node_addr = 0xf, data_addr = 0x2 */
+#define AN_STATE_MASK GENMASK(22, 19)
+#define AN_STATE_SHIFT 19
+#define AN_STATE_TX_DISABLE 1
+
+/* ch_addr = 0x0, node_addr = 0xf, data_addr = 0x3c */
+#define AN_NEW_LP_CNT_LIMIT_MASK GENMASK(23, 20)
+#define AUTO_NP_10XEN BIT(6)
+
+/* Registers on MDIO_MMD_VEND1 */
+#define MTK_PHY_LINK_STATUS_MISC (0xa2)
+#define MTK_PHY_FINAL_SPEED_1000 BIT(3)
+
/* Registers on MDIO_MMD_VEND2 */
#define MTK_PHY_LED0_ON_CTRL 0x24
#define MTK_PHY_LED1_ON_CTRL 0x26
@@ -78,6 +98,7 @@ void __mtk_tr_clr_bits(struct phy_device
int mtk_phy_read_page(struct phy_device *phydev);
int mtk_phy_write_page(struct phy_device *phydev, int page);
+int mtk_gphy_cl22_read_status(struct phy_device *phydev);
int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
unsigned long rules,
unsigned long supported_triggers);

View File

@@ -0,0 +1,477 @@
From 69ca89165e39e6b6f4c79e6b4c03559e0fac7051 Mon Sep 17 00:00:00 2001
From: "SkyLake.Huang" <skylake.huang@mediatek.com>
Date: Mon, 1 Jul 2024 18:54:15 +0800
Subject: [PATCH 11/13] net: phy: add driver for built-in 2.5G ethernet PHY on
MT7988
Add support for internal 2.5Gphy on MT7988. This driver will load
necessary firmware, add appropriate time delay and figure out LED.
Also, certain control registers will be set to fix link-up issues.
Signed-off-by: SkyLake.Huang <skylake.huang@mediatek.com>
---
drivers/net/phy/mediatek/Kconfig | 11 +
drivers/net/phy/mediatek/Makefile | 1 +
drivers/net/phy/mediatek/mtk-2p5ge.c | 432 +++++++++++++++++++++++++++
4 files changed, 445 insertions(+)
create mode 100644 drivers/net/phy/mediatek/mtk-2p5ge.c
--- a/drivers/net/phy/mediatek/Kconfig
+++ b/drivers/net/phy/mediatek/Kconfig
@@ -25,3 +25,14 @@ config MEDIATEK_GE_SOC_PHY
the MT7981 and MT7988 SoCs. These PHYs need calibration data
present in the SoCs efuse and will dynamically calibrate VCM
(common-mode voltage) during startup.
+
+config MEDIATEK_2P5GE_PHY
+ tristate "MediaTek 2.5Gb Ethernet PHYs"
+ depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
+ select MTK_NET_PHYLIB
+ help
+ Supports MediaTek SoC built-in 2.5Gb Ethernet PHYs.
+
+ This will load necessary firmware and add appropriate time delay.
+ Accelerate this procedure through internal pbus instead of MDIO
+ bus. Certain link-up issues will also be fixed here.
--- a/drivers/net/phy/mediatek/Makefile
+++ b/drivers/net/phy/mediatek/Makefile
@@ -2,3 +2,4 @@
obj-$(CONFIG_MTK_NET_PHYLIB) += mtk-phy-lib.o
obj-$(CONFIG_MEDIATEK_GE_PHY) += mtk-ge.o
obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mtk-ge-soc.o
+obj-$(CONFIG_MEDIATEK_2P5GE_PHY) += mtk-2p5ge.o
--- /dev/null
+++ b/drivers/net/phy/mediatek/mtk-2p5ge.c
@@ -0,0 +1,432 @@
+// SPDX-License-Identifier: GPL-2.0+
+#include <linux/bitfield.h>
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/phy.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
+
+#include "mtk.h"
+
+#define MTK_2P5GPHY_ID_MT7988 (0x00339c11)
+
+#define MT7988_2P5GE_PMB_FW "mediatek/mt7988/i2p5ge-phy-pmb.bin"
+#define MT7988_2P5GE_PMB_FW_SIZE (0x20000)
+#define MT7988_2P5GE_PMB_FW_BASE (0x0f100000)
+#define MT7988_2P5GE_PMB_FW_LEN (0x20000)
+#define MT7988_2P5GE_MD32_EN_CFG_BASE (0x0f0f0018)
+#define MT7988_2P5GE_MD32_EN_CFG_LEN (0x20)
+#define MD32_EN BIT(0)
+
+#define BASE100T_STATUS_EXTEND (0x10)
+#define BASE1000T_STATUS_EXTEND (0x11)
+#define EXTEND_CTRL_AND_STATUS (0x16)
+
+#define PHY_AUX_CTRL_STATUS (0x1d)
+#define PHY_AUX_DPX_MASK GENMASK(5, 5)
+#define PHY_AUX_SPEED_MASK GENMASK(4, 2)
+
+#define MTK_PHY_LPI_PCS_DSP_CTRL (0x121)
+#define MTK_PHY_LPI_SIG_EN_LO_THRESH100_MASK GENMASK(12, 8)
+
+/* Registers on Token Ring debug nodes */
+/* ch_addr = 0x0, node_addr = 0xf, data_addr = 0x3c */
+#define AUTO_NP_10XEN BIT(6)
+
+struct mtk_i2p5ge_phy_priv {
+ bool fw_loaded;
+ unsigned long led_state;
+};
+
+enum {
+ PHY_AUX_SPD_10 = 0,
+ PHY_AUX_SPD_100,
+ PHY_AUX_SPD_1000,
+ PHY_AUX_SPD_2500,
+};
+
+static int mt798x_2p5ge_phy_load_fw(struct phy_device *phydev)
+{
+ struct mtk_i2p5ge_phy_priv *priv = phydev->priv;
+ void __iomem *md32_en_cfg_base, *pmb_addr;
+ struct device *dev = &phydev->mdio.dev;
+ const struct firmware *fw;
+ int ret, i;
+ u16 reg;
+
+ if (priv->fw_loaded)
+ return 0;
+
+ pmb_addr = ioremap(MT7988_2P5GE_PMB_FW_BASE, MT7988_2P5GE_PMB_FW_LEN);
+ if (!pmb_addr)
+ return -ENOMEM;
+ md32_en_cfg_base = ioremap(MT7988_2P5GE_MD32_EN_CFG_BASE,
+ MT7988_2P5GE_MD32_EN_CFG_LEN);
+ if (!md32_en_cfg_base) {
+ ret = -ENOMEM;
+ goto free_pmb;
+ }
+
+ ret = request_firmware(&fw, MT7988_2P5GE_PMB_FW, dev);
+ if (ret) {
+ dev_err(dev, "failed to load firmware: %s, ret: %d\n",
+ MT7988_2P5GE_PMB_FW, ret);
+ goto free;
+ }
+
+ if (fw->size != MT7988_2P5GE_PMB_FW_SIZE) {
+ dev_err(dev, "Firmware size 0x%zx != 0x%x\n",
+ fw->size, MT7988_2P5GE_PMB_FW_SIZE);
+ ret = -EINVAL;
+ goto release_fw;
+ }
+
+ reg = readw(md32_en_cfg_base);
+ if (reg & MD32_EN) {
+ phy_set_bits(phydev, MII_BMCR, BMCR_RESET);
+ usleep_range(10000, 11000);
+ }
+ phy_set_bits(phydev, MII_BMCR, BMCR_PDOWN);
+
+ /* Write magic number to safely stall MCU */
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x800e, 0x1100);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x800f, 0x00df);
+
+ for (i = 0; i < MT7988_2P5GE_PMB_FW_SIZE - 1; i += 4)
+ writel(*((uint32_t *)(fw->data + i)), pmb_addr + i);
+ dev_info(dev, "Firmware date code: %x/%x/%x, version: %x.%x\n",
+ be16_to_cpu(*((__be16 *)(fw->data +
+ MT7988_2P5GE_PMB_FW_SIZE - 8))),
+ *(fw->data + MT7988_2P5GE_PMB_FW_SIZE - 6),
+ *(fw->data + MT7988_2P5GE_PMB_FW_SIZE - 5),
+ *(fw->data + MT7988_2P5GE_PMB_FW_SIZE - 2),
+ *(fw->data + MT7988_2P5GE_PMB_FW_SIZE - 1));
+
+ writew(reg & ~MD32_EN, md32_en_cfg_base);
+ writew(reg | MD32_EN, md32_en_cfg_base);
+ phy_set_bits(phydev, MII_BMCR, BMCR_RESET);
+ /* We need a delay here to stabilize initialization of MCU */
+ usleep_range(7000, 8000);
+ dev_info(dev, "Firmware loading/trigger ok.\n");
+
+ priv->fw_loaded = true;
+
+release_fw:
+ release_firmware(fw);
+free:
+ iounmap(md32_en_cfg_base);
+free_pmb:
+ iounmap(pmb_addr);
+
+ return ret;
+}
+
+static int mt798x_2p5ge_phy_config_init(struct phy_device *phydev)
+{
+ struct pinctrl *pinctrl;
+ int ret;
+
+ /* Check if PHY interface type is compatible */
+ if (phydev->interface != PHY_INTERFACE_MODE_INTERNAL)
+ return -ENODEV;
+
+ ret = mt798x_2p5ge_phy_load_fw(phydev);
+ if (ret < 0)
+ return ret;
+
+ /* Setup LED */
+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL,
+ MTK_PHY_LED_ON_POLARITY | MTK_PHY_LED_ON_LINK10 |
+ MTK_PHY_LED_ON_LINK100 | MTK_PHY_LED_ON_LINK1000 |
+ MTK_PHY_LED_ON_LINK2500);
+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED1_ON_CTRL,
+ MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX);
+
+ /* Switch pinctrl after setting polarity to avoid bogus blinking */
+ pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "i2p5gbe-led");
+ if (IS_ERR(pinctrl))
+ dev_err(&phydev->mdio.dev, "Fail to set LED pins!\n");
+
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LPI_PCS_DSP_CTRL,
+ MTK_PHY_LPI_SIG_EN_LO_THRESH100_MASK, 0);
+
+ /* Enable 16-bit next page exchange bit if 1000-BT isn't advertising */
+ mtk_tr_modify(phydev, 0x0, 0xf, 0x3c, AUTO_NP_10XEN,
+ FIELD_PREP(AUTO_NP_10XEN, 0x1));
+
+ /* Enable HW auto downshift */
+ phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED_1,
+ MTK_PHY_AUX_CTRL_AND_STATUS,
+ 0, MTK_PHY_ENABLE_DOWNSHIFT);
+
+ return 0;
+}
+
+static int mt798x_2p5ge_phy_config_aneg(struct phy_device *phydev)
+{
+ bool changed = false;
+ u32 adv;
+ int ret;
+
+ /* In fact, if we disable autoneg, we can't link up correctly:
+ * 2.5G/1G: Need AN to exchange master/slave information.
+ * 100M/10M: Without AN, link starts at half duplex (According to
+ * IEEE 802.3-2018), which this phy doesn't support.
+ */
+ if (phydev->autoneg == AUTONEG_DISABLE)
+ return -EOPNOTSUPP;
+
+ ret = genphy_c45_an_config_aneg(phydev);
+ if (ret < 0)
+ return ret;
+ if (ret > 0)
+ changed = true;
+
+ /* Clause 45 doesn't define 1000BaseT support. Use Clause 22 instead in
+ * our design.
+ */
+ adv = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising);
+ ret = phy_modify_changed(phydev, MII_CTRL1000, ADVERTISE_1000FULL, adv);
+ if (ret < 0)
+ return ret;
+ if (ret > 0)
+ changed = true;
+
+ return genphy_c45_check_and_restart_aneg(phydev, changed);
+}
+
+static int mt798x_2p5ge_phy_get_features(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = genphy_c45_pma_read_abilities(phydev);
+ if (ret)
+ return ret;
+
+ /* This phy can't handle collision, and neither can (XFI)MAC it's
+ * connected to. Although it can do HDX handshake, it doesn't support
+ * CSMA/CD that HDX requires.
+ */
+ linkmode_clear_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
+ phydev->supported);
+
+ return 0;
+}
+
+static int mt798x_2p5ge_phy_read_status(struct phy_device *phydev)
+{
+ int ret;
+
+ /* When MDIO_STAT1_LSTATUS is raised genphy_c45_read_link(), this phy
+ * actually hasn't finished AN. So use CL22's link update function
+ * instead.
+ */
+ ret = genphy_update_link(phydev);
+ if (ret)
+ return ret;
+
+ phydev->speed = SPEED_UNKNOWN;
+ phydev->duplex = DUPLEX_UNKNOWN;
+ phydev->pause = 0;
+ phydev->asym_pause = 0;
+
+ /* We'll read link speed through vendor specific registers down below.
+ * So remove phy_resolve_aneg_linkmode (AN on) & genphy_c45_read_pma
+ * (AN off).
+ */
+ if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) {
+ ret = genphy_c45_read_lpa(phydev);
+ if (ret < 0)
+ return ret;
+
+ /* Clause 45 doesn't define 1000BaseT support. Read the link
+ * partner's 1G advertisement via Clause 22.
+ */
+ ret = phy_read(phydev, MII_STAT1000);
+ if (ret < 0)
+ return ret;
+ mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, ret);
+ } else if (phydev->autoneg == AUTONEG_DISABLE) {
+ linkmode_zero(phydev->lp_advertising);
+ }
+
+ if (phydev->link) {
+ ret = phy_read(phydev, PHY_AUX_CTRL_STATUS);
+ if (ret < 0)
+ return ret;
+
+ switch (FIELD_GET(PHY_AUX_SPEED_MASK, ret)) {
+ case PHY_AUX_SPD_10:
+ phydev->speed = SPEED_10;
+ break;
+ case PHY_AUX_SPD_100:
+ phydev->speed = SPEED_100;
+ break;
+ case PHY_AUX_SPD_1000:
+ phydev->speed = SPEED_1000;
+ break;
+ case PHY_AUX_SPD_2500:
+ phydev->speed = SPEED_2500;
+ break;
+ }
+
+ phydev->duplex = DUPLEX_FULL;
+ /* FIXME:
+ * The current firmware always enables rate adaptation mode.
+ */
+ phydev->rate_matching = RATE_MATCH_PAUSE;
+ }
+
+ return 0;
+}
+
+static int mt798x_2p5ge_phy_get_rate_matching(struct phy_device *phydev,
+ phy_interface_t iface)
+{
+ return RATE_MATCH_PAUSE;
+}
+
+static const unsigned long supported_triggers =
+ BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
+ BIT(TRIGGER_NETDEV_LINK) |
+ BIT(TRIGGER_NETDEV_LINK_10) |
+ BIT(TRIGGER_NETDEV_LINK_100) |
+ BIT(TRIGGER_NETDEV_LINK_1000) |
+ BIT(TRIGGER_NETDEV_LINK_2500) |
+ BIT(TRIGGER_NETDEV_RX) |
+ BIT(TRIGGER_NETDEV_TX);
+
+static int mt798x_2p5ge_phy_led_blink_set(struct phy_device *phydev, u8 index,
+ unsigned long *delay_on,
+ unsigned long *delay_off)
+{
+ struct mtk_i2p5ge_phy_priv *priv = phydev->priv;
+ bool blinking = false;
+ int err = 0;
+
+ err = mtk_phy_led_num_dly_cfg(index, delay_on, delay_off, &blinking);
+ if (err < 0)
+ return err;
+
+ err = mtk_phy_hw_led_blink_set(phydev, index, &priv->led_state,
+ blinking);
+ if (err)
+ return err;
+
+ return mtk_phy_hw_led_on_set(phydev, index, &priv->led_state,
+ MTK_2P5GPHY_LED_ON_MASK, false);
+}
+
+static int mt798x_2p5ge_phy_led_brightness_set(struct phy_device *phydev,
+ u8 index,
+ enum led_brightness value)
+{
+ struct mtk_i2p5ge_phy_priv *priv = phydev->priv;
+ int err;
+
+ err = mtk_phy_hw_led_blink_set(phydev, index, &priv->led_state, false);
+ if (err)
+ return err;
+
+ return mtk_phy_hw_led_on_set(phydev, index, &priv->led_state,
+ MTK_2P5GPHY_LED_ON_MASK,
+ (value != LED_OFF));
+}
+
+static int mt798x_2p5ge_phy_led_hw_is_supported(struct phy_device *phydev,
+ u8 index, unsigned long rules)
+{
+ return mtk_phy_led_hw_is_supported(phydev, index, rules,
+ supported_triggers);
+}
+
+static int mt798x_2p5ge_phy_led_hw_control_get(struct phy_device *phydev,
+ u8 index, unsigned long *rules)
+{
+ struct mtk_i2p5ge_phy_priv *priv = phydev->priv;
+
+ return mtk_phy_led_hw_ctrl_get(phydev, index, rules, &priv->led_state,
+ MTK_2P5GPHY_LED_ON_SET,
+ MTK_2P5GPHY_LED_RX_BLINK_SET,
+ MTK_2P5GPHY_LED_TX_BLINK_SET);
+};
+
+static int mt798x_2p5ge_phy_led_hw_control_set(struct phy_device *phydev,
+ u8 index, unsigned long rules)
+{
+ struct mtk_i2p5ge_phy_priv *priv = phydev->priv;
+
+ return mtk_phy_led_hw_ctrl_set(phydev, index, rules, &priv->led_state,
+ MTK_2P5GPHY_LED_ON_SET,
+ MTK_2P5GPHY_LED_RX_BLINK_SET,
+ MTK_2P5GPHY_LED_TX_BLINK_SET);
+};
+
+static int mt798x_2p5ge_phy_probe(struct phy_device *phydev)
+{
+ struct mtk_i2p5ge_phy_priv *priv;
+
+ priv = devm_kzalloc(&phydev->mdio.dev,
+ sizeof(struct mtk_i2p5ge_phy_priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ switch (phydev->drv->phy_id) {
+ case MTK_2P5GPHY_ID_MT7988:
+ /* The original hardware only sets MDIO_DEVS_PMAPMD */
+ phydev->c45_ids.mmds_present |= MDIO_DEVS_PCS |
+ MDIO_DEVS_AN |
+ MDIO_DEVS_VEND1 |
+ MDIO_DEVS_VEND2;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ priv->fw_loaded = false;
+ phydev->priv = priv;
+
+ mtk_phy_leds_state_init(phydev);
+
+ return 0;
+}
+
+static struct phy_driver mtk_2p5gephy_driver[] = {
+ {
+ PHY_ID_MATCH_MODEL(MTK_2P5GPHY_ID_MT7988),
+ .name = "MediaTek MT7988 2.5GbE PHY",
+ .probe = mt798x_2p5ge_phy_probe,
+ .config_init = mt798x_2p5ge_phy_config_init,
+ .config_aneg = mt798x_2p5ge_phy_config_aneg,
+ .get_features = mt798x_2p5ge_phy_get_features,
+ .read_status = mt798x_2p5ge_phy_read_status,
+ .get_rate_matching = mt798x_2p5ge_phy_get_rate_matching,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+ .read_page = mtk_phy_read_page,
+ .write_page = mtk_phy_write_page,
+ .led_blink_set = mt798x_2p5ge_phy_led_blink_set,
+ .led_brightness_set = mt798x_2p5ge_phy_led_brightness_set,
+ .led_hw_is_supported = mt798x_2p5ge_phy_led_hw_is_supported,
+ .led_hw_control_get = mt798x_2p5ge_phy_led_hw_control_get,
+ .led_hw_control_set = mt798x_2p5ge_phy_led_hw_control_set,
+ },
+};
+
+module_phy_driver(mtk_2p5gephy_driver);
+
+static struct mdio_device_id __maybe_unused mtk_2p5ge_phy_tbl[] = {
+ { PHY_ID_MATCH_VENDOR(0x00339c00) },
+ { }
+};
+
+MODULE_DESCRIPTION("MediaTek 2.5Gb Ethernet PHY driver");
+MODULE_AUTHOR("SkyLake Huang <SkyLake.Huang@mediatek.com>");
+MODULE_LICENSE("GPL");
+
+MODULE_DEVICE_TABLE(mdio, mtk_2p5ge_phy_tbl);
+MODULE_FIRMWARE(MT7988_2P5GE_PMB_FW);

View File

@@ -0,0 +1,130 @@
From 07e90eb1819319a0c34b0cf3a57a4a3878e96e4d Mon Sep 17 00:00:00 2001
From: "SkyLake.Huang" <skylake.huang@mediatek.com>
Date: Mon, 1 Jul 2024 18:54:16 +0800
Subject: [PATCH 12/13] net: phy: mediatek: Fix alignment in callback
functions' hook
Align declarations in mtk_gephy_driver(mtk-ge.c) and
mtk_socphy_driver(mtk-ge-soc.c). At first, some of them are
".foo<tab>= method_foo", and others are ".bar<space>= method_bar".
Use space instead for all of them here in case line is longer than
80 chars.
Signed-off-by: SkyLake.Huang <skylake.huang@mediatek.com>
---
drivers/net/phy/mediatek/mtk-ge-soc.c | 40 +++++++++++++--------------
drivers/net/phy/mediatek/mtk-ge.c | 34 +++++++++++------------
2 files changed, 37 insertions(+), 37 deletions(-)
--- a/drivers/net/phy/mediatek/mtk-ge-soc.c
+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
@@ -1394,17 +1394,17 @@ static int mt7981_phy_probe(struct phy_d
static struct phy_driver mtk_socphy_driver[] = {
{
PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981),
- .name = "MediaTek MT7981 PHY",
- .config_init = mt798x_phy_config_init,
- .read_status = mtk_gphy_cl22_read_status,
- .config_intr = genphy_no_config_intr,
+ .name = "MediaTek MT7981 PHY",
+ .config_init = mt798x_phy_config_init,
+ .read_status = mtk_gphy_cl22_read_status,
+ .config_intr = genphy_no_config_intr,
.handle_interrupt = genphy_handle_interrupt_no_ack,
- .probe = mt7981_phy_probe,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
- .read_page = mtk_phy_read_page,
- .write_page = mtk_phy_write_page,
- .led_blink_set = mt798x_phy_led_blink_set,
+ .probe = mt7981_phy_probe,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+ .read_page = mtk_phy_read_page,
+ .write_page = mtk_phy_write_page,
+ .led_blink_set = mt798x_phy_led_blink_set,
.led_brightness_set = mt798x_phy_led_brightness_set,
.led_hw_is_supported = mt798x_phy_led_hw_is_supported,
.led_hw_control_set = mt798x_phy_led_hw_control_set,
@@ -1412,17 +1412,17 @@ static struct phy_driver mtk_socphy_driv
},
{
PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988),
- .name = "MediaTek MT7988 PHY",
- .config_init = mt798x_phy_config_init,
- .read_status = mtk_gphy_cl22_read_status,
- .config_intr = genphy_no_config_intr,
+ .name = "MediaTek MT7988 PHY",
+ .config_init = mt798x_phy_config_init,
+ .read_status = mtk_gphy_cl22_read_status,
+ .config_intr = genphy_no_config_intr,
.handle_interrupt = genphy_handle_interrupt_no_ack,
- .probe = mt7988_phy_probe,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
- .read_page = mtk_phy_read_page,
- .write_page = mtk_phy_write_page,
- .led_blink_set = mt798x_phy_led_blink_set,
+ .probe = mt7988_phy_probe,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+ .read_page = mtk_phy_read_page,
+ .write_page = mtk_phy_write_page,
+ .led_blink_set = mt798x_phy_led_blink_set,
.led_brightness_set = mt798x_phy_led_brightness_set,
.led_hw_is_supported = mt798x_phy_led_hw_is_supported,
.led_hw_control_set = mt798x_phy_led_hw_control_set,
--- a/drivers/net/phy/mediatek/mtk-ge.c
+++ b/drivers/net/phy/mediatek/mtk-ge.c
@@ -230,34 +230,34 @@ static int mt753x_phy_led_hw_control_set
static struct phy_driver mtk_gephy_driver[] = {
{
PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7530),
- .name = "MediaTek MT7530 PHY",
- .config_init = mt7530_phy_config_init,
+ .name = "MediaTek MT7530 PHY",
+ .config_init = mt7530_phy_config_init,
/* Interrupts are handled by the switch, not the PHY
* itself.
*/
- .config_intr = genphy_no_config_intr,
+ .config_intr = genphy_no_config_intr,
.handle_interrupt = genphy_handle_interrupt_no_ack,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
- .read_page = mtk_phy_read_page,
- .write_page = mtk_phy_write_page,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+ .read_page = mtk_phy_read_page,
+ .write_page = mtk_phy_write_page,
},
{
PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7531),
- .name = "MediaTek MT7531 PHY",
- .probe = mt7531_phy_probe,
- .config_init = mt7531_phy_config_init,
- .read_status = mtk_gphy_cl22_read_status,
+ .name = "MediaTek MT7531 PHY",
+ .probe = mt7531_phy_probe,
+ .config_init = mt7531_phy_config_init,
+ .read_status = mtk_gphy_cl22_read_status,
/* Interrupts are handled by the switch, not the PHY
* itself.
*/
- .config_intr = genphy_no_config_intr,
+ .config_intr = genphy_no_config_intr,
.handle_interrupt = genphy_handle_interrupt_no_ack,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
- .read_page = mtk_phy_read_page,
- .write_page = mtk_phy_write_page,
- .led_blink_set = mt753x_phy_led_blink_set,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+ .read_page = mtk_phy_read_page,
+ .write_page = mtk_phy_write_page,
+ .led_blink_set = mt753x_phy_led_blink_set,
.led_brightness_set = mt753x_phy_led_brightness_set,
.led_hw_is_supported = mt753x_phy_led_hw_is_supported,
.led_hw_control_set = mt753x_phy_led_hw_control_set,

View File

@@ -0,0 +1,65 @@
From e59883b637ae317c2ac275b542e8a50670d76e7c Mon Sep 17 00:00:00 2001
From: "SkyLake.Huang" <skylake.huang@mediatek.com>
Date: Mon, 1 Jul 2024 18:54:17 +0800
Subject: [PATCH 13/13] net: phy: mediatek: Remove unnecessary outer parens of
"supported_triggers" var
This patch removes unnecessary outer parens of "supported_triggers" vars
in mtk-ge.c & mtk-ge-soc.c to improve readability.
Signed-off-by: SkyLake.Huang <skylake.huang@mediatek.com>
---
drivers/net/phy/mediatek/mtk-ge-soc.c | 16 ++++++++--------
drivers/net/phy/mediatek/mtk-ge.c | 16 ++++++++--------
2 files changed, 16 insertions(+), 16 deletions(-)
--- a/drivers/net/phy/mediatek/mtk-ge-soc.c
+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
@@ -1224,14 +1224,14 @@ static int mt798x_phy_led_brightness_set
}
static const unsigned long supported_triggers =
- (BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
- BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
- BIT(TRIGGER_NETDEV_LINK) |
- BIT(TRIGGER_NETDEV_LINK_10) |
- BIT(TRIGGER_NETDEV_LINK_100) |
- BIT(TRIGGER_NETDEV_LINK_1000) |
- BIT(TRIGGER_NETDEV_RX) |
- BIT(TRIGGER_NETDEV_TX));
+ BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
+ BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
+ BIT(TRIGGER_NETDEV_LINK) |
+ BIT(TRIGGER_NETDEV_LINK_10) |
+ BIT(TRIGGER_NETDEV_LINK_100) |
+ BIT(TRIGGER_NETDEV_LINK_1000) |
+ BIT(TRIGGER_NETDEV_RX) |
+ BIT(TRIGGER_NETDEV_TX);
static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
unsigned long rules)
--- a/drivers/net/phy/mediatek/mtk-ge.c
+++ b/drivers/net/phy/mediatek/mtk-ge.c
@@ -189,14 +189,14 @@ static int mt753x_phy_led_brightness_set
}
static const unsigned long supported_triggers =
- (BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
- BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
- BIT(TRIGGER_NETDEV_LINK) |
- BIT(TRIGGER_NETDEV_LINK_10) |
- BIT(TRIGGER_NETDEV_LINK_100) |
- BIT(TRIGGER_NETDEV_LINK_1000) |
- BIT(TRIGGER_NETDEV_RX) |
- BIT(TRIGGER_NETDEV_TX));
+ BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
+ BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
+ BIT(TRIGGER_NETDEV_LINK) |
+ BIT(TRIGGER_NETDEV_LINK_10) |
+ BIT(TRIGGER_NETDEV_LINK_100) |
+ BIT(TRIGGER_NETDEV_LINK_1000) |
+ BIT(TRIGGER_NETDEV_RX) |
+ BIT(TRIGGER_NETDEV_TX);
static int mt753x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
unsigned long rules)

View File

@@ -1,39 +0,0 @@
From 128dc09b0af36772062142ce9e85b19c84ac789a Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Tue, 28 Feb 2023 17:53:37 +0000
Subject: [PATCH] net: phy: add driver for MediaTek 2.5G PHY
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/net/phy/Kconfig | 7 ++
drivers/net/phy/Makefile | 1 +
drivers/net/phy/mediatek-2p5ge.c | 220 +++++++++++++++++++++++++++++++
3 files changed, 226 insertions(+)
create mode 100644 drivers/net/phy/mediatek-2p5ge.c
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -330,6 +330,13 @@ config MEDIATEK_GE_SOC_PHY
present in the SoCs efuse and will dynamically calibrate VCM
(common-mode voltage) during startup.
+config MEDIATEK_2P5G_PHY
+ tristate "MediaTek 2.5G Ethernet PHY"
+ depends on (ARCH_MEDIATEK && ARM64) || COMPILE_TEST
+ default NET_MEDIATEK_SOC
+ help
+ Supports the MediaTek 2.5G Ethernet PHY.
+
config MICREL_PHY
tristate "Micrel PHYs"
depends on PTP_1588_CLOCK_OPTIONAL
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_MARVELL_PHY) += marvell.o
obj-$(CONFIG_MARVELL_88Q2XXX_PHY) += marvell-88q2xxx.o
obj-$(CONFIG_MARVELL_88X2222_PHY) += marvell-88x2222.o
obj-$(CONFIG_MAXLINEAR_GPHY) += mxl-gpy.o
+obj-$(CONFIG_MEDIATEK_2P5G_PHY) += mediatek-2p5ge.o
obj-$(CONFIG_MEDIATEK_GE_PHY) += mediatek-ge.o
obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mediatek-ge-soc.o
obj-$(CONFIG_MESON_GXL_PHY) += meson-gxl.o

View File

@@ -8,12 +8,12 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=ddns-go PKG_NAME:=ddns-go
PKG_VERSION:=6.7.3 PKG_VERSION:=6.7.5
PKG_RELEASE:=1 PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/jeessy2/ddns-go/tar.gz/v$(PKG_VERSION)? PKG_SOURCE_URL:=https://codeload.github.com/jeessy2/ddns-go/tar.gz/v$(PKG_VERSION)?
PKG_HASH:=3edaf68505df7188e57ad89c1fc66fd7c2918e36017f357953fce4101e493424 PKG_HASH:=b6f5f74c544c4765ac5499c3f47ec3c07e6f6a55c1ff4e510433334786cf8aaa
PKG_LICENSE:=MIT PKG_LICENSE:=MIT
PKG_LICENSE_FILES:=LICENSE PKG_LICENSE_FILES:=LICENSE

View File

@@ -1079,3 +1079,24 @@ function luci_types(id, m, s, type_name, option_prefix)
end end
end end
end end
function get_std_domain(domain)
domain = trim(domain)
if domain == "" or domain:find("#") then return "" end
-- 删除首尾所有的 .
domain = domain:gsub("^[%.]+", ""):gsub("[%.]+$", "")
-- 如果 domain 包含 '*',则分割并删除包含 '*' 的部分及其前面的部分
if domain:find("%*") then
local parts = {}
for part in domain:gmatch("[^%.]+") do
table.insert(parts, part)
end
for i = #parts, 1, -1 do
if parts[i]:find("%*") then
-- 删除包含 '*' 的部分及其前面的部分
return parts[i + 1] and parts[i + 1] .. "." .. table.concat(parts, ".", i + 2) or ""
end
end
end
return domain
end

View File

@@ -546,6 +546,8 @@ run_chinadns_ng() {
local _flag _listen_port _dns_local _dns_trust _no_ipv6_trust _use_direct_list _use_proxy_list _gfwlist _chnlist _default_mode _default_tag local _flag _listen_port _dns_local _dns_trust _no_ipv6_trust _use_direct_list _use_proxy_list _gfwlist _chnlist _default_mode _default_tag
eval_set_val $@ eval_set_val $@
lua $APP_PATH/helper_chinadns_add.lua -FLAG $_flag -USE_DIRECT_LIST $_use_direct_list -USE_PROXY_LIST $_use_proxy_list
local _CONF_FILE=$TMP_ACL_PATH/$_flag/chinadns_ng.conf local _CONF_FILE=$TMP_ACL_PATH/$_flag/chinadns_ng.conf
local _LOG_FILE=$TMP_ACL_PATH/$_flag/chinadns_ng.log local _LOG_FILE=$TMP_ACL_PATH/$_flag/chinadns_ng.log
_LOG_FILE="/dev/null" _LOG_FILE="/dev/null"
@@ -579,7 +581,7 @@ run_chinadns_ng() {
EOF EOF
} }
[ "${_use_direct_list}" = "1" ] && [ -s "${RULES_PATH}/direct_host" ] && { [ "${_use_direct_list}" = "1" ] && [ -s "${TMP_PATH}/direct_host" ] && {
local whitelist4_set="passwall_whitelist" local whitelist4_set="passwall_whitelist"
local whitelist6_set="passwall_whitelist6" local whitelist6_set="passwall_whitelist6"
[ "$nftflag" = "1" ] && { [ "$nftflag" = "1" ] && {
@@ -588,13 +590,13 @@ run_chinadns_ng() {
} }
cat <<-EOF >> ${_CONF_FILE} cat <<-EOF >> ${_CONF_FILE}
group directlist group directlist
group-dnl ${RULES_PATH}/direct_host group-dnl ${TMP_PATH}/direct_host
group-upstream ${_dns_local} group-upstream ${_dns_local}
group-ipset ${whitelist4_set},${whitelist6_set} group-ipset ${whitelist4_set},${whitelist6_set}
EOF EOF
} }
[ "${_use_proxy_list}" = "1" ] && [ -s "${RULES_PATH}/proxy_host" ] && { [ "${_use_proxy_list}" = "1" ] && [ -s "${TMP_PATH}/proxy_host" ] && {
local blacklist4_set="passwall_blacklist" local blacklist4_set="passwall_blacklist"
local blacklist6_set="passwall_blacklist6" local blacklist6_set="passwall_blacklist6"
[ "$nftflag" = "1" ] && { [ "$nftflag" = "1" ] && {
@@ -603,7 +605,7 @@ run_chinadns_ng() {
} }
cat <<-EOF >> ${_CONF_FILE} cat <<-EOF >> ${_CONF_FILE}
group proxylist group proxylist
group-dnl ${RULES_PATH}/proxy_host group-dnl ${TMP_PATH}/proxy_host
group-upstream ${_dns_trust} group-upstream ${_dns_trust}
group-ipset ${blacklist4_set},${blacklist6_set} group-ipset ${blacklist4_set},${blacklist6_set}
EOF EOF

View File

@@ -0,0 +1,50 @@
require 'nixio'
local api = require "luci.passwall.api"
local appname = "passwall"
local var = api.get_args(arg)
local FLAG = var["-FLAG"]
local USE_DIRECT_LIST = var["-USE_DIRECT_LIST"]
local USE_PROXY_LIST = var["-USE_PROXY_LIST"]
local TMP_PATH = "/tmp/etc/" .. appname
if not nixio.fs.access(TMP_PATH) then
nixio.fs.mkdir(TMP_PATH, 493)
end
local tmp_direct_host = TMP_PATH .. "/direct_host"
if USE_DIRECT_LIST == "1" and not nixio.fs.access(tmp_direct_host) then
local direct_domain = {}
for line in io.lines("/usr/share/passwall/rules/direct_host") do
line = api.get_std_domain(line)
if line ~= "" and not line:find("#") then
table.insert(direct_domain, line)
end
end
if #direct_domain > 0 then
local direct_out = io.open(tmp_direct_host, "a")
for i = 1, #direct_domain do
direct_out:write(direct_domain[i] .. "\n")
end
direct_out:close()
end
end
local tmp_proxy_host = TMP_PATH .. "/proxy_host"
if USE_PROXY_LIST == "1" and not nixio.fs.access(tmp_proxy_host) then
local proxy_domain = {}
for line in io.lines("/usr/share/passwall/rules/proxy_host") do
line = api.get_std_domain(line)
if line ~= "" and not line:find("#") then
table.insert(proxy_domain, line)
end
end
if #proxy_domain > 0 then
local proxy_out = io.open(tmp_proxy_host, "a")
for i = 1, #proxy_domain do
proxy_out:write(proxy_domain[i] .. "\n")
end
proxy_out:close()
end
end

View File

@@ -196,6 +196,7 @@ if not fs.access(CACHE_DNS_PATH) then
--屏蔽列表 --屏蔽列表
if USE_BLOCK_LIST == "1" then if USE_BLOCK_LIST == "1" then
for line in io.lines("/usr/share/passwall/rules/block_host") do for line in io.lines("/usr/share/passwall/rules/block_host") do
line = api.get_std_domain(line)
if line ~= "" and not line:find("#") then if line ~= "" and not line:find("#") then
set_domain_address(line, "") set_domain_address(line, "")
end end
@@ -234,6 +235,7 @@ if not fs.access(CACHE_DNS_PATH) then
if fwd_dns then if fwd_dns then
--始终用国内DNS解析直连白名单列表 --始终用国内DNS解析直连白名单列表
for line in io.lines("/usr/share/passwall/rules/direct_host") do for line in io.lines("/usr/share/passwall/rules/direct_host") do
line = api.get_std_domain(line)
if line ~= "" and not line:find("#") then if line ~= "" and not line:find("#") then
add_excluded_domain(line) add_excluded_domain(line)
set_domain_dns(line, fwd_dns) set_domain_dns(line, fwd_dns)
@@ -255,6 +257,7 @@ if not fs.access(CACHE_DNS_PATH) then
if fwd_dns then if fwd_dns then
--始终使用远程DNS解析代理黑名单列表 --始终使用远程DNS解析代理黑名单列表
for line in io.lines("/usr/share/passwall/rules/proxy_host") do for line in io.lines("/usr/share/passwall/rules/proxy_host") do
line = api.get_std_domain(line)
if line ~= "" and not line:find("#") then if line ~= "" and not line:find("#") then
add_excluded_domain(line) add_excluded_domain(line)
local ipset_flag = setflag_4 .. "passwall_blacklist," .. setflag_6 .. "passwall_blacklist6" local ipset_flag = setflag_4 .. "passwall_blacklist," .. setflag_6 .. "passwall_blacklist6"

View File

@@ -0,0 +1,19 @@
name: Cargo Deny Check
on: [push, pull_request]
jobs:
cargo-deny:
runs-on: ubuntu-latest
strategy:
matrix:
checks:
- advisories
- bans licenses sources
# Prevent sudden announcement of a new advisory from failing ci:
continue-on-error: ${{ matrix.checks == 'advisories' }}
steps:
- uses: actions/checkout@v4
- uses: EmbarkStudios/cargo-deny-action@v2
with:
command: check ${{ matrix.checks }}

View File

@@ -136,9 +136,9 @@ dependencies = [
[[package]] [[package]]
name = "anstyle" name = "anstyle"
version = "1.0.9" version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8365de52b16c035ff4fcafe0092ba9390540e3e352870ac09933bebcaa2c8c56" checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
[[package]] [[package]]
name = "anstyle-parse" name = "anstyle-parse"
@@ -170,9 +170,9 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.91" version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c042108f3ed77fd83760a5fd79b53be043192bb3b9dba91d8c574c0ada7850c8" checksum = "74f37166d7d48a0284b99dd824694c26119c700b53bf0d1540cdb147dbdaaf13"
[[package]] [[package]]
name = "arc-swap" name = "arc-swap"
@@ -465,9 +465,9 @@ dependencies = [
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.1.31" version = "1.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" checksum = "538b056773ee67775e422d15c33169f5415706855814b96505c84ee942f2bae2"
dependencies = [ dependencies = [
"jobserver", "jobserver",
"libc", "libc",
@@ -1097,9 +1097,9 @@ checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
[[package]] [[package]]
name = "futures-lite" name = "futures-lite"
version = "2.3.0" version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" checksum = "3f1fa2f9765705486b33fd2acf1577f8ec449c2ba1f318ae5447697b7c08d210"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"pin-project-lite", "pin-project-lite",
@@ -1503,7 +1503,7 @@ dependencies = [
"http 1.1.0", "http 1.1.0",
"hyper", "hyper",
"hyper-util", "hyper-util",
"rustls 0.23.15", "rustls 0.23.16",
"rustls-native-certs 0.8.0", "rustls-native-certs 0.8.0",
"rustls-pki-types", "rustls-pki-types",
"tokio", "tokio",
@@ -1530,9 +1530,9 @@ dependencies = [
[[package]] [[package]]
name = "hyper-util" name = "hyper-util"
version = "0.1.9" version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4"
dependencies = [ dependencies = [
"bytes", "bytes",
"futures-channel", "futures-channel",
@@ -2569,9 +2569,9 @@ dependencies = [
"bytes", "bytes",
"pin-project-lite", "pin-project-lite",
"quinn-proto 0.11.8", "quinn-proto 0.11.8",
"quinn-udp 0.5.5", "quinn-udp 0.5.6",
"rustc-hash 2.0.0", "rustc-hash 2.0.0",
"rustls 0.23.15", "rustls 0.23.16",
"socket2", "socket2",
"thiserror", "thiserror",
"tokio", "tokio",
@@ -2605,7 +2605,7 @@ dependencies = [
"rand", "rand",
"ring 0.17.8", "ring 0.17.8",
"rustc-hash 2.0.0", "rustc-hash 2.0.0",
"rustls 0.23.15", "rustls 0.23.16",
"slab", "slab",
"thiserror", "thiserror",
"tinyvec", "tinyvec",
@@ -2627,10 +2627,11 @@ dependencies = [
[[package]] [[package]]
name = "quinn-udp" name = "quinn-udp"
version = "0.5.5" version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fe68c2e9e1a1234e218683dbdf9f9dfcb094113c5ac2b938dfcb9bab4c4140b" checksum = "e346e016eacfff12233c243718197ca12f148c84e1e84268a896699b41c71780"
dependencies = [ dependencies = [
"cfg_aliases",
"libc", "libc",
"once_cell", "once_cell",
"socket2", "socket2",
@@ -2785,7 +2786,7 @@ dependencies = [
"percent-encoding", "percent-encoding",
"pin-project-lite", "pin-project-lite",
"quinn 0.11.5", "quinn 0.11.5",
"rustls 0.23.15", "rustls 0.23.16",
"rustls-native-certs 0.8.0", "rustls-native-certs 0.8.0",
"rustls-pemfile 2.2.0", "rustls-pemfile 2.2.0",
"rustls-pki-types", "rustls-pki-types",
@@ -2926,9 +2927,9 @@ checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152"
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.38.37" version = "0.38.38"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.6.0",
"errno", "errno",
@@ -2951,9 +2952,9 @@ dependencies = [
[[package]] [[package]]
name = "rustls" name = "rustls"
version = "0.23.15" version = "0.23.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fbb44d7acc4e873d613422379f69f237a1b141928c02f6bc6ccfddddc2d7993" checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e"
dependencies = [ dependencies = [
"log", "log",
"once_cell", "once_cell",
@@ -3259,9 +3260,9 @@ dependencies = [
[[package]] [[package]]
name = "shadowsocks-crypto" name = "shadowsocks-crypto"
version = "0.5.5" version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9e49ecfad8b27f3df28848af11f08aa10df0c6b74b45748131753913be23373" checksum = "bc77ecb3a97509d22751b76665894fcffad2d10df8758f4e3f20c92ccde6bf4f"
dependencies = [ dependencies = [
"aead", "aead",
"aes", "aes",
@@ -3287,7 +3288,7 @@ dependencies = [
[[package]] [[package]]
name = "shadowsocks-rust" name = "shadowsocks-rust"
version = "1.21.2" version = "1.21.3"
dependencies = [ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"build-time", "build-time",
@@ -3328,7 +3329,7 @@ dependencies = [
[[package]] [[package]]
name = "shadowsocks-service" name = "shadowsocks-service"
version = "1.21.2" version = "1.21.3"
dependencies = [ dependencies = [
"arc-swap", "arc-swap",
"async-trait", "async-trait",
@@ -3809,7 +3810,7 @@ version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4"
dependencies = [ dependencies = [
"rustls 0.23.15", "rustls 0.23.16",
"rustls-pki-types", "rustls-pki-types",
"tokio", "tokio",
] ]

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "shadowsocks-rust" name = "shadowsocks-rust"
version = "1.21.2" version = "1.21.3"
authors = ["Shadowsocks Contributors"] authors = ["Shadowsocks Contributors"]
description = "shadowsocks is a fast tunnel proxy that helps you bypass firewalls." description = "shadowsocks is a fast tunnel proxy that helps you bypass firewalls."
repository = "https://github.com/shadowsocks/shadowsocks-rust" repository = "https://github.com/shadowsocks/shadowsocks-rust"
@@ -67,11 +67,19 @@ default = [
"local-tunnel", "local-tunnel",
"local-socks4", "local-socks4",
"multi-threaded", "multi-threaded",
"aead-cipher",
"aead-cipher-2022", "aead-cipher-2022",
] ]
# Basic Features # Basic Features
basic = ["logging", "hickory-dns", "local", "server", "multi-threaded"] basic = [
"logging",
"hickory-dns",
"local",
"server",
"multi-threaded",
"aead-cipher",
]
# All Suggested Features # All Suggested Features
full = [ full = [
@@ -95,6 +103,7 @@ full = [
"local-online-config", "local-online-config",
"multi-threaded", "multi-threaded",
"stream-cipher", "stream-cipher",
"aead-cipher",
"aead-cipher-2022", "aead-cipher-2022",
] ]
@@ -190,9 +199,12 @@ multi-threaded = ["tokio/rt-multi-thread"]
# Users should always avoid using these ciphers in practice # Users should always avoid using these ciphers in practice
stream-cipher = ["shadowsocks-service/stream-cipher"] stream-cipher = ["shadowsocks-service/stream-cipher"]
# Enable AEAD ciphers
aead-cipher = ["shadowsocks-service/aead-cipher"]
# Enable extra AEAD ciphers # Enable extra AEAD ciphers
# WARN: These non-standard AEAD ciphers are not officially supported by shadowsocks community # WARN: These non-standard AEAD ciphers are not officially supported by shadowsocks community
aead-cipher-extra = ["shadowsocks-service/aead-cipher-extra"] aead-cipher-extra = ["aead-cipher", "shadowsocks-service/aead-cipher-extra"]
# Enable AEAD 2022 # Enable AEAD 2022
aead-cipher-2022 = ["shadowsocks-service/aead-cipher-2022"] aead-cipher-2022 = ["shadowsocks-service/aead-cipher-2022"]
@@ -248,7 +260,7 @@ jemallocator = { version = "0.5", optional = true }
snmalloc-rs = { version = "0.3", optional = true } snmalloc-rs = { version = "0.3", optional = true }
rpmalloc = { version = "0.2", optional = true } rpmalloc = { version = "0.2", optional = true }
shadowsocks-service = { version = "1.21.2", path = "./crates/shadowsocks-service" } shadowsocks-service = { version = "1.21.3", path = "./crates/shadowsocks-service" }
windows-service = { version = "0.7", optional = true } windows-service = { version = "0.7", optional = true }

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "shadowsocks-service" name = "shadowsocks-service"
version = "1.21.2" version = "1.21.3"
authors = ["Shadowsocks Contributors"] authors = ["Shadowsocks Contributors"]
description = "shadowsocks is a fast tunnel proxy that helps you bypass firewalls." description = "shadowsocks is a fast tunnel proxy that helps you bypass firewalls."
repository = "https://github.com/shadowsocks/shadowsocks-rust" repository = "https://github.com/shadowsocks/shadowsocks-rust"
@@ -15,6 +15,9 @@ rust-version = "1.74"
maintenance = { status = "passively-maintained" } maintenance = { status = "passively-maintained" }
[features] [features]
# WARN: Just for compatible. May be removed in the future releases.
default = ["aead-cipher"]
full = [ full = [
"local", "local",
"server", "server",
@@ -24,6 +27,7 @@ full = [
"local-redir", "local-redir",
"local-tunnel", "local-tunnel",
"local-socks4", "local-socks4",
"aead-cipher",
] ]
# Enable local server # Enable local server
@@ -114,14 +118,20 @@ local-online-config = [
# Users should always avoid using these ciphers in practice # Users should always avoid using these ciphers in practice
stream-cipher = ["shadowsocks/stream-cipher"] stream-cipher = ["shadowsocks/stream-cipher"]
# Enable AEAD ciphers
aead-cipher = ["shadowsocks/aead-cipher"]
# Enable extra AEAD ciphers # Enable extra AEAD ciphers
# WARN: These non-standard AEAD ciphers are not officially supported by shadowsocks community # WARN: These non-standard AEAD ciphers are not officially supported by shadowsocks community
aead-cipher-extra = ["shadowsocks/aead-cipher-extra"] aead-cipher-extra = ["aead-cipher", "shadowsocks/aead-cipher-extra"]
# Enable AEAD 2022 # Enable AEAD 2022
aead-cipher-2022 = ["shadowsocks/aead-cipher-2022"] aead-cipher-2022 = ["shadowsocks/aead-cipher-2022"]
# Enable AEAD 2022 with extra ciphers # Enable AEAD 2022 with extra ciphers
aead-cipher-2022-extra = ["shadowsocks/aead-cipher-2022-extra"] aead-cipher-2022-extra = [
"aead-cipher-2022",
"shadowsocks/aead-cipher-2022-extra",
]
# Enable detection against replay attack # Enable detection against replay attack
security-replay-attack-detect = ["shadowsocks/security-replay-attack-detect"] security-replay-attack-detect = ["shadowsocks/security-replay-attack-detect"]
@@ -205,7 +215,7 @@ serde = { version = "1.0", features = ["derive"] }
json5 = "0.4" json5 = "0.4"
bson = { version = "2.13.0", optional = true } bson = { version = "2.13.0", optional = true }
shadowsocks = { version = "1.21.0", path = "../shadowsocks", default-features = false } shadowsocks = { version = "1.21.1", path = "../shadowsocks", default-features = false }
# Just for the ioctl call macro # Just for the ioctl call macro
[target.'cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "openbsd"))'.dependencies] [target.'cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "openbsd"))'.dependencies]

View File

@@ -473,7 +473,10 @@ impl Manager {
return Ok(AddResponse(err)); return Ok(AddResponse(err));
} }
}, },
#[cfg(feature = "aead-cipher")]
None => self.svr_cfg.method.unwrap_or(CipherKind::CHACHA20_POLY1305), None => self.svr_cfg.method.unwrap_or(CipherKind::CHACHA20_POLY1305),
#[cfg(not(feature = "aead-cipher"))]
None => return Ok(AddResponse("method is required")),
}; };
let mut svr_cfg = ServerConfig::new(addr, req.password.clone(), method); let mut svr_cfg = ServerConfig::new(addr, req.password.clone(), method);

View File

@@ -113,9 +113,9 @@ impl UdpServer {
} }
let assoc_map = match svr_cfg.method().category() { let assoc_map = match svr_cfg.method().category() {
CipherCategory::None | CipherCategory::Aead => { CipherCategory::None => NatMap::Association(create_assoc_map(time_to_live, capacity)),
NatMap::Association(create_assoc_map(time_to_live, capacity)) #[cfg(feature = "aead-cipher")]
} CipherCategory::Aead => NatMap::Association(create_assoc_map(time_to_live, capacity)),
#[cfg(feature = "stream-cipher")] #[cfg(feature = "stream-cipher")]
CipherCategory::Stream => NatMap::Association(create_assoc_map(time_to_live, capacity)), CipherCategory::Stream => NatMap::Association(create_assoc_map(time_to_live, capacity)),
#[cfg(feature = "aead-cipher-2022")] #[cfg(feature = "aead-cipher-2022")]

View File

@@ -15,7 +15,7 @@ rust-version = "1.74"
maintenance = { status = "passively-maintained" } maintenance = { status = "passively-maintained" }
[features] [features]
default = ["hickory-dns"] default = ["hickory-dns", "aead-cipher"]
# Uses Hickory-DNS instead of tokio's builtin DNS resolver # Uses Hickory-DNS instead of tokio's builtin DNS resolver
hickory-dns = ["hickory-resolver", "arc-swap", "notify"] hickory-dns = ["hickory-resolver", "arc-swap", "notify"]
@@ -26,19 +26,22 @@ trust-dns = ["hickory-dns"]
# WARN: Stream Cipher Protocol is proved to be insecure # WARN: Stream Cipher Protocol is proved to be insecure
# https://github.com/shadowsocks/shadowsocks-rust/issues/373 # https://github.com/shadowsocks/shadowsocks-rust/issues/373
# Users should always avoid using these ciphers in practice # Users should always avoid using these ciphers in practice
stream-cipher = ["shadowsocks-crypto/v1-stream"] stream-cipher = ["shadowsocks-crypto/v1-stream", "shadowsocks-crypto/ring"]
# Enable AEAD ciphers
aead-cipher = ["shadowsocks-crypto/v1-aead", "shadowsocks-crypto/ring"]
# Enable extra AEAD ciphers # Enable extra AEAD ciphers
# WARN: These non-standard AEAD ciphers are not officially supported by shadowsocks community # WARN: These non-standard AEAD ciphers are not officially supported by shadowsocks community
aead-cipher-extra = ["shadowsocks-crypto/v1-aead-extra"] aead-cipher-extra = ["aead-cipher", "shadowsocks-crypto/v1-aead-extra"]
# Enable AEAD 2022
aead-cipher-2022 = [ aead-cipher-2022 = [
"shadowsocks-crypto/v2", "shadowsocks-crypto/v2",
"shadowsocks-crypto/ring",
"rand/small_rng", "rand/small_rng",
"aes", "aes",
"lru_time_cache", "lru_time_cache",
] ] # Enable AEAD 2022
# Enable AEAD 2022 with extra ciphers # Enable AEAD 2022 with extra ciphers
aead-cipher-2022-extra = ["aead-cipher-2022", "shadowsocks-crypto/v2-extra"] aead-cipher-2022-extra = ["aead-cipher-2022", "shadowsocks-crypto/v2-extra"]
@@ -88,12 +91,7 @@ notify = { version = "7.0", optional = true }
aes = { version = "0.8", optional = true } aes = { version = "0.8", optional = true }
blake3 = "1.5" blake3 = "1.5"
shadowsocks-crypto = { version = "0.5.8", default-features = false }
[target.'cfg(any(target_arch = "x86_64", target_arch = "aarch64"))'.dependencies]
shadowsocks-crypto = { version = "0.5.4", features = ["ring"] }
[target.'cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))'.dependencies]
shadowsocks-crypto = { version = "0.5.4", features = [] }
[target.'cfg(any(windows, target_os = "linux", target_os = "android", target_os = "freebsd", target_os = "macos", target_os = "ios", target_os = "watchos", target_os = "tvos"))'.dependencies] [target.'cfg(any(windows, target_os = "linux", target_os = "android", target_os = "freebsd", target_os = "macos", target_os = "ios", target_os = "watchos", target_os = "tvos"))'.dependencies]
tokio-tfo = "0.3" tokio-tfo = "0.3"

View File

@@ -16,15 +16,13 @@ use base64::Engine as _;
use byte_string::ByteStr; use byte_string::ByteStr;
use bytes::Bytes; use bytes::Bytes;
use cfg_if::cfg_if; use cfg_if::cfg_if;
use log::error; use log::{error, warn};
use thiserror::Error; use thiserror::Error;
use url::{self, Url}; use url::{self, Url};
use crate::{ #[cfg(any(feature = "stream-cipher", feature = "aead-cipher"))]
crypto::{v1::openssl_bytes_to_key, CipherKind}, use crate::crypto::v1::openssl_bytes_to_key;
plugin::PluginConfig, use crate::{crypto::CipherKind, plugin::PluginConfig, relay::socks5::Address};
relay::socks5::Address,
};
const USER_KEY_BASE64_ENGINE: base64::engine::GeneralPurpose = base64::engine::GeneralPurpose::new( const USER_KEY_BASE64_ENGINE: base64::engine::GeneralPurpose = base64::engine::GeneralPurpose::new(
&base64::alphabet::STANDARD, &base64::alphabet::STANDARD,
@@ -427,9 +425,9 @@ pub struct ServerConfig {
source: ServerSource, source: ServerSource,
} }
#[cfg(feature = "aead-cipher-2022")]
#[inline] #[inline]
fn make_derived_key(method: CipherKind, password: &str, enc_key: &mut [u8]) { fn make_derived_key(method: CipherKind, password: &str, enc_key: &mut [u8]) {
#[cfg(feature = "aead-cipher-2022")]
if method.is_aead_2022() { if method.is_aead_2022() {
// AEAD 2022 password is a base64 form of enc_key // AEAD 2022 password is a base64 form of enc_key
match AEAD2022_PASSWORD_BASE64_ENGINE.decode(password) { match AEAD2022_PASSWORD_BASE64_ENGINE.decode(password) {
@@ -449,15 +447,21 @@ fn make_derived_key(method: CipherKind, password: &str, enc_key: &mut [u8]) {
panic!("{method} password {password} is not base64 encoded, error: {err}"); panic!("{method} password {password} is not base64 encoded, error: {err}");
} }
} }
} else {
openssl_bytes_to_key(password.as_bytes(), enc_key);
}
}
#[cfg(not(feature = "aead-cipher-2022"))] return;
#[inline] }
fn make_derived_key(_method: CipherKind, password: &str, enc_key: &mut [u8]) {
openssl_bytes_to_key(password.as_bytes(), enc_key); cfg_if! {
if #[cfg(any(feature = "stream-cipher", feature = "aead-cipher"))] {
let _ = method;
openssl_bytes_to_key(password.as_bytes(), enc_key);
} else {
// No default implementation.
let _ = password;
let _ = enc_key;
unreachable!("{method} don't know how to make a derived key");
}
}
} }
/// Check if method supports Extended Identity Header /// Check if method supports Extended Identity Header
@@ -478,12 +482,28 @@ where
{ {
let password = password.into(); let password = password.into();
#[cfg(feature = "stream-cipher")] match method {
if method == CipherKind::SS_TABLE { CipherKind::NONE => {
// TABLE cipher doesn't need key derivation. // NONE method's key length is 0
// Reference implemenation: shadowsocks-libev, shadowsocks (Python) debug_assert_eq!(method.key_len(), 0);
let enc_key = password.clone().into_bytes().into_boxed_slice();
return (password, enc_key, Vec::new()); if !password.is_empty() {
warn!("method \"none\" doesn't need a password, which should be set as an empty String, but password.len() = {}", password.len());
}
return (password, Vec::new().into_boxed_slice(), Vec::new());
}
#[cfg(feature = "stream-cipher")]
CipherKind::SS_TABLE => {
// TABLE cipher doesn't need key derivation.
// Reference implemenation: shadowsocks-libev, shadowsocks (Python)
let enc_key = password.clone().into_bytes().into_boxed_slice();
return (password, enc_key, Vec::new());
}
#[allow(unreachable_patterns)]
_ => {}
} }
#[cfg(feature = "aead-cipher-2022")] #[cfg(feature = "aead-cipher-2022")]

View File

@@ -7,7 +7,7 @@ use log::warn;
use crate::{ use crate::{
config::{ReplayAttackPolicy, ServerType}, config::{ReplayAttackPolicy, ServerType},
crypto::{v1::random_iv_or_salt, CipherKind}, crypto::CipherKind,
dns_resolver::DnsResolver, dns_resolver::DnsResolver,
security::replay::ReplayProtector, security::replay::ReplayProtector,
}; };
@@ -50,6 +50,7 @@ impl Context {
/// Check if nonce exist or not /// Check if nonce exist or not
/// ///
/// If not, set into the current bloom filter /// If not, set into the current bloom filter
#[cfg(any(feature = "stream-cipher", feature = "aead-cipher", feature = "aead-cipher-2022"))]
#[inline(always)] #[inline(always)]
fn check_nonce_and_set(&self, method: CipherKind, nonce: &[u8]) -> bool { fn check_nonce_and_set(&self, method: CipherKind, nonce: &[u8]) -> bool {
match self.replay_policy { match self.replay_policy {
@@ -64,7 +65,10 @@ impl Context {
return; return;
} }
#[cfg(any(feature = "stream-cipher", feature = "aead-cipher", feature = "aead-cipher-2022"))]
loop { loop {
use crate::crypto::utils::random_iv_or_salt;
random_iv_or_salt(nonce); random_iv_or_salt(nonce);
// Salt already exists, generate a new one. // Salt already exists, generate a new one.
@@ -74,6 +78,12 @@ impl Context {
break; break;
} }
#[cfg(not(any(feature = "stream-cipher", feature = "aead-cipher", feature = "aead-cipher-2022")))]
if !nonce.is_empty() {
let _ = unique;
panic!("{method} don't know how to generate nonce");
}
} }
/// Check nonce replay /// Check nonce replay

View File

@@ -8,9 +8,11 @@ use std::{
task::{self, Poll}, task::{self, Poll},
}; };
#[cfg(any(feature = "stream-cipher", feature = "aead-cipher", feature = "aead-cipher-2022"))]
use byte_string::ByteStr; use byte_string::ByteStr;
use bytes::Bytes; use bytes::Bytes;
use futures::ready; use futures::ready;
#[cfg(any(feature = "stream-cipher", feature = "aead-cipher", feature = "aead-cipher-2022"))]
use log::trace; use log::trace;
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
@@ -20,6 +22,7 @@ use crate::{
crypto::{CipherCategory, CipherKind}, crypto::{CipherCategory, CipherKind},
}; };
#[cfg(feature = "aead-cipher")]
use super::aead::{DecryptedReader as AeadDecryptedReader, EncryptedWriter as AeadEncryptedWriter}; use super::aead::{DecryptedReader as AeadDecryptedReader, EncryptedWriter as AeadEncryptedWriter};
#[cfg(feature = "aead-cipher-2022")] #[cfg(feature = "aead-cipher-2022")]
use super::aead_2022::{DecryptedReader as Aead2022DecryptedReader, EncryptedWriter as Aead2022EncryptedWriter}; use super::aead_2022::{DecryptedReader as Aead2022DecryptedReader, EncryptedWriter as Aead2022EncryptedWriter};
@@ -34,6 +37,7 @@ pub enum ProtocolError {
#[cfg(feature = "stream-cipher")] #[cfg(feature = "stream-cipher")]
#[error(transparent)] #[error(transparent)]
StreamError(#[from] super::stream::ProtocolError), StreamError(#[from] super::stream::ProtocolError),
#[cfg(feature = "aead-cipher")]
#[error(transparent)] #[error(transparent)]
AeadError(#[from] super::aead::ProtocolError), AeadError(#[from] super::aead::ProtocolError),
#[cfg(feature = "aead-cipher-2022")] #[cfg(feature = "aead-cipher-2022")]
@@ -50,6 +54,7 @@ impl From<ProtocolError> for io::Error {
ProtocolError::IoError(err) => err, ProtocolError::IoError(err) => err,
#[cfg(feature = "stream-cipher")] #[cfg(feature = "stream-cipher")]
ProtocolError::StreamError(err) => err.into(), ProtocolError::StreamError(err) => err.into(),
#[cfg(feature = "aead-cipher")]
ProtocolError::AeadError(err) => err.into(), ProtocolError::AeadError(err) => err.into(),
#[cfg(feature = "aead-cipher-2022")] #[cfg(feature = "aead-cipher-2022")]
ProtocolError::Aead2022Error(err) => err.into(), ProtocolError::Aead2022Error(err) => err.into(),
@@ -70,6 +75,7 @@ pub enum StreamType {
#[allow(clippy::large_enum_variant)] #[allow(clippy::large_enum_variant)]
pub enum DecryptedReader { pub enum DecryptedReader {
None, None,
#[cfg(feature = "aead-cipher")]
Aead(AeadDecryptedReader), Aead(AeadDecryptedReader),
#[cfg(feature = "stream-cipher")] #[cfg(feature = "stream-cipher")]
Stream(StreamDecryptedReader), Stream(StreamDecryptedReader),
@@ -98,8 +104,13 @@ impl DecryptedReader {
match method.category() { match method.category() {
#[cfg(feature = "stream-cipher")] #[cfg(feature = "stream-cipher")]
CipherCategory::Stream => DecryptedReader::Stream(StreamDecryptedReader::new(method, key)), CipherCategory::Stream => DecryptedReader::Stream(StreamDecryptedReader::new(method, key)),
#[cfg(feature = "aead-cipher")]
CipherCategory::Aead => DecryptedReader::Aead(AeadDecryptedReader::new(method, key)), CipherCategory::Aead => DecryptedReader::Aead(AeadDecryptedReader::new(method, key)),
CipherCategory::None => DecryptedReader::None, CipherCategory::None => {
let _ = method;
let _ = key;
DecryptedReader::None
}
#[cfg(feature = "aead-cipher-2022")] #[cfg(feature = "aead-cipher-2022")]
CipherCategory::Aead2022 => DecryptedReader::Aead2022(Aead2022DecryptedReader::with_user_manager( CipherCategory::Aead2022 => DecryptedReader::Aead2022(Aead2022DecryptedReader::with_user_manager(
stream_ty, stream_ty,
@@ -127,10 +138,14 @@ impl DecryptedReader {
DecryptedReader::Stream(ref mut reader) => { DecryptedReader::Stream(ref mut reader) => {
reader.poll_read_decrypted(cx, context, stream, buf).map_err(Into::into) reader.poll_read_decrypted(cx, context, stream, buf).map_err(Into::into)
} }
#[cfg(feature = "aead-cipher")]
DecryptedReader::Aead(ref mut reader) => { DecryptedReader::Aead(ref mut reader) => {
reader.poll_read_decrypted(cx, context, stream, buf).map_err(Into::into) reader.poll_read_decrypted(cx, context, stream, buf).map_err(Into::into)
} }
DecryptedReader::None => Pin::new(stream).poll_read(cx, buf).map_err(Into::into), DecryptedReader::None => {
let _ = context;
Pin::new(stream).poll_read(cx, buf).map_err(Into::into)
}
#[cfg(feature = "aead-cipher-2022")] #[cfg(feature = "aead-cipher-2022")]
DecryptedReader::Aead2022(ref mut reader) => { DecryptedReader::Aead2022(ref mut reader) => {
reader.poll_read_decrypted(cx, context, stream, buf).map_err(Into::into) reader.poll_read_decrypted(cx, context, stream, buf).map_err(Into::into)
@@ -143,6 +158,7 @@ impl DecryptedReader {
match *self { match *self {
#[cfg(feature = "stream-cipher")] #[cfg(feature = "stream-cipher")]
DecryptedReader::Stream(ref reader) => reader.iv(), DecryptedReader::Stream(ref reader) => reader.iv(),
#[cfg(feature = "aead-cipher")]
DecryptedReader::Aead(ref reader) => reader.salt(), DecryptedReader::Aead(ref reader) => reader.salt(),
DecryptedReader::None => None, DecryptedReader::None => None,
#[cfg(feature = "aead-cipher-2022")] #[cfg(feature = "aead-cipher-2022")]
@@ -155,6 +171,7 @@ impl DecryptedReader {
match *self { match *self {
#[cfg(feature = "stream-cipher")] #[cfg(feature = "stream-cipher")]
DecryptedReader::Stream(..) => None, DecryptedReader::Stream(..) => None,
#[cfg(feature = "aead-cipher")]
DecryptedReader::Aead(..) => None, DecryptedReader::Aead(..) => None,
DecryptedReader::None => None, DecryptedReader::None => None,
#[cfg(feature = "aead-cipher-2022")] #[cfg(feature = "aead-cipher-2022")]
@@ -167,6 +184,7 @@ impl DecryptedReader {
match *self { match *self {
#[cfg(feature = "stream-cipher")] #[cfg(feature = "stream-cipher")]
DecryptedReader::Stream(..) => None, DecryptedReader::Stream(..) => None,
#[cfg(feature = "aead-cipher")]
DecryptedReader::Aead(..) => None, DecryptedReader::Aead(..) => None,
DecryptedReader::None => None, DecryptedReader::None => None,
#[cfg(feature = "aead-cipher-2022")] #[cfg(feature = "aead-cipher-2022")]
@@ -178,6 +196,7 @@ impl DecryptedReader {
match *self { match *self {
#[cfg(feature = "stream-cipher")] #[cfg(feature = "stream-cipher")]
DecryptedReader::Stream(ref reader) => reader.handshaked(), DecryptedReader::Stream(ref reader) => reader.handshaked(),
#[cfg(feature = "aead-cipher")]
DecryptedReader::Aead(ref reader) => reader.handshaked(), DecryptedReader::Aead(ref reader) => reader.handshaked(),
DecryptedReader::None => true, DecryptedReader::None => true,
#[cfg(feature = "aead-cipher-2022")] #[cfg(feature = "aead-cipher-2022")]
@@ -189,6 +208,7 @@ impl DecryptedReader {
/// Writer for writing encrypted data stream into shadowsocks' tunnel /// Writer for writing encrypted data stream into shadowsocks' tunnel
pub enum EncryptedWriter { pub enum EncryptedWriter {
None, None,
#[cfg(feature = "aead-cipher")]
Aead(AeadEncryptedWriter), Aead(AeadEncryptedWriter),
#[cfg(feature = "stream-cipher")] #[cfg(feature = "stream-cipher")]
Stream(StreamEncryptedWriter), Stream(StreamEncryptedWriter),
@@ -206,8 +226,13 @@ impl EncryptedWriter {
match method.category() { match method.category() {
#[cfg(feature = "stream-cipher")] #[cfg(feature = "stream-cipher")]
CipherCategory::Stream => EncryptedWriter::Stream(StreamEncryptedWriter::new(method, key, nonce)), CipherCategory::Stream => EncryptedWriter::Stream(StreamEncryptedWriter::new(method, key, nonce)),
#[cfg(feature = "aead-cipher")]
CipherCategory::Aead => EncryptedWriter::Aead(AeadEncryptedWriter::new(method, key, nonce)), CipherCategory::Aead => EncryptedWriter::Aead(AeadEncryptedWriter::new(method, key, nonce)),
CipherCategory::None => EncryptedWriter::None, CipherCategory::None => {
let _ = key;
let _ = nonce;
EncryptedWriter::None
}
#[cfg(feature = "aead-cipher-2022")] #[cfg(feature = "aead-cipher-2022")]
CipherCategory::Aead2022 => { CipherCategory::Aead2022 => {
EncryptedWriter::Aead2022(Aead2022EncryptedWriter::new(stream_ty, method, key, nonce)) EncryptedWriter::Aead2022(Aead2022EncryptedWriter::new(stream_ty, method, key, nonce))
@@ -231,8 +256,13 @@ impl EncryptedWriter {
match method.category() { match method.category() {
#[cfg(feature = "stream-cipher")] #[cfg(feature = "stream-cipher")]
CipherCategory::Stream => EncryptedWriter::Stream(StreamEncryptedWriter::new(method, key, nonce)), CipherCategory::Stream => EncryptedWriter::Stream(StreamEncryptedWriter::new(method, key, nonce)),
#[cfg(feature = "aead-cipher")]
CipherCategory::Aead => EncryptedWriter::Aead(AeadEncryptedWriter::new(method, key, nonce)), CipherCategory::Aead => EncryptedWriter::Aead(AeadEncryptedWriter::new(method, key, nonce)),
CipherCategory::None => EncryptedWriter::None, CipherCategory::None => {
let _ = key;
let _ = nonce;
EncryptedWriter::None
}
#[cfg(feature = "aead-cipher-2022")] #[cfg(feature = "aead-cipher-2022")]
CipherCategory::Aead2022 => EncryptedWriter::Aead2022(Aead2022EncryptedWriter::with_identity( CipherCategory::Aead2022 => EncryptedWriter::Aead2022(Aead2022EncryptedWriter::with_identity(
stream_ty, stream_ty,
@@ -258,6 +288,7 @@ impl EncryptedWriter {
match *self { match *self {
#[cfg(feature = "stream-cipher")] #[cfg(feature = "stream-cipher")]
EncryptedWriter::Stream(ref mut writer) => writer.poll_write_encrypted(cx, stream, buf).map_err(Into::into), EncryptedWriter::Stream(ref mut writer) => writer.poll_write_encrypted(cx, stream, buf).map_err(Into::into),
#[cfg(feature = "aead-cipher")]
EncryptedWriter::Aead(ref mut writer) => writer.poll_write_encrypted(cx, stream, buf).map_err(Into::into), EncryptedWriter::Aead(ref mut writer) => writer.poll_write_encrypted(cx, stream, buf).map_err(Into::into),
EncryptedWriter::None => Pin::new(stream).poll_write(cx, buf).map_err(Into::into), EncryptedWriter::None => Pin::new(stream).poll_write(cx, buf).map_err(Into::into),
#[cfg(feature = "aead-cipher-2022")] #[cfg(feature = "aead-cipher-2022")]
@@ -272,6 +303,7 @@ impl EncryptedWriter {
match *self { match *self {
#[cfg(feature = "stream-cipher")] #[cfg(feature = "stream-cipher")]
EncryptedWriter::Stream(ref writer) => writer.iv(), EncryptedWriter::Stream(ref writer) => writer.iv(),
#[cfg(feature = "aead-cipher")]
EncryptedWriter::Aead(ref writer) => writer.salt(), EncryptedWriter::Aead(ref writer) => writer.salt(),
EncryptedWriter::None => &[], EncryptedWriter::None => &[],
#[cfg(feature = "aead-cipher-2022")] #[cfg(feature = "aead-cipher-2022")]
@@ -355,6 +387,7 @@ impl<S> CryptoStream<S> {
let prev_len = match category { let prev_len = match category {
#[cfg(feature = "stream-cipher")] #[cfg(feature = "stream-cipher")]
CipherCategory::Stream => method.iv_len(), CipherCategory::Stream => method.iv_len(),
#[cfg(feature = "aead-cipher")]
CipherCategory::Aead => method.salt_len(), CipherCategory::Aead => method.salt_len(),
CipherCategory::None => 0, CipherCategory::None => 0,
#[cfg(feature = "aead-cipher-2022")] #[cfg(feature = "aead-cipher-2022")]
@@ -369,13 +402,18 @@ impl<S> CryptoStream<S> {
trace!("generated Stream cipher IV {:?}", ByteStr::new(&local_iv)); trace!("generated Stream cipher IV {:?}", ByteStr::new(&local_iv));
local_iv local_iv
} }
#[cfg(feature = "aead-cipher")]
CipherCategory::Aead => { CipherCategory::Aead => {
let mut local_salt = vec![0u8; prev_len]; let mut local_salt = vec![0u8; prev_len];
context.generate_nonce(method, &mut local_salt, true); context.generate_nonce(method, &mut local_salt, true);
trace!("generated AEAD cipher salt {:?}", ByteStr::new(&local_salt)); trace!("generated AEAD cipher salt {:?}", ByteStr::new(&local_salt));
local_salt local_salt
} }
CipherCategory::None => Vec::new(), CipherCategory::None => {
debug_assert_eq!(prev_len, 0);
let _ = context;
Vec::new()
}
#[cfg(feature = "aead-cipher-2022")] #[cfg(feature = "aead-cipher-2022")]
CipherCategory::Aead2022 => { CipherCategory::Aead2022 => {
// AEAD-2022 has a request-salt in respond header, so the generated salt doesn't need to be remembered. // AEAD-2022 has a request-salt in respond header, so the generated salt doesn't need to be remembered.

View File

@@ -5,6 +5,7 @@ pub use self::{
proxy_stream::{ProxyClientStream, ProxyServerStream}, proxy_stream::{ProxyClientStream, ProxyServerStream},
}; };
#[cfg(feature = "aead-cipher")]
mod aead; mod aead;
#[cfg(feature = "aead-cipher-2022")] #[cfg(feature = "aead-cipher-2022")]
mod aead_2022; mod aead_2022;

View File

@@ -28,7 +28,11 @@ pub enum TcpRequestHeader {
impl TcpRequestHeader { impl TcpRequestHeader {
pub async fn read_from<R: AsyncRead + Unpin>(method: CipherKind, reader: &mut R) -> io::Result<TcpRequestHeader> { pub async fn read_from<R: AsyncRead + Unpin>(method: CipherKind, reader: &mut R) -> io::Result<TcpRequestHeader> {
match method.category() { match method.category() {
CipherCategory::None | CipherCategory::Aead => Ok(TcpRequestHeader::Stream( CipherCategory::None => Ok(TcpRequestHeader::Stream(
StreamTcpRequestHeader::read_from(reader).await?,
)),
#[cfg(feature = "aead-cipher")]
CipherCategory::Aead => Ok(TcpRequestHeader::Stream(
StreamTcpRequestHeader::read_from(reader).await?, StreamTcpRequestHeader::read_from(reader).await?,
)), )),
#[cfg(feature = "stream-cipher")] #[cfg(feature = "stream-cipher")]

View File

@@ -155,6 +155,7 @@ where
fn plain_read_buffer_size(method: CipherKind) -> usize { fn plain_read_buffer_size(method: CipherKind) -> usize {
match method.category() { match method.category() {
#[cfg(feature = "aead-cipher")]
CipherCategory::Aead => super::aead::MAX_PACKET_SIZE, CipherCategory::Aead => super::aead::MAX_PACKET_SIZE,
#[cfg(feature = "stream-cipher")] #[cfg(feature = "stream-cipher")]
CipherCategory::Stream => 1 << 14, CipherCategory::Stream => 1 << 14,

View File

@@ -30,17 +30,16 @@ use crate::{
relay::socks5::{Address, Error as Socks5Error}, relay::socks5::{Address, Error as Socks5Error},
}; };
#[cfg(feature = "aead-cipher")]
use super::aead::{decrypt_payload_aead, encrypt_payload_aead};
#[cfg(feature = "aead-cipher-2022")] #[cfg(feature = "aead-cipher-2022")]
use super::aead_2022::{ use super::aead_2022::{
decrypt_client_payload_aead_2022, decrypt_server_payload_aead_2022, encrypt_client_payload_aead_2022, decrypt_client_payload_aead_2022, decrypt_server_payload_aead_2022, encrypt_client_payload_aead_2022,
encrypt_server_payload_aead_2022, encrypt_server_payload_aead_2022,
}; };
use super::options::UdpSocketControlData;
#[cfg(feature = "stream-cipher")] #[cfg(feature = "stream-cipher")]
use super::stream::{decrypt_payload_stream, encrypt_payload_stream}; use super::stream::{decrypt_payload_stream, encrypt_payload_stream};
use super::{
aead::{decrypt_payload_aead, encrypt_payload_aead},
options::UdpSocketControlData,
};
/// UDP shadowsocks protocol errors /// UDP shadowsocks protocol errors
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
@@ -50,6 +49,7 @@ pub enum ProtocolError {
#[cfg(feature = "stream-cipher")] #[cfg(feature = "stream-cipher")]
#[error(transparent)] #[error(transparent)]
StreamError(#[from] super::stream::ProtocolError), StreamError(#[from] super::stream::ProtocolError),
#[cfg(feature = "aead-cipher")]
#[error(transparent)] #[error(transparent)]
AeadError(#[from] super::aead::ProtocolError), AeadError(#[from] super::aead::ProtocolError),
#[cfg(feature = "aead-cipher-2022")] #[cfg(feature = "aead-cipher-2022")]
@@ -74,6 +74,8 @@ pub fn encrypt_client_payload(
) { ) {
match method.category() { match method.category() {
CipherCategory::None => { CipherCategory::None => {
let _ = context;
let _ = key;
let _ = control; let _ = control;
let _ = identity_keys; let _ = identity_keys;
dst.reserve(addr.serialized_len() + payload.len()); dst.reserve(addr.serialized_len() + payload.len());
@@ -86,6 +88,7 @@ pub fn encrypt_client_payload(
let _ = identity_keys; let _ = identity_keys;
encrypt_payload_stream(context, method, key, addr, payload, dst) encrypt_payload_stream(context, method, key, addr, payload, dst)
} }
#[cfg(feature = "aead-cipher")]
CipherCategory::Aead => { CipherCategory::Aead => {
let _ = control; let _ = control;
let _ = identity_keys; let _ = identity_keys;
@@ -110,6 +113,8 @@ pub fn encrypt_server_payload(
) { ) {
match method.category() { match method.category() {
CipherCategory::None => { CipherCategory::None => {
let _ = context;
let _ = key;
let _ = control; let _ = control;
dst.reserve(addr.serialized_len() + payload.len()); dst.reserve(addr.serialized_len() + payload.len());
addr.write_to_buf(dst); addr.write_to_buf(dst);
@@ -120,6 +125,7 @@ pub fn encrypt_server_payload(
let _ = control; let _ = control;
encrypt_payload_stream(context, method, key, addr, payload, dst) encrypt_payload_stream(context, method, key, addr, payload, dst)
} }
#[cfg(feature = "aead-cipher")]
CipherCategory::Aead => { CipherCategory::Aead => {
let _ = control; let _ = control;
encrypt_payload_aead(context, method, key, addr, payload, dst) encrypt_payload_aead(context, method, key, addr, payload, dst)
@@ -139,6 +145,8 @@ pub fn decrypt_client_payload(
) -> ProtocolResult<(usize, Address, Option<UdpSocketControlData>)> { ) -> ProtocolResult<(usize, Address, Option<UdpSocketControlData>)> {
match method.category() { match method.category() {
CipherCategory::None => { CipherCategory::None => {
let _ = context;
let _ = key;
let _ = user_manager; let _ = user_manager;
let mut cur = Cursor::new(payload); let mut cur = Cursor::new(payload);
match Address::read_cursor(&mut cur) { match Address::read_cursor(&mut cur) {
@@ -158,6 +166,7 @@ pub fn decrypt_client_payload(
.map(|(n, a)| (n, a, None)) .map(|(n, a)| (n, a, None))
.map_err(Into::into) .map_err(Into::into)
} }
#[cfg(feature = "aead-cipher")]
CipherCategory::Aead => { CipherCategory::Aead => {
let _ = user_manager; let _ = user_manager;
decrypt_payload_aead(context, method, key, payload) decrypt_payload_aead(context, method, key, payload)
@@ -180,6 +189,9 @@ pub fn decrypt_server_payload(
) -> ProtocolResult<(usize, Address, Option<UdpSocketControlData>)> { ) -> ProtocolResult<(usize, Address, Option<UdpSocketControlData>)> {
match method.category() { match method.category() {
CipherCategory::None => { CipherCategory::None => {
let _ = context;
let _ = key;
let mut cur = Cursor::new(payload); let mut cur = Cursor::new(payload);
match Address::read_cursor(&mut cur) { match Address::read_cursor(&mut cur) {
Ok(address) => { Ok(address) => {
@@ -195,6 +207,7 @@ pub fn decrypt_server_payload(
CipherCategory::Stream => decrypt_payload_stream(context, method, key, payload) CipherCategory::Stream => decrypt_payload_stream(context, method, key, payload)
.map(|(n, a)| (n, a, None)) .map(|(n, a)| (n, a, None))
.map_err(Into::into), .map_err(Into::into),
#[cfg(feature = "aead-cipher")]
CipherCategory::Aead => decrypt_payload_aead(context, method, key, payload) CipherCategory::Aead => decrypt_payload_aead(context, method, key, payload)
.map(|(n, a)| (n, a, None)) .map(|(n, a)| (n, a, None))
.map_err(Into::into), .map_err(Into::into),

View File

@@ -52,6 +52,7 @@ use std::time::Duration;
pub use self::proxy_socket::ProxySocket; pub use self::proxy_socket::ProxySocket;
pub use compat::{DatagramReceive, DatagramReceiveExt, DatagramSend, DatagramSendExt, DatagramSocket}; pub use compat::{DatagramReceive, DatagramReceiveExt, DatagramSend, DatagramSendExt, DatagramSocket};
#[cfg(feature = "aead-cipher")]
mod aead; mod aead;
#[cfg(feature = "aead-cipher-2022")] #[cfg(feature = "aead-cipher-2022")]
mod aead_2022; mod aead_2022;

View File

@@ -151,6 +151,7 @@ async fn tcp_tunnel_example(
Ok(()) Ok(())
} }
#[cfg(feature = "aead-cipher")]
#[tokio::test] #[tokio::test]
async fn tcp_tunnel_aead() { async fn tcp_tunnel_aead() {
let _ = env_logger::try_init(); let _ = env_logger::try_init();
@@ -180,7 +181,7 @@ async fn tcp_tunnel_none() {
let server_addr = "127.0.0.1:33001".parse::<SocketAddr>().unwrap(); let server_addr = "127.0.0.1:33001".parse::<SocketAddr>().unwrap();
let local_addr = "127.0.0.1:33101".parse::<SocketAddr>().unwrap(); let local_addr = "127.0.0.1:33101".parse::<SocketAddr>().unwrap();
tcp_tunnel_example(server_addr, local_addr, "p$p", CipherKind::NONE) tcp_tunnel_example(server_addr, local_addr, "", CipherKind::NONE)
.await .await
.unwrap(); .unwrap();
} }

View File

@@ -32,7 +32,7 @@ use tokio::{
async fn tcp_tunnel_tfo() { async fn tcp_tunnel_tfo() {
let _ = env_logger::try_init(); let _ = env_logger::try_init();
let svr_cfg = ServerConfig::new(("127.0.0.1", 41000), "?", CipherKind::NONE); let svr_cfg = ServerConfig::new(("127.0.0.1", 41000), "", CipherKind::NONE);
let svr_cfg_client = svr_cfg.clone(); let svr_cfg_client = svr_cfg.clone();
tokio::spawn(async move { tokio::spawn(async move {

View File

@@ -136,6 +136,7 @@ async fn udp_tunnel_echo(
Ok(()) Ok(())
} }
#[cfg(feature = "aead-cipher")]
#[tokio::test] #[tokio::test]
async fn udp_tunnel_aead() { async fn udp_tunnel_aead() {
let _ = env_logger::try_init(); let _ = env_logger::try_init();

250
shadowsocks-rust/deny.toml Normal file
View File

@@ -0,0 +1,250 @@
# This template contains all of the possible sections and their default values
# Note that all fields that take a lint level have these possible values:
# * deny - An error will be produced and the check will fail
# * warn - A warning will be produced, but the check will not fail
# * allow - No warning or error will be produced, though in some cases a note
# will be
# The values provided in this template are the default values that will be used
# when any section or field is not specified in your own configuration
# Root options
# The graph table configures how the dependency graph is constructed and thus
# which crates the checks are performed against
[graph]
# If 1 or more target triples (and optionally, target_features) are specified,
# only the specified targets will be checked when running `cargo deny check`.
# This means, if a particular package is only ever used as a target specific
# dependency, such as, for example, the `nix` crate only being used via the
# `target_family = "unix"` configuration, that only having windows targets in
# this list would mean the nix crate, as well as any of its exclusive
# dependencies not shared by any other crates, would be ignored, as the target
# list here is effectively saying which targets you are building for.
targets = [
# The triple can be any string, but only the target triples built in to
# rustc (as of 1.40) can be checked against actual config expressions
#"x86_64-unknown-linux-musl",
# You can also specify which target_features you promise are enabled for a
# particular target. target_features are currently not validated against
# the actual valid features supported by the target architecture.
#{ triple = "wasm32-unknown-unknown", features = ["atomics"] },
]
# When creating the dependency graph used as the source of truth when checks are
# executed, this field can be used to prune crates from the graph, removing them
# from the view of cargo-deny. This is an extremely heavy hammer, as if a crate
# is pruned from the graph, all of its dependencies will also be pruned unless
# they are connected to another crate in the graph that hasn't been pruned,
# so it should be used with care. The identifiers are [Package ID Specifications]
# (https://doc.rust-lang.org/cargo/reference/pkgid-spec.html)
#exclude = []
# If true, metadata will be collected with `--all-features`. Note that this can't
# be toggled off if true, if you want to conditionally enable `--all-features` it
# is recommended to pass `--all-features` on the cmd line instead
all-features = false
# If true, metadata will be collected with `--no-default-features`. The same
# caveat with `all-features` applies
no-default-features = false
# If set, these feature will be enabled when collecting metadata. If `--features`
# is specified on the cmd line they will take precedence over this option.
features = ["full-extra"]
# The output table provides options for how/if diagnostics are outputted
[output]
# When outputting inclusion graphs in diagnostics that include features, this
# option can be used to specify the depth at which feature edges will be added.
# This option is included since the graphs can be quite large and the addition
# of features from the crate(s) to all of the graph roots can be far too verbose.
# This option can be overridden via `--feature-depth` on the cmd line
feature-depth = 1
# This section is considered when running `cargo deny check advisories`
# More documentation for the advisories section can be found here:
# https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html
[advisories]
# The path where the advisory databases are cloned/fetched into
#db-path = "$CARGO_HOME/advisory-dbs"
# The url(s) of the advisory databases to use
#db-urls = ["https://github.com/rustsec/advisory-db"]
# A list of advisory IDs to ignore. Note that ignored advisories will still
# output a note when they are encountered.
ignore = [
#"RUSTSEC-0000-0000",
#{ id = "RUSTSEC-0000-0000", reason = "you can specify a reason the advisory is ignored" },
#"a-crate-that-is-yanked@0.1.1", # you can also ignore yanked crate versions if you wish
#{ crate = "a-crate-that-is-yanked@0.1.1", reason = "you can specify why you are ignoring the yanked crate" },
]
# If this is true, then cargo deny will use the git executable to fetch advisory database.
# If this is false, then it uses a built-in git library.
# Setting this to true can be helpful if you have special authentication requirements that cargo-deny does not support.
# See Git Authentication for more information about setting up git authentication.
#git-fetch-with-cli = true
# This section is considered when running `cargo deny check licenses`
# More documentation for the licenses section can be found here:
# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html
[licenses]
# List of explicitly allowed licenses
# See https://spdx.org/licenses/ for list of possible licenses
# [possible values: any SPDX 3.11 short identifier (+ optional exception)].
allow = [
"MIT",
"Apache-2.0",
"Apache-2.0 WITH LLVM-exception",
"ISC",
"BSD-2-Clause",
"BSD-3-Clause",
"Unicode-3.0",
"Unicode-DFS-2016",
"MPL-2.0",
"CC0-1.0",
"0BSD",
]
# The confidence threshold for detecting a license from license text.
# The higher the value, the more closely the license text must be to the
# canonical license text of a valid SPDX license file.
# [possible values: any between 0.0 and 1.0].
confidence-threshold = 0.8
# Allow 1 or more licenses on a per-crate basis, so that particular licenses
# aren't accepted for every possible crate as with the normal allow list
exceptions = [
# Each entry is the crate and version constraint, and its specific allow
# list
#{ allow = ["Zlib"], crate = "adler32" },
{ allow = ["WTFPL"], crate = "tun2" },
{ allow = ["LicenseRef-ring"], crate = "ring" },
]
# Some crates don't have (easily) machine readable licensing information,
# adding a clarification entry for it allows you to manually specify the
# licensing information
#[[licenses.clarify]]
# The package spec the clarification applies to
#crate = "ring"
# The SPDX expression for the license requirements of the crate
#expression = "MIT AND ISC AND OpenSSL"
# One or more files in the crate's source used as the "source of truth" for
# the license expression. If the contents match, the clarification will be used
# when running the license check, otherwise the clarification will be ignored
# and the crate will be checked normally, which may produce warnings or errors
# depending on the rest of your configuration
#license-files = [
# Each entry is a crate relative path, and the (opaque) hash of its contents
#{ path = "LICENSE", hash = 0xbd0eed23 }
#]
[[licenses.clarify]]
name = "ring"
expression = "LicenseRef-ring"
license-files = [{ path = "LICENSE", hash = 0xbd0eed23 }]
[licenses.private]
# If true, ignores workspace crates that aren't published, or are only
# published to private registries.
# To see how to mark a crate as unpublished (to the official registry),
# visit https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field.
ignore = false
# One or more private registries that you might publish crates to, if a crate
# is only published to private registries, and ignore is true, the crate will
# not have its license(s) checked
registries = [
#"https://sekretz.com/registry
]
# This section is considered when running `cargo deny check bans`.
# More documentation about the 'bans' section can be found here:
# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html
[bans]
# Lint level for when multiple versions of the same crate are detected
multiple-versions = "warn"
# Lint level for when a crate version requirement is `*`
wildcards = "deny"
# The graph highlighting used when creating dotgraphs for crates
# with multiple versions
# * lowest-version - The path to the lowest versioned duplicate is highlighted
# * simplest-path - The path to the version with the fewest edges is highlighted
# * all - Both lowest-version and simplest-path are used
highlight = "all"
# The default lint level for `default` features for crates that are members of
# the workspace that is being checked. This can be overridden by allowing/denying
# `default` on a crate-by-crate basis if desired.
workspace-default-features = "allow"
# The default lint level for `default` features for external crates that are not
# members of the workspace. This can be overridden by allowing/denying `default`
# on a crate-by-crate basis if desired.
external-default-features = "allow"
# List of crates that are allowed. Use with care!
allow = [
#"ansi_term@0.11.0",
#{ crate = "ansi_term@0.11.0", reason = "you can specify a reason it is allowed" },
]
# List of crates to deny
deny = [
#"ansi_term@0.11.0",
#{ crate = "ansi_term@0.11.0", reason = "you can specify a reason it is banned" },
# Wrapper crates can optionally be specified to allow the crate when it
# is a direct dependency of the otherwise banned crate
#{ crate = "ansi_term@0.11.0", wrappers = ["this-crate-directly-depends-on-ansi_term"] },
]
# List of features to allow/deny
# Each entry the name of a crate and a version range. If version is
# not specified, all versions will be matched.
#[[bans.features]]
#crate = "reqwest"
# Features to not allow
#deny = ["json"]
# Features to allow
#allow = [
# "rustls",
# "__rustls",
# "__tls",
# "hyper-rustls",
# "rustls",
# "rustls-pemfile",
# "rustls-tls-webpki-roots",
# "tokio-rustls",
# "webpki-roots",
#]
# If true, the allowed features must exactly match the enabled feature set. If
# this is set there is no point setting `deny`
#exact = true
# Certain crates/versions that will be skipped when doing duplicate detection.
skip = [
#"ansi_term@0.11.0",
#{ crate = "ansi_term@0.11.0", reason = "you can specify a reason why it can't be updated/removed" },
]
# Similarly to `skip` allows you to skip certain crates during duplicate
# detection. Unlike skip, it also includes the entire tree of transitive
# dependencies starting at the specified crate, up to a certain depth, which is
# by default infinite.
skip-tree = [
#"ansi_term@0.11.0", # will be skipped along with _all_ of its direct and transitive dependencies
#{ crate = "ansi_term@0.11.0", depth = 20 },
]
# This section is considered when running `cargo deny check sources`.
# More documentation about the 'sources' section can be found here:
# https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html
[sources]
# Lint level for what to happen when a crate from a crate registry that is not
# in the allow list is encountered
unknown-registry = "warn"
# Lint level for what to happen when a crate from a git repository that is not
# in the allow list is encountered
unknown-git = "warn"
# List of URLs for allowed crate registries. Defaults to the crates.io index
# if not specified. If it is specified but empty, no registries are allowed.
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
# List of URLs for allowed Git repositories
allow-git = []
[sources.allow-org]
# github.com organizations to allow git sources for
github = []
# gitlab.com organizations to allow git sources for
gitlab = []
# bitbucket.org organizations to allow git sources for
bitbucket = []

View File

@@ -155,7 +155,16 @@ upload_macos_dmg:
cp SFM.dmg "SFM-${VERSION}-universal.dmg" && \ cp SFM.dmg "SFM-${VERSION}-universal.dmg" && \
ghr --replace --draft --prerelease "v${VERSION}" "SFM-${VERSION}-universal.dmg" ghr --replace --draft --prerelease "v${VERSION}" "SFM-${VERSION}-universal.dmg"
release_macos_standalone: build_macos_standalone build_macos_dmg upload_macos_dmg upload_macos_dsyms:
pushd ../sing-box-for-apple/build/SFM.System.xcarchive && \
zip -r SFM.dSYMs.zip dSYMs && \
mv SFM.dSYMs.zip ../../../sing-box/dist/SFM && \
popd && \
cd dist/SFM && \
cp SFM.dSYMs.zip "SFM-${VERSION}-universal.dSYMs.zip" && \
ghr --replace --draft --prerelease "v${VERSION}" "SFM-${VERSION}-universal.dSYMs.zip"
release_macos_standalone: build_macos_standalone build_macos_dmg upload_macos_dmg upload_macos_dsyms
build_tvos: build_tvos:
cd ../sing-box-for-apple && \ cd ../sing-box-for-apple && \

View File

@@ -81,7 +81,7 @@ func NewDefault(router adapter.Router, options option.DialerOptions) (*DefaultDi
if options.ConnectTimeout != 0 { if options.ConnectTimeout != 0 {
dialer.Timeout = time.Duration(options.ConnectTimeout) dialer.Timeout = time.Duration(options.ConnectTimeout)
} else { } else {
dialer.Timeout = C.TCPTimeout dialer.Timeout = C.TCPConnectTimeout
} }
// TODO: Add an option to customize the keep alive period // TODO: Add an option to customize the keep alive period
dialer.KeepAlive = C.TCPKeepAliveInitial dialer.KeepAlive = C.TCPKeepAliveInitial

View File

@@ -8,6 +8,7 @@ import (
"sync" "sync"
"time" "time"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
M "github.com/sagernet/sing/common/metadata" M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network" N "github.com/sagernet/sing/common/network"
@@ -113,6 +114,7 @@ func URLTest(ctx context.Context, link string, detour N.Dialer) (t uint16, err e
CheckRedirect: func(req *http.Request, via []*http.Request) error { CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse return http.ErrUseLastResponse
}, },
Timeout: C.TCPTimeout,
} }
defer client.CloseIdleConnections() defer client.CloseIdleConnections()
resp, err := client.Do(req.WithContext(ctx)) resp, err := client.Do(req.WithContext(ctx))

View File

@@ -5,7 +5,8 @@ import "time"
const ( const (
TCPKeepAliveInitial = 10 * time.Minute TCPKeepAliveInitial = 10 * time.Minute
TCPKeepAliveInterval = 75 * time.Second TCPKeepAliveInterval = 75 * time.Second
TCPTimeout = 5 * time.Second TCPConnectTimeout = 5 * time.Second
TCPTimeout = 15 * time.Second
ReadPayloadTimeout = 300 * time.Millisecond ReadPayloadTimeout = 300 * time.Millisecond
DNSTimeout = 10 * time.Second DNSTimeout = 10 * time.Second
QUICTimeout = 30 * time.Second QUICTimeout = 30 * time.Second

View File

@@ -2,6 +2,10 @@
icon: material/alert-decagram icon: material/alert-decagram
--- ---
#### 1.11.0-alpha.5
* Fixes and improvements
#### 1.11.0-alpha.2 #### 1.11.0-alpha.2
* Add warnings for usage of deprecated features * Add warnings for usage of deprecated features

View File

@@ -9,9 +9,9 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"time"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata" M "github.com/sagernet/sing/common/metadata"
@@ -60,7 +60,7 @@ func (s *Server) downloadExternalUI() error {
httpClient := &http.Client{ httpClient := &http.Client{
Transport: &http.Transport{ Transport: &http.Transport{
ForceAttemptHTTP2: true, ForceAttemptHTTP2: true,
TLSHandshakeTimeout: 5 * time.Second, TLSHandshakeTimeout: C.TCPTimeout,
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
return detour.DialContext(ctx, network, M.ParseSocksaddr(addr)) return detour.DialContext(ctx, network, M.ParseSocksaddr(addr))
}, },

View File

@@ -20,6 +20,7 @@ type CommandClient struct {
type CommandClientOptions struct { type CommandClientOptions struct {
Command int32 Command int32
StatusInterval int64 StatusInterval int64
IsMainClient bool
} }
type CommandClientHandler interface { type CommandClientHandler interface {
@@ -28,6 +29,7 @@ type CommandClientHandler interface {
ClearLogs() ClearLogs()
WriteLogs(messageList StringIterator) WriteLogs(messageList StringIterator)
WriteStatus(message *StatusMessage) WriteStatus(message *StatusMessage)
OpenURL(url string)
WriteGroups(message OutboundGroupIterator) WriteGroups(message OutboundGroupIterator)
InitializeClashMode(modeList StringIterator, currentMode string) InitializeClashMode(modeList StringIterator, currentMode string)
UpdateClashMode(newMode string) UpdateClashMode(newMode string)
@@ -91,9 +93,13 @@ func (c *CommandClient) Connect() error {
c.handler.Connected() c.handler.Connected()
go c.handleLogConn(conn) go c.handleLogConn(conn)
case CommandStatus: case CommandStatus:
err = binary.Write(conn, binary.BigEndian, c.options.IsMainClient)
if err != nil {
return E.Cause(err, "write is main client")
}
err = binary.Write(conn, binary.BigEndian, c.options.StatusInterval) err = binary.Write(conn, binary.BigEndian, c.options.StatusInterval)
if err != nil { if err != nil {
return E.Cause(err, "write interval") return E.Cause(err, "write header")
} }
c.handler.Connected() c.handler.Connected()
go c.handleStatusConn(conn) go c.handleStatusConn(conn)

View File

@@ -0,0 +1,40 @@
package libbox
import (
"encoding/binary"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/varbin"
)
type myEvent interface {
writeTo(writer varbin.Writer)
}
func readEvent(reader varbin.Reader) (myEvent, error) {
eventType, err := reader.ReadByte()
if err != nil {
return nil, err
}
switch eventType {
case eventTypeEmpty:
return nil, nil
case eventTypeOpenURL:
url, err := varbin.ReadValue[string](reader, binary.BigEndian)
if err != nil {
return nil, err
}
return &eventOpenURL{URL: url}, nil
default:
return nil, E.New("unknown event type: ", eventType)
}
}
type eventOpenURL struct {
URL string
}
func (e *eventOpenURL) writeTo(writer varbin.Writer) {
writer.WriteByte(eventTypeOpenURL)
varbin.Write(writer, binary.BigEndian, e.URL)
}

View File

@@ -33,6 +33,7 @@ type CommandServer struct {
urlTestUpdate chan struct{} urlTestUpdate chan struct{}
modeUpdate chan struct{} modeUpdate chan struct{}
logReset chan struct{} logReset chan struct{}
events chan myEvent
closedConnections []Connection closedConnections []Connection
} }
@@ -52,6 +53,7 @@ func NewCommandServer(handler CommandServerHandler, maxLines int32) *CommandServ
urlTestUpdate: make(chan struct{}, 1), urlTestUpdate: make(chan struct{}, 1),
modeUpdate: make(chan struct{}, 1), modeUpdate: make(chan struct{}, 1),
logReset: make(chan struct{}, 1), logReset: make(chan struct{}, 1),
events: make(chan myEvent, 8),
} }
server.observer = observable.NewObserver[string](server.subscriber, 64) server.observer = observable.NewObserver[string](server.subscriber, 64)
return server return server
@@ -61,6 +63,12 @@ func (s *CommandServer) SetService(newService *BoxService) {
if newService != nil { if newService != nil {
service.PtrFromContext[urltest.HistoryStorage](newService.ctx).SetHook(s.urlTestUpdate) service.PtrFromContext[urltest.HistoryStorage](newService.ctx).SetHook(s.urlTestUpdate)
newService.instance.Router().ClashServer().(*clashapi.Server).SetModeUpdateHook(s.modeUpdate) newService.instance.Router().ClashServer().(*clashapi.Server).SetModeUpdateHook(s.modeUpdate)
newService.platformInterface.openURLFunc = func(url string) {
select {
case s.events <- &eventOpenURL{URL: url}:
default:
}
}
} }
s.service = newService s.service = newService
s.notifyURLTestUpdate() s.notifyURLTestUpdate()

View File

@@ -1,6 +1,7 @@
package libbox package libbox
import ( import (
std_bufio "bufio"
"encoding/binary" "encoding/binary"
"net" "net"
"runtime" "runtime"
@@ -9,9 +10,15 @@ import (
"github.com/sagernet/sing-box/common/conntrack" "github.com/sagernet/sing-box/common/conntrack"
"github.com/sagernet/sing-box/experimental/clashapi" "github.com/sagernet/sing-box/experimental/clashapi"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format"
"github.com/sagernet/sing/common/memory" "github.com/sagernet/sing/common/memory"
) )
const (
eventTypeEmpty byte = iota
eventTypeOpenURL
)
type StatusMessage struct { type StatusMessage struct {
Memory int64 Memory int64
Goroutines int32 Goroutines int32
@@ -44,31 +51,73 @@ func (s *CommandServer) readStatus() StatusMessage {
} }
func (s *CommandServer) handleStatusConn(conn net.Conn) error { func (s *CommandServer) handleStatusConn(conn net.Conn) error {
var isMainClient bool
err := binary.Read(conn, binary.BigEndian, &isMainClient)
if err != nil {
return E.Cause(err, "read is main client")
}
var interval int64 var interval int64
err := binary.Read(conn, binary.BigEndian, &interval) err = binary.Read(conn, binary.BigEndian, &interval)
if err != nil { if err != nil {
return E.Cause(err, "read interval") return E.Cause(err, "read interval")
} }
ticker := time.NewTicker(time.Duration(interval)) ticker := time.NewTicker(time.Duration(interval))
defer ticker.Stop() defer ticker.Stop()
ctx := connKeepAlive(conn) ctx := connKeepAlive(conn)
for { writer := std_bufio.NewWriter(conn)
err = binary.Write(conn, binary.BigEndian, s.readStatus()) if isMainClient {
if err != nil { for {
return err writer.WriteByte(eventTypeEmpty)
err = binary.Write(conn, binary.BigEndian, s.readStatus())
if err != nil {
return err
}
writer.Flush()
select {
case <-ctx.Done():
return ctx.Err()
case <-ticker.C:
case event := <-s.events:
event.writeTo(writer)
writer.Flush()
}
} }
select { } else {
case <-ctx.Done(): for {
return ctx.Err() err = binary.Write(conn, binary.BigEndian, s.readStatus())
case <-ticker.C: if err != nil {
return err
}
writer.Flush()
select {
case <-ctx.Done():
return ctx.Err()
case <-ticker.C:
}
} }
} }
} }
func (c *CommandClient) handleStatusConn(conn net.Conn) { func (c *CommandClient) handleStatusConn(conn net.Conn) {
reader := std_bufio.NewReader(conn)
for { for {
if c.options.IsMainClient {
rawEvent, err := readEvent(reader)
if err != nil {
c.handler.Disconnected(err.Error())
return
}
switch event := rawEvent.(type) {
case *eventOpenURL:
c.handler.OpenURL(event.URL)
continue
case nil:
default:
panic(F.ToString("unexpected event type: ", event))
}
}
var message StatusMessage var message StatusMessage
err := binary.Read(conn, binary.BigEndian, &message) err := binary.Read(reader, binary.BigEndian, &message)
if err != nil { if err != nil {
c.handler.Disconnected(err.Error()) c.handler.Disconnected(err.Error())
return return

View File

@@ -134,6 +134,9 @@ func (s *interfaceMonitorStub) RegisterCallback(callback tun.DefaultInterfaceUpd
func (s *interfaceMonitorStub) UnregisterCallback(element *list.Element[tun.DefaultInterfaceUpdateCallback]) { func (s *interfaceMonitorStub) UnregisterCallback(element *list.Element[tun.DefaultInterfaceUpdateCallback]) {
} }
func (s *platformInterfaceStub) OpenURL(url string) {
}
func FormatConfig(configContent string) (string, error) { func FormatConfig(configContent string) (string, error) {
options, err := parseConfig(configContent) options, err := parseConfig(configContent)
if err != nil { if err != nil {

View File

@@ -17,8 +17,8 @@ import (
"os" "os"
"strconv" "strconv"
"sync" "sync"
"time"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/bufio" "github.com/sagernet/sing/common/bufio"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
@@ -69,8 +69,9 @@ type httpClient struct {
func NewHTTPClient() HTTPClient { func NewHTTPClient() HTTPClient {
client := new(httpClient) client := new(httpClient)
client.client.Timeout = 15 * time.Second
client.client.Transport = &client.transport client.client.Transport = &client.transport
client.transport.ForceAttemptHTTP2 = true
client.transport.TLSHandshakeTimeout = C.TCPTimeout
client.transport.TLSClientConfig = &client.tls client.transport.TLSClientConfig = &client.tls
client.transport.DisableKeepAlives = true client.transport.DisableKeepAlives = true
return client return client
@@ -127,7 +128,6 @@ func (c *httpClient) TrySocks5(port int32) {
} }
func (c *httpClient) KeepAlive() { func (c *httpClient) KeepAlive() {
c.transport.ForceAttemptHTTP2 = true
c.transport.DisableKeepAlives = false c.transport.DisableKeepAlives = false
} }

View File

@@ -25,4 +25,5 @@ type Interface interface {
ClearDNSCache() ClearDNSCache()
ReadWIFIState() adapter.WIFIState ReadWIFIState() adapter.WIFIState
process.Searcher process.Searcher
OpenURL(url string)
} }

View File

@@ -34,9 +34,9 @@ type BoxService struct {
ctx context.Context ctx context.Context
cancel context.CancelFunc cancel context.CancelFunc
instance *box.Box instance *box.Box
platformInterface *platformInterfaceWrapper
pauseManager pause.Manager pauseManager pause.Manager
urlTestHistoryStorage *urltest.HistoryStorage urlTestHistoryStorage *urltest.HistoryStorage
servicePauseFields servicePauseFields
} }
@@ -67,6 +67,7 @@ func NewService(configContent string, platformInterface PlatformInterface) (*Box
ctx: ctx, ctx: ctx,
cancel: cancel, cancel: cancel,
instance: instance, instance: instance,
platformInterface: platformWrapper,
urlTestHistoryStorage: urlTestHistoryStorage, urlTestHistoryStorage: urlTestHistoryStorage,
pauseManager: service.FromContext[pause.Manager](ctx), pauseManager: service.FromContext[pause.Manager](ctx),
}, nil }, nil
@@ -102,9 +103,10 @@ var (
) )
type platformInterfaceWrapper struct { type platformInterfaceWrapper struct {
iif PlatformInterface iif PlatformInterface
useProcFS bool useProcFS bool
router adapter.Router router adapter.Router
openURLFunc func(url string)
} }
func (w *platformInterfaceWrapper) Initialize(ctx context.Context, router adapter.Router) error { func (w *platformInterfaceWrapper) Initialize(ctx context.Context, router adapter.Router) error {
@@ -238,3 +240,9 @@ func (w *platformInterfaceWrapper) DisableColors() bool {
func (w *platformInterfaceWrapper) WriteMessage(level log.Level, message string) { func (w *platformInterfaceWrapper) WriteMessage(level log.Level, message string) {
w.iif.WriteLog(message) w.iif.WriteLog(message)
} }
func (w *platformInterfaceWrapper) OpenURL(url string) {
if w.openURLFunc != nil {
w.openURLFunc(url)
}
}

View File

@@ -11,6 +11,11 @@ import (
) )
func New(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.Outbound) (adapter.Outbound, error) { func New(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.Outbound) (adapter.Outbound, error) {
if tag != "" {
ctx = adapter.WithContext(ctx, &adapter.InboundContext{
Outbound: tag,
})
}
if options.Type == "" { if options.Type == "" {
return nil, E.New("missing outbound type") return nil, E.New("missing outbound type")
} }

View File

@@ -7,7 +7,6 @@ import (
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
"time"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/geoip" "github.com/sagernet/sing-box/common/geoip"
@@ -161,7 +160,7 @@ func (r *Router) downloadGeoIPDatabase(savePath string) error {
httpClient := &http.Client{ httpClient := &http.Client{
Transport: &http.Transport{ Transport: &http.Transport{
ForceAttemptHTTP2: true, ForceAttemptHTTP2: true,
TLSHandshakeTimeout: 5 * time.Second, TLSHandshakeTimeout: C.TCPTimeout,
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
return detour.DialContext(ctx, network, M.ParseSocksaddr(addr)) return detour.DialContext(ctx, network, M.ParseSocksaddr(addr))
}, },
@@ -216,7 +215,7 @@ func (r *Router) downloadGeositeDatabase(savePath string) error {
httpClient := &http.Client{ httpClient := &http.Client{
Transport: &http.Transport{ Transport: &http.Transport{
ForceAttemptHTTP2: true, ForceAttemptHTTP2: true,
TLSHandshakeTimeout: 5 * time.Second, TLSHandshakeTimeout: C.TCPTimeout,
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
return detour.DialContext(ctx, network, M.ParseSocksaddr(addr)) return detour.DialContext(ctx, network, M.ParseSocksaddr(addr))
}, },

View File

@@ -67,7 +67,6 @@ func NewRemoteRuleSet(ctx context.Context, router adapter.Router, logger logger.
logger: logger, logger: logger,
options: options, options: options,
updateInterval: updateInterval, updateInterval: updateInterval,
cacheFile: service.FromContext[adapter.CacheFile](ctx),
pauseManager: service.FromContext[pause.Manager](ctx), pauseManager: service.FromContext[pause.Manager](ctx),
} }
} }
@@ -81,6 +80,7 @@ func (s *RemoteRuleSet) String() string {
} }
func (s *RemoteRuleSet) StartContext(ctx context.Context, startContext *adapter.HTTPStartContext) error { func (s *RemoteRuleSet) StartContext(ctx context.Context, startContext *adapter.HTTPStartContext) error {
s.cacheFile = service.FromContext[adapter.CacheFile](s.ctx)
var dialer N.Dialer var dialer N.Dialer
if s.options.RemoteOptions.DownloadDetour != "" { if s.options.RemoteOptions.DownloadDetour != "" {
outbound, loaded := s.router.Outbound(s.options.RemoteOptions.DownloadDetour) outbound, loaded := s.router.Outbound(s.options.RemoteOptions.DownloadDetour)

View File

@@ -1079,3 +1079,24 @@ function luci_types(id, m, s, type_name, option_prefix)
end end
end end
end end
function get_std_domain(domain)
domain = trim(domain)
if domain == "" or domain:find("#") then return "" end
-- 删除首尾所有的 .
domain = domain:gsub("^[%.]+", ""):gsub("[%.]+$", "")
-- 如果 domain 包含 '*',则分割并删除包含 '*' 的部分及其前面的部分
if domain:find("%*") then
local parts = {}
for part in domain:gmatch("[^%.]+") do
table.insert(parts, part)
end
for i = #parts, 1, -1 do
if parts[i]:find("%*") then
-- 删除包含 '*' 的部分及其前面的部分
return parts[i + 1] and parts[i + 1] .. "." .. table.concat(parts, ".", i + 2) or ""
end
end
end
return domain
end

View File

@@ -546,6 +546,8 @@ run_chinadns_ng() {
local _flag _listen_port _dns_local _dns_trust _no_ipv6_trust _use_direct_list _use_proxy_list _gfwlist _chnlist _default_mode _default_tag local _flag _listen_port _dns_local _dns_trust _no_ipv6_trust _use_direct_list _use_proxy_list _gfwlist _chnlist _default_mode _default_tag
eval_set_val $@ eval_set_val $@
lua $APP_PATH/helper_chinadns_add.lua -FLAG $_flag -USE_DIRECT_LIST $_use_direct_list -USE_PROXY_LIST $_use_proxy_list
local _CONF_FILE=$TMP_ACL_PATH/$_flag/chinadns_ng.conf local _CONF_FILE=$TMP_ACL_PATH/$_flag/chinadns_ng.conf
local _LOG_FILE=$TMP_ACL_PATH/$_flag/chinadns_ng.log local _LOG_FILE=$TMP_ACL_PATH/$_flag/chinadns_ng.log
_LOG_FILE="/dev/null" _LOG_FILE="/dev/null"
@@ -579,7 +581,7 @@ run_chinadns_ng() {
EOF EOF
} }
[ "${_use_direct_list}" = "1" ] && [ -s "${RULES_PATH}/direct_host" ] && { [ "${_use_direct_list}" = "1" ] && [ -s "${TMP_PATH}/direct_host" ] && {
local whitelist4_set="passwall_whitelist" local whitelist4_set="passwall_whitelist"
local whitelist6_set="passwall_whitelist6" local whitelist6_set="passwall_whitelist6"
[ "$nftflag" = "1" ] && { [ "$nftflag" = "1" ] && {
@@ -588,13 +590,13 @@ run_chinadns_ng() {
} }
cat <<-EOF >> ${_CONF_FILE} cat <<-EOF >> ${_CONF_FILE}
group directlist group directlist
group-dnl ${RULES_PATH}/direct_host group-dnl ${TMP_PATH}/direct_host
group-upstream ${_dns_local} group-upstream ${_dns_local}
group-ipset ${whitelist4_set},${whitelist6_set} group-ipset ${whitelist4_set},${whitelist6_set}
EOF EOF
} }
[ "${_use_proxy_list}" = "1" ] && [ -s "${RULES_PATH}/proxy_host" ] && { [ "${_use_proxy_list}" = "1" ] && [ -s "${TMP_PATH}/proxy_host" ] && {
local blacklist4_set="passwall_blacklist" local blacklist4_set="passwall_blacklist"
local blacklist6_set="passwall_blacklist6" local blacklist6_set="passwall_blacklist6"
[ "$nftflag" = "1" ] && { [ "$nftflag" = "1" ] && {
@@ -603,7 +605,7 @@ run_chinadns_ng() {
} }
cat <<-EOF >> ${_CONF_FILE} cat <<-EOF >> ${_CONF_FILE}
group proxylist group proxylist
group-dnl ${RULES_PATH}/proxy_host group-dnl ${TMP_PATH}/proxy_host
group-upstream ${_dns_trust} group-upstream ${_dns_trust}
group-ipset ${blacklist4_set},${blacklist6_set} group-ipset ${blacklist4_set},${blacklist6_set}
EOF EOF

View File

@@ -0,0 +1,50 @@
require 'nixio'
local api = require "luci.passwall.api"
local appname = "passwall"
local var = api.get_args(arg)
local FLAG = var["-FLAG"]
local USE_DIRECT_LIST = var["-USE_DIRECT_LIST"]
local USE_PROXY_LIST = var["-USE_PROXY_LIST"]
local TMP_PATH = "/tmp/etc/" .. appname
if not nixio.fs.access(TMP_PATH) then
nixio.fs.mkdir(TMP_PATH, 493)
end
local tmp_direct_host = TMP_PATH .. "/direct_host"
if USE_DIRECT_LIST == "1" and not nixio.fs.access(tmp_direct_host) then
local direct_domain = {}
for line in io.lines("/usr/share/passwall/rules/direct_host") do
line = api.get_std_domain(line)
if line ~= "" and not line:find("#") then
table.insert(direct_domain, line)
end
end
if #direct_domain > 0 then
local direct_out = io.open(tmp_direct_host, "a")
for i = 1, #direct_domain do
direct_out:write(direct_domain[i] .. "\n")
end
direct_out:close()
end
end
local tmp_proxy_host = TMP_PATH .. "/proxy_host"
if USE_PROXY_LIST == "1" and not nixio.fs.access(tmp_proxy_host) then
local proxy_domain = {}
for line in io.lines("/usr/share/passwall/rules/proxy_host") do
line = api.get_std_domain(line)
if line ~= "" and not line:find("#") then
table.insert(proxy_domain, line)
end
end
if #proxy_domain > 0 then
local proxy_out = io.open(tmp_proxy_host, "a")
for i = 1, #proxy_domain do
proxy_out:write(proxy_domain[i] .. "\n")
end
proxy_out:close()
end
end

View File

@@ -196,6 +196,7 @@ if not fs.access(CACHE_DNS_PATH) then
--屏蔽列表 --屏蔽列表
if USE_BLOCK_LIST == "1" then if USE_BLOCK_LIST == "1" then
for line in io.lines("/usr/share/passwall/rules/block_host") do for line in io.lines("/usr/share/passwall/rules/block_host") do
line = api.get_std_domain(line)
if line ~= "" and not line:find("#") then if line ~= "" and not line:find("#") then
set_domain_address(line, "") set_domain_address(line, "")
end end
@@ -234,6 +235,7 @@ if not fs.access(CACHE_DNS_PATH) then
if fwd_dns then if fwd_dns then
--始终用国内DNS解析直连白名单列表 --始终用国内DNS解析直连白名单列表
for line in io.lines("/usr/share/passwall/rules/direct_host") do for line in io.lines("/usr/share/passwall/rules/direct_host") do
line = api.get_std_domain(line)
if line ~= "" and not line:find("#") then if line ~= "" and not line:find("#") then
add_excluded_domain(line) add_excluded_domain(line)
set_domain_dns(line, fwd_dns) set_domain_dns(line, fwd_dns)
@@ -255,6 +257,7 @@ if not fs.access(CACHE_DNS_PATH) then
if fwd_dns then if fwd_dns then
--始终使用远程DNS解析代理黑名单列表 --始终使用远程DNS解析代理黑名单列表
for line in io.lines("/usr/share/passwall/rules/proxy_host") do for line in io.lines("/usr/share/passwall/rules/proxy_host") do
line = api.get_std_domain(line)
if line ~= "" and not line:find("#") then if line ~= "" and not line:find("#") then
add_excluded_domain(line) add_excluded_domain(line)
local ipset_flag = setflag_4 .. "passwall_blacklist," .. setflag_6 .. "passwall_blacklist6" local ipset_flag = setflag_4 .. "passwall_blacklist," .. setflag_6 .. "passwall_blacklist6"

View File

@@ -103,6 +103,7 @@ ipset_r() {
$IPT -A SS_SPEC_WAN_AC -m set --match-set china dst -j RETURN $IPT -A SS_SPEC_WAN_AC -m set --match-set china dst -j RETURN
$IPT -A SS_SPEC_WAN_AC -m set --match-set gfwlist dst -j SS_SPEC_WAN_FW $IPT -A SS_SPEC_WAN_AC -m set --match-set gfwlist dst -j SS_SPEC_WAN_FW
$IPT -A SS_SPEC_WAN_AC -m set --match-set gmlan src -m set ! --match-set china dst -j SS_SPEC_WAN_FW $IPT -A SS_SPEC_WAN_AC -m set --match-set gmlan src -m set ! --match-set china dst -j SS_SPEC_WAN_FW
$IPT -A SS_SPEC_WAN_AC -j SS_SPEC_WAN_FW
;; ;;
oversea) oversea)
ipset -N oversea hash:net 2>/dev/null ipset -N oversea hash:net 2>/dev/null

View File

@@ -5,6 +5,7 @@
ClearMsg, ClearMsg,
SendMsgView, SendMsgView,
SendSnackMsg, SendSnackMsg,
RefreshProfiles RefreshProfiles,
StopSpeedtest
} }
} }

View File

@@ -1,7 +1,7 @@
using System.Diagnostics; using ReactiveUI;
using System.Diagnostics;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
namespace ServiceLib.Services namespace ServiceLib.Services
{ {
public class SpeedtestService public class SpeedtestService
@@ -80,10 +80,12 @@ namespace ServiceLib.Services
Task.Run(RunMixedtestAsync); Task.Run(RunMixedtestAsync);
break; break;
} }
MessageBus.Current.Listen<string>(EMsgCommand.StopSpeedtest.ToString()).Subscribe(ExitLoop);
} }
public void ExitLoop() private void ExitLoop(string x)
{ {
if(_exitLoop) return;
_exitLoop = true; _exitLoop = true;
UpdateFunc("", ResUI.SpeedtestingStop); UpdateFunc("", ResUI.SpeedtestingStop);
} }

Some files were not shown because too many files have changed in this diff Show More