diff --git a/unixgram.go b/unixgram.go index e2e9594..f2b016a 100644 --- a/unixgram.go +++ b/unixgram.go @@ -225,6 +225,18 @@ func (uc *unixgramConn) EnableNetwork(networkID int) error { return uc.runCommand(fmt.Sprintf("ENABLE_NETWORK %d", networkID)) } +func (uc *unixgramConn) DisableNetwork(networkID int) error { + return uc.runCommand(fmt.Sprintf("DISABLE_NETWORK %d", networkID)) +} + +func (uc *unixgramConn) RemoveNetwork(networkID int) error { + return uc.runCommand(fmt.Sprintf("REMOVE_NETWORK %d", networkID)) +} + +func (uc *unixgramConn) RemoveAllNetworks() error { + return uc.runCommand("REMOVE_NETWORK all") +} + func (uc *unixgramConn) SetNetwork(networkID int, variable string, value string) error { return uc.runCommand(fmt.Sprintf("SET_NETWORK %d %s \"%s\"", networkID, variable, value)) } @@ -233,6 +245,18 @@ func (uc *unixgramConn) SaveConfig() error { return uc.runCommand("SAVE_CONFIG") } +func (uc *unixgramConn) Reconfigure() error { + return uc.runCommand("RECONFIGURE") +} + +func (uc *unixgramConn) Reassociate() error { + return uc.runCommand("REASSOCIATE") +} + +func (uc *unixgramConn) Reconnect() error { + return uc.runCommand("RECONNECT") +} + func (uc *unixgramConn) Scan() error { return uc.runCommand("SCAN") } @@ -246,6 +270,15 @@ func (uc *unixgramConn) ScanResults() ([]ScanResult, []error) { return parseScanResults(bytes.NewBuffer(resp)) } +func (uc *unixgramConn) ListNetworks() ([]ConfiguredNetwork, error) { + resp, err := uc.cmd("LIST_NETWORKS") + if err != nil { + return nil, err + } + + return parseListNetworksResult(bytes.NewBuffer(resp)) +} + // runCommand is a wrapper around the uc.cmd command which makes sure the // command returned a successful (OK) response. func (uc *unixgramConn) runCommand(cmd string) error { @@ -261,6 +294,76 @@ func (uc *unixgramConn) runCommand(cmd string) error { return &ParseError{Line: string(resp)} } +func parseListNetworksResult(resp io.Reader) (res []ConfiguredNetwork, err error) { + s := bufio.NewScanner(resp) + if !s.Scan() { + return nil, &ParseError{} + } + + fmt.Println("Listing networks") + + networkIDCol, ssidCol, bssidCol, flagsCol, maxCol := -1, -1, -1, -1, -1 + fmt.Println(strings.Split(s.Text(), " / ")) + for n, col := range strings.Split(s.Text(), " / ") { + switch col { + case "network id": + networkIDCol = n + case "ssid": + ssidCol = n + case "bssid": + bssidCol = n + case "flags": + flagsCol = n + } + + maxCol = n + } + + fmt.Println(networkIDCol) + + for s.Scan() { + ln := s.Text() + fields := strings.Split(ln, "\t") + fmt.Println(fields) + if len(fields) < maxCol { + return nil, &ParseError{Line: ln} + } + + var networkID string + if networkIDCol != -1 { + networkID = fields[networkIDCol] + } + + var ssid string + if ssidCol != -1 { + ssid = fields[ssidCol] + } + + var bssid string + if bssidCol != -1 { + bssid = fields[bssidCol] + } + + var flags []string + if flagsCol != -1 { + if len(fields[flagsCol]) >= 2 && fields[flagsCol][0] == '[' && fields[flagsCol][len(fields[flagsCol])-1] == ']' { + flags = strings.Split(fields[flagsCol][1:len(fields[flagsCol])-1], "][") + } + } + + res = append(res, &configuredNetwork{ + networkID: networkID, + ssid: ssid, + bssid: bssid, + flags: flags, + }) + + // fmt.Println(res) + } + + return res, nil +} + // parseScanResults parses the SCAN_RESULTS output from wpa_supplicant. This // is split out from ScanResults() to make testing easier. func parseScanResults(resp io.Reader) (res []ScanResult, errs []error) { diff --git a/wpasupplicant.go b/wpasupplicant.go index 83c49aa..2b67ee3 100644 --- a/wpasupplicant.go +++ b/wpasupplicant.go @@ -120,6 +120,26 @@ func (r *scanResult) Frequency() int { return r.frequency } func (r *scanResult) RSSI() int { return r.rssi } func (r *scanResult) Flags() []string { return r.flags } +// ConfiguredNetwork is a configured network (from LIST_NETWORKS) +type ConfiguredNetwork interface { + NetworkID() string + SSID() string + BSSID() string + Flags() []string +} + +type configuredNetwork struct { + networkID string + ssid string + bssid string // Since bssid can be any + flags []string +} + +func (r *configuredNetwork) NetworkID() string { return r.networkID } +func (r *configuredNetwork) BSSID() string { return r.bssid } +func (r *configuredNetwork) SSID() string { return r.ssid } +func (r *configuredNetwork) Flags() []string { return r.flags } + // Conn is a connection to wpa_supplicant over one of its communication // channels. type Conn interface { @@ -138,9 +158,34 @@ type Conn interface { // EnableNetwork enables a network. Returns error if the command fails. EnableNetwork(int) error + // DisableNetwork disables a network. + DisableNetwork(int) error + + // RemoveNetwork removes a network from the configuration. + RemoveNetwork(int) error + + // RemoveAllNetworks removes all networks (basically running `REMOVE_NETWORK all`). + // Returns error if command fails. + RemoveAllNetworks() error + // SaveConfig stores the current network configuration to disk. SaveConfig() error + // Reconfigure sends a RECONFIGURE command to the wpa_supplicant. Returns error when + // command fails. + Reconfigure() error + + // Reassociate sends a REASSOCIATE command to the wpa_supplicant. Returns error when + // command fails. + Reassociate() error + + // Reconnect sends a RECONNECT command to the wpa_supplicant. Returns error when + // command fails. + Reconnect() error + + // ListNetworks returns the currently configured networks. + ListNetworks() ([]ConfiguredNetwork, error) + // Scan triggers a new scan. Returns error if the wpa_supplicant does not // return OK. Scan() error