diff --git a/network/net_linux.go b/network/net_linux.go index 7d817549..cf4cd40d 100644 --- a/network/net_linux.go +++ b/network/net_linux.go @@ -16,7 +16,6 @@ var IPv4RouteParser = regexp.MustCompile(`^(default|[0-9]+\.[0-9]+\.[0-9]+\.[0-9 var IPv4RouteTokens = 4 var IPv4RouteCmd = "ip" var IPv4RouteCmdOpts = []string{"route"} -var WiFiFreqParser = regexp.MustCompile(`^\s+Channel.([0-9]+)\s+:\s+([0-9\.]+)\s+GHz.*$`) func IPv4RouteIsGateway(ifname string, tokens []string, f func(gateway string) (*Endpoint, error)) (*Endpoint, error) { ifname2 := tokens[3] @@ -65,15 +64,20 @@ func SetInterfaceChannel(iface string, channel int) error { return nil } -func processSupportedFrequencies(output string, err error) ([]int, error) { - freqs := make([]int, 0) +var iwlistFreqParser = regexp.MustCompile(`^\s+Channel.([0-9]+)\s+:\s+([0-9\.]+)\s+GHz.*$`) + +func iwlistSupportedFrequencies(iface string) ([]int, error) { + out, err := core.Exec("iwlist", []string{iface, "freq"}) if err != nil { - return freqs, err - } else if output != "" { + return err + } + + freqs := make([]int, 0) + if output != "" { scanner := bufio.NewScanner(strings.NewReader(output)) for scanner.Scan() { line := scanner.Text() - matches := WiFiFreqParser.FindStringSubmatch(line) + matches := iwlistFreqParser.FindStringSubmatch(line) if len(matches) == 3 { if freq, err := strconv.ParseFloat(matches[2], 64); err == nil { freqs = append(freqs, int(freq*1000)) @@ -81,10 +85,65 @@ func processSupportedFrequencies(output string, err error) ([]int, error) { } } } + + return freqs, nil +} + +var iwPhyParser = regexp.MustCompile(`^\s*wiphy\s+(\d+)$`) +var iwFreqParser = regexp.MustCompile(`^\s+\*\s+(\d+)\s+MHz.+$`) + +func iwSupportedFrequencies(iface string) ([]int, error) { + // first determine phy index + out, err := core.Exec("iw", []string{iface, "info"}) + if err != nil { + return nil, fmt.Errorf("error getting %s phy index: %v", iface, err) + } + + phy := int64(-1) + scanner := bufio.NewScanner(strings.NewReader(out)) + for scanner.Scan() { + line := scanner.Text() + matches := iwPhyParser.FindStringSubmatch(line) + if len(matches) == 2 { + if phy, err = strconv.ParseInt(matches[1], 10, 32); err != nil { + return nil, fmt.Errorf("error parsing %s phy index: %v (line: %s)", iface, err, line) + } + } + } + + if phy == -1 { + return nil, fmt.Errorf("could not find %s phy index", iface) + } + + // then get phyN info + phyName := fmt.Sprintf("phy%d", phy) + out, err = core.Exec("iw", []string{phyName, "info"}) + if err != nil { + return nil, fmt.Errorf("error getting %s (%s) info: %v", phyName, iface, err) + } + + freqs := []int{} + scanner = bufio.NewScanner(strings.NewReader(out)) + for scanner.Scan() { + line := scanner.Text() + matches := iwFreqParser.FindStringSubmatch(line) + if len(matches) == 2 { + if freq, err := strconv.ParseInt(matches[1], 10, 64); err != nil { + return nil, fmt.Errorf("error parsing %s freq: %v (line: %s)", iface, err, line) + } else { + freqs = append(freqs, int(freq)) + } + } + } + return freqs, nil } func GetSupportedFrequencies(iface string) ([]int, error) { - out, err := core.Exec("iwlist", []string{iface, "freq"}) - return processSupportedFrequencies(out, err) + if core.HasBinary("iw") { + return iwSupportedFrequencies(iface) + } else if core.HasBinary("iwlist") { + return iwlistSupportedFrequencies(iface) + } + return fmt.Errorf("no iw or iwlist binaries found in $PATH") } diff --git a/network/net_linux_test.go b/network/net_linux_test.go index 01fa3f4e..56e12348 100644 --- a/network/net_linux_test.go +++ b/network/net_linux_test.go @@ -7,7 +7,7 @@ import ( ) func TestProcessSupportedFrequencies(t *testing.T) { - // Actually test processSupportedFrequencies; IO is lifted out. + // Actually test parseIWListFreqs; IO is lifted out. cases := []struct { Name string InputString string