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.
|
* string: crash when failing to convert string to UTF-32.
|
||||||
* script: only first transaction processed when receiving multiple
|
* script: only first transaction processed when receiving multiple
|
||||||
transactions in a single batch ([#221][221]).
|
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
|
[169]: https://codeberg.org/dnkl/yambar/issues/169
|
||||||
[172]: https://codeberg.org/dnkl/yambar/issues/172
|
[172]: https://codeberg.org/dnkl/yambar/issues/172
|
||||||
|
@ -117,6 +120,7 @@
|
||||||
[177]: https://codeberg.org/dnkl/yambar/issues/177
|
[177]: https://codeberg.org/dnkl/yambar/issues/177
|
||||||
[198]: https://codeberg.org/dnkl/yambar/issues/198
|
[198]: https://codeberg.org/dnkl/yambar/issues/198
|
||||||
[221]: https://codeberg.org/dnkl/yambar/issues/221
|
[221]: https://codeberg.org/dnkl/yambar/issues/221
|
||||||
|
[226]: https://codeberg.org/dnkl/yambar/issues/226
|
||||||
|
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
|
|
|
@ -60,6 +60,7 @@ struct private {
|
||||||
uint16_t family_id;
|
uint16_t family_id;
|
||||||
uint32_t get_interface_seq_nr;
|
uint32_t get_interface_seq_nr;
|
||||||
uint32_t get_station_seq_nr;
|
uint32_t get_station_seq_nr;
|
||||||
|
uint32_t get_scan_seq_nr;
|
||||||
} nl80211;
|
} nl80211;
|
||||||
|
|
||||||
bool get_addresses;
|
bool get_addresses;
|
||||||
|
@ -457,6 +458,32 @@ send_nl80211_get_station(struct private *m)
|
||||||
return false;
|
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
|
static bool
|
||||||
find_my_ifindex(struct module *mod, const struct ifinfomsg *msg, size_t len)
|
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: {
|
case NL80211_ATTR_SSID: {
|
||||||
const char *ssid = payload;
|
const char *ssid = payload;
|
||||||
|
LOG_INFO("%s: SSID: %.*s", m->iface, (int)len, ssid);
|
||||||
|
|
||||||
mtx_lock(&mod->lock);
|
mtx_lock(&mod->lock);
|
||||||
free(m->ssid);
|
free(m->ssid);
|
||||||
|
@ -951,6 +979,102 @@ handle_nl80211_new_station(struct module *mod, uint16_t type, bool nested,
|
||||||
return true;
|
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.
|
* 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 */
|
/* Current request is now considered complete */
|
||||||
m->nl80211.get_station_seq_nr = 0;
|
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) {
|
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);
|
LOG_DBG("%s: got interface information", m->iface);
|
||||||
foreach_nlattr(
|
foreach_nlattr(
|
||||||
mod, genl, msg_size, &handle_nl80211_new_interface);
|
mod, genl, msg_size, &handle_nl80211_new_interface);
|
||||||
|
|
||||||
LOG_INFO("%s: SSID: %s", m->iface, m->ssid);
|
|
||||||
}
|
}
|
||||||
break;
|
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->iface, m->signal_strength_dbm,
|
||||||
m->rx_bitrate / 1000 / 1000,
|
m->rx_bitrate / 1000 / 1000,
|
||||||
m->tx_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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -1165,7 +1304,8 @@ parse_genl_reply(struct module *mod, const struct nlmsghdr *hdr, size_t len)
|
||||||
else if (nl_errno == ENOENT)
|
else if (nl_errno == ENOENT)
|
||||||
; /* iface down? */
|
; /* iface down? */
|
||||||
else
|
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 {
|
else {
|
||||||
|
|
Loading…
Add table
Reference in a new issue