Merge branch 'feature/uciClient' into develop

This commit is contained in:
Philippe Caseiro 2018-09-21 16:05:16 +02:00
commit a44e40eea2
16 changed files with 1022 additions and 0 deletions

38
openwrt/dhcp_client.go Normal file
View File

@ -0,0 +1,38 @@
package openwrt
// DhcpClient represents a dhcp client ... :)
type DhcpClient struct {
exec Executor
iface string
}
// NewDhcpClient return an UCI instance to interact with UCI
func NewDhcpClient(netIface string) *DhcpClient {
exec := &localExecutor{}
iface := netIface
return &DhcpClient{exec, iface}
}
// NewDhcpClientWithExecutor return an UCI instance to interact with UCI
func NewDhcpClientWithExecutor(netIface string, exe Executor) *DhcpClient {
exec := exe
iface := netIface
return &DhcpClient{exec, iface}
}
// NewDhcpClient return an UCI instance to interact with UCI
//func NewDhcpClient(netIface string, exe Executor) *DhcpClient {
// var exec Executor
// if exe == nil {
// exec = &localExecutor{}
// } else {
// exec = exe
// }
// iface := netIface
// return &DhcpClient{exec, iface}
//}
// AskForIP runs a dhclient ip request with udhcpc
func (dc *DhcpClient) AskForIP() *CommandResult {
return dc.exec.Run("udhcpc", "-i", dc.iface)
}

View File

@ -0,0 +1,12 @@
package openwrt
import "testing"
func TestDhcpClientAskForIP(t *testing.T) {
uexec := createMockExecutor("", "", 0)
dhc := NewDhcpClientWithExecutor("wlan1", uexec)
res := dhc.AskForIP()
if res.ReturnCode != 0 {
t.Error("Error in DHCP Client !!")
}
}

67
openwrt/executor.go Normal file
View File

@ -0,0 +1,67 @@
package openwrt
import (
"bytes"
"fmt"
"log"
"os/exec"
"syscall"
)
// Executor interface to describe command runners signature
type Executor interface {
Run(command string, params ...string) *CommandResult
}
// CommandResult contain all information about a command execution, stdout, stderr
type CommandResult struct {
Stdout string
Stderr string
ReturnCode int
}
type localExecutor struct{}
func (e *localExecutor) Run(command string, params ...string) *CommandResult {
var out bytes.Buffer
var stderr bytes.Buffer
var exitCode int
defaultFailedCode := 255
exe := exec.Command(command, params...)
exe.Stdout = &out
exe.Stderr = &stderr
err := exe.Run()
if err != nil {
if exitError, ok := err.(*exec.ExitError); ok {
ws := exitError.Sys().(syscall.WaitStatus)
exitCode = ws.ExitStatus()
} else {
// This will happen (in OSX) if `name` is not available in $PATH,
// in this situation, exit code could not be get, and stderr will be
// empty string very likely, so we use the default fail code, and format err
// to string and set to stderr
log.Printf("Could not get exit code for failed program: %v, %v", command, params)
exitCode = defaultFailedCode
}
fmt.Println(fmt.Sprint(err) + ": " + stderr.String())
log.Fatal(err)
}
if err != nil {
// try to get the exit code
} else {
// success, exitCode should be 0 if go is ok
ws := exe.ProcessState.Sys().(syscall.WaitStatus)
exitCode = ws.ExitStatus()
}
return &CommandResult{
Stdout: out.String(),
Stderr: stderr.String(),
ReturnCode: exitCode,
}
}

18
openwrt/executor_test.go Normal file
View File

@ -0,0 +1,18 @@
package openwrt
import (
"testing"
)
func TestRun(t *testing.T) {
exec := &localExecutor{}
res := exec.Run("uname", "-a")
if g, e := res.ReturnCode, 0; g != e {
t.Errorf("Run command failed ! Got bad return code [%d], [%d} is expected\n", g, e)
}
// res = exec.Run("noCommandWithThisNameExists", "-a")
// if g, e := res.ReturnCode, 127; g != e {
// t.Errorf("Run command failed ! Got bad return code [%d], [%d} is expected\n", g, e)
// }
}

77
openwrt/network.go Normal file
View File

@ -0,0 +1,77 @@
package openwrt
import (
"fmt"
"io/ioutil"
"net"
"strings"
)
// Network provides a representation of network
type Network struct {
exec Executor
}
// NewNetwork return an UCI instance to interact with UCI
func NewNetwork() *Network {
exec := &localExecutor{}
return &Network{exec}
}
// NewNetworkWithExecutor return an UCI instance to interact with UCI
func NewNetworkWithExecutor(exe Executor) *Network {
exec := exe
return &Network{exec}
}
// ListInterfaces list all available interfaces on a system using "ip" commmand
func (n *Network) ListInterfaces() []net.Interface {
var result []net.Interface
ifaces, err := net.Interfaces()
if err != nil {
fmt.Print(fmt.Errorf("error listing network interfacess: %+v", err.Error()))
return nil
}
result = append(result, ifaces...)
return result
}
// ListWirelessInterfaces list all wifi cards
// you need to provide the wireless file or "" to use
// Linux default one "/proc/net/wireless"
func (n *Network) ListWirelessInterfaces(wifiFile string) []net.Interface {
var result []net.Interface
var ifaceNames []string
if wifiFile == "" {
wifiFile = "/proc/net/wireless"
}
wifiFileContent, err := ioutil.ReadFile(wifiFile)
check(err)
index := 0
for _, line := range strings.Split(string(wifiFileContent), "\n") {
if index < 2 {
index++
continue
} else {
name := strings.Split(line, ":")[0]
ifaceNames = append(ifaceNames, name)
}
}
ifaces, err := net.Interfaces()
if err != nil {
fmt.Print(fmt.Errorf("error listing network interfaces : %+v", err.Error()))
return nil
}
for _, i := range ifaces {
for _, name := range ifaceNames {
if name == i.Name {
result = append(result, i)
}
}
}
return result
}

22
openwrt/network_test.go Normal file
View File

@ -0,0 +1,22 @@
package openwrt
import (
"fmt"
"testing"
)
func TestNetworkListInterfaces(t *testing.T) {
net := NewNetwork()
iface := net.ListInterfaces()
for _, ife := range iface {
fmt.Printf("%s\n", ife.Name)
}
}
func TestListWirelessInterfaces(t *testing.T) {
net := NewNetwork()
res := net.ListWirelessInterfaces("./testdata/proc_net_wireless.txt")
for _, el := range res {
fmt.Printf("%s\n", el.Name)
}
}

35
openwrt/test.go Normal file
View File

@ -0,0 +1,35 @@
package openwrt
import (
"log"
"strings"
)
func check(e error) {
if e != nil {
panic(e)
}
}
func createMockExecutor(stdout string, stderr string, returnCode int) Executor {
return &mockExecutor{
stdout: stdout,
stderr: stderr,
returnCode: returnCode,
}
}
type mockExecutor struct {
stdout string
stderr string
returnCode int
}
func (e *mockExecutor) Run(command string, params ...string) *CommandResult {
log.Printf("executing '%s %s'", command, strings.Join(params, " "))
return &CommandResult{
Stderr: e.stderr,
Stdout: e.stdout,
ReturnCode: e.returnCode,
}
}

View File

@ -0,0 +1,4 @@
Inter-| sta-| Quality | Discarded packets | Missed | WE
face | tus | link level noise | nwid crypt frag retry misc | beacon | 22
wlan1: 0000 0 0 0 0 0 0 0 0 0
wlan0: 0000 0 0 0 0 0 0 0 0 0

View File

@ -0,0 +1,17 @@
Cell 40 - Address: 68:A3:78:6E:D9:24
ESSID: "PyxisWifi"
Mode: Master Channel: 3
Signal: -90 dBm Quality: 20/70
Encryption: none
Cell 41 - Address: B0:39:56:92:59:E2
ESSID: "NET17"
Mode: Master Channel: 4
Signal: -88 dBm Quality: 22/70
Encryption: WPA2 PSK (CCMP)
Cell 42 - Address: 0C:F4:D5:16:AA:18
ESSID: "DIJON-METROPOLE-WIFI"
Mode: Master Channel: 13
Signal: -90 dBm Quality: 20/70
Encryption: none

View File

@ -0,0 +1,293 @@
Cell 01 - Address: 0C:8D:DB:C4:A0:34
ESSID: "pfPauvres"
Mode: Master Channel: 11
Signal: -50 dBm Quality: 60/70
Encryption: mixed WPA/WPA2 PSK (TKIP, CCMP)
Cell 02 - Address: 40:5A:9B:ED:BA:F0
ESSID: "Cadoles"
Mode: Master Channel: 6
Signal: -36 dBm Quality: 70/70
Encryption: mixed WPA/WPA2 PSK (TKIP, CCMP)
Cell 03 - Address: A0:04:60:B2:8A:C8
ESSID: "Cadoles Formations (N)"
Mode: Master Channel: 13
Signal: -32 dBm Quality: 70/70
Encryption: WPA2 PSK (CCMP)
Cell 04 - Address: B0:39:56:D8:38:ED
ESSID: "Frate Dijon EXT"
Mode: Master Channel: 11
Signal: -57 dBm Quality: 53/70
Encryption: WPA2 PSK (CCMP)
Cell 05 - Address: 00:A6:CA:10:DF:00
ESSID: unknown
Mode: Master Channel: 6
Signal: -80 dBm Quality: 30/70
Encryption: WPA2 802.1X (CCMP)
Cell 06 - Address: AC:84:C9:2F:59:6E
ESSID: "Livebox-596a"
Mode: Master Channel: 1
Signal: -62 dBm Quality: 48/70
Encryption: mixed WPA/WPA2 PSK (TKIP, CCMP)
Cell 07 - Address: 00:A6:CA:10:DF:01
ESSID: "EFF-Mobility"
Mode: Master Channel: 6
Signal: -74 dBm Quality: 36/70
Encryption: WPA2 PSK (CCMP)
Cell 08 - Address: A0:1B:29:BE:98:26
ESSID: "Livebox-9822"
Mode: Master Channel: 6
Signal: -81 dBm Quality: 29/70
Encryption: mixed WPA/WPA2 PSK (TKIP, CCMP)
Cell 09 - Address: 7C:26:64:66:CC:44
ESSID: "Livebox-32c8"
Mode: Master Channel: 1
Signal: -74 dBm Quality: 36/70
Encryption: mixed WPA/WPA2 PSK (TKIP, CCMP)
Cell 10 - Address: 00:A6:CA:10:DF:02
ESSID: "Keo-HotSpot"
Mode: Master Channel: 6
Signal: -79 dBm Quality: 31/70
Encryption: none
Cell 11 - Address: 7E:26:64:66:CC:44
ESSID: "orange"
Mode: Master Channel: 1
Signal: -73 dBm Quality: 37/70
Encryption: none
Cell 12 - Address: 3C:52:82:FC:5E:21
ESSID: "DIRECT-20-HP DeskJet 3630 series"
Mode: Master Channel: 6
Signal: -78 dBm Quality: 32/70
Encryption: WPA2 PSK (CCMP)
Cell 13 - Address: E4:9E:12:8B:EF:73
ESSID: "Freebox-8BEF72"
Mode: Master Channel: 9
Signal: -79 dBm Quality: 31/70
Encryption: WPA2 PSK (CCMP)
Cell 14 - Address: 40:4A:03:05:D2:68
ESSID: "ZyXEL"
Mode: Master Channel: 11
Signal: -71 dBm Quality: 39/70
Encryption: WPA2 PSK (CCMP)
Cell 15 - Address: 5C:C3:07:7E:39:D4
ESSID: "pfP Xa"
Mode: Master Channel: 1
Signal: -65 dBm Quality: 45/70
Encryption: WPA2 PSK (CCMP)
Cell 16 - Address: AC:84:C9:1D:C6:7C
ESSID: "Frate Djon"
Mode: Master Channel: 1
Signal: -79 dBm Quality: 31/70
Encryption: mixed WPA/WPA2 PSK (TKIP, CCMP)
Cell 17 - Address: 00:17:33:9F:4D:80
ESSID: "NEUF_4D7C"
Mode: Master Channel: 11
Signal: -83 dBm Quality: 27/70
Encryption: WPA PSK (TKIP, CCMP)
Cell 18 - Address: A2:17:33:9F:4D:81
ESSID: "SFR WiFi FON"
Mode: Master Channel: 11
Signal: -85 dBm Quality: 25/70
Encryption: none
Cell 19 - Address: BC:F6:85:FE:6D:46
ESSID: "Dlink"
Mode: Master Channel: 12
Signal: -70 dBm Quality: 40/70
Encryption: WPA2 PSK (CCMP)
Cell 20 - Address: 30:7C:B2:D1:0B:0D
ESSID: "Livebox-0b09"
Mode: Master Channel: 11
Signal: -81 dBm Quality: 29/70
Encryption: mixed WPA/WPA2 PSK (TKIP, CCMP)
Cell 21 - Address: A2:17:33:9F:4D:83
ESSID: "SFR WiFi Mobile"
Mode: Master Channel: 11
Signal: -85 dBm Quality: 25/70
Encryption: WPA2 802.1X (CCMP)
Cell 22 - Address: 90:4D:4A:F7:B9:70
ESSID: "Livebox-B970"
Mode: Master Channel: 11
Signal: -84 dBm Quality: 26/70
Encryption: WPA2 PSK (CCMP)
Cell 23 - Address: 90:4D:4A:F7:B9:71
ESSID: "orange"
Mode: Master Channel: 11
Signal: -89 dBm Quality: 21/70
Encryption: none
Cell 24 - Address: 00:22:6B:86:5B:71
ESSID: "linksys"
Mode: Master Channel: 11
Signal: -86 dBm Quality: 24/70
Encryption: mixed WPA/WPA2 PSK (TKIP, CCMP)
Cell 25 - Address: 68:A3:78:6E:D9:25
ESSID: "FreeWifi_secure"
Mode: Master Channel: 3
Signal: -86 dBm Quality: 24/70
Encryption: WPA2 802.1X (TKIP, CCMP)
Cell 26 - Address: 6C:38:A1:62:1B:28
ESSID: "Bbox-1B7889A9"
Mode: Master Channel: 1
Signal: -90 dBm Quality: 20/70
Encryption: mixed WPA/WPA2 PSK (CCMP)
Cell 27 - Address: 78:81:02:5E:B7:14
ESSID: "Livebox-B714"
Mode: Master Channel: 6
Signal: -86 dBm Quality: 24/70
Encryption: WPA2 PSK (CCMP)
Cell 28 - Address: F4:CA:E5:98:3B:DC
ESSID: "Freebox-5D2400"
Mode: Master Channel: 11
Signal: -84 dBm Quality: 26/70
Encryption: WPA PSK (CCMP)
Cell 29 - Address: 8C:DC:D4:93:69:17
ESSID: "HP-Print-17-Photosmart 5520"
Mode: Master Channel: 11
Signal: -87 dBm Quality: 23/70
Encryption: none
Cell 30 - Address: 44:CE:7D:20:5C:A4
ESSID: "SFR_5CA0"
Mode: Master Channel: 6
Signal: -86 dBm Quality: 24/70
Encryption: WPA PSK (TKIP, CCMP)
Cell 31 - Address: F4:CA:E5:98:3B:DE
ESSID: "FreeWifi_secure"
Mode: Master Channel: 11
Signal: -72 dBm Quality: 38/70
Encryption: WPA2 802.1X (TKIP, CCMP)
Cell 32 - Address: 70:0B:01:C0:B3:E0
ESSID: "Livebox-B3E0"
Mode: Master Channel: 11
Signal: -80 dBm Quality: 30/70
Encryption: WPA2 PSK (CCMP)
Cell 33 - Address: D2:CE:7D:20:5C:A7
ESSID: "SFR WiFi Mobile"
Mode: Master Channel: 6
Signal: -85 dBm Quality: 25/70
Encryption: WPA2 802.1X (CCMP)
Cell 34 - Address: 68:A3:78:0D:B6:51
ESSID: "Freebox-0DB650"
Mode: Master Channel: 1
Signal: -92 dBm Quality: 18/70
Encryption: WPA2 PSK (CCMP)
Cell 35 - Address: F8:AB:05:1D:6A:E0
ESSID: "Bbox-8CE43C68"
Mode: Master Channel: 6
Signal: -88 dBm Quality: 22/70
Encryption: mixed WPA/WPA2 PSK (CCMP)
Cell 36 - Address: F4:CA:E5:98:3B:DD
ESSID: "FreeWifi"
Mode: Master Channel: 11
Signal: -87 dBm Quality: 23/70
Encryption: none
Cell 37 - Address: 14:0C:76:79:C0:D9
ESSID: "freebox_ZFSFUA"
Mode: Master Channel: 4
Signal: -88 dBm Quality: 22/70
Encryption: WPA PSK (TKIP, CCMP)
Cell 38 - Address: 68:15:90:36:63:60
ESSID: "Livebox-6360"
Mode: Master Channel: 1
Signal: -81 dBm Quality: 29/70
Encryption: mixed WPA/WPA2 PSK (TKIP, CCMP)
Cell 39 - Address: 64:7C:34:29:2B:7C
ESSID: "Bbox-D646CB51"
Mode: Master Channel: 1
Signal: -90 dBm Quality: 20/70
Encryption: mixed WPA/WPA2 PSK (CCMP)
Cell 40 - Address: 68:A3:78:6E:D9:24
ESSID: "FreeWifi"
Mode: Master Channel: 3
Signal: -90 dBm Quality: 20/70
Encryption: none
Cell 41 - Address: B0:39:56:92:59:E2
ESSID: "NETGEAR17"
Mode: Master Channel: 4
Signal: -88 dBm Quality: 22/70
Encryption: WPA2 PSK (CCMP)
Cell 42 - Address: 0C:F4:D5:16:AA:18
ESSID: "DIJON-METROPOLE-WIFI"
Mode: Master Channel: 13
Signal: -90 dBm Quality: 20/70
Encryption: none
Cell 43 - Address: D2:CE:7D:20:5C:A5
ESSID: "SFR WiFi FON"
Mode: Master Channel: 6
Signal: -81 dBm Quality: 29/70
Encryption: none
Cell 44 - Address: 34:27:92:42:CD:72
ESSID: "Freebox-42CD71"
Mode: Master Channel: 8
Signal: -88 dBm Quality: 22/70
Encryption: WPA2 PSK (CCMP)
Cell 45 - Address: 72:5D:51:78:4C:87
ESSID: "SFR WiFi FON"
Mode: Master Channel: 11
Signal: -87 dBm Quality: 23/70
Encryption: none
Cell 46 - Address: 68:A3:78:6E:D9:23
ESSID: "Freebox-6ED922"
Mode: Master Channel: 3
Signal: -76 dBm Quality: 34/70
Encryption: WPA2 PSK (CCMP)
Cell 47 - Address: 00:19:70:4F:DE:F2
ESSID: "Livebox-45cc"
Mode: Master Channel: 6
Signal: -78 dBm Quality: 32/70
Encryption: mixed WPA/WPA2 PSK (TKIP, CCMP)
Cell 48 - Address: AC:84:C9:CC:AE:90
ESSID: "Livebox-AE90"
Mode: Master Channel: 11
Signal: -81 dBm Quality: 29/70
Encryption: WPA2 PSK (CCMP)
Cell 49 - Address: 00:07:7D:89:81:B0
ESSID: "orange"
Mode: Master Channel: 6
Signal: -85 dBm Quality: 25/70
Encryption: none

72
openwrt/uci.go Normal file
View File

@ -0,0 +1,72 @@
package openwrt
import (
"fmt"
"time"
)
// Action is the result of an UCI action output and return code
type Action struct {
*CommandResult
}
// UCI "Object"
type UCI struct {
exec Executor
}
// NewUCI return an UCI instance to interact with UCI
func NewUCI() *UCI {
exec := &localExecutor{}
return &UCI{exec}
}
// NewUCIWithExecutor returns a UCI Instance an gives you the ability to provide
// a different command executor than the default one.
func NewUCIWithExecutor(exec Executor) *UCI {
return &UCI{exec}
}
// uciRun, private method to run the UCI command
func (u *UCI) uciRun(uciAction string, param string) *Action {
cmd := "uci"
res := u.exec.Run(cmd, uciAction, param)
return &Action{res}
}
// Add add an entry to UCI configuration, specify the Module and the value
func (u *UCI) Add(module string, name string) *Action {
commandRes := u.exec.Run("uci add", module, name)
return &Action{commandRes}
}
// Delete delete an entry from UCI configuration specify the entry name
func (u *UCI) Delete(entry string) *Action {
return u.uciRun("delete", entry)
}
// Set set a value ton an UCI configuration entry
func (u *UCI) Set(entry string, value string) *Action {
return u.uciRun("set", fmt.Sprintf("%s=%s", entry, value))
}
// Commit the recent actions to UCI
func (u *UCI) Commit() *Action {
return u.uciRun("commit", "")
}
// Reload reload uci configuration
func (u *UCI) Reload() *Action {
cmdResult := u.exec.Run("reload_config")
time.Sleep(5 * time.Second)
return &Action{cmdResult}
}
// AddWireless Create a new Wireless entry in UCI configuration
func (u *UCI) AddWireless(name string) *Action {
res := u.Add("wireless", name)
return res
}

91
openwrt/uci_test.go Normal file
View File

@ -0,0 +1,91 @@
package openwrt
import (
"fmt"
"testing"
)
func TestUCIAdd(t *testing.T) {
exec := createMockExecutor("", "", 0)
uci := NewUCIWithExecutor(exec)
res := uci.Add("wireless", "test")
if res.ReturnCode != 0 {
t.Error("Bad Return Code !")
}
if res.Stdout != "" {
fmt.Printf("[%s] - ", res.Stdout)
t.Error("Stdout is not empty ...")
}
if res.Stderr != "" {
fmt.Printf("[%s] - ", res.Stdout)
t.Error("Stderr is not empty ...")
}
}
func TestUCIDelete(t *testing.T) {
exec := createMockExecutor("", "", 0)
uci := NewUCIWithExecutor(exec)
res := uci.Delete("wireless.@wifi-iface[1]")
if res.ReturnCode != 0 {
t.Error("Bad Return Code !")
}
if res.Stdout != "" {
fmt.Printf("[%s] - ", res.Stdout)
t.Error("Stdout is not empty ...")
}
if res.Stderr != "" {
fmt.Printf("[%s] - ", res.Stdout)
t.Error("Stderr is not empty ...")
}
}
func TestUCISet(t *testing.T) {
exec := createMockExecutor("", "", 0)
uci := NewUCIWithExecutor(exec)
res := uci.Set("wireless.@wifi-iface[1].network", "OrionNetwork")
if res.ReturnCode != 0 {
t.Error("Bad Return Code !")
}
if res.Stdout != "" {
fmt.Printf("[%s] - ", res.Stdout)
t.Error("Stdout is not empty ...")
}
if res.Stderr != "" {
fmt.Printf("[%s] - ", res.Stdout)
t.Error("Stderr is not empty ...")
}
}
func TestUCICommit(t *testing.T) {
exec := createMockExecutor("", "", 0)
uci := NewUCIWithExecutor(exec)
res := uci.Commit()
if res.ReturnCode != 0 {
t.Error("Bad Return Code !")
}
if res.Stdout != "" {
fmt.Printf("[%s] - ", res.Stdout)
t.Error("Stdout is not empty ...")
}
if res.Stderr != "" {
fmt.Printf("[%s] - ", res.Stdout)
t.Error("Stderr is not empty ...")
}
}
func TestUCIReload(t *testing.T) {
exec := createMockExecutor("", "", 0)
uci := NewUCIWithExecutor(exec)
res := uci.Reload()
if res.ReturnCode != 0 {
t.Error("Bad Return Code !")
}
if res.Stdout != "" {
fmt.Printf("[%s] - ", res.Stdout)
t.Error("Stdout is not empty ...")
}
if res.Stderr != "" {
fmt.Printf("[%s] - ", res.Stdout)
t.Error("Stderr is not empty ...")
}
}

91
openwrt/wifi.go Normal file
View File

@ -0,0 +1,91 @@
package openwrt
import (
"log"
"strings"
"time"
)
// Wifi gives access to al OpenWRT Wifi operations
type Wifi struct {
exec Executor
iface string
Cells []*WifiCell
}
// NewWifi return an UCI instance to interact with UCI
func NewWifi(wIface string) *Wifi {
exec := &localExecutor{}
iface := wIface
return &Wifi{exec, iface, nil}
}
// NewWifiWithExecutor returns a Wifi Instance an gives you the ability to provide
// a different command executor than the default one.
func NewWifiWithExecutor(exec Executor, wIface string) *Wifi {
return &Wifi{exec, wIface, nil}
}
func (w *Wifi) getEncryption(line string) string {
enc := "unkn"
if strings.Contains(line, "WPA2 PSK") {
enc = "psk"
} else if strings.Contains(line, "none") {
enc = "none"
}
return enc
}
func (w *Wifi) parseWifiCells(stdout string) int {
new := false
mac, ssid, enc := "", "", ""
for _, line := range strings.Split(strings.TrimSuffix(stdout, "\n"), "\n") {
if strings.HasPrefix(line, "Cell") && new == false {
new = true
mac = strings.Split(line, " ")[4]
}
if strings.Contains(line, "ESSID:") {
ssid = strings.Split(line, " ")[1]
ssid = strings.Trim(ssid, "\"")
}
if strings.Contains(line, "Encryption:") {
enc = w.getEncryption(line)
}
if len(mac) > 0 && len(ssid) > 0 && len(enc) > 0 {
cell := NewWifiCell(ssid, mac, enc)
w.Cells = append(w.Cells, cell)
ssid, mac, enc = "", "", ""
new = false
}
}
return 0
}
// GetWifiCells retrieves all availabe wifi cells for a card !
func (w *Wifi) GetWifiCells() int {
res := w.exec.Run("iwinfo", w.iface, "scan")
if res.ReturnCode != 0 {
log.Fatal(res.Stderr)
return res.ReturnCode
}
for res.Stdout == "Scanning not possible" {
time.Sleep(time.Second)
res = w.exec.Run("iwinfo", w.iface, "scan")
if res.ReturnCode != 0 {
log.Fatal(res.Stderr)
return res.ReturnCode
}
}
return w.parseWifiCells(res.Stdout)
}
// GetCell retreives an WifiCell by SSID provided in parameter
func (w *Wifi) GetCell(ssid string) *WifiCell {
for _, v := range w.Cells {
if v.Ssid == ssid {
return v
}
}
return nil
}

93
openwrt/wifi_cell.go Normal file
View File

@ -0,0 +1,93 @@
package openwrt
import "time"
// WifiCell reprensents wifi network Cell
type WifiCell struct {
Ssid string
MacAdress string
Encryption string
}
// NewWifiCell returns a new WifiCell object
func NewWifiCell(ssid string, mac string, encrypt string) *WifiCell {
return &WifiCell{
Ssid: ssid,
MacAdress: mac,
Encryption: encrypt,
}
}
func (cell *WifiCell) uciWifiConfigure(uci *UCI, secret string) *Action {
setRes := uci.Set("wireless.@wifi-iface[1].network", "PyxisNetwork")
if setRes.ReturnCode != 0 {
return setRes
}
setRes = uci.Set("wireless.@wifi-iface[1].ssid", cell.Ssid)
if setRes.ReturnCode != 0 {
return setRes
}
setRes = uci.Set("wireless.@wifi-iface[1].encryption", cell.Encryption)
if setRes.ReturnCode != 0 {
return setRes
}
setRes = uci.Set("wireless.@wifi-iface[1].device", "radio1")
if setRes.ReturnCode != 0 {
return setRes
}
setRes = uci.Set("wireless.@wifi-iface[1].mode", "sta")
if setRes.ReturnCode != 0 {
return setRes
}
setRes = uci.Set("wireless.@wifi-iface[1].bssid", cell.MacAdress)
if setRes.ReturnCode != 0 {
return setRes
}
setRes = uci.Set("wireless.@wifi-iface[1].key", secret)
if setRes.ReturnCode != 0 {
return setRes
}
return &Action{
&CommandResult{
Stdout: "",
Stderr: "",
ReturnCode: 0,
},
}
}
// Connect to wifi Cell
func (cell *WifiCell) Connect(uci *UCI, secret string) *Action {
delRes := uci.Delete("wireless.@wifi-iface[1]")
if delRes.ReturnCode != 0 {
return delRes
}
addRes := uci.AddWireless("wifi-iface")
if addRes.ReturnCode != 0 {
return addRes
}
setRes := cell.uciWifiConfigure(uci, secret)
if setRes.ReturnCode != 0 {
return setRes
}
setRes = uci.Commit()
if setRes.ReturnCode != 0 {
return setRes
}
setRes = uci.Reload()
if setRes.ReturnCode != 0 {
return setRes
}
time.Sleep(20 * time.Second)
return &Action{
&CommandResult{
Stdout: "",
Stderr: "",
ReturnCode: 0,
},
}
}

21
openwrt/wifi_cell_test.go Normal file
View File

@ -0,0 +1,21 @@
package openwrt
import "testing"
func TestWifiCellConnection(t *testing.T) {
uexec := createMockExecutor("", "", 0)
uci := NewUCIWithExecutor(uexec)
cellList := `Cell 40 - Address: 68:A3:78:6E:D9:24
ESSID: "PyxisWifi"
Mode: Master Channel: 3
Signal: -90 dBm Quality: 20/70
Encryption: WPA2 PSK (CCMP)`
exec := createMockExecutor(cellList, "", 0)
wifi := NewWifiWithExecutor(exec, "wlan1")
_ = wifi.GetWifiCells()
cell := wifi.GetCell("PyxisWifi")
cell.Connect(uci, "secret")
}

71
openwrt/wifi_test.go Normal file
View File

@ -0,0 +1,71 @@
package openwrt
import (
"fmt"
"io/ioutil"
"testing"
)
// Test GestWifiCells method with 3 Cells
func TestGetWifiCells(t *testing.T) {
cellList, err := ioutil.ReadFile("testdata/wifi_cells_output_3.txt")
if err != nil {
t.Fatal(err)
}
exec := createMockExecutor(string(cellList), "", 0)
wifi := NewWifiWithExecutor(exec, "wlan1")
_ = wifi.GetWifiCells()
if len(wifi.Cells) != 3 {
fmt.Printf("Size of wifi.Cells is %d and not 3 !!!\n", len(wifi.Cells))
t.Error("Cell list is empty ... This can not append !! Fix your code Dummy !")
}
if g, e := wifi.Cells[0].Ssid, "PyxisWifi"; g != e {
t.Errorf("The first Cell have a bad SSID !\n %s is expected and we have %s", e, g)
}
if g, e := wifi.Cells[0].MacAdress, "68:A3:78:6E:D9:24"; g != e {
t.Errorf("The first Cell have a bad MAC !\n %s is expected and we have %s", e, g)
}
if g, e := wifi.Cells[0].Encryption, "none"; g != e {
t.Errorf("The first Cell have a bad Encryption!\n %s is expected and we have %s", e, g)
}
if g, e := wifi.Cells[1].Encryption, "psk"; g != e {
t.Errorf("The second Cell have a bad Encryption!\n %s is expected and we have %s", e, g)
}
if g, e := wifi.Cells[2].MacAdress, "0C:F4:D5:16:AA:18"; g != e {
t.Errorf("The last Cell have a bad MAC !\n %s is expected and we have %s", e, g)
}
}
// Test GestWifiCells method with empty list
func TestGetWifiCellsEmpty(t *testing.T) {
exec := createMockExecutor("", "", 0)
wifi := NewWifiWithExecutor(exec, "wlan1")
_ = wifi.GetWifiCells()
if len(wifi.Cells) != 0 {
fmt.Printf("Size of wifi.Cells is %d and not 0 !!!\n", len(wifi.Cells))
t.Error("Cell list is empty ... This can not append !! Fix your code Dummy !")
}
}
// Test GestWifiCells method with 3 Cells
func TestGetWifiCellsLarge(t *testing.T) {
cellList, err := ioutil.ReadFile("testdata/wifi_cells_output_large.txt")
if err != nil {
t.Fatal(err)
}
exec := createMockExecutor(string(cellList), "", 0)
wifi := NewWifiWithExecutor(exec, "wlan1")
_ = wifi.GetWifiCells()
if len(wifi.Cells) != 49 {
fmt.Printf("Size of wifi.Cells is %d and not 49 !!!\n", len(wifi.Cells))
t.Error("Cell list is empty ... This can not append !! Fix your code Dummy !")
}
}