wifi
wifi copied to clipboard
Support for Linux AP scanning
Adds support for Linux AP scanning, with unit tests handling unicode in AP SSIDs.
This needs a rebase.
(maybe stupid question) Why is multicast group needed here?
I am getting operation not supported when using dump flag on the TRIGGER_SCAN.
I don't know enough about netlink and nl80211 yet, but I am trying to learn. I would love if anyone could point me in a direction. Right now the only method I have is to try out commands from here and parsing the response manually. I am looking at iw, and wpa_supplicant sourcecode as well, but it is not easy for me to understand because I am not a C programmer.
I changed the first call to socket using the get method on the cli, and I changed dump to acknowlegde, because then I will get other errors.
msgs, err := c.get(
unix.NL80211_CMD_TRIGGER_SCAN,
netlink.Acknowledge,
ifi,
func(ae *netlink.AttributeEncoder) {
ae.Nested(unix.NL80211_ATTR_SCAN_SSIDS,
func(nae *netlink.AttributeEncoder) error {
nae.Bytes(
unix.NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
nlenc.Bytes(""),
)
return nil
})
ae.Bytes(
unix.NL80211_ATTR_IFINDEX,
nlenc.Uint32Bytes(uint32(ifi.Index)),
)
},
)
if err != nil {
return nil, fmt.Errorf("failed to trigger scheduled scan: %s", err)
}
First error was not permitted, so I run with sudo, and get: netlink validate: mismatched sequence in netlink reply.
So I removed the part where you create a multicast group and join it.
Then I get the error that the header version is not the family version and the response from the first call to socket is:
{{0 0} [48 0 0 0 36 0 5 0 203 41 13 27 209 148 2 0]}
I don't know how to interpret it.
The final response from CMD_GET_SCAN is one or more of this:
&{ 0 0s 0s authenticated}
&{ 0 0s 0s authenticated}
&{ 0 0s 0s authenticated}
&{ 0 0s 0s authenticated}
Here is a copy of the whole function, how it look on my machine now
func (c *client) Scan(ifi *Interface) ([]*BSS, error) {
//family, err := c.c.GetFamily(unix.NL80211_GENL_NAME)
//if err != nil {
// return nil, err
//}
//var mcastScan genetlink.MulticastGroup
//for _, mcast := range family.Groups {
// if mcast.Name == unix.NL80211_MULTICAST_GROUP_SCAN {
// mcastScan = mcast
// }
//}
//if mcastScan.Name != unix.NL80211_MULTICAST_GROUP_SCAN {
// return nil, errMissingMulticastGroupScan
//}
//err = c.c.JoinGroup(mcastScan.ID)
//if err != nil {
// return nil, err
//}
msgs, err := c.get(
unix.NL80211_CMD_TRIGGER_SCAN,
netlink.Acknowledge,
ifi,
func(ae *netlink.AttributeEncoder) {
ae.Nested(unix.NL80211_ATTR_SCAN_SSIDS,
func(nae *netlink.AttributeEncoder) error {
nae.Bytes(
unix.NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
nlenc.Bytes(""),
)
return nil
})
ae.Bytes(
unix.NL80211_ATTR_IFINDEX,
nlenc.Uint32Bytes(uint32(ifi.Index)),
)
},
)
if err != nil {
return nil, fmt.Errorf("failed to trigger scheduled scan: %s", err)
}
for _, m := range msgs {
fmt.Println(m)
//if m.Header.Version != c.familyVersion {
// fmt.Println(m.Header.Version)
// return nil, errInvalidFamilyVersion
//}
if m.Header.Command == unix.NL80211_CMD_ABORT_SCAN {
return nil, errScanAborted
}
if m.Header.Command == unix.NL80211_CMD_NEW_SCAN_RESULTS {
fmt.Println("ok")
break
}
}
//err = c.c.LeaveGroup(mcastScan.ID)
//if err != nil {
// return nil, err
//}
msgs, err = c.get(unix.NL80211_CMD_GET_SCAN, netlink.Dump, ifi,
func(ae *netlink.AttributeEncoder) {
ae.Bytes(
unix.NL80211_ATTR_IFINDEX,
nlenc.Uint32Bytes(uint32(ifi.Index)),
)
},
)
if err != nil {
return nil, err
}
//if err := c.checkMessages(msgs, unix.NL80211_CMD_NEW_SCAN_RESULTS); err != nil {
// return nil, err
//}
bssm, err := parseBSSMulti(msgs)
if err != nil {
return nil, err
}
return bssm, nil
}
@oldgalileo Do you still work on this?
I am planing to implement something similar (Trigger Scans and more importantly receive all scan results). Can I join into the effort?
@lukas-mbag this seems to be abandoned long enough that I would go ahead with what you want to work on. You're welcome to cherry-pick changes from this PR if that makes sense.