From b70264bcf8c542bae9997a7aaf74e1ae14cede39 Mon Sep 17 00:00:00 2001 From: Matias Doyle Date: Tue, 5 Sep 2017 15:56:03 +0200 Subject: [PATCH 01/11] Expose more control interface commands --- unixgram.go | 41 +++++++++++++++++++++++++++++++++++++++++ wpasupplicant.go | 18 ++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/unixgram.go b/unixgram.go index e42e23c..e2e9594 100644 --- a/unixgram.go +++ b/unixgram.go @@ -211,6 +211,32 @@ func (uc *unixgramConn) Ping() error { return &ParseError{Line: string(resp)} } +func (uc *unixgramConn) AddNetwork() (int, error) { + resp, err := uc.cmd("ADD_NETWORK") + if err != nil { + return -1, err + } + + b := bytes.NewBuffer(resp) + return strconv.Atoi(strings.Trim(b.String(), "\n")) +} + +func (uc *unixgramConn) EnableNetwork(networkID int) error { + return uc.runCommand(fmt.Sprintf("ENABLE_NETWORK %d", networkID)) +} + +func (uc *unixgramConn) SetNetwork(networkID int, variable string, value string) error { + return uc.runCommand(fmt.Sprintf("SET_NETWORK %d %s \"%s\"", networkID, variable, value)) +} + +func (uc *unixgramConn) SaveConfig() error { + return uc.runCommand("SAVE_CONFIG") +} + +func (uc *unixgramConn) Scan() error { + return uc.runCommand("SCAN") +} + func (uc *unixgramConn) ScanResults() ([]ScanResult, []error) { resp, err := uc.cmd("SCAN_RESULTS") if err != nil { @@ -220,6 +246,21 @@ func (uc *unixgramConn) ScanResults() ([]ScanResult, []error) { return parseScanResults(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 { + resp, err := uc.cmd(cmd) + if err != nil { + return err + } + + if bytes.Compare(resp, []byte("OK\n")) == 0 { + return nil + } + + return &ParseError{Line: string(resp)} +} + // 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 5037268..83c49aa 100644 --- a/wpasupplicant.go +++ b/wpasupplicant.go @@ -127,6 +127,24 @@ type Conn interface { // responding. Ping() error + // AddNetwork creates an empty network configuration. Returns the network + // ID. + AddNetwork() (int, error) + + // SetNetwork configures a network property. Returns error if the property + // configuration failed. + SetNetwork(int, string, string) error + + // EnableNetwork enables a network. Returns error if the command fails. + EnableNetwork(int) error + + // SaveConfig stores the current network configuration to disk. + SaveConfig() error + + // Scan triggers a new scan. Returns error if the wpa_supplicant does not + // return OK. + Scan() error + // ScanResult returns the latest scanning results. It returns a slice // of scanned BSSs, and/or a slice of errors representing problems // communicating with wpa_supplicant or parsing its output. From 03f5226fe06f6cff752fc217ba4896df3d8b55b4 Mon Sep 17 00:00:00 2001 From: Matias Doyle Date: Wed, 6 Sep 2017 18:15:56 +0200 Subject: [PATCH 02/11] Add more commands (notably list_networks) Add method wrappers for commands: - DISABLE_NETWORK - REMOVE_NETWORK - REMOVE_NETWORK all (as separate method) - RECONFIGURE - REASSOCIATE - RECONNECT - LIST_NETWORKS --- unixgram.go | 103 +++++++++++++++++++++++++++++++++++++++++++++++ wpasupplicant.go | 45 +++++++++++++++++++++ 2 files changed, 148 insertions(+) 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 From 0402bbb5de1cc2f2741c43cd725bb41c51ec100d Mon Sep 17 00:00:00 2001 From: Matias Doyle Date: Tue, 19 Sep 2017 15:38:36 +0200 Subject: [PATCH 03/11] Add function to close unixgram connection --- unixgram.go | 4 ++++ wpasupplicant.go | 3 +++ 2 files changed, 7 insertions(+) diff --git a/unixgram.go b/unixgram.go index f2b016a..ae54dbd 100644 --- a/unixgram.go +++ b/unixgram.go @@ -199,6 +199,10 @@ func (err *ParseError) Error() string { return b.String() } +func (uc *unixgramConn) Close() error { + return uc.c.Close() +} + func (uc *unixgramConn) Ping() error { resp, err := uc.cmd("PING") if err != nil { diff --git a/wpasupplicant.go b/wpasupplicant.go index 2b67ee3..2ff06b5 100644 --- a/wpasupplicant.go +++ b/wpasupplicant.go @@ -143,6 +143,9 @@ func (r *configuredNetwork) Flags() []string { return r.flags } // Conn is a connection to wpa_supplicant over one of its communication // channels. type Conn interface { + // Close closes the unixgram connection + Close() error + // Ping tests the connection. It returns nil if wpa_supplicant is // responding. Ping() error From becc4580a55bf7997ac9afc872ef2f384e6941dd Mon Sep 17 00:00:00 2001 From: Matias Doyle Date: Mon, 16 Oct 2017 11:26:17 +0200 Subject: [PATCH 04/11] Read and parse unsolicited messages Currently only handling CTRL-EVENT-* messages and parses them to WPAEvent. --- unixgram.go | 52 ++++++++++++++++++++++++++++++++++++++++++++---- wpasupplicant.go | 7 +++++++ 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/unixgram.go b/unixgram.go index ae54dbd..0086493 100644 --- a/unixgram.go +++ b/unixgram.go @@ -58,6 +58,7 @@ type unixgramConn struct { c *net.UnixConn fd uintptr solicited, unsolicited chan message + wpaEvents chan WPAEvent } // socketPath is where to find the the AF_UNIX sockets for each interface. It @@ -91,12 +92,15 @@ func Unixgram(ifName string) (Conn, error) { uc.solicited = make(chan message) uc.unsolicited = make(chan message) + uc.wpaEvents = make(chan WPAEvent) go uc.readLoop() - - // TODO: issue an ACCEPT command so as to receive unsolicited - // messages. (We don't do this yet, since we don't yet have any way - // to consume them.) + go uc.readUnsolicited() + // Issue an ATTACH command to start receiving unsolicited events. + err = uc.runCommand("ATTACH") + if err != nil { + return nil, err + } return uc, nil } @@ -160,6 +164,42 @@ func (uc *unixgramConn) readLoop() { } } +// readUnsolicited handles messages sent to the unsolicited channel and parse them +// into a WPAEvent. At the moment we only handle `CTRL-EVENT-*` events and only events +// where the 'payload' is formatted with key=val. +func (uc *unixgramConn) readUnsolicited() { + for { + mgs := <-uc.unsolicited + data := bytes.NewBuffer(mgs.data).String() + + parts := strings.Split(data, " ") + if len(parts) == 0 { + continue + } + + if strings.Index(parts[0], "CTRL-") != 0 { + continue + } + + event := WPAEvent{ + Event: strings.TrimPrefix(parts[0], "CTRL-EVENT-"), + Arguments: make(map[string]string), + } + + for _, args := range parts[1:] { + if strings.Contains(args, "=") { + keyval := strings.Split(args, "=") + if len(keyval) != 2 { + continue + } + event.Arguments[keyval[0]] = keyval[1] + } + } + + uc.wpaEvents <- event + } +} + // cmd executes a command and waits for a reply. func (uc *unixgramConn) cmd(cmd string) ([]byte, error) { // TODO: block if any other commands are running @@ -199,6 +239,10 @@ func (err *ParseError) Error() string { return b.String() } +func (uc *unixgramConn) EventQueue() chan WPAEvent { + return uc.wpaEvents +} + func (uc *unixgramConn) Close() error { return uc.c.Close() } diff --git a/wpasupplicant.go b/wpasupplicant.go index 2ff06b5..672a545 100644 --- a/wpasupplicant.go +++ b/wpasupplicant.go @@ -140,6 +140,11 @@ func (r *configuredNetwork) BSSID() string { return r.bssid } func (r *configuredNetwork) SSID() string { return r.ssid } func (r *configuredNetwork) Flags() []string { return r.flags } +type WPAEvent struct { + Event string + Arguments map[string]string +} + // Conn is a connection to wpa_supplicant over one of its communication // channels. type Conn interface { @@ -197,4 +202,6 @@ type Conn interface { // of scanned BSSs, and/or a slice of errors representing problems // communicating with wpa_supplicant or parsing its output. ScanResults() ([]ScanResult, []error) + + EventQueue() chan WPAEvent } From ba0f86f6a1ad584aa50ebfbf7af57bd40512d53e Mon Sep 17 00:00:00 2001 From: Matias Doyle Date: Mon, 6 Nov 2017 13:11:22 +0100 Subject: [PATCH 05/11] Add SelectNetwork command --- unixgram.go | 4 ++++ wpasupplicant.go | 3 +++ 2 files changed, 7 insertions(+) diff --git a/unixgram.go b/unixgram.go index 0086493..4433a79 100644 --- a/unixgram.go +++ b/unixgram.go @@ -273,6 +273,10 @@ func (uc *unixgramConn) EnableNetwork(networkID int) error { return uc.runCommand(fmt.Sprintf("ENABLE_NETWORK %d", networkID)) } +func (uc *unixgramConn) SelectNetwork(networkID int) error { + return uc.runCommand(fmt.Sprintf("SELECT_NETWORK %d", networkID)) +} + func (uc *unixgramConn) DisableNetwork(networkID int) error { return uc.runCommand(fmt.Sprintf("DISABLE_NETWORK %d", networkID)) } diff --git a/wpasupplicant.go b/wpasupplicant.go index 672a545..accb63c 100644 --- a/wpasupplicant.go +++ b/wpasupplicant.go @@ -166,6 +166,9 @@ type Conn interface { // EnableNetwork enables a network. Returns error if the command fails. EnableNetwork(int) error + // SelectNetwork selects a network (and disables the others). + SelectNetwork(int) error + // DisableNetwork disables a network. DisableNetwork(int) error From a0e5516dbc0f4e4a8e222f394ccfcb4a1e89a914 Mon Sep 17 00:00:00 2001 From: Matias Doyle Date: Thu, 9 Nov 2017 14:09:56 +0100 Subject: [PATCH 06/11] Send DETACH message before Closing connection --- unixgram.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/unixgram.go b/unixgram.go index 4433a79..9995795 100644 --- a/unixgram.go +++ b/unixgram.go @@ -244,6 +244,10 @@ func (uc *unixgramConn) EventQueue() chan WPAEvent { } func (uc *unixgramConn) Close() error { + if err := uc.runCommand("DETACH"); err != nil { + return err + } + return uc.c.Close() } From 763b1685dffc6f55cc6c65421e60af177e1790b0 Mon Sep 17 00:00:00 2001 From: Matias Doyle Date: Thu, 9 Nov 2017 20:52:26 +0100 Subject: [PATCH 07/11] Add func to enable all networks --- unixgram.go | 4 ++++ wpasupplicant.go | 3 +++ 2 files changed, 7 insertions(+) diff --git a/unixgram.go b/unixgram.go index 9995795..90ab44f 100644 --- a/unixgram.go +++ b/unixgram.go @@ -277,6 +277,10 @@ func (uc *unixgramConn) EnableNetwork(networkID int) error { return uc.runCommand(fmt.Sprintf("ENABLE_NETWORK %d", networkID)) } +func (uc *unixgramConn) EnableAllNetworks() error { + return uc.runCommand("ENABLE_NETWORK all") +} + func (uc *unixgramConn) SelectNetwork(networkID int) error { return uc.runCommand(fmt.Sprintf("SELECT_NETWORK %d", networkID)) } diff --git a/wpasupplicant.go b/wpasupplicant.go index accb63c..1152b44 100644 --- a/wpasupplicant.go +++ b/wpasupplicant.go @@ -166,6 +166,9 @@ type Conn interface { // EnableNetwork enables a network. Returns error if the command fails. EnableNetwork(int) error + // EnableAllNetworks enables all configured networks. Returns error if the command fails. + EnableAllNetworks() error + // SelectNetwork selects a network (and disables the others). SelectNetwork(int) error From 676121199d07f10a345d5f80a162834f325c9048 Mon Sep 17 00:00:00 2001 From: Matias Doyle Date: Thu, 9 Nov 2017 20:52:46 +0100 Subject: [PATCH 08/11] Initial version of STATUS command At the moment only returning a subset of the values you can get. That will come later. --- unixgram.go | 44 +++++++++++++++++++++++++++++++++++++------- unixgram_test.go | 34 ++++++++++++++++++++++++++++++++++ wpasupplicant.go | 25 +++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 7 deletions(-) diff --git a/unixgram.go b/unixgram.go index 90ab44f..2795f80 100644 --- a/unixgram.go +++ b/unixgram.go @@ -330,6 +330,15 @@ func (uc *unixgramConn) ScanResults() ([]ScanResult, []error) { return parseScanResults(bytes.NewBuffer(resp)) } +func (uc *unixgramConn) Status() (StatusResult, error) { + resp, err := uc.cmd("STATUS") + if err != nil { + return nil, err + } + + return parseStatusResults(bytes.NewBuffer(resp)) +} + func (uc *unixgramConn) ListNetworks() ([]ConfiguredNetwork, error) { resp, err := uc.cmd("LIST_NETWORKS") if err != nil { @@ -360,10 +369,7 @@ func parseListNetworksResult(resp io.Reader) (res []ConfiguredNetwork, err error 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": @@ -379,12 +385,9 @@ func parseListNetworksResult(resp io.Reader) (res []ConfiguredNetwork, err error 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} } @@ -417,8 +420,35 @@ func parseListNetworksResult(resp io.Reader) (res []ConfiguredNetwork, err error bssid: bssid, flags: flags, }) + } - // fmt.Println(res) + return res, nil +} + +func parseStatusResults(resp io.Reader) (StatusResult, error) { + s := bufio.NewScanner(resp) + + res := &statusResult{} + + for s.Scan() { + ln := s.Text() + fields := strings.Split(ln, "=") + if len(fields) != 2 { + continue + } + + switch fields[0] { + case "wpa_state": + res.wpaState = fields[1] + case "key_mgmt": + res.keyMgmt = fields[1] + case "ip_address": + res.ipAddr = fields[1] + case "ssid": + res.ssid = fields[1] + case "address": + res.address = fields[1] + } } return res, nil diff --git a/unixgram_test.go b/unixgram_test.go index 431bc4c..64006f3 100644 --- a/unixgram_test.go +++ b/unixgram_test.go @@ -131,3 +131,37 @@ func TestParseScanResults(t *testing.T) { } } } + +func TestParseStatusResults(t *testing.T) { + testData := "bssid=02:00:01:02:03:04\n" + + "ssid=test network\n" + + "pairwise_cipher=CCMP\n" + + "group_cipher=CCMP\n" + + "key_mgmt=WPA-PSK\n" + + "wpa_state=COMPLETED\n" + + "ip_address=192.168.1.21\n" + + "Supplicant PAE state=AUTHENTICATED\n" + + "suppPortStatus=Authorized\n" + + "EAP state=SUCCESS" + + res, err := parseStatusResults(bytes.NewBufferString(testData)) + if err != nil { + t.Errorf("Error parsing status result %t", err) + } + + if res.WPAState() != "COMPLETED" { + t.Errorf("WPAState was not COMPLETED. Was %s", res.WPAState()) + } + + if res.IPAddr() != "192.168.1.21" { + t.Errorf("IPAddr was not 192.168.1.21. Was %s", res.IPAddr()) + } + + if res.KeyMgmt() != "WPA-PSK" { + t.Errorf("KeyMgmt was not WPA-PSK. Was %s", res.KeyMgmt()) + } + + if res.Address() != "" { + t.Errorf("Address should be empty. Was %s", res.Address()) + } +} diff --git a/wpasupplicant.go b/wpasupplicant.go index 1152b44..5cd413c 100644 --- a/wpasupplicant.go +++ b/wpasupplicant.go @@ -140,6 +140,28 @@ func (r *configuredNetwork) BSSID() string { return r.bssid } func (r *configuredNetwork) SSID() string { return r.ssid } func (r *configuredNetwork) Flags() []string { return r.flags } +type StatusResult interface { + WPAState() string + KeyMgmt() string + IPAddr() string + SSID() string + Address() string +} + +type statusResult struct { + wpaState string + keyMgmt string + ipAddr string + ssid string + address string +} + +func (s *statusResult) WPAState() string { return s.wpaState } +func (s *statusResult) KeyMgmt() string { return s.keyMgmt } +func (s *statusResult) IPAddr() string { return s.ipAddr } +func (s *statusResult) SSID() string { return s.ssid } +func (s *statusResult) Address() string { return s.address } + type WPAEvent struct { Event string Arguments map[string]string @@ -200,6 +222,9 @@ type Conn interface { // ListNetworks returns the currently configured networks. ListNetworks() ([]ConfiguredNetwork, error) + // Status returns current wpa_supplicant status + Status() (StatusResult, error) + // Scan triggers a new scan. Returns error if the wpa_supplicant does not // return OK. Scan() error From 853de1e2372037436a9aebb550e0f94cbfdd5a22 Mon Sep 17 00:00:00 2001 From: Matias Doyle Date: Wed, 15 Nov 2017 20:20:45 +0100 Subject: [PATCH 09/11] Emit non CTRL-* events as MESSAGE events And add a Line prop to the WPAEvent struct which contains the original line received from the wpa_supplicant. --- unixgram.go | 5 +++++ wpasupplicant.go | 1 + 2 files changed, 6 insertions(+) diff --git a/unixgram.go b/unixgram.go index 2795f80..5e187a6 100644 --- a/unixgram.go +++ b/unixgram.go @@ -178,12 +178,17 @@ func (uc *unixgramConn) readUnsolicited() { } if strings.Index(parts[0], "CTRL-") != 0 { + uc.wpaEvents <- WPAEvent{ + Event: "MESSAGE", + Line: data, + } continue } event := WPAEvent{ Event: strings.TrimPrefix(parts[0], "CTRL-EVENT-"), Arguments: make(map[string]string), + Line: data, } for _, args := range parts[1:] { diff --git a/wpasupplicant.go b/wpasupplicant.go index 5cd413c..cacaec9 100644 --- a/wpasupplicant.go +++ b/wpasupplicant.go @@ -165,6 +165,7 @@ func (s *statusResult) Address() string { return s.address } type WPAEvent struct { Event string Arguments map[string]string + Line string } // Conn is a connection to wpa_supplicant over one of its communication From f41eb91a5163c6affe5a94db2a13d7f4f5b783ca Mon Sep 17 00:00:00 2001 From: Matias Doyle Date: Tue, 28 Nov 2017 12:10:11 +0100 Subject: [PATCH 10/11] Return err instead of panic when creating temp file fails --- unixgram.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unixgram.go b/unixgram.go index 5e187a6..8a5d21c 100644 --- a/unixgram.go +++ b/unixgram.go @@ -73,7 +73,7 @@ func Unixgram(ifName string) (Conn, error) { local, err := ioutil.TempFile("/tmp", "wpa_supplicant") if err != nil { - panic(err) + return nil, err } os.Remove(local.Name()) From abcde53d842735462a55d6aa4ae49c02efd4adf6 Mon Sep 17 00:00:00 2001 From: Matias Doyle Date: Mon, 4 Dec 2017 17:37:34 +0100 Subject: [PATCH 11/11] Add support for setting key_mgmt value --- unixgram.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/unixgram.go b/unixgram.go index 8a5d21c..8bbc117 100644 --- a/unixgram.go +++ b/unixgram.go @@ -303,7 +303,16 @@ func (uc *unixgramConn) RemoveAllNetworks() error { } func (uc *unixgramConn) SetNetwork(networkID int, variable string, value string) error { - return uc.runCommand(fmt.Sprintf("SET_NETWORK %d %s \"%s\"", networkID, variable, value)) + var cmd string + + // Since key_mgmt expects the value to not be wrapped in "" we do a little check here. + if variable == "key_mgmt" { + cmd = fmt.Sprintf("SET_NETWORK %d %s %s", networkID, variable, value) + } else { + cmd = fmt.Sprintf("SET_NETWORK %d %s \"%s\"", networkID, variable, value) + } + + return uc.runCommand(cmd) } func (uc *unixgramConn) SaveConfig() error {