From becc4580a55bf7997ac9afc872ef2f384e6941dd Mon Sep 17 00:00:00 2001 From: Matias Doyle Date: Mon, 16 Oct 2017 11:26:17 +0200 Subject: [PATCH] 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 }