diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 355e84200..ed5e4a8e2 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -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, void *global_priv, int hostapd, const u8 *set_addr, const char *driver_params) { struct wpa_driver_nl80211_data *drv; - struct rfkill_config *rcfg; struct i802_bss *bss; 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)) 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) 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) nl80211_get_macaddr(bss); + wpa_driver_nl80211_drv_init_rfkill(drv); + if (!rfkill_is_blocked(drv->rfkill)) { int ret = i802_set_iface_flags(bss, 1); if (ret) { diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h index 21c0b6db9..09e03b3dd 100644 --- a/src/drivers/driver_nl80211.h +++ b/src/drivers/driver_nl80211.h @@ -84,6 +84,7 @@ struct wpa_driver_nl80211_data { struct dl_list list; struct dl_list wiphy_list; char phyname[32]; + unsigned int wiphy_idx; u8 perm_addr[ETH_ALEN]; void *ctx; int ifindex; diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c index c74ed5ff7..8c3ba491d 100644 --- a/src/drivers/driver_nl80211_capa.c +++ b/src/drivers/driver_nl80211_capa.c @@ -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), 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]) os_strlcpy(drv->phyname, nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]), diff --git a/src/drivers/rfkill.c b/src/drivers/rfkill.c index 45b26c46b..464cf7834 100644 --- a/src/drivers/rfkill.c +++ b/src/drivers/rfkill.c @@ -8,6 +8,7 @@ #include "includes.h" #include +#include #include "utils/common.h" #include "utils/eloop.h" @@ -47,6 +48,7 @@ struct rfkill_data { struct rfkill_config *cfg; int fd; 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); return; } + if (event.op != RFKILL_OP_CHANGE || event.idx != rfkill->idx) + return; + wpa_printf(MSG_DEBUG, "rfkill: event: idx=%u type=%d " "op=%u soft=%u hard=%u", event.idx, event.type, event.op, event.soft, event.hard); - if (event.op != RFKILL_OP_CHANGE || event.type != RFKILL_TYPE_WLAN) - return; if (event.hard) { 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_event event; 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)); if (rfkill == 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->fd = open("/dev/rfkill", O_RDONLY); if (rfkill->fd < 0) { @@ -136,13 +151,27 @@ struct rfkill_data * rfkill_init(struct rfkill_config *cfg) (int) len, RFKILL_EVENT_SIZE_V1); 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 " "op=%u soft=%u hard=%u", event.idx, event.type, event.op, event.soft, event.hard); - if (event.op != RFKILL_OP_ADD || - event.type != RFKILL_TYPE_WLAN) - continue; + + rfkill->idx = event.idx; if (event.hard) { wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked"); rfkill->blocked = 1; @@ -150,8 +179,12 @@ struct rfkill_data * rfkill_init(struct rfkill_config *cfg) wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked"); rfkill->blocked = 1; } + break; } + if (!found) + goto fail2; + eloop_register_read_sock(rfkill->fd, rfkill_receive, rfkill, NULL); return rfkill; @@ -160,6 +193,8 @@ fail2: close(rfkill->fd); fail: os_free(rfkill); + /* use standard free function to match realpath() */ + free(phy); return NULL; }