mirror of
https://codeberg.org/dnkl/yambar.git
synced 2025-04-20 03:35:41 +02:00
module/network: resurrect SSID
Recent kernels, or possibly updated wireless drivers, no longer provide the SSID in `NL80211_CMD_NEW_STATION` responses. For yambar, this meant the SSID was always missing. This patch fixes this, by also issuing a NL80211_CMD_GET_SCAN command. The response to this (NL80211_CMD_SCAN_RESULTS) _may_ return many access points. Pick out the one that we’re associated with, and inspect its BSS_INFORMATION_ELEMENTS. This is a raw data structure containing, among other things, the SSID. I haven’t been able to find any documentation of the format, but could glean enough from https://git.kernel.org/pub/scm/linux/kernel/git/jberg/iw.git/tree/scan.c#n2313 to be able to parse out the SSID. Note that we get a “device or resource busy” error if we try to issue both the NL80211_CMD_GET_STATION and the NL80211_CMD_GET_SCAN commands at the same time. Therefore, we issue the GET_SCAN command after completing the GET_STATION command. Closes #226
This commit is contained in:
parent
d1a8029e6c
commit
4143099e94
2 changed files with 147 additions and 3 deletions
|
@ -110,6 +110,9 @@
|
|||
* string: crash when failing to convert string to UTF-32.
|
||||
* script: only first transaction processed when receiving multiple
|
||||
transactions in a single batch ([#221][221]).
|
||||
* network: missing SSID (recent kernels, or possibly wireless drivers,
|
||||
no longer provide the SSID in the `NL80211_CMD_NEW_STATION`
|
||||
response) ([#226][226]).
|
||||
|
||||
[169]: https://codeberg.org/dnkl/yambar/issues/169
|
||||
[172]: https://codeberg.org/dnkl/yambar/issues/172
|
||||
|
@ -117,6 +120,7 @@
|
|||
[177]: https://codeberg.org/dnkl/yambar/issues/177
|
||||
[198]: https://codeberg.org/dnkl/yambar/issues/198
|
||||
[221]: https://codeberg.org/dnkl/yambar/issues/221
|
||||
[226]: https://codeberg.org/dnkl/yambar/issues/226
|
||||
|
||||
|
||||
### Security
|
||||
|
|
|
@ -60,6 +60,7 @@ struct private {
|
|||
uint16_t family_id;
|
||||
uint32_t get_interface_seq_nr;
|
||||
uint32_t get_station_seq_nr;
|
||||
uint32_t get_scan_seq_nr;
|
||||
} nl80211;
|
||||
|
||||
bool get_addresses;
|
||||
|
@ -457,6 +458,32 @@ send_nl80211_get_station(struct private *m)
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
send_nl80211_get_scan(struct private *m)
|
||||
{
|
||||
if (m->nl80211.get_scan_seq_nr > 0) {
|
||||
LOG_ERR(
|
||||
"%s: nl80211 get-scan request already in progress", m->iface);
|
||||
return true;
|
||||
}
|
||||
|
||||
LOG_DBG("%s: sending nl80211 get-scan request", m->iface);
|
||||
|
||||
uint32_t seq;
|
||||
if (read(m->urandom_fd, &seq, sizeof(seq)) != sizeof(seq)) {
|
||||
LOG_ERRNO("failed to read from /dev/urandom");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (send_nl80211_request(
|
||||
m, NL80211_CMD_GET_SCAN, NLM_F_REQUEST | NLM_F_DUMP, seq))
|
||||
{
|
||||
m->nl80211.get_scan_seq_nr = seq;
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
find_my_ifindex(struct module *mod, const struct ifinfomsg *msg, size_t len)
|
||||
{
|
||||
|
@ -810,6 +837,7 @@ handle_nl80211_new_interface(struct module *mod, uint16_t type, bool nested,
|
|||
|
||||
case NL80211_ATTR_SSID: {
|
||||
const char *ssid = payload;
|
||||
LOG_INFO("%s: SSID: %.*s", m->iface, (int)len, ssid);
|
||||
|
||||
mtx_lock(&mod->lock);
|
||||
free(m->ssid);
|
||||
|
@ -951,6 +979,102 @@ handle_nl80211_new_station(struct module *mod, uint16_t type, bool nested,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
handle_ies(struct module *mod, const void *_ies, size_t len)
|
||||
{
|
||||
struct private *m = mod->private;
|
||||
const uint8_t *ies = _ies;
|
||||
|
||||
while (len >= 2 && len - 2 >= ies[1]) {
|
||||
switch (ies[0]) {
|
||||
case 0: { /* SSID */
|
||||
const char *ssid = (const char *)&ies[2];
|
||||
const size_t ssid_len = ies[1];
|
||||
|
||||
LOG_INFO("%s: SSID: %.*s", m->iface, (int)ssid_len, ssid);
|
||||
|
||||
mtx_lock(&mod->lock);
|
||||
free(m->ssid);
|
||||
m->ssid = strndup(ssid, ssid_len);
|
||||
mtx_unlock(&mod->lock);
|
||||
|
||||
mod->bar->refresh(mod->bar);
|
||||
break;
|
||||
}
|
||||
}
|
||||
len -= ies[1] + 2;
|
||||
ies += ies[1] + 2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct scan_results_context {
|
||||
bool associated;
|
||||
|
||||
const void *ies;
|
||||
size_t ies_size;
|
||||
};
|
||||
|
||||
static bool
|
||||
handle_nl80211_bss(struct module *mod, uint16_t type, bool nested,
|
||||
const void *payload, size_t len, void *_ctx)
|
||||
{
|
||||
struct private *m UNUSED = mod->private;
|
||||
struct scan_results_context *ctx = _ctx;
|
||||
|
||||
switch (type) {
|
||||
case NL80211_BSS_STATUS: {
|
||||
const uint32_t status = *(uint32_t *)payload;
|
||||
|
||||
if (status == NL80211_BSS_STATUS_ASSOCIATED) {
|
||||
ctx->associated = true;
|
||||
|
||||
if (ctx->ies != NULL) {
|
||||
/* Deferred handling of BSS_INFORMATION_ELEMENTS */
|
||||
return handle_ies(mod, ctx->ies, ctx->ies_size);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case NL80211_BSS_INFORMATION_ELEMENTS:
|
||||
if (ctx->associated)
|
||||
return handle_ies(mod, payload, len);
|
||||
else {
|
||||
/*
|
||||
* We’re either not associated, or, we haven’t seen the
|
||||
* BSS_STATUS attribute yet.
|
||||
*
|
||||
* Save a pointer to the IES payload, so that we can
|
||||
* process it later, if we see a
|
||||
* BSS_STATUS == BSS_STATUS_ASSOCIATED.
|
||||
*/
|
||||
ctx->ies = payload;
|
||||
ctx->ies_size = len;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
handle_nl80211_scan_results(struct module *mod, uint16_t type, bool nested,
|
||||
const void *payload, size_t len)
|
||||
{
|
||||
struct private *m UNUSED = mod->private;
|
||||
|
||||
struct scan_results_context ctx = {0};
|
||||
|
||||
switch (type) {
|
||||
case NL80211_ATTR_BSS:
|
||||
foreach_nlattr_nested(mod, payload, len, &handle_nl80211_bss, &ctx);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads at least one (possibly more) message.
|
||||
*
|
||||
|
@ -1083,6 +1207,11 @@ parse_genl_reply(struct module *mod, const struct nlmsghdr *hdr, size_t len)
|
|||
/* Current request is now considered complete */
|
||||
m->nl80211.get_station_seq_nr = 0;
|
||||
}
|
||||
|
||||
else if (hdr->nlmsg_seq == m->nl80211.get_scan_seq_nr) {
|
||||
/* Current request is now considered complete */
|
||||
m->nl80211.get_scan_seq_nr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
else if (hdr->nlmsg_type == GENL_ID_CTRL) {
|
||||
|
@ -1101,8 +1230,6 @@ parse_genl_reply(struct module *mod, const struct nlmsghdr *hdr, size_t len)
|
|||
LOG_DBG("%s: got interface information", m->iface);
|
||||
foreach_nlattr(
|
||||
mod, genl, msg_size, &handle_nl80211_new_interface);
|
||||
|
||||
LOG_INFO("%s: SSID: %s", m->iface, m->ssid);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1148,6 +1275,18 @@ parse_genl_reply(struct module *mod, const struct nlmsghdr *hdr, size_t len)
|
|||
m->iface, m->signal_strength_dbm,
|
||||
m->rx_bitrate / 1000 / 1000,
|
||||
m->tx_bitrate / 1000 / 1000);
|
||||
|
||||
/* Can’t issue both get-station and get-scan at the
|
||||
* same time. So, always run a get-scan when a
|
||||
* get-station is complete */
|
||||
send_nl80211_get_scan(m);
|
||||
break;
|
||||
|
||||
case NL80211_CMD_NEW_SCAN_RESULTS:
|
||||
if (nl80211_is_for_us(mod, genl, msg_size)) {
|
||||
LOG_DBG("%s: got scan results", m->iface);
|
||||
foreach_nlattr(mod, genl, msg_size, &handle_nl80211_scan_results);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1165,7 +1304,8 @@ parse_genl_reply(struct module *mod, const struct nlmsghdr *hdr, size_t len)
|
|||
else if (nl_errno == ENOENT)
|
||||
; /* iface down? */
|
||||
else
|
||||
LOG_ERRNO_P(nl_errno, "%s: nl80211 reply", m->iface);
|
||||
LOG_ERRNO_P(nl_errno, "%s: nl80211 reply (seq-nr: %u)",
|
||||
m->iface, hdr->nlmsg_seq);
|
||||
}
|
||||
|
||||
else {
|
||||
|
|
Loading…
Add table
Reference in a new issue