Update On Fri Oct 24 20:39:48 CEST 2025

This commit is contained in:
github-action[bot]
2025-10-24 20:39:49 +02:00
parent e8b76761e1
commit bf9e802a78
558 changed files with 7599 additions and 27751 deletions

1
.github/update.log vendored
View File

@@ -1160,3 +1160,4 @@ Update On Mon Oct 20 20:40:25 CEST 2025
Update On Tue Oct 21 20:38:48 CEST 2025
Update On Wed Oct 22 20:43:37 CEST 2025
Update On Thu Oct 23 20:39:01 CEST 2025
Update On Fri Oct 24 20:39:40 CEST 2025

View File

@@ -24,7 +24,7 @@ require (
github.com/metacubex/fswatch v0.1.1
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759
github.com/metacubex/kcp-go v0.0.0-20251007183319-0df1aec1639a
github.com/metacubex/quic-go v0.55.1-0.20251004050223-450bd9e32033
github.com/metacubex/quic-go v0.55.1-0.20251024060151-bd465f127128
github.com/metacubex/randv2 v0.2.0
github.com/metacubex/restls-client-go v0.1.7
github.com/metacubex/sing v0.5.6
@@ -37,7 +37,7 @@ require (
github.com/metacubex/sing-vmess v0.2.4
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f
github.com/metacubex/smux v0.0.0-20250922175018-15c9a6a78719
github.com/metacubex/tfo-go v0.0.0-20250921095601-b102db4216c0
github.com/metacubex/tfo-go v0.0.0-20251024101424-368b42b59148
github.com/metacubex/utls v1.8.3
github.com/metacubex/wireguard-go v0.0.0-20250820062549-a6cecdd7f57f
github.com/miekg/dns v1.1.63 // lastest version compatible with golang1.20

View File

@@ -112,8 +112,8 @@ github.com/metacubex/kcp-go v0.0.0-20251007183319-0df1aec1639a h1:5vdk2pI71itLBT
github.com/metacubex/kcp-go v0.0.0-20251007183319-0df1aec1639a/go.mod h1:HIJZW4QMhbBqXuqC1ly6Hn0TEYT2SzRw58ns1yGhXTs=
github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793 h1:1Qpuy+sU3DmyX9HwI+CrBT/oLNJngvBorR2RbajJcqo=
github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793/go.mod h1:RjRNb4G52yAgfR+Oe/kp9G4PJJ97Fnj89eY1BFO3YyA=
github.com/metacubex/quic-go v0.55.1-0.20251004050223-450bd9e32033 h1:LEzvR5AmHEatqE6IWgMBUJHnaiz9VJfZeDGOiHFuWZU=
github.com/metacubex/quic-go v0.55.1-0.20251004050223-450bd9e32033/go.mod h1:1lktQFtCD17FZliVypbrDHwbsFSsmz2xz2TRXydvB5c=
github.com/metacubex/quic-go v0.55.1-0.20251024060151-bd465f127128 h1:I1uvJl206/HbkzEAZpLgGkZgUveOZb+P+6oTUj7dN+o=
github.com/metacubex/quic-go v0.55.1-0.20251024060151-bd465f127128/go.mod h1:1lktQFtCD17FZliVypbrDHwbsFSsmz2xz2TRXydvB5c=
github.com/metacubex/randv2 v0.2.0 h1:uP38uBvV2SxYfLj53kuvAjbND4RUDfFJjwr4UigMiLs=
github.com/metacubex/randv2 v0.2.0/go.mod h1:kFi2SzrQ5WuneuoLLCMkABtiBu6VRrMrWFqSPyj2cxY=
github.com/metacubex/restls-client-go v0.1.7 h1:eCwiXCTQb5WJu9IlgYvDBA1OgrINv58dEe7hcN5H15k=
@@ -139,8 +139,8 @@ github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f h1:Sr/DYK
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f/go.mod h1:jpAkVLPnCpGSfNyVmj6Cq4YbuZsFepm/Dc+9BAOcR80=
github.com/metacubex/smux v0.0.0-20250922175018-15c9a6a78719 h1:T6qCCfolRDAVJKeaPW/mXwNLjnlo65AYN7WS2jrBNaM=
github.com/metacubex/smux v0.0.0-20250922175018-15c9a6a78719/go.mod h1:4bPD8HWx9jPJ9aE4uadgyN7D1/Wz3KmPy+vale8sKLE=
github.com/metacubex/tfo-go v0.0.0-20250921095601-b102db4216c0 h1:Ui+/2s5Qz0lSnDUBmEL12M5Oi/PzvFxGTNohm8ZcsmE=
github.com/metacubex/tfo-go v0.0.0-20250921095601-b102db4216c0/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
github.com/metacubex/tfo-go v0.0.0-20251024101424-368b42b59148 h1:Zd0QqciLIhv9MKbGKTPEgN8WUFsgQGA1WJBy6spEnVU=
github.com/metacubex/tfo-go v0.0.0-20251024101424-368b42b59148/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
github.com/metacubex/utls v1.8.3 h1:0m/yCxm3SK6kWve2lKiFb1pue1wHitJ8sQQD4Ikqde4=
github.com/metacubex/utls v1.8.3/go.mod h1:kncGGVhFaoGn5M3pFe3SXhZCzsbCJayNOH4UEqTKTko=
github.com/metacubex/wireguard-go v0.0.0-20250820062549-a6cecdd7f57f h1:FGBPRb1zUabhPhDrlKEjQ9lgIwQ6cHL4x8M9lrERhbk=

View File

@@ -21,7 +21,6 @@ func SetCongestionController(quicConn *quic.Conn, cc string, cwnd int) {
case "cubic":
quicConn.SetCongestionControl(
congestion.NewCubicSender(
congestion.DefaultClock{},
congestion.GetInitialPacketSize(quicConn),
false,
),
@@ -29,7 +28,6 @@ func SetCongestionController(quicConn *quic.Conn, cc string, cwnd int) {
case "new_reno":
quicConn.SetCongestionControl(
congestion.NewCubicSender(
congestion.DefaultClock{},
congestion.GetInitialPacketSize(quicConn),
true,
),
@@ -37,7 +35,6 @@ func SetCongestionController(quicConn *quic.Conn, cc string, cwnd int) {
case "bbr_meta_v1":
quicConn.SetCongestionControl(
congestion.NewBBRSender(
congestion.DefaultClock{},
congestion.GetInitialPacketSize(quicConn),
c.ByteCount(cwnd)*congestion.InitialMaxDatagramSize,
congestion.DefaultBBRMaxCongestionWindow*congestion.InitialMaxDatagramSize,
@@ -48,7 +45,6 @@ func SetCongestionController(quicConn *quic.Conn, cc string, cwnd int) {
case "bbr":
quicConn.SetCongestionControl(
congestionv2.NewBbrSender(
congestionv2.DefaultClock{},
congestionv2.GetInitialPacketSize(quicConn),
c.ByteCount(cwnd),
),

View File

@@ -101,7 +101,6 @@ const (
type bbrSender struct {
mode bbrMode
clock Clock
rttStats congestion.RTTStatsProvider
bytesInFlight congestion.ByteCount
// return total bytes of unacked packets.
@@ -232,14 +231,12 @@ type bbrSender struct {
}
func NewBBRSender(
clock Clock,
initialMaxDatagramSize,
initialCongestionWindow,
initialMaxCongestionWindow congestion.ByteCount,
) *bbrSender {
b := &bbrSender{
mode: STARTUP,
clock: clock,
sampler: NewBandwidthSampler(),
maxBandwidth: NewWindowedFilter(int64(BandwidthWindowSize), MaxFilter),
maxAckHeight: NewWindowedFilter(int64(BandwidthWindowSize), MaxFilter),

View File

@@ -1,18 +0,0 @@
package congestion
import "time"
// A Clock returns the current time
type Clock interface {
Now() time.Time
}
// DefaultClock implements the Clock interface using the Go stdlib clock.
type DefaultClock struct{}
var _ Clock = DefaultClock{}
// Now gets the current time
func (DefaultClock) Now() time.Time {
return time.Now()
}

View File

@@ -37,8 +37,6 @@ const betaLastMax float32 = 0.85
// Cubic implements the cubic algorithm from TCP
type Cubic struct {
clock Clock
// Number of connections to simulate.
numConnections int
@@ -67,9 +65,8 @@ type Cubic struct {
}
// NewCubic returns a new Cubic instance
func NewCubic(clock Clock) *Cubic {
func NewCubic() *Cubic {
c := &Cubic{
clock: clock,
numConnections: defaultNumConnections,
}
c.Reset()

View File

@@ -23,7 +23,6 @@ type cubicSender struct {
rttStats congestion.RTTStatsProvider
cubic *Cubic
pacer *pacer
clock Clock
reno bool
@@ -61,12 +60,10 @@ var (
// NewCubicSender makes a new cubic sender
func NewCubicSender(
clock Clock,
initialMaxDatagramSize congestion.ByteCount,
reno bool,
) *cubicSender {
return newCubicSender(
clock,
reno,
initialMaxDatagramSize,
initialCongestionWindow*initialMaxDatagramSize,
@@ -75,7 +72,6 @@ func NewCubicSender(
}
func newCubicSender(
clock Clock,
reno bool,
initialMaxDatagramSize,
initialCongestionWindow,
@@ -89,8 +85,6 @@ func newCubicSender(
initialMaxCongestionWindow: initialMaxCongestionWindow,
congestionWindow: initialCongestionWindow,
slowStartThreshold: MaxByteCount,
cubic: NewCubic(clock),
clock: clock,
reno: reno,
maxDatagramSize: initialMaxDatagramSize,
}

View File

@@ -96,7 +96,6 @@ const (
type bbrSender struct {
rttStats congestion.RTTStatsProvider
clock Clock
pacer *Pacer
mode bbrMode
@@ -244,12 +243,10 @@ type bbrSender struct {
var _ congestion.CongestionControl = &bbrSender{}
func NewBbrSender(
clock Clock,
initialMaxDatagramSize congestion.ByteCount,
initialCongestionWindowPackets congestion.ByteCount,
) *bbrSender {
return newBbrSender(
clock,
initialMaxDatagramSize,
initialCongestionWindowPackets*initialMaxDatagramSize,
congestion.MaxCongestionWindowPackets*initialMaxDatagramSize,
@@ -257,13 +254,11 @@ func NewBbrSender(
}
func newBbrSender(
clock Clock,
initialMaxDatagramSize,
initialCongestionWindow,
initialMaxCongestionWindow congestion.ByteCount,
) *bbrSender {
b := &bbrSender{
clock: clock,
mode: bbrModeStartup,
sampler: newBandwidthSampler(roundTripCount(bandwidthWindowSize)),
lastSentPacket: invalidPacketNumber,
@@ -297,7 +292,7 @@ func newBbrSender(
}
*/
b.enterStartupMode(b.clock.Now())
b.enterStartupMode()
b.setHighCwndGain(derivedHighCWNDGain)
return b
@@ -605,7 +600,7 @@ func (b *bbrSender) maybeUpdateMinRtt(now monotime.Time, sampleMinRtt time.Durat
}
// Enters the STARTUP mode.
func (b *bbrSender) enterStartupMode(now monotime.Time) {
func (b *bbrSender) enterStartupMode() {
b.mode = bbrModeStartup
// b.maybeTraceStateChange(logging.CongestionStateStartup)
b.pacingGain = b.highGain
@@ -757,7 +752,7 @@ func (b *bbrSender) maybeEnterOrExitProbeRtt(now monotime.Time, isRoundStart, mi
if now.Sub(b.exitProbeRttAt) >= 0 && b.probeRttRoundPassed {
b.minRttTimestamp = now
if !b.isAtFullBandwidth {
b.enterStartupMode(now)
b.enterStartupMode()
} else {
b.enterProbeBandwidthMode(now)
}

View File

@@ -1,20 +0,0 @@
package congestion
import (
"github.com/metacubex/quic-go/monotime"
)
// A Clock returns the current time
type Clock interface {
Now() monotime.Time
}
// DefaultClock implements the Clock interface using the Go stdlib clock.
type DefaultClock struct{}
var _ Clock = DefaultClock{}
// Now gets the current time
func (DefaultClock) Now() monotime.Time {
return monotime.Now()
}

View File

@@ -30,7 +30,7 @@ require (
require (
github.com/andybalholm/brotli v1.1.0 // indirect
github.com/apernet/quic-go v0.54.1-0.20250907230547-eb32f8aec5e2 // indirect
github.com/apernet/quic-go v0.54.1-0.20251024023933-5e0818a71079 // indirect
github.com/cloudflare/circl v1.3.9 // indirect
github.com/database64128/netx-go v0.0.0-20240905055117-62795b8b054a // indirect
github.com/database64128/tfo-go/v2 v2.2.2 // indirect

View File

@@ -42,10 +42,8 @@ github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/apernet/go-tproxy v0.0.0-20230809025308-8f4723fd742f h1:uVh0qpEslrWjgzx9vOcyCqsOY3c9kofDZ1n+qaw35ZY=
github.com/apernet/go-tproxy v0.0.0-20230809025308-8f4723fd742f/go.mod h1:xkkq9D4ygcldQQhKS/w9CadiCKwCngU7K9E3DaKahpM=
github.com/apernet/quic-go v0.54.1-0.20250907230547-eb32f8aec5e2 h1:03y2WeGln3/QmBzm+KGQ3yej7Uz+76CqHoisdzYzf30=
github.com/apernet/quic-go v0.54.1-0.20250907230547-eb32f8aec5e2/go.mod h1:Y4cCWi64O51TRUKDPy0ShA2/pevlWiWJJnlNo2fO2ds=
github.com/apernet/sing-tun v0.2.6-0.20250726070404-c99085f9af13 h1:gzets97c/u5iMj1zjanMBVkIYOdaVw+RXPzTT1xQoyM=
github.com/apernet/sing-tun v0.2.6-0.20250726070404-c99085f9af13/go.mod h1:S5IydyLSN/QAfvY+r2GoomPJ6hidtXWm/Ad18sJVssk=
github.com/apernet/quic-go v0.54.1-0.20251024023933-5e0818a71079 h1:WgFl2esvC7FnVhhBvA+BJUgxyheiTAhJ4CIbRlaK22I=
github.com/apernet/quic-go v0.54.1-0.20251024023933-5e0818a71079/go.mod h1:Y4cCWi64O51TRUKDPy0ShA2/pevlWiWJJnlNo2fO2ds=
github.com/apernet/sing-tun v0.2.6-0.20250920121535-299f04629986 h1:w62V0oOO2Do0vXeZkx7mgZ2YFuUaRcO6rNZewI3xzuE=
github.com/apernet/sing-tun v0.2.6-0.20250920121535-299f04629986/go.mod h1:S5IydyLSN/QAfvY+r2GoomPJ6hidtXWm/Ad18sJVssk=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=

View File

@@ -5,7 +5,7 @@ go 1.23
toolchain go1.25.1
require (
github.com/apernet/quic-go v0.54.1-0.20250907230547-eb32f8aec5e2
github.com/apernet/quic-go v0.54.1-0.20251024023933-5e0818a71079
github.com/stretchr/testify v1.9.0
go.uber.org/goleak v1.2.1
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842

View File

@@ -1,5 +1,5 @@
github.com/apernet/quic-go v0.54.1-0.20250907230547-eb32f8aec5e2 h1:03y2WeGln3/QmBzm+KGQ3yej7Uz+76CqHoisdzYzf30=
github.com/apernet/quic-go v0.54.1-0.20250907230547-eb32f8aec5e2/go.mod h1:Y4cCWi64O51TRUKDPy0ShA2/pevlWiWJJnlNo2fO2ds=
github.com/apernet/quic-go v0.54.1-0.20251024023933-5e0818a71079 h1:WgFl2esvC7FnVhhBvA+BJUgxyheiTAhJ4CIbRlaK22I=
github.com/apernet/quic-go v0.54.1-0.20251024023933-5e0818a71079/go.mod h1:Y4cCWi64O51TRUKDPy0ShA2/pevlWiWJJnlNo2fO2ds=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=

View File

@@ -6,7 +6,7 @@ toolchain go1.25.1
require (
github.com/apernet/hysteria/core/v2 v2.0.0-00010101000000-000000000000
github.com/apernet/quic-go v0.54.1-0.20250907230547-eb32f8aec5e2
github.com/apernet/quic-go v0.54.1-0.20251024023933-5e0818a71079
github.com/database64128/tfo-go/v2 v2.2.2
github.com/hashicorp/golang-lru/v2 v2.0.5
github.com/miekg/dns v1.1.59

View File

@@ -1,7 +1,7 @@
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/apernet/quic-go v0.54.1-0.20250907230547-eb32f8aec5e2 h1:03y2WeGln3/QmBzm+KGQ3yej7Uz+76CqHoisdzYzf30=
github.com/apernet/quic-go v0.54.1-0.20250907230547-eb32f8aec5e2/go.mod h1:Y4cCWi64O51TRUKDPy0ShA2/pevlWiWJJnlNo2fO2ds=
github.com/apernet/quic-go v0.54.1-0.20251024023933-5e0818a71079 h1:WgFl2esvC7FnVhhBvA+BJUgxyheiTAhJ4CIbRlaK22I=
github.com/apernet/quic-go v0.54.1-0.20251024023933-5e0818a71079/go.mod h1:Y4cCWi64O51TRUKDPy0ShA2/pevlWiWJJnlNo2fO2ds=
github.com/cloudflare/circl v1.3.9 h1:QFrlgFYf2Qpi8bSpVPK1HBvWpx16v/1TZivyo7pGuBE=
github.com/cloudflare/circl v1.3.9/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=

View File

@@ -33,6 +33,7 @@ github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbi
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/apernet/quic-go v0.54.1-0.20251024023933-5e0818a71079/go.mod h1:Y4cCWi64O51TRUKDPy0ShA2/pevlWiWJJnlNo2fO2ds=
github.com/armon/go-metrics v0.4.0 h1:yCQqn7dwca4ITXb+CbubHmedzaQYHhNhrEXLYUeEe8Q=
github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=

View File

@@ -69,6 +69,7 @@ menu "Global build settings"
default y
config USE_APK
imply PACKAGE_apk-mbedtls
bool "Use APK instead of OPKG to build distribution (EXPERIMENTAL)"
comment "General build options"

View File

@@ -17,7 +17,7 @@ endif
opkg_package_files = $(wildcard \
$(foreach dir,$(PACKAGE_SUBDIRS), \
$(foreach pkg,$(1), $(dir)/$(pkg)_*.ipk)))
apk_package_files = $(wildcard \
$(foreach dir,$(PACKAGE_SUBDIRS), \
$(foreach pkg,$(1), $(dir)/$(pkg)_*.apk)))

View File

@@ -46,7 +46,7 @@ define Package/base-files
+SELINUX:busybox-selinux +!SELINUX:busybox
TITLE:=Base filesystem for LEDE
URL:=http://openwrt.org/
VERSION:=$(PKG_RELEASE)~$(lastword $(subst -, ,$(REVISION)))
VERSION:=$(PKG_RELEASE)-$(REVISION)
endef
define Package/base-files/conffiles
@@ -81,7 +81,7 @@ endef
define ImageConfigOptions
mkdir -p $(1)/lib/preinit
echo 'pi_suppress_stderr="$(CONFIG_TARGET_PREINIT_SUPPRESS_STDERR)"' >$(1)/lib/preinit/00_preinit.conf
echo 'fs_failsafe_wait_timeout=$(if $(CONFIG_TARGET_PREINIT_TIMEOUT),$(CONFIG_TARGET_PREINIT_TIMEOUT),4)' >>$(1)/lib/preinit/00_preinit.conf
echo 'fs_failsafe_wait_timeout=$(if $(CONFIG_TARGET_PREINIT_TIMEOUT),$(CONFIG_TARGET_PREINIT_TIMEOUT),2)' >>$(1)/lib/preinit/00_preinit.conf
echo 'pi_init_path="$(TARGET_INIT_PATH)"' >>$(1)/lib/preinit/00_preinit.conf
echo 'pi_init_env=$(if $(CONFIG_TARGET_INIT_ENV),$(CONFIG_TARGET_INIT_ENV),"")' >>$(1)/lib/preinit/00_preinit.conf
echo 'pi_init_cmd=$(if $(CONFIG_TARGET_INIT_CMD),$(CONFIG_TARGET_INIT_CMD),"/sbin/init")' >>$(1)/lib/preinit/00_preinit.conf
@@ -248,7 +248,7 @@ endif
$(if $(CONFIG_TARGET_PREINIT_DISABLE_FAILSAFE), \
rm -f $(1)/etc/banner.failsafe,)
if [ ! -f $(TOPDIR)/feeds/luci/package.json ]; then \
$(CP) ./luci/* $(1)/; \
fi

View File

@@ -3,7 +3,6 @@
CFG=/etc/board.json
. /usr/share/libubox/jshn.sh
. /lib/functions/ipv4.sh
[ -s $CFG ] || /bin/board_detect || exit 1
[ -s /etc/config/network -a -s /etc/config/system ] && exit 0
@@ -43,16 +42,16 @@ generate_static_network() {
set network.loopback='interface'
set network.loopback.device='lo'
set network.loopback.proto='static'
add_list network.loopback.ipaddr='127.0.0.1/8'
delete network.globals
set network.globals='globals'
set network.globals.dhcp_default_duid='auto'
set network.loopback.ipaddr='127.0.0.1'
set network.loopback.netmask='255.0.0.0'
EOF
[ -e /proc/sys/net/ipv6 ] && {
uci -q batch <<-EOF
set network.globals.ula_prefix='auto'
EOF
}
[ -e /proc/sys/net/ipv6 ] && {
uci -q batch <<-EOF
delete network.globals
set network.globals='globals'
set network.globals.ula_prefix='auto'
EOF
}
if json_is_a dsl object; then
json_select dsl
@@ -161,19 +160,18 @@ generate_network() {
case "$protocol" in
static)
local ipad netm prefix
local ipad
case "$1" in
lan) ipad=${ipaddr:-"192.168.1.1"} ;;
*) ipad=${ipaddr:-"192.168.$((addr_offset++)).1"} ;;
esac
netm=${netmask:-"255.255.255.0"}
str2ip netm "$netm"
netmask2prefix prefix "$netm"
uci -q batch <<-EOF
set network.$1.proto='static'
add_list network.$1.ipaddr='$ipad/$prefix'
set network.$1.ipaddr='$ipad'
set network.$1.netmask='$netm'
EOF
[ -e /proc/sys/net/ipv6 ] && uci set network.$1.ip6assign='60'
;;
@@ -323,11 +321,11 @@ generate_static_system() {
delete system.ntp
set system.ntp='timeserver'
set system.ntp.enabled='1'
set system.ntp.enable_server='0'
add_list system.ntp.server='0.openwrt.pool.ntp.org'
add_list system.ntp.server='1.openwrt.pool.ntp.org'
add_list system.ntp.server='2.openwrt.pool.ntp.org'
add_list system.ntp.server='3.openwrt.pool.ntp.org'
set system.ntp.enable_server='1'
add_list system.ntp.server='time.apple.com'
add_list system.ntp.server='time.google.com'
add_list system.ntp.server='time.windows.com'
add_list system.ntp.server='time.cloudflare.com'
EOF
if json_is_a system object; then

View File

@@ -10,6 +10,7 @@ uci_apply_defaults() {
cd /etc/uci-defaults || return 0
files="$(ls)"
[ -z "$files" ] && return 0
mkdir -p /tmp/.uci
applied=""
for file in $files; do
( . "./$(basename $file)" ) && applied="$applied $file"
@@ -43,7 +44,6 @@ boot() {
grep -q pstore /proc/filesystems && /bin/mount -o nosuid,nodev,noexec,noatime -t pstore pstore /sys/fs/pstore
[ "$FAILSAFE" = "true" ] && touch /tmp/.failsafe
touch /tmp/.config_pending
/sbin/kmodloader
[ ! -f /etc/config/wireless ] && {
@@ -51,14 +51,10 @@ boot() {
sleep 1
}
mkdir -p /tmp/.uci
[ -f /etc/uci-defaults/30_uboot-envtools ] && (. /etc/uci-defaults/30_uboot-envtools)
/bin/config_generate
rm -f /tmp/.config_pending
/sbin/wifi config
uci_apply_defaults
sync
# temporary hack until configd exists
/sbin/reload_config
}

View File

@@ -38,24 +38,3 @@ in order to prevent unauthorized SSH logins.
--------------------------------------------------
EOF
fi
if [ -x /usr/bin/apk ]; then
cat << EOF
OpenWrt recently switched to the "apk" package manager!
OPKG Command APK Equivalent Description
------------------------------------------------------------------
opkg install <pkg> apk add <pkg> Install a package
opkg remove <pkg> apk del <pkg> Remove a package
opkg upgrade apk upgrade Upgrade all packages
opkg files <pkg> apk info -L <pkg> List package contents
opkg list-installed apk info List installed packages
opkg update apk update Update package lists
opkg search <pkg> apk search <pkg> Search for packages
------------------------------------------------------------------
For more https://openwrt.org/docs/guide-user/additional-software/opkg-to-apk-cheatsheet
EOF
fi

View File

@@ -1,2 +1,5 @@
# User defined entries should be added to this file not to /etc/sysctl.d/* as
# that directory is not backed-up by default and will not survive a reimage
# Defaults are configured in /etc/sysctl.d/* and can be customized in this file
net.bridge.bridge-nf-call-arptables = 0
net.bridge.bridge-nf-call-ip6tables = 0
net.bridge.bridge-nf-call-iptables = 0

View File

@@ -1,49 +0,0 @@
. /lib/functions.sh
migrate_ports() {
local config="$1"
local type ports ifname
config_get type "$config" type
[ "$type" != "bridge" ] && return
config_get ports "$config" ports
[ -n "$ports" ] && return
config_get ifname "$config" ifname
[ -z "$ifname" ] && return
for port in $ifname; do
uci add_list network.$config.ports="$port"
done
uci delete network.$config.ifname
}
migrate_bridge() {
local config="$1"
local type ifname
config_get type "$config" type
[ "$type" != "bridge" ] && return
config_get ifname "$config" ifname
uci -q batch <<-EOF
add network device
set network.@device[-1].name='br-$config'
set network.@device[-1].type='bridge'
EOF
for port in $ifname; do
uci add_list network.@device[-1].ports="$port"
done
uci -q batch <<-EOF
delete network.$config.type
delete network.$config.ifname
set network.$config.device='br-$config'
EOF
}
config_load network
config_foreach migrate_ports device
config_foreach migrate_bridge interface

View File

@@ -1,9 +0,0 @@
[ "$(uci -q get network.globals.dhcp_default_duid)" != "auto" ] && exit 0
uci -q batch <<-EOF >/dev/null
# DUID-UUID - RFC6355
set network.globals.dhcp_default_duid="$(hexdump -vn 16 -e '"0004" 2/2 "%x"' /dev/urandom)"
commit network
EOF
exit 0

View File

@@ -211,14 +211,9 @@ config_list_foreach() {
default_prerm() {
local root="${IPKG_INSTROOT}"
[ -z "$pkgname" ] && local pkgname="$(basename ${1%.*})"
local pkgname="$(basename ${1%.*})"
local ret=0
local filelist="${root}/usr/lib/opkg/info/${pkgname}.list"
[ -f "$root/lib/apk/packages/${pkgname}.list" ] && filelist="$root/lib/apk/packages/${pkgname}.list"
if [ -e "$root/lib/apk/packages/${pkgname}.alternatives" ]; then
update_alternatives remove "${pkgname}"
fi
if [ -f "$root/usr/lib/opkg/info/${pkgname}.prerm-pkg" ]; then
( . "$root/usr/lib/opkg/info/${pkgname}.prerm-pkg" )
@@ -241,11 +236,8 @@ default_prerm() {
}
add_group_and_user() {
[ -z "$pkgname" ] && local pkgname="$(basename ${1%.*})"
local pkgname="$(basename ${1%.*})"
local rusers="$(sed -ne 's/^Require-User: *//p' $root/usr/lib/opkg/info/${pkgname}.control 2>/dev/null)"
if [ -f "$root/lib/apk/packages/${pkgname}.rusers" ]; then
local rusers="$(cat $root/lib/apk/packages/${pkgname}.rusers)"
fi
if [ -n "$rusers" ]; then
local tuple oIFS="$IFS"
@@ -295,70 +287,13 @@ add_group_and_user() {
fi
}
update_alternatives() {
local root="${IPKG_INSTROOT}"
local action="$1"
local pkgname="$2"
if [ -f "$root/lib/apk/packages/${pkgname}.alternatives" ]; then
for pkg_alt in $(cat $root/lib/apk/packages/${pkgname}.alternatives); do
local best_prio=0;
local best_src="/bin/busybox";
pkg_prio=${pkg_alt%%:*};
pkg_target=${pkg_alt#*:};
pkg_target=${pkg_target%:*};
pkg_src=${pkg_alt##*:};
if [ -e "$root/$target" ]; then
for alts in $root/lib/apk/packages/*.alternatives; do
for alt in $(cat $alts); do
prio=${alt%%:*};
target=${alt#*:};
target=${target%:*};
src=${alt##*:};
if [ "$target" = "$pkg_target" ] &&
[ "$src" != "$pkg_src" ] &&
[ "$best_prio" -lt "$prio" ]; then
best_prio=$prio;
best_src=$src;
fi
done
done
fi
case "$action" in
install)
if [ "$best_prio" -lt "$pkg_prio" ]; then
ln -sf "$pkg_src" "$root/$pkg_target"
echo "add alternative: $pkg_target -> $pkg_src"
fi
;;
remove)
if [ "$best_prio" -lt "$pkg_prio" ]; then
ln -sf "$best_src" "$root/$pkg_target"
echo "add alternative: $pkg_target -> $best_src"
fi
;;
esac
done
fi
}
default_postinst() {
local root="${IPKG_INSTROOT}"
[ -z "$pkgname" ] && local pkgname="$(basename ${1%.*})"
local filelist="${root}/usr/lib/opkg/info/${pkgname}.list"
[ -f "$root/lib/apk/packages/${pkgname}.list" ] && filelist="$root/lib/apk/packages/${pkgname}.list"
local pkgname="$(basename ${1%.*})"
local filelist="/usr/lib/opkg/info/${pkgname}.list"
local ret=0
if [ -e "${root}/usr/lib/opkg/info/${pkgname}.list" ]; then
filelist="${root}/usr/lib/opkg/info/${pkgname}.list"
add_group_and_user "${pkgname}"
fi
if [ -e "${root}/lib/apk/packages/${pkgname}.alternatives" ]; then
update_alternatives install "${pkgname}"
fi
add_group_and_user "${pkgname}"
if [ -d "$root/rootfs-overlay" ]; then
cp -R $root/rootfs-overlay/. $root/

View File

@@ -201,7 +201,7 @@ ath11k_remove_regdomain() {
regdomain=$(hexdump -v -n 2 -s 0x34 -e '1/1 "%02x"' $target)
caldata_patch_data "0000" 0x34 0xa "$target"
for offset in 0x450 0x458 0x500 0x5a8; do
regdomain_data=$(hexdump -v -n 2 -s $offset -e '1/1 "%02x"' $target)

View File

@@ -66,7 +66,7 @@ get_mac_ascii() {
local key="$2"
local mac_dirty
mac_dirty=$(strings "$part" | tr -d ' \t' | sed -n 's/^'"$key"'=//p' | head -n 1)
mac_dirty=$(strings "$part" | sed -n "s/^$key\\(=\\?\)//p")
# "canonicalize" mac
[ -n "$mac_dirty" ] && macaddr_canonicalize "$mac_dirty"
@@ -275,7 +275,7 @@ macaddr_unsetbit_mc() {
macaddr_random() {
local randsrc=$(get_mac_binary /dev/urandom 0)
echo "$(macaddr_unsetbit_mc "$(macaddr_setbit_la "${randsrc}")")"
}

View File

@@ -9,14 +9,9 @@ indicate_failsafe_led () {
indicate_failsafe() {
[ "$pi_preinit_no_failsafe" = "y" ] && return
local consoles="$(cat /sys/class/tty/console/active)"
[ -n "$consoles" ] || consoles=console
for console in $consoles; do
[ -c "/dev/$console" ] && echo "- failsafe -" >"/dev/$console"
done
echo "- failsafe -"
preinit_net_echo "Entering Failsafe!\n"
indicate_failsafe_led
echo OpenWrt-failsafe > /proc/sys/kernel/hostname
}
boot_hook_add failsafe indicate_failsafe

View File

@@ -36,6 +36,7 @@ compose_rootfs_mount_options() {
do_mount_root() {
mount_root start "$(compose_rootfs_mount_options)"
boot_run_hook preinit_mount_root
[ ! -f /etc/bench.log ] && touch /etc/bench.log
[ -f /sysupgrade.tgz -o -f /tmp/sysupgrade.tar ] && {
echo "- config restore -"
cp /etc/passwd /etc/group /etc/shadow /tmp

View File

@@ -5,19 +5,11 @@ failsafe_shell() {
local consoles="$(cat /sys/class/tty/console/active)"
[ -n "$consoles" ] || consoles=console
for console in $consoles; do
case "$console" in
console|tty[0-9]*)
term=${TERM:-linux}
;;
*)
term=vt102
;;
esac
# Running asynchronously via the shell's & would ignore SIGINT,
# breaking ^C. Use start-stop-daemon instead.
[ -c "/dev/$console" ] && start-stop-daemon -Sb -p /dev/null -- env -i ash -c "while true; do setsid -c env -i USER=root LOGNAME=root SHELL=/bin/ash TERM="$term" ash --login <\"/dev/$console\" >\"/dev/$console\" 2>\"/dev/$console\"; sleep 1; done"
[ -c "/dev/$console" ] && while true; do
ash --login <"/dev/$console" >"/dev/$console" 2>"/dev/$console"
sleep 1
done &
done
}
boot_hook_add failsafe failsafe_shell

View File

@@ -165,6 +165,23 @@ part_magic_fat() {
[ "$magic" = "FAT" ] || [ "$magic_fat32" = "FAT32" ]
}
fitblk_get_bootdev() {
[ -e /sys/firmware/devicetree/base/chosen/rootdisk ] || return
local rootdisk="$(cat /sys/firmware/devicetree/base/chosen/rootdisk)"
local handle bootdev
for handle in /sys/class/block/*/of_node/phandle /sys/class/block/*/device/of_node/phandle; do
[ ! -e "$handle" ] && continue
if [ "$rootdisk" = "$(cat $handle)" ]; then
bootdev="${handle%/of_node/phandle}"
bootdev="${bootdev%/device}"
bootdev="${bootdev#/sys/class/block/}"
echo "$bootdev"
break
fi
done
}
export_bootdevice() {
local cmdline uuid blockdev uevent line class
local MAJOR MINOR DEVNAME DEVTYPE
@@ -196,6 +213,7 @@ export_bootdevice() {
done
;;
/dev/*)
[ "$rootpart" = "/dev/fit0" ] && rootpart="$(fitblk_get_bootdev)"
uevent="/sys/class/block/${rootpart##*/}/../uevent"
;;
0x[a-f0-9][a-f0-9][a-f0-9] | 0x[a-f0-9][a-f0-9][a-f0-9][a-f0-9] | \

View File

@@ -8,38 +8,22 @@ emmc_upgrade_tar() {
[ "$CI_KERNPART" -a -z "$EMMC_KERN_DEV" ] && export EMMC_KERN_DEV="$(find_mmc_part $CI_KERNPART $CI_ROOTDEV)"
[ "$CI_ROOTPART" -a -z "$EMMC_ROOT_DEV" ] && export EMMC_ROOT_DEV="$(find_mmc_part $CI_ROOTPART $CI_ROOTDEV)"
[ "$CI_DATAPART" -a -z "$EMMC_DATA_DEV" ] && export EMMC_DATA_DEV="$(find_mmc_part $CI_DATAPART $CI_ROOTDEV)"
[ "$CI_DTBPART" -a -z "$EMMC_DTB_DEV" ] && export EMMC_DTB_DEV="$(find_mmc_part $CI_DTBPART $CI_ROOTDEV)"
local has_kernel
local has_rootfs
local has_dtb
local gz
local board_dir
[ "$(identify_magic_long $(get_magic_long "$tar_file" cat))" = "gzip" ] && \
gz="z"
board_dir=$(tar t${gz}f "$tar_file" | grep -m 1 '^sysupgrade-.*/$')
local board_dir=$(tar tf "$tar_file" | grep -m 1 '^sysupgrade-.*/$')
board_dir=${board_dir%/}
tar t${gz}f "$tar_file" ${board_dir}/kernel 1>/dev/null 2>/dev/null && has_kernel=1
tar t${gz}f "$tar_file" ${board_dir}/root 1>/dev/null 2>/dev/null && has_rootfs=1
tar t${gz}f "$tar_file" ${board_dir}/dtb 1>/dev/null 2>/dev/null && has_dtb=1
[ "$has_rootfs" = 1 -a "$EMMC_ROOT_DEV" ] && {
# Invalidate kernel image while rootfs is being written
[ "$has_kernel" = 1 -a "$EMMC_KERN_DEV" ] && {
dd if=/dev/zero of="$EMMC_KERN_DEV" bs=512 count=8
sync
}
export EMMC_ROOTFS_BLOCKS=$(($(tar x${gz}f "$tar_file" ${board_dir}/root -O | dd of="$EMMC_ROOT_DEV" bs=512 2>&1 | grep "records out" | cut -d' ' -f1)))
# Account for 64KiB ROOTDEV_OVERLAY_ALIGN in libfstools
EMMC_ROOTFS_BLOCKS=$(((EMMC_ROOTFS_BLOCKS + 127) & ~127))
sync
}
[ "$has_dtb" = 1 -a "$EMMC_DTB_DEV" ] &&
export EMMC_DTB_BLOCKS=$(($(tar x${gz}f "$tar_file" ${board_dir}/dtb -O | dd of="$EMMC_DTB_DEV" bs=512 2>&1 | grep "records out" | cut -d' ' -f1)))
tar tf "$tar_file" ${board_dir}/kernel 1>/dev/null 2>/dev/null && has_kernel=1
tar tf "$tar_file" ${board_dir}/root 1>/dev/null 2>/dev/null && has_rootfs=1
[ "$has_kernel" = 1 -a "$EMMC_KERN_DEV" ] &&
export EMMC_KERNEL_BLOCKS=$(($(tar x${gz}f "$tar_file" ${board_dir}/kernel -O | dd of="$EMMC_KERN_DEV" bs=512 2>&1 | grep "records out" | cut -d' ' -f1)))
export EMMC_KERNEL_BLOCKS=$(($(tar xf "$tar_file" ${board_dir}/kernel -O | dd of="$EMMC_KERN_DEV" bs=512 2>&1 | grep "records out" | cut -d' ' -f1)))
[ "$has_rootfs" = 1 -a "$EMMC_ROOT_DEV" ] && {
export EMMC_ROOTFS_BLOCKS=$(($(tar xf "$tar_file" ${board_dir}/root -O | dd of="$EMMC_ROOT_DEV" bs=512 2>&1 | grep "records out" | cut -d' ' -f1)))
# Account for 64KiB ROOTDEV_OVERLAY_ALIGN in libfstools
EMMC_ROOTFS_BLOCKS=$(((EMMC_ROOTFS_BLOCKS + 127) & ~127))
}
if [ -z "$UPGRADE_BACKUP" ]; then
if [ "$EMMC_DATA_DEV" ]; then

View File

@@ -42,9 +42,7 @@ fwtool_check_image() {
v "Invalid image metadata"
return 1
}
# Step 1. check if oem_name file exist and is not empty
# If the above is true store the contents (b3000) in $oem value for later
[ -s /tmp/sysinfo/oem_name ] && oem="$(cat /tmp/sysinfo/oem_name)"
device="$(cat /tmp/sysinfo/board_name)"
devicecompat="$(uci -q get system.@system[0].compat_version)"
[ -n "$devicecompat" ] || devicecompat="1.0"
@@ -63,16 +61,7 @@ fwtool_check_image() {
json_get_keys dev_keys
for k in $dev_keys; do
json_get_var dev "$k"
# Step 2.
# lets start with the original case [ "$dev" = "$device" ]
# if the evaluated firmware is vanila openwrt, this evals as true -ie
# [ ("$dev" == "glinet.gl-b3000") == ("$device" == "glinet,gl-b3000") ]
# however if the firmware is oem then $dev = b3000 and the above check fails resulting
# in the erroneous warnings.
# so we add the secondary check [ "$dev" = "$oem" ];
# If in Step 1 the oem_file was found and valid, the $oem == "b3000" so
# [ ("$dev" == "b3000) == ("$oem" == "b3000") ] so firmware is valid oem
if [ "$dev" = "$device" ] || [ "$dev" = "$oem" ]; then
if [ "$dev" = "$device" ]; then
# major compat version -> no sysupgrade
if [ "${devicecompat%.*}" != "${imagecompat%.*}" ]; then
v "The device is supported, but this image is incompatible for sysupgrade based on the image version ($devicecompat->$imagecompat)."
@@ -81,16 +70,7 @@ fwtool_check_image() {
fi
# minor compat version -> sysupgrade with -n required
# Step 3.
# here we must check if $dev == $oem to use this native compatability check
# so we add the check for [ "$dev" = "$oem" ]
if (([ "${devicecompat#.*}" != "${imagecompat#.*}" ] || [ "$dev" = "$oem" ])) && [ "$SAVE_CONFIG" = "1" ]; then
# Step 4.
# here we have to gaurd against the default case, oem may exsist and default will pass
# the original check [ "${devicecompat#.*}" != "${imagecompat#.*}" ] so we must
# explicitly check $dev == $oem, if it is we update(reuse) the $devicecompat and imagecompat
# variable to reflect the case - ( Openwrt -> OEM )
[ "$dev" = "$oem" ] && devicecompat="Openwrt " && imagecompat=" OEM"
if [ "${devicecompat#.*}" != "${imagecompat#.*}" ] && [ "$SAVE_CONFIG" = "1" ]; then
[ "$IGNORE_MINOR_COMPAT" = 1 ] && return 0
v "The device is supported, but the config is incompatible to the new image ($devicecompat->$imagecompat). Please upgrade without keeping config (sysupgrade -n)."
[ -n "$compatmessage" ] && v "$compatmessage"

View File

@@ -57,11 +57,11 @@ nand_find_ubi() {
}
nand_get_magic_long() {
($2 < "$1" | dd bs=4 "skip=${3:-0}" count=1 | hexdump -v -n 4 -e '1/1 "%02x"') 2> /dev/null
(${3}cat "$1" | dd bs=4 "skip=${2:-0}" count=1 | hexdump -v -n 4 -e '1/1 "%02x"') 2> /dev/null
}
get_magic_long_tar() {
($2 < "$1" | tar xOf - "$3" | dd bs=4 count=1 | hexdump -v -n 4 -e '1/1 "%02x"') 2> /dev/null
(tar xO${3}f "$1" "$2" | dd bs=4 count=1 | hexdump -v -n 4 -e '1/1 "%02x"') 2> /dev/null
}
identify() {
@@ -73,7 +73,7 @@ identify_tar() {
}
identify_if_gzip() {
if [ "$(identify "$1" "cat")" = gzip ]; then echo -n z; fi
if [ "$(identify "$1")" = gzip ]; then echo -n z; fi
}
nand_restore_config() {
@@ -111,7 +111,7 @@ nand_remove_ubiblock() {
local ubiblk="ubiblock${ubivol:3}"
if [ -e "/dev/$ubiblk" ]; then
umount "/dev/$ubiblk" 2>/dev/null && echo "unmounted /dev/$ubiblk" || :
umount "/dev/$ubiblk" && echo "unmounted /dev/$ubiblk" || :
if ! ubiblock -r "/dev/$ubivol"; then
echo "cannot remove $ubiblk"
return 1
@@ -217,16 +217,6 @@ nand_upgrade_prepare_ubi() {
[ "$root_ubivol" ] && ubirmvol /dev/$root_ubidev -N "$CI_ROOTPART" || :
[ "$data_ubivol" ] && ubirmvol /dev/$root_ubidev -N rootfs_data || :
# create provisioning vol
if [ "${UPGRADE_OPT_ADD_PROVISIONING:-0}" -gt 0 ]; then
[ -n "$(nand_find_volume $root_ubidev provisioning)" ] || {
if ! ubimkvol /dev/$root_ubidev -N provisioning -s 131072; then
echo "cannot create provisioning volume"
return 1
fi
}
fi
# create kernel vol
if [ -n "$kernel_length" ]; then
if ! ubimkvol /dev/$kern_ubidev -N "$CI_KERNPART" -s $kernel_length; then
@@ -269,64 +259,64 @@ nand_upgrade_prepare_ubi() {
# Write the UBI image to MTD ubi partition
nand_upgrade_ubinized() {
local ubi_file="$1"
local cmd="$2"
local gz="$2"
local ubi_length=$( ($cmd < "$ubi_file" | wc -c) 2> /dev/null)
local ubi_length=$( (${gz}cat "$ubi_file" | wc -c) 2> /dev/null)
nand_detach_ubi "$CI_UBIPART" || return 1
local mtdnum="$( find_mtd_index "$CI_UBIPART" )"
$cmd < "$ubi_file" | ubiformat "/dev/mtd$mtdnum" -S "$ubi_length" -y -f - && ubiattach -m "$mtdnum"
${gz}cat "$ubi_file" | ubiformat "/dev/mtd$mtdnum" -S "$ubi_length" -y -f - && ubiattach -m "$mtdnum"
}
# Write the UBIFS image to UBI rootfs volume
nand_upgrade_ubifs() {
local ubifs_file="$1"
local cmd="$2"
local gz="$2"
local ubifs_length=$( ($cmd < "$ubifs_file" | wc -c) 2> /dev/null)
local ubifs_length=$( (${gz}cat "$ubifs_file" | wc -c) 2> /dev/null)
nand_upgrade_prepare_ubi "$ubifs_length" "ubifs" "" "" || return 1
local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
local root_ubivol="$(nand_find_volume $ubidev "$CI_ROOTPART")"
$cmd < "$ubifs_file" | ubiupdatevol /dev/$root_ubivol -s "$ubifs_length" -
${gz}cat "$ubifs_file" | ubiupdatevol /dev/$root_ubivol -s "$ubifs_length" -
}
# Write the FIT image to UBI kernel volume
nand_upgrade_fit() {
local fit_file="$1"
local cmd="$2"
local gz="$2"
local fit_length=$( ($cmd < "$fit_file" | wc -c) 2> /dev/null)
local fit_length=$( (${gz}cat "$fit_file" | wc -c) 2> /dev/null)
nand_upgrade_prepare_ubi "" "" "$fit_length" "1" || return 1
local fit_ubidev="$(nand_find_ubi "$CI_UBIPART")"
local fit_ubivol="$(nand_find_volume $fit_ubidev "$CI_KERNPART")"
$cmd < "$fit_file" | ubiupdatevol /dev/$fit_ubivol -s "$fit_length" -
${gz}cat "$fit_file" | ubiupdatevol /dev/$fit_ubivol -s "$fit_length" -
}
# Write images in the TAR file to MTD partitions and/or UBI volumes as required
nand_upgrade_tar() {
local tar_file="$1"
local cmd="${2:-cat}"
local gz="$2"
local jffs2_markers="${CI_JFFS2_CLEAN_MARKERS:-0}"
# WARNING: This fails if tar contains more than one 'sysupgrade-*' directory.
local board_dir="$($cmd < "$tar_file" | tar tf - | grep -m 1 '^sysupgrade-.*/$')"
local board_dir="$(tar t${gz}f "$tar_file" | grep -m 1 '^sysupgrade-.*/$')"
board_dir="${board_dir%/}"
local kernel_mtd kernel_length
if [ "$CI_KERNPART" != "none" ]; then
kernel_mtd="$(find_mtd_index "$CI_KERNPART")"
kernel_length=$( ($cmd < "$tar_file" | tar xOf - "$board_dir/kernel" | wc -c) 2> /dev/null)
kernel_length=$( (tar xO${gz}f "$tar_file" "$board_dir/kernel" | wc -c) 2> /dev/null)
[ "$kernel_length" = 0 ] && kernel_length=
fi
local rootfs_length=$( ($cmd < "$tar_file" | tar xOf - "$board_dir/root" | wc -c) 2> /dev/null)
local rootfs_length=$( (tar xO${gz}f "$tar_file" "$board_dir/root" | wc -c) 2> /dev/null)
[ "$rootfs_length" = 0 ] && rootfs_length=
local rootfs_type
[ "$rootfs_length" ] && rootfs_type="$(identify_tar "$tar_file" "$cmd" "$board_dir/root")"
[ "$rootfs_length" ] && rootfs_type="$(identify_tar "$tar_file" "$board_dir/root" "$gz")"
local ubi_kernel_length
if [ "$kernel_length" ]; then
@@ -347,23 +337,23 @@ nand_upgrade_tar() {
if [ "$rootfs_length" ]; then
local ubidev="$( nand_find_ubi "${CI_ROOT_UBIPART:-$CI_UBIPART}" )"
local root_ubivol="$( nand_find_volume $ubidev "$CI_ROOTPART" )"
$cmd < "$tar_file" | tar xOf - "$board_dir/root" | \
tar xO${gz}f "$tar_file" "$board_dir/root" | \
ubiupdatevol /dev/$root_ubivol -s "$rootfs_length" -
fi
if [ "$kernel_length" ]; then
if [ "$kernel_mtd" ]; then
if [ "$jffs2_markers" = 1 ]; then
flash_erase -j "/dev/mtd${kernel_mtd}" 0 0
$cmd < "$tar_file" | tar xOf - "$board_dir/kernel" | \
tar xO${gz}f "$tar_file" "$board_dir/kernel" | \
nandwrite "/dev/mtd${kernel_mtd}" -
else
$cmd < "$tar_file" | tar xOf - "$board_dir/kernel" | \
tar xO${gz}f "$tar_file" "$board_dir/kernel" | \
mtd write - "$CI_KERNPART"
fi
else
local ubidev="$( nand_find_ubi "${CI_KERN_UBIPART:-$CI_UBIPART}" )"
local kern_ubivol="$( nand_find_volume $ubidev "$CI_KERNPART" )"
$cmd < "$tar_file" | tar xOf - "$board_dir/kernel" | \
tar xO${gz}f "$tar_file" "$board_dir/kernel" | \
ubiupdatevol /dev/$kern_ubivol -s "$kernel_length" -
fi
fi
@@ -373,9 +363,9 @@ nand_upgrade_tar() {
nand_verify_if_gzip_file() {
local file="$1"
local cmd="$2"
local gz="$2"
if [ "$cmd" = zcat ]; then
if [ "$gz" = z ]; then
echo "verifying compressed sysupgrade file integrity"
if ! gzip -t "$file"; then
echo "corrupted compressed sysupgrade file"
@@ -386,10 +376,10 @@ nand_verify_if_gzip_file() {
nand_verify_tar_file() {
local file="$1"
local cmd="$2"
local gz="$2"
echo "verifying sysupgrade tar file integrity"
if ! $cmd < "$file" | tar xOf - > /dev/null; then
if ! tar xO${gz}f "$file" > /dev/null; then
echo "corrupted sysupgrade tar file"
return 1
fi
@@ -397,30 +387,28 @@ nand_verify_tar_file() {
nand_do_flash_file() {
local file="$1"
local cmd="$2"
local file_type
[ -z "$cmd" ] && cmd="$(identify_if_gzip "$file")cat"
file_type="$(identify "$file" "$cmd" "")"
local gz="$(identify_if_gzip "$file")"
local file_type="$(identify "$file" "" "$gz")"
[ ! "$(find_mtd_index "$CI_UBIPART")" ] && CI_UBIPART=rootfs
case "$file_type" in
"fit")
nand_verify_if_gzip_file "$file" "$cmd" || return 1
nand_upgrade_fit "$file" "$cmd"
nand_verify_if_gzip_file "$file" "$gz" || return 1
nand_upgrade_fit "$file" "$gz"
;;
"ubi")
nand_verify_if_gzip_file "$file" "$cmd" || return 1
nand_upgrade_ubinized "$file" "$cmd"
nand_verify_if_gzip_file "$file" "$gz" || return 1
nand_upgrade_ubinized "$file" "$gz"
;;
"ubifs")
nand_verify_if_gzip_file "$file" "$cmd" || return 1
nand_upgrade_ubifs "$file" "$cmd"
nand_verify_if_gzip_file "$file" "$gz" || return 1
nand_upgrade_ubifs "$file" "$gz"
;;
*)
nand_verify_tar_file "$file" "$cmd" || return 1
nand_upgrade_tar "$file" "$cmd"
nand_verify_tar_file "$file" "$gz" || return 1
nand_upgrade_tar "$file" "$gz"
;;
esac
}
@@ -431,26 +419,11 @@ nand_do_restore_config() {
}
# Recognize type of passed file and start the upgrade process
#
# Supported firmware containers:
# 1. Raw file
# 2. Gzip
# 3. Custom (requires passing extracting command)
#
# Supported data formats:
# 1. Tar with kernel/rootfs
# 2. UBI image (built using "ubinized")
# 3. UBIFS image (to update UBI volume with)
# 4. FIT image (to update UBI volume with)
#
# $(1): firmware file path
# $(2): (optional) pipe command to extract firmware
nand_do_upgrade() {
local file="$1"
local cmd="$2"
sync
nand_do_flash_file "$file" "$cmd" && nand_do_upgrade_success
nand_do_flash_file "$file" && nand_do_upgrade_success
nand_do_upgrade_failed
}
@@ -487,18 +460,18 @@ nand_do_platform_check() {
local board_name="$1"
local file="$2"
local cmd="$(identify_if_gzip "$file")cat"
local file_type="$(identify "$file" "$cmd" "")"
local control_length=$( ($cmd < "$file" | tar xOf - "sysupgrade-${board_name//,/_}/CONTROL" | wc -c) 2> /dev/null)
local gz="$(identify_if_gzip "$file")"
local file_type="$(identify "$file" "" "$gz")"
local control_length=$( (tar xO${gz}f "$file" "sysupgrade-${board_name//,/_}/CONTROL" | wc -c) 2> /dev/null)
if [ "$control_length" = 0 ]; then
control_length=$( ($cmd < "$file" | tar xOf - "sysupgrade-${board_name//_/,}/CONTROL" | wc -c) 2> /dev/null)
control_length=$( (tar xO${gz}f "$file" "sysupgrade-${board_name//_/,}/CONTROL" | wc -c) 2> /dev/null)
fi
if [ "$control_length" != 0 ]; then
nand_verify_tar_file "$file" "$cmd" || return 1
nand_verify_tar_file "$file" "$gz" || return 1
else
nand_verify_if_gzip_file "$file" "$cmd" || return 1
nand_verify_if_gzip_file "$file" "$gz" || return 1
if [ "$file_type" != "fit" -a "$file_type" != "ubi" -a "$file_type" != "ubifs" ]; then
echo "invalid sysupgrade file"
return 1

View File

@@ -4,37 +4,29 @@
. /lib/functions/system.sh
. /usr/share/libubox/jshn.sh
# File-local constants
CONF_TAR=/tmp/sysupgrade.tgz
ETCBACKUP_DIR=/etc/backup
INSTALLED_PACKAGES=${ETCBACKUP_DIR}/installed_packages.txt
COMMAND=/lib/upgrade/do_stage2
# File-local globals
ADD_PROVISIONING=0
SAVE_OVERLAY=0
SAVE_OVERLAY_PATH=
SAVE_PARTITIONS=1
SAVE_INSTALLED_PKGS=0
SKIP_UNCHANGED=0
CONF_IMAGE=
CONF_BACKUP_LIST=0
CONF_BACKUP=
CONF_RESTORE=
USE_CURR_PART=0
NEED_IMAGE=
HELP=0
TEST=0
# Globals accessed in other files
# initialize defaults
export MTD_ARGS=""
export MTD_CONFIG_ARGS=""
export INTERACTIVE=0
export VERBOSE=1
export SAVE_CONFIG=1
export SAVE_OVERLAY=0
export SAVE_OVERLAY_PATH=
export SAVE_PARTITIONS=1
export SAVE_INSTALLED_PKGS=0
export SKIP_UNCHANGED=0
export CONF_IMAGE=
export CONF_BACKUP_LIST=0
export CONF_BACKUP=
export CONF_RESTORE=
export IGNORE_MINOR_COMPAT=0
export NEED_IMAGE=
export HELP=0
export FORCE=0
export CONFFILES=/tmp/sysupgrade.conffiles
export TEST=0
export USE_CURR_PART=0
export ADD_PROVISIONING=0
export UMOUNT_ETCBACKUP_DIR=0
# parse options
while [ -n "$1" ]; do
@@ -43,20 +35,20 @@ while [ -n "$1" ]; do
-v) export VERBOSE="$(($VERBOSE + 1))";;
-q) export VERBOSE="$(($VERBOSE - 1))";;
-n) export SAVE_CONFIG=0;;
-c) SAVE_OVERLAY=1 SAVE_OVERLAY_PATH=/etc;;
-o) SAVE_OVERLAY=1 SAVE_OVERLAY_PATH=/;;
-p) SAVE_PARTITIONS=0;;
-P) ADD_PROVISIONING=1;;
-k) SAVE_INSTALLED_PKGS=1;;
-u) SKIP_UNCHANGED=1;;
-b|--create-backup) CONF_BACKUP="$2" NEED_IMAGE=1; shift;;
-r|--restore-backup) CONF_RESTORE="$2" NEED_IMAGE=1; shift;;
-l|--list-backup) CONF_BACKUP_LIST=1;;
-f) CONF_IMAGE="$2"; shift;;
-s) USE_CURR_PART=1;;
-c) export SAVE_OVERLAY=1 SAVE_OVERLAY_PATH=/etc;;
-o) export SAVE_OVERLAY=1 SAVE_OVERLAY_PATH=/;;
-p) export SAVE_PARTITIONS=0;;
-P) export ADD_PROVISIONING=1;;
-k) export SAVE_INSTALLED_PKGS=1;;
-u) export SKIP_UNCHANGED=1;;
-b|--create-backup) export CONF_BACKUP="$2" NEED_IMAGE=1; shift;;
-r|--restore-backup) export CONF_RESTORE="$2" NEED_IMAGE=1; shift;;
-l|--list-backup) export CONF_BACKUP_LIST=1;;
-f) export CONF_IMAGE="$2"; shift;;
-s) export USE_CURR_PART=1;;
-F|--force) export FORCE=1;;
-T|--test) TEST=1;;
-h|--help) HELP=1; break;;
-T|--test) export TEST=1;;
-h|--help) export HELP=1; break;;
--ignore-minor-compat-version) export IGNORE_MINOR_COMPAT=1;;
-*)
echo "Invalid option: $1" >&2
@@ -67,6 +59,11 @@ while [ -n "$1" ]; do
shift;
done
export CONFFILES=/tmp/sysupgrade.conffiles
export CONF_TAR=/tmp/sysupgrade.tgz
export ETCBACKUP_DIR=/etc/backup
export INSTALLED_PACKAGES=${ETCBACKUP_DIR}/installed_packages.txt
print_help() {
cat <<EOF
Usage: $0 [<upgrade-option>...] <image file or URL>
@@ -137,20 +134,12 @@ fi
list_conffiles() {
if [ -f /usr/lib/opkg/status ]; then
awk '
BEGIN { conffiles = 0 }
/^Conffiles:/ { conffiles = 1; next }
!/^ / { conffiles = 0; next }
conffiles == 1 { print }
' /usr/lib/opkg/status
elif [ -d /lib/apk/packages ]; then
conffiles=""
for file in /lib/apk/packages/*.conffiles_static; do
conffiles="$(echo -e "$(cat $file)\n$conffiles")"
done
echo "$conffiles"
fi
awk '
BEGIN { conffiles = 0 }
/^Conffiles:/ { conffiles = 1; next }
!/^ / { conffiles = 0; next }
conffiles == 1 { print }
' /usr/lib/opkg/status
}
list_changed_conffiles() {
@@ -249,77 +238,53 @@ fi
include /lib/upgrade
create_backup_archive() {
do_save_conffiles() {
local conf_tar="$1"
local disabled
local err
[ "$(rootfs_type)" = "tmpfs" ] && {
echo "Cannot save config while running from ramdisk." >&2
ask_bool 0 "Abort" && exit
rm -f "$conf_tar"
return 0
}
run_hooks "$CONFFILES" $sysupgrade_init_conffiles
ask_bool 0 "Edit config file list" && vi "$CONFFILES"
[ "$conf_tar" != "-" ] || conf_tar=""
if [ "$SAVE_INSTALLED_PKGS" -eq 1 ]; then
echo "${INSTALLED_PACKAGES}" >> "$CONFFILES"
mkdir -p "$ETCBACKUP_DIR"
# Avoid touching filesystem on each backup
RAMFS="$(mktemp -d -t sysupgrade.XXXXXX)"
mkdir -p "$RAMFS/upper" "$RAMFS/work"
mount -t overlay overlay -o lowerdir=$ETCBACKUP_DIR,upperdir=$RAMFS/upper,workdir=$RAMFS/work $ETCBACKUP_DIR &&
UMOUNT_ETCBACKUP_DIR=1 || {
echo "Cannot mount '$ETCBACKUP_DIR' as tmpfs to avoid touching disk while saving the list of installed packages." >&2
ask_bool 0 "Abort" && exit
}
# Format: pkg-name<TAB>{rom,overlay,unkown}
# rom is used for pkgs in /rom, even if updated later
find /usr/lib/opkg/info -name "*.control" \( \
\( -exec test -f /rom/{} \; -exec echo {} rom \; \) -o \
\( -exec test -f /overlay/upper/{} \; -exec echo {} overlay \; \) -o \
\( -exec echo {} unknown \; \) \
\) | sed -e 's,.*/,,;s/\.control /\t/' > ${INSTALLED_PACKAGES}
fi
v "Saving config files..."
[ "$VERBOSE" -gt 1 ] && TAR_V="v" || TAR_V=""
sed -i -e 's,^/,,' "$CONFFILES"
set -o pipefail
{
local ret=0
if [ $ret -eq 0 ]; then
for service in /etc/init.d/*; do
if ! $service enabled >/dev/null 2>&1; then
disabled="$disabled$service disable\n"
fi
done
disabled="$disabled\nexit 0"
tar_print_member "/etc/uci-defaults/10_disable_services" "$(echo -e $disabled)" "$(date -r /etc/rc.d "+%s")" || ret=1
fi
# Part of archive with installed packages info
if [ $ret -eq 0 ]; then
if [ "$SAVE_INSTALLED_PKGS" -eq 1 ]; then
# Format: pkg-name<TAB>{rom,overlay,unknown}
# rom is used for pkgs in /rom, even if updated later
if [ -d "/usr/lib/opkg/info" ]; then
tar_print_member "$INSTALLED_PACKAGES" "$(find /usr/lib/opkg/info -name "*.control" \( \
\( -exec test -f /rom/{} \; -exec echo {} rom \; \) -o \
\( -exec test -f /overlay/upper/{} \; -exec echo {} overlay \; \) -o \
\( -exec echo {} unknown \; \) \
\) | sed -e 's,.*/,,;s/\.control /\t/')" || ret=1
elif [ -d "/lib/apk/packages" ]; then
tar_print_member "$INSTALLED_PACKAGES" "$(find /lib/apk/packages -name "*.list" \( \
\( -exec test -f /rom/{} \; -exec echo {} rom \; \) -o \
\( -exec test -f /overlay/upper/{} \; -exec echo {} overlay \; \) -o \
\( -exec echo {} unknown \; \) \
\) | sed -e 's,.*/,,;s/\.list /\t/')" || ret=1
fi
fi
fi
# Rest of archive with config files and ending padding
if [ $ret -eq 0 ]; then
tar c${TAR_V} -C / -T "$CONFFILES" || ret=1
fi
[ $ret -eq 0 ]
} | gzip > "${conf_tar:-/proc/self/fd/1}"
err=$?
set +o pipefail
if [ "$err" -ne 0 ]; then
tar c${TAR_V}zf "$conf_tar" -T "$CONFFILES" 2>/dev/null
if [ "$?" -ne 0 ]; then
echo "Failed to create the configuration backup."
[ -f "$conf_tar" ] && rm -f "$conf_tar"
rm -f "$conf_tar"
exit 1
fi
[ "$UMOUNT_ETCBACKUP_DIR" -eq 1 ] && {
umount "$ETCBACKUP_DIR"
rm -rf "$RAMFS"
}
rm -f "$CONFFILES"
return "$err"
}
if [ $CONF_BACKUP_LIST -eq 1 ]; then
@@ -331,8 +296,8 @@ if [ $CONF_BACKUP_LIST -eq 1 ]; then
fi
if [ -n "$CONF_BACKUP" ]; then
create_backup_archive "$CONF_BACKUP"
exit
do_save_conffiles "$CONF_BACKUP"
exit $?
fi
if [ -n "$CONF_RESTORE" ]; then
@@ -343,11 +308,7 @@ if [ -n "$CONF_RESTORE" ]; then
[ "$VERBOSE" -gt 1 ] && TAR_V="v" || TAR_V=""
v "Restoring config files..."
if [ "$(type -t platform_restore_backup)" == 'platform_restore_backup' ]; then
platform_restore_backup "$TAR_V"
else
tar -C / -x${TAR_V}zf "$CONF_RESTORE"
fi
tar -C / -x${TAR_V}zf "$CONF_RESTORE"
exit $?
fi
@@ -406,7 +367,7 @@ if [ -n "$CONF_IMAGE" ]; then
get_image "$CONF_IMAGE" "cat" > "$CONF_TAR"
export SAVE_CONFIG=1
elif ask_bool $SAVE_CONFIG "Keep config files over reflash"; then
[ $TEST -eq 1 ] || create_backup_archive "$CONF_TAR" || exit
[ $TEST -eq 1 ] || do_save_conffiles "$CONF_TAR"
export SAVE_CONFIG=1
else
[ $TEST -eq 1 ] || rm -f "$CONF_TAR"
@@ -420,6 +381,8 @@ fi
install_bin /sbin/upgraded
v "Commencing upgrade. Closing all shell sessions."
COMMAND='/lib/upgrade/do_stage2'
if [ -n "$FAILSAFE" ]; then
printf '%s\x00%s\x00%s' "$RAM_ROOT" "$IMAGE" "$COMMAND" >/tmp/sysupgrade
lock -u /tmp/.failsafe

View File

@@ -0,0 +1,271 @@
#!/bin/sh
# Copyright (C) 2006 OpenWrt.org
. /lib/functions.sh
. /usr/share/libubox/jshn.sh
usage() {
cat <<EOF
Usage: $0 [config|up|down|reconf|reload|status|isup]
enables (default), disables or configures devices not yet configured.
EOF
exit 1
}
ubus_wifi_cmd() {
local cmd="$1"
local dev="$2"
json_init
[ -n "$2" ] && json_add_string device "$2"
ubus call network.wireless "$1" "$(json_dump)"
}
wifi_isup() {
local dev="$1"
json_load "$(ubus_wifi_cmd "status" "$dev")"
json_get_keys devices
for device in $devices; do
json_select "$device"
json_get_var up up
[ $up -eq 0 ] && return 1
json_select ..
done
return 0
}
find_net_config() {(
local vif="$1"
local cfg
local ifname
config_get cfg "$vif" network
[ -z "$cfg" ] && {
include /lib/network
scan_interfaces
config_get ifname "$vif" ifname
cfg="$(find_config "$ifname")"
}
[ -z "$cfg" ] && return 0
echo "$cfg"
)}
bridge_interface() {(
local cfg="$1"
[ -z "$cfg" ] && return 0
include /lib/network
scan_interfaces
for cfg in $cfg; do
config_get iftype "$cfg" type
[ "$iftype" = bridge ] && config_get "$cfg" ifname
prepare_interface_bridge "$cfg"
return $?
done
)}
prepare_key_wep() {
local key="$1"
local hex=1
echo -n "$key" | grep -qE "[^a-fA-F0-9]" && hex=0
[ "${#key}" -eq 10 -a $hex -eq 1 ] || \
[ "${#key}" -eq 26 -a $hex -eq 1 ] || {
[ "${key:0:2}" = "s:" ] && key="${key#s:}"
key="$(echo -n "$key" | hexdump -ve '1/1 "%02x" ""')"
}
echo "$key"
}
wifi_fixup_hwmode() {
local device="$1"
local default="$2"
local hwmode hwmode_11n
config_get channel "$device" channel
config_get hwmode "$device" hwmode
case "$hwmode" in
11bg) hwmode=bg;;
11a) hwmode=a;;
11ad) hwmode=ad;;
11b) hwmode=b;;
11g) hwmode=g;;
11n*)
hwmode_11n="${hwmode##11n}"
case "$hwmode_11n" in
a|g) ;;
default) hwmode_11n="$default"
esac
config_set "$device" hwmode_11n "$hwmode_11n"
;;
*)
hwmode=
if [ "${channel:-0}" -gt 0 ]; then
if [ "${channel:-0}" -gt 14 ]; then
hwmode=a
else
hwmode=g
fi
else
hwmode="$default"
fi
;;
esac
config_set "$device" hwmode "$hwmode"
}
_wifi_updown() {
for device in ${2:-$DEVICES}; do (
config_get disabled "$device" disabled
[ "$disabled" = "1" ] && {
echo "'$device' is disabled"
set disable
}
config_get iftype "$device" type
if eval "type ${1}_$iftype" 2>/dev/null >/dev/null; then
eval "scan_$iftype '$device'"
eval "${1}_$iftype '$device'" || echo "$device($iftype): ${1} failed"
elif [ ! -f /lib/netifd/wireless/$iftype.sh ]; then
echo "$device($iftype): Interface type not supported"
fi
); done
}
wifi_updown() {
cmd=down
[ enable = "$1" ] && {
_wifi_updown disable "$2"
ubus_wifi_cmd "$cmd" "$2"
ubus call network reload
scan_wifi
cmd=up
}
[ reconf = "$1" ] && {
ubus call network reload
scan_wifi
cmd=reconf
}
ubus_wifi_cmd "$cmd" "$2"
_wifi_updown "$@"
}
wifi_reload_legacy() {
_wifi_updown "disable" "$1"
scan_wifi
_wifi_updown "enable" "$1"
}
wifi_reload() {
ubus call network reload
wifi_reload_legacy
}
wifi_detect_notice() {
>&2 echo "WARNING: Wifi detect is deprecated. Use wifi config instead"
>&2 echo "For more information, see commit 5f8f8a366136a07df661e31decce2458357c167a"
exit 1
}
wifi_config() {
[ ! -f /etc/config/wireless ] && touch /etc/config/wireless
for driver in $DRIVERS; do (
if eval "type detect_$driver" 2>/dev/null >/dev/null; then
eval "detect_$driver" || echo "$driver: Detect failed" >&2
else
echo "$driver: Hardware detection not supported" >&2
fi
); done
}
start_net() {(
local iface="$1"
local config="$2"
local vifmac="$3"
[ -f "/var/run/$iface.pid" ] && kill "$(cat /var/run/${iface}.pid)" 2>/dev/null
[ -z "$config" ] || {
include /lib/network
scan_interfaces
for config in $config; do
setup_interface "$iface" "$config" "" "$vifmac"
done
}
)}
set_wifi_up() {
local cfg="$1"
local ifname="$2"
uci_set_state wireless "$cfg" up 1
uci_set_state wireless "$cfg" ifname "$ifname"
}
set_wifi_down() {
local cfg="$1"
local vifs vif vifstr
[ -f "/var/run/wifi-${cfg}.pid" ] &&
kill "$(cat "/var/run/wifi-${cfg}.pid")" 2>/dev/null
uci_revert_state wireless "$cfg"
config_get vifs "$cfg" vifs
for vif in $vifs; do
uci_revert_state wireless "$vif"
done
}
scan_wifi() {
local cfgfile="$1"
DEVICES=
config_cb() {
local type="$1"
local section="$2"
# section start
case "$type" in
wifi-device)
append DEVICES "$section"
config_set "$section" vifs ""
config_set "$section" ht_capab ""
;;
esac
# section end
config_get TYPE "$CONFIG_SECTION" TYPE
case "$TYPE" in
wifi-iface)
config_get device "$CONFIG_SECTION" device
config_get vifs "$device" vifs
append vifs "$CONFIG_SECTION"
config_set "$device" vifs "$vifs"
;;
esac
}
config_load "${cfgfile:-wireless}"
}
DEVICES=
DRIVERS=
include /lib/wifi
scan_wifi
case "$1" in
down) wifi_updown "disable" "$2";;
detect) wifi_detect_notice ;;
config) wifi_config ;;
status) ubus_wifi_cmd "status" "$2";;
isup) wifi_isup "$2"; exit $?;;
reload) wifi_reload "$2";;
reload_legacy) wifi_reload_legacy "$2";;
--help|help) usage;;
reconf) wifi_updown "reconf" "$2";;
''|up) wifi_updown "enable" "$2";;
*) usage; exit 1;;
esac

View File

@@ -1,17 +1,5 @@
#!/bin/sh
[ -t 0 ] && {
tty_dev=$(readlink /proc/self/fd/0)
case "$tty_dev" in
/dev/console|/dev/tty[0-9]*)
export TERM=${TERM:-linux}
;;
/dev/*)
export TERM=vt102
;;
esac
}
[ "$(uci -q get system.@system[0].ttylogin)" = 1 ] || exec /bin/login -f root
[ "$(uci -q get system.@system[0].ttylogin)" = 1 ] || exec /bin/ash --login
exec /bin/login

View File

@@ -56,17 +56,7 @@ json_init
# Call platform_check_image() here so it can add its test
# results and still mark image properly.
json_set_namespace $old_ns
platform_check_image "$1" >&2
case "$?" in
0)
;;
74)
notify_firmware_broken
;;
*)
notify_firmware_invalid
;;
esac
platform_check_image "$1" >&2 || notify_firmware_invalid
json_set_namespace validate_firmware_image old_ns
json_close_object
json_add_boolean valid "$VALID"

View File

@@ -44,7 +44,7 @@ config TARGET_PREINIT_DISABLE_FAILSAFE
config TARGET_PREINIT_TIMEOUT
int
prompt "Failsafe/Debug wait timeout" if PREINITOPT
default 4
default 2
help
How long to wait for failsafe mode to be entered or for
a debug option to be pressed before continuing with a
@@ -241,12 +241,6 @@ if VERSIONOPT
help
This an URL to provide users seeking support
config VERSION_FIRMWARE_URL
string
prompt "Firmware URL"
help
This is an URL to provide users for downloading firmware
config VERSION_PRODUCT
string
prompt "Product name"

View File

@@ -40,7 +40,7 @@ endef
define KernelPackage/brcm-wl/Default
$(call Package/broadcom-wl/Default)
SECTION:=kernel
DEPENDS:=@(TARGET_bcm47xx||TARGET_bcm63xx) +wireless-tools +wifi-scripts +@KERNEL_WIRELESS_EXT
DEPENDS:=@(TARGET_bcm47xx||TARGET_bcm63xx) +wireless-tools
TITLE:=Kernel driver for BCM43xx chipsets
FILES:=$(PKG_BUILD_DIR)/driver$(1)/wl.ko $(PKG_BUILD_DIR)/glue/wl_glue.ko
AUTOLOAD:=$(call AutoProbe,wl)

View File

@@ -95,13 +95,12 @@ include ralink.mk
include realtek.mk
PKG_CONFIG_DEPENDS += \
CONFIG_WIFI_SCRIPTS_UCODE \
$(patsubst %,CONFIG_PACKAGE_kmod-%,$(PKG_DRIVERS))
define KernelPackage/cfg80211
$(call KernelPackage/mac80211/Default)
TITLE:=cfg80211 - wireless configuration API
DEPENDS+= +iw +!WIFI_SCRIPTS_UCODE:iwinfo +wifi-scripts +wireless-regdb +USE_RFKILL:kmod-rfkill
DEPENDS+= +iw +iwinfo +wireless-regdb +USE_RFKILL:kmod-rfkill
ABI_VERSION:=$(PKG_VERSION)-$(PKG_RELEASE)
FILES:= \
$(PKG_BUILD_DIR)/compat/compat.ko \
@@ -395,6 +394,14 @@ define Build/InstallDev
endef
define KernelPackage/cfg80211/install
$(INSTALL_DIR) $(1)/lib/wifi $(1)/lib/netifd/wireless
$(INSTALL_DATA) ./files/lib/wifi/mac80211.sh $(1)/lib/wifi
$(INSTALL_BIN) ./files/lib/netifd/wireless/mac80211.sh $(1)/lib/netifd/wireless
$(INSTALL_DIR) $(1)/etc/hotplug.d/ieee80211
$(INSTALL_DATA) ./files/mac80211.hotplug $(1)/etc/hotplug.d/ieee80211/10-wifi-detect
endef
$(eval $(foreach drv,$(PKG_DRIVERS),$(call KernelPackage,$(drv))))
$(eval $(call KernelPackage,cfg80211))
$(eval $(call KernelPackage,mac80211))

View File

@@ -393,9 +393,9 @@ define KernelPackage/ath12k
$(call KernelPackage/mac80211/Default)
TITLE:=Qualcomm 802.11be wireless chipset support
URL:=https://wireless.wiki.kernel.org/en/users/drivers/ath12k
DEPENDS+= @PCI_SUPPORT +kmod-ath +@DRIVER_11AC_SUPPORT +@DRIVER_11AX_SUPPORT \
+kmod-crypto-michael-mic +kmod-qrtr-mhi \
+kmod-qcom-qmi-helpers
DEPENDS+= @PCI_SUPPORT +kmod-ath +kmod-crypto-michael-mic \
+kmod-qrtr-mhi +kmod-qcom-qmi-helpers +@DRIVER_11AC_SUPPORT \
+@DRIVER_11AX_SUPPORT +@DRIVER_11BE_SUPPORT
FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/ath/ath12k/ath12k.ko
AUTOLOAD:=$(call AutoProbe,ath12k)
endef

View File

@@ -157,77 +157,79 @@ mac80211_hostapd_setup_base() {
chan_ofs=0
[ "$band" = "6g" ] && chan_ofs=1
ieee80211n=1
ht_capab=
case "$htmode" in
VHT20|HT20|HE20) ;;
HT40*|VHT40|VHT80|VHT160|HE40|HE80|HE160)
case "$hwmode" in
a)
case "$(( (($channel / 4) + $chan_ofs) % 2 ))" in
1) ht_capab="[HT40+]";;
0) ht_capab="[HT40-]";;
esac
;;
*)
case "$htmode" in
HT40+) ht_capab="[HT40+]";;
HT40-) ht_capab="[HT40-]";;
*)
if [ "$channel" -lt 7 ]; then
ht_capab="[HT40+]"
else
ht_capab="[HT40-]"
fi
;;
esac
;;
esac
[ "$auto_channel" -gt 0 ] && ht_capab="[HT40+]"
;;
*) ieee80211n= ;;
esac
if [ "$band" != "6g" ]; then
ieee80211n=1
ht_capab=
case "$htmode" in
VHT20|HT20|HE20|EHT20) ;;
HT40*|VHT40|VHT80|VHT160|HE40|HE80|HE160|EHT40|EHT80|EHT160)
case "$hwmode" in
a)
case "$(( (($channel / 4) + $chan_ofs) % 2 ))" in
1) ht_capab="[HT40+]";;
0) ht_capab="[HT40-]";;
esac
;;
*)
case "$htmode" in
HT40+) ht_capab="[HT40+]";;
HT40-) ht_capab="[HT40-]";;
*)
if [ "$channel" -lt 7 ]; then
ht_capab="[HT40+]"
else
ht_capab="[HT40-]"
fi
;;
esac
;;
esac
[ "$auto_channel" -gt 0 ] && ht_capab="[HT40+]"
;;
*) ieee80211n= ;;
esac
[ -n "$ieee80211n" ] && {
append base_cfg "ieee80211n=1" "$N"
[ -n "$ieee80211n" ] && {
append base_cfg "ieee80211n=1" "$N"
set_default ht_coex 0
append base_cfg "ht_coex=$ht_coex" "$N"
set_default ht_coex 0
append base_cfg "ht_coex=$ht_coex" "$N"
json_get_vars \
ldpc:1 \
greenfield:0 \
short_gi_20:1 \
short_gi_40:1 \
tx_stbc:1 \
rx_stbc:3 \
max_amsdu:1 \
dsss_cck_40:1
json_get_vars \
ldpc:1 \
greenfield:0 \
short_gi_20:1 \
short_gi_40:1 \
tx_stbc:1 \
rx_stbc:3 \
max_amsdu:1 \
dsss_cck_40:1
ht_cap_mask=0
for cap in $(iw phy "$phy" info | grep -E '^\s*Capabilities:' | cut -d: -f2); do
ht_cap_mask="$(($ht_cap_mask | $cap))"
done
ht_cap_mask=0
for cap in $(iw phy "$phy" info | grep -E '^\s*Capabilities:' | cut -d: -f2); do
ht_cap_mask="$(($ht_cap_mask | $cap))"
done
cap_rx_stbc=$((($ht_cap_mask >> 8) & 3))
[ "$rx_stbc" -lt "$cap_rx_stbc" ] && cap_rx_stbc="$rx_stbc"
ht_cap_mask="$(( ($ht_cap_mask & ~(0x300)) | ($cap_rx_stbc << 8) ))"
cap_rx_stbc=$((($ht_cap_mask >> 8) & 3))
[ "$rx_stbc" -lt "$cap_rx_stbc" ] && cap_rx_stbc="$rx_stbc"
ht_cap_mask="$(( ($ht_cap_mask & ~(0x300)) | ($cap_rx_stbc << 8) ))"
mac80211_add_capabilities ht_capab_flags $ht_cap_mask \
LDPC:0x1::$ldpc \
GF:0x10::$greenfield \
SHORT-GI-20:0x20::$short_gi_20 \
SHORT-GI-40:0x40::$short_gi_40 \
TX-STBC:0x80::$tx_stbc \
RX-STBC1:0x300:0x100:1 \
RX-STBC12:0x300:0x200:1 \
RX-STBC123:0x300:0x300:1 \
MAX-AMSDU-7935:0x800::$max_amsdu \
DSSS_CCK-40:0x1000::$dsss_cck_40
mac80211_add_capabilities ht_capab_flags $ht_cap_mask \
LDPC:0x1::$ldpc \
GF:0x10::$greenfield \
SHORT-GI-20:0x20::$short_gi_20 \
SHORT-GI-40:0x40::$short_gi_40 \
TX-STBC:0x80::$tx_stbc \
RX-STBC1:0x300:0x100:1 \
RX-STBC12:0x300:0x200:1 \
RX-STBC123:0x300:0x300:1 \
MAX-AMSDU-7935:0x800::$max_amsdu \
DSSS_CCK-40:0x1000::$dsss_cck_40
ht_capab="$ht_capab$ht_capab_flags"
[ -n "$ht_capab" ] && append base_cfg "ht_capab=$ht_capab" "$N"
}
ht_capab="$ht_capab$ht_capab_flags"
[ -n "$ht_capab" ] && append base_cfg "ht_capab=$ht_capab" "$N"
}
fi
# 802.11ac
enable_ac=0
@@ -236,8 +238,8 @@ mac80211_hostapd_setup_base() {
idx="$channel"
case "$htmode" in
VHT20|HE20) enable_ac=1;;
VHT40|HE40)
VHT20|HE20|EHT20) enable_ac=1;;
VHT40|HE40|EHT40)
case "$(( (($channel / 4) + $chan_ofs) % 2 ))" in
1) idx=$(($channel + 2));;
0) idx=$(($channel - 2));;
@@ -245,7 +247,7 @@ mac80211_hostapd_setup_base() {
enable_ac=1
vht_center_seg0=$idx
;;
VHT80|HE80)
VHT80|HE80|EHT80)
case "$(( (($channel / 4) + $chan_ofs) % 4 ))" in
1) idx=$(($channel + 6));;
2) idx=$(($channel + 2));;
@@ -256,7 +258,7 @@ mac80211_hostapd_setup_base() {
vht_oper_chwidth=1
vht_center_seg0=$idx
;;
VHT160|HE160)
VHT160|HE160|EHT160|EHT320)
if [ "$band" = "6g" ]; then
case "$channel" in
1|5|9|13|17|21|25|29) idx=15;;
@@ -284,15 +286,32 @@ mac80211_hostapd_setup_base() {
[ "$background_radar" -eq 1 ] && append base_cfg "enable_background_radar=1" "$N"
}
eht_oper_chwidth=$vht_oper_chwidth
eht_center_seg0=$vht_center_seg0
[ "$band" = "6g" ] && {
op_class=
case "$htmode" in
HE20) op_class=131;;
HE*) op_class=$((132 + $vht_oper_chwidth))
HE20|EHT20) op_class=131;;
EHT320)
case "$channel" in
1|5|9|13|17|21|25|29|33|37|41|45|49|53|57|61) idx=31;;
65|69|73|77|81|85|89|93|97|101|105|109|113|117|121|125) idx=95;;
129|133|137|141|145|149|153|157|161|165|169|173|177|181|185|189) idx=159;;
193|197|201|205|209|213|217|221) idx=191;;
esac
op_class=137
eht_center_seg0=$idx
eht_oper_chwidth=9
;;
HE*|EHT*) op_class=$((132 + $vht_oper_chwidth));;
esac
[ -n "$op_class" ] && append base_cfg "op_class=$op_class" "$N"
}
[ "$hwmode" = "a" ] || enable_ac=0
[ "$band" = "6g" ] && enable_ac=0
if [ "$enable_ac" != "0" -o "$vendor_vht" = "1" ]; then
json_get_vars \
@@ -415,8 +434,10 @@ mac80211_hostapd_setup_base() {
# 802.11ax
enable_ax=0
enable_be=0
case "$htmode" in
HE*) enable_ax=1 ;;
EHT*) enable_ax=1; enable_be=1 ;;
esac
if [ "$enable_ax" != "0" ]; then
@@ -490,6 +511,14 @@ mac80211_hostapd_setup_base() {
append base_cfg "he_mu_edca_ac_vo_timer=255" "$N"
fi
if [ "$enable_be" != "0" ]; then
append base_cfg "ieee80211be=1" "$N"
[ "$hwmode" = "a" ] && {
append base_cfg "eht_oper_chwidth=$eht_oper_chwidth" "$N"
append base_cfg "eht_oper_centr_freq_seg0_idx=$eht_center_seg0" "$N"
}
fi
hostapd_prepare_device_config "$hostapd_conf_file" nl80211
cat >> "$hostapd_conf_file" <<EOF
${channel:+channel=$channel}
@@ -1111,7 +1140,6 @@ drv_mac80211_setup() {
hostapd_conf_file="/var/run/hostapd-$phy.conf"
no_ap=1
macidx=0
staidx=0

View File

@@ -64,8 +64,7 @@ define KernelPackage/mt76-default
DEPENDS:= \
+kmod-mac80211 \
+@DRIVER_11AC_SUPPORT \
+@KERNEL_PAGE_POOL \
@!TARGET_uml
+@KERNEL_PAGE_POOL
endef
define KernelPackage/mt76
@@ -342,8 +341,8 @@ endef
define KernelPackage/mt7996e
$(KernelPackage/mt76-default)
TITLE:=MediaTek MT7996E wireless driver
DEPENDS+=@PCI_SUPPORT +kmod-mt76-connac +kmod-hwmon-core +@DRIVER_11AX_SUPPORT \
+@KERNEL_RELAY +@DRIVER_11BE_SUPPORT
DEPENDS+=@PCI_SUPPORT +kmod-mt76-connac +kmod-hwmon-core \
+@KERNEL_RELAY +@DRIVER_11AX_SUPPORT +@DRIVER_11BE_SUPPORT
FILES:= $(PKG_BUILD_DIR)/mt7996/mt7996e.ko
AUTOLOAD:=$(call AutoProbe,mt7996e)
endef
@@ -388,7 +387,7 @@ define KernelPackage/mt7925-common
$(KernelPackage/mt76-default)
TITLE:=MediaTek MT7925 wireless driver common code
HIDDEN:=1
DEPENDS+=+kmod-mt792x-common +@DRIVER_11AX_SUPPORT +kmod-hwmon-core +@DRIVER_11BE_SUPPORT
DEPENDS+=+kmod-mt792x-common +@DRIVER_11AX_SUPPORT +kmod-hwmon-core
FILES:= $(PKG_BUILD_DIR)/mt7925/mt7925-common.ko
endef

View File

@@ -36,6 +36,7 @@ sed -i 's/services/nas/g' /usr/lib/lua/luci/view/minidlna_status.htm
sed -i 's/\"services\"/\"nas\"/g' /usr/share/luci/menu.d/luci-app-samba4.json
sed -i 's#downloads.openwrt.org#mirrors.tencent.com/lede#g' /etc/opkg/distfeeds.conf
sed -i 's#downloads.openwrt.org#mirrors.tencent.com/lede#g' /etc/apk/repositories.d/distfeeds.list
sed -i 's/root::0:0:99999:7:::/root:$1$V4UetPzk$CYXluq4wUazHjmCDBCqXF.:0:0:99999:7:::/g' /etc/shadow
sed -i 's/root:::0:99999:7:::/root:$1$V4UetPzk$CYXluq4wUazHjmCDBCqXF.:0:0:99999:7:::/g' /etc/shadow

View File

@@ -12,9 +12,9 @@ PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/libnl-tiny.git
PKG_SOURCE_DATE:=2025-10-03
PKG_SOURCE_VERSION:=feca1d341d4baa9579ec62762672aa0f20edf564
PKG_MIRROR_HASH:=6362b51a2413684a259fb57847adad4ba934578a7e2c0c2cc5360e931115de21
PKG_SOURCE_DATE:=2025-03-19
PKG_SOURCE_VERSION:=c0df580adbd4d555ecc1962dbe88e91d75b67a4e
PKG_MIRROR_HASH:=e0a723e791549866e2d7e1f2aec2392343186645a2c7eae97e73e9fa72171d96
CMAKE_INSTALL:=1
PKG_LICENSE:=LGPL-2.1

View File

@@ -5,9 +5,9 @@ PKG_RELEASE=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/uclient.git
PKG_MIRROR_HASH:=7c443cac02a734dd312c65618f4de17248d188317f30a9fac192c1503b3d5c05
PKG_SOURCE_DATE:=2021-05-14
PKG_SOURCE_VERSION:=6a6011df3429ffa5958d12b1327eeda4fd9daa47
PKG_MIRROR_HASH:=339b58bd6d6f4b56bb5b0d41c9b47fdad6a7211a2a2eb264a62de3e07fcedfad
PKG_SOURCE_DATE:=2024-10-22
PKG_SOURCE_VERSION:=88ae8f208dd313f69e268234f7db55956aef1cb9
CMAKE_INSTALL:=1
PKG_BUILD_DEPENDS:=ustream-ssl
@@ -16,6 +16,7 @@ PKG_LICENSE:=ISC
PKG_LICENSE_FILES:=
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
PKG_CONFIG_DEPENDS := CONFIG_PACKAGE_ucode-mod-uclient
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mk
@@ -37,6 +38,16 @@ define Package/uclient-fetch
DEPENDS:=+libuclient
endef
define Package/ucode-mod-uclient
SECTION:=utils
CATEGORY:=Utilities
TITLE:=ucode uclient module
DEPENDS:=+libucode +libuclient
endef
CMAKE_OPTIONS += \
-DBUILD_UCODE=$(if $(CONFIG_PACKAGE_ucode-mod-uclient),ON,OFF)
define Package/libuclient/install
$(INSTALL_DIR) $(1)/usr/lib
$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libuclient.so $(1)/usr/lib/
@@ -47,5 +58,11 @@ define Package/uclient-fetch/install
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/uclient-fetch $(1)/bin/
endef
define Package/ucode-mod-uclient/install
$(INSTALL_DIR) $(1)/usr/lib/ucode
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/ucode/*.so $(1)/usr/lib/ucode
endef
$(eval $(call BuildPackage,libuclient))
$(eval $(call BuildPackage,uclient-fetch))
$(eval $(call BuildPackage,ucode-mod-uclient))

View File

@@ -11,9 +11,9 @@ PKG_NAME:=udebug
CMAKE_INSTALL:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/udebug.git
PKG_MIRROR_HASH:=553a58a14b59dc7b22755557acbc74f0655a431442a4faca56d28cdb1ef14fb4
PKG_SOURCE_DATE:=2023-12-06
PKG_SOURCE_VERSION:=6d3f51f9fda706f0cf4732c762e4dbe8c21e12cf
PKG_MIRROR_HASH:=6a056e6ed77bf0a7af74fcbac9cdd10bbc51868eea054da8a2d18ef1e3c4abca
PKG_SOURCE_DATE:=2025-08-24
PKG_SOURCE_VERSION:=edeb4d6dc690acb476a47e6b11633b5632b08437
PKG_ABI_VERSION:=$(call abi_version_str,$(PKG_SOURCE_DATE))
PKG_LICENSE:=GPL-2.0
@@ -51,7 +51,7 @@ define Package/udebug-cli
SECTION:=utils
CATEGORY:=Utilities
TITLE:=OpenWrt debug service CLI
DEPENDS:=+udebugd +ucode-mod-udebug
DEPENDS:=+udebugd +ucode-mod-udebug +ucode-mod-uloop +ucode-mod-ubus
endef
define Package/libudebug/install

View File

@@ -5,9 +5,9 @@ PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/ustream-ssl.git
PKG_SOURCE_DATE:=2022-12-08
PKG_SOURCE_VERSION:=9217ab46536353c7c792951b57163063f5ec7a3b
PKG_MIRROR_HASH:=cd4dc6a6c18290348b1f8b1c01df3320e4954dc46d714c797bef066f7a91248d
PKG_SOURCE_DATE:=2024-07-28
PKG_SOURCE_VERSION:=99bd3d2b167ccdffb6de072d02c380cb37b23e33
PKG_MIRROR_HASH:=9165ce1b05e7bf5ab2cd8450da30c980f1996c9d3a97c4ed2a573b282467b839
CMAKE_INSTALL:=1
PKG_LICENSE:=ISC

View File

@@ -20,7 +20,6 @@ PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_REAL_
PKG_FIXUP:=libtool libtool-abiver
PKG_INSTALL:=1
PKG_USE_MIPS16:=0
PKG_BUILD_FLAGS:=no-mips16 lto
PKG_BUILD_PARALLEL:=1
PKG_LICENSE:=GPL-2.0-or-later

View File

@@ -5,9 +5,9 @@ PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/netifd.git
PKG_SOURCE_DATE:=2025-10-06
PKG_SOURCE_VERSION:=649028013a3c8f6ed53fc97ca997d2528d06b5d9
PKG_MIRROR_HASH:=4399542c79dbb6860748d3e5746b003bc56061374a4f4de7bdde80fa803bbc0d
PKG_SOURCE_DATE:=2021-06-04
PKG_SOURCE_VERSION:=50381d0a2998f6c0fc4823f0c2aa4206063d549e
PKG_MIRROR_HASH:=2718df3d3538c93ac77accf55716fb341741df3d231aac59e04dd1f80f558889
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
PKG_LICENSE:=GPL-2.0
@@ -21,8 +21,7 @@ include $(INCLUDE_DIR)/cmake.mk
define Package/netifd
SECTION:=base
CATEGORY:=Base system
DEPENDS:=+libuci +libnl-tiny +libubus +ubus +ubusd +jshn +libubox +libudebug \
+ucode +ucode-mod-fs +ucode-mod-ubus +ucode-mod-uloop +ucode-mod-uci
DEPENDS:=+libuci +libnl-tiny +libubus +ubus +ubusd +jshn +libubox
TITLE:=OpenWrt Network Interface Configuration Daemon
endef
@@ -44,10 +43,7 @@ define Package/netifd/install
$(INSTALL_BIN) $(PKG_BUILD_DIR)/netifd $(1)/sbin/
$(CP) ./files/* $(1)/
$(INSTALL_DIR) $(1)/etc/udhcpc.user.d/
$(CP) \
$(PKG_BUILD_DIR)/scripts/utils.sh \
$(PKG_BUILD_DIR)/scripts/netifd-proto.sh \
$(1)/lib/netifd/
$(CP) $(PKG_BUILD_DIR)/scripts/* $(1)/lib/netifd/
endef
$(eval $(call BuildPackage,netifd))

View File

@@ -30,11 +30,12 @@ reload_service() {
init_switch
ubus call network reload || rv=1
/sbin/wifi reload_legacy
return $rv
}
stop_service() {
[ -x /sbin/wifi ] && /sbin/wifi down
/sbin/wifi down
ifdown -a
sleep 1
}

View File

@@ -14,12 +14,5 @@ service_triggers() {
}
reload_service() {
packet_steering="$(uci -q get "network.@globals[0].packet_steering")"
steering_flows="$(uci -q get "network.@globals[0].steering_flows")"
[ "${steering_flows:-0}" -gt 0 ] && opts="-l $steering_flows"
if [ -e "/usr/libexec/platform/packet-steering.sh" ]; then
/usr/libexec/platform/packet-steering.sh "$packet_steering"
else
/usr/libexec/network/packet-steering.uc $opts "$packet_steering"
fi
/usr/libexec/network/packet-steering.sh
}

View File

@@ -18,13 +18,13 @@ setup_interface () {
proto_add_ipv4_address "$ip" "${subnet:-255.255.255.0}"
# TODO: apply $broadcast
local ip_net IP PREFIX NETWORK NETMASK BROADCAST
ipcalc "$ip/$mask" && ip_net="$NETWORK"
local ip_net
eval "$(ipcalc.sh "$ip/$mask")";ip_net="$NETWORK"
local i
for i in $router; do
local gw_net
ipcalc "$i/$mask" && gw_net="$NETWORK"
eval "$(ipcalc.sh "$i/$mask")";gw_net="$NETWORK"
[ "$ip_net" != "$gw_net" ] && proto_add_ipv4_route "$i" 32 "" "$ip"
proto_add_ipv4_route 0.0.0.0 0 "$i" "$ip"

View File

@@ -1,79 +0,0 @@
import * as uci from "uci";
import * as uloop from "uloop";
import * as ubus from "ubus";
import { access, dirname } from "fs";
function ex_handler(e)
{
netifd.log(netifd.L_WARNING, `Exception: ${e}\n${e.stacktrace[0].context}\n`);
}
uloop.guard(ex_handler);
ubus.guard(ex_handler);
let wireless;
function uci_ctx()
{
let savedir = netifd.dummy_mode ? "./tmp" : null;
let ctx = uci.cursor(netifd.config_path, savedir, null, {
strict: false
});
return ctx;
}
function config_init()
{
let ctx = uci_ctx();
if (wireless)
wireless.config_init(ctx);
}
function config_start()
{
if (wireless)
wireless.config_start();
}
function check_interfaces()
{
if (wireless)
wireless.check_interfaces();
}
function hotplug(name, add)
{
if (wireless)
wireless.hotplug(name, add);
}
function ex_wrap(cb)
{
let fn = cb;
return (...args) => {
try {
return fn(...args);
} catch (e) {
netifd.log(netifd.L_WARNING, `${e}\n${e.stacktrace[0].context}`);
}
};
}
netifd.cb = {
hotplug: ex_wrap(hotplug),
config_init: ex_wrap(config_init),
config_start: ex_wrap(config_start),
check_interfaces: ex_wrap(check_interfaces),
};
const wireless_module = dirname(sourcepath()) + "/wireless.uc";
if (access(wireless_module, "r")) {
try {
wireless = loadfile(wireless_module)();
} catch (e) {
netifd.log(netifd.L_WARNING, `Error loading wireless module: ${e}\n${e.stacktrace[0].context}\n`);
}
} else {
netifd.log(netifd.L_WARNING, `Wireless module not found\n`);
}

View File

@@ -1,10 +1,9 @@
#!/bin/sh
[ -x /sbin/udhcpc ] || exit 0
[ -L /sbin/udhcpc ] || exit 0
. /lib/functions.sh
. ../netifd-proto.sh
. /lib/config/uci.sh
init_proto "$@"
proto_dhcp_init_config() {
@@ -32,18 +31,6 @@ proto_dhcp_add_sendopts() {
[ -n "$1" ] && append "$3" "-x $1"
}
proto_dhcp_get_default_clientid() {
[ -z "$1" ] && return
local iface="$1"
local duid
local iaid="0"
[ -e "/sys/class/net/$iface/ifindex" ] && iaid="$(cat "/sys/class/net/$iface/ifindex")"
duid="$(uci_get network @globals[0] dhcp_default_duid)"
[ -n "$duid" ] && printf "ff%08x%s" "$iaid" "$duid"
}
proto_dhcp_setup() {
local config="$1"
local iface="$2"
@@ -64,8 +51,7 @@ proto_dhcp_setup() {
[ "$defaultreqopts" = 0 ] && defaultreqopts="-o" || defaultreqopts=
[ "$broadcast" = 1 ] && broadcast="-B" || broadcast=
[ "$norelease" = 1 ] && norelease="" || norelease="-R"
[ -z "$clientid" ] && clientid="$(proto_dhcp_get_default_clientid "$iface")"
[ -n "$clientid" ] && clientid="-x 0x3d:${clientid//:/}"
[ -n "$clientid" ] && clientid="-x 0x3d:${clientid//:/}" || clientid="-C"
[ -n "$iface6rd" ] && proto_export "IFACE6RD=$iface6rd"
[ "$iface6rd" != 0 -a -f /lib/netifd/proto/6rd.sh ] && append dhcpopts "-O 212"
[ -n "$zone6rd" ] && proto_export "ZONE6RD=$zone6rd"
@@ -81,7 +67,7 @@ proto_dhcp_setup() {
-p /var/run/udhcpc-$iface.pid \
-s /lib/netifd/dhcp.script \
-f -t 0 -i "$iface" \
${ipaddr:+-r ${ipaddr/\/*/}} \
${ipaddr:+-r $ipaddr} \
${hostname:+-x "hostname:$hostname"} \
${vendorid:+-V "$vendorid"} \
$clientid $defaultreqopts $broadcast $norelease $dhcpopts

View File

@@ -1,131 +0,0 @@
'use strict';
import { glob, basename, realpath, chdir, mkstemp } from "fs";
export const TYPE_ARRAY = 1;
export const TYPE_STRING = 3;
export const TYPE_INT = 5;
export const TYPE_BOOL = 7;
export function parse_bool(val)
{
switch (val) {
case "1":
case "true":
return true;
case "0":
case "false":
return false;
}
};
export function parse_array(val)
{
if (type(val) != "array")
val = split(val, /\s+/);
return val;
};
function __type_parsers()
{
let ret = [];
ret[TYPE_ARRAY] = parse_array;
ret[TYPE_STRING] = function(val) {
return val;
};
ret[TYPE_INT] = function(val) {
return +val;
};
ret[TYPE_BOOL] = parse_bool;
return ret;
}
export const type_parser = __type_parsers();
export function handler_load(path, cb)
{
for (let script in glob(path + "/*.sh")) {
script = basename(script);
let f = mkstemp();
let prev_dir = realpath(".");
chdir(path);
system(`./${script} "" "dump" >&${f.fileno()}`);
chdir(prev_dir);
f.seek();
while (!f.error()) {
let data = trim(f.read("line"));
try {
data = json(data);
} catch (e) {
continue;
}
if (type(data) != "object")
continue;
cb(script, data);
}
f.close();
}
};
export function handler_attributes(data, extra, validate)
{
let ret = { ...extra };
for (let cur in data) {
let name_data = split(cur[0], ":", 2);
let name = name_data[0];
ret[name] = cur[1];
if (validate && name_data[1])
validate[name] = name_data[1];
}
return ret;
};
export function parse_attribute_list(data, spec)
{
let ret = {};
for (let name, type_id in spec) {
if (!(name in data))
continue;
let val = data[name];
let parser = type_parser[type_id];
if (parser)
val = parser(val);
ret[name] = val;
}
return ret;
};
export function is_equal(val1, val2) {
let t1 = type(val1);
if (t1 != type(val2))
return false;
if (t1 == "array") {
if (length(val1) != length(val2))
return false;
for (let i = 0; i < length(val1); i++)
if (!is_equal(val1[i], val2[i]))
return false;
return true;
} else if (t1 == "object") {
for (let key in val1)
if (!is_equal(val1[key], val2[key]))
return false;
for (let key in val2)
if (val1[key] == null)
return false;
return true;
} else {
return val1 == val2;
}
};

View File

@@ -1,6 +1,7 @@
#!/bin/sh
ifup_all=
setup_wifi=
if_call() {
local interface="$1"
@@ -13,6 +14,7 @@ case "$0" in
*ifdown) modes=down;;
*ifup)
modes="down up"
setup_wifi=1
;;
*) echo "Invalid command: $0";;
esac
@@ -23,6 +25,10 @@ while :; do
ifup_all=1
shift
;;
-w)
setup_wifi=
shift
;;
*)
break
;;
@@ -34,6 +40,7 @@ if [ -n "$ifup_all" ]; then
for interface in $(ubus -S list 'network.interface.*'); do
if_call "${interface##network.interface.}"
done
[ -n "$setup_wifi" ] && /sbin/wifi up
exit
else
ubus -S list "network.interface.$1" > /dev/null || {
@@ -42,3 +49,29 @@ else
}
if_call "$1"
fi
if [ -n "$setup_wifi" ] && grep -sq config /etc/config/wireless; then
. /lib/functions.sh
find_related_radios() {
local wdev wnet
config_get wdev "$1" device
config_get wnet "$1" network
if [ -n "$wdev" ]; then
for wnet in $wnet; do
if [ "$wnet" = "$network" ]; then
append radio_devs "$wdev" "$N"
fi
done
fi
}
network="$1"
config_load wireless
config_foreach find_related_radios wifi-iface
for dev in $(echo "$radio_devs" | sort -u); do
/sbin/wifi up "$dev"
done
fi

View File

@@ -0,0 +1,70 @@
#!/bin/sh
NPROCS="$(grep -c "^processor.*:" /proc/cpuinfo)"
[ "$NPROCS" -gt 1 ] || exit
PROC_MASK="$(( (1 << $NPROCS) - 1 ))"
find_irq_cpu() {
local dev="$1"
local match="$(grep -m 1 "$dev\$" /proc/interrupts)"
local cpu=0
[ -n "$match" ] && {
set -- $match
shift
for cur in $(seq 1 $NPROCS); do
[ "$1" -gt 0 ] && {
cpu=$(($cur - 1))
break
}
shift
done
}
echo "$cpu"
}
set_hex_val() {
local file="$1"
local val="$2"
val="$(printf %x "$val")"
[ -n "$DEBUG" ] && echo "$file = $val"
echo "$val" > "$file" 2>/dev/null
}
packet_steering="$(uci get "network.@globals[0].packet_steering")"
[ "$packet_steering" != 1 ] && exit 0
exec 512>/var/lock/smp_tune.lock
flock 512 || exit 1
[ -e "/usr/libexec/platform/packet-steering.sh" ] && {
/usr/libexec/platform/packet-steering.sh
exit 0
}
for dev in /sys/class/net/*; do
[ -d "$dev" ] || continue
# ignore virtual interfaces
[ -n "$(ls "${dev}/" | grep '^lower_')" ] && continue
[ -d "${dev}/device" ] || continue
device="$(readlink "${dev}/device")"
device="$(basename "$device")"
irq_cpu="$(find_irq_cpu "$device")"
irq_cpu_mask="$((1 << $irq_cpu))"
for q in ${dev}/queues/tx-*; do
set_hex_val "$q/xps_cpus" "$PROC_MASK"
done
# ignore dsa slave ports for RPS
subsys="$(readlink "${dev}/device/subsystem")"
subsys="$(basename "$subsys")"
[ "$subsys" = "mdio_bus" ] && continue
for q in ${dev}/queues/rx-*; do
set_hex_val "$q/rps_cpus" "$PROC_MASK"
done
done

View File

@@ -1,279 +0,0 @@
#!/usr/bin/env ucode
'use strict';
import { glob, basename, dirname, readlink, readfile, realpath, writefile, error, open } from "fs";
let napi_weight = 1.0;
let cpu_thread_weight = 0.75;
let rx_weight = 0.75;
let eth_bias = 2.0;
let debug = 0, do_nothing = 0;
let disable;
let cpus;
let all_cpus;
let local_flows = 0;
while (length(ARGV) > 0) {
let arg = shift(ARGV);
switch (arg) {
case "-d":
debug++;
break;
case "-n":
do_nothing++;
break;
case '0':
disable = true;
break;
case '2':
all_cpus = true;
break;
case '-l':
local_flows = +shift(ARGV);
break;
}
}
function task_name(pid)
{
let stat = open(`/proc/${pid}/status`, "r");
if (!stat)
return;
let line = stat.read("line");
stat.close();
return trim(split(line, "\t", 2)[1]);
}
function set_task_cpu(pid, cpu) {
if (disable)
cpu = join(",", map(cpus, (cpu) => cpu.id));
let name = task_name(pid);
if (!name)
return;
if (debug || do_nothing)
warn(`taskset -p -c ${cpu} ${name}\n`);
if (!do_nothing)
system(`taskset -p -c ${cpu} ${pid}`);
}
function cpu_mask(cpu)
{
let mask;
if (cpu < 0)
mask = (1 << length(cpus)) - 1;
else
mask = (1 << int(cpu));
return sprintf("%x", mask);
}
function set_netdev_cpu(dev, cpu, rx_queue) {
rx_queue ??= "rx-*";
let queues = glob(`/sys/class/net/${dev}/queues/${rx_queue}/rps_cpus`);
let val = cpu_mask(cpu);
if (disable)
val = 0;
for (let queue in queues) {
if (debug || do_nothing)
warn(`echo ${val} > ${queue}\n`);
if (!do_nothing)
writefile(queue, `${val}`);
}
queues = glob(`/sys/class/net/${dev}/queues/${rx_queue}/rps_flow_cnt`);
for (let queue in queues) {
if (debug || do_nothing)
warn(`echo ${local_flows} > ${queue}\n`);
if (!do_nothing)
writefile(queue, `${local_flows}`);
}
}
function task_device_match(name, device)
{
let napi_match = match(name, /napi\/([^-]*)-\d+/);
if (!napi_match)
napi_match = match(name, /mt76-tx (phy\d+)/);
if (napi_match &&
(index(device.phy, napi_match[1]) >= 0 ||
index(device.netdev, napi_match[1]) >= 0))
return true;
if (device.driver == "mtk_soc_eth" && match(name, /napi\/mtk_eth-/))
return true;
return false;
}
cpus = map(glob("/sys/bus/cpu/devices/*"), (path) => {
return {
id: int(match(path, /.*cpu(\d+)/)[1]),
core: int(trim(readfile(`${path}/topology/core_id`))),
load: 0.0,
};
});
cpus = slice(cpus, 0, 64);
if (length(cpus) < 2)
exit(0);
function cpu_add_weight(cpu_id, weight)
{
let cpu = cpus[cpu_id];
cpu.load += weight;
for (let sibling in cpus) {
if (sibling == cpu || sibling.core != cpu.core)
continue;
sibling.load += weight * cpu_thread_weight;
}
}
function get_next_cpu(weight, prev_cpu)
{
if (disable)
return 0;
let sort_cpus = sort(slice(cpus), (a, b) => a.load - b.load);
let idx = 0;
if (prev_cpu != null && sort_cpus[idx].id == prev_cpu)
idx++;
let cpu = sort_cpus[idx].id;
cpu_add_weight(cpu, weight);
return cpu;
}
let phys_devs = {};
let netdev_phys = {};
let netdevs = map(glob("/sys/class/net/*"), (dev) => basename(dev));
for (let dev in netdevs) {
let pdev_path = realpath(`/sys/class/net/${dev}/device`);
if (!pdev_path)
continue;
if (length(glob(`/sys/class/net/${dev}/lower_*`)) > 0)
continue;
let pdev = phys_devs[pdev_path];
if (!pdev) {
pdev = phys_devs[pdev_path] = {
path: pdev_path,
driver: basename(readlink(`${pdev_path}/driver`)),
netdev: [],
phy: [],
tasks: [],
rx_tasks: [],
rx_queues: map(glob(`/sys/class/net/${dev}/queues/rx-*/rps_cpus`),
(v) => basename(dirname(v))),
};
}
let phyidx = trim(readfile(`/sys/class/net/${dev}/phy80211/index`));
if (phyidx != null) {
let phy = `phy${phyidx}`;
if (index(pdev.phy, phy) < 0)
push(pdev.phy, phy);
}
push(pdev.netdev, dev);
netdev_phys[dev] = pdev;
}
for (let path in glob("/proc/*/exe")) {
readlink(path);
if (error() != "No such file or directory")
continue;
let pid = basename(dirname(path));
let name = task_name(pid);
for (let devname in phys_devs) {
let dev = phys_devs[devname];
if (!task_device_match(name, dev))
continue;
push(dev.tasks, pid);
let napi_match = match(name, /napi\/([^-]*)-(\d+)/);
if (napi_match && napi_match[2] > 0)
push(dev.rx_tasks, pid);
break;
}
}
function assign_dev_queues_cpu(dev) {
let num = length(dev.rx_queues);
if (num < length(dev.rx_tasks))
num = length(dev.rx_tasks);
for (let i = 0; i < num; i++) {
let cpu;
let task = dev.rx_tasks[i];
if (num >= length(cpus))
cpu = i % length(cpus);
else if (task)
cpu = get_next_cpu(napi_weight);
else
cpu = -1;
set_task_cpu(task, cpu);
let rxq = dev.rx_queues[i];
if (!rxq)
continue;
if (num >= length(cpus))
cpu = (i + 1) % length(cpus);
else if (all_cpus)
cpu = -1;
else
cpu = get_next_cpu(napi_weight, cpu);
for (let netdev in dev.netdev)
set_netdev_cpu(netdev, cpu, rxq);
}
}
function assign_dev_cpu(dev) {
if (length(dev.rx_queues) > 1 &&
length(dev.rx_tasks) > 1)
return assign_dev_queues_cpu(dev);
if (length(dev.tasks) > 0) {
let cpu = dev.napi_cpu = get_next_cpu(napi_weight);
for (let task in dev.tasks)
set_task_cpu(task, cpu);
}
if (length(dev.netdev) > 0) {
let cpu;
if (all_cpus)
cpu = -1;
else
cpu = get_next_cpu(rx_weight, dev.napi_cpu);
for (let netdev in dev.netdev)
set_netdev_cpu(netdev, cpu);
}
}
// Assign ethernet devices first
for (let devname in phys_devs) {
let dev = phys_devs[devname];
if (!length(dev.phy))
assign_dev_cpu(dev);
}
// Add bias to avoid assigning other tasks to CPUs with ethernet NAPI
for (let devname in phys_devs) {
let dev = phys_devs[devname];
if (!length(dev.tasks) || dev.napi_cpu == null)
continue;
cpu_add_weight(dev.napi_cpu, eth_bias);
}
// Assign WLAN devices
for (let devname in phys_devs) {
let dev = phys_devs[devname];
if (length(dev.phy) > 0)
assign_dev_cpu(dev);
}
if (debug > 1)
warn(sprintf("devices: %.J\ncpus: %.J\n", phys_devs, cpus));

View File

@@ -1,3 +0,0 @@
config WIFI_SCRIPTS_UCODE
bool "Use new ucode based scripts"
default n

View File

@@ -1,53 +0,0 @@
#
# Copyright (C) 2024 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=wifi-scripts
PKG_VERSION:=1.0
PKG_RELEASE:=1
PKG_LICENSE:=GPL-2.0
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
PKG_CONFIG_DEPENDS:=CONFIG_WIFI_SCRIPTS_UCODE
include $(INCLUDE_DIR)/package.mk
define Package/wifi-scripts
SECTION:=utils
CATEGORY:=Base system
DEPENDS:=+netifd +ucode +ucode-mod-nl80211 +ucode-mod-rtnl +ucode-mod-ubus +ucode-mod-uci +ucode-mod-digest
TITLE:=Wi-Fi configuration scripts
PKGARCH:=all
endef
define Package/wifi-scripts/config
source "$(SOURCE)/Config.in"
endef
define Package/wifi-scripts/description
A set of scripts that handle setup and configuration of Wi-Fi devices.
endef
define Build/Prepare
endef
define Build/Configure
endef
define Build/Compile
endef
define Package/wifi-scripts/install
$(INSTALL_DIR) $(1)
$(CP) ./files/* $(1)/
ifeq ($(CONFIG_WIFI_SCRIPTS_UCODE),y)
$(CP) ./files-ucode/* $(1)/
endif
endef
$(eval $(call BuildPackage,wifi-scripts))

View File

@@ -1,338 +0,0 @@
#!/usr/bin/ucode
'use strict';
import { set_default, log } from 'wifi.common';
import { validate, dump_options } from 'wifi.validate';
import * as supplicant from 'wifi.supplicant';
import * as hostapd from 'wifi.hostapd';
import * as netifd from 'wifi.netifd';
import * as iface from 'wifi.iface';
import { find_phy } from 'wifi.utils';
import * as nl80211 from 'nl80211';
import * as fs from 'fs';
global.radio = ARGV[2];
const mesh_param_list = [
"mesh_retry_timeout", "mesh_confirm_timeout", "mesh_holding_timeout", "mesh_max_peer_links",
"mesh_max_retries", "mesh_ttl", "mesh_element_ttl", "mesh_hwmp_max_preq_retries",
"mesh_path_refresh_time", "mesh_min_discovery_timeout", "mesh_hwmp_active_path_timeout",
"mesh_hwmp_preq_min_interval", "mesh_hwmp_net_diameter_traversal_time", "mesh_hwmp_rootmode",
"mesh_hwmp_rann_interval", "mesh_gate_announcements", "mesh_sync_offset_max_neighor",
"mesh_rssi_threshold", "mesh_hwmp_active_path_to_root_timeout", "mesh_hwmp_root_interval",
"mesh_hwmp_confirmation_interval", "mesh_awake_window", "mesh_plink_timeout",
"mesh_auto_open_plinks", "mesh_fwding", "mesh_nolearn", "mesh_power_mode"
];
function phy_suffix(radio, sep) {
if (radio == null || radio < 0)
return "";
return sep + radio;
}
function reset_config(phy, radio) {
let name = phy + phy_suffix(radio, ".");
let prev_config = `/var/run/hostapd-${name}.conf`;
global.ubus.call('hostapd', 'config_set', { phy, radio, config: '', prev_config });
global.ubus.call('wpa_supplicant', 'config_set', { phy, radio, config: []});
name = phy + phy_suffix(radio, ":");
system(`ucode /usr/share/hostap/wdev.uc ${name} set_config '{}'`);
}
function get_channel_frequency(band, channel) {
if (channel < 1)
return null;
switch (band) {
case '2g':
if (channel == 14)
return 2484;
return 2407 + channel * 5;
case '5g':
if (channel >= 182 && channel <= 196)
return 4000 + channel * 5;
return 5000 + channel * 5;
case '6g':
if (channel == 2)
return 5935;
return 5950 + channel * 5;
case '60g':
return 56160 + channel * 2160;
}
}
function setup_phy(phy, config, data) {
if (config.channel == "auto")
config.channel = 0;
config.channel = +config.channel;
config.frequency = get_channel_frequency(config.band, config.channel);
if (config.country) {
log(`Setting country code to ${config.country}`);
system(`iw reg set ${config.country}`);
}
set_default(config, 'rxantenna', 0xffffffff);
set_default(config, 'txantenna', 0xffffffff);
if (config.txantenna == 'all')
config.txantenna = 0xffffffff;
if (config.rxantenna == 'all')
config.rxantenna = 0xffffffff;
if (config.txantenna != data?.txantenna || config.rxantenna != data?.rxantenna)
reset_config(phy, config.radio);
netifd.set_data({
phy,
radio: config.radio,
txantenna: config.txantenna,
rxantenna: config.rxantenna
});
if (config.txpower)
config.txpower = 'fixed ' + config.txpower + '00';
else
config.txpower = 'auto';
log(`Configuring '${phy}' txantenna: ${config.txantenna}, rxantenna: ${config.rxantenna} distance: ${config.distance}`);
system(`iw phy ${phy} set antenna ${config.txantenna} ${config.rxantenna}`);
system(`iw phy ${phy} set distance ${config.distance}`);
system(`iw phy ${phy} set txpower ${config.txpower}`);
if (config.frag)
system(`iw phy ${phy} set frag ${config.frag}`);
if (config.rts)
system(`iw phy ${phy} set rts ${config.rts}`);
}
function iw_htmode(config) {
let suffix = substr(config.htmode, 3);
if (suffix == "40+" || suffix == "40-")
return "HT" + suffix;
switch (config.htmode ?? "NONE") {
case "HT20":
case "VHT20":
case "HE20":
case "EHT20":
return "HT20";
case "VHT80":
case "HE80":
case "EHT80":
case "HE160":
case "EHT160":
case "EHT320":
return "80MHZ";
case "NONE":
case "NOHT":
return "NOHT";
}
if (substr(config.htmode, 2) == "40") {
switch (config.band) {
case "2g":
if (+config.channel < 7)
return "HT40+";
else
return "HT40-";
default:
return ((+config.channel / 4) % 2) ? "HT40+" : "HT40-";
}
}
return null;
}
function config_add(config, name, val) {
if (val != null)
config[name] = val;
}
function config_add_mesh_params(config, data) {
for (let param in mesh_param_list)
config_add(config, param, data[param]);
}
function setup() {
let data = json(ARGV[3]);
data.phy = find_phy(data.config, true);
if (!data.phy) {
log('Bug: PHY is undefined for device');
netifd.set_retry(false);
return 1;
}
data.phy_suffix = phy_suffix(data.config.radio, ":");
data.vif_phy_suffix = phy_suffix(data.config.radio, ".");
data.ifname_prefix = data.config.ifname_prefix;
if (!data.ifname_prefix)
data.ifname_prefix = data.phy + data.vif_phy_suffix + "-";
let active_ifnames = [];
log('Starting');
let config = data.config;
if (!config.band) {
switch (config.hwmode) {
case 'a':
case '11a':
config.band = '5g';
break;
case 'ad':
case '11ad':
config.band = '60g';
break;
case 'b':
case 'g':
case '11b':
case '11g':
default:
config.band = '2g';
break;
}
}
delete config.hwmode;
validate('device', config);
setup_phy(data.phy, data.config, data.data);
let supplicant_mesh;
let has_ap = false;
let idx = {};
let supplicant_data = [];
let wdev_data = {};
for (let k, v in data.interfaces) {
let mode = v.config.mode;
idx[mode] ??= 0;
let mode_idx = idx[mode]++;
if (!v.config.ifname)
v.config.ifname = data.ifname_prefix + mode + mode_idx;
push(active_ifnames, v.config.ifname);
if (v.config.encryption == 'owe' && v.config.owe_transition) {
mode_idx = idx[mode]++;
v.config.owe_transition_ifname = data.ifname_prefix + mode + mode_idx;
push(active_ifnames, v.config.ifname);
}
switch (mode) {
case 'ap':
has_ap = true;
for (let _, sta in v.stas)
validate('station', sta.config);
// fallthrough
case 'sta':
case 'adhoc':
case 'mesh':
if (mode != "ap")
data.config.noscan = true;
validate('iface', v.config);
iface.prepare(v.config, data.phy + data.phy_suffix, data.config.num_global_macaddr, data.config.macaddr_base);
netifd.set_vif(k, v.config.ifname);
break;
}
switch (mode) {
case 'adhoc':
if (config.frequency && !v.config.wpa)
break;
// fallthrough
case 'mesh':
supplicant_mesh ??= !system("wpa_supplicant -vmesh");
if (mode == "mesh" && !supplicant_mesh)
break;
// fallthrough
case 'sta':
data.ap_start_disabled = true;
let config = supplicant.generate(supplicant_data, data, v);
if (mode == "mesh")
config_add_mesh_params(config, v.config);
continue;
case 'monitor':
break;
default:
continue;
}
// fallback to wdev setup
let config = {
mode,
ssid: v.config.ssid,
};
if (!v.config.default_macaddr)
config.macaddr = v.config.macaddr;
config_add(config, "freq", data.config.frequency);
config_add(config, "htmode", iw_htmode(data.config));
if (mode != "monitor") {
let basic_rate_list = v.config.basic_rate ?? data.config.basic_rate;
config_add(config, "basic-rates", supplicant.ratelist(basic_rate_list));
config_add(config, "mcast-rate", supplicant.ratestr(v.config.mcast_rate));
config_add(config, "beacon-interval", data.config.beacon_int);
if (mode == "adhoc")
config_add(config, "bssid", v.config.bssid);
if (mode == "mesh") {
config_add(config, "ssid", v.config.mesh_id);
config_add_mesh_params(config, v.config);
}
}
wdev_data[v.config.ifname] = config;
}
supplicant.setup(supplicant_data, data);
hostapd.setup(data);
system(`ucode /usr/share/hostap/wdev.uc ${data.phy}${data.phy_suffix} set_config '${printf("%J", wdev_data)}' ${join(' ', active_ifnames)}`);
if (length(supplicant_data) > 0)
supplicant.start(data);
netifd.set_up();
return 0
}
function teardown() {
let data = json(ARGV[3]);
if (ARGV[2] == "#mlo")
return 0;
if (!data.data?.phy) {
log('Bug: PHY is undefined for device');
return 1;
}
log(`Tearing down ${data.data.phy}`);
reset_config(data.data.phy, data.data.radio);
return 0;
}
let ret = 1;
switch(ARGV[1]) {
case 'dump':
ret = dump_options();
break;
case 'setup':
ret = setup();
break;
case 'teardown':
ret = teardown();
break;
}
exit(ret);

View File

@@ -1,191 +0,0 @@
#!/usr/bin/ucode
'use strict';
import { find_phy } from 'wifi.utils';
import * as uci from 'uci';
import * as iwinfo from 'iwinfo';
function print_assoclist(stations) {
for (let mac, station in stations) {
printf(`${station.mac} ${station.signal} dBm / ${station.noise} dBm (SNR ${station.snr}) ${station.inactive_time} ms ago\n`);
for (let k in [ 'rx', 'tx' ]) {
let bitrate = station[k];
let flags = join(', ', bitrate.flags);
printf(`\t${uc(k)}: ${bitrate.bitrate == 'unknown' ? 'unknown' : bitrate.bitrate + ' MBit/s'}`);
if (length(bitrate.flags))
printf(', %s', flags);
printf('%10d Pkts.\n', bitrate.packets);
}
printf(`\texpected throughput: ${station.expected_throughput}\n\n`);
}
}
function print_countrylist(list) {
for (let k, v in list.countries)
printf(`${k == list.active ? '*' : ' '} ${k} "${v}"\n`);
}
function print_freqlist(channels) {
for (let channel in channels) {
printf(`${channel.active ? '*' : ' '} ${channel.freq} GHz (Band: ${channel.band} GHz, Channel ${channel.channel})`);
if (length(channel.flags))
printf(` [${join(', ', channel.flags)}]`);
printf('\n');
}
}
function print_htmodelist(htmode) {
printf('%s\n', join(' ', htmode));
}
function print_info(list) {
let padding = ' ';
for (let bss in list) {
printf(`${bss.iface} ESSID: ${bss.ssid === null ? 'unknown' : '"' + bss.ssid + '"'}\n`);
printf(`${padding}Access Point: ${bss.mac}\n`);
printf(`${padding}Mode: ${bss.mode} Channel: ${bss.channel} (${bss.freq} GHz) HT Mode: ${bss.htmode}\n`);
printf(`${padding}Center Channel 1: ${bss.center_freq1} 2: ${bss.center_freq2}\n`);
printf(`${padding}Tx-Power: ${bss.txpower} dBm Link Quality: ${bss.quality}/70\n`);
printf(`${padding}Signal: ${bss.signal} dBm Noise: ${bss.noise} dBm\n`);
printf(`${padding}Bit Rate: ${bss.bitrate == 'unknown' ? 'unknown' : bss.bitrate + ' MBit/s'}\n`);
printf(`${padding}Encryption: ${bss.encryption}\n`);
printf(`${padding}Type: nl80211 HW Mode(s): 802.11${bss.hwmode}\n`);
printf(`${padding}Hardware: ${bss.hw_type} [${bss.hw_id}]\n`);
printf(`${padding}TX power offset: ${bss.power_offset}\n`);
printf(`${padding}Channel offset: ${bss.channel_offset}\n`);
printf(`${padding}Supports VAPs: ${bss.vaps} PHY name: ${bss.phy}\n`);
if (bss.owe_transition_ifname)
printf(`${padding}OWE partner: ${bss.owe_transition_ifname}\n`);
printf('\n');
}
return 0;
}
function print_scan(cells) {
let idx = 1;
for (let cell in cells) {
printf('Cell %02d - Address: %s\n', idx++, cell.bssid);
printf('\t Mode: %s Frequency: %s GHz Band: %s GHz Channel: %d\n', cell.mode, cell.frequency, cell.band, cell.channel);
printf('\t Signal: %d dBm Quality: %2d/70\n', cell.dbm, cell.quality);
if (!length(cell.crypto.key_mgmt))
printf('\t Encryption: NONE\n');
else
printf('\t Encryption: %s (%s)\n', join(' / ', cell.crypto.key_mgmt), join(' / ', cell.crypto.pair));
if (cell.ht) {
printf('\t HT Operation:\n');
printf('\t\tPrimary Channel: %d\n', cell.ht.primary_channel);
printf('\t\tSecondary Channel Offset: %s\n', cell.ht.secondary_chan_off);
printf('\t\tChannel Width: %s\n', cell.ht.chan_width);
}
if (cell.vht) {
printf('\t VHT Operation:\n');
printf('\t\tCenter Frequency 1: %d\n', cell.vht.center_chan_1);
printf('\t\tCenter Frequency 2: %s\n', cell.vht.center_chan_2);
printf('\t\tChannel Width: %s\n', cell.vht.chan_width);
}
if (cell.he) {
printf('\t HE Operation:\n');
printf('\t\tCenter Frequency 1: %d\n', cell.he.center_chan_1);
printf('\t\tCenter Frequency 2: %s\n', cell.he.center_chan_2);
printf('\t\tChannel Width: %s\n', cell.he.chan_width);
}
if (cell.eht) {
printf('\t EHT Operation:\n');
printf('\t\tCenter Frequency 1: %d\n', cell.eht.center_chan_1);
printf('\t\tCenter Frequency 2: %s\n', cell.eht.center_chan_2);
printf('\t\tChannel Width: %s\n', cell.eht.chan_width);
}
printf('\n');
}
}
function print_txpowerlist(list) {
for (let power in list)
printf('%s %2d dbm (%4d mW)\n', power.active ? '*' : ' ', power.dbm, power.mw);
}
let pretty = true;
if (ARGV[0] == '-j') {
pretty = false;
shift(ARGV);
}
if (!length(ARGV)) {
let info = iwinfo.info();
if (pretty)
print_info(info);
else
printf('%.J\n', info);
return 0;
}
const commands = {
assoclist: [ iwinfo.assoclist, print_assoclist ],
countrylist: [ iwinfo.countrylist, print_countrylist ],
freqlist: [ iwinfo.freqlist, print_freqlist ],
htmodelist: [ iwinfo.htmodelist, print_htmodelist ],
info: [ iwinfo.info, print_info ],
scan: [ iwinfo.scan, print_scan ],
txpowerlist: [ iwinfo.txpowerlist, print_txpowerlist ],
};
if (ARGV[0] == 'nl80211' && ARGV[1] == 'phyname') {
let sec_name = ARGV[2];
let sec = uci.cursor(null, null, null, { strict: false }).get_all('wireless', sec_name);
if (!sec || sec['.type'] != 'wifi-device') {
warn(`Config section ${sec_name} not found\n`);
return 1;
}
let name = find_phy(sec);
if (!name) {
warn('Phy not found\n');
return 1;
}
print(name + '\n');
return 0;
}
if (length(ARGV) == 2 && iwinfo.ifaces[ARGV[0]])
for (let cmd, cb in commands)
if (substr(cmd, 0, length(ARGV[1])) == ARGV[1]) {
let ret = cb[0](ARGV[0]);
if (pretty)
cb[1](ret);
else
printf('%.J\n', ret);
return 0;
}
switch(ARGV[0]) {
case 'phy':
printf('%.J\n', iwinfo.phys);
return 0;
case 'iface':
printf('%.J\n', iwinfo.ifaces);
return 0;
}
warn('Usage:\n' +
'\tiwinfo <device> info\n' +
'\tiwinfo <device> scan\n' +
'\tiwinfo <device> txpowerlist\n' +
'\tiwinfo <device> freqlist\n' +
'\tiwinfo <device> assoclist\n' +
'\tiwinfo <device> countrylist\n' +
'\tiwinfo <device> htmodelist\n' +
'\tiwinfo nl80211 phyname <section>\n');
return 1;

View File

@@ -1,249 +0,0 @@
{
"00": "World",
"AD": "Andorra",
"AE": "United Arab Emirates",
"AF": "Afghanistan",
"AG": "Antigua and Barbuda",
"AI": "Anguilla",
"AL": "Albania",
"AM": "Armenia",
"AN": "Netherlands Antilles",
"AO": "Angola",
"AQ": "Antarctica",
"AR": "Argentina",
"AS": "American Samoa",
"AT": "Austria",
"AU": "Australia",
"AW": "Aruba",
"AX": "Aland Islands",
"AZ": "Azerbaijan",
"BA": "Bosnia and Herzegovina",
"BB": "Barbados",
"BD": "Bangladesh",
"BE": "Belgium",
"BF": "Burkina Faso",
"BG": "Bulgaria",
"BH": "Bahrain",
"BI": "Burundi",
"BJ": "Benin",
"BL": "Saint Barthelemy",
"BM": "Bermuda",
"BN": "Brunei Darussalam",
"BO": "Bolivia",
"BR": "Brazil",
"BS": "Bahamas",
"BT": "Bhutan",
"BV": "Bouvet Island",
"BW": "Botswana",
"BY": "Belarus",
"BZ": "Belize",
"CA": "Canada",
"CC": "Cocos (Keeling) Islands",
"CD": "Congo",
"CF": "Central African Republic",
"CG": "Congo",
"CH": "Switzerland",
"CI": "Cote d'Ivoire",
"CK": "Cook Islands",
"CL": "Chile",
"CM": "Cameroon",
"CN": "China",
"CO": "Colombia",
"CR": "Costa Rica",
"CU": "Cuba",
"CV": "Cape Verde",
"CX": "Christmas Island",
"CY": "Cyprus",
"CZ": "Czech Republic",
"DE": "Germany",
"DJ": "Djibouti",
"DK": "Denmark",
"DM": "Dominica",
"DO": "Dominican Republic",
"DZ": "Algeria",
"EC": "Ecuador",
"EE": "Estonia",
"EG": "Egypt",
"EH": "Western Sahara",
"ER": "Eritrea",
"ES": "Spain",
"ET": "Ethiopia",
"FI": "Finland",
"FJ": "Fiji",
"FK": "Falkland Islands",
"FM": "Micronesia",
"FO": "Faroe Islands",
"FR": "France",
"GA": "Gabon",
"GB": "United Kingdom",
"GD": "Grenada",
"GE": "Georgia",
"GF": "French Guiana",
"GG": "Guernsey",
"GH": "Ghana",
"GI": "Gibraltar",
"GL": "Greenland",
"GM": "Gambia",
"GN": "Guinea",
"GP": "Guadeloupe",
"GQ": "Equatorial Guinea",
"GR": "Greece",
"GS": "South Georgia",
"GT": "Guatemala",
"GU": "Guam",
"GW": "Guinea-Bissau",
"GY": "Guyana",
"HK": "Hong Kong",
"HM": "Heard and McDonald Islands",
"HN": "Honduras",
"HR": "Croatia",
"HT": "Haiti",
"HU": "Hungary",
"ID": "Indonesia",
"IE": "Ireland",
"IL": "Israel",
"IM": "Isle of Man",
"IN": "India",
"IO": "Chagos Islands",
"IQ": "Iraq",
"IR": "Iran",
"IS": "Iceland",
"IT": "Italy",
"JE": "Jersey",
"JM": "Jamaica",
"JO": "Jordan",
"JP": "Japan",
"KE": "Kenya",
"KG": "Kyrgyzstan",
"KH": "Cambodia",
"KI": "Kiribati",
"KM": "Comoros",
"KN": "Saint Kitts and Nevis",
"KP": "North Korea",
"KR": "South Korea",
"KW": "Kuwait",
"KY": "Cayman Islands",
"KZ": "Kazakhstan",
"LA": "Laos",
"LB": "Lebanon",
"LC": "Saint Lucia",
"LI": "Liechtenstein",
"LK": "Sri Lanka",
"LR": "Liberia",
"LS": "Lesotho",
"LT": "Lithuania",
"LU": "Luxembourg",
"LV": "Latvia",
"LY": "Libyan Arab Jamahiriya",
"MA": "Morocco",
"MC": "Monaco",
"MD": "Moldova",
"ME": "Montenegro",
"MF": "Saint Martin (French part)",
"MG": "Madagascar",
"MH": "Marshall Islands",
"MK": "Macedonia",
"ML": "Mali",
"MM": "Myanmar",
"MN": "Mongolia",
"MO": "Macao",
"MP": "Northern Mariana Islands",
"MQ": "Martinique",
"MR": "Mauritania",
"MS": "Montserrat",
"MT": "Malta",
"MU": "Mauritius",
"MV": "Maldives",
"MW": "Malawi",
"MX": "Mexico",
"MY": "Malaysia",
"MZ": "Mozambique",
"NA": "Namibia",
"NC": "New Caledonia",
"NE": "Niger",
"NF": "Norfolk Island",
"NG": "Nigeria",
"NI": "Nicaragua",
"NL": "Netherlands",
"NO": "Norway",
"NP": "Nepal",
"NR": "Nauru",
"NU": "Niue",
"NZ": "New Zealand",
"OM": "Oman",
"PA": "Panama",
"PE": "Peru",
"PF": "French Polynesia",
"PG": "Papua New Guinea",
"PH": "Philippines",
"PK": "Pakistan",
"PL": "Poland",
"PM": "Saint Pierre and Miquelon",
"PN": "Pitcairn",
"PR": "Puerto Rico",
"PS": "Palestinian Territory",
"PT": "Portugal",
"PW": "Palau",
"PY": "Paraguay",
"QA": "Qatar",
"RE": "Reunion",
"RO": "Romania",
"RS": "Serbia",
"RU": "Russian Federation",
"RW": "Rwanda",
"SA": "Saudi Arabia",
"SB": "Solomon Islands",
"SC": "Seychelles",
"SD": "Sudan",
"SE": "Sweden",
"SG": "Singapore",
"SH": "St. Helena and Dependencies",
"SI": "Slovenia",
"SJ": "Svalbard and Jan Mayen",
"SK": "Slovakia",
"SL": "Sierra Leone",
"SM": "San Marino",
"SN": "Senegal",
"SO": "Somalia",
"SR": "Suriname",
"ST": "Sao Tome and Principe",
"SV": "El Salvador",
"SY": "Syrian Arab Republic",
"SZ": "Swaziland",
"TC": "Turks and Caicos Islands",
"TD": "Chad",
"TF": "French Southern Territories",
"TG": "Togo",
"TH": "Thailand",
"TJ": "Tajikistan",
"TK": "Tokelau",
"TL": "Timor-Leste",
"TM": "Turkmenistan",
"TN": "Tunisia",
"TO": "Tonga",
"TR": "Turkey",
"TT": "Trinidad and Tobago",
"TV": "Tuvalu",
"TW": "Taiwan",
"TZ": "Tanzania",
"UA": "Ukraine",
"UG": "Uganda",
"UM": "U.S. Minor Outlying Islands",
"US": "United States",
"UY": "Uruguay",
"UZ": "Uzbekistan",
"VA": "Vatican City State",
"VC": "St. Vincent and Grenadines",
"VE": "Venezuela",
"VG": "Virgin Islands, British",
"VI": "Virgin Islands, U.S.",
"VN": "Viet Nam",
"VU": "Vanuatu",
"WF": "Wallis and Futuna",
"WS": "Samoa",
"YE": "Yemen",
"YT": "Mayotte",
"ZA": "South Africa",
"ZM": "Zambia",
"ZW": "Zimbabwe"
}

View File

@@ -1,742 +0,0 @@
{
"$id": "https://openwrt.org/wifi.device.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "OpenWrt WiFi Device Schema",
"type": "object",
"properties": {
"acs_chan_bias": {
"description": "Can be used to increase (or decrease) the likelihood of a specific channel to be selected by the ACS algorithm",
"type": "string"
},
"acs_exclude_dfs": {
"description": "Exclude DFS channels from ACS",
"type": "boolean",
"default": false
},
"airtime_mode": {
"description": "Set the airtime policy operating mode",
"type": "number",
"default": 0,
"minimum": 0,
"maximum": 3
},
"antenna_gain": {
"description": "Reduction in antenna gain from regulatory maximum in dBi",
"type": "number",
"default": 0
},
"assoc_sa_query_max_timeout": {
"description": "Association SA Query maximum timeout",
"type": "number"
},
"assoc_sa_query_retry_timeout": {
"description": "Association SA Query retry timeout",
"type": "number"
},
"auth_cache": {
"type": "alias",
"default": "okc"
},
"background_radar": {
"type": "alias",
"default": "enable_background_radar"
},
"band": {
"description": "The wireless band thatthe radio shall operate on",
"type": "string",
"enum": [
"2g",
"5g",
"6g",
"60g"
]
},
"basic_rate": {
"type": "alias",
"default": "basic_rates"
},
"basic_rates": {
"description": "Set the supported basic rates. Each basic_rate is measured in kb/s. This option only has an effect on ap and adhoc wifi-ifaces. ",
"type": "array",
"items": {
"type": "number"
}
},
"beacon_int": {
"description": "Set the beacon interval. This is the time interval between beacon frames, measured in units of 1.024 ms. hostapd permits this to be set between 15 and 65535. This option only has an effect on ap and adhoc wifi-ifaces",
"type": "number",
"default": 100,
"minimum": 15,
"maximum": 65535
},
"beacon_rate": {
"description": "Beacon frame TX rate configuration",
"type": "string"
},
"beamformee_antennas": {
"description": "Beamformee antenna override",
"type": "number",
"default": 4
},
"beamformer_antennas": {
"description": "Beamformer antenna override",
"type": "number",
"default": 4
},
"bssid": {
"description": "Overrides the MAC address used for the Wi-Fi interface. Warning: if the MAC address specified is a multicast address, this override will fail silently. To avoid this problem, ensure that the mac address specified is a valid unicast mac address",
"type": "string"
},
"cell_density": {
"description": "Configures data rates based on the coverage cell density. Normal configures basic rates to 6, 12, 24 Mbps if legacy_rates is 0, else to 5.5, 11 Mbps. High configures basic rates to 12, 24 Mbps if legacy_rates is 0, else to the 11 Mbps rate. Very High configures 24 Mbps as the basic rate. Supported rates lower than the minimum basic rate are not offered. The basic_rate and supported_rates options overrides this option. 0 = Disabled, 1 = Normal, 2 = High, 3 = Very High",
"type": "number",
"default": 0,
"minimum": 0,
"maximum": 3
},
"chanbw": {
"description": "Specifies a narrow channel width in MHz, possible values are: 5, 10, 20",
"type": "number",
"enum": [ 5, 10, 20 ]
},
"channel": {
"description": "Specifies the wireless channel. “auto” defaults to the lowest available channel, or utilizes the ACS algorithm depending on hardware/driver support",
"type": "string"
},
"channels": {
"type": "alias",
"default": "chanlist"
},
"channel_list": {
"type": "alias",
"default": "chanlist"
},
"chanlist": {
"description": "Use specific channels, when channel is in “auto” mode. This option allows hostapd to select one of the provided channels when a channel should be automatically selected. Channels can be provided as range using hyphen ('-') or individual channels can be specified by space (' ') separated values",
"type": "array",
"items": {
"type": "string"
}
},
"country": {
"type": "alias",
"default": "country_code"
},
"country3": {
"description": "The third octet of the Country String (dot11CountryString)",
"type": "string"
},
"country_code": {
"description": "Specifies the two-letter country code (e.g. EN or DE), affects the available channels and transmission powers",
"type": "string"
},
"country_ie": {
"type": "alias",
"default": "ieee80211d"
},
"disabled": {
"description": "When set to 1, wireless network is disabled",
"type": "boolean",
"default": false
},
"distance": {
"description": "Distance between the ap and the furthest client in meters",
"type": "number",
"default": 0
},
"doth": {
"type": "alias",
"default": "ieee80211h"
},
"dsss_cck_40": {
"description": "DSSS/CCK Mode in 40 MHz allowed in Beacon, Measurement Pilot and Probe Response frames",
"type": "boolean",
"default": true
},
"enable_background_radar": {
"description": "This feature allows CAC to be run on dedicated radio RF chains",
"type": "boolean"
},
"frag": {
"description": "Fragmentation threshold",
"type": "number"
},
"greenfield": {
"description": "Receive Greenfield - treats pre-80211n traffic as noise",
"type": "boolean",
"default": false
},
"he_bss_color": {
"description": "BSS color to be announced",
"type": "number",
"minimum": 1,
"maximum": 128,
"default": 128
},
"he_bss_color_enabled": {
"description": "Enable BSS color",
"type": "boolean",
"default": true
},
"he_default_pe_duration": {
"description": "The duration of PE field in an HE PPDU in us",
"type": "number",
"default": 4,
"enum": [ 4, 8, 12, 16 ]
},
"he_mu_beamformer": {
"description": "HE multiple user beamformer support",
"type": "boolean",
"default": true
},
"he_mu_edca_ac_be_aci": {
"type": "number",
"default": 0
},
"he_mu_edca_ac_be_aifsn": {
"type": "number",
"default": 8
},
"he_mu_edca_ac_be_ecwmax": {
"type": "number",
"default": 10
},
"he_mu_edca_ac_be_ecwmin": {
"type": "number",
"default": 9
},
"he_mu_edca_ac_be_timer": {
"type": "number",
"default": 255
},
"he_mu_edca_ac_bk_aci": {
"type": "number",
"default": 1
},
"he_mu_edca_ac_bk_aifsn": {
"type": "number",
"default": 15
},
"he_mu_edca_ac_bk_ecwmax": {
"type": "number",
"default": 10
},
"he_mu_edca_ac_bk_ecwmin": {
"type": "number",
"default": 9
},
"he_mu_edca_ac_bk_timer": {
"type": "number",
"default": 255
},
"he_mu_edca_ac_vi_aci": {
"type": "number",
"default": 2
},
"he_mu_edca_ac_vi_aifsn": {
"type": "number",
"default": 5
},
"he_mu_edca_ac_vi_ecwmax": {
"type": "number",
"default": 7
},
"he_mu_edca_ac_vi_ecwmin": {
"type": "number",
"default": 5
},
"he_mu_edca_ac_vi_timer": {
"type": "number",
"default": 255
},
"he_mu_edca_ac_vo_aci": {
"type": "number",
"default": 3
},
"he_mu_edca_ac_vo_aifsn": {
"type": "number",
"default": 5
},
"he_mu_edca_ac_vo_ecwmax": {
"type": "number",
"default": 7
},
"he_mu_edca_ac_vo_ecwmin": {
"type": "number",
"default": 5
},
"he_mu_edca_ac_vo_timer": {
"type": "number",
"default": 255
},
"he_mu_edca_qos_info_param_count": {
"type": "number",
"default": 0
},
"he_mu_edca_qos_info_q_ack": {
"type": "number",
"default": 0
},
"he_mu_edca_qos_info_queue_request": {
"type": "number",
"default": 0
},
"he_mu_edca_qos_info_txop_request": {
"type": "number",
"default": 0
},
"he_oper_centr_freq_seg0_idx": {
"description": "",
"type": "string"
},
"he_oper_chwidth": {
"description": "",
"type": "string"
},
"he_6ghz_reg_pwr_type": {
"description": "This config is to set the 6 GHz Access Point type.",
"type": "number",
"minimum": 0,
"maximum": 4,
"default": 0
},
"he_rts_threshold": {
"description": "Duration of STA transmission",
"type": "number",
"default": 1023
},
"he_spr_non_srg_obss_pd_max_offset": {
"description": "",
"type": "number"
},
"he_spr_psr_enabled": {
"description": "",
"type": "boolean",
"default": false
},
"he_spr_sr_control": {
"description": "",
"type": "number",
"default": 3
},
"he_su_beamformee": {
"description": "",
"type": "boolean",
"default": true
},
"he_su_beamformer": {
"description": "",
"type": "boolean",
"default": true
},
"he_twt_required": {
"description": "",
"type": "boolean",
"default": false
},
"hostapd_options": {
"type": "array",
"items": {
"type": "string"
}
},
"ht_coex": {
"description": "Disable honoring 40 MHz intolerance in coexistence flags of stations",
"type": "boolean",
"default": false
},
"htc_vht": {
"description": "STA supports receiving a VHT variant HT Control field",
"type": "boolean",
"default": true
},
"htmode": {
"description": "Specifies the high throughput mode",
"type": "string",
"enum": [
"NOHT", "HT20", "HT40-", "HT40+", "HT40",
"VHT20", "VHT40", "VHT80", "VHT160",
"HE20", "HE40", "HE80", "HE160",
"EHT20", "EHT40", "EHT80", "EHT160", "EHT320" ]
},
"hwmode": {
"type": "alias",
"default": "hw_mode"
},
"hw_mode": {
"description": "Legacy way, use the band property instead",
"type": "string",
"enum": [ "11a", "11b", "11g", "11ad" ]
},
"ieee80211d": {
"description": "Enables IEEE 802.11d country IE (information element) advertisement in beacon and probe response frames. This IE contains the country code and channel/power map. Requires country",
"type": "boolean",
"default": true
},
"ieee80211h": {
"description": "This enables radar detection and DFS support",
"type": "boolean",
"default": true
},
"ieee80211w": {
"description": "Whether management frame protection (MFP) is enabled",
"type": "number",
"minimum": 0,
"maximum": 2
},
"ieee80211w_max_timeout": {
"type": "alias",
"default": "assoc_sa_query_max_timeout"
},
"ieee80211w_mgmt_cipher": {
"description": "Cypher used for MFP",
"type": "string"
},
"ieee80211w_retry_timeout": {
"type": "alias",
"default": "assoc_sa_query_retry_timeout"
},
"ifname_prefix": {
"description": "Default ifname prefix for this radio",
"type": "string"
},
"iface_max_num_sta": {
"description": "Limits the maximum allowed number of associated clients",
"type": "number"
},
"ldpc": {
"description": " LDPC (Low-Density Parity-Check code) capability ",
"type": "boolean",
"default": true
},
"legacy_rates": {
"description": "Allow legacy 802.11b data rates (used by cell_density)",
"type": "boolean",
"default": false
},
"local_pwr_constraint": {
"description": "Add Power Constraint element to Beacon and Probe Response frame",
"type": "number",
"minimum": 0,
"maximum": 255
},
"log_80211": {
"description": "Enable IEEE 802.11 logging",
"type": "boolean",
"default": true
},
"log_8021x": {
"description": "Enable IEEE 802.1X logging",
"type": "boolean",
"default": true
},
"log_driver": {
"description": "Enable driver interface logging",
"type": "boolean",
"default": true
},
"log_iapp": {
"description": "Enable iapp logging",
"type": "boolean",
"default": true
},
"log_level": {
"description": "Log severity",
"type": "number",
"default": 2,
"minimum": 0,
"maximum": 4
},
"log_mlme": {
"description": "Enable MLME logging",
"type": "boolean",
"default": true
},
"log_radius": {
"description": "Enable Radius logging",
"type": "boolean",
"default": true
},
"log_wpa": {
"description": "Enable WPA logging",
"type": "boolean",
"default": true
},
"logger_stdout": {
"description": "Log to stdout",
"type": "boolean",
"default": true
},
"logger_stdout_level": {
"description": "Log severity",
"type": "number",
"default": 2,
"minimum": 0,
"maximum": 4
},
"logger_syslog": {
"description": "Log to syslog",
"type": "boolean",
"default": true
},
"logger_syslog_level": {
"description": "Syslog severity",
"type": "number",
"default": 2,
"minimum": 0,
"maximum": 4
},
"macaddr": {
"type": "alias",
"default": "bssid"
},
"macaddr_base": {
"type": "string",
"description": "Base MAC address used for deriving interface MAC addresses"
},
"max_amsdu": {
"description": "Maximum A-MSDU length of 7935 octects (3839 octets if option set to 0)",
"type": "boolean",
"default": true
},
"maxassoc": {
"type": "alias",
"default": "iface_max_num_sta"
},
"mbssid": {
"description": "Multiple BSSID Advertisement in IEEE 802.11ax IEEE Std 802.11ax-2021 added a feature where instead of multiple interfaces on a common radio transmitting individual Beacon frames, those interfaces can form a set with a common Beacon frame transmitted for all Set minimum permitted max TX power (in dBm) for ACS and DFS channel selection",
"type": "number",
"default": 0,
"minimum": 0,
"maximum": 2
},
"min_tx_power": {
"description": "Set minimum permitted max TX power (in dBm) for ACS and DFS channel selection",
"type": "number",
"default": 0
},
"mu_beamformee": {
"description": "Supports operation as an MU beamformee",
"type": "boolean",
"default": true
},
"mu_beamformer": {
"description": " Supports operation as an MU beamformer",
"type": "boolean",
"default": true
},
"multiple_bssid": {
"type": "alias",
"default": "mbssid"
},
"num_global_macaddr": {
"description": "The number of MACs that this radio can use",
"type": "number",
"default": 1
},
"no_probe_resp_if_max_sta": {
"description": "Do not answer probe requests if iface_max_num_sta was reached",
"type": "boolean"
},
"noscan": {
"description": "Do not scan for overlapping BSSs in HT40+/- mode.",
"type": "boolean",
"default": false
},
"okc": {
"description": "Enable Opportunistic Key Caching",
"type": "boolean"
},
"path": {
"description": "Alternative to phy used to identify the device based paths in /sys/devices",
"type": "string"
},
"phy": {
"description": "Name of the phy, as described in board.json",
"type": "string"
},
"radio": {
"description": "Index of the phy radio (for multi-radio PHYs)",
"type": "number",
"default": -1
},
"reg_power_type": {
"type": "alias",
"default": "he_6ghz_reg_pwr_type"
},
"require_mode": {
"description": "Sets the minimum client capability level mode that connecting clients must support to be allowed to connect",
"type": "string",
"enum": [ "n", "ac", "ax" ]
},
"rnr_beacon": {
"description": "",
"type": "string"
},
"rsn_preauth": {
"description": "Enable IEEE 802.11i/RSN/WPA2 pre-authentication",
"type": "boolean"
},
"rssi_ignore_probe_request": {
"description": "Ignore Probe Request frames if RSSI is below given threshold (in dBm)",
"type": "number",
"default": 0
},
"rssi_reject_assoc_rssi": {
"description": "Reject STA association if RSSI is below given threshold (in dBm)",
"type": "number",
"default": 0
},
"rts": {
"description": "Override the RTS/CTS threshold",
"type": "number"
},
"rts_threshold": {
"description": "RTS/CTS threshold",
"type": "number",
"minimum": -1,
"maximum": 65535
},
"rx_antenna_pattern": {
"description": "Rx antenna pattern does not change during the lifetime of an association",
"type": "boolean",
"default": true
},
"rx_stbc": {
"description": "Supports reception of PPDUs using STBC",
"type": "number",
"default": 3,
"minimum": 0,
"maximum": 4
},
"rxantenna": {
"description": "Specifies the antenna for receiving, the value may be driver specific, usually it is 1 for the first and 2 for the second antenna. Specifying 0 enables automatic selection by the driver if supported. This option has no effect if diversity is enabled",
"type": "number"
},
"rxldpc": {
"description": "Supports receiving LDPC coded pkts",
"type": "boolean",
"default": true
},
"scan_list": {
"description": "List of frequencies (in MHz) to scan when looking for networks in client mode",
"type": "array",
"items": {
"type": "number"
}
},
"short_gi_160": {
"description": "Short GI for 160 MHz",
"type": "boolean",
"default": true
},
"short_gi_20": {
"description": "Short GI for 20 MHz",
"type": "boolean",
"default": true
},
"short_gi_40": {
"description": "Short GI for 40 MHz",
"type": "boolean",
"default": true
},
"short_gi_80": {
"description": "Short GI for 80 MHz",
"type": "boolean",
"default": true
},
"spectrum_mgmt_required": {
"description": "Set Spectrum Management subfield in the Capability Information field",
"type": "boolean",
"default": false
},
"stationary_ap": {
"description": "Stationary AP config indicates that the AP doesn't move hence location data can be considered as always up to date.",
"type": "boolean",
"default": true
},
"su_beamformee": {
"description": "Single user beamformee",
"type": "boolean",
"default": true
},
"su_beamformer": {
"description": "Single user beamformer",
"type": "boolean",
"default": true
},
"supported_rates": {
"description": "Set the supported data rates. Each supported rate is measured in kb/s. This option only has an effect on ap and adhoc wifi-ifaces. This must be a superset of the rates set in basic_rate. The minimum basic rate should also be the minimum supported rate. It is recommended to use the cell_density option instead",
"type": "array",
"items": {
"type": "number"
}
},
"tx_antenna_pattern": {
"description": "Tx antenna pattern does not change during the lifetime of an association",
"type": "boolean",
"default": true
},
"tx_burst": {
"type": "alias",
"default": "tx_queue_data2_burst"
},
"tx_queue_data2_burst": {
"description": "",
"type": "number"
},
"tx_stbc": {
"description": "Transmit STBC (Space-Time Block Coding)",
"type": "boolean",
"default": true
},
"tx_stbc_2by1": {
"description": "Supports transmission of at least 2×1 STBC",
"type": "boolean",
"default": true
},
"txantenna": {
"description": "Specifies the antenna for transmitting, values are identical to rxantenna",
"type": "number"
},
"txpower": {
"description": "Specifies the maximum desired transmission power in dBm. The actual txpower used depends on regulatory requirements",
"type": "number"
},
"type": {
"description": "Device type (only mac80211 supported)",
"type": "string"
},
"vht160": {
"description": "Supported channel widths. 0 == 160MHz and 80+80 MHz not supported, 1 == 160 MHz supported, 2 == 160MHz and 80+80 MHz supported",
"type": "number",
"minimum": 0,
"maximum": 2,
"default": 2
},
"vht_link_adapt": {
"description": "TA supports link adaptation using VHT variant HT Control field",
"type": "number",
"minimum": 0,
"maximum": 3
},
"vht_max_a_mpdu_len_exp": {
"description": "Indicates the maximum length of A-MPDU pre-EOF padding that the STA can recv",
"type": "number",
"minimum": 0,
"maximum": 7,
"default": 7
},
"vht_max_mpdu": {
"description": "Maximum MPDU length",
"type": "number",
"enum": [ 3895, 7991, 11454 ],
"default": 11454
},
"vht_txop_ps": {
"description": "VHT TXOP PS mode",
"type": "boolean",
"default": true
}
}
}

View File

@@ -1,21 +0,0 @@
{
"$id": "https://openwrt.org/wifi.station.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "OpenWrt WiFi Station Schema",
"type": "object",
"properties": {
"mac": {
"description": "The stations MAC",
"type": "string",
"default": "00:00:00:00:00:00"
},
"key": {
"description": "The passphrase that shall be used",
"type": "string"
},
"vid": {
"description": "The VLAN Id used by the station",
"type": "string"
}
}
}

View File

@@ -1,16 +0,0 @@
{
"$id": "https://openwrt.org/wifi.vlan.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "OpenWrt WiFi VLAN Schema",
"type": "object",
"properties": {
"name": {
"description": "VLAN name",
"type": "string"
},
"vid": {
"description": "VLAN ID",
"type": "string"
}
}
}

View File

@@ -1,642 +0,0 @@
'use strict';
import * as nl80211 from 'nl80211';
import * as libubus from 'ubus';
import { readfile, stat } from "fs";
let wifi_devices = json(readfile('/usr/share/wifi_devices.json'));
let countries = json(readfile('/usr/share/iso3166.json'));
let board_data = json(readfile('/etc/board.json'));
export let phys = nl80211.request(nl80211.const.NL80211_CMD_GET_WIPHY, nl80211.const.NLM_F_DUMP, { split_wiphy_dump: true });
let interfaces = nl80211.request(nl80211.const.NL80211_CMD_GET_INTERFACE, nl80211.const.NLM_F_DUMP);
let ubus = libubus.connect();
let wireless_status = ubus.call('network.wireless', 'status');
function find_phy(wiphy) {
for (let k, phy in phys)
if (phy && phy.wiphy == wiphy)
return phy;
return null;
}
function get_noise(iface) {
for (let phy in phys) {
let channels = nl80211.request(nl80211.const.NL80211_CMD_GET_SURVEY, nl80211.const.NLM_F_DUMP, { dev: iface.ifname });
for (let k, channel in channels)
if (channel.survey_info.frequency == iface.wiphy_freq)
return channel.survey_info.noise;
}
return -100;
}
function get_country(iface) {
let reg = nl80211.request(nl80211.const.NL80211_CMD_GET_REG, 0, { dev: iface.ifname });
return reg.reg_alpha2 ?? '';
}
function get_max_power(iface) {
let phy = find_phy(iface.wiphy);
for (let k, band in phy.wiphy_bands)
if (band)
for (let freq in band.freqs)
if (freq.freq == iface.wiphy_freq)
return freq.max_tx_power;;
return 0;
}
function get_hardware_id(iface) {
let hw = {
type: 'nl80211',
id: 'Generic MAC80211',
power_offset: 0,
channel_offset: 0,
};
let path = `/sys/class/ieee80211/phy${iface.wiphy}/device/`;
if (stat(path + 'vendor')) {
let data = [];
for (let lookup in [ 'vendor', 'device', 'subsystem_vendor', 'subsystem_device' ])
push(data, trim(readfile(path + lookup), '\n'));
for (let device in wifi_devices.pci) {
let match = 0;
for (let i = 0; i < 4; i++)
if (lc(data[i]) == lc(device[i]))
match++;
if (match == 4) {
hw.type = `${data[0]}:${data[1]} ${data[2]}:${data[3]}`;
hw.power_offset = device[4];
hw.channel_offset = device[5];
hw.id = `${device[6]} ${device[7]}`;
}
}
}
let compatible = trim(readfile(`/sys/class/net/${iface.ifname}/device/of_node/compatible`), '\n');
if (compatible && wifi_devices.compatible[compatible]) {
hw.id = wifi_devices.compatible[compatible][0] + ' ' + wifi_devices.compatible[compatible][1];
hw.compatible = compatible;
hw.type = 'embedded';
}
return hw;
}
const iftypes = [
'Unknown', 'Ad-Hoc', 'Client', 'Master', 'Master (VLAN)',
'WDS', 'Monitor', 'Mesh Point', 'P2P Client', 'P2P Go',
];
export let ifaces = {};
for (let k, v in interfaces) {
let iface = ifaces[v.ifname] = v;
iface.mode = iftypes[iface.iftype] ?? 'unknown',
iface.noise = get_noise(iface);
iface.country = get_country(iface);
iface.max_power = get_max_power(iface);
iface.assoclist = nl80211.request(nl80211.const.NL80211_CMD_GET_STATION, nl80211.const.NLM_F_DUMP, { dev: v.ifname }) ?? [];
iface.hardware = get_hardware_id(iface);
iface.bss_info = ubus.call('hostapd', 'bss_info', { iface: v.ifname });
if (!iface.bss_info)
iface.bss_info = ubus.call('wpa_supplicant', 'bss_info', { iface: v.ifname });
}
for (let radio, data in wireless_status)
for (let k, v in data.interfaces) {
if (!v.ifname || !ifaces[v.ifname])
continue;
ifaces[v.ifname].ssid = v.config.ssid || v.config.mesh_id;
ifaces[v.ifname].radio = data.config;
let bss_info = ifaces[v.ifname].bss_info;
let owe_transition_ifname = bss_info?.owe_transition_ifname;
if (v.config.owe_transition && ifaces[owe_transition_ifname]) {
ifaces[v.ifname].owe_transition_ifname = owe_transition_ifname;
ifaces[owe_transition_ifname].ssid = v.config.ssid;
ifaces[owe_transition_ifname].radio = data.config;
ifaces[owe_transition_ifname].owe_transition_ifname = v.ifname
}
}
function format_channel(freq) {
if (freq < 1000)
return 0;
if (freq == 2484)
return 14;
if (freq == 5935)
return 2;
if (freq < 2484)
return (freq - 2407) / 5;
if (freq >= 4910 && freq <= 4980)
return (freq - 4000) / 5;
if (freq < 5950)
return (freq - 5000) / 5;
if (freq <= 45000)
return (freq - 5950) / 5;
if (freq >= 58320 && freq <= 70200)
return (freq - 56160) / 2160;
return 'unknown';
}
function format_band(freq) {
if (freq == 5935)
return '6';
if (freq < 2484)
return '2.4';
if (freq < 5950)
return '5';
if (freq <= 45000)
return '6';
return '60';
}
function format_frequency(freq) {
return freq ? sprintf('%.03f', freq / 1000.0) : 'unknown';
}
function format_rate(rate) {
return rate ? sprintf('%.01f', rate / 10.0) : 'unknown';
}
function format_mgmt_key(key) {
switch(+key) {
case 1:
case 11:
case 12:
case 13:
case 14:
case 15:
case 16:
case 17:
return '802.1x';
case 2:
return 'WPA PSK';
case 4:
return 'FT PSK';
case 6:
return 'WPA PSK2';
case 8:
return 'SAE';
case 18:
return 'OWE';
}
return null;
}
function assoc_flags(data) {
const assoc_mhz = {
width_40: 40,
width_80: 80,
width_80p80: '80+80',
width_160: 160,
width_320: 320,
width_10: 10,
width_5: 5
};
let mhz = 'unknown';
for (let k, v in assoc_mhz)
if (data[k])
mhz = v;
const assoc_flags = {
mcs: {
mcs: 'MCS',
},
vht_mcs: {
vht_mcs: 'VHT-MCS',
vht_nss: 'VHT-NSS',
},
he_mcs: {
he_mcs: 'HE-MCS',
he_nss: 'HE-NSS',
he_gi: 'HE-GI',
he_dcm: 'HE-DCM',
},
eht_mcs: {
eht_mcs: 'EHT-MCS',
eht_nss: 'EHT-NSS',
eht_gi: 'EHT-GI',
},
};
let flags = [];
for (let k, v in assoc_flags) {
if (!data[k])
continue;
let first = 0;
for (let name, flag in v) {
if (data[name] == null)
continue;
push(flags, `${flag} ${data[name]}`);
if (!first++)
push(flags, `${mhz}MHz`);
}
}
return flags;
}
function dbm2mw(dbm) {
const LOG10_MAGIC = 1.25892541179;
let res = 1.0;
let ip = dbm / 10;
let fp = dbm % 10;
for (let k = 0; k < ip; k++)
res *= 10;
for (let k = 0; k < fp; k++)
res *= LOG10_MAGIC;
return int(res);
}
function dbm2quality(dbm) {
let quality = dbm;
if (quality < -110)
quality = -110;
else if (quality > -40)
quality = -40;
quality += 110;
return quality;
}
function hwmodelist(name) {
const mode = { 'HT*': 'n', 'VHT*': 'ac', 'HE*': 'ax' };
let iface = ifaces[name];
let phy = board_data.wlan?.['phy' + iface.wiphy];
if (!phy || !iface.radio?.band)
return '';
let htmodes = phy.info.bands[uc(iface.radio.band)].modes;
let list = [];
if (iface.radio.band == '2g' && 'NOHT' in htmodes)
push(list, 'g/b');
for (let k, v in mode)
for (let htmode in htmodes)
if (wildcard(htmode, k))
push(list, v);
return join('/', reverse(uniq(list)));
}
export function assoclist(dev) {
let stations = ifaces[dev].assoclist;
let ret = {};
for (let station in stations) {
let sta = {
mac: uc(station.mac),
signal: station.sta_info.signal_avg,
noise: ifaces[dev].noise,
snr: station.sta_info.signal_avg - ifaces[dev].noise,
inactive_time: station.sta_info.inactive_time,
rx: {
bitrate: format_rate(station.sta_info.rx_bitrate?.bitrate ?? 0),
bitrate_raw: station.sta_info.rx_bitrate?.bitrate ?? 0,
packets: station.sta_info.rx_packets ?? 0,
flags: assoc_flags(station.sta_info.rx_bitrate ?? {}),
},
tx: {
bitrate: format_rate(station.sta_info.tx_bitrate?.bitrate ?? 0),
bitrate_raw: station.sta_info.tx_bitrate?.bitrate ?? 0,
packets: station.sta_info.tx_packets ?? 0,
flags: assoc_flags(station.sta_info.tx_bitrate ?? {}),
},
expected_throughput: station.sta_info.expected_throughput ?? 'unknown',
};
ret[sta.mac] = sta;
}
return ret;
};
export function freqlist(name) {
const freq_flags = {
no_10mhz: 'NO_10MHZ',
no_20mhz: 'NO_20MHZ',
no_ht40_minus: 'NO_HT40-',
no_ht40_plus: 'NO_HT40+',
no_80mhz: 'NO_80MHZ',
no_160mhz: 'NO_160MHZ',
indoor_only: 'INDOOR_ONLY',
no_ir: 'NO_IR',
no_he: 'NO_HE',
radar: 'RADAR_DETECTION',
};
let iface = ifaces[name];
let phy = find_phy(iface.wiphy);
let channels = [];
for (let k, band in phy.wiphy_bands) {
if (!band)
continue;
let band_name = format_band(band.freqs[0].freq);
for (let freq in band.freqs) {
if (freq.disabled)
continue;
let channel = {
freq: format_frequency(freq.freq),
band: band_name,
channel: format_channel(freq.freq),
flags: [],
active: iface.wiphy_freq == freq.freq,
};
for (let k, v in freq_flags)
if (freq[k])
push(channel.flags, v);
push(channels, channel);
}
}
return channels;
};
export function info(name) {
let order = [];
for (let iface, data in ifaces)
push(order, iface);
let list = [];
for (let iface in sort(order)) {
if (name && iface != name)
continue;
let data = ifaces[iface];
let dev = {
iface,
ssid: data.ssid,
mac: data.mac,
mode: data.mode,
channel: format_channel(data.wiphy_freq),
freq: format_frequency(data.wiphy_freq),
htmode: data.radio?.htmode,
center_freq1: format_channel(data.center_freq1) || 'unknown',
center_freq2: format_channel(data.center_freq2) || 'unknown',
txpower: data.wiphy_tx_power_level / 100,
noise: data.noise,
signal: 0,
bitrate: 0,
encryption: 'unknown',
hwmode: hwmodelist(iface),
phy: 'phy' + data.wiphy,
vaps: 'no',
hw_type: data.hardware.type,
hw_id: data.hardware.id,
power_offset: data.hardware.power_offset || 'none',
channel_offset: data.hardware.channel_offset || 'none',
};
let phy = find_phy(data.wiphy);
for (let limit in phy.interface_combinations[0]?.limits)
if (limit.types?.ap && limit.max > 1)
dev.vaps = 'yes';
if (data.bss_info) {
if (data.bss_info.wpa_key_mgmt && data.bss_info.wpa_pairwise)
dev.encryption = `${replace(data.bss_info.wpa_key_mgmt, ' ', ' / ')} (${data.bss_info.wpa_pairwise})`;
else if (data.owe_transition_ifname)
dev.encryption = 'none (OWE transition)';
else
dev.encryption = 'none';
}
let stations = assoclist(iface);
for (let k, station in stations) {
dev.signal += station.signal;
dev.bitrate += station.tx.bitrate_raw;
}
dev.signal /= length(data.assoclist) || 1;
dev.bitrate /= length(data.assoclist) || 1;
dev.bitrate = format_rate(dev.bitrate);
dev.quality = dbm2quality(dev.signal);
if (data.owe_transition_ifname)
dev.owe_transition_ifname = data.owe_transition_ifname;
push(list, dev);
}
return list;
};
export function htmodelist(name) {
let iface = ifaces[name];
let phy = board_data.wlan?.['phy' + iface.wiphy];
if (!phy || !iface.radio.band)
return [];
return filter(phy.info.bands[uc(iface.radio.band)].modes, (v) => v != 'NOHT');
};
export function txpowerlist(name) {
let iface = ifaces[name];
let max_power = iface.max_power / 100;
let match = iface.wiphy_tx_power_level / 100;
let list = [];
for (let power = 0; power <= max_power; power++) {
let txpower = {
dbm: power,
mw: dbm2mw(power),
active: power == match,
};
push(list, txpower);
}
return list;
};
export function countrylist(dev) {
let iface = ifaces[dev];
let list = {
active: iface.country,
countries,
};
return list;
};
function scan_extension(ext, cell) {
const eht_chan_width = [ '20 MHz', '40 MHz', '80 MHz', '160 MHz', '320 MHz'];
switch(ord(ext, 0)) {
case 36:
let offset = 7;
if (!(ord(ext, 3) & 0x2))
break;
if (ord(ext, 2) & 0x40)
offset += 3;
if (ord(ext, 2) & 0x80)
offset += 1;
cell.he = {
chan_width: eht_chan_width[ord(ext, offset + 1) & 0x3],
center_chan_1: ord(ext, offset + 2),
center_chan_2: ord(ext, offset + 3),
};
break;
case 106:
if (!(ord(ext, 1) & 0x1))
break;
cell.eht = {
chan_width: eht_chan_width[ord(ext, 6) & 0x7],
center_chan_1: ord(ext, 7),
center_chan_2: ord(ext, 8),
};
break;
}
};
export function scan(dev) {
const rsn_cipher = [ 'NONE', 'WEP-40', 'TKIP', 'WRAP', 'CCMP', 'WEP-104', 'AES-OCB', 'CKIP', 'GCMP', 'GCMP-256', 'CCMP-256' ];
const ht_chan_offset = [ 'no secondary', 'above', '[reserved]', 'below' ];
const vht_chan_width = [ '20 or 40 MHz', '80 MHz', '80+80 MHz', '160 MHz' ];
const ht_chan_width = [ '20 MHz', '40 MHz or higher' ];
const SCAN_FLAG_AP = (1<<2);
let params = {
dev,
scan_flags: SCAN_FLAG_AP,
scan_ssids: [ '' ],
};
let res = nl80211.request(nl80211.const.NL80211_CMD_TRIGGER_SCAN, 0, params);
if (res === false) {
printf("Unable to trigger scan: " + nl80211.error() + "\n");
exit(1);
}
res = nl80211.waitfor([
nl80211.const.NL80211_CMD_NEW_SCAN_RESULTS,
nl80211.const.NL80211_CMD_SCAN_ABORTED
], 5000);
if (!res) {
printf("Netlink error while awaiting scan results: " + nl80211.error() + "\n");
exit(1);
} else if (res.cmd == nl80211.const.NL80211_CMD_SCAN_ABORTED) {
printf("Scan aborted by kernel\n");
exit(1);
}
let scan = nl80211.request(nl80211.const.NL80211_CMD_GET_SCAN, nl80211.const.NLM_F_DUMP, { dev });
let cells = [];
for (let k, bss in scan) {
bss = bss.bss;
let cell = {
bssid: uc(bss.bssid),
frequency: format_frequency(bss.frequency),
band: format_band(bss.frequency),
channel: format_channel(bss.frequency),
dbm: bss.signal_mbm / 100,
};
if (bss.capability & (1 << 1))
cell.mode = 'Ad-Hoc';
else if (bss.capability & (1 << 0))
cell.mode = 'Master';
else
cell.mode = 'Mesh Point';
cell.quality = dbm2quality(cell.dbm);
for (let ie in bss.information_elements)
switch(ie.type) {
case 0:
case 114:
cell.ssid = ie.data;
break;
case 7:
cell.country = substr(ie.data, 0, 2);
break;
case 48:
cell.crypto = {
group: rsn_cipher[ord(ie.data, 5)] ?? '',
pair: [],
key_mgmt: [],
};
let offset = 6;
let count = ord(ie.data, offset);
offset += 2;
for (let i = 0; i < count; i++) {
let key = rsn_cipher[ord(ie.data, offset + 3)];
if (key)
push(cell.crypto.pair, key);
offset += 4;
}
count = ord(ie.data, offset);
offset += 2;
for (let i = 0; i < count; i++) {
let key = format_mgmt_key(ord(ie.data, offset + 3));
if (key)
push(cell.crypto.key_mgmt, key);
offset += 4;
}
break;
case 61:
cell.ht = {
primary_channel: ord(ie.data, 0),
secondary_chan_off: ht_chan_offset[ord(ie.data, 1) & 0x3],
chan_width: ht_chan_width[(ord(ie.data, 1) & 0x4) >> 2],
};
break;
case 192:
cell.vht = {
chan_width: vht_chan_width[ord(ie.data, 0)],
center_chan_1: ord(ie.data, 1),
center_chan_2: ord(ie.data, 2),
};
break;
case 255:
scan_extension(ie.data, cell);
break;
};
push(cells, cell);
}
return cells;
};

View File

@@ -1,518 +0,0 @@
'use strict';
import * as libuci from 'uci';
import { md5 } from 'digest';
import * as fs from 'fs';
import { append, append_raw, append_value, append_vars, append_string_vars, comment, push_config, set_default, touch_file } from 'wifi.common';
import * as netifd from 'wifi.netifd';
import * as iface from 'wifi.iface';
function iface_setup(config) {
switch(config.fixup) {
case 'owe':
config.ignore_broadcast_ssid = true;
config.ssid = config.ssid + 'OWE';
break;
case 'owe-transition':
let ifname = config.ifname;
config.ifname = config.owe_transition_ifname;
config.owe_transition_ifname = ifname;
config.owe_transition_ssid = config.ssid + 'OWE';
config.encryption = 'none';
config.ignore_broadcast_ssid = false;
iface.prepare(config);
break;
}
comment('Setup interface: ' + config.ifname);
config.bridge = config.network_bridge;
config.snoop_iface = config.network_ifname;
if (!config.wds)
config.wds_bridge = null;
else
config.wds_sta = true;
if (!config.idx)
append('interface', config.ifname);
else
append('bss', config.ifname);
if (config.multicast_to_unicast || config.proxy_arp)
config.ap_isolate = 1;
append('bssid', config.macaddr);
config.ssid2 = config.ssid;
config.wmm_enabled = 1;
append_string_vars(config, [ 'ssid2' ]);
append_vars(config, [
'ctrl_interface', 'ap_isolate', 'max_num_sta', 'ap_max_inactivity', 'airtime_bss_weight',
'airtime_bss_limit', 'airtime_sta_weight', 'bss_load_update_period', 'chan_util_avg_period',
'disassoc_low_ack', 'skip_inactivity_poll', 'ignore_broadcast_ssid', 'uapsd_advertisement_enabled',
'utf8_ssid', 'multi_ap', 'multi_ap_vlanid', 'multi_ap_profile', 'tdls_prohibit', 'bridge',
'wds_sta', 'wds_bridge', 'snoop_iface', 'vendor_elements', 'nas_identifier', 'radius_acct_interim_interval',
'ocv', 'multicast_to_unicast', 'preamble', 'proxy_arp', 'per_sta_vif', 'mbo',
'bss_transition', 'wnm_sleep_mode', 'wnm_sleep_mode_no_keys', 'qos_map_set', 'max_listen_int',
'dtim_period', 'wmm_enabled', 'start_disabled',
]);
}
function iface_authentication_server(config) {
for (let server in config.auth_server_addr) {
append('auth_server_addr', server);
append_vars(config, [ 'auth_server_port', 'auth_server_shared_secret' ]);
}
append_vars(config, [ 'radius_auth_req_attr' ]);
}
function iface_accounting_server(config) {
for (let server in config.acct_server_addr) {
append('acct_server_addr', server);
append_vars(config, [ 'acct_server_port', 'acct_server_shared_secret' ]);
}
append_vars(config, [ 'radius_acct_req_attr' ]);
}
function iface_auth_type(config) {
if (config.auth_type in [ 'sae', 'owe', 'eap2', 'eap192' ]) {
config.ieee80211w = 2;
config.sae_require_mfp = 1;
config.sae_pwe = 2;
}
if (config.auth_type in [ 'psk-sae', 'eap-eap2' ]) {
config.ieee80211w = 1;
if (config.rsn_override)
config.rsn_override_mfp = 2;
config.sae_require_mfp = 1;
config.sae_pwe = 2;
}
if (config.own_ip_addr)
config.dynamic_own_ip_addr = null;
if (!config.wpa)
config.wpa_disable_eapol_key_retries = null;
switch(config.auth_type) {
case 'none':
case 'owe':
config.wps_possible = 1;
config.wps_state = 1;
append_string_vars(config, [ 'owe_transition_ssid' ]);
append_vars(config, [
'owe_transition_bssid', 'owe_transition_ifname',
]);
break;
case 'psk':
case 'psk2':
case 'sae':
case 'psk-sae':
config.vlan_possible = 1;
config.wps_possible = 1;
if (config.auth_type == 'psk' && config.ppsk) {
iface_authentication_server(config);
config.macaddr_acl = 2;
config.wpa_psk_radius = 2;
} else if (length(config.key) == 64) {
config.wpa_psk = key;
} else if (length(config.key) >= 8) {
config.wpa_passphrase = config.key;
} else if (!config.wpa_psk_file) {
netifd.setup_failed('INVALID_WPA_PSK');
}
set_default(config, 'wpa_psk_file', `/var/run/hostapd-${config.ifname}.psk`);
touch_file(config.wpa_psk_file);
break;
case 'eap':
case 'eap2':
case 'eap-eap2':
case 'eap192':
config.vlan_possible = 1;
if (config.fils) {
set_default(config, 'erp_domain', substr(md5(config.ssid), 0, 4));
set_default(config, 'fils_realm', config.erp_domain);
set_default(config, 'erp_send_reauth_start', 1);
set_default(config, 'fils_cache_id', substr(md5(config.fils_realm), 0, 4));
}
if (!config.eap_server) {
iface_authentication_server(config);
iface_accounting_server(config);
}
if (config.radius_das_client && config.radius_das_secret) {
set_default(config, 'radius_das_port', 3799);
set_default(config, 'radius_das_client', `${config.radius_das_client} ${config.radius_das_secret}`);
}
set_default(config, 'eapol_version', config.wpa & 1);
if (!config.eapol_version)
config.eapol_version = null;
append('eapol_key_index_workaround', '1');
append('ieee8021x', '1');
break;
}
append_vars(config, [
'sae_require_mfp', 'sae_pwe', 'time_advertisement', 'time_zone',
'wpa_group_rekey', 'wpa_ptk_rekey', 'wpa_gmk_rekey', 'wpa_strict_rekey',
'macaddr_acl', 'wpa_psk_radius', 'wpa_psk', 'wpa_passphrase', 'wpa_psk_file',
'eapol_version', 'dynamic_vlan', 'radius_request_cui', 'eap_reauth_period',
'radius_das_client', 'radius_das_port', 'own_ip_addr', 'dynamic_own_ip_addr',
'wpa_disable_eapol_key_retries', 'auth_algs', 'wpa', 'wpa_pairwise',
'erp_domain', 'fils_realm', 'erp_send_reauth_start', 'fils_cache_id'
]);
}
function iface_ppsk(config) {
if (!(config.auth_type in [ 'none', 'owe', 'psk', 'sae', 'psk-sae', 'wep' ]) || !config.auth_server_addr)
return;
iface_authentication_server(config);
append('macaddr_acl', '2');
}
function iface_wps(config) {
push_config(config, 'config_methods', 'wps_pushbutton', 'push_button');
push_config(config, 'config_methods', 'wps_label', 'label');
if (config.multi_ap == 1)
config.wps_possible = false;
if (config.wps_possible && length(config.config_methods)) {
config.eap_server = 1;
set_default(config, 'wps_state', 2);
if (config.ext_registrar && config.network_bridge)
set_default(config, 'upnp_iface', config.network_bridge);
if (config.multi_ap && config.multi_ap_backhaul_ssid) {
append_string_vars(config, [ 'multi_ap_backhaul_ssid' ]);
if (length(config.multi_ap_backhaul_key) == 64)
append('multi_ap_backhaul_wpa_psk', config.multi_ap_backhaul_key);
else if (length(config.multi_ap_backhaul_key) > 8)
append('multi_ap_backhaul_wpa_passphrase', config.multi_ap_backhaul_key);
else
netifd.setup_failed('INVALID_WPA_PSK');
}
append_vars(config, [
'wps_state', 'device_type', 'device_name', 'config_methods', 'wps_independent', 'eap_server',
'ap_pin', 'ap_setup_locked', 'upnp_iface'
]);
}
}
function iface_rrm(config) {
set_default(config, 'rrm_neighbor_report', config.ieee80211k);
set_default(config, 'rrm_beacon_report', config.ieee80211k);
append_vars(config, [
'rrm_neighbor_report', 'rrm_beacon_report', 'rnr', 'ftm_responder',
]);
}
function iface_ftm(config, phy_features) {
if (!phy_features.ftm_responder || !config.ftm_responder)
return;
append_vars(config, [
'ftm_responder', 'lci', 'civic'
]);
}
function iface_macfilter(config) {
let path = `/var/run/hostapd-${config.ifname}.maclist`;
switch(config.macfilter) {
case 'allow':
append('accept_mac_file', path);
append('macaddr_acl', 1);
config.vlan_possible = 1;
break;
case 'deny':
append('deny_mac_file', path);
append('macaddr_acl', 0);
break;
default:
return;
}
let file = fs.open(path, 'w');
if (!file) {
warn(`Failed to open ${path}`);
return;
}
if (config.maclist)
file.write(join('\n', config.maclist));
let macfile = fs.readfile(config.macfile);
if (macfile)
file.write(macfile);
file.close();
}
function iface_vlan(interface, config, vlans) {
let path = `/var/run/hostapd-${config.ifname}.vlan`;
let file = fs.open(path, 'w');
for (let k, vlan in vlans)
if (vlan.config.name && vlan.config.vid) {
let ifname = `${config.ifname}-${vlan.config.name}`;
file.write(`${vlan.config.vid} ${ifname}\n`);
netifd.set_vlan(interface, k, ifname);
}
file.close();
set_default(config, 'vlan_file', path);
append_vars(config, [ 'vlan_file' ]);
if (!config.vlan_possible || !config.dynamic_vlan)
return;
set_default(config, 'vlan_no_bridge', !config.vlan_bridge);
append_vars(config, [
'dynamic_vlan', 'vlan_naming', 'vlan_bridge', 'vlan_no_bridge',
'vlan_tagged_interface'
]);
}
function iface_stations(config, stas) {
if (!length(stas))
return;
let path = `/var/run/hostapd-${config.ifname}.psk`;
let file = fs.open(path, 'w');
for (let k, sta in stas)
if (sta.config.mac && sta.config.key) {
let station = `${sta.config.mac} ${sta.config.key}\n`;
if (sta.config.vid)
station = `vlanid=${sta.config.vid} ` + station;
file.write(station);
}
file.close();
set_default(config, 'wpa_psk_file', path);
}
function iface_eap_server(config) {
if (!config.eap_server)
return;
set_default(config, 'eap_server', true);
set_default(config, 'eap_server_erp', true);
append_vars(config, [
'eap_server', 'eap_server_erp', 'eap_user_file', 'ca_cert', 'server_cert',
'private_key', 'private_key_passwd', 'server_id',
]);
}
function iface_roaming(config) {
if (!config.ieee80211r || config.wpa < 2)
return;
set_default(config, 'mobility_domain', substr(md5(config.ssid), 0, 4));
set_default(config, 'ft_psk_generate_local', config.auth_type == 'psk');
set_default(config, 'ft_iface', config.network_ifname);
if (!config.ft_psk_generate_local) {
if (!config.r0kh || !config.r1kh) {
if (!config.auth_secret && !config.key)
netifd.setup_failed('FT_KEY_CANT_BE_DERIVED');
let ft_key = md5(`${config.mobility_domain}/${config.auth_secret ?? config.key}`);
set_default(config, 'r0kh', [ 'ff:ff:ff:ff:ff:ff,*,' + ft_key ]);
set_default(config, 'r1kh', [ '00:00:00:00:00:00,00:00:00:00:00:00,' + ft_key ]);
}
for (let name in [ 'r0kh', 'r1kh' ])
for (let val in config[name])
append(name, join(' ', split(val, ',', 3)));
append_vars(config, [
'r1_key_holder', 'r0_key_lifetime', 'pmk_r1_push'
]);
}
append_vars(config, [
'mobility_domain', 'ft_psk_generate_local', 'ft_over_ds', 'reassociation_deadline',
'ft_iface'
]);
}
function iface_mfp(config) {
if (!config.ieee80211w || config.wpa < 2) {
append('ieee80211w', 0);
return;
}
if (config.auth_type == 'eap192')
config.group_mgmt_cipher = 'BIP-GMAC-256';
else
config.group_mgmt_cipher = config.ieee80211w_mgmt_cipher ?? 'AES-128-CMAC';
append_vars(config, [
'ieee80211w', 'group_mgmt_cipher', 'assoc_sa_query_max_timeout', 'assoc_sa_query_retry_timeout'
]);
}
function iface_key_caching(config) {
if (config.wpa < 2)
return;
if (config.network_bridge && config.rsn_preauth) {
set_default(config, 'okc', true);
config.rsn_preauth_interfaces = config.network_bridge;
append_vars(config, [
'rsn_preauth', 'rsn_preauth_interfaces'
]);
} else {
set_default(config, 'okc', (config.auth_type in [ 'sae', 'psk-sae', 'owe' ]));
}
if (!config.okc && !config.fils)
config.disable_pmksa_caching = 1;
append_vars(config, [
'okc', 'disable_pmksa_caching'
]);
}
function iface_hs20(config) {
if (!config.hs20)
return;
append_vars(config, [
'hs20', 'disable_dgaf', 'anqp_domain_id', 'hs20_deauth_req_timeout',
'hs20_wan_metrics', 'hs20_operating_class', 'hs20_t_c_filename', 'hs20_t_c_timestamp',
'hs20_t_c_server_url', 'hs20_conn_capab'
]);
}
function iface_interworking(config) {
if (!config.iw_enabled)
return;
config.interworking = true;
if (config.domain_name)
config.domain_name = join(',', config.domain_name);
if (config.anqp_3gpp_cell_net)
config.domain_name = join(',', config.anqp_3gpp_cell_net);
append_vars(config, [
'interworking', 'internet', 'asra', 'uesa', 'access_network_type', 'hessid', 'venue_group',
'venue_type', 'network_auth_type', 'gas_address3', 'roaming_consortium', 'anqp_elem', 'nai_realm',
'venue_name', 'venue_url', 'domain_name', 'anqp_3gpp_cell_net',
]);
}
export function generate(interface, data, config, vlans, stas, phy_features) {
config.ctrl_interface = '/var/run/hostapd';
iface_stations(config, stas);
config.start_disabled = data.ap_start_disabled;
iface_setup(config);
iface.parse_encryption(config, data.config);
if (data.config.band == '6g') {
if (config.auth_type == 'psk-sae')
config.auth_type = 'sae';
if (config.auth_type == 'eap-eap2')
config.auth_type = 'eap2';
}
iface_auth_type(config);
iface_accounting_server(config);
iface_ppsk(config);
iface_wps(config);
iface_rrm(config);
iface_ftm(config, phy_features);
iface_macfilter(config);
iface_vlan(interface, config, vlans);
iface_eap_server(config);
iface_roaming(config);
iface_mfp(config);
iface_key_caching(config);
iface_hs20(config);
iface_interworking(config);
iface.wpa_key_mgmt(config);
append_vars(config, [
'wpa_key_mgmt',
]);
if (config.rsn_override_key_mgmt || config.rsn_override_pairwise) {
config.rsn_override_mfp ??= config.ieee80211w;
config.rsn_override_key_mgmt ??= config.wpa_key_mgmt;
config.rsn_override_pairwise ??= config.wpa_pairwise;
append_vars(config, [
'rsn_override_key_mgmt',
'rsn_override_pairwise',
'rsn_override_mfp'
]);
if (config.mlo) {
config.rsn_override_mfp_2 ??= config.rsn_override_mfp;
config.rsn_override_key_mgmt_2 ??= config.rsn_override_key_mgmt;
config.rsn_override_pairwise_2 ??= config.rsn_override_pairwise;
append_vars(config, [
'rsn_override_key_mgmt_2',
'rsn_override_pairwise_2',
'rsn_override_mfp_2'
]);
}
}
/* raw options */
for (let raw in config.hostapd_options)
append_raw(raw);
if (config.mlo) {
append_raw('mld_ap=1');
if (data.config.radio != null)
append_raw('mld_link_id=' + data.config.radio);
}
if (config.default_macaddr)
append_raw('#default_macaddr');
else if (config.random_macaddr)
append_raw('#random_macaddr');
};

View File

@@ -1,174 +0,0 @@
'use strict';
import * as libubus from 'ubus';
import * as nl80211 from 'nl80211';
import * as fs from 'fs';
global.ubus = libubus.connect();
let config_data = '';
let network_data = '';
const nl80211_bands = [ '2g', '5g', '60g', '6g' ];
export function wiphy_info(phy) {
let idx = +fs.readfile(`/sys/class/ieee80211/${phy}/index`);
return nl80211.request(nl80211.const.NL80211_CMD_GET_WIPHY, nl80211.const.NLM_F_DUMP, {
wiphy: idx,
split_wiphy_dump: true
});
};
export function wiphy_band(info, band) {
let band_idx = index(nl80211_bands, band);
if (band_idx < 0 || !info)
return;
return info.wiphy_bands[band_idx];
};
export function log(msg) {
printf(`wifi-scripts: ${msg}\n`);
};
export function append_raw(value) {
config_data += value + '\n';
};
export function append(key, value) {
if (value == null)
return;
switch (type(value)) {
case 'array':
value = join(' ', value);
break;
case 'bool':
value = value ? 1 : 0;
break;
}
append_raw(key + '=' + value);
};
function escape_string(value) {
let chars = map(split(value, ''), (v) => ord(v));
if (length(filter(chars, (v) => (v < 32 || v >= 128))) > 0)
return hexenc(value);
return `"${value}"`;
}
export function append_string(key, value) {
if (value == null)
return;
append(key, escape_string(value));
};
export function append_vars(dict, keys) {
for (let key in keys)
append(key, dict[key]);
};
export function append_string_vars(dict, keys) {
for (let key in keys)
append_string(key, dict[key]);
};
export function network_append_raw(value) {
network_data += value + '\n';
};
export function network_append(key, value) {
if (value == null)
return;
switch (type(value)) {
case 'array':
value = join(' ', value);
break;
case 'bool':
value = value ? 1 : 0;
break;
}
network_append_raw('\t' + key + '=' + value);
};
export function network_append_string(key, value) {
if (value == null)
return;
network_append_raw('\t' + key + '=' + escape_string(value));
};
export function network_append_vars(dict, keys) {
for (let key in keys)
network_append(key, dict[key]);
};
export function network_append_string_vars(dict, keys) {
for (let key in keys)
network_append_string(key, dict[key]);
};
export function set_default(dict, key, value) {
if (dict[key] == null)
dict[key] = value;
};
export function push_config(dict, key, option, value) {
if (!dict[option])
return;
dict[key] ??= [];
push(dict[key], value);
};
export function touch_file(filename) {
let file = fs.open(filename, "a");
if (file)
file.close();
else
log('Failed to touch ' + filename);
};
export function append_value(config, key, value) {
if (!config[key])
config[key] = value;
else
config[key] += ' ' + value;
};
export function comment(comment) {
append_raw('\n# ' + comment);
};
export function dump_config(file) {
if (file)
fs.writefile(file, config_data);
return config_data;
};
export function dump_network(file) {
config_data += 'network={\n';
config_data += network_data;;
config_data += '}\n';
if (file)
fs.writefile(file, config_data);
return config_data;
};
export function flush_config() {
config_data = '';
};
export function flush_network() {
config_data = '';
network_data = '';
};

View File

@@ -1,580 +0,0 @@
'use strict';
import {
append, append_raw, append_vars, dump_config, flush_config, set_default,
wiphy_info, wiphy_band
} from 'wifi.common';
import { validate } from 'wifi.validate';
import * as netifd from 'wifi.netifd';
import * as iface from 'wifi.iface';
import * as nl80211 from 'nl80211';
import * as ap from 'wifi.ap';
import * as fs from 'fs';
const NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER = 33;
const NL80211_EXT_FEATURE_RADAR_BACKGROUND = 61;
let phy_features = {};
let phy_capabilities = {};
/* make sure old style UCI and hwmode and newer band properties are correctly resolved */
function set_device_defaults(config) {
/* validate the hw mode */
if (config.hw_mode in [ '11a', '11b', '11g', '11ad' ])
config.hw_mode = substr(config.hw_mode, 2);
else if (config.channel > 14)
config.hw_mode = 'a';
else
config.hw_mode = 'g';
/* validate band */
if (config.band == '2g')
config.hw_mode = 'g';
else if (config.band in [ '5g', '6g', '60g' ])
config.hw_mode = 'a';
else
switch (config.hw_mode) {
case 'a':
config.band = '5g';
break;
case 'ad':
config.band = '60g';
break;
default:
config.band = '2g';
break;
}
}
/* setup sylog / stdout */
function device_log_append(config) {
let log_mask = 0;
for (let k in [ 'log_mlme', 'log_iapp', 'log_driver', 'log_wpa', 'log_radius', 'log_8021x', 'log_80211' ]) {
log_mask <<= 1;
log_mask |= config[k] ? 1 : 0;
}
append('logger_syslog', log_mask);
append('logger_syslog_level', config.log_level);
append('logger_stdout', log_mask);
append('logger_stdout_level', config.log_level);
}
/* setup country code */
function device_country_code(config) {
let status = global.ubus.call('network.wireless', 'status');
for (let name, radio in status) {
if (!radio.config.country)
continue;
config.country_code = radio.config.country;
}
if (!exists(config, 'country_code'))
return;
if (config.hw_mode != 'a')
delete config.ieee80211h;
append_vars(config, [ 'country_code', 'country3', 'ieee80211h' ]);
if (config.ieee80211d)
append_vars(config, [ 'ieee80211d', 'local_pwr_constraint', 'spectrum_mgmt_required' ]);
}
/* setup cell density */
function device_cell_density_append(config) {
switch (config.hw_mode) {
case 'b':
if (config.cell_density == 1) {
config.supported_rates ??= [ 5500, 11000 ];
config.basic_rates ??= [ 5500, 11000 ];
} else if (config.cell_density > 2) {
config.supported_rates ??= [ 11000 ];
config.basic_rates ??= [ 11000 ];
}
;;
case 'g':
if (config.cell_density in [ 0, 1 ]) {
if (!config.legacy_rates) {
config.supported_rates ??= [ 6000, 9000, 12000, 18000, 24000, 36000, 48000, 54000 ];
config.basic_rates ??= [ 6000, 12000, 24000 ];
} else if (config.cell_density == 1) {
config.supported_rates ??= [ 5500, 6000, 9000, 11000, 12000, 18000, 24000, 36000, 48000, 54000 ];
config.basic_rates ??= [ 5500, 11000 ];
}
} else if (config.cell_density == 2 || (config.cell_density > 3 && config.legacy_rates)) {
if (!config.legacy_rates) {
config.supported_rates ??= [ 12000, 18000, 24000, 36000, 48000, 54000 ];
config.basic_rates ??= [ 12000, 24000 ];
} else {
config.supported_rates ??= [ 11000, 12000, 18000, 24000, 36000, 48000, 54000 ];
config.basic_rates ??= [ 11000 ];
}
} else if (config.cell_density > 2) {
config.supported_rates ??= [ 24000, 36000, 48000, 54000 ];
config.basic_rates ??= [ 24000 ];
}
;;
case 'a':
switch (config.cell_density) {
case 1:
config.supported_rates ??= [ 6000, 9000, 12000, 18000, 24000, 36000, 48000, 54000 ];
config.basic_rates ??= [ 6000, 12000, 24000 ];
break;
case 2:
config.supported_rates ??= [ 12000, 18000, 24000, 36000, 48000, 54000 ];
config.basic_rates ??= [ 12000, 24000 ];
break;
case 3:
config.supported_rates ??= [ 24000, 36000, 48000, 54000 ];
config.basic_rates ??= [ 24000 ];
break;
}
}
}
function device_rates(config) {
for (let key in [ 'supported_rates', 'basic_rates' ])
config[key] = map(config[key], x => x / 100);
append_vars(config, [ 'beacon_rate', 'supported_rates', 'basic_rates' ]);
}
function device_htmode_append(config) {
config.channel_offset = config.band == '6g' ? 1 : 0;
/* 802.11n */
config.ieee80211n = 0;
if (config.band != '6g') {
if (config.htmode in [ 'VHT20', 'HT20', 'HE20', 'EHT20' ])
config.ieee80211n = 1;
if (config.htmode in [ 'HT40', 'HT40+', 'HT40-', 'VHT40', 'VHT80', 'VHT160', 'HE40', 'HE80', 'HE160', 'EHT40', 'EHT80', 'EHT160' ]) {
config.ieee80211n = 1;
if (!config.channel)
config.ht_capab = '[HT40+]';
else
switch (config.hw_mode) {
case 'a':
switch (((config.channel / 4) + config.channel_offset) % 2) {
case 0:
config.ht_capab = '[HT40-]';
break;
case 1:
config.ht_capab = '[HT40+]';
break;
}
break;
default:
switch (config.htmode) {
case 'HT40+':
case 'HT40-':
config.ht_capab = '[' + config.htmode + ']';
break;
default:
if (config.channel < 7)
config.ht_capab = '[HT40+]';
else
config.ht_capab = '[HT40-]';
break;
}
}
}
if (config.ieee80211n) {
let ht_capab = phy_capabilities.ht_capa;
if (ht_capab & 0x1 && config.ldpc)
config.ht_capab += '[LDPC]';
if (ht_capab & 0x10 && config.greenfield)
config.ht_capab += '[GF]';
if (ht_capab & 0x20 && config.short_gi_20)
config.ht_capab += '[SHORT-GI-20]';
if (ht_capab & 0x40 && config.short_gi_40)
config.ht_capab += '[SHORT-GI-40]';
if (ht_capab & 0x80 && config.tx_stbc)
config.ht_capab += '[TX-STBC]';
if (ht_capab & 0x800 && config.max_amsdu)
config.ht_capab += '[MAX-AMSDU-7935]';
if (ht_capab & 0x1000 && config.dsss_cck_40)
config.ht_capab += '[DSSS_CCK-40]';
let rx_stbc = [ '', '[RX-STBC1]', '[RX-STBC12]', '[RX-STBC123]' ];
config.ht_capab += rx_stbc[min(config.rx_stbc, (ht_capab >> 8) & 3)];
append_vars(config, [ 'ieee80211n', 'ht_coex', 'ht_capab' ]);
}
}
/* 802.11ac */
config.ieee80211ac = 1;
config.vht_oper_centr_freq_seg0_idx = 0;
config.vht_oper_chwidth = 0;
switch (config.htmode) {
case 'VHT20':
case 'HE20':
case 'EHT20':
break;
case 'VHT40':
case 'HE40':
case 'EHT40':
config.vht_oper_centr_freq_seg0_idx = config.channel + (((config.channel / 4) + config.channel_offset) % 2 ? 2 : -2);
break;
case 'VHT80':
case 'HE80':
case 'EHT80':
let delta = [ -6, 6, 2, -2 ];
config.vht_oper_centr_freq_seg0_idx = config.channel + delta[((config.channel / 4) + config.channel_offset) % 4];
config.vht_oper_chwidth = 1;
break;
case 'VHT160':
case 'HE160':
case 'EHT160':
let vht_oper_centr_freq_seg0_idx_map = [[ 64, 50 ], [ 128, 114 ], [ 177, 163 ]];
if (config.band == '6g')
vht_oper_centr_freq_seg0_idx_map = [
[ 29, 15 ], [ 61, 47 ], [ 93, 79 ], [ 125, 111 ],
[ 157, 143 ], [ 189, 175 ], [ 221, 207 ]];
for (let k, v in vht_oper_centr_freq_seg0_idx_map)
if (config.channel >= (v[0] - 28) && config.channel <= v[0]) {
config.vht_oper_centr_freq_seg0_idx = v[1];
break;
}
config.vht_oper_chwidth = 2;
break;
default:
config.ieee80211ac = 0;
break;
}
config.eht_oper_chwidth = config.vht_oper_chwidth;
config.eht_oper_centr_freq_seg0_idx = config.vht_oper_centr_freq_seg0_idx;
if (config.band == '6g') {
config.ieee80211ac = 0;
switch(config.htmode) {
case 'HE20':
case 'EHT20':
config.op_class = 131;
break;
case 'EHT320':
let eht_center_seg0_map = [
[ 61, 31 ], [ 125, 95 ], [ 189, 159 ], [ 221, 191 ]
];
for (let k, v in eht_center_seg0_map)
if (config.channel <= v[0]) {
config.eht_oper_centr_freq_seg0_idx = v[1];
break;
}
config.op_class = 137;
config.eht_oper_chwidth = 7;
break;
case 'HE40':
case 'HE80':
case 'HE160':
case 'EHT40':
case 'EHT80':
case 'EHT160':
config.op_class = 132 + config.eht_oper_chwidth;
break;
}
append_vars(config, [ 'op_class' ]);
}
if (config.ieee80211ac && config.hw_mode == 'a') {
/* VHT capab */
if (config.vht_oper_chwidth < 2) {
config.vht160 = 0;
config.short_gi_160 = 0;
}
config.tx_queue_data2_burst = '2.0';
let vht_capab = phy_capabilities.vht_capa;
config.vht_capab = '';
if (vht_capab & 0x10 && config.rxldpc)
config.vht_capab += '[RXLDPC]';
if (vht_capab & 0x20 && config.short_gi_80)
config.vht_capab += '[SHORT-GI-80]';
if (vht_capab & 0x40 && config.short_gi_160)
config.vht_capab += '[SHORT-GI-160]';
if (vht_capab & 0x80 && config.tx_stbc_2by1)
config.vht_capab += '[TX-STBC-2BY1]';
if (vht_capab & 0x800 && config.su_beamformer)
config.vht_capab += '[SU-BEAMFORMER]';
if (vht_capab & 0x1000 && config.su_beamformee)
config.vht_capab += '[SU-BEAMFORMEE]';
if (vht_capab & 0x80000 && config.mu_beamformer)
config.vht_capab += '[MU-BEAMFORMER]';
if (vht_capab & 0x100000 && config.mu_beamformee)
config.vht_capab += '[MU-BEAMFORMEE]';
if (vht_capab & 0x200000 && config.vht_txop_ps)
config.vht_capab += '[VHT-TXOP-PS]';
if (vht_capab & 0x400000 && config.htc_vht)
config.vht_capab += '[HTC-VHT]';
if (vht_capab & 0x10000000 && config.rx_antenna_pattern)
config.vht_capab += '[RX-ANTENNA-PATTERN]';
if (vht_capab & 0x20000000 && config.tx_antenna_pattern)
config.vht_capab += '[TX-ANTENNA-PATTERN]';
let rx_stbc = [ '', '[RX-STBC-1]', '[RX-STBC-12]', '[RX-STBC-123]', '[RX-STBC-1234]' ];
config.vht_capab += rx_stbc[min(config.rx_stbc, (vht_capab >> 8) & 7)];
if (vht_capab & 0x800 && config.su_beamformer)
config.vht_capab += '[SOUNDING-DIMENSION-' + min(((vht_capab >> 16) & 3) + 1, config.beamformer_antennas) + ']';
if (vht_capab & 0x1000 && config.su_beamformee)
config.vht_capab += '[BF-ANTENNA-' + min(((vht_capab >> 13) & 3) + 1, config.beamformer_antennas) + ']';
/* supported Channel widths */
if ((vht_capab & 0xc) == 8 && config.vht160 <= 2)
config.vht_capab += '[VHT160-80PLUS80]';
else if ((vht_capab & 0xc) == 4 && config.vht160 <= 2)
config.vht_capab += '[VHT160]';
/* maximum MPDU length */
if ((vht_capab & 3) > 1 && config.vht_max_mpdu >= 11454)
config.vht_capab += '[MAX-MPDU-11454]';
else if ((vht_capab & 3) && config.vht_max_mpdu >= 7991)
config.vht_capab += '[MAX-MPDU-7991]';
/* maximum A-MPDU length exponent */
let max_a_mpdu_len_exp = (vht_capab >> 20) & 0x38;
for (let exp = 7; exp; exp--)
if (max_a_mpdu_len_exp >= (0x8 * exp) && exp <= config.vht_max_a_mpdu_len_exp) {
config.vht_capab += '[MAX-A-MPDU-LEN-EXP' + exp + ']';
break;
}
/* whether or not the STA supports link adaptation using VHT variant */
let vht_link_adapt = vht_capab & 0xC000000;
if (vht_link_adapt >= 0xC000000 && config.vht_link_adapt > 3)
config.vht_capab += '[VHT-LINK-ADAPT-3]';
if (vht_link_adapt >= 0x8000000 && config.vht_link_adapt > 2)
config.vht_capab += '[VHT-LINK-ADAPT-2]';
append_vars(config, [
'ieee80211ac', 'vht_oper_chwidth', 'vht_oper_centr_freq_seg0_idx',
'vht_capab'
]);
}
/* 802.11ax */
if (wildcard(config.htmode, 'HE*') || wildcard(config.htmode, 'EHT*')) {
let he_phy_cap = phy_capabilities.he_phy_cap;
let he_mac_cap = phy_capabilities.he_mac_cap;
config.ieee80211ax = true;
if (config.hw_mode == 'a') {
config.he_oper_chwidth = config.vht_oper_chwidth;
config.he_oper_centr_freq_seg0_idx = config.vht_oper_centr_freq_seg0_idx;
}
if (config.he_bss_color_enabled) {
if (config.he_spr_non_srg_obss_pd_max_offset)
config.he_spr_sr_control |= 1 << 2;
if (!config.he_spr_psr_enabled)
config.he_spr_sr_control |= 1;
append_vars(config, [ 'he_bss_color', 'he_spr_non_srg_obss_pd_max_offset', 'he_spr_sr_control' ]);
}
if (!(he_phy_cap[3] & 0x80))
config.he_su_beamformer = false;
if (!(he_phy_cap[4] & 0x1))
config.he_su_beamformee = false;
if (!(he_phy_cap[4] & 0x2))
config.he_mu_beamformer = false;
if (!(he_phy_cap[7] & 0x1))
config.he_spr_psr_enabled = false;
if (!(he_mac_cap[0] & 0x1))
config.he_twt_required= false;
append_vars(config, [
'ieee80211ax', 'he_oper_chwidth', 'he_oper_centr_freq_seg0_idx',
'he_su_beamformer', 'he_su_beamformee', 'he_mu_beamformer', 'he_twt_required',
'he_default_pe_duration', 'he_rts_threshold', 'he_mu_edca_qos_info_param_count',
'he_mu_edca_qos_info_q_ack', 'he_mu_edca_qos_info_queue_request', 'he_mu_edca_qos_info_txop_request',
'he_mu_edca_ac_be_aifsn', 'he_mu_edca_ac_be_aci', 'he_mu_edca_ac_be_ecwmin',
'he_mu_edca_ac_be_ecwmax', 'he_mu_edca_ac_be_timer', 'he_mu_edca_ac_bk_aifsn',
'he_mu_edca_ac_bk_aci', 'he_mu_edca_ac_bk_ecwmin', 'he_mu_edca_ac_bk_ecwmax',
'he_mu_edca_ac_bk_timer', 'he_mu_edca_ac_vi_ecwmin', 'he_mu_edca_ac_vi_ecwmax',
'he_mu_edca_ac_vi_aifsn', 'he_mu_edca_ac_vi_aci', 'he_mu_edca_ac_vi_timer',
'he_mu_edca_ac_vo_aifsn', 'he_mu_edca_ac_vo_aci', 'he_mu_edca_ac_vo_ecwmin',
'he_mu_edca_ac_vo_ecwmax', 'he_mu_edca_ac_vo_timer',
]);
}
if (wildcard(config.htmode, 'EHT*')) {
config.ieee80211be = true;
append_vars(config, [ 'ieee80211be' ]);
if (config.hw_mode == 'a')
append_vars(config, [ 'eht_oper_chwidth', 'eht_oper_centr_freq_seg0_idx' ]);
if (config.band == "6g") {
config.stationary_ap = true;
append_vars(config, [ 'he_6ghz_reg_pwr_type', ]);
}
}
append_vars(config, [ 'tx_queue_data2_burst', 'stationary_ap' ]);
}
function device_extended_features(data, flag) {
return !!(data[flag / 8] | (1 << (flag % 8)));
}
function device_capabilities(config) {
let phy = config.phy;
phy = wiphy_info(phy);
let band = wiphy_band(phy, config.band);
phy_capabilities.ht_capa = band.ht_capa ?? 0;
phy_capabilities.vht_capa = band.vht_capa ?? 0;
for (let iftype in band.iftype_data) {
if (!iftype.iftypes.ap)
continue;
phy_capabilities.he_mac_cap = iftype.he_cap_mac;
phy_capabilities.he_phy_cap = iftype.he_cap_phy;
}
phy_features.ftm_responder = device_extended_features(phy.extended_features, NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER);
phy_features.radar_background = device_extended_features(phy.extended_features, NL80211_EXT_FEATURE_RADAR_BACKGROUND);
}
function generate(config) {
if (!config)
die(`${config.path} is an unknown phy`);
device_capabilities(config);
append('driver', 'nl80211');
set_device_defaults(config);
device_log_append(config);
device_country_code(config);
device_cell_density_append(config);
device_rates(config);
/* beacon */
append_vars(config, [ 'beacon_int', 'beacon_rate', 'rnr_beacon' ]);
/* wpa_supplicant co-exist */
append_vars(config, [ 'noscan' ]);
/* airtime */
if (config.airtime_mode)
append_vars(config, [ 'airtime_mode' ]);
/* assoc/thresholds */
append_vars(config, [ 'rssi_reject_assoc_rssi', 'rssi_ignore_probe_request', 'iface_max_num_sta', 'no_probe_resp_if_max_sta' ]);
/* ACS / Radar*/
if (!phy_features.radar_background || config.band != '5g')
delete config.enable_background_radar;
else
set_default(config, 'enable_background_radar', false);
append_vars(config, [ 'acs_chan_bias', 'acs_exclude_dfs', 'enable_background_radar' ]);
/* TX Power */
append_vars(config, [ 'min_tx_power' ]);
/* hwmode, channel, op_class, ... */
append_vars(config, [ 'hw_mode', 'channel', 'rts_threshold', 'chanlist' ]);
if (config.hw_mode in [ 'a', 'g' ] && config.require_mode in [ 'n', 'ac', 'ax' ]) {
let require_mode = { n: 'require_ht', ac: 'require_vht', ax: 'require_he' };
config.legacy_rates = false;
append(require_mode[config.require_mode], 1);
}
device_htmode_append(config);
if (config.ieee80211ax || config.ieee80211be)
append_vars(config, [ 'mbssid' ]);
/* 6G power mode */
if (config.band != '6g')
append_vars(config, [ 'reg_power_type' ]);
/* raw options */
for (let raw in config.hostapd_options)
append_raw(raw);
}
let iface_idx = 0;
function setup_interface(interface, data, config, vlans, stas, phy_features, fixup) {
config = { ...config, fixup };
config.idx = iface_idx++;
ap.generate(interface, data, config, vlans, stas, phy_features);
}
export function setup(data) {
let file_name = `/var/run/hostapd-${data.phy}${data.vif_phy_suffix}.conf`;
flush_config();
if (fs.stat(file_name))
fs.rename(file_name, file_name + '.prev');
data.config.phy = data.phy;
generate(data.config);
if (data.config.num_global_macaddr)
append('\n#num_global_macaddr', data.config.num_global_macaddr);
if (data.config.macaddr_base)
append('\n#macaddr_base', data.config.macaddr_base);
let has_ap;
for (let k, interface in data.interfaces) {
if (interface.config.mode != 'ap')
continue;
interface.config.network_bridge = interface.bridge;
interface.config.network_ifname = interface['bridge-ifname'];
let owe = interface.config.encryption == 'owe' && interface.config.owe_transition;
setup_interface(k, data, interface.config, interface.vlans, interface.stas, phy_features, owe ? 'owe' : null );
if (owe)
setup_interface(k, data, interface.config, interface.vlans, interface.stas, phy_features, 'owe-transition');
has_ap = true;
}
let config = dump_config(file_name);
let msg = {
phy: data.phy,
radio: data.config.radio,
config: has_ap ? file_name : "",
prev_config: file_name + '.prev'
};
let ret = global.ubus.call('hostapd', 'config_set', msg);
if (ret)
netifd.add_process('/usr/sbin/hostapd', ret.pid, true, true);
else if (fs.access('/usr/sbin/hostapd', 'x'))
netifd.setup_failed('HOSTAPD_START_FAILED');
};

View File

@@ -1,252 +0,0 @@
'use strict';
import { append_value, log } from 'wifi.common';
import * as fs from 'fs';
export function parse_encryption(config, dev_config) {
let encryption = split(config.encryption, '+', 2);
config.wpa = 0;
for (let k, v in { 'wpa2*': 2, 'wpa3*': 2, '*psk2*': 2, 'psk3*': 2, 'sae*': 2,
'owe*': 2, 'wpa*mixed*': 3, '*psk*mixed*': 3, 'wpa*': 1, '*psk*': 1, })
if (wildcard(config.encryption, k)) {
config.wpa = v;
break;
}
if (!config.wpa)
config.wpa_pairwise = null;
config.wpa_pairwise = (config.hw_mode == 'ad') ? 'GCMP' : 'CCMP';
config.auth_type = encryption[0] ?? 'none';
let wpa3_pairwise = config.wpa_pairwise;
if (wildcard(dev_config?.htmode, 'EHT*') || wildcard(dev_config?.htmode, 'HE*'))
wpa3_pairwise = 'GCMP-256 ' + wpa3_pairwise;
switch(config.auth_type) {
case 'owe':
config.auth_type = 'owe';
break;
case 'wpa3-192':
config.auth_type = 'eap192';
break;
case 'wpa3-mixed':
config.auth_type = 'eap-eap2';
break;
case 'wpa3':
config.auth_type = 'eap2';
break;
case 'psk':
case 'psk-mixed':
config.auth_type = "psk";
wpa3_pairwise = null;
break;
case 'sae':
case 'psk3':
config.auth_type = 'sae';
break;
case 'psk3-mixed':
case 'sae-mixed':
config.auth_type = 'psk-sae';
break;
case 'wpa':
case 'wpa2':
case 'wpa-mixed':
config.auth_type = 'eap';
wpa3_pairwise = null;
break;
case 'psk2':
wpa3_pairwise = null;
break;
default:
config.wpa_pairwise = null;
wpa3_pairwise = null;
break;
}
switch(encryption[1]){
case 'tkip+aes':
case 'tkip+ccmp':
case 'aes+tkip':
case 'ccmp+tkip':
config.wpa_pairwise = 'CCMP TKIP';
break;
case 'ccmp256':
config.wpa_pairwise = 'CCMP-256';
break;
case 'aes':
case 'ccmp':
config.wpa_pairwise = 'CCMP';
break;
case 'tkip':
config.wpa_pairwise = 'TKIP';
break;
case 'gcmp256':
config.wpa_pairwise = 'GCMP-256';
break;
case 'gcmp':
config.wpa_pairwise = 'GCMP';
break;
default:
if (config.encryption == 'wpa3-192') {
config.wpa_pairwise = 'GCMP-256';
break;
}
if (!wpa3_pairwise)
break;
if (config.rsn_override)
config.rsn_override_pairwise = wpa3_pairwise;
else
config.wpa_pairwise = wpa3_pairwise;
break;
}
};
export function wpa_key_mgmt(config) {
if (!config.wpa)
return;
switch(config.auth_type) {
case 'psk':
case 'psk2':
append_value(config, 'wpa_key_mgmt', 'WPA-PSK');
if (config.wpa >= 2 && config.ieee80211r)
append_value(config, 'wpa_key_mgmt', 'FT-PSK');
if (config.ieee80211w)
append_value(config, 'wpa_key_mgmt', 'WPA-PSK-SHA256');
break;
case 'eap':
append_value(config, 'wpa_key_mgmt', 'WPA-EAP');
if (config.wpa >= 2 && config.ieee80211r)
append_value(config, 'wpa_key_mgmt', 'FT-EAP');
if (config.ieee80211w)
append_value(config, 'wpa_key_mgmt', 'WPA-EAP-SHA256');
break;
case 'eap192':
append_value(config, 'wpa_key_mgmt', 'WPA-EAP-SUITE-B-192');
if (config.ieee80211r)
append_value(config, 'wpa_key_mgmt', 'FT-EAP-SHA384');
break;
case 'eap-eap2':
append_value(config, 'wpa_key_mgmt', 'WPA-EAP-SHA256');
if (config.ieee80211r)
append_value(config, 'wpa_key_mgmt', 'FT-EAP');
config.rsn_override_key_mgmt = config.wpa_key_mgmt;
append_value(config, 'wpa_key_mgmt', 'WPA-EAP');
break;
case 'eap2':
append_value(config, 'wpa_key_mgmt', 'WPA-EAP-SHA256');
if (config.ieee80211r)
append_value(config, 'wpa_key_mgmt', 'FT-EAP');
break;
case 'sae':
append_value(config, 'wpa_key_mgmt', 'SAE');
if (config.ieee80211r)
append_value(config, 'wpa_key_mgmt', 'FT-SAE');
break;
case 'psk-sae':
append_value(config, 'wpa_key_mgmt', 'SAE');
if (config.ieee80211r)
append_value(config, 'wpa_key_mgmt', 'FT-SAE');
config.rsn_override_key_mgmt = config.wpa_key_mgmt;
append_value(config, 'rsn_override_key_mgmt_2', 'SAE-EXT-KEY');
if (config.ieee80211r)
append_value(config, 'rsn_override_key_mgmt_2', 'FT-SAE-EXT-KEY');
if (config.rsn_override > 1)
delete config.wpa_key_mgmt;
append_value(config, 'wpa_key_mgmt', 'WPA-PSK');
if (config.ieee80211w)
append_value(config, 'wpa_key_mgmt', 'WPA-PSK-SHA256');
if (config.ieee80211r)
append_value(config, 'wpa_key_mgmt', 'FT-PSK');
break;
case 'owe':
append_value(config, 'wpa_key_mgmt', 'OWE');
break;
}
if (config.fils) {
switch(config.auth_type) {
case 'eap192':
append_value(config, 'wpa_key_mgmt', 'FILS-SHA384');
if (config.ieee80211r)
append_value(config, 'wpa_key_mgmt', 'FT-FILS-SHA384');
break;
case 'eap-eap2':
case 'eap2':
case 'eap':
append_value(config, 'wpa_key_mgmt', 'FILS-SHA256');
if (config.ieee80211r)
append_value(config, 'wpa_key_mgmt', 'FT-FILS-SHA256');
if (!config.rsn_override_key_mgmt)
break;
append_value(config, 'rsn_override_key_mgmt', 'FILS-SHA256');
if (config.ieee80211r)
append_value(config, 'rsn_override_key_mgmt', 'FT-FILS-SHA256');
break;
}
}
config.key_mgmt = config.wpa_key_mgmt;
};
function macaddr_random() {
let f = fs.open("/dev/urandom", "r");
let addr = f.read(6);
addr = map(split(addr, ""), (v) => ord(v));
addr[0] &= ~1;
addr[0] |= 2;
return join(":", map(addr, (v) => sprintf("%02x", v)));
}
let mac_idx = 0;
export function prepare(data, phy, num_global_macaddr, macaddr_base) {
if (!data.macaddr) {
let pipe = fs.popen(`ucode /usr/share/hostap/wdev.uc ${phy} get_macaddr id=${mac_idx} num_global=${num_global_macaddr} mbssid=${data.mbssid ?? 0} macaddr_base=${macaddr_base ?? ""}`);
data.macaddr = trim(pipe.read("all"), '\n');
pipe.close();
data.default_macaddr = true;
mac_idx++;
} else if (data.macaddr == 'random') {
data.macaddr = macaddr_random();
data.random_macaddr = true;
}
log(`Preparing interface: ${data.ifname} with MAC: ${data.macaddr}`);
};

View File

@@ -1,49 +0,0 @@
'use strict';
import { log } from 'wifi.common';
import * as fs from 'fs';
const CMD_UP = 0;
const CMD_SET_DATA = 1;
const CMD_PROCESS_ADD = 2;
const CMD_PROCESS_KILL_ALL = 3;
const CMD_SET_RETRY = 4;
export function notify(command, params, data) {
params ??= {};
data ??= {};
global.ubus.call('network.wireless', 'notify', { command, device: global.radio, ...params, data });
};
export function set_up() {
notify(CMD_UP);
};
export function set_data(data) {
notify(CMD_SET_DATA, null, data);
};
export function add_process(exe, pid, required, keep) {
exe = fs.realpath(exe);
notify(CMD_PROCESS_ADD, null, { pid, exe, required, keep });
};
export function set_retry(retry) {
notify(CMD_SET_RETRY, null, { retry });
};
export function set_vif(interface, ifname) {
notify(CMD_SET_DATA, { interface }, { ifname });
};
export function set_vlan(interface, ifname, vlan) {
notify(CMD_SET_DATA, { interface, vlan }, { ifname });
};
export function setup_failed(reason) {
log(`Device setup failed: ${reason}`);
printf('%s\n', reason);
set_retry(false);
};

View File

@@ -1,296 +0,0 @@
'use strict';
import {
append, append_raw, append_vars, network_append, network_append_raw, network_append_vars,
network_append_string_vars, set_default, dump_network, flush_network,
wiphy_info, wiphy_band
} from 'wifi.common';
import * as netifd from 'wifi.netifd';
import * as iface from 'wifi.iface';
import * as fs from 'fs';
function set_fixed_freq(data, config) {
if (!data.frequency)
return;
set_default(config, 'fixed_freq', 1);
set_default(config, 'frequency', data.frequency);
if (data.htmode in [ 'VHT80', 'HE80' ])
set_default(config, 'max_oper_chwidth', 1);
else if (data.htmode in [ 'VHT160', 'HE160' ])
set_default(config, 'max_oper_chwidth', 2);
else if (data.htmode in [ 'VHT20', 'VHT40', 'HE20', 'HE40' ])
set_default(config, 'max_oper_chwidth', 0);
else
set_default(config, 'disable_vht', true);
if (data.htmode in [ 'NOHT' ])
set_default(config, 'disable_ht', true);
else if (data.htmode in [ 'HT20', 'VHT20', 'HE20' ])
set_default(config, 'disable_ht40', true);
else if (data.htmode in [ 'VHT40', 'VHT80', 'VHT160', 'HE40', 'HE80', 'HE160' ])
set_default(config, 'ht40', true);
if (wildcard(data.htmode, 'VHT*'))
set_default(config, 'vht', 1);
}
export function ratestr(rate) {
if (rate == null)
return rate;
let rem = (rate / 100) % 10;
rate = int(rate / 1000);
if (rem > 0)
rate += "." + rem;
return "" + rate;
};
export function ratelist(rates) {
if (length(rates) < 1)
return null;
return join(",", map(rates, (rate) => ratestr(rate)));
};
function setup_sta(data, config) {
iface.parse_encryption(config);
if (config.auth_type in [ 'sae', 'owe', 'eap2', 'eap192' ])
config.ieee80211w = 2;
else if (config.auth_type in [ 'psk-sae' ])
config.ieee80211w = 1;
if ((wildcard(data.htmode, 'EHT*') || wildcard(data.htmode, 'HE*')) &&
config.rsn_override)
config.rsn_overriding = 1;
else
config.rsn_overriding = 0;
set_default(config, 'ieee80211r', 0);
set_default(config, 'sae_pwe', 2);
set_default(config, 'multi_ap', 0);
set_default(config, 'multi_profile', 1);
set_default(config, 'default_disabled', 0);
config.scan_ssid = 1;
switch(config.mode) {
case 'sta':
set_default(config, 'multi_ap_backhaul_sta', config.multi_ap);
break;
case 'adhoc':
config.ap_scan = 2;
config.scan_ssid = 0;
network_append('mode', 1);
set_fixed_freq(data, config);
break;
case 'mesh':
config.ssid = config.mesh_id;
config.scan_ssid = null;
network_append('mode', 5);
set_fixed_freq(data, config);
if (config.encryption && config.encryption != 'none')
config.key_mgmt = 'SAE';
config.ieee80211w = null;
break;
}
if (config.mode != 'mesh' ) {
switch(config.wpa) {
case 1:
config.proto = 'WPA';
break;
case 2:
config.proto = 'RSN';
break;
}
}
switch(config.auth_type) {
case 'none':
break;
case 'owe':
iface.wpa_key_mgmt(config);
break;
case 'wps':
config.key_mgmt = 'WPS';
break;
case 'psk':
case 'psk2':
case 'sae':
case 'psk-sae':
if (config.mode != 'mesh')
iface.wpa_key_mgmt(config);
if (config.mode == 'mesh' || config.auth_type == 'sae')
config.sae_password = `"${config.key}"`;
else
config.psk = `"${config.key}"`;
break;
case 'eap':
case 'eap2':
case 'eap192':
iface.wpa_key_mgmt(config);
set_default(config, 'erp', config.fils);
if (config.ca_cert_usesystem && fs.stat('/etc/ssl/certs/ca-certificates.crt'))
config.ca_cert = '/etc/ssl/certs/ca-certificates.crt';
switch(config.eap_type) {
case 'fast':
case 'peap':
case 'ttls':
set_default(config, 'auth', 'MSCHAPV2');
if (config.auth == 'EAP-TLS') {
if (config.ca_cert2_usesystem && fs.stat('/etc/ssl/certs/ca-certificates.crt'))
config.ca_cert2 = '/etc/ssl/certs/ca-certificates.crt';
}
break;
}
}
if (config.wpa_pairwise == 'GCMP') {
config.pairwise = 'GCMP';
config.group = 'GCMP';
}
config.key_mgmt ??= 'NONE';
config.basic_rate = ratelist(config.basic_rate);
config.mcast_rate = ratestr(config.mcast_rate);
network_append_string_vars(config, [ 'ssid' ]);
network_append_vars(config, [
'rsn_overriding', 'scan_ssid', 'noscan', 'disabled', 'multi_ap_profile', 'multi_ap_backhaul_sta',
'ocv', 'key_mgmt', 'sae_pwe', 'psk', 'sae_password', 'pairwise', 'group', 'bssid',
'proto', 'mesh_fwding', 'mesh_rssi_threshold', 'frequency', 'fixed_freq',
'disable_ht', 'disable_ht40', 'disable_vht', 'vht', 'max_oper_chwidth',
'ht40', 'beacon_int', 'ieee80211w', 'basic_rate', 'mcast_rate',
'bssid_blacklist', 'bssid_whitelist', 'erp', 'ca_cert', 'identity',
'anonymous_identity', 'client_cert', 'private_key', 'private_key_passwd',
'subject_match', 'altsubject_match', 'domain_match', 'domain_suffix_match',
'ca_cert2', 'client_cert2', 'private_key2', 'private_key2_passwd', 'password'
]);
}
function freq_in_range(freq_ranges, freq)
{
if (!freq_ranges)
return true;
freq *= 1000;
for (let range in freq_ranges)
if (freq >= range.start && freq <= range.end)
return true;
}
function wiphy_frequencies(phy, band, radio) {
phy = wiphy_info(phy);
band = wiphy_band(phy, band);
if (!band)
return;
let ranges;
for (let r in phy.radios)
if (r.index == radio)
ranges = r.freq_ranges;
let freqs = [];
for (let chan in band.freqs)
if (!chan.disabled && freq_in_range(ranges, chan.freq))
push(freqs, chan.freq);
if (length(freqs) > 0)
return freqs;
}
export function generate(config_list, data, interface) {
flush_network();
if (interface.bridge &&
(interface.config.mode == 'adhoc' ||
(interface.config.mode == 'sta' && !interface.config.wds && !interface.config.multi_ap))){
netifd.setup_failed('BRIDGE_NOT_ALLOWED');
return 1;
}
interface.config.country = data.config.country_code;
interface.config.beacon_int = data.config.beacon_int;
if (!data.config.scan_list)
data.config.scan_list = wiphy_frequencies(data.phy, data.config.band, data.config.radio);
if (data.config.scan_list)
interface.config.freq_list = join(" ", data.config.scan_list);
append_vars(interface.config, [ 'country', 'beacon_int', 'freq_list' ]);
setup_sta(data.config, interface.config);
let file_name = `/var/run/wpa-supplicant-${interface.config.ifname}.conf`;
if (fs.stat(file_name))
fs.rename(file_name, file_name + '.prev');
dump_network(file_name);
let config = {
mode: interface.config.mode,
ctrl: '/var/run/wpa_supplicant',
iface: interface.config.ifname,
config: file_name,
'4addr': !!interface.config.wds,
mlo: !!interface.config.mlo,
freq_list: data.config.scan_list,
powersave: false
};
if (!interface.config.default_macaddr)
config.macaddr = interface.config.macaddr;
if (interface.config.wds)
config.bridge = interface.bridge;
push(config_list, config);
return config;
};
export function setup(config, data) {
let ret = global.ubus.call('wpa_supplicant', 'config_set', {
phy: data.phy,
radio: data.config.radio,
config,
defer: true,
num_global_macaddr: data.config.num_global_macaddr,
macaddr_base: data.config.macaddr_base ?? "",
});
if (ret)
netifd.add_process('/usr/sbin/wpa_supplicant', ret.pid, true, true);
else if (fs.access('/usr/sbin/wpa_supplicant', 'x'))
netifd.setup_failed('SUPPLICANT_START_FAILED');
};
export function start(data) {
global.ubus.call('wpa_supplicant', 'config_set', {
phy: data.phy,
radio: data.config.radio,
num_global_macaddr: data.config.num_global_macaddr,
macaddr_base: data.config.macaddr_base ?? "",
});
};

View File

@@ -1,121 +0,0 @@
'use strict';
import { log } from 'wifi.common';
import * as fs from 'fs';
const schemas = {
device: json(fs.readfile('/usr/share/schema/wireless.wifi-device.json')).properties,
iface: json(fs.readfile('/usr/share/schema/wireless.wifi-iface.json')).properties,
vlan: json(fs.readfile('/usr/share/schema/wireless.wifi-vlan.json')).properties,
station: json(fs.readfile('/usr/share/schema/wireless.wifi-station.json')).properties,
};
const types = {
"array": 1,
"string": 3,
"number": 5,
"boolean": 7,
};
function dump_option(schema, key) {
let _key = (schema[key].type == 'alias') ? schema[key].default : key;
return [
key,
types[schema[_key].type]
];
}
export function dump_options() {
let dump = {
"name": "mac80211",
};
for (let k, v in schemas) {
dump[k] = [];
for (let option in v)
push(dump[k], dump_option(v, option));
};
printf('%J\n', dump);
return 0;
};
function abort(msg) {
log(msg);
die();
}
function validate_value(schema, key, value) {
switch(schema.type) {
case 'number':
value = +value;
if (schema.minimum && value < schema.minimum)
abort(`${key}: ${value} is lower than the minimum value`);
if (schema.maximum && value > schema.maximum)
abort(`${key}: ${value} is larger than the maximum value`);
if (schema.enum && !(value in schema.enum))
abort(`${key}: ${value} has to be one of ${schema.enum}`);
break;
case 'boolean':
value = !!+value;
break;
case 'string':
if (schema.enum && !(value in schema.enum))
abort(`${key}: ${value} has to be one of ${schema.enum}`);
break;
case 'array':
if (type(value) != 'array')
value = [ value ];
if (schema.items?.type)
for (let k, v in value)
value[k] = validate_value(schema.items, key, v);
break;
}
return value;
}
export function validate(schema, dict) {
schema = schemas[schema];
/* complain about anything that is not in the schema */
for (let k, v in dict) {
if (substr(k, 0, 1) == '.')
continue;
if (schema[k])
continue;
log(`${k} is not present in the schema`);
}
/* convert all aliases */
for (let k, v in dict) {
if (schema[k]?.type != 'alias')
continue;
if (schema[k].default == null)
abort(`${k} alias does not have a default value`);
dict[schema[k].default] = v;
delete dict[k];
}
/* set defaults */
for (let k, v in schema) {
if (schema[k]?.type == 'alias')
continue;
if (dict[k] != null || schema[k].default == null)
continue;
dict[k] = schema[k].default;
}
/* validate value constraints */
for (let k, v in dict) {
if (!schema[k])
continue;
dict[k] = validate_value(schema[k], k, v);
}
};

View File

@@ -1,261 +0,0 @@
{
"pci": [
[ "0x0777", "0x11ac", "0x0777", "0xe7f9", 0, 0, "Ubiquiti", "LiteBeam, 5AC" ],
[ "0xffff", "0xffff", "0xffff", "0xb102", 0, 0, "Ubiquiti", "PowerStation2, (18V)" ],
[ "0xffff", "0xffff", "0xffff", "0xb202", 0, 0, "Ubiquiti", "PowerStation2, (16D)" ],
[ "0xffff", "0xffff", "0xffff", "0xb302", 0, 0, "Ubiquiti", "PowerStation2, (EXT)" ],
[ "0xffff", "0xffff", "0xffff", "0xb105", 0, 0, "Ubiquiti", "PowerStation5, (22V)" ],
[ "0xffff", "0xffff", "0xffff", "0xb305", 0, 0, "Ubiquiti", "PowerStation5, (EXT)" ],
[ "0xffff", "0xffff", "0xffff", "0xc302", 0, 0, "Ubiquiti", "PicoStation2" ],
[ "0xffff", "0xffff", "0xffff", "0xc3a2", 10, 0, "Ubiquiti", "PicoStation2, HP" ],
[ "0xffff", "0xffff", "0xffff", "0xa105", 0, 0, "Ubiquiti", "WispStation5" ],
[ "0xffff", "0xffff", "0xffff", "0xa002", 10, 0, "Ubiquiti", "LiteStation2" ],
[ "0xffff", "0xffff", "0xffff", "0xa005", 5, 0, "Ubiquiti", "LiteStation5" ],
[ "0xffff", "0xffff", "0xffff", "0xc002", 10, 0, "Ubiquiti", "NanoStation2" ],
[ "0xffff", "0xffff", "0xffff", "0xc005", 5, 0, "Ubiquiti", "NanoStation5" ],
[ "0xffff", "0xffff", "0xffff", "0xc102", 10, 0, "Ubiquiti", "NanoStation, Loco2" ],
[ "0xffff", "0xffff", "0xffff", "0xc105", 5, 0, "Ubiquiti", "NanoStation, Loco5" ],
[ "0xffff", "0xffff", "0xffff", "0xc202", 10, 0, "Ubiquiti", "Bullet2" ],
[ "0xffff", "0xffff", "0xffff", "0xc205", 5, 0, "Ubiquiti", "Bullet5" ],
[ "0x168c", "0xffff", "0x0777", "0xe002", 6, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe003", 3, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe005", 5, 0, "Ubiquiti", "NanoStation, M5" ],
[ "0x168c", "0xffff", "0x0777", "0xe006", 5, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe009", 6, 0, "Ubiquiti", "NanoStation, Loco, M9" ],
[ "0x168c", "0xffff", "0x0777", "0xe012", 10, 0, "Ubiquiti", "NanoStation, M2" ],
[ "0x168c", "0xffff", "0x0777", "0xe035", 3, 0, "Ubiquiti", "NanoStation, M3" ],
[ "0x168c", "0xffff", "0x0777", "0xe0a2", 2, 0, "Ubiquiti", "NanoStation, Loco, M2" ],
[ "0x168c", "0xffff", "0x0777", "0xe0a5", 1, 0, "Ubiquiti", "NanoStation, Loco, M5" ],
[ "0x168c", "0xffff", "0x0777", "0xe102", 6, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe105", 5, 0, "Ubiquiti", "Rocket, M5" ],
[ "0x168c", "0xffff", "0x0777", "0xe112", 10, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe115", 3, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe1a3", 3, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe1a5", 5, 0, "Ubiquiti", "PowerBridge, M5" ],
[ "0x168c", "0xffff", "0x0777", "0xe1b2", 10, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe1b3", 3, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe1b5", 5, 0, "Ubiquiti", "Rocket, M5" ],
[ "0x168c", "0xffff", "0x0777", "0xe1b6", 5, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe1b9", 6, 0, "Ubiquiti", "Rocket, M9" ],
[ "0x168c", "0xffff", "0x0777", "0xe1c2", 10, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe1c3", 3, 0, "Ubiquiti", "Rocket, M3" ],
[ "0x168c", "0xffff", "0x0777", "0xe1c5", 5, 0, "Ubiquiti", "Rocket, M5, GPS" ],
[ "0x168c", "0xffff", "0x0777", "0xe1c5", 5, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe1d2", 10, 0, "Ubiquiti", "Rocket, M2, Titanium" ],
[ "0x168c", "0xffff", "0x0777", "0xe1d3", 3, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe1d5", 5, 0, "Ubiquiti", "airOS, XM/XW" ],
[ "0x168c", "0xffff", "0x0777", "0xe1d9", 6, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe1e3", 3, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe1e5", 5, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe202", 12, 0, "Ubiquiti", "Bullet, M2" ],
[ "0x168c", "0xffff", "0x0777", "0xe205", 6, 0, "Ubiquiti", "Bullet, M5" ],
[ "0x168c", "0xffff", "0x0777", "0xe212", 1, 0, "Ubiquiti", "AirGrid, M2" ],
[ "0x168c", "0xffff", "0x0777", "0xe215", 1, 0, "Ubiquiti", "AirGrid, M5" ],
[ "0x168c", "0xffff", "0x0777", "0xe232", 2, 0, "Ubiquiti", "NanoBridge, M2" ],
[ "0x168c", "0xffff", "0x0777", "0xe233", 3, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe235", 1, 0, "Ubiquiti", "NanoBridge, M5" ],
[ "0x168c", "0xffff", "0x0777", "0xe239", 6, 0, "Ubiquiti", "NanoBridge, M9" ],
[ "0x168c", "0xffff", "0x0777", "0xe242", 9, 0, "Ubiquiti", "AirGrid, M2, HP" ],
[ "0x168c", "0xffff", "0x0777", "0xe243", 3, 0, "Ubiquiti", "NanoBridge, M3" ],
[ "0x168c", "0xffff", "0x0777", "0xe245", 6, 0, "Ubiquiti", "AirGrid, M5, HP" ],
[ "0x168c", "0xffff", "0x0777", "0xe252", 9, 0, "Ubiquiti", "AirGrid, M2, HP" ],
[ "0x168c", "0xffff", "0x0777", "0xe255", 6, 0, "Ubiquiti", "AirGrid, M5, HP" ],
[ "0x168c", "0xffff", "0x0777", "0xe2a3", 3, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe2a5", 5, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe2b2", 10, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe2b5", 1, 0, "Ubiquiti", "NanoBridge, M5" ],
[ "0x168c", "0xffff", "0x0777", "0xe2b9", 6, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe2c2", 10, 0, "Ubiquiti", "NanoBeam, M2, Int" ],
[ "0x168c", "0xffff", "0x0777", "0xe2c3", 6, 0, "Ubiquiti", "Bullet, M2, XW" ],
[ "0x168c", "0xffff", "0x0777", "0xe2c4", 6, 0, "Ubiquiti", "airOS, XW" ],
[ "0x168c", "0xffff", "0x0777", "0xe2d2", 12, 0, "Ubiquiti", "Bullet, M2, Titanium, HP" ],
[ "0x168c", "0xffff", "0x0777", "0xe2d4", 6, 0, "Ubiquiti", "airOS, XW" ],
[ "0x168c", "0xffff", "0x0777", "0xe2d5", 6, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe2e5", 4, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe302", 12, 0, "Ubiquiti", "PicoStation, M2"],
[ "0x168c", "0xffff", "0x0777", "0xe305", 6, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe345", 6, 0, "Ubiquiti", "WispStation, M5" ],
[ "0x168c", "0xffff", "0x0777", "0xe3a5", 5, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe3b5", 6, 0, "Ubiquiti", "airOS, XM/XW" ],
[ "0x168c", "0xffff", "0x0777", "0xe3e5", 4, 0, "Ubiquiti", "PowerBeam, M5, 300" ],
[ "0x168c", "0xffff", "0x0777", "0xe402", 10, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe405", 1, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe4a2", 1, 0, "Ubiquiti", "AirRouter" ],
[ "0x168c", "0xffff", "0x0777", "0xe4a5", 1, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe4b2", 9, 0, "Ubiquiti", "AirRouter, HP" ],
[ "0x168c", "0xffff", "0x0777", "0xe4d5", 5, 0, "Ubiquiti", "Rocket, M5, Titanium" ],
[ "0x168c", "0xffff", "0x0777", "0xe4e5", 4, 0, "Ubiquiti", "PowerBeam, M5, 400" ],
[ "0x168c", "0xffff", "0x0777", "0xe5e5", 4, 0, "Ubiquiti", "airOS, XW" ],
[ "0x168c", "0xffff", "0x0777", "0xe6a2", 1, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe6b2", 1, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe6b5", 5, 0, "Ubiquiti", "Rocket, M5, XW" ],
[ "0x168c", "0xffff", "0x0777", "0xe6c2", 6, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe6e5", 4, 0, "Ubiquiti", "PowerBeam, M5, 400, ISO" ],
[ "0x168c", "0xffff", "0x0777", "0xe7f8", 2, 0, "Ubiquiti", "airOS, XW" ],
[ "0x168c", "0xffff", "0x0777", "0xe805", 5, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0xffff", "0x0777", "0xe812", 6, 0, "Ubiquiti", "NanoBeam, M2, 13" ],
[ "0x168c", "0xffff", "0x0777", "0xe815", 4, 0, "Ubiquiti", "NanoBeam, M5, 16" ],
[ "0x168c", "0xffff", "0x0777", "0xe825", 4, 0, "Ubiquiti", "NanoBeam, M5, 19" ],
[ "0x168c", "0xffff", "0x0777", "0xe835", 6, 0, "Ubiquiti", "AirGrid, M5, XW" ],
[ "0x168c", "0xffff", "0x0777", "0xe845", 1, 0, "Ubiquiti", "NanoStation, Loco, M5, XW" ],
[ "0x168c", "0xffff", "0x0777", "0xe855", 5, 0, "Ubiquiti", "NanoStation, M5, XW" ],
[ "0x168c", "0xffff", "0x0777", "0xe865", 6, 0, "Ubiquiti", "LiteBeam, M5" ],
[ "0x168c", "0xffff", "0x0777", "0xe866", 6, 0, "Ubiquiti", "NanoStation, M2, XW" ],
[ "0x168c", "0xffff", "0x0777", "0xe867", 2, 0, "Ubiquiti", "NanoStation, Loco, M2, XW" ],
[ "0x168c", "0xffff", "0x0777", "0xe868", 7, 0, "Ubiquiti", "Rocket, M2, XW" ],
[ "0x168c", "0xffff", "0x0777", "0xe869", 2, 0, "Ubiquiti", "airOS, XW" ],
[ "0x168c", "0xffff", "0x0777", "0xe875", 4, 0, "Ubiquiti", "airOS, XW" ],
[ "0x168c", "0xffff", "0x0777", "0xe879", 2, 0, "Ubiquiti", "airOS, XW" ],
[ "0x168c", "0xffff", "0x0777", "0xe885", 4, 0, "Ubiquiti", "PowerBeam, M5, 620, XW" ],
[ "0x168c", "0xffff", "0x0777", "0xe895", 4, 0, "Ubiquiti", "airOS, XW" ],
[ "0x168c", "0xffff", "0x0777", "0xe8a5", 1, 0, "Ubiquiti", "NanoStation, Loco, M5"],
[ "0x168c", "0xffff", "0x0777", "0xe8b5", 5, 0, "Ubiquiti", "airOS, XM" ],
[ "0x168c", "0x001b", "0x0777", "0x3002", 10, 0, "Ubiquiti", "XR2" ],
[ "0x168c", "0x001b", "0x7777", "0x3002", 10, 0, "Ubiquiti", "XR2" ],
[ "0x168c", "0x001b", "0x0777", "0x3b02", 10, 0, "Ubiquiti", "XR2.3" ],
[ "0x168c", "0x001b", "0x0777", "0x3c02", 10, 0, "Ubiquiti", "XR2.6" ],
[ "0x168c", "0x001b", "0x0777", "0x3b03", 10, 0, "Ubiquiti", "XR3-2.8" ],
[ "0x168c", "0x001b", "0x0777", "0x3c03", 10, 0, "Ubiquiti", "XR3-3.6" ],
[ "0x168c", "0x001b", "0x0777", "0x3003", 10, 0, "Ubiquiti", "XR3" ],
[ "0x168c", "0x001b", "0x0777", "0x3004", 10, 0, "Ubiquiti", "XR4" ],
[ "0x168c", "0x001b", "0x0777", "0x3005", 10, 0, "Ubiquiti", "XR5" ],
[ "0x168c", "0x001b", "0x7777", "0x3005", 10, 0, "Ubiquiti", "XR5" ],
[ "0x168c", "0x001b", "0x0777", "0x3007", 10, 0, "Ubiquiti", "XR7" ],
[ "0x168c", "0x001b", "0x0777", "0x3009", 10, -1520, "Ubiquiti", "XR9" ],
[ "0x168c", "0x001b", "0x168c", "0x2063", 0, 0, "Atheros", "AR5413" ],
[ "0x168c", "0x0013", "0x168c", "0x1042", 1, 0, "Ubiquiti", "SRC" ],
[ "0x168c", "0x0013", "0x0777", "0x2041", 10, 0, "Ubiquiti", "SR2" ],
[ "0x168c", "0x0013", "0x0777", "0x2004", 6, 0, "Ubiquiti", "SR4" ],
[ "0x168c", "0x0013", "0x7777", "0x2004", 6, 0, "Ubiquiti", "SR4" ],
[ "0x168c", "0x0013", "0x0777", "0x1004", 6, 0, "Ubiquiti", "SR4C" ],
[ "0x168c", "0x0013", "0x7777", "0x1004", 6, 0, "Ubiquiti", "SR4C" ],
[ "0x168c", "0x0013", "0x168c", "0x2042", 7, 0, "Ubiquiti", "SR5" ],
[ "0x168c", "0x0013", "0x7777", "0x2009", 12, -1500, "Ubiquiti", "SR9" ],
[ "0x168c", "0x0027", "0x168c", "0x2082", 7, 0, "Ubiquiti", "SR71A" ],
[ "0x168c", "0x0027", "0x0777", "0x4082", 7, 0, "Ubiquiti", "SR71" ],
[ "0x168c", "0x0029", "0x0777", "0x4005", 7, 0, "Ubiquiti", "SR71-15" ],
[ "0x168c", "0x002a", "0x0777", "0xe302", 12, 0, "Ubiquiti", "PicoStation, M2" ],
[ "0x168c", "0x002a", "0x0777", "0xe012", 12, 0, "Ubiquiti", "NanoStation, M2" ],
[ "0x168c", "0x002a", "0x0777", "0xe005", 5, 0, "Ubiquiti", "NanoStation, M5" ],
[ "0x168c", "0x002a", "0x0777", "0xe202", 12, 0, "Ubiquiti", "Bullet, M2" ],
[ "0x168c", "0x002a", "0x0777", "0xe805", 5, 0, "Ubiquiti", "Bullet, M5" ],
[ "0x168c", "0x002a", "0x0777", "0xe345", 0, 0, "Ubiquiti", "WispStation, M5" ],
[ "0x168c", "0x0029", "0x168c", "0xa094", 0, 0, "Atheros", "AR9220" ],
[ "0x168c", "0x0029", "0x168c", "0xa095", 0, 0, "Atheros", "AR9223" ],
[ "0x168c", "0x002a", "0x168c", "0xa093", 0, 0, "Atheros", "AR9280" ],
[ "0x168c", "0x002b", "0x168c", "0xa091", 0, 0, "Atheros", "AR9285" ],
[ "0x168c", "0x002d", "0x168c", "0x209a", 0, 0, "Atheros", "AR9287" ],
[ "0x168c", "0x002e", "0x1a3b", "0x1121", 0, 0, "Atheros", "AR9287" ],
[ "0x168c", "0x002e", "0x0777", "0xe0a2", 8, 0, "Ubiquiti", "NanoStation, Loco, M2, (XM)" ],
[ "0x168c", "0x002e", "0x168c", "0x30a4", 0, 0, "Atheros", "AR9287" ],
[ "0x168c", "0x002e", "0x168c", "0xa199", 0, 0, "Atheros", "AR9287" ],
[ "0x168c", "0x0030", "0x168c", "0x3112", 0, 0, "Atheros", "AR9380" ],
[ "0x168c", "0x0030", "0x168c", "0x3114", 0, 0, "Atheros", "AR9390" ],
[ "0x168c", "0x0033", "0x168c", "0xa120", 0, 0, "Atheros", "AR9580" ],
[ "0x168c", "0x0033", "0x168c", "0xa136", 0, 0, "Atheros", "AR9580" ],
[ "0x168c", "0x0033", "0x168c", "0x3123", 0, 0, "Atheros", "AR9590" ],
[ "0x168c", "0x0033", "0x19b6", "0xd014", 0, 0, "MikroTik", "R11e-5HnD" ],
[ "0x168c", "0x0033", "0x19b6", "0xd057", 0, 0, "MikroTik", "R11e-5HnDr2" ],
[ "0x168c", "0x0033", "0x19b6", "0xd016", 0, 0, "MikroTik", "R11e-2HPnD" ],
[ "0x168c", "0x0034", "0x17aa", "0x3214", 0, 0, "Atheros", "AR9462" ],
[ "0x168c", "0x003c", "0x0000", "0x0000", 0, 0, "Qualcomm Atheros", "QCA9880" ],
[ "0x168c", "0x003c", "0x168c", "0x3223", 0, 0, "Qualcomm Atheros", "QCA9880" ],
[ "0x168c", "0x003c", "0x1a56", "0x1420", 0, 0, "Qualcomm Atheros", "QCA9862" ],
[ "0x168c", "0x003c", "0x19b6", "0xd03c", 0, 0, "Mikrotik", "R11e-5HacT" ],
[ "0x168c", "0x003c", "0x19b6", "0xd075", 0, 0, "Mikrotik", "R11e-5HacD" ],
[ "0x168c", "0x003e", "0x168c", "0x3361", 0, 0, "Qualcomm Atheros", "QCA6174" ],
[ "0x168c", "0x0046", "0x168c", "0xcafe", 0, 0, "Qualcomm Atheros", "QCA9984" ],
[ "0x168c", "0x0040", "0x168c", "0x0002", 0, 0, "Qualcomm Atheros", "QCA9990" ],
[ "0x168c", "0x0046", "0x0777", "0xe535", 0, 0, "Qualcomm Atheros", "QCA9994" ],
[ "0x168c", "0x0046", "0x0777", "0xe5a2", 0, 0, "Qualcomm Atheros", "QCA9994" ],
[ "0x168c", "0x0050", "0x0000", "0x0000", 0, 0, "Qualcomm Atheros", "QCA9887" ],
[ "0x168c", "0x0056", "0x0000", "0x0000", 0, 0, "Qualcomm Atheros", "QCA9886" ],
[ "0x17cb", "0x1104", "0x17cb", "0x1104", 0, 0, "Qualcomm Atheros", "QCN6024/9024/9074" ],
[ "0x1814", "0x3051", "0x1814", "0x0007", 0, 0, "Ralink", "Rt3051" ],
[ "0x1814", "0x3052", "0x1814", "0x0008", 0, 0, "Ralink", "Rt3052" ],
[ "0x1814", "0x3350", "0x1814", "0x000b", 0, 0, "Ralink", "Rt3350" ],
[ "0x1814", "0x3662", "0x1814", "0x000d", 0, 0, "Ralink", "Rt3662" ],
[ "0x11ab", "0x2a55", "0x11ab", "0x0000", 0, 0, "Marvell", "88W8864" ],
[ "0x02df", "0x9135", "0x0000", "0x0000", 0, 0, "Marvell", "88W8887" ],
[ "0x11ab", "0x2b40", "0x11ab", "0x0000", 0, 0, "Marvell", "88W8964" ],
[ "0x02df", "0x9141", "0x0000", "0x0000", 0, 0, "Marvell", "88W8997" ],
[ "0x14c3", "0x0608", "0x14c3", "0x0608", 0, 0, "AMD", "RZ608" ],
[ "0x14c3", "0x7603", "0x14c3", "0x7603", 0, 0, "MediaTek", "MT7603E" ],
[ "0x14c3", "0x7610", "0x14c3", "0x7610", 0, 0, "MediaTek", "MT7610E" ],
[ "0x14c3", "0x7612", "0x14c3", "0x7612", 0, 0, "MediaTek", "MT7612E" ],
[ "0x14c3", "0x7663", "0x14c3", "0x7663", 0, 0, "MediaTek", "MT7613BE" ],
[ "0x14c3", "0x7615", "0x7615", "0x14c3", 0, 0, "MediaTek", "MT7615E" ],
[ "0x14c3", "0x7628", "0x14c3", "0x0004", 0, 0, "MediaTek", "MT76x8" ],
[ "0x14c3", "0x7650", "0x14c3", "0x7650", 0, 0, "MediaTek", "MT7610E" ],
[ "0x14c3", "0x7662", "0x14c3", "0x7662", 0, 0, "MediaTek", "MT76x2E" ],
[ "0x14c3", "0x7915", "0x14c3", "0x7915", 0, 0, "MediaTek", "MT7915E" ],
[ "0x14c3", "0x7906", "0x14c3", "0x7906", 0, 0, "MediaTek", "MT7916AN" ],
[ "0x14c3", "0x7990", "0x14C3", "0x6639", 0, 0, "MediaTek", "MT7996E" ],
[ "0x14c3", "0x7992", "0x14C3", "0x7992", 0, 0, "MediaTek", "MT7992E" ],
[ "0x14e4", "0xaa52", "0x14e4", "0xaa52", 0, 0, "Broadcom", "BCM43602" ],
[ "0x02d0", "0xa9a6", "0x0000", "0x0000", 0, 0, "Cypress", "CYW43455" ],
[ "0x02d0", "0x4345", "0x0000", "0x0000", 0, 0, "Cypress", "CYW43455" ],
[ "0x1ae9", "0x0310", "0x1ae9", "0x0000", 0, 0, "Wilocity", "Wil6210" ],
[ "0x0000", "0x0000", "0x148f", "0x7601", 0, 0, "MediaTek", "MT7601U" ],
[ "0x0000", "0x0000", "0x0e8d", "0x7961", 0, 0, "MediaTek", "MT7921AU" ],
[ "0x0000", "0x0000", "0x0b05", "0x1833", 0, 0, "ASUS", "USB-AC54" ],
[ "0x0000", "0x0000", "0x0b05", "0x17eb", 0, 0, "ASUS", "USB-AC55" ],
[ "0x0000", "0x0000", "0x0b05", "0x180b", 0, 0, "ASUS", "USB-N53, B1" ],
[ "0x0000", "0x0000", "0x0e8d", "0x7612", 0, 0, "Aukey", "USBAC1200" ],
[ "0x0000", "0x0000", "0x057c", "0x8503", 0, 0, "AVM", "FRITZ!WLAN, AC860" ],
[ "0x0000", "0x0000", "0x7392", "0xb711", 0, 0, "Edimax", "EW-7722UAC" ],
[ "0x0000", "0x0000", "0x0e8d", "0x7632", 0, 0, "High, Cloud", "HC-M7662BU1" ],
[ "0x0000", "0x0000", "0x2c4e", "0x0103", 0, 0, "Mercury", "UD13" ],
[ "0x0000", "0x0000", "0x0846", "0x9053", 0, 0, "Netgear", "A6210" ],
[ "0x0000", "0x0000", "0x045e", "0x02e6", 0, 0, "Microsoft", "XBox, One, Wireless, Adapter" ],
[ "0x0000", "0x0000", "0x045e", "0x02fe", 0, 0, "Microsoft", "XBox, One, Wireless, Adapter" ],
[ "0x0000", "0x0000", "0x148f", "0x7610", 0, 0, "MediaTek", "MT7610U" ],
[ "0x0000", "0x0000", "0x13b1", "0x003e", 0, 0, "Linksys", "AE6000" ],
[ "0x0000", "0x0000", "0x0e8d", "0x7610", 0, 0, "Sabrent", "NTWLAC" ],
[ "0x0000", "0x0000", "0x7392", "0xa711", 0, 0, "Edimax", "7711MAC" ],
[ "0x0000", "0x0000", "0x148f", "0x761a", 0, 0, "TP-Link", "TL-WDN5200" ],
[ "0x0000", "0x0000", "0x0b05", "0x17d1", 0, 0, "ASUS", "USB-AC51" ],
[ "0x0000", "0x0000", "0x0b05", "0x17db", 0, 0, "ASUS", "USB-AC50" ],
[ "0x0000", "0x0000", "0x0df6", "0x0075", 0, 0, "Sitecom", "WLA-3100" ],
[ "0x0000", "0x0000", "0x2019", "0xab31", 0, 0, "Planex", "GW-450D" ],
[ "0x0000", "0x0000", "0x2001", "0x3d02", 0, 0, "D-Link", "DWA-171, rev, B1" ],
[ "0x0000", "0x0000", "0x0586", "0x3425", 0, 0, "Zyxel", "NWD6505" ],
[ "0x0000", "0x0000", "0x07b8", "0x7610", 0, 0, "AboCom", "AU7212" ],
[ "0x0000", "0x0000", "0x04bb", "0x0951", 0, 0, "I-O, DATA", "WN-AC433UK" ],
[ "0x0000", "0x0000", "0x057c", "0x8502", 0, 0, "AVM", "FRITZ!WLAN, AC430" ],
[ "0x0000", "0x0000", "0x293c", "0x5702", 0, 0, "Comcast", "Xfinity, KXW02AAA" ],
[ "0x0000", "0x0000", "0x20f4", "0x806b", 0, 0, "TRENDnet", "TEW-806UBH" ],
[ "0x0000", "0x0000", "0x7392", "0xc711", 0, 0, "Devolo", "WiFi, Stick, ac" ],
[ "0x0000", "0x0000", "0x0df6", "0x0079", 0, 0, "Sitecom", "WL-356" ],
[ "0x0000", "0x0000", "0x2357", "0x0123", 0, 0, "TP-Link", "T2UHP, US, v1" ],
[ "0x0000", "0x0000", "0x2357", "0x010b", 0, 0, "TP-Link", "T2UHP, UN, v1" ],
[ "0x0000", "0x0000", "0x2357", "0x0105", 0, 0, "TP-Link", "Archer, T1U" ],
[ "0x0000", "0x0000", "0x0e8d", "0x7630", 0, 0, "MediaTek", "MT7630U" ],
[ "0x0000", "0x0000", "0x0e8d", "0x7650", 0, 0, "MediaTek", "MT7650U" ],
[ "0x0000", "0x0000", "0x0e8d", "0x7663", 0, 0, "MediaTek", "MT7663U" ],
[ "0x0000", "0x0000", "0x043e", "0x310c", 0, 0, "LG", "LGSBWAC02" ],
[ "0x0000", "0x0000", "0x0bda", "0x8176", 0, 0, "Realtek", "RTL8188CU" ],
[ "0x0000", "0x0000", "0x0bda", "0xf179", 0, 0, "Realtek", "RTL8188FTV" ]
],
"compatible": {
"qca,ar9130-wifi": [ "Atheros", "AR9130" ],
"qca,ar9330-wifi": [ "Atheros", "AR9330" ],
"qca,ar9340-wifi": [ "Atheros", "AR9340" ],
"qca,qca9530-wifi": [ "Qualcomm Atheros", "QCA9530" ],
"qca,qca9550-wifi": [ "Qualcomm Atheros", "QCA9550" ],
"qca,qca9560-wifi": [ "Qualcomm Atheros", "QCA9560" ],
"qcom,ipq4019-wifi": [ "Qualcomm Atheros", "IPQ4019" ],
"qcom,ipq6018-wifi": [ "Qualcomm Atheros", "IPQ6018" ],
"qcom,ipq8074-wifi": [ "Qualcomm Atheros", "IPQ8074" ],
"mediatek,mt7622-wmac": [ "MediaTek", "MT7622" ],
"mediatek,mt7628-wmac": [ "MediaTek", "MT7628" ],
"mediatek,mt7981-wmac": [ "MediaTek", "MT7981" ],
"mediatek,mt7986-wmac": [ "MediaTek", "MT7986" ],
"ralink,rt2880-wmac": [ "Ralink", "Rt2880" ],
"ralink,rt3050-wmac": [ "Ralink", "Rt3050" ],
"ralink,rt3352-wmac": [ "Ralink", "Rt3352" ],
"ralink,rt3883-wmac": [ "Ralink", "Rt3883" ],
"ralink,rt5350-wmac": [ "Ralink", "Rt5350" ],
"ralink,rt7620-wmac": [ "MediaTek", "MT7620" ]
}
}

View File

@@ -1,6 +0,0 @@
#!/bin/sh
[ "${ACTION}" = "add" ] && {
/sbin/wifi config
ubus call network.wireless retry
}

View File

@@ -1,36 +0,0 @@
#!/bin/sh
# Restart ath12k radios that take long time to initialize on boot
[ "${ACTION}" = "add" ] || exit 0
[ $(grep -c DRIVER=ath12k_pci /sys/$DEVPATH/device/uevent) -gt 0 ] || exit 0
. /usr/share/libubox/jshn.sh
restart_radio() {
radio=$1
arg="{\"radio\": \"$radio\"}"
ubus call network reload
ubus call network.wireless down "$arg"
ubus call network.wireless up "$arg"
}
json_init
json_load "$(ubus -S call network.wireless status)"
json_get_keys radios
for radio in $radios; do
json_select $radio
json_get_vars up
json_get_vars retry_setup_failed
json_select config
json_get_vars path
json_select ..
if [ $up = 0 -a $retry_setup_failed = 1 ] &&
[ $(iwinfo nl80211 phyname "path=$path") = "$DEVICENAME" ]; then
restart_radio $radio
fi
json_select ..
done

View File

@@ -1,6 +0,0 @@
#!/bin/sh
[ "$ACTION" = "pressed" ] && exit 5
for script in /etc/rc.wps/*; do
[ -x "$script" ] || continue
"$script" && break
done

View File

@@ -1,10 +0,0 @@
#!/bin/sh
[ "$SEEN" -ge 3 ] && exit 1
wps_done=0
ubusobjs="$( ubus -S list hostapd.* )"
for ubusobj in $ubusobjs; do
ubus -S call $ubusobj wps_start && wps_done=1
done
[ $wps_done = 1 ]

View File

@@ -1,451 +0,0 @@
NETIFD_MAIN_DIR="${NETIFD_MAIN_DIR:-/lib/netifd}"
. /usr/share/libubox/jshn.sh
. $NETIFD_MAIN_DIR/utils.sh
CMD_UP=0
CMD_SET_DATA=1
CMD_PROCESS_ADD=2
CMD_PROCESS_KILL_ALL=3
CMD_SET_RETRY=4
add_driver() {
return
}
wireless_setup_vif_failed() {
local error="$1"
echo "Interface $_w_iface setup failed: $error"
}
wireless_setup_failed() {
local error="$1"
echo "Device setup failed: $error"
wireless_set_retry 0
}
prepare_key_wep() {
local key="$1"
local hex=1
echo -n "$key" | grep -qE "[^a-fA-F0-9]" && hex=0
[ "${#key}" -eq 10 -a $hex -eq 1 ] || \
[ "${#key}" -eq 26 -a $hex -eq 1 ] || {
[ "${key:0:2}" = "s:" ] && key="${key#s:}"
key="$(echo -n "$key" | hexdump -ve '1/1 "%02x" ""')"
}
echo "$key"
}
_wdev_prepare_channel() {
json_get_vars channel band hwmode htmode
auto_channel=0
enable_ht=0
hwmode="${hwmode##11}"
case "$channel" in
""|0|auto)
channel=0
auto_channel=1
;;
[0-9]*) ;;
*)
wireless_setup_failed "INVALID_CHANNEL"
;;
esac
case "$hwmode" in
a|b|g|ad) ;;
*)
if [ "$channel" -gt 14 ]; then
hwmode=a
else
hwmode=g
fi
;;
esac
case "$band" in
2g) hwmode=g;;
5g|6g) hwmode=a;;
60g) hwmode=ad;;
*)
case "$hwmode" in
*a) band=5g;;
*ad) band=60g;;
*b|*g) band=2g;;
esac
;;
esac
case "$htmode" in
HE*|EHT*) wpa3_cipher="GCMP-256 ";;
*) wpa3_cipher="";;
esac
}
_wdev_handler() {
json_load "$data"
json_select config
_wdev_prepare_channel
json_select ..
eval "drv_$1_$2 \"$interface\""
}
_wdev_msg_call() {
local old_cb
json_set_namespace wdev old_cb
"$@"
json_set_namespace $old_cb
}
_wdev_wrapper() {
while [ -n "$1" ]; do
eval "$1() { _wdev_msg_call _$1 \"\$@\"; }"
shift
done
}
_wdev_notify_init() {
local command="$1"; shift;
json_init
json_add_int "command" "$command"
json_add_string "device" "$__netifd_device"
while [ -n "$1" ]; do
local name="$1"; shift
local value="$1"; shift
json_add_string "$name" "$value"
done
json_add_object "data"
}
_wdev_notify() {
local options="$1"
json_close_object
ubus $options call network.wireless notify "$(json_dump)"
}
_wdev_add_variables() {
while [ -n "$1" ]; do
local var="${1%%=*}"
local val="$1"
shift
[[ "$var" = "$val" ]] && continue
val="${val#*=}"
json_add_string "$var" "$val"
done
}
_wireless_add_vif() {
local name="$1"; shift
local ifname="$1"; shift
_wdev_notify_init $CMD_SET_DATA "interface" "$name"
json_add_string "ifname" "$ifname"
_wdev_add_variables "$@"
_wdev_notify
}
_wireless_add_vlan() {
local name="$1"; shift
local ifname="$1"; shift
_wdev_notify_init $CMD_SET_DATA interface "$__cur_interface" "vlan" "$name"
json_add_string "ifname" "$ifname"
_wdev_add_variables "$@"
_wdev_notify
}
_wireless_set_up() {
_wdev_notify_init $CMD_UP
_wdev_notify
}
_wireless_set_data() {
_wdev_notify_init $CMD_SET_DATA
_wdev_add_variables "$@"
_wdev_notify
}
_wireless_add_process() {
_wdev_notify_init $CMD_PROCESS_ADD
local exe="$2"
[ -L "$exe" ] && exe="$(readlink -f "$exe")"
json_add_int pid "$1"
json_add_string exe "$exe"
[ -n "$3" ] && json_add_boolean required 1
[ -n "$4" ] && json_add_boolean keep 1
exe2="$(readlink -f /proc/$1/exe)"
[ "$exe" != "$exe2" ] && echo "WARNING (wireless_add_process): executable path $exe does not match process $1 path ($exe2)"
_wdev_notify
}
_wireless_process_kill_all() {
_wdev_notify_init $CMD_PROCESS_KILL_ALL
[ -n "$1" ] && json_add_int signal "$1"
_wdev_notify
}
_wireless_set_retry() {
_wdev_notify_init $CMD_SET_RETRY
json_add_int retry "$1"
_wdev_notify
}
_wdev_wrapper \
wireless_add_vif \
wireless_add_vlan \
wireless_set_up \
wireless_set_data \
wireless_add_process \
wireless_process_kill_all \
wireless_set_retry \
wireless_vif_parse_encryption() {
json_get_vars encryption rsn_override
set_default encryption none
set_default rsn_override 1
auth_mode_open=1
auth_mode_shared=0
auth_type=none
wpa_override_cipher=
rsn_override_pairwise=
if [ "$hwmode" = "ad" ]; then
wpa_cipher="GCMP"
else
wpa_cipher="CCMP"
case "$encryption" in
sae*|wpa3*|psk3*|owe)
if [ "$rsn_override" -gt 0 ]; then
wpa_override_cipher="${wpa3_cipher}$wpa_cipher"
else
wpa_cipher="${wpa3_cipher}$wpa_cipher"
fi
;;
esac
fi
case "$encryption" in
*tkip+aes|*tkip+ccmp|*aes+tkip|*ccmp+tkip) wpa_cipher="CCMP TKIP";;
*ccmp256) wpa_cipher="CCMP-256";;
*aes|*ccmp) wpa_cipher="CCMP";;
*tkip) wpa_cipher="TKIP";;
*gcmp256) wpa_cipher="GCMP-256";;
*gcmp) wpa_cipher="GCMP";;
wpa3-192*) wpa_cipher="GCMP-256";;
*) rsn_override_pairwise="$wpa_override_cipher";;
esac
# 802.11n requires CCMP for WPA
[ "$enable_ht:$wpa_cipher" = "1:TKIP" ] && wpa_cipher="CCMP TKIP"
# Examples:
# psk-mixed/tkip => WPA1+2 PSK, TKIP
# wpa-psk2/tkip+aes => WPA2 PSK, CCMP+TKIP
# wpa2/tkip+aes => WPA2 RADIUS, CCMP+TKIP
case "$encryption" in
wpa2*|wpa3*|*psk2*|psk3*|sae*|owe*)
wpa=2
;;
wpa*mixed*|*psk*mixed*)
wpa=3
;;
wpa*|*psk*)
wpa=1
;;
*)
wpa=0
wpa_cipher=
;;
esac
wpa_pairwise="$wpa_cipher"
case "$encryption" in
owe*)
auth_type=owe
;;
wpa3-192*)
auth_type=eap192
;;
wpa3-mixed*)
auth_type=eap-eap2
;;
wpa3*)
auth_type=eap2
;;
psk3-mixed*|sae-mixed*)
auth_type=psk-sae
;;
psk3*|sae*)
auth_type=sae
;;
*psk*)
auth_type=psk
;;
*wpa*|*8021x*)
auth_type=eap
;;
*wep*)
auth_type=wep
case "$encryption" in
*shared*)
auth_mode_open=0
auth_mode_shared=1
;;
*mixed*)
auth_mode_shared=1
;;
esac
;;
esac
}
_wireless_set_brsnoop_isolation() {
local multicast_to_unicast="$1"
local isolate
json_get_vars isolate proxy_arp
[ ${isolate:-0} -gt 0 -o -z "$network_bridge" ] && return
[ ${multicast_to_unicast:-1} -gt 0 -o ${proxy_arp:-0} -gt 0 ] && json_add_boolean isolate 1
}
for_each_interface() {
local _w_types="$1"; shift
local _w_ifaces _w_iface
local _w_type
local _w_found
local multicast_to_unicast
json_get_keys _w_ifaces interfaces
json_select interfaces
for _w_iface in $_w_ifaces; do
json_select "$_w_iface"
if [ -n "$_w_types" ]; then
json_get_var network_bridge bridge
json_get_var network_ifname bridge-ifname
json_get_var multicast_to_unicast multicast_to_unicast
json_select config
_wireless_set_brsnoop_isolation "$multicast_to_unicast"
json_get_var _w_type mode
json_select ..
_w_types=" $_w_types "
[[ "${_w_types%$_w_type*}" = "$_w_types" ]] && {
json_select ..
continue
}
fi
__cur_interface="$_w_iface"
"$@" "$_w_iface"
json_select ..
done
json_select ..
}
for_each_vlan() {
local _w_vlans _w_vlan
json_get_keys _w_vlans vlans
json_select vlans
for _w_vlan in $_w_vlans; do
json_select "$_w_vlan"
json_select config
"$@" "$_w_vlan"
json_select ..
json_select ..
done
json_select ..
}
for_each_station() {
local _w_stas _w_sta
json_get_keys _w_stas stas
json_select stas
for _w_sta in $_w_stas; do
json_select "$_w_sta"
json_select config
"$@" "$_w_sta"
json_select ..
json_select ..
done
json_select ..
}
_wdev_common_device_config() {
config_add_string channel hwmode band htmode noscan
}
_wdev_common_iface_config() {
config_add_string mode ssid encryption 'key:wpakey'
config_add_boolean bridge_isolate
config_add_array tags
}
_wdev_common_vlan_config() {
config_add_string name vid iface
config_add_boolean bridge_isolate
}
_wdev_common_station_config() {
config_add_string mac key vid iface
}
init_wireless_driver() {
name="$1"; shift
cmd="$1"; shift
case "$cmd" in
dump)
add_driver() {
eval "drv_$1_cleanup"
json_init
json_add_string name "$1"
json_add_array device
_wdev_common_device_config
eval "drv_$1_init_device_config"
json_close_array
json_add_array iface
_wdev_common_iface_config
eval "drv_$1_init_iface_config"
json_close_array
json_add_array vlan
_wdev_common_vlan_config
eval "drv_$1_init_vlan_config"
json_close_array
json_add_array station
_wdev_common_station_config
eval "drv_$1_init_station_config"
json_close_array
json_dump
}
;;
setup|teardown)
interface="$1"; shift
data="$1"; shift
export __netifd_device="$interface"
add_driver() {
[[ "$name" == "$1" ]] || return 0
_wdev_handler "$1" "$cmd"
}
;;
esac
}

View File

@@ -1,649 +0,0 @@
'use strict';
import * as ubus from "ubus";
import * as uloop from "uloop";
import { is_equal } from "./utils.uc";
import { access } from "fs";
const NOTIFY_CMD_UP = 0;
const NOTIFY_CMD_SET_DATA = 1;
const NOTIFY_CMD_PROCESS_ADD = 2;
const NOTIFY_CMD_SET_RETRY = 4;
const DEFAULT_RETRY = 3;
const DEFAULT_SCRIPT_TIMEOUT = 30 * 1000;
let wdev_cur;
let wdev_handler = {};
let wdev_script_task, wdev_script_timeout;
let handler_timer;
function wireless_config_done()
{
ubus.call({
object: "wpa_supplicant",
method: "mld_start",
return: "ignore",
data: { },
});
ubus.call({
object: "service",
method: "event",
return: "ignore",
data: {
type: "netifd.wireless.done",
data: {},
},
});
}
function delete_wdev(name)
{
delete netifd.wireless.devices[name];
gc();
}
function handle_link(dev, data, up)
{
let config = data.config;
let bridge_isolate;
let ap = false;
if (dev == data.ifname)
ap = data.type == "vlan" ||
(data.type == "vif" && config.mode == "ap");
let dev_data = {
external: 2,
check_vlan: false,
isolate: !!config.bridge_isolate,
wireless: true,
wireless_ap: ap,
};
if (ap && config.multicast_to_unicast != null)
dev_data.multicast_to_unicast = config.multicast_to_unicast;
if (data.type == "vif" && config.mode == "ap") {
dev_data.wireless_proxyarp = !!config.proxy_arp;
dev_data.wireless_isolate = !!config.isolate;
}
if (up)
netifd.device_set(dev, dev_data);
for (let net in config.network)
netifd.interface_handle_link({
name: net,
ifname: dev,
vlan: config.network_vlan,
link_ext: true,
up,
});
}
function wdev_config_init(wdev)
{
let data = wdev.data;
let config = data.config;
let interfaces = {};
let vif_idx = 0;
for (let vif in data.vif) {
let vlan_idx = 0, sta_idx = 0;
let vlans = {}, stas = {};
if (wdev.disabled_vifs[vif.name])
continue;
for (let vlan in vif.vlan) {
let vlan_name = sprintf("%02d", ++vlan_idx);
let cur_vlan = vlans[vlan_name] = {
name: vlan.name,
config: vlan.config,
};
if (wdev.disabled_vifs[vif.name])
continue;
for (let net in vlan.config.network)
if (netifd.interface_get_bridge(net, cur_vlan))
break;
}
for (let sta in vif.sta) {
let sta_name = sprintf("%02d", ++sta_idx);
stas[sta_name] = {
name: sta.name,
config: sta.config,
};
}
let vif_name = sprintf("%02d", ++vif_idx);
let iface = interfaces[vif_name] = {
name: vif.name,
config: vif.config,
vlans, stas,
};
for (let net in vif.config.network)
if (netifd.interface_get_bridge(net, iface))
break;
}
wdev.handler_config = {
config,
interfaces,
};
let prev = wdev.handler_data;
wdev.handler_data = {};
if (prev && prev[wdev.name])
wdev.handler_data[wdev.name] = prev[wdev.name];
}
function wdev_setup_cb(wdev)
{
if (wdev.state != "setup")
return;
if (wdev.retry > 0)
wdev.retry--;
else
wdev.retry_setup_failed = true;
wdev.teardown();
}
function wdev_teardown_cb(wdev)
{
for (let section, data in wdev.handler_data) {
if (data.ifname)
handle_link(data.ifname, data, false);
}
wdev.handler_data = {};
wdev.state = "down";
if (wdev.delete) {
delete_wdev(wdev.data.name);
return;
}
wdev.setup();
}
function run_handler_cb(wdev, cb)
{
if (wdev != wdev_cur.wdev)
return;
wdev.dbg("complete " + wdev_cur.op);
if (wdev_script_timeout)
wdev_script_timeout.cancel();
wdev_script_timeout = null;
wdev_script_task = null;
wdev_cur = null;
handler_timer.set(1);
cb(wdev);
}
function run_handler_timeout(wdev, cb)
{
wdev_script_task.cancel();
run_handler_cb(wdev, cb);
}
function handler_sort_fn(a, b)
{
return wdev_handler[a].time - wdev_handler[b].time
}
function __run_next_handler_name()
{
return sort(keys(wdev_handler), handler_sort_fn)[0];
}
function __run_next_handler()
{
let name = __run_next_handler_name();
if (!name)
return;
wdev_cur = wdev_handler[name];
delete wdev_handler[name];
let wdev = wdev_cur.wdev;
let op = wdev_cur.op;
let cb = wdev_cur.cb;
wdev.dbg("run " + op);
wdev.handler_config.data = wdev.handler_data[wdev.name] ?? {};
wdev_script_task = netifd.process({
cb: () => run_handler_cb(wdev, cb),
dir: netifd.wireless.path,
argv: [ './' + wdev.script, wdev.data.config.type, op, wdev.name, "" + wdev.handler_config ],
log_prefix: wdev.name,
});
if (!wdev_script_task)
return run_handler_cb(wdev, cb);
wdev_script_timeout = uloop.timer(DEFAULT_SCRIPT_TIMEOUT,
() => run_handler_timeout(wdev, cb)
);
}
function run_next_handler()
{
while (!wdev_cur && length(wdev_handler) > 0)
__run_next_handler();
if (!wdev_cur && !length(wdev_handler))
wireless_config_done();
}
function run_handler(wdev, op, cb)
{
wdev.dbg("queue " + op);
wdev_handler[wdev.name] = {
op, wdev, cb,
time: time()
};
run_next_handler();
}
function wdev_proc_reset(wdev)
{
if (wdev.proc_timer) {
wdev.proc_timer.cancel();
delete wdev.proc_timer;
}
wdev.procs = [];
}
function __wdev_proc_check(wdev, proc)
{
if (netifd.process_check(proc.pid, proc.exe))
return;
wdev.dbg(`process ${proc.exe}(${proc.pid}) no longer active`);
wdev.teardown();
return true;
}
function wdev_proc_check(wdev)
{
for (let proc in wdev.procs)
if (__wdev_proc_check(wdev, proc))
break;
}
function wdev_proc_add(wdev, data)
{
if (!data.pid || !data.exe)
return;
push(wdev.procs, data);
if (!wdev.proc_timer)
wdev.proc_timer = uloop.interval(1000, () => wdev_proc_check(wdev));
}
function setup()
{
if (this.state != "up" && this.state != "down")
return;
this.dbg("setup, state=" + this.state);
if (!this.autostart || this.retry_setup_failed)
return;
wdev_proc_reset(this);
delete this.config_change;
this.state = "setup";
run_handler(this, "setup", wdev_setup_cb);
}
function teardown()
{
delete this.cancel_setup;
this.dbg("teardown, state=" + this.state);
if (this.state == "teardown" || this.state == "down")
return;
wdev_proc_reset(this);
this.state = "teardown";
run_handler(this, "teardown", wdev_teardown_cb);
}
function wdev_update_disabled_vifs(wdev)
{
let cache = wdev.ifindex_cache;
let prev_disabled = wdev.disabled_vifs;
let disabled = wdev.disabled_vifs = {};
let changed;
let vifs = [];
for (let vif in wdev.data.vif)
push(vifs, vif, ...vif.vlan);
for (let vif in vifs) {
let enabled, ifindex;
for (let net in vif.config.network) {
let state = netifd.interface_get_enabled(net);
if (!state)
continue;
if (state.enabled)
enabled = true;
else if (enabled == null)
enabled = false;
if (state.ifindex)
ifindex = state.ifindex;
}
let name = vif.name;
if (enabled == false)
disabled[wdev] = true;
else if (ifindex != cache[name])
changed = true;
if (ifindex)
cache[name] = ifindex;
else
delete cache[name];
}
if (changed || !is_equal(prev_disabled, disabled))
wdev.config_change = true;
return wdev.config_change;
}
function wdev_reset(wdev)
{
wdev.retry = DEFAULT_RETRY;
delete wdev.retry_setup_failed;
}
function update(data)
{
if (is_equal(this.data, data))
return;
if (data) {
this.data = data;
this.ifindex_cache = {};
delete this.retry_setup_failed;
delete this.delete;
}
wdev_reset(this);
this.config_change = true;
this.check();
}
function start()
{
if (this.delete)
return;
this.dbg("start, state=" + this.state);
this.autostart = true;
wdev_reset(this);
if (this.state != "down")
return;
if (wdev_update_disabled_vifs(this))
wdev_config_init(this);
this.setup();
}
function retry_setup()
{
if (this.delete)
return;
if (this.state != "down" || !this.autostart)
return;
this.start();
}
function stop()
{
this.dbg("stop, state=" + this.state);
this.autostart = false;
switch (this.state) {
case "setup":
this.cancel_setup = true;
break;
case "up":
this.teardown();
break;
}
}
function check()
{
if (!wdev_update_disabled_vifs(this))
return;
wdev_config_init(this);
this.setup();
}
function wdev_mark_up(wdev)
{
wdev.dbg("mark up, state=" + wdev.state);
if (wdev.state != "setup")
return;
if (wdev.config_change) {
wdev.setup();
return;
}
for (let section, data in wdev.handler_data) {
if (data.ifname)
handle_link(data.ifname, data, true);
}
wdev.state = "up";
return 0;
}
function wdev_set_data(wdev, vif, vlan, data)
{
let config = wdev.handler_config;
let cur = wdev;
let cur_type = "device";
if (!config)
return ubus.STATUS_INVALID_ARGUMENT;
if (vif) {
cur = vif = config.interfaces[vif];
if (!vif)
return ubus.STATUS_NOT_FOUND;
cur_type = "vif";
}
if (vlan) {
if (!vif)
return ubus.STATUS_INVALID_ARGUMENT;
cur = vlan = vif.vlans[vlan];
if (!vlan)
return ubus.STATUS_NOT_FOUND;
cur_type = "vlan";
}
wdev.handler_data[cur.name] = {
...cur,
...data,
type: cur_type,
config: cur.config,
};
return 0;
}
function notify(req)
{
let vif = req.args.interface;
let vlan = req.args.vlan;
let data = req.args.data;
switch (req.args.command) {
case NOTIFY_CMD_UP:
if (vif || vlan || this.state != "setup")
return ubus.STATUS_INVALID_ARGUMENT;
return wdev_mark_up(this);
case NOTIFY_CMD_SET_DATA:
return wdev_set_data(this, vif, vlan, data);
case NOTIFY_CMD_PROCESS_ADD:
if (this.state != "setup" && this.state != "up")
return 0;
wdev_proc_add(this, data);
return 0;
case NOTIFY_CMD_SET_RETRY:
if (data.retry != null)
this.retry = data.retry;
else
this.retry = DEFAULT_RETRY;
return 0;
default:
return ubus.STATUS_INVALID_ARGUMENT;
}
}
function hotplug(name, add)
{
let dev = name;
let m = match(name, /(.+)\.sta.+/);
if (m)
name = m[1];
for (let section, data in this.handler_data) {
if (data.ifname != name ||
data.type != "vif" && data.type != "vlan")
continue;
handle_link(dev, data, add);
}
}
function get_status_data(wdev, vif)
{
let hdata = wdev.handler_data[vif.name];
let data = {
section: vif.name,
config: vif.config
};
if (hdata && hdata.ifname)
data.ifname = hdata.ifname;
return data;
}
function get_status_vlans(wdev, vif)
{
let vlans = [];
for (let vlan in vif.vlan)
push(vlans, get_status_data(wdev, vlan));
return vlans;
}
function get_status_stations(wdev, vif)
{
let vlans = [];
for (let vlan in vif.sta)
push(vlans, get_status_data(wdev, vlan));
return vlans;
}
function status()
{
let interfaces = [];
for (let vif in this.data.vif) {
let vlans = get_status_vlans(this, vif);
let stations = get_status_stations(this, vif);
let data = get_status_data(this, vif);
push(interfaces, {
...data,
vlans, stations
});
}
return {
up: this.state == "up",
pending: this.state == "setup" || this.state == "teardown",
autostart: this.autostart,
disabled: !!this.data.config.disabled,
retry_setup_failed: !!this.retry_setup_failed,
config: this.data.config,
interfaces
};
}
function destroy()
{
this.dbg("destroy");
this.autostart = false;
this.delete = true;
if (this.state != "down") {
this.stop();
return;
}
delete_wdev(this.data.name);
}
function dbg(msg)
{
netifd.log(netifd.L_DEBUG, `wireless: ${this.name}: ${msg}\n`);
}
const wdev_proto = {
update,
destroy,
retry_setup,
start,
stop,
setup,
status,
teardown,
check,
notify,
hotplug,
dbg,
};
export function new(data, script, driver)
{
let wdev = {
name: data.name,
script, data,
procs: [],
vifs: {},
disabled_vifs: {},
ifindex_cache: {},
autostart: true,
state: "down",
};
wdev_update_disabled_vifs(wdev);
wdev_config_init(wdev);
handler_timer = uloop.timer(1, run_next_handler);
return proto(wdev, wdev_proto);
};

View File

@@ -1,550 +0,0 @@
'use strict';
import * as ubus from "ubus";
import { realpath } from "fs";
import {
handler_load, handler_attributes,
parse_attribute_list, parse_bool, parse_array,
TYPE_ARRAY, TYPE_STRING, TYPE_INT, TYPE_BOOL
} from "./utils.uc";
import { find_phy } from "wifi.utils";
import * as wdev from "./wireless-device.uc";
let wireless = netifd.wireless = {
handlers: {},
devices: {},
mlo: {},
path: realpath(netifd.main_path + "/wireless"),
};
function wpad_update_mlo(service, mode)
{
let config = {};
for (let ifname, data in wireless.mlo) {
if (data.mode != mode)
continue;
data.phy = find_phy(data.radio_config[0], true);
if (!data.phy)
continue;
config[ifname] = data;
}
ubus.call({
object: service,
method: "mld_set",
return: "ignore",
data: { config },
});
}
function hostapd_update_mlo()
{
wpad_update_mlo("hostapd", "ap");
}
function supplicant_update_mlo()
{
wpad_update_mlo("wpa_supplicant", "sta");
}
function update_config(new_devices, mlo_vifs)
{
wireless.mlo = mlo_vifs;
hostapd_update_mlo();
supplicant_update_mlo();
for (let name, dev in wireless.devices)
if (!new_devices[name])
dev.destroy();
for (let name, dev in new_devices) {
let cur_dev = wireless.devices[name];
if (cur_dev) {
cur_dev.update(dev);
continue;
}
let handler = wireless.handlers[dev.config.type];
cur_dev = wdev.new(dev, handler.script);
if (!cur_dev)
continue;
wireless.devices[name] = cur_dev;
}
}
function config_init(uci)
{
let config = uci.get_all("wireless");
let handlers = {};
let devices = {};
let vifs = {};
let mlo_vifs = {};
let sections = {
device: {},
iface: {},
vlan: {},
station: {},
};
let radio_idx = {};
let vif_idx = {};
for (let name, data in config) {
let type = data[".type"];
if (parse_bool(data.disabled) && type != "wifi-device")
continue;
if (substr(type, 0, 5) != "wifi-")
continue;
let list = sections[substr(type, 5)];
if (list)
list[name] = data;
}
for (let name, data in sections.device) {
if (!data.type)
continue;
let handler = wireless.handlers[data.type];
if (!handler)
continue;
if (data.radio != null)
radio_idx[name] = +data.radio;
let config = parse_attribute_list(data, handler.device);
devices[name] = {
name,
config,
vif: [],
};
handlers[name] = handler;
}
for (let name, data in sections.iface) {
let dev_names = parse_array(data.device);
let mlo_vif = parse_bool(data.mlo);
let radios = map(dev_names, (v) => radio_idx[v]);
radios = filter(radios, (v) => v != null);
let radio_config = map(dev_names, (v) => devices[v].config);
let ifname;
for (let dev_name in dev_names) {
let dev = devices[dev_name];
if (!dev || dev.config.disabled)
continue;
let handler = handlers[dev_name];
if (!handler)
continue;
let config = parse_attribute_list(data, handler.iface);
config.radios = radios;
if (mlo_vif && dev_name == dev_names[0]) {
let mlo_config = { ...config };
mlo_config.radio_config = radio_config;
ifname = config.ifname;
if (!ifname) {
let idx = vif_idx[config.mode] ?? 0;
vif_idx[config.mode] = idx + 1;
ifname = config.mode + "-mld" + idx;
}
mlo_vifs[ifname] = mlo_config;
}
if (ifname)
config.ifname = ifname;
if (dev_name != dev_names[0])
delete config.macaddr;
if (config.radio_macaddr) {
let idx = index(dev_names, dev_name);
let macaddr = idx >= 0 ? config.radio_macaddr[idx] : null;
if (macaddr)
config.macaddr = macaddr;
}
let vif = {
name, config,
device: dev_name,
vlan: [],
sta: [],
};
push(dev.vif, vif);
vifs[name] ??= [];
push(vifs[name], vif);
}
}
for (let name, data in sections.vlan) {
for (let iface, iface_vifs in vifs) {
if (data.iface && data.iface != iface)
continue;
for (let vif in iface_vifs) {
let dev = devices[vif.device];
let handler = handlers[vif.device];
if (!dev || !handler)
continue;
let config = parse_attribute_list(data, handler.vlan);
let vlan = {
name,
config
};
push(vif.vlan, vlan);
}
}
}
for (let name, data in sections.station) {
if (!data.iface || !vifs[data.iface])
continue;
for (let vif in vifs[data.iface]) {
let dev = devices[vif.device];
let handler = handlers[vif.device];
if (!dev || !handler)
continue;
let config = parse_attribute_list(data, handler.station);
let sta = {
name,
config
};
push(vif.sta, sta);
}
}
let udata = ubus.call({
object: "service",
method: "get_data",
data: {
type: "wifi-device"
},
});
for (let svcname, svc in udata) {
for (let insname, ins in svc) {
for (let typename, data in ins) {
for (let radio, config in data) {
if (type(config) != "object")
continue;
let dev = devices[radio];
if (dev) {
dev.config = { ...dev.config, ...config };
continue;
}
let handler = wireless.handlers[config.type];
if (!handler)
continue;
dev = devices[radio] = {
name,
config,
vif: [],
};
handlers[radio] = handler;
}
}
}
}
udata = ubus.call({
object: "service",
method: "get_data",
data: {
type: "wifi-iface"
},
});
for (let svcname, svc in udata) {
for (let insname, ins in svc) {
for (let typename, data in ins) {
for (let radio, vifs in data) {
if (type(vifs) != "object")
continue;
for (let name, vif in vifs) {
let devs = vif.device;
if (type(devs) != "array")
devs = [ devs ];
let config = vif.config;
if (!config)
continue;
for (let device in devs) {
let dev = devices[device];
if (!dev)
continue;
let vif_data = {
name, device, config,
vlan: [],
sta: []
};
if (vif.vlans)
vif_data.vlans = vif.vlans;
if (vif.stations)
vif_data.sta = vif.stations;
vifs[name] ??= [];
push(vifs[name], vif_data);
push(dev.vif, vif_data);
}
}
}
}
}
}
update_config(devices, mlo_vifs);
}
function config_start()
{
for (let name, dev in wireless.devices)
if (dev.autostart)
dev.start();
}
function check_interfaces()
{
for (let name, dev in wireless.devices)
if (dev.autostart)
dev.check();
}
function hotplug(ifname, add)
{
for (let name, dev in wireless.devices)
if (dev.autostart)
dev.hotplug(ifname, add);
}
const network_config_attr = {
network: TYPE_ARRAY,
network_vlan: TYPE_ARRAY,
bridge_isolate: TYPE_BOOL,
isolate: TYPE_BOOL,
proxy_arp: TYPE_BOOL,
multicast_to_unicast: TYPE_BOOL,
};
const default_config_attr = {
device: {
disabled: TYPE_BOOL,
type: TYPE_STRING,
},
iface: {
...network_config_attr,
device: TYPE_STRING,
mode: TYPE_STRING,
radio_macaddr: TYPE_ARRAY,
},
station: {
iface: TYPE_STRING,
mac: TYPE_STRING,
key: TYPE_STRING,
vid: TYPE_STRING,
},
vlan: {
...network_config_attr,
iface: TYPE_STRING,
name: TYPE_STRING,
vid: TYPE_STRING,
},
};
const wdev_args = {
device: ""
};
function wdev_call(req, cb)
{
let dev = req.args.device;
if (dev) {
dev = wireless.devices[dev];
if (!dev)
return ubus.STATUS_NOT_FOUND;
return cb(dev);
}
for (let name, dev in wireless.devices)
cb(dev);
return 0;
}
function attr_validate(attr_type, validate)
{
if (validate)
return validate;
switch (attr_type) {
case TYPE_STRING:
return "string";
case TYPE_ARRAY:
return "list(string)";
case TYPE_INT:
return "uinteger";
case TYPE_BOOL:
return "bool";
}
}
function get_validate_info(ret, handler)
{
for (let kind in default_config_attr) {
let cur = ret[kind == "iface" ? "interface" : kind] = {};
let validate = handler[kind + "_validate"];
for (let attr, attr_type in handler[kind]) {
let val = attr_validate(attr_type, validate[attr]);
if (val != null)
cur[attr] = val;
}
}
return ret;
}
const ubus_obj = {
up: {
args: wdev_args,
call: function(req) {
hostapd_update_mlo();
return wdev_call(req, (dev) => {
dev.start();
return 0;
});
}
},
down: {
args: wdev_args,
call: function(req) {
return wdev_call(req, (dev) => {
dev.stop();
return 0;
});
}
},
retry: {
args: wdev_args,
call: function(req) {
hostapd_update_mlo();
return wdev_call(req, (dev) => {
dev.retry_setup();
return 0;
});
}
},
reconf: {
args: wdev_args,
call: function(req) {
hostapd_update_mlo();
return wdev_call(req, (dev) => {
dev.update();
return 0;
});
}
},
status: {
args: wdev_args,
call: function(req) {
let ret = {};
let err = wdev_call(req, (dev) => {
ret[dev.data.name] = dev.status();
return 0;
});
if (err != 0)
return err;
return ret;
}
},
notify: {
args: {
...wdev_args,
command: 0,
interface: "",
vlan: "",
data: {},
},
call: function(req) {
let dev = req.args.device;
if (!dev)
return ubus.STATUS_INVALID_ARGUMENT;
dev = wireless.devices[dev];
if (!dev)
return ubus.STATUS_NOT_FOUND;
return dev.notify(req);
}
},
get_validate: {
args: wdev_args,
call: function(req) {
let ret = {};
let err = wdev_call(req, (dev) => {
let dev_type = dev.data.config.type;
let cur = ret[dev.data.name] = {};
get_validate_info(cur, wireless.handlers[dev_type]);
return 0;
});
if (err != 0)
return err;
return ret;
}
},
};
handler_load(wireless.path, (script, data) => {
if (!data.name)
return;
let handler = wireless.handlers[data.name] = {
script,
};
for (let kind, attr in default_config_attr) {
let validate = handler[kind + "_validate"] = {};
handler[kind] = handler_attributes(data[kind], attr, validate);
}
});
wireless.obj = ubus.publish("network.wireless", ubus_obj);
wireless.listener = ubus.listener("ubus.object.add", (event, msg) => {
if (msg.path == "hostapd")
hostapd_update_mlo();
else if (msg.path == "wpa_supplicant")
supplicant_update_mlo();
});
return {
hotplug,
config_init,
config_start,
check_interfaces,
};

View File

@@ -1,118 +0,0 @@
#!/usr/bin/env ucode
import { readfile } from "fs";
import * as uci from 'uci';
const bands_order = [ "6G", "5G", "2G" ];
const htmode_order = [ "EHT", "HE", "VHT", "HT" ];
let board = json(readfile("/etc/board.json"));
if (!board.wlan)
exit(0);
let idx = 0;
let commit;
let config = uci.cursor().get_all("wireless") ?? {};
function radio_exists(path, macaddr, phy, radio) {
for (let name, s in config) {
if (s[".type"] != "wifi-device")
continue;
if (radio != null && int(s.radio) != radio)
continue;
if (s.macaddr & lc(s.macaddr) == lc(macaddr))
return true;
if (s.phy == phy)
return true;
if (!s.path || !path)
continue;
if (substr(s.path, -length(path)) == path)
return true;
}
}
for (let phy_name, phy in board.wlan) {
let info = phy.info;
if (!info || !length(info.bands))
continue;
let radios = length(info.radios) > 0 ? info.radios : [{ bands: info.bands }];
for (let radio in radios) {
while (config[`radio${idx}`])
idx++;
let name = "radio" + idx;
let s = "wireless." + name;
let si = "wireless.default_" + name;
let band_name = filter(bands_order, (b) => radio.bands[b])[0];
if (!band_name)
continue;
let band = info.bands[band_name];
let rband = radio.bands[band_name];
let channel = rband.default_channel ?? "auto";
let width = band.max_width;
if (band_name == "2G")
width = 20;
else if (width > 80)
width = 80;
let htmode = filter(htmode_order, (m) => band[lc(m)])[0];
if (htmode)
htmode += width;
else
htmode = "NOHT";
if (!phy.path)
continue;
let macaddr = trim(readfile(`/sys/class/ieee80211/${phy_name}/macaddress`));
if (radio_exists(phy.path, macaddr, phy_name, radio.index))
continue;
let id = `phy='${phy_name}'`;
if (match(phy_name, /^phy[0-9]/))
id = `path='${phy.path}'`;
band_name = lc(band_name);
let country, defaults, num_global_macaddr;
if (board.wlan.defaults) {
defaults = board.wlan.defaults.ssids?.[band_name]?.ssid ? board.wlan.defaults.ssids?.[band_name] : board.wlan.defaults.ssids?.all;
country = board.wlan.defaults.country;
if (!country && band_name != '2g')
defaults = null;
num_global_macaddr = board.wlan.defaults.ssids?.[band_name]?.mac_count;
}
if (length(info.radios) > 0)
id += `\nset ${s}.radio='${radio.index}'`;
print(`set ${s}=wifi-device
set ${s}.type='mac80211'
set ${s}.${id}
set ${s}.band='${band_name}'
set ${s}.channel='${channel}'
set ${s}.htmode='${htmode}'
set ${s}.country='${country || ''}'
set ${s}.num_global_macaddr='${num_global_macaddr || ''}'
set ${s}.disabled='${defaults ? 1 : 0}'
set ${si}=wifi-iface
set ${si}.device='${name}'
set ${si}.network='lan'
set ${si}.mode='ap'
set ${si}.ssid='${defaults?.ssid || "LEDE"}'
set ${si}.encryption='${defaults?.encryption || "none"}'
set ${si}.key='${defaults?.key || ""}'
`);
config[name] = {};
commit = true;
}
}
if (commit)
print("commit wireless\n");

View File

@@ -1,94 +0,0 @@
#!/bin/sh
# Copyright (C) 2006 OpenWrt.org
. /lib/functions.sh
. /usr/share/libubox/jshn.sh
usage() {
cat <<EOF
Usage: $0 [config|up|down|reconf|reload|status|isup]
enables (default), disables or configures devices not yet configured.
EOF
exit 1
}
ubus_wifi_cmd() {
local cmd="$1"
local dev="$2"
json_init
[ -n "$dev" ] && json_add_string device "$dev"
ubus call network.wireless "$cmd" "$(json_dump)"
}
wifi_isup() {
local dev="$1"
json_load "$(ubus_wifi_cmd "status" "$dev")"
json_get_keys devices
for device in $devices; do
json_select "$device"
json_get_var up up
[ $up -eq 0 ] && return 1
json_select ..
done
return 0
}
wifi_updown() {
cmd=down
[ enable = "$1" ] && {
ubus_wifi_cmd "$cmd" "$2"
ubus call network reload
cmd=up
}
[ reconf = "$1" ] && {
ubus call network reload
cmd=reconf
}
ubus_wifi_cmd "$cmd" "$2"
}
wifi_reload() {
ubus call network reload
}
wifi_detect_notice() {
>&2 echo "WARNING: Wifi detect is deprecated. Use wifi config instead"
>&2 echo "For more information, see commit 5f8f8a366136a07df661e31decce2458357c167a"
exit 1
}
wifi_config() {
[ -e /tmp/.config_pending ] && return
ucode /usr/share/hostap/wifi-detect.uc
[ ! -f /etc/config/wireless ] && touch /etc/config/wireless
ucode /lib/wifi/mac80211.uc | uci -q batch
for driver in $DRIVERS; do (
if eval "type detect_$driver" 2>/dev/null >/dev/null; then
eval "detect_$driver" || echo "$driver: Detect failed" >&2
else
echo "$driver: Hardware detection not supported" >&2
fi
); done
}
DEVICES=
DRIVERS=
include /lib/wifi
case "$1" in
down) wifi_updown "disable" "$2";;
detect) wifi_detect_notice ;;
config) wifi_config ;;
status) ubus_wifi_cmd "status" "$2";;
isup) wifi_isup "$2"; exit $?;;
reload) wifi_reload "$2";;
--help|help) usage;;
reconf) wifi_updown "reconf" "$2";;
''|up) wifi_updown "enable" "$2";;
*) usage; exit 1;;
esac

View File

@@ -1,423 +0,0 @@
import * as nl80211 from "nl80211";
import * as rtnl from "rtnl";
import { readfile, glob, basename, readlink, open } from "fs";
const iftypes = {
ap: nl80211.const.NL80211_IFTYPE_AP,
mesh: nl80211.const.NL80211_IFTYPE_MESH_POINT,
sta: nl80211.const.NL80211_IFTYPE_STATION,
adhoc: nl80211.const.NL80211_IFTYPE_ADHOC,
monitor: nl80211.const.NL80211_IFTYPE_MONITOR,
};
const mesh_params = {
mesh_retry_timeout: "retry_timeout",
mesh_confirm_timeout: "confirm_timeout",
mesh_holding_timeout: "holding_timeout",
mesh_max_peer_links: "max_peer_links",
mesh_max_retries: "max_retries",
mesh_ttl: "ttl",
mesh_element_ttl: "element_ttl",
mesh_auto_open_plinks: "auto_open_plinks",
mesh_hwmp_max_preq_retries: "hwmp_max_preq_retries",
mesh_path_refresh_time: "path_refresh_time",
mesh_min_discovery_timeout: "min_discovery_timeout",
mesh_hwmp_active_path_timeout: "hwmp_active_path_timeout",
mesh_hwmp_preq_min_interval: "hwmp_preq_min_interval",
mesh_hwmp_net_diameter_traversal_time: "hwmp_net_diam_trvs_time",
mesh_hwmp_rootmode: "hwmp_rootmode",
mesh_hwmp_rann_interval: "hwmp_rann_interval",
mesh_gate_announcements: "gate_announcements",
mesh_sync_offset_max_neighor: "sync_offset_max_neighbor",
mesh_rssi_threshold: "rssi_threshold",
mesh_hwmp_active_path_to_root_timeout: "hwmp_path_to_root_timeout",
mesh_hwmp_root_interval: "hwmp_root_interval",
mesh_hwmp_confirmation_interval: "hwmp_confirmation_interval",
mesh_awake_window: "awake_window",
mesh_plink_timeout: "plink_timeout",
mesh_fwding: "forwarding",
mesh_power_mode: "power_mode",
mesh_nolearn: "nolearn"
};
function wdev_remove(name)
{
nl80211.request(nl80211.const.NL80211_CMD_DEL_INTERFACE, 0, { dev: name });
}
function __phy_is_fullmac(phyidx)
{
let data = nl80211.request(nl80211.const.NL80211_CMD_GET_WIPHY, 0, { wiphy: phyidx });
return !data.software_iftypes.monitor;
}
function phy_is_fullmac(phy)
{
let phyidx = int(trim(readfile(`/sys/class/ieee80211/${phy}/index`)));
return __phy_is_fullmac(phyidx);
}
function find_reusable_wdev(phyidx)
{
if (!__phy_is_fullmac(phyidx))
return null;
let data = nl80211.request(
nl80211.const.NL80211_CMD_GET_INTERFACE,
nl80211.const.NLM_F_DUMP,
{ wiphy: phyidx });
for (let res in data)
if (trim(readfile(`/sys/class/net/${res.ifname}/operstate`)) == "down")
return res.ifname;
return null;
}
function wdev_set_radio_mask(name, mask)
{
nl80211.request(nl80211.const.NL80211_CMD_SET_INTERFACE, 0, {
dev: name,
vif_radio_mask: mask
});
}
function wdev_create(phy, name, data)
{
let phyidx = int(readfile(`/sys/class/ieee80211/${phy}/index`));
wdev_remove(name);
if (!iftypes[data.mode])
return `Invalid mode: ${data.mode}`;
let req = {
wiphy: phyidx,
ifname: name,
iftype: iftypes[data.mode],
};
if (data["4addr"])
req["4addr"] = data["4addr"];
if (data.macaddr)
req.mac = data.macaddr;
if (data.radio_mask > 0)
req.vif_radio_mask = data.radio_mask;
else if (data.radio != null && data.radio >= 0)
req.vif_radio_mask = 1 << data.radio;
nl80211.error();
let reuse_ifname = find_reusable_wdev(phyidx);
if (reuse_ifname &&
(reuse_ifname == name ||
rtnl.request(rtnl.const.RTM_SETLINK, 0, { dev: reuse_ifname, ifname: name}) != false)) {
req.dev = req.ifname;
delete req.ifname;
nl80211.request(nl80211.const.NL80211_CMD_SET_INTERFACE, 0, req);
} else {
nl80211.request(
nl80211.const.NL80211_CMD_NEW_INTERFACE,
nl80211.const.NLM_F_CREATE,
req);
}
let error = nl80211.error();
if (error)
return error;
if (data.powersave != null) {
nl80211.request(nl80211.const.NL80211_CMD_SET_POWER_SAVE, 0,
{ dev: name, ps_state: data.powersave ? 1 : 0});
}
return null;
}
function wdev_set_mesh_params(name, data)
{
let mesh_cfg = {};
for (let key in mesh_params) {
let val = data[key];
if (val == null)
continue;
mesh_cfg[mesh_params[key]] = int(val);
}
if (!length(mesh_cfg))
return null;
nl80211.request(nl80211.const.NL80211_CMD_SET_MESH_CONFIG, 0,
{ dev: name, mesh_params: mesh_cfg });
return nl80211.error();
}
function wdev_set_up(name, up)
{
rtnl.request(rtnl.const.RTM_SETLINK, 0, { dev: name, change: 1, flags: up ? 1 : 0 });
}
function phy_sysfs_file(phy, name)
{
return trim(readfile(`/sys/class/ieee80211/${phy}/${name}`));
}
function macaddr_split(str)
{
return map(split(str, ":"), (val) => hex(val));
}
function macaddr_join(addr)
{
return join(":", map(addr, (val) => sprintf("%02x", val)));
}
function wdev_macaddr(wdev)
{
return trim(readfile(`/sys/class/net/${wdev}/address`));
}
const phy_proto = {
macaddr_init: function(used, options) {
this.macaddr_options = options ?? {};
this.macaddr_list = {};
if (type(used) == "object")
for (let addr in used)
this.macaddr_list[addr] = used[addr];
else
for (let addr in used)
this.macaddr_list[addr] = -1;
this.for_each_wdev((wdev) => {
let macaddr = wdev_macaddr(wdev);
this.macaddr_list[macaddr] ??= -1;
});
return this.macaddr_list;
},
macaddr_generate: function(data) {
let phy = this.phy;
let radio_idx = this.radio;
let idx = int(data.id ?? 0);
let mbssid = int(data.mbssid ?? 0) > 0;
let num_global = int(data.num_global ?? 1);
let use_global = !mbssid && idx < num_global;
let base_addr = phy_sysfs_file(phy, "macaddress");
if (!base_addr)
return null;
let base_mask = phy_sysfs_file(phy, "address_mask");
if (!base_mask)
return null;
if (base_mask == "00:00:00:00:00:00")
base_mask = "ff:ff:ff:ff:ff:ff";
if (data.macaddr_base)
base_addr = data.macaddr_base;
else if (base_mask == "ff:ff:ff:ff:ff:ff" &&
(radio_idx > 0 || idx >= num_global)) {
let addrs = split(phy_sysfs_file(phy, "addresses"), "\n");
if (radio_idx != null) {
if (radio_idx && radio_idx < length(addrs))
base_addr = addrs[radio_idx];
else
idx += radio_idx * 16;
} else {
if (idx < length(addrs))
return addrs[idx];
}
}
if (!idx && !mbssid)
return base_addr;
let addr = macaddr_split(base_addr);
let mask = macaddr_split(base_mask);
let type;
if (mbssid)
type = "b5";
else if (use_global)
type = "add";
else if (mask[0] > 0)
type = "b1";
else if (mask[5] < 0xff)
type = "b5";
else
type = "add";
switch (type) {
case "b1":
if (!(addr[0] & 2))
idx--;
addr[0] |= 2;
addr[0] ^= idx << 2;
break;
case "b5":
if (mbssid)
addr[0] |= 2;
addr[5] ^= idx;
break;
default:
for (let i = 5; i > 0; i--) {
addr[i] += idx;
if (addr[i] < 256)
break;
addr[i] %= 256;
}
break;
}
return macaddr_join(addr);
},
macaddr_next: function(val) {
let data = this.macaddr_options ?? {};
let list = this.macaddr_list;
for (let i = 0; i < 32; i++) {
data.id = i;
let mac = this.macaddr_generate(data);
if (!mac)
return null;
if (list[mac] != null)
continue;
list[mac] = val != null ? val : -1;
return mac;
}
},
wdev_add: function(name, data) {
let phydev = this;
wdev_create(this.phy, name, {
...data,
radio: this.radio,
});
},
for_each_wdev: function(cb) {
let wdevs = nl80211.request(
nl80211.const.NL80211_CMD_GET_INTERFACE,
nl80211.const.NLM_F_DUMP,
{ wiphy: this.idx }
);
let mac_wdev = {};
for (let wdev in wdevs) {
if (wdev.iftype == nl80211.const.NL80211_IFTYPE_AP_VLAN)
continue;
if (this.radio != null && wdev.vif_radio_mask != null &&
wdev.vif_radio_mask != (1 << this.radio))
continue;
mac_wdev[wdev.mac] = wdev;
}
for (let wdev in wdevs) {
if (!mac_wdev[wdev.mac])
continue;
cb(wdev.ifname);
}
}
};
function phy_open(phy, radio)
{
let phyidx = readfile(`/sys/class/ieee80211/${phy}/index`);
if (!phyidx)
return null;
let name = phy;
if (radio === "" || radio < 0)
radio = null;
if (radio != null)
name += "." + radio;
return proto({
phy, name, radio,
idx: int(phyidx),
}, phy_proto);
}
const vlist_proto = {
update: function(values, arg) {
let data = this.data;
let cb = this.cb;
let seq = { };
let new_data = {};
let old_data = {};
this.data = new_data;
if (type(values) == "object") {
for (let key in values) {
old_data[key] = data[key];
new_data[key] = values[key];
delete data[key];
}
} else {
for (let val in values) {
let cur_key = val[0];
let cur_obj = val[1];
old_data[cur_key] = data[cur_key];
new_data[cur_key] = val[1];
delete data[cur_key];
}
}
for (let key in data) {
cb(null, data[key], arg);
delete data[key];
}
for (let key in new_data)
cb(new_data[key], old_data[key], arg);
}
};
function is_equal(val1, val2) {
let t1 = type(val1);
if (t1 != type(val2))
return false;
if (t1 == "array") {
if (length(val1) != length(val2))
return false;
for (let i = 0; i < length(val1); i++)
if (!is_equal(val1[i], val2[i]))
return false;
return true;
} else if (t1 == "object") {
for (let key in val1)
if (!is_equal(val1[key], val2[key]))
return false;
for (let key in val2)
if (val1[key] == null)
return false;
return true;
} else {
return val1 == val2;
}
}
function vlist_new(cb) {
return proto({
cb: cb,
data: {}
}, vlist_proto);
}
export { wdev_remove, wdev_create, wdev_set_mesh_params, wdev_set_radio_mask, wdev_set_up, is_equal, vlist_new, phy_is_fullmac, phy_open };

View File

@@ -1,183 +0,0 @@
#!/usr/bin/env ucode
'use strict';
import { vlist_new, is_equal, wdev_set_mesh_params, wdev_remove, wdev_set_up, phy_open } from "/usr/share/hostap/common.uc";
import { readfile, writefile, basename, readlink, glob } from "fs";
let libubus = require("ubus");
let keep_devices = {};
let phy_name = shift(ARGV);
let command = shift(ARGV);
let phy, phydev;
function iface_stop(wdev)
{
if (keep_devices[wdev.ifname])
return;
wdev_remove(wdev.ifname);
}
function iface_start(wdev)
{
let ifname = wdev.ifname;
if (readfile(`/sys/class/net/${ifname}/ifindex`)) {
wdev_set_up(ifname, false);
wdev_remove(ifname);
}
let wdev_config = {};
for (let key in wdev)
wdev_config[key] = wdev[key];
if (!wdev_config.macaddr && wdev.mode != "monitor")
wdev_config.macaddr = phydev.macaddr_next();
phydev.wdev_add(ifname, wdev_config);
wdev_set_up(ifname, true);
let htmode = wdev.htmode || "NOHT";
if (wdev.freq)
system(`iw dev ${ifname} set freq ${wdev.freq} ${htmode}`);
if (wdev.mode == "adhoc") {
let cmd = ["iw", "dev", ifname, "ibss", "join", wdev.ssid, wdev.freq, htmode, "fixed-freq" ];
if (wdev.bssid)
push(cmd, wdev.bssid);
for (let key in [ "beacon-interval", "basic-rates", "mcast-rate", "keys" ])
if (wdev[key])
push(cmd, key, wdev[key]);
system(cmd);
} else if (wdev.mode == "mesh") {
let cmd = [ "iw", "dev", ifname, "mesh", "join", wdev.ssid, "freq", wdev.freq, htmode ];
for (let key in [ "basic-rates", "mcast-rate", "beacon-interval" ])
if (wdev[key])
push(cmd, key, wdev[key]);
system(cmd);
wdev_set_mesh_params(ifname, wdev);
}
}
function iface_cb(new_if, old_if)
{
if (old_if && new_if && is_equal(old_if, new_if))
return;
if (old_if)
iface_stop(old_if);
if (new_if)
iface_start(new_if);
}
function drop_inactive(config)
{
for (let key in config) {
if (!readfile(`/sys/class/net/${key}/ifindex`))
delete config[key];
}
}
function add_ifname(config)
{
for (let key in config)
config[key].ifname = key;
}
function delete_ifname(config)
{
for (let key in config)
delete config[key].ifname;
}
function add_existing(phydev, config)
{
phydev.for_each_wdev((wdev) => {
if (config[wdev])
return;
if (trim(readfile(`/sys/class/net/${wdev}/operstate`)) == "down")
config[wdev] = {};
});
}
function usage()
{
warn(`Usage: ${basename(sourcepath())} <phy> <command> [<arguments>]
Commands:
set_config <config> [<device]...] - set phy configuration
get_macaddr <id> - get phy MAC address for vif index <id>
`);
exit(1);
}
const commands = {
set_config: function(args) {
let statefile = `/var/run/wdev-${phy_name}.json`;
let new_config = shift(args);
for (let dev in ARGV)
keep_devices[dev] = true;
if (!new_config)
usage();
new_config = json(new_config);
if (!new_config) {
warn("Invalid configuration\n");
exit(1);
}
let old_config = readfile(statefile);
if (old_config)
old_config = json(old_config);
let config = vlist_new(iface_cb);
if (type(old_config) == "object")
config.data = old_config;
add_existing(phydev, config.data);
add_ifname(config.data);
drop_inactive(config.data);
let ubus = libubus.connect();
let data = ubus.call("hostapd", "config_get_macaddr_list", { phy: phydev.name, radio: phydev.radio ?? -1 });
let macaddr_list = [];
if (type(data) == "object" && data.macaddr)
macaddr_list = data.macaddr;
ubus.disconnect();
phydev.macaddr_init(macaddr_list);
add_ifname(new_config);
config.update(new_config);
drop_inactive(config.data);
delete_ifname(config.data);
writefile(statefile, sprintf("%J", config.data));
},
get_macaddr: function(args) {
let data = {};
for (let arg in args) {
arg = split(arg, "=", 2);
data[arg[0]] = arg[1];
}
let macaddr = phydev.macaddr_generate(data);
if (!macaddr) {
warn(`Could not get MAC address for phy ${phy_name}\n`);
exit(1);
}
print(macaddr + "\n");
},
};
if (!phy_name || !command | !commands[command])
usage();
let phy_split = split(phy_name, ":");
phydev = phy_open(phy_split[0], phy_split[1]);
phy = phydev.phy;
if (!phydev) {
warn(`PHY ${phy_name} does not exist\n`);
exit(1);
}
commands[command](ARGV);

View File

@@ -1,260 +0,0 @@
#!/usr/bin/env ucode
'use strict';
import { readfile, writefile, realpath, glob, basename, unlink, open, rename } from "fs";
import { is_equal } from "/usr/share/hostap/common.uc";
let nl = require("nl80211");
let board_file = "/etc/board.json";
let prev_board_data = json(readfile(board_file));
let board_data = json(readfile(board_file));
function phy_idx(name) {
return +rtrim(readfile(`/sys/class/ieee80211/${name}/index`));
}
function phy_path(name) {
let devpath = realpath(`/sys/class/ieee80211/${name}/device`);
devpath = replace(devpath, /^\/sys\/devices\//, "");
if (match(devpath, /^platform\/.*\/pci/))
devpath = replace(devpath, /^platform\//, "");
let dev_phys = map(glob(`/sys/class/ieee80211/${name}/device/ieee80211/*`), basename);
sort(dev_phys, (a, b) => phy_idx(a) - phy_idx(b));
let ofs = index(dev_phys, name);
if (ofs > 0)
devpath += `+${ofs}`;
return devpath;
}
function cleanup() {
let wlan = board_data.wlan;
for (let name in wlan)
if (substr(name, 0, 3) == "phy")
delete wlan[name];
else
delete wlan[name].info;
}
function wiphy_get_entry(phy, path) {
board_data.wlan ??= {};
let wlan = board_data.wlan;
for (let name in wlan)
if (wlan[name].path == path)
return wlan[name];
wlan[phy] = {
path: path
};
return wlan[phy];
}
function freq_to_channel(freq) {
if (freq < 1000)
return 0;
if (freq == 2484)
return 14;
if (freq == 5935)
return 2;
if (freq < 2484)
return (freq - 2407) / 5;
if (freq >= 4910 && freq <= 4980)
return (freq - 4000) / 5;
if (freq < 5950)
return (freq - 5000) / 5;
if (freq <= 45000)
return (freq - 5950) / 5;
if (freq >= 58320 && freq <= 70200)
return (freq - 56160) / 2160;
return 0;
}
function freq_range_match(ranges, freq) {
freq *= 1000;
for (let range in ranges) {
if (freq >= range[0] && freq <= range[1])
return true;
}
return false;
}
function wiphy_detect() {
let phys = nl.request(nl.const.NL80211_CMD_GET_WIPHY, nl.const.NLM_F_DUMP, { split_wiphy_dump: true });
if (!phys)
return;
for (let phy in phys) {
if (!phy)
continue;
let name = phy.wiphy_name;
let path = phy_path(name);
let info = {
antenna_rx: phy.wiphy_antenna_avail_rx,
antenna_tx: phy.wiphy_antenna_avail_tx,
bands: {},
radios: []
};
for (let radio in phy.radios) {
// S1G is not supported yet
radio.freq_ranges = filter(radio.freq_ranges,
(range) => range.end > 2000000
);
if (!length(radio.freq_ranges))
continue;
push(info.radios, {
index: radio.index,
freq_ranges: map(radio.freq_ranges,
(range) => [ range.start, range.end ]
),
bands: {}
});
}
let bands = info.bands;
for (let band in phy.wiphy_bands) {
if (!band || !band.freqs)
continue;
let freq = band.freqs[0].freq;
let band_info = {};
let band_name;
if (freq > 50000)
band_name = "60G";
else if (freq > 5900)
band_name = "6G";
else if (freq > 4000)
band_name = "5G";
else if (freq > 2000)
band_name = "2G";
else
continue;
bands[band_name] = band_info;
if (band.ht_capa > 0)
band_info.ht = true;
if (band.vht_capa > 0)
band_info.vht = true;
let he_phy_cap = 0;
let eht_phy_cap = 0;
for (let ift in band.iftype_data) {
if (!ift.he_cap_phy)
continue;
band_info.he = true;
he_phy_cap |= ift.he_cap_phy[0];
if (!ift.eht_cap_phy)
continue;
band_info.eht = true;
eht_phy_cap |= ift.eht_cap_phy[0];
}
if (band_name != "2G" &&
(he_phy_cap & 0x18) || ((band.vht_capa >> 2) & 0x3))
band_info.max_width = 160;
else if (band_name != "2G" &&
(he_phy_cap & 4) || band.vht_capa > 0)
band_info.max_width = 80;
else if ((band.ht_capa & 0x2) || (he_phy_cap & 0x2))
band_info.max_width = 40;
else
band_info.max_width = 20;
let modes = band_info.modes = [ "NOHT" ];
if (band_info.ht)
push(modes, "HT20");
if (band_info.vht)
push(modes, "VHT20");
if (band_info.he)
push(modes, "HE20");
if (band_info.eht)
push(modes, "EHT20");
if (band.ht_capa & 0x2) {
push(modes, "HT40");
if (band_info.vht)
push(modes, "VHT40")
}
if (he_phy_cap & 2)
push(modes, "HE40");
if (eht_phy_cap && he_phy_cap & 2)
push(modes, "EHT40");
for (let radio in info.radios) {
let freq_match = filter(band.freqs,
(freq) => freq_range_match(radio.freq_ranges, freq.freq)
);
if (!length(freq_match))
continue;
let radio_band = {};
radio.bands[band_name] = radio_band;
freq_match = filter(freq_match,
(freq) => !freq.disabled
);
let freq = freq_match[0];
if (freq)
radio_band.default_channel = freq_to_channel(freq.freq);
}
for (let freq in band.freqs) {
if (freq.disabled)
continue;
let chan = freq_to_channel(freq.freq);
if (!chan)
continue;
band_info.default_channel = chan;
break;
}
if (band_name == "2G")
continue;
if (he_phy_cap & 4)
push(modes, "HE40");
if (eht_phy_cap && he_phy_cap & 4)
push(modes, "EHT40");
if (band_info.vht)
push(modes, "VHT80");
if (he_phy_cap & 4)
push(modes, "HE80");
if (eht_phy_cap && he_phy_cap & 4)
push(modes, "EHT80");
if ((band.vht_capa >> 2) & 0x3)
push(modes, "VHT160");
if (he_phy_cap & 0x18)
push(modes, "HE160");
if (eht_phy_cap && he_phy_cap & 0x18)
push(modes, "EHT160");
if (eht_phy_cap & 2)
push(modes, "EHT320");
}
let entry = wiphy_get_entry(name, path);
entry.info = info;
}
}
cleanup();
wiphy_detect();
if (!is_equal(prev_board_data, board_data)) {
let new_file = board_file + ".new";
unlink(new_file);
let f = open(new_file, "wx");
if (!f)
exit(1);
f.write(sprintf("%.J\n", board_data));
f.close();
rename(new_file, board_file);
}

View File

@@ -1,107 +0,0 @@
'use strict';
import { readfile, realpath, lsdir } from "fs";
import * as nl80211 from "nl80211";
function phy_filename(phy, name) {
return `/sys/class/ieee80211/${phy}/${name}`;
}
function phy_file(phy, name) {
return readfile(phy_filename(phy, name));
}
function phy_index(phy) {
return +phy_file(phy, "index");
}
function phy_path_match(phy, path) {
let phy_path = realpath(phy_filename(phy, "device"));
return substr(phy_path, -length(path)) == path;
}
function __find_phy_by_path(phys, path) {
if (!path)
return null;
path = split(path, "+");
phys = filter(phys, (phy) => phy_path_match(phy, path[0]));
phys = sort(phys, (a, b) => phy_index(a) - phy_index(b));
return phys[+path[1]];
}
function find_phy_by_macaddr(phys, macaddr) {
macaddr = lc(macaddr);
return filter(phys, (phy) => phy_file(phy, "macaddr") == macaddr)[0];
}
function rename_phy_by_name(phys, name, rename) {
let data = json(readfile("/etc/board.json")).wlan;
if (!data)
return;
data = data[name];
if (!data)
return;
let prev_name = __find_phy_by_path(phys, data.path);
if (!prev_name)
return;
if (!rename)
return true;
let idx = phy_index(prev_name);
nl80211.request(nl80211.const.NL80211_CMD_SET_WIPHY, 0, {
wiphy: idx,
wiphy_name: name
});
return true;
}
function find_phy_by_path(phys, path) {
let name = __find_phy_by_path(phys, path);
if (!name)
return;
let data = json(readfile("/etc/board.json")).wlan;
if (!data || data[name])
return name;
for (let cur_name, cur_data in data) {
if (!phy_path_match(name, cur_data.path))
continue;
let idx = phy_index(name);
nl80211.request(nl80211.const.NL80211_CMD_SET_WIPHY, 0, {
wiphy: idx,
wiphy_name: cur_name
});
return cur_name;
}
return name;
}
function find_phy_by_name(phys, name, rename) {
if (index(phys, name) >= 0)
return name;
if (!rename_phy_by_name(phys, name, rename))
return;
if (!rename)
return name;
return index(phys, name) < 0 ? null : name;
}
export function find_phy(config, rename) {
let phys = lsdir("/sys/class/ieee80211");
return find_phy_by_path(phys, config.path) ??
find_phy_by_macaddr(phys, config.macaddr) ??
find_phy_by_name(phys, config.phy, rename);
};

View File

@@ -1,12 +1,54 @@
# wpa_supplicant config
config WPA_RFKILL_SUPPORT
bool "Add rfkill support"
depends on PACKAGE_hostapd-common
depends on PACKAGE_wpa-supplicant || \
PACKAGE_wpa-supplicant-openssl || \
PACKAGE_wpa-supplicant-wolfssl || \
PACKAGE_wpa-supplicant-mbedtls || \
PACKAGE_wpa-supplicant-mesh-openssl || \
PACKAGE_wpa-supplicant-mesh-wolfssl || \
PACKAGE_wpa-supplicant-mesh-mbedtls || \
PACKAGE_wpa-supplicant-basic || \
PACKAGE_wpa-supplicant-mini || \
PACKAGE_wpa-supplicant-p2p || \
PACKAGE_wpad || \
PACKAGE_wpad-openssl || \
PACKAGE_wpad-wolfssl || \
PACKAGE_wpad-mbedtls || \
PACKAGE_wpad-basic || \
PACKAGE_wpad-basic-openssl || \
PACKAGE_wpad-basic-wolfssl || \
PACKAGE_wpad-basic-mbedtls || \
PACKAGE_wpad-mini || \
PACKAGE_wpad-mesh-openssl || \
PACKAGE_wpad-mesh-wolfssl || \
PACKAGE_wpad-mesh-mbedtls
default n
config WPA_MSG_MIN_PRIORITY
int "Minimum debug message priority"
depends on PACKAGE_hostapd-common
depends on PACKAGE_wpa-supplicant || \
PACKAGE_wpa-supplicant-openssl || \
PACKAGE_wpa-supplicant-wolfssl || \
PACKAGE_wpa-supplicant-mbedtls || \
PACKAGE_wpa-supplicant-mesh-openssl || \
PACKAGE_wpa-supplicant-mesh-wolfssl || \
PACKAGE_wpa-supplicant-mesh-mbedtls || \
PACKAGE_wpa-supplicant-basic || \
PACKAGE_wpa-supplicant-mini || \
PACKAGE_wpa-supplicant-p2p || \
PACKAGE_wpad || \
PACKAGE_wpad-openssl || \
PACKAGE_wpad-wolfssl || \
PACKAGE_wpad-mbedtls || \
PACKAGE_wpad-basic || \
PACKAGE_wpad-basic-openssl || \
PACKAGE_wpad-basic-wolfssl || \
PACKAGE_wpad-basic-mbedtls || \
PACKAGE_wpad-mini || \
PACKAGE_wpad-mesh-openssl || \
PACKAGE_wpad-mesh-wolfssl || \
PACKAGE_wpad-mesh-mbedtls
default 3
help
Useful values are:
@@ -46,7 +88,6 @@ config DRIVER_11BE_SUPPORT
config WPA_ENABLE_WEP
bool "Enable support for unsecure and obsolete WEP"
depends on PACKAGE_hostapd-common
help
Wired equivalent privacy (WEP) is an obsolete cryptographic data
confidentiality algorithm that is not considered secure. It should not be used
@@ -56,8 +97,14 @@ config WPA_ENABLE_WEP
config WPA_MBO_SUPPORT
bool "Multi Band Operation (Agile Multiband)"
depends on PACKAGE_hostapd-common
default y
default PACKAGE_wpa-supplicant || \
PACKAGE_wpa-supplicant-openssl || \
PACKAGE_wpa-supplicant-wolfssl || \
PACKAGE_wpa-supplicant-mbedtls || \
PACKAGE_wpad || \
PACKAGE_wpad-openssl || \
PACKAGE_wpad-wolfssl || \
PACKAGE_wpad-mbedtls
help
Multi Band Operation aka (Agile Multiband) enables features
that facilitate efficient use of multiple frequency bands.

View File

@@ -5,13 +5,13 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=hostapd
PKG_RELEASE:=1
PKG_RELEASE:=1.2
PKG_SOURCE_URL:=https://w1.fi/hostap.git
PKG_SOURCE_URL:=http://w1.fi/hostap.git
PKG_SOURCE_PROTO:=git
PKG_SOURCE_DATE:=2025-08-26
PKG_SOURCE_VERSION:=ca266cc24d8705eb1a2a0857ad326e48b1408b20
PKG_MIRROR_HASH:=cccbb170ca289ad4505a399747c6503fd479ee5a6b836fa0174f727fb400d8df
PKG_SOURCE_DATE:=2023-06-22
PKG_SOURCE_VERSION:=599d00be9de2846c6ea18c1487d8329522ade22b
PKG_MIRROR_HASH:=828810c558ea181e45ed0c8b940f5c41e55775e2979a15aed8cf0ab17dd7723c
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
PKG_LICENSE:=BSD-3-Clause
@@ -80,28 +80,21 @@ ifneq ($(CONFIG_DRIVER_11AX_SUPPORT),)
HOSTAPD_IEEE80211AX:=y
endif
ifneq ($(LOCAL_VARIANT),mini)
ifneq ($(CONFIG_DRIVER_11BE_SUPPORT),)
HOSTAPD_IEEE80211BE:=y
endif
ifneq ($(CONFIG_DRIVER_11BE_SUPPORT),)
HOSTAPD_IEEE80211BE:=y
endif
CORE_DEPENDS = +ucode +libucode \
+ucode-mod-fs +ucode-mod-nl80211 +ucode-mod-rtnl +ucode-mod-ubus +ucode-mod-uloop \
+libubus +libblobmsg-json \
+libudebug
OPENSSL_DEPENDS = +PACKAGE_$(1):libopenssl +PACKAGE_$(1):libopenssl-legacy
+libubus +libblobmsg-json
DRIVER_MAKEOPTS= \
CONFIG_ACS=y CONFIG_DRIVER_NL80211=y \
CONFIG_IEEE80211AC=$(HOSTAPD_IEEE80211AC) \
CONFIG_IEEE80211AX=$(HOSTAPD_IEEE80211AX) \
CONFIG_IEEE80211BE=$(HOSTAPD_IEEE80211BE) \
CONFIG_MBO=$(CONFIG_WPA_MBO_SUPPORT) \
CONFIG_UCODE=y CONFIG_APUP=y \
$(if $(HOSTAPD_IEEE80211BE),CONFIG_OCV=y)
CONFIG_MBO=$(CONFIG_WPA_MBO_SUPPORT)
ifeq ($(SSL_VARIANT),openssl)
DRIVER_MAKEOPTS += CONFIG_TLS=openssl CONFIG_SAE=y
@@ -114,7 +107,7 @@ ifeq ($(SSL_VARIANT),openssl)
DRIVER_MAKEOPTS += CONFIG_AP=y CONFIG_MESH=y
endif
ifeq ($(LOCAL_VARIANT),full)
DRIVER_MAKEOPTS += CONFIG_OWE=y CONFIG_SUITEB192=y CONFIG_AP=y CONFIG_MESH=y CONFIG_EAP_PWD=y CONFIG_DPP=y CONFIG_DPP2=y
DRIVER_MAKEOPTS += CONFIG_OWE=y CONFIG_SUITEB192=y CONFIG_AP=y CONFIG_MESH=y
endif
endif
@@ -129,7 +122,7 @@ ifeq ($(SSL_VARIANT),wolfssl)
DRIVER_MAKEOPTS += CONFIG_AP=y CONFIG_MESH=y CONFIG_WPS_NFC=1
endif
ifeq ($(LOCAL_VARIANT),full)
DRIVER_MAKEOPTS += CONFIG_OWE=y CONFIG_SUITEB192=y CONFIG_AP=y CONFIG_MESH=y CONFIG_WPS_NFC=1 CONFIG_EAP_PWD=y
DRIVER_MAKEOPTS += CONFIG_OWE=y CONFIG_SUITEB192=y CONFIG_AP=y CONFIG_MESH=y CONFIG_WPS_NFC=1
endif
endif
@@ -144,7 +137,7 @@ ifeq ($(SSL_VARIANT),mbedtls)
DRIVER_MAKEOPTS += CONFIG_AP=y CONFIG_MESH=y CONFIG_WPS_NFC=1
endif
ifeq ($(LOCAL_VARIANT),full)
DRIVER_MAKEOPTS += CONFIG_OWE=y CONFIG_SUITEB192=y CONFIG_AP=y CONFIG_MESH=y CONFIG_WPS_NFC=1 CONFIG_EAP_PWD=y CONFIG_DPP=y CONFIG_DPP2=y
DRIVER_MAKEOPTS += CONFIG_OWE=y CONFIG_SUITEB192=y CONFIG_AP=y CONFIG_MESH=y CONFIG_WPS_NFC=1
endif
endif
@@ -162,7 +155,7 @@ define Package/hostapd/Default
CATEGORY:=Network
SUBMENU:=WirelessAPD
TITLE:=IEEE 802.1x Authenticator
URL:=https://w1.fi/hostapd/
URL:=http://hostap.epitest.fi/
DEPENDS:=$(DRV_DEPENDS) +hostapd-common $(CORE_DEPENDS)
EXTRA_DEPENDS:=hostapd-common (=$(PKG_VERSION)-$(PKG_RELEASE))
USERID:=network=101:network=101
@@ -186,7 +179,7 @@ define Package/hostapd-openssl
$(call Package/hostapd/Default,$(1))
TITLE+= (OpenSSL full)
VARIANT:=full-openssl
DEPENDS+=$(OPENSSL_DEPENDS)
DEPENDS+=+PACKAGE_hostapd-openssl:libopenssl
endef
Package/hostapd-openssl/description = $(Package/hostapd/description)
@@ -271,7 +264,7 @@ define Package/wpad/Default
DEPENDS:=$(DRV_DEPENDS) +hostapd-common $(CORE_DEPENDS)
EXTRA_DEPENDS:=hostapd-common (=$(PKG_VERSION)-$(PKG_RELEASE))
USERID:=network=101:network=101
URL:=https://w1.fi/
URL:=http://hostap.epitest.fi/
PROVIDES:=hostapd wpa-supplicant
CONFLICTS:=$(HOSTAPD_PROVIDERS) $(SUPPLICANT_PROVIDERS)
HOSTAPD_PROVIDERS+=$(1)
@@ -293,7 +286,7 @@ define Package/wpad-openssl
$(call Package/wpad/Default,$(1))
TITLE+= (OpenSSL full)
VARIANT:=wpad-full-openssl
DEPENDS+=$(OPENSSL_DEPENDS)
DEPENDS+=+PACKAGE_wpad-openssl:libopenssl
endef
Package/wpad-openssl/description = $(Package/wpad/description)
@@ -330,7 +323,7 @@ define Package/wpad-basic-openssl
$(call Package/wpad/Default,$(1))
TITLE+= (OpenSSL, 11r, 11w)
VARIANT:=wpad-basic-openssl
DEPENDS+=$(OPENSSL_DEPENDS)
DEPENDS+=+PACKAGE_wpad-basic-openssl:libopenssl
endef
define Package/wpad-basic-openssl/description
@@ -382,7 +375,7 @@ endef
define Package/wpad-mesh-openssl
$(call Package/wpad-mesh,$(1))
TITLE+= (OpenSSL, 11s, SAE)
DEPENDS+=$(OPENSSL_DEPENDS)
DEPENDS+=+PACKAGE_wpad-mesh-openssl:libopenssl
VARIANT:=wpad-mesh-openssl
endef
@@ -412,7 +405,7 @@ define Package/wpa-supplicant/Default
CATEGORY:=Network
SUBMENU:=WirelessAPD
TITLE:=WPA Supplicant
URL:=https://w1.fi/wpa_supplicant/
URL:=http://hostap.epitest.fi/wpa_supplicant/
DEPENDS:=$(DRV_DEPENDS) +hostapd-common $(CORE_DEPENDS)
EXTRA_DEPENDS:=hostapd-common (=$(PKG_VERSION)-$(PKG_RELEASE))
USERID:=network=101:network=101
@@ -431,7 +424,7 @@ define Package/wpa-supplicant-openssl
$(call Package/wpa-supplicant/Default,$(1))
TITLE+= (OpenSSL full)
VARIANT:=supplicant-full-openssl
DEPENDS+=$(OPENSSL_DEPENDS)
DEPENDS+=+PACKAGE_wpa-supplicant-openssl:libopenssl
endef
define Package/wpa-supplicant-wolfssl
@@ -468,7 +461,7 @@ define Package/wpa-supplicant-mesh-openssl
$(call Package/wpa-supplicant-mesh/Default,$(1))
TITLE+= (OpenSSL, 11s, SAE)
VARIANT:=supplicant-mesh-openssl
DEPENDS+=$(OPENSSL_DEPENDS)
DEPENDS+=+PACKAGE_wpa-supplicant-mesh-openssl:libopenssl
endef
define Package/wpa-supplicant-mesh-wolfssl
@@ -510,7 +503,7 @@ define Package/hostapd-utils
CATEGORY:=Network
SUBMENU:=WirelessAPD
TITLE:=IEEE 802.1x Authenticator (utils)
URL:=https://w1.fi/hostapd/
URL:=http://hostap.epitest.fi/
DEPENDS:=@$(subst $(space),||,$(foreach pkg,$(HOSTAPD_PROVIDERS),PACKAGE_$(pkg)))
VARIANT:=*
endef
@@ -548,7 +541,7 @@ define Package/eapol-test-openssl
TITLE+= (OpenSSL full)
VARIANT:=supplicant-full-openssl
CONFLICTS:=$(filter-out eapol-test-openssl ,$(EAPOL_TEST_PROVIDERS))
DEPENDS+=$(OPENSSL_DEPENDS)
DEPENDS+=+PACKAGE_eapol-test-openssl:libopenssl
PROVIDES:=eapol-test
endef
@@ -599,7 +592,7 @@ TARGET_CPPFLAGS := \
-D_GNU_SOURCE \
$(if $(CONFIG_WPA_MSG_MIN_PRIORITY),-DCONFIG_MSG_MIN_PRIORITY=$(CONFIG_WPA_MSG_MIN_PRIORITY))
TARGET_LDFLAGS += -lubox -lubus -lblobmsg_json -lucode -lm -lnl-tiny -ludebug
TARGET_LDFLAGS += -lubox -lubus -lblobmsg_json -lucode -lm -lnl-tiny
ifdef CONFIG_WPA_ENABLE_WEP
DRIVER_MAKEOPTS += CONFIG_WEP=y
@@ -713,25 +706,20 @@ Package/hostapd-mbedtls/conffiles = $(Package/hostapd-full/conffiles)
endif
define Install/hostapd
$(INSTALL_DIR) $(1)/usr/sbin $(1)/usr/share/hostap
$(INSTALL_DATA) ./files/hostapd.uc $(1)/usr/share/hostap/
$(INSTALL_DIR) $(1)/usr/sbin
$(if $(findstring full,$(CONFIG_VARIANT)),$(Install/hostapd/full))
endef
define Install/supplicant
$(INSTALL_DIR) $(1)/usr/sbin $(1)/usr/share/hostap
$(INSTALL_DATA) ./files/wpa_supplicant.uc $(1)/usr/share/hostap/
$(INSTALL_DIR) $(1)/usr/sbin
endef
define Package/hostapd-common/install
$(INSTALL_DIR) \
$(1)/etc/capabilities \
$(1)/etc/hotplug.d/ieee80211 \
$(1)/etc/init.d $(1)/lib/netifd \
$(1)/usr/share/acl.d \
$(1)/usr/share/hostap
$(INSTALL_DIR) $(1)/etc/capabilities $(1)/etc/rc.button $(1)/etc/hotplug.d/ieee80211 $(1)/etc/init.d $(1)/lib/netifd $(1)/usr/share/acl.d
$(INSTALL_BIN) ./files/dhcp-get-server.sh $(1)/lib/netifd/dhcp-get-server.sh
$(INSTALL_DATA) ./files/hostapd.sh $(1)/lib/netifd/hostapd.sh
$(INSTALL_BIN) ./files/wpad.init $(1)/etc/init.d/wpad
$(INSTALL_BIN) ./files/wps-hotplug.sh $(1)/etc/rc.button/wps
$(INSTALL_DATA) ./files/wpad_acl.json $(1)/usr/share/acl.d
$(INSTALL_DATA) ./files/wpad.json $(1)/etc/capabilities
endef

View File

@@ -94,7 +94,7 @@ CONFIG_EAP_TTLS=y
#CONFIG_EAP_PAX=y
# EAP-PSK for the integrated EAP server (this is _not_ needed for WPA-PSK)
CONFIG_EAP_PSK=y
#CONFIG_EAP_PSK=y
# EAP-pwd for the integrated EAP server (secure authentication with a password)
#CONFIG_EAP_PWD=y

View File

@@ -43,37 +43,32 @@ hostapd_append_wpa_key_mgmt() {
case "$auth_type" in
psk|eap)
append wpa_key_mgmt "WPA-$auth_type_l"
[ "${wpa:-2}" -ge 2 ] && [ "${ieee80211r:-0}" -gt 0 ] && append wpa_key_mgmt "FT-${auth_type_l}"
[ "${ieee80211r:-0}" -gt 0 ] && append wpa_key_mgmt "FT-${auth_type_l}"
[ "${ieee80211w:-0}" -gt 0 ] && append wpa_key_mgmt "WPA-${auth_type_l}-SHA256"
;;
eap192)
append wpa_key_mgmt "WPA-EAP-SUITE-B-192"
[ "${ieee80211r:-0}" -gt 0 ] && append wpa_key_mgmt "FT-EAP-SHA384"
;;
eap-eap2)
append wpa_key_mgmt "WPA-EAP-SHA256"
[ "${ieee80211r:-0}" -gt 0 ] && append wpa_key_mgmt "FT-EAP"
[ "$rsn_override" -gt 0 ] && rsn_override_key_mgmt="$wpa_key_mgmt"
eap-eap192)
append wpa_key_mgmt "WPA-EAP-SUITE-B-192"
append wpa_key_mgmt "WPA-EAP"
;;
eap2)
[ "${ieee80211r:-0}" -gt 0 ] && append wpa_key_mgmt "FT-EAP"
append wpa_key_mgmt "WPA-EAP-SHA256"
[ "${ieee80211r:-0}" -gt 0 ] && {
append wpa_key_mgmt "FT-EAP-SHA384"
append wpa_key_mgmt "FT-EAP"
}
[ "${ieee80211w:-0}" -gt 0 ] && append wpa_key_mgmt "WPA-EAP-SHA256"
;;
sae)
append wpa_key_mgmt "SAE"
[ "${ieee80211r:-0}" -gt 0 ] && append wpa_key_mgmt "FT-SAE"
;;
psk-sae)
append wpa_key_mgmt "WPA-PSK"
[ "${ieee80211r:-0}" -gt 0 ] && append wpa_key_mgmt "FT-PSK"
[ "${ieee80211w:-0}" -gt 0 ] && append wpa_key_mgmt "WPA-PSK-SHA256"
append wpa_key_mgmt "SAE"
[ "${ieee80211r:-0}" -gt 0 ] && append wpa_key_mgmt "FT-SAE"
[ "$rsn_override" -gt 0 ] && rsn_override_key_mgmt="$wpa_key_mgmt"
[ "$rsn_override" -gt 1 ] && wpa_key_mgmt=
[ "$band" = "6g" ] || {
append wpa_key_mgmt "WPA-PSK"
[ "${ieee80211r:-0}" -gt 0 ] && append wpa_key_mgmt "FT-PSK"
[ "${ieee80211w:-0}" -gt 0 ] && append wpa_key_mgmt "WPA-PSK-SHA256"
}
;;
owe)
append wpa_key_mgmt "OWE"
@@ -82,21 +77,14 @@ hostapd_append_wpa_key_mgmt() {
[ "$fils" -gt 0 ] && {
case "$auth_type" in
eap192)
append wpa_key_mgmt FILS-SHA384
[ "${ieee80211r:-0}" -gt 0 ] && append wpa_key_mgmt FT-FILS-SHA384
;;
eap*)
append wpa_key_mgmt FILS-SHA256
[ "${ieee80211r:-0}" -gt 0 ] && append wpa_key_mgmt FT-FILS-SHA256
[ "$rsn_override" -gt 0 ] && {
append rsn_override_key_mgmt FILS-SHA256
[ "${ieee80211r:-0}" -gt 0 ] && append rsn_override_key_mgmt FT-FILS-SHA256
}
;;
esac
}
[ "$auth_osen" = "1" ] && append wpa_key_mgmt "OSEN"
}
hostapd_add_log_config() {
@@ -128,8 +116,7 @@ hostapd_common_add_device_config() {
config_add_int rssi_reject_assoc_rssi
config_add_int rssi_ignore_probe_request
config_add_int maxassoc
config_add_int reg_power_type
config_add_boolean stationary_ap
config_add_boolean vendor_vht
config_add_string acs_chan_bias
config_add_array hostapd_options
@@ -149,7 +136,7 @@ hostapd_prepare_device_config() {
json_get_vars country country3 country_ie beacon_int:100 doth require_mode legacy_rates \
acs_chan_bias local_pwr_constraint spectrum_mgmt_required airtime_mode cell_density \
rts_threshold beacon_rate rssi_reject_assoc_rssi rssi_ignore_probe_request maxassoc \
mbssid:0 band reg_power_type stationary_ap
vendor_vht mbssid:0
hostapd_set_log_options base_cfg
@@ -218,6 +205,7 @@ hostapd_prepare_device_config() {
set_default rate_list "24000 36000 48000 54000"
set_default basic_rate_list "24000"
fi
[ -n "$vendor_vht" ] && append base_cfg "vendor_vht=$vendor_vht" "$N"
;;
a)
if [ "$cell_density" -eq 1 ]; then
@@ -252,14 +240,6 @@ hostapd_prepare_device_config() {
[ -n "$maxassoc" ] && append base_cfg "iface_max_num_sta=$maxassoc" "$N"
[ "$mbssid" -gt 0 ] && [ "$mbssid" -le 2 ] && append base_cfg "mbssid=$mbssid" "$N"
[ "$band" = "6g" ] && {
set_default reg_power_type 0
append base_cfg "he_6ghz_reg_pwr_type=$reg_power_type" "$N"
}
set_default stationary_ap 1
append base_cfg "stationary_ap=$stationary_ap" "$N"
json_get_values opts hostapd_options
for val in $opts; do
append base_cfg "$val" "$N"
@@ -273,7 +253,7 @@ EOF
hostapd_common_add_bss_config() {
config_add_string 'bssid:macaddr' 'ssid:string'
config_add_boolean wds uapsd hidden utf8_ssid ppsk
config_add_boolean wds wmm uapsd hidden utf8_ssid ppsk
config_add_int maxassoc max_inactivity
config_add_boolean disassoc_low_ack isolate short_preamble skip_inactivity_poll
@@ -343,11 +323,10 @@ hostapd_common_add_bss_config() {
config_add_boolean ieee80211r pmk_r1_push ft_psk_generate_local ft_over_ds
config_add_int r0_key_lifetime reassociation_deadline
config_add_string mobility_domain r1_key_holder rxkh_file
config_add_string mobility_domain r1_key_holder
config_add_array r0kh r1kh
config_add_int ieee80211w_max_timeout ieee80211w_retry_timeout
config_add_int rsn_override
config_add_string macfilter 'macfile:file'
config_add_array 'maclist:list(macaddr)'
@@ -372,11 +351,14 @@ hostapd_common_add_bss_config() {
config_add_array iw_roaming_consortium iw_domain_name iw_anqp_3gpp_cell_net iw_nai_realm
config_add_array iw_anqp_elem iw_venue_name iw_venue_url
config_add_boolean hs20 disable_dgaf
config_add_boolean hs20 disable_dgaf osen
config_add_int anqp_domain_id
config_add_int hs20_deauth_req_timeout
config_add_array hs20_oper_friendly_name
config_add_array osu_provider
config_add_array operator_icon
config_add_array hs20_conn_capab
config_add_string hs20_wan_metrics hs20_operating_class hs20_t_c_filename hs20_t_c_timestamp
config_add_string osu_ssid hs20_wan_metrics hs20_operating_class hs20_t_c_filename hs20_t_c_timestamp
config_add_string hs20_t_c_server_url
@@ -392,16 +374,13 @@ hostapd_common_add_bss_config() {
config_add_array radius_auth_req_attr
config_add_array radius_acct_req_attr
config_add_int eap_server radius_server_auth_port
config_add_string eap_user_file ca_cert server_cert private_key private_key_passwd server_id radius_server_clients
config_add_int eap_server
config_add_string eap_user_file ca_cert server_cert private_key private_key_passwd server_id
config_add_boolean fils
config_add_string fils_dhcp
config_add_int ocv
config_add_boolean apup
config_add_string apup_peer_ifname_prefix
}
hostapd_set_vlan_file() {
@@ -434,36 +413,9 @@ hostapd_set_psk() {
local ifname="$1"
rm -f /var/run/hostapd-${ifname}.psk
case "$auth_type" in
psk|psk-sae) ;;
*) return ;;
esac
for_each_station hostapd_set_psk_file ${ifname}
}
hostapd_set_sae_file() {
local ifname="$1"
local vlan="$2"
local vlan_id=""
json_get_vars mac vid key
set_default mac "ff:ff:ff:ff:ff:ff"
[ -n "$mac" ] && mac="|mac=$mac"
[ -n "$vid" ] && vlan_id="|vlanid=$vid"
printf '%s%s%s\n' "${key}" "${mac}" "${vlan_id}" >> /var/run/hostapd-${ifname}.sae
}
hostapd_set_sae() {
local ifname="$1"
rm -f /var/run/hostapd-${ifname}.sae
case "$auth_type" in
sae|psk-sae) ;;
*) return ;;
esac
for_each_station hostapd_set_sae_file ${ifname}
}
append_iw_roaming_consortium() {
[ -n "$1" ] && append bss_conf "roaming_consortium=$1" "$N"
}
@@ -480,7 +432,7 @@ append_iw_anqp_3gpp_cell_net() {
if [ -z "$iw_anqp_3gpp_cell_net_conf" ]; then
iw_anqp_3gpp_cell_net_conf="$1"
else
iw_anqp_3gpp_cell_net_conf="$iw_anqp_3gpp_cell_net_conf;$1"
iw_anqp_3gpp_cell_net_conf="$iw_anqp_3gpp_cell_net_conf:$1"
fi
}
@@ -500,6 +452,67 @@ append_iw_venue_url() {
append bss_conf "venue_url=$1" "$N"
}
append_hs20_oper_friendly_name() {
append bss_conf "hs20_oper_friendly_name=$1" "$N"
}
append_osu_provider_friendly_name() {
append bss_conf "osu_friendly_name=$1" "$N"
}
append_osu_provider_service_desc() {
append bss_conf "osu_service_desc=$1" "$N"
}
append_hs20_icon() {
local width height lang type path
config_get width "$1" width
config_get height "$1" height
config_get lang "$1" lang
config_get type "$1" type
config_get path "$1" path
append bss_conf "hs20_icon=$width:$height:$lang:$type:$1:$path" "$N"
}
append_hs20_icons() {
config_load wireless
config_foreach append_hs20_icon hs20-icon
}
append_operator_icon() {
append bss_conf "operator_icon=$1" "$N"
}
append_osu_icon() {
append bss_conf "osu_icon=$1" "$N"
}
append_osu_provider() {
local cfgtype osu_server_uri osu_friendly_name osu_nai osu_nai2 osu_method_list
config_load wireless
config_get cfgtype "$1" TYPE
[ "$cfgtype" != "osu-provider" ] && return
append bss_conf "# provider $1" "$N"
config_get osu_server_uri "$1" osu_server_uri
config_get osu_nai "$1" osu_nai
config_get osu_nai2 "$1" osu_nai2
config_get osu_method_list "$1" osu_method
append bss_conf "osu_server_uri=$osu_server_uri" "$N"
append bss_conf "osu_nai=$osu_nai" "$N"
append bss_conf "osu_nai2=$osu_nai2" "$N"
append bss_conf "osu_method_list=$osu_method_list" "$N"
config_list_foreach "$1" osu_service_desc append_osu_provider_service_desc
config_list_foreach "$1" osu_friendly_name append_osu_friendly_name
config_list_foreach "$1" osu_icon append_osu_icon
append bss_conf "$N"
}
append_hs20_conn_capab() {
[ -n "$1" ] && append bss_conf "hs20_conn_capab=$1" "$N"
}
@@ -537,7 +550,7 @@ hostapd_set_bss_options() {
wireless_vif_parse_encryption
local bss_conf bss_md5sum ft_key rxkhs
local bss_conf bss_md5sum ft_key
local wep_rekey wpa_group_rekey wpa_pair_rekey wpa_master_rekey wpa_key_mgmt
json_get_vars \
@@ -546,17 +559,16 @@ hostapd_set_bss_options() {
maxassoc max_inactivity disassoc_low_ack isolate auth_cache \
wps_pushbutton wps_label ext_registrar wps_pbc_in_m1 wps_ap_setup_locked \
wps_independent wps_device_type wps_device_name wps_manufacturer wps_pin \
macfilter ssid utf8_ssid uapsd hidden short_preamble rsn_preauth \
macfilter ssid utf8_ssid wmm uapsd hidden short_preamble rsn_preauth \
iapp_interface eapol_version dynamic_vlan ieee80211w nasid \
acct_secret acct_port acct_interval \
bss_load_update_period chan_util_avg_period sae_require_mfp sae_pwe \
multi_ap multi_ap_backhaul_ssid multi_ap_backhaul_key skip_inactivity_poll \
ppsk airtime_bss_weight airtime_bss_limit airtime_sta_weight \
multicast_to_unicast_all proxy_arp per_sta_vif \
eap_server eap_user_file ca_cert server_cert private_key private_key_passwd server_id radius_server_clients radius_server_auth_port \
vendor_elements fils ocv apup rsn_override
eap_server eap_user_file ca_cert server_cert private_key private_key_passwd server_id \
vendor_elements fils ocv
set_default rsn_override 1
set_default fils 0
set_default isolate 0
set_default maxassoc 0
@@ -565,6 +577,7 @@ hostapd_set_bss_options() {
set_default disassoc_low_ack 1
set_default skip_inactivity_poll 0
set_default hidden 0
set_default wmm 1
set_default uapsd 1
set_default wpa_disable_eapol_key_retries 0
set_default tdls_prohibit 0
@@ -578,7 +591,6 @@ hostapd_set_bss_options() {
set_default airtime_bss_weight 0
set_default airtime_bss_limit 0
set_default eap_server 0
set_default apup 0
/usr/sbin/hostapd -vfils || fils=0
@@ -602,7 +614,7 @@ hostapd_set_bss_options() {
append bss_conf "disassoc_low_ack=$disassoc_low_ack" "$N"
append bss_conf "skip_inactivity_poll=$skip_inactivity_poll" "$N"
append bss_conf "preamble=$short_preamble" "$N"
append bss_conf "wmm_enabled=1" "$N"
append bss_conf "wmm_enabled=$wmm" "$N"
append bss_conf "ignore_broadcast_ssid=$hidden" "$N"
append bss_conf "uapsd_advertisement_enabled=$uapsd" "$N"
append bss_conf "utf8_ssid=$utf8_ssid" "$N"
@@ -618,7 +630,8 @@ hostapd_set_bss_options() {
[ -n "$wpa_strict_rekey" ] && append bss_conf "wpa_strict_rekey=$wpa_strict_rekey" "$N"
}
[ -n "$nasid" ] && append bss_conf "nas_identifier=$nasid" "$N"
set_default nasid "${macaddr//\:}"
append bss_conf "nas_identifier=$nasid" "$N"
[ -n "$acct_interval" ] && \
append bss_conf "radius_acct_interim_interval=$acct_interval" "$N"
@@ -628,19 +641,15 @@ hostapd_set_bss_options() {
[ -n "$ocv" ] && append bss_conf "ocv=$ocv" "$N"
case "$auth_type" in
sae|owe|eap2|eap192)
sae|owe|eap192|eap-eap192)
set_default ieee80211w 2
set_default sae_require_mfp 1
[ "$ppsk" -eq 0 ] && set_default sae_pwe 2
set_default sae_pwe 2
;;
psk-sae|eap-eap2)
if [ "$band" = 6g ]; then
set_default ieee80211w 2
else
set_default ieee80211w 1
fi
psk-sae)
set_default ieee80211w 1
set_default sae_require_mfp 1
[ "$ppsk" -eq 0 ] && set_default sae_pwe 2
set_default sae_pwe 2
;;
esac
[ -n "$sae_require_mfp" ] && append bss_conf "sae_require_mfp=$sae_require_mfp" "$N"
@@ -662,8 +671,8 @@ hostapd_set_bss_options() {
wps_not_configured=1
;;
psk|sae|psk-sae)
json_get_vars key wpa_psk_file sae_password_file
if [ "$ppsk" -ne 0 ]; then
json_get_vars key wpa_psk_file
if [ "$auth_type" = "psk" ] && [ "$ppsk" -ne 0 ] ; then
json_get_vars auth_secret auth_port
set_default auth_port 1812
json_for_each_item append_auth_server auth_server
@@ -673,27 +682,22 @@ hostapd_set_bss_options() {
append bss_conf "wpa_psk=$key" "$N"
elif [ ${#key} -ge 8 ] && [ ${#key} -le 63 ]; then
append bss_conf "wpa_passphrase=$key" "$N"
elif [ -n "$key" ]; then
elif [ -n "$key" ] || [ -z "$wpa_psk_file" ]; then
wireless_setup_vif_failed INVALID_WPA_PSK
return 1
fi
[ -z "$wpa_psk_file" ] && set_default wpa_psk_file /var/run/hostapd-$ifname.psk
[ -n "$wpa_psk_file" ] && [ "$auth_type" = "psk" -o "$auth_type" = "psk-sae" ] && {
[ -n "$wpa_psk_file" ] && {
[ -e "$wpa_psk_file" ] || touch "$wpa_psk_file"
append bss_conf "wpa_psk_file=$wpa_psk_file" "$N"
}
[ -z "$sae_password_file" ] && set_default sae_password_file /var/run/hostapd-$ifname.sae
[ -n "$sae_password_file" ] && [ "$auth_type" = "sae" -o "$auth_type" = "psk-sae" ] && {
[ -e "$sae_password_file" ] || touch "$sae_password_file"
append bss_conf "sae_password_file=$sae_password_file" "$N"
}
[ "$eapol_version" -ge "1" -a "$eapol_version" -le "2" ] && append bss_conf "eapol_version=$eapol_version" "$N"
set_default dynamic_vlan 0
vlan_possible=1
wps_possible=1
;;
eap|eap2|eap-eap2|eap192)
eap|eap192|eap-eap192)
json_get_vars \
auth_server auth_secret auth_port \
dae_client dae_secret dae_port \
@@ -865,9 +869,8 @@ hostapd_set_bss_options() {
[ "$bss_transition" -eq "1" ] && append bss_conf "bss_transition=1" "$N"
[ "$mbo" -eq 1 ] && append bss_conf "mbo=1" "$N"
json_get_vars ieee80211k rrm_neighbor_report rrm_beacon_report rnr
json_get_vars ieee80211k rrm_neighbor_report rrm_beacon_report
set_default ieee80211k 0
set_default rnr 0
if [ "$ieee80211k" -eq "1" ]; then
set_default rrm_neighbor_report 1
set_default rrm_beacon_report 1
@@ -878,7 +881,6 @@ hostapd_set_bss_options() {
[ "$rrm_neighbor_report" -eq "1" ] && append bss_conf "rrm_neighbor_report=1" "$N"
[ "$rrm_beacon_report" -eq "1" ] && append bss_conf "rrm_beacon_report=1" "$N"
[ "$rnr" -eq "1" ] && append bss_conf "rnr=1" "$N"
json_get_vars ftm_responder stationary_ap lci civic
set_default ftm_responder 0
@@ -892,26 +894,10 @@ hostapd_set_bss_options() {
}
fi
json_get_vars ieee80211r
set_default ieee80211r 0
if [ "$wpa" -ge "1" ]; then
if [ "$fils" -gt 0 ]; then
json_get_vars fils_realm
set_default fils_realm "$(echo "$ssid" | md5sum | head -c 8)"
fi
json_get_vars ieee80211r
set_default ieee80211r 0
append bss_conf "wpa_disable_eapol_key_retries=$wpa_disable_eapol_key_retries" "$N"
hostapd_append_wpa_key_mgmt
[ -n "$wpa_key_mgmt" ] && append bss_conf "wpa_key_mgmt=$wpa_key_mgmt" "$N"
[ -n "$rsn_override_key_mgmt" -o -n "$rsn_override_pairwise" ] && {
append bss_conf "rsn_override_key_mgmt=${rsn_override_key_mgmt:-$wpa_key_mgmt}" "$N"
append bss_conf "rsn_override_pairwise=${rsn_override_pairwise:-$wpa_pairwise}" "$N"
append bss_conf "rsn_override_mfp=$ieee80211w" "$N"
}
fi
if [ "$wpa" -ge "2" ]; then
if [ "$ieee80211r" -gt "0" ]; then
json_get_vars mobility_domain ft_psk_generate_local ft_over_ds reassociation_deadline
@@ -920,7 +906,7 @@ hostapd_set_bss_options() {
set_default reassociation_deadline 1000
case "$auth_type" in
psk)
psk|sae|psk-sae)
set_default ft_psk_generate_local 1
;;
*)
@@ -935,7 +921,7 @@ hostapd_set_bss_options() {
append bss_conf "reassociation_deadline=$reassociation_deadline" "$N"
if [ "$ft_psk_generate_local" -eq "0" ]; then
json_get_vars r0_key_lifetime r1_key_holder pmk_r1_push rxkh_file
json_get_vars r0_key_lifetime r1_key_holder pmk_r1_push
json_get_values r0kh r0kh
json_get_values r1kh r1kh
@@ -943,10 +929,6 @@ hostapd_set_bss_options() {
set_default pmk_r1_push 0
[ -n "$r0kh" -a -n "$r1kh" ] || {
if [ -z "$auth_secret" -a -z "$key" ]; then
wireless_setup_vif_failed FT_KEY_CANT_BE_DERIVED
return 1
fi
ft_key=`echo -n "$mobility_domain/${auth_secret:-${key}}" | md5sum | awk '{print $1}'`
set_default r0kh "ff:ff:ff:ff:ff:ff,*,$ft_key"
@@ -957,23 +939,26 @@ hostapd_set_bss_options() {
append bss_conf "r0_key_lifetime=$r0_key_lifetime" "$N"
append bss_conf "pmk_r1_push=$pmk_r1_push" "$N"
if [ -z "$rxkh_file" ]; then
set_default rxkh_file /var/run/hostapd-$ifname.rxkh
[ -e "$rxkh_file" ] && rm -f "$rxkh_file"
touch "$rxkh_file"
for kh in $r0kh; do
append rxkhs "r0kh=${kh//,/ }" "$N"
done
for kh in $r1kh; do
append rxkhs "r1kh=${kh//,/ }" "$N"
done
echo "$rxkhs" > "$rxkh_file"
fi
append bss_conf "rxkh_file=$rxkh_file" "$N"
for kh in $r0kh; do
append bss_conf "r0kh=${kh//,/ }" "$N"
done
for kh in $r1kh; do
append bss_conf "r1kh=${kh//,/ }" "$N"
done
fi
fi
if [ "$fils" -gt 0 ]; then
json_get_vars fils_realm
set_default fils_realm "$(echo "$ssid" | md5sum | head -c 8)"
fi
append bss_conf "wpa_disable_eapol_key_retries=$wpa_disable_eapol_key_retries" "$N"
hostapd_append_wpa_key_mgmt
[ -n "$wpa_key_mgmt" ] && append bss_conf "wpa_key_mgmt=$wpa_key_mgmt" "$N"
fi
if [ "$wpa" -ge "2" ]; then
if [ -n "$network_bridge" -a "$rsn_preauth" = 1 ]; then
set_default auth_cache 1
append bss_conf "rsn_preauth=1" "$N"
@@ -1115,28 +1100,35 @@ hostapd_set_bss_options() {
esac
[ -n "$iw_qos_map_set" ] && append bss_conf "qos_map_set=$iw_qos_map_set" "$N"
local hs20 disable_dgaf anqp_domain_id hs20_deauth_req_timeout \
hs20_wan_metrics hs20_operating_class hs20_t_c_filename hs20_t_c_timestamp \
local hs20 disable_dgaf osen anqp_domain_id hs20_deauth_req_timeout \
osu_ssid hs20_wan_metrics hs20_operating_class hs20_t_c_filename hs20_t_c_timestamp \
hs20_t_c_server_url
json_get_vars hs20 disable_dgaf anqp_domain_id hs20_deauth_req_timeout \
hs20_wan_metrics hs20_operating_class hs20_t_c_filename hs20_t_c_timestamp \
json_get_vars hs20 disable_dgaf osen anqp_domain_id hs20_deauth_req_timeout \
osu_ssid hs20_wan_metrics hs20_operating_class hs20_t_c_filename hs20_t_c_timestamp \
hs20_t_c_server_url
set_default hs20 0
set_default disable_dgaf $hs20
set_default osen 0
set_default anqp_domain_id 0
set_default hs20_deauth_req_timeout 60
if [ "$hs20" = "1" ]; then
append bss_conf "hs20=1" "$N"
append_hs20_icons
append bss_conf "disable_dgaf=$disable_dgaf" "$N"
append bss_conf "osen=$osen" "$N"
append bss_conf "anqp_domain_id=$anqp_domain_id" "$N"
append bss_conf "hs20_deauth_req_timeout=$hs20_deauth_req_timeout" "$N"
[ -n "$osu_ssid" ] && append bss_conf "osu_ssid=$osu_ssid" "$N"
[ -n "$hs20_wan_metrics" ] && append bss_conf "hs20_wan_metrics=$hs20_wan_metrics" "$N"
[ -n "$hs20_operating_class" ] && append bss_conf "hs20_operating_class=$hs20_operating_class" "$N"
[ -n "$hs20_t_c_filename" ] && append bss_conf "hs20_t_c_filename=$hs20_t_c_filename" "$N"
[ -n "$hs20_t_c_timestamp" ] && append bss_conf "hs20_t_c_timestamp=$hs20_t_c_timestamp" "$N"
[ -n "$hs20_t_c_server_url" ] && append bss_conf "hs20_t_c_server_url=$hs20_t_c_server_url" "$N"
json_for_each_item append_hs20_oper_friendly_name hs20_oper_friendly_name
json_for_each_item append_hs20_conn_capab hs20_conn_capab
json_for_each_item append_osu_provider osu_provider
json_for_each_item append_operator_icon operator_icon
fi
if [ "$eap_server" = "1" ]; then
@@ -1148,8 +1140,6 @@ hostapd_set_bss_options() {
[ -n "$private_key" ] && append bss_conf "private_key=$private_key" "$N"
[ -n "$private_key_passwd" ] && append bss_conf "private_key_passwd=$private_key_passwd" "$N"
[ -n "$server_id" ] && append bss_conf "server_id=$server_id" "$N"
[ -n "$radius_server_clients" ] && append bss_conf "radius_server_clients=$radius_server_clients" "$N"
[ -n "$radius_server_auth_port" ] && append bss_conf "radius_server_auth_port=$radius_server_auth_port" "$N"
fi
set_default multicast_to_unicast_all 0
@@ -1166,21 +1156,14 @@ hostapd_set_bss_options() {
append bss_conf "per_sta_vif=$per_sta_vif" "$N"
fi
if [ "$apup" -gt 0 ]; then
append bss_conf "apup=$apup" "$N"
local apup_peer_ifname_prefix
json_get_vars apup_peer_ifname_prefix
if [ -n "$apup_peer_ifname_prefix" ] ; then
append bss_conf "apup_peer_ifname_prefix=$apup_peer_ifname_prefix" "$N"
fi
fi
json_get_values opts hostapd_bss_options
for val in $opts; do
append bss_conf "$val" "$N"
done
bss_md5sum="$(echo $bss_conf | md5sum | cut -d" " -f1)"
append bss_conf "config_id=$bss_md5sum" "$N"
append "$var" "$bss_conf" "$N"
return 0
}
@@ -1315,18 +1298,14 @@ wpa_supplicant_add_network() {
wireless_vif_parse_encryption
json_get_vars \
ssid bssid key rsn_override \
mcast_rate \
ssid bssid key \
basic_rate mcast_rate \
ieee80211w ieee80211r fils ocv \
multi_ap \
default_disabled
json_get_values basic_rate_list basic_rate
set_default rsn_override 1
case "$auth_type" in
sae|owe|eap2|eap192)
sae|owe|eap192|eap-eap192)
set_default ieee80211w 2
;;
psk-sae)
@@ -1336,7 +1315,6 @@ wpa_supplicant_add_network() {
set_default ieee80211r 0
set_default multi_ap 0
set_default sae_pwe 2
set_default default_disabled 0
local key_mgmt='NONE'
@@ -1376,12 +1354,6 @@ wpa_supplicant_add_network() {
[ -n "$ocv" ] && append network_data "ocv=$ocv" "$N$T"
rsn_overriding=0
case "$htmode" in
EHT*|HE*) [ "$rsn_override" -gt 0 ] && rsn_overriding=1;;
esac
append network_data "rsn_overriding=$rsn_overriding" "$N$T"
case "$auth_type" in
none) ;;
owe)
@@ -1416,7 +1388,7 @@ wpa_supplicant_add_network() {
fi
append network_data "$passphrase" "$N$T"
;;
eap|eap2|eap192)
eap|eap192|eap-eap192)
hostapd_append_wpa_key_mgmt
key_mgmt="$wpa_key_mgmt"
@@ -1592,21 +1564,12 @@ wpa_supplicant_add_network() {
[ -n "$bssid_blacklist" ] && append network_data "bssid_blacklist=$bssid_blacklist" "$N$T"
[ -n "$bssid_whitelist" ] && append network_data "bssid_whitelist=$bssid_whitelist" "$N$T"
[ -n "$basic_rate_list" ] && {
local br rate rate_list=
if [ "$mode" = mesh ]; then
for br in $basic_rate_list; do
rate="$(($br / 100))"
append rate_list "$rate" " "
done
[ -n "$rate_list" ] && append network_data "mesh_basic_rates=$rate_list" "$N$T"
else
for br in $basic_rate_list; do
wpa_supplicant_add_rate rate_list "$br"
done
[ -n "$rate_list" ] && append network_data "rates=$rate_list" "$N$T"
fi
[ -n "$basic_rate" ] && {
local br rate_list=
for br in $basic_rate; do
wpa_supplicant_add_rate rate_list "$br"
done
[ -n "$rate_list" ] && append network_data "rates=$rate_list" "$N$T"
}
[ -n "$mcast_rate" ] && {
@@ -1623,10 +1586,36 @@ network={
$scan_ssid
ssid="$ssid"
key_mgmt=$key_mgmt
sae_pwe=$sae_pwe
$network_data
}
EOF
fi
return 0
}
wpa_supplicant_run() {
local ifname="$1"
local hostapd_ctrl="$2"
_wpa_supplicant_common "$ifname"
ubus wait_for wpa_supplicant
local supplicant_res="$(ubus call wpa_supplicant config_add "{ \
\"driver\": \"${_w_driver:-wext}\", \"ctrl\": \"$_rpath\", \
\"iface\": \"$ifname\", \"config\": \"$_config\" \
${network_bridge:+, \"bridge\": \"$network_bridge\"} \
${hostapd_ctrl:+, \"hostapd_ctrl\": \"$hostapd_ctrl\"} \
}")"
ret="$?"
[ "$ret" != 0 -o -z "$supplicant_res" ] && wireless_setup_vif_failed WPA_SUPPLICANT_FAILED
wireless_add_process "$(jsonfilter -s "$supplicant_res" -l 1 -e @.pid)" "/usr/sbin/wpa_supplicant" 1 1
return $ret
}
hostapd_common_cleanup() {
killall meshd-nl80211
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,17 +1,5 @@
config radius
option disabled '1'
option ipv6 '1'
# Logging levels:
# 0: ALL
# 1: MSGDUMP
# 2: DEBUG
# 3: INFO
# 4: WARNING
# 5: ERROR
# Default: INFO
option log_level '3'
option ca_cert '/etc/radius/ca.pem'
option cert '/etc/radius/cert.pem'
option key '/etc/radius/key.pem'

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