From aa6ae55fb339b8bd1f37b8443ccff8fa91e660c5 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Wed, 2 Feb 2011 11:51:58 -0800 Subject: [PATCH 13/16] rfkill: Support multiple phys, global rfkill device. Update nl80211 driver to have one global rfkill object, and to correctly deal with events from different phys. Wext was changed to compile, but still needs work to properly deal with a single global rfkill object and pay attention to phy devices. Needs testing on system with rfkill capability. Signed-off-by: Ben Greear --- :100644 100644 ba32f88... f0d0451... M src/drivers/driver_nl80211.c :100644 100644 723ffa2... 6d61fa1... M src/drivers/driver_wext.c :100644 100644 8818311... 03eba71... M src/drivers/rfkill.c :100644 100644 7a984a6... cb790f3... M src/drivers/rfkill.h src/drivers/driver_nl80211.c | 121 ++++++++++++++++++++++++++++++------------ src/drivers/driver_wext.c | 13 +++-- src/drivers/rfkill.c | 75 ++++++++++++++++---------- src/drivers/rfkill.h | 18 ++++--- 4 files changed, 150 insertions(+), 77 deletions(-) diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index ba32f88..f0d0451 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -129,6 +129,7 @@ struct nl80211_global { struct nl_cb *nl_cb; struct genl_family *nl80211; int ioctl_sock; /* socket for ioctl() use */ + struct rfkill_data *rfkill; }; static struct nl80211_global* global_ptr = NULL; @@ -156,10 +157,9 @@ struct wpa_driver_nl80211_data { int ifindex; int if_removed; int if_disabled; - struct rfkill_data *rfkill; struct wpa_driver_capa capa; int has_capability; - + int rfkill_blocked; int operstate; int scan_complete_events; @@ -439,6 +439,9 @@ static int wpa_driver_nl80211_own_ifname(struct wpa_driver_nl80211_data *drv, int attrlen, rta_len; struct rtattr *attr; + if (!buf) + return 0; + attrlen = len; attr = (struct rtattr *) buf; @@ -1676,26 +1679,52 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv) #endif /* HOSTAPD */ -static void wpa_driver_nl80211_rfkill_blocked(void *ctx) +static void wpa_driver_nl80211_rfkill_blocked(void *ctx, int rfkill_idx) { - struct wpa_driver_nl80211_data *drv = ctx; - wpa_msg(drv->ctx, MSG_DEBUG, "nl80211: RFKILL blocked"); - /* - * This may be for any interface; use ifdown event to disable - * interface. + struct nl80211_global *global = ctx; + struct wpa_driver_nl80211_data *drv; + /* For all drivers, check to see if we belong to the + * phy that cooresponds to the rfkill_idx. */ + dl_list_for_each(drv, &global->interfaces, + struct wpa_driver_nl80211_data, list) { + if (rfkill_idx_belongs_to_phyname(rfkill_idx, drv->phyname)) { + if (drv->rfkill_blocked == 1) + continue; + wpa_msg(drv->ctx, MSG_DEBUG, + "nl80211: RFKILL blocked, idx: %i", rfkill_idx); + drv->rfkill_blocked = 1; + /* + * Use ifdown event to disable interface. + */ + } + } } - -static void wpa_driver_nl80211_rfkill_unblocked(void *ctx) +static void wpa_driver_nl80211_rfkill_unblocked(void *ctx, int rfkill_idx) { - struct wpa_driver_nl80211_data *drv = ctx; - wpa_msg(drv->ctx, MSG_DEBUG, "nl80211: RFKILL unblocked"); - if (linux_set_iface_flags(drv->global->ioctl_sock, - drv->first_bss.ifname, 1)) { - wpa_msg(drv->ctx, MSG_DEBUG, "nl80211: Could not set interface UP " - "after rfkill unblock"); - return; + struct nl80211_global *global = ctx; + struct wpa_driver_nl80211_data *drv; + + /* For all drivers, check to see if we belong to the + * phy that cooresponds to the rfkill_idx. + */ + dl_list_for_each(drv, &global->interfaces, + struct wpa_driver_nl80211_data, list) { + if (rfkill_idx_belongs_to_phyname(rfkill_idx, drv->phyname)) { + if (drv->rfkill_blocked == 0) + continue; + wpa_msg(drv->ctx, MSG_DEBUG, + "nl80211: RFKILL unblocked, idx: %i", + rfkill_idx); + drv->rfkill_blocked = 0; + if (linux_set_iface_flags(drv->global->ioctl_sock, + drv->first_bss.ifname, 1)) { + wpa_msg(drv->ctx, MSG_DEBUG, + "nl80211: Could not set interface UP " + "after rfkill unblock"); + } + } } /* rtnetlink ifup handler will report interface as enabled */ } @@ -1808,8 +1837,6 @@ static void wpa_driver_nl80211_deinit(void *priv) nl80211_disable_11b_rates(drv, drv->ifindex, 0); netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 0, IF_OPER_UP); - if (drv->rfkill) - rfkill_deinit(drv->rfkill); eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx); @@ -1837,7 +1864,6 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname, void *global_priv) { struct wpa_driver_nl80211_data *drv; - struct rfkill_config *rcfg; struct i802_bss *bss; drv = os_zalloc(sizeof(*drv)); @@ -1857,19 +1883,6 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname, nl80211_get_phy_name(drv); - 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_msg(drv->ctx, MSG_DEBUG, "nl80211: RFKILL status not available"); - os_free(rcfg); - } - if (wpa_driver_nl80211_finish_drv_init(drv)) goto failed; @@ -1979,6 +1992,10 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv) { struct i802_bss *bss = &drv->first_bss; int send_rfkill_event = 0; +#ifndef HOSTAPD + struct rfkill_config *rcfg; + struct rfkill_data *rfkill; +#endif drv->ifindex = if_nametoindex(bss->ifname); drv->first_bss.ifindex = drv->ifindex; @@ -1989,9 +2006,26 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv) "use managed mode"); } + /* Probe rfkill current state for our phyname */ + rcfg = os_zalloc(sizeof(*rcfg)); + if (rcfg) { + rcfg->ctx = drv; + rfkill = rfkill_init(rcfg, drv->phyname); + if (rfkill == NULL) { + wpa_msg(drv->ctx, MSG_DEBUG, + "nl80211: RFKILL status not available"); + os_free(rcfg); + } else { + /* Set initial state and clean up */ + drv->rfkill_blocked = rfkill->is_blocked; + rfkill_deinit(rfkill); + } + } + if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) { - if (rfkill_is_blocked(drv->rfkill)) { - wpa_msg(drv->ctx, MSG_DEBUG, "nl80211: Could not yet enable " + if (drv->rfkill_blocked) { + wpa_msg(drv->ctx, MSG_DEBUG, + "nl80211: Could not yet enable " "interface '%s' due to rfkill", bss->ifname); drv->if_disabled = 1; @@ -6343,6 +6377,9 @@ static void nl80211_global_deinit(void *priv) if (global->ioctl_sock >= 0) close(global->ioctl_sock); + if (global->rfkill) + rfkill_deinit(global->rfkill); + if (global == global_ptr) global_ptr = NULL; @@ -6355,6 +6392,7 @@ static void * nl80211_global_init(void) struct nl80211_global *global = NULL; struct netlink_config *cfg = NULL; int ret; + struct rfkill_config *rcfg; /* already initailized? */ if (global_ptr) @@ -6483,6 +6521,19 @@ static void * nl80211_global_init(void) goto err; } + rcfg = os_zalloc(sizeof(*rcfg)); + if (rcfg == NULL) + goto err; + rcfg->ctx = global; + rcfg->blocked_cb = wpa_driver_nl80211_rfkill_blocked; + rcfg->unblocked_cb = wpa_driver_nl80211_rfkill_unblocked; + global->rfkill = rfkill_init(rcfg, NULL); + if (global->rfkill == NULL) { + wpa_msg(NULL, MSG_DEBUG, + "nl80211: RFKILL status not available"); + os_free(rcfg); + } + eloop_register_read_sock(nl_socket_get_fd(global->nl_handle_event), wpa_driver_nl80211_event_receive, global, global->nl_handle_event); diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c index 723ffa2..6d61fa1 100644 --- a/src/drivers/driver_wext.c +++ b/src/drivers/driver_wext.c @@ -727,7 +727,7 @@ static void wpa_driver_wext_event_rtm_dellink(void *ctx, struct ifinfomsg *ifi, } -static void wpa_driver_wext_rfkill_blocked(void *ctx) +static void wpa_driver_wext_rfkill_blocked(void *ctx, int rfkill_idx) { struct wpa_driver_wext_data *drv = ctx; wpa_msg(drv->ctx, MSG_DEBUG, "WEXT: RFKILL blocked"); @@ -737,8 +737,10 @@ static void wpa_driver_wext_rfkill_blocked(void *ctx) */ } - -static void wpa_driver_wext_rfkill_unblocked(void *ctx) +/* TODO: Make this deal properly with rfkill_idx, as driver_nl80211 + * does. Make the rfkill object global. + */ +static void wpa_driver_wext_rfkill_unblocked(void *ctx, int rfkill_idx) { struct wpa_driver_wext_data *drv = ctx; wpa_msg(drv->ctx, MSG_DEBUG, "WEXT: RFKILL unblocked"); @@ -837,10 +839,9 @@ void * wpa_driver_wext_init(void *ctx, const char *ifname) if (rcfg == NULL) goto err3; rcfg->ctx = drv; - os_strlcpy(rcfg->ifname, ifname, sizeof(rcfg->ifname)); rcfg->blocked_cb = wpa_driver_wext_rfkill_blocked; rcfg->unblocked_cb = wpa_driver_wext_rfkill_unblocked; - drv->rfkill = rfkill_init(rcfg); + drv->rfkill = rfkill_init(rcfg, NULL); if (drv->rfkill == NULL) { wpa_msg(drv->ctx, MSG_DEBUG, "WEXT: RFKILL status not available"); os_free(rcfg); @@ -884,7 +885,7 @@ static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv) int send_rfkill_event = 0; if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1) < 0) { - if (rfkill_is_blocked(drv->rfkill)) { + if (drv->rfkill->is_blocked) { wpa_msg(drv->ctx, MSG_DEBUG, "WEXT: Could not yet enable " "interface '%s' due to rfkill", drv->ifname); diff --git a/src/drivers/rfkill.c b/src/drivers/rfkill.c index 8818311..03eba71 100644 --- a/src/drivers/rfkill.c +++ b/src/drivers/rfkill.c @@ -49,13 +49,6 @@ enum rfkill_type { }; -struct rfkill_data { - struct rfkill_config *cfg; - int fd; - int blocked; -}; - - static void rfkill_receive(int sock, void *eloop_ctx, void *sock_ctx) { struct rfkill_data *rfkill = eloop_ctx; @@ -93,17 +86,45 @@ static void rfkill_receive(int sock, void *eloop_ctx, void *sock_ctx) new_blocked = 0; } - if (new_blocked != rfkill->blocked) { - rfkill->blocked = new_blocked; - if (new_blocked) - rfkill->cfg->blocked_cb(rfkill->cfg->ctx); - else - rfkill->cfg->unblocked_cb(rfkill->cfg->ctx); + if (new_blocked) { + if (rfkill->cfg->blocked_cb) + rfkill->cfg->blocked_cb(rfkill->cfg->ctx, event.idx); + } else { + if (rfkill->cfg->unblocked_cb) + rfkill->cfg->unblocked_cb(rfkill->cfg->ctx, event.idx); } } +int rfkill_idx_belongs_to_phyname(int rfkill_idx, + const char *phyname) +{ + /* Phyname: /sys/class/rfkill/rfkill[idx]/device/name */ + char buf[100]; + int fd; + snprintf(buf, sizeof(buf), + "/sys/class/rfkill/rfkill%d/device/name", rfkill_idx); + fd = open(buf, O_RDONLY); + if (fd) { + int rv; + buf[0] = 0; + rv = read(fd, buf, sizeof(buf)); + close(fd); + if (rv > 0) { + buf[rv] = 0; + if (strcmp(buf, phyname) == 0) + return 1; + } + return 0; + } + /* Maybe devfs isn't mounted or existing? Or on older + * kernel that doesn't have requested sysfs file? + * Assume one rfkill struct for all devices. + */ + return 1; +} + -struct rfkill_data * rfkill_init(struct rfkill_config *cfg) +struct rfkill_data * rfkill_init(struct rfkill_config *cfg, const char *phyname) { struct rfkill_data *rfkill; struct rfkill_event event; @@ -149,12 +170,17 @@ struct rfkill_data * rfkill_init(struct rfkill_config *cfg) if (event.op != RFKILL_OP_ADD || event.type != RFKILL_TYPE_WLAN) continue; - if (event.hard) { - wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked"); - rfkill->blocked = 1; - } else if (event.soft) { - wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked"); - rfkill->blocked = 1; + if (!phyname || !phyname[0] || + rfkill_idx_belongs_to_phyname(event.idx, phyname)) { + if (event.hard) { + wpa_printf(MSG_INFO, + "rfkill: WLAN hard blocked"); + rfkill->is_blocked = 1; + } else if (event.soft) { + wpa_printf(MSG_INFO, + "rfkill: WLAN soft blocked"); + rfkill->is_blocked = 1; + } } } @@ -183,12 +209,3 @@ void rfkill_deinit(struct rfkill_data *rfkill) os_free(rfkill->cfg); os_free(rfkill); } - - -int rfkill_is_blocked(struct rfkill_data *rfkill) -{ - if (rfkill == NULL) - return 0; - - return rfkill->blocked; -} diff --git a/src/drivers/rfkill.h b/src/drivers/rfkill.h index 7a984a6..cb790f3 100644 --- a/src/drivers/rfkill.h +++ b/src/drivers/rfkill.h @@ -15,17 +15,21 @@ #ifndef RFKILL_H #define RFKILL_H -struct rfkill_data; +struct rfkill_data { + struct rfkill_config *cfg; + int fd; + int is_blocked; +}; struct rfkill_config { void *ctx; - char ifname[IFNAMSIZ]; - void (*blocked_cb)(void *ctx); - void (*unblocked_cb)(void *ctx); + void (*blocked_cb)(void *ctx, int rfkill_index); + void (*unblocked_cb)(void *ctx, int rfkill_index); }; -struct rfkill_data * rfkill_init(struct rfkill_config *cfg); +struct rfkill_data * rfkill_init(struct rfkill_config *cfg, + const char *phyname); void rfkill_deinit(struct rfkill_data *rfkill); -int rfkill_is_blocked(struct rfkill_data *rfkill); - +int rfkill_idx_belongs_to_phyname(int rfkill_idx, + const char *phyname); #endif /* RFKILL_H */ -- 1.6.2.5