package wpasupplicant import ( "fmt" "github.com/godbus/dbus/v5" ) // BSS represents a wpa_supplicant BSS (Basic Service Set) object type BSS struct { path dbus.ObjectPath conn *dbus.Conn obj dbus.BusObject } // BSSProperties holds the properties of a BSS type BSSProperties struct { SSID []byte BSSID []byte Signal int16 // Signal strength in dBm Frequency uint32 // Frequency in MHz Privacy bool // Whether encryption is enabled RSN map[string]dbus.Variant WPA map[string]dbus.Variant } // NewBSS creates a new BSS instance func NewBSS(conn *dbus.Conn, path dbus.ObjectPath) *BSS { return &BSS{ path: path, conn: conn, obj: conn.Object(Service, path), } } // GetProperties returns all properties of the BSS func (b *BSS) GetProperties() (*BSSProperties, error) { props := &BSSProperties{} // Get SSID if ssidProp, err := b.obj.GetProperty(BSSInterface + ".SSID"); err == nil { if ssid, ok := ssidProp.Value().([]byte); ok { props.SSID = ssid } } // Get BSSID if bssidProp, err := b.obj.GetProperty(BSSInterface + ".BSSID"); err == nil { if bssid, ok := bssidProp.Value().([]byte); ok { props.BSSID = bssid } } // Get Signal if signalProp, err := b.obj.GetProperty(BSSInterface + ".Signal"); err == nil { if signal, ok := signalProp.Value().(int16); ok { props.Signal = signal } } // Get Frequency if freqProp, err := b.obj.GetProperty(BSSInterface + ".Frequency"); err == nil { if freq, ok := freqProp.Value().(uint16); ok { props.Frequency = uint32(freq) } } // Get Privacy if privacyProp, err := b.obj.GetProperty(BSSInterface + ".Privacy"); err == nil { if privacy, ok := privacyProp.Value().(bool); ok { props.Privacy = privacy } } // Get RSN (WPA2) information if rsnProp, err := b.obj.GetProperty(BSSInterface + ".RSN"); err == nil { if rsn, ok := rsnProp.Value().(map[string]dbus.Variant); ok { props.RSN = rsn } } // Get WPA information if wpaProp, err := b.obj.GetProperty(BSSInterface + ".WPA"); err == nil { if wpa, ok := wpaProp.Value().(map[string]dbus.Variant); ok { props.WPA = wpa } } return props, nil } // GetSSIDString returns the SSID as a string func (b *BSS) GetSSIDString() (string, error) { prop, err := b.obj.GetProperty(BSSInterface + ".SSID") if err != nil { return "", fmt.Errorf("failed to get SSID property: %v", err) } ssid, ok := prop.Value().([]byte) if !ok { return "", fmt.Errorf("SSID property is not a byte array") } return string(ssid), nil } // GetBSSIDString returns the BSSID as a formatted MAC address string func (b *BSS) GetBSSIDString() (string, error) { prop, err := b.obj.GetProperty(BSSInterface + ".BSSID") if err != nil { return "", fmt.Errorf("failed to get BSSID property: %v", err) } bssid, ok := prop.Value().([]byte) if !ok || len(bssid) != 6 { return "", fmt.Errorf("BSSID property is not a valid MAC address") } return fmt.Sprintf("%02x:%02x:%02x:%02x:%02x:%02x", bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]), nil } // GetSignal returns the signal strength in dBm func (b *BSS) GetSignal() (int16, error) { prop, err := b.obj.GetProperty(BSSInterface + ".Signal") if err != nil { return 0, fmt.Errorf("failed to get Signal property: %v", err) } signal, ok := prop.Value().(int16) if !ok { return 0, fmt.Errorf("Signal property is not an int16") } return signal, nil } // DetermineSecurityType determines the security type based on BSS properties func (p *BSSProperties) DetermineSecurityType() string { // Check for WPA2 (RSN) - need to check if KeyMgmt has actual values if hasKeyManagement(p.RSN) { return "psk" } // Check for WPA if hasKeyManagement(p.WPA) { return "psk" } // Check for WEP (privacy but no WPA/RSN) if p.Privacy { return "wep" } // Open network return "open" } // hasKeyManagement checks if a WPA/RSN map contains actual key management methods func hasKeyManagement(secMap map[string]dbus.Variant) bool { if len(secMap) == 0 { return false } // Check if KeyMgmt field exists and has values if keyMgmtVariant, ok := secMap["KeyMgmt"]; ok { // KeyMgmt is an array of strings if keyMgmt, ok := keyMgmtVariant.Value().([]string); ok { return len(keyMgmt) > 0 } } return false }