Implement wpa_supplicant backend
This commit is contained in:
parent
79c28da9c5
commit
04ada45f44
7 changed files with 874 additions and 2 deletions
236
internal/wifi/wpasupplicant/signals.go
Normal file
236
internal/wifi/wpasupplicant/signals.go
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
package wpasupplicant
|
||||
|
||||
import (
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
"github.com/godbus/dbus/v5"
|
||||
"github.com/nemunaire/repeater/internal/wifi/backend"
|
||||
)
|
||||
|
||||
// SignalMonitor monitors D-Bus signals from wpa_supplicant
|
||||
type SignalMonitor struct {
|
||||
conn *dbus.Conn
|
||||
iface *WPAInterface
|
||||
callbacks backend.EventCallbacks
|
||||
|
||||
// Signal channel
|
||||
signalChan chan *dbus.Signal
|
||||
|
||||
// Control
|
||||
stopChan chan struct{}
|
||||
mu sync.RWMutex
|
||||
running bool
|
||||
|
||||
// State tracking
|
||||
lastState WPAState
|
||||
}
|
||||
|
||||
// NewSignalMonitor creates a new signal monitor
|
||||
func NewSignalMonitor(conn *dbus.Conn, iface *WPAInterface) *SignalMonitor {
|
||||
return &SignalMonitor{
|
||||
conn: conn,
|
||||
iface: iface,
|
||||
signalChan: make(chan *dbus.Signal, 100),
|
||||
stopChan: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
// Start begins monitoring D-Bus signals
|
||||
func (sm *SignalMonitor) Start(callbacks backend.EventCallbacks) error {
|
||||
sm.mu.Lock()
|
||||
if sm.running {
|
||||
sm.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
sm.running = true
|
||||
sm.callbacks = callbacks
|
||||
sm.mu.Unlock()
|
||||
|
||||
interfacePath := sm.iface.GetPath()
|
||||
|
||||
// Add signal match for PropertiesChanged on Interface
|
||||
matchOptions := []dbus.MatchOption{
|
||||
dbus.WithMatchObjectPath(interfacePath),
|
||||
dbus.WithMatchInterface("org.freedesktop.DBus.Properties"),
|
||||
dbus.WithMatchMember("PropertiesChanged"),
|
||||
}
|
||||
|
||||
if err := sm.conn.AddMatchSignal(matchOptions...); err != nil {
|
||||
sm.mu.Lock()
|
||||
sm.running = false
|
||||
sm.mu.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
// Add signal match for ScanDone
|
||||
scanDoneOptions := []dbus.MatchOption{
|
||||
dbus.WithMatchObjectPath(interfacePath),
|
||||
dbus.WithMatchInterface(InterfaceInterface),
|
||||
dbus.WithMatchMember("ScanDone"),
|
||||
}
|
||||
|
||||
if err := sm.conn.AddMatchSignal(scanDoneOptions...); err != nil {
|
||||
sm.mu.Lock()
|
||||
sm.running = false
|
||||
sm.mu.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
// Register signal channel
|
||||
sm.conn.Signal(sm.signalChan)
|
||||
|
||||
// Get initial state
|
||||
state, err := sm.iface.GetState()
|
||||
if err == nil {
|
||||
sm.lastState = state
|
||||
}
|
||||
|
||||
// Start monitoring goroutine
|
||||
go sm.monitor()
|
||||
|
||||
log.Printf("D-Bus signal monitoring started for wpa_supplicant interface %s", interfacePath)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop stops monitoring D-Bus signals
|
||||
func (sm *SignalMonitor) Stop() {
|
||||
sm.mu.Lock()
|
||||
if !sm.running {
|
||||
sm.mu.Unlock()
|
||||
return
|
||||
}
|
||||
sm.running = false
|
||||
sm.mu.Unlock()
|
||||
|
||||
// Signal stop
|
||||
close(sm.stopChan)
|
||||
|
||||
// Remove signal channel
|
||||
sm.conn.RemoveSignal(sm.signalChan)
|
||||
|
||||
log.Printf("D-Bus signal monitoring stopped for wpa_supplicant")
|
||||
}
|
||||
|
||||
// monitor is the main signal processing loop
|
||||
func (sm *SignalMonitor) monitor() {
|
||||
for {
|
||||
select {
|
||||
case sig := <-sm.signalChan:
|
||||
sm.handleSignal(sig)
|
||||
case <-sm.stopChan:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handleSignal processes a D-Bus signal
|
||||
func (sm *SignalMonitor) handleSignal(sig *dbus.Signal) {
|
||||
// Handle ScanDone signal
|
||||
if sig.Name == InterfaceInterface+".ScanDone" {
|
||||
sm.handleScanDone(sig)
|
||||
return
|
||||
}
|
||||
|
||||
// Handle PropertiesChanged signals
|
||||
if sig.Name != "org.freedesktop.DBus.Properties.PropertiesChanged" {
|
||||
return
|
||||
}
|
||||
|
||||
// Verify signal is from Interface
|
||||
if len(sig.Body) < 2 {
|
||||
return
|
||||
}
|
||||
|
||||
interfaceName, ok := sig.Body[0].(string)
|
||||
if !ok || interfaceName != InterfaceInterface {
|
||||
return
|
||||
}
|
||||
|
||||
// Parse changed properties
|
||||
changedProps, ok := sig.Body[1].(map[string]dbus.Variant)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
// Check for State property change
|
||||
if stateVariant, ok := changedProps["State"]; ok {
|
||||
if state, ok := stateVariant.Value().(string); ok {
|
||||
sm.handleStateChange(WPAState(state))
|
||||
}
|
||||
}
|
||||
|
||||
// Check for CurrentBSS property change (connection status)
|
||||
if _, ok := changedProps["CurrentBSS"]; ok {
|
||||
// BSS changed, trigger state update
|
||||
sm.handleConnectionChange()
|
||||
}
|
||||
}
|
||||
|
||||
// handleStateChange processes a state change
|
||||
func (sm *SignalMonitor) handleStateChange(state WPAState) {
|
||||
sm.lastState = state
|
||||
|
||||
sm.mu.RLock()
|
||||
callback := sm.callbacks.OnStateChange
|
||||
sm.mu.RUnlock()
|
||||
|
||||
if callback == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Map wpa_supplicant state to backend state
|
||||
backendState := mapWPAState(state)
|
||||
|
||||
// Get connected SSID if connected
|
||||
ssid := ""
|
||||
if backendState == backend.StateConnected {
|
||||
if bssPath, err := sm.iface.GetCurrentBSS(); err == nil && bssPath != "/" {
|
||||
bss := NewBSS(sm.conn, bssPath)
|
||||
if ssidStr, err := bss.GetSSIDString(); err == nil {
|
||||
ssid = ssidStr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
callback(backendState, ssid)
|
||||
}
|
||||
|
||||
// handleConnectionChange processes connection changes
|
||||
func (sm *SignalMonitor) handleConnectionChange() {
|
||||
// Get current state and trigger state change callback
|
||||
state, err := sm.iface.GetState()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
sm.handleStateChange(state)
|
||||
}
|
||||
|
||||
// handleScanDone processes scan completion
|
||||
func (sm *SignalMonitor) handleScanDone(sig *dbus.Signal) {
|
||||
sm.mu.RLock()
|
||||
callback := sm.callbacks.OnScanComplete
|
||||
sm.mu.RUnlock()
|
||||
|
||||
if callback != nil {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
// mapWPAState maps wpa_supplicant states to backend-agnostic states
|
||||
func mapWPAState(state WPAState) backend.ConnectionState {
|
||||
switch state {
|
||||
case StateCompleted:
|
||||
return backend.StateConnected
|
||||
case StateAuthenticating, StateAssociating, StateAssociated, State4WayHandshake, StateGroupHandshake:
|
||||
return backend.StateConnecting
|
||||
case StateDisconnected, StateInactive, StateInterfaceDisabled:
|
||||
return backend.StateDisconnected
|
||||
case StateScanning:
|
||||
// Keep as disconnected if just scanning
|
||||
return backend.StateDisconnected
|
||||
default:
|
||||
return backend.StateDisconnected
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue