rfkill: Match only the correct expected wiphy rfkill
On systems that have multiple WLAN rfkill instances, the rfkill code can become confused into thinking that the device was unblocked when in fact it wasn't, because it only matches on the WLAN type. Since it then stores the new (unblocked) state from the wrong rfkill instance, it will never retry the failing IFF_UP operation and the user has to toggle rfkill again, or otherwise intervene manually, in this case to get back to operational state. Fix this by using the existing (but unused) ifname argument when the rfkill instance is created to match to a specific rfkill index only. As a P2P Device interface does not have a netdev interface associated with it, use the name of a sibling interface to initialize the rfkill context for the P2P Device interface. For nl80211, as the wiphy index is known only after getting the driver capabilities from the kernel, move the initialization of the rfkill object to wpa_driver_nl80211_finish_drv_init(). Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Ilan Peer <ilan.peer@intel.com>
This commit is contained in:
parent
6da504a1f5
commit
0e92fb8fae
4 changed files with 99 additions and 19 deletions
|
@ -1636,13 +1636,65 @@ static void nl80211_destroy_bss(struct i802_bss *bss)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
wpa_driver_nl80211_drv_init_rfkill(struct wpa_driver_nl80211_data *drv)
|
||||||
|
{
|
||||||
|
struct rfkill_config *rcfg;
|
||||||
|
|
||||||
|
if (drv->rfkill)
|
||||||
|
return;
|
||||||
|
|
||||||
|
rcfg = os_zalloc(sizeof(*rcfg));
|
||||||
|
if (!rcfg)
|
||||||
|
return;
|
||||||
|
|
||||||
|
rcfg->ctx = drv;
|
||||||
|
|
||||||
|
/* rfkill uses netdev sysfs for initialization. However, P2P Device is
|
||||||
|
* not associated with a netdev, so use the name of some other interface
|
||||||
|
* sharing the same wiphy as the P2P Device interface.
|
||||||
|
*
|
||||||
|
* Note: This is valid, as a P2P Device interface is always dynamically
|
||||||
|
* created and is created only once another wpa_s interface was added.
|
||||||
|
*/
|
||||||
|
if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) {
|
||||||
|
struct nl80211_global *global = drv->global;
|
||||||
|
struct wpa_driver_nl80211_data *tmp1;
|
||||||
|
|
||||||
|
dl_list_for_each(tmp1, &global->interfaces,
|
||||||
|
struct wpa_driver_nl80211_data, list) {
|
||||||
|
if (drv == tmp1 || drv->wiphy_idx != tmp1->wiphy_idx ||
|
||||||
|
!tmp1->rfkill)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"nl80211: Use (%s) to initialize P2P Device rfkill",
|
||||||
|
tmp1->first_bss->ifname);
|
||||||
|
os_strlcpy(rcfg->ifname, tmp1->first_bss->ifname,
|
||||||
|
sizeof(rcfg->ifname));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
os_strlcpy(rcfg->ifname, drv->first_bss->ifname,
|
||||||
|
sizeof(rcfg->ifname));
|
||||||
|
}
|
||||||
|
|
||||||
|
rcfg->blocked_cb = wpa_driver_nl80211_rfkill_blocked;
|
||||||
|
rcfg->unblocked_cb = wpa_driver_nl80211_rfkill_unblocked;
|
||||||
|
drv->rfkill = rfkill_init(rcfg);
|
||||||
|
if (!drv->rfkill) {
|
||||||
|
wpa_printf(MSG_DEBUG, "nl80211: RFKILL status not available");
|
||||||
|
os_free(rcfg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
|
static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
|
||||||
void *global_priv, int hostapd,
|
void *global_priv, int hostapd,
|
||||||
const u8 *set_addr,
|
const u8 *set_addr,
|
||||||
const char *driver_params)
|
const char *driver_params)
|
||||||
{
|
{
|
||||||
struct wpa_driver_nl80211_data *drv;
|
struct wpa_driver_nl80211_data *drv;
|
||||||
struct rfkill_config *rcfg;
|
|
||||||
struct i802_bss *bss;
|
struct i802_bss *bss;
|
||||||
|
|
||||||
if (global_priv == NULL)
|
if (global_priv == NULL)
|
||||||
|
@ -1683,19 +1735,6 @@ static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
|
||||||
if (nl80211_init_bss(bss))
|
if (nl80211_init_bss(bss))
|
||||||
goto failed;
|
goto failed;
|
||||||
|
|
||||||
rcfg = os_zalloc(sizeof(*rcfg));
|
|
||||||
if (rcfg == NULL)
|
|
||||||
goto failed;
|
|
||||||
rcfg->ctx = drv;
|
|
||||||
os_strlcpy(rcfg->ifname, ifname, sizeof(rcfg->ifname));
|
|
||||||
rcfg->blocked_cb = wpa_driver_nl80211_rfkill_blocked;
|
|
||||||
rcfg->unblocked_cb = wpa_driver_nl80211_rfkill_unblocked;
|
|
||||||
drv->rfkill = rfkill_init(rcfg);
|
|
||||||
if (drv->rfkill == NULL) {
|
|
||||||
wpa_printf(MSG_DEBUG, "nl80211: RFKILL status not available");
|
|
||||||
os_free(rcfg);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (linux_iface_up(drv->global->ioctl_sock, ifname) > 0)
|
if (linux_iface_up(drv->global->ioctl_sock, ifname) > 0)
|
||||||
drv->start_iface_up = 1;
|
drv->start_iface_up = 1;
|
||||||
|
|
||||||
|
@ -2234,6 +2273,8 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
|
||||||
if (nlmode == NL80211_IFTYPE_P2P_DEVICE)
|
if (nlmode == NL80211_IFTYPE_P2P_DEVICE)
|
||||||
nl80211_get_macaddr(bss);
|
nl80211_get_macaddr(bss);
|
||||||
|
|
||||||
|
wpa_driver_nl80211_drv_init_rfkill(drv);
|
||||||
|
|
||||||
if (!rfkill_is_blocked(drv->rfkill)) {
|
if (!rfkill_is_blocked(drv->rfkill)) {
|
||||||
int ret = i802_set_iface_flags(bss, 1);
|
int ret = i802_set_iface_flags(bss, 1);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
|
|
@ -84,6 +84,7 @@ struct wpa_driver_nl80211_data {
|
||||||
struct dl_list list;
|
struct dl_list list;
|
||||||
struct dl_list wiphy_list;
|
struct dl_list wiphy_list;
|
||||||
char phyname[32];
|
char phyname[32];
|
||||||
|
unsigned int wiphy_idx;
|
||||||
u8 perm_addr[ETH_ALEN];
|
u8 perm_addr[ETH_ALEN];
|
||||||
void *ctx;
|
void *ctx;
|
||||||
int ifindex;
|
int ifindex;
|
||||||
|
|
|
@ -487,6 +487,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
|
||||||
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
|
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
|
||||||
genlmsg_attrlen(gnlh, 0), NULL);
|
genlmsg_attrlen(gnlh, 0), NULL);
|
||||||
|
|
||||||
|
if (tb[NL80211_ATTR_WIPHY])
|
||||||
|
drv->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
|
||||||
|
|
||||||
if (tb[NL80211_ATTR_WIPHY_NAME])
|
if (tb[NL80211_ATTR_WIPHY_NAME])
|
||||||
os_strlcpy(drv->phyname,
|
os_strlcpy(drv->phyname,
|
||||||
nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]),
|
nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]),
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
#include "utils/common.h"
|
#include "utils/common.h"
|
||||||
#include "utils/eloop.h"
|
#include "utils/eloop.h"
|
||||||
|
@ -47,6 +48,7 @@ struct rfkill_data {
|
||||||
struct rfkill_config *cfg;
|
struct rfkill_config *cfg;
|
||||||
int fd;
|
int fd;
|
||||||
int blocked;
|
int blocked;
|
||||||
|
uint32_t idx;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -69,12 +71,13 @@ static void rfkill_receive(int sock, void *eloop_ctx, void *sock_ctx)
|
||||||
(int) len, RFKILL_EVENT_SIZE_V1);
|
(int) len, RFKILL_EVENT_SIZE_V1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (event.op != RFKILL_OP_CHANGE || event.idx != rfkill->idx)
|
||||||
|
return;
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "rfkill: event: idx=%u type=%d "
|
wpa_printf(MSG_DEBUG, "rfkill: event: idx=%u type=%d "
|
||||||
"op=%u soft=%u hard=%u",
|
"op=%u soft=%u hard=%u",
|
||||||
event.idx, event.type, event.op, event.soft,
|
event.idx, event.type, event.op, event.soft,
|
||||||
event.hard);
|
event.hard);
|
||||||
if (event.op != RFKILL_OP_CHANGE || event.type != RFKILL_TYPE_WLAN)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (event.hard) {
|
if (event.hard) {
|
||||||
wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked");
|
wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked");
|
||||||
|
@ -102,11 +105,23 @@ struct rfkill_data * rfkill_init(struct rfkill_config *cfg)
|
||||||
struct rfkill_data *rfkill;
|
struct rfkill_data *rfkill;
|
||||||
struct rfkill_event event;
|
struct rfkill_event event;
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
|
char *phy = NULL, *rfk_phy;
|
||||||
|
char buf[24 + IFNAMSIZ + 1];
|
||||||
|
char buf2[31 + 11 + 1];
|
||||||
|
int found = 0;
|
||||||
|
|
||||||
rfkill = os_zalloc(sizeof(*rfkill));
|
rfkill = os_zalloc(sizeof(*rfkill));
|
||||||
if (rfkill == NULL)
|
if (rfkill == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
os_snprintf(buf, sizeof(buf), "/sys/class/net/%s/phy80211",
|
||||||
|
cfg->ifname);
|
||||||
|
phy = realpath(buf, NULL);
|
||||||
|
if (!phy) {
|
||||||
|
wpa_printf(MSG_INFO, "rfkill: Cannot get wiphy information");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
rfkill->cfg = cfg;
|
rfkill->cfg = cfg;
|
||||||
rfkill->fd = open("/dev/rfkill", O_RDONLY);
|
rfkill->fd = open("/dev/rfkill", O_RDONLY);
|
||||||
if (rfkill->fd < 0) {
|
if (rfkill->fd < 0) {
|
||||||
|
@ -136,13 +151,27 @@ struct rfkill_data * rfkill_init(struct rfkill_config *cfg)
|
||||||
(int) len, RFKILL_EVENT_SIZE_V1);
|
(int) len, RFKILL_EVENT_SIZE_V1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (event.op != RFKILL_OP_ADD ||
|
||||||
|
event.type != RFKILL_TYPE_WLAN)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
os_snprintf(buf2, sizeof(buf2),
|
||||||
|
"/sys/class/rfkill/rfkill%d/device", event.idx);
|
||||||
|
rfk_phy = realpath(buf2, NULL);
|
||||||
|
if (!rfk_phy)
|
||||||
|
goto fail2;
|
||||||
|
found = os_strcmp(phy, rfk_phy) == 0;
|
||||||
|
free(rfk_phy);
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
continue;
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "rfkill: initial event: idx=%u type=%d "
|
wpa_printf(MSG_DEBUG, "rfkill: initial event: idx=%u type=%d "
|
||||||
"op=%u soft=%u hard=%u",
|
"op=%u soft=%u hard=%u",
|
||||||
event.idx, event.type, event.op, event.soft,
|
event.idx, event.type, event.op, event.soft,
|
||||||
event.hard);
|
event.hard);
|
||||||
if (event.op != RFKILL_OP_ADD ||
|
|
||||||
event.type != RFKILL_TYPE_WLAN)
|
rfkill->idx = event.idx;
|
||||||
continue;
|
|
||||||
if (event.hard) {
|
if (event.hard) {
|
||||||
wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked");
|
wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked");
|
||||||
rfkill->blocked = 1;
|
rfkill->blocked = 1;
|
||||||
|
@ -150,8 +179,12 @@ struct rfkill_data * rfkill_init(struct rfkill_config *cfg)
|
||||||
wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked");
|
wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked");
|
||||||
rfkill->blocked = 1;
|
rfkill->blocked = 1;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
goto fail2;
|
||||||
|
|
||||||
eloop_register_read_sock(rfkill->fd, rfkill_receive, rfkill, NULL);
|
eloop_register_read_sock(rfkill->fd, rfkill_receive, rfkill, NULL);
|
||||||
|
|
||||||
return rfkill;
|
return rfkill;
|
||||||
|
@ -160,6 +193,8 @@ fail2:
|
||||||
close(rfkill->fd);
|
close(rfkill->fd);
|
||||||
fail:
|
fail:
|
||||||
os_free(rfkill);
|
os_free(rfkill);
|
||||||
|
/* use standard free function to match realpath() */
|
||||||
|
free(phy);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue