diff --git a/src/common/defs.h b/src/common/defs.h index 173bbd1c9..f3f80a697 100644 --- a/src/common/defs.h +++ b/src/common/defs.h @@ -136,6 +136,15 @@ enum wpa_states { */ WPA_DISCONNECTED, + /** + * WPA_INTERFACE_DISABLED - Interface disabled + * + * This stat eis entered if the network interface is disabled, e.g., + * due to rfkill. wpa_supplicant refuses any new operations that would + * use the radio until the interface has been enabled. + */ + WPA_INTERFACE_DISABLED, + /** * WPA_INACTIVE - Inactive state (wpa_supplicant disabled) * diff --git a/src/drivers/driver.h b/src/drivers/driver.h index fa49da454..85ca0a5be 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -2046,7 +2046,23 @@ enum wpa_event_type { * observed in frames received from the current AP if signal strength * monitoring has been enabled with signal_monitor(). */ - EVENT_SIGNAL_CHANGE + EVENT_SIGNAL_CHANGE, + + /** + * EVENT_INTERFACE_ENABLED - Notify that interface was enabled + * + * This event is used to indicate that the interface was enabled after + * having been previously disabled, e.g., due to rfkill. + */ + EVENT_INTERFACE_ENABLED, + + /** + * EVENT_INTERFACE_DISABLED - Notify that interface was disabled + * + * This event is used to indicate that the interface was disabled, + * e.g., due to rfkill. + */ + EVENT_INTERFACE_DISABLED }; diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index a1233274c..136ca11c9 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -33,6 +33,7 @@ #include "linux_ioctl.h" #include "radiotap.h" #include "radiotap_iter.h" +#include "rfkill.h" #include "driver.h" #ifdef CONFIG_LIBNL20 @@ -72,6 +73,7 @@ struct wpa_driver_nl80211_data { char brname[IFNAMSIZ]; int ifindex; int if_removed; + struct rfkill_data *rfkill; struct wpa_driver_capa capa; int has_capability; @@ -1347,6 +1349,27 @@ err1: } +static void wpa_driver_nl80211_rfkill_blocked(void *ctx) +{ + struct wpa_driver_nl80211_data *drv = ctx; + wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked"); + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL); +} + + +static void wpa_driver_nl80211_rfkill_unblocked(void *ctx) +{ + struct wpa_driver_nl80211_data *drv = ctx; + wpa_printf(MSG_DEBUG, "nl80211: RFKILL unblocked"); + if (linux_set_iface_flags(drv->ioctl_sock, drv->first_bss.ifname, 1)) { + wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP " + "after rfkill unblock"); + return; + } + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, NULL); +} + + /** * wpa_driver_nl80211_init - Initialize nl80211 driver interface * @ctx: context to be used when calling wpa_supplicant functions, @@ -1358,6 +1381,7 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname) { struct wpa_driver_nl80211_data *drv; struct netlink_config *cfg; + struct rfkill_config *rcfg; struct i802_bss *bss; drv = os_zalloc(sizeof(*drv)); @@ -1393,12 +1417,25 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname) os_free(cfg); 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"); + if (wpa_driver_nl80211_finish_drv_init(drv)) goto failed; return bss; failed: + rfkill_deinit(drv->rfkill); netlink_deinit(drv->netlink); if (drv->ioctl_sock >= 0) close(drv->ioctl_sock); @@ -1459,10 +1496,17 @@ static int nl80211_register_action_frames(struct wpa_driver_nl80211_data *drv) } +static void wpa_driver_nl80211_send_rfkill(void *eloop_ctx, void *timeout_ctx) +{ + wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL); +} + + static int wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv) { struct i802_bss *bss = &drv->first_bss; + int send_rfkill_event = 0; drv->ifindex = if_nametoindex(bss->ifname); drv->first_bss.ifindex = drv->ifindex; @@ -1474,9 +1518,16 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv) } if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) { - wpa_printf(MSG_ERROR, "Could not set interface '%s' UP", - bss->ifname); - return -1; + if (rfkill_is_blocked(drv->rfkill)) { + wpa_printf(MSG_DEBUG, "nl80211: Could not yet enable " + "interface '%s' due to rfkill", + bss->ifname); + send_rfkill_event = 1; + } else { + wpa_printf(MSG_ERROR, "nl80211: Could not set " + "interface '%s' UP", bss->ifname); + return -1; + } } if (wpa_driver_nl80211_capa(drv)) @@ -1496,6 +1547,11 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv) */ } + if (send_rfkill_event) { + eloop_register_timeout(0, 0, wpa_driver_nl80211_send_rfkill, + drv, drv->ctx); + } + return 0; } @@ -1572,6 +1628,7 @@ static void wpa_driver_nl80211_deinit(void *priv) netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP); netlink_deinit(drv->netlink); + rfkill_deinit(drv->rfkill); eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx); diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c index 2614f2309..ef3a30c3b 100644 --- a/src/drivers/driver_wext.c +++ b/src/drivers/driver_wext.c @@ -31,6 +31,7 @@ #include "priv_netlink.h" #include "netlink.h" #include "linux_ioctl.h" +#include "rfkill.h" #include "driver.h" #include "driver_wext.h" @@ -687,6 +688,27 @@ static void wpa_driver_wext_event_rtm_dellink(void *ctx, struct ifinfomsg *ifi, } +static void wpa_driver_wext_rfkill_blocked(void *ctx) +{ + struct wpa_driver_wext_data *drv = ctx; + wpa_printf(MSG_DEBUG, "WEXT: RFKILL blocked"); + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL); +} + + +static void wpa_driver_wext_rfkill_unblocked(void *ctx) +{ + struct wpa_driver_wext_data *drv = ctx; + wpa_printf(MSG_DEBUG, "WEXT: RFKILL unblocked"); + if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1)) { + wpa_printf(MSG_DEBUG, "WEXT: Could not set interface UP " + "after rfkill unblock"); + return; + } + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, NULL); +} + + /** * wpa_driver_wext_init - Initialize WE driver interface * @ctx: context to be used when calling wpa_supplicant functions, @@ -698,6 +720,7 @@ void * wpa_driver_wext_init(void *ctx, const char *ifname) { struct wpa_driver_wext_data *drv; struct netlink_config *cfg; + struct rfkill_config *rcfg; char path[128]; struct stat buf; @@ -731,6 +754,17 @@ void * wpa_driver_wext_init(void *ctx, const char *ifname) goto err2; } + rcfg = os_zalloc(sizeof(*rcfg)); + 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); + if (drv->rfkill == NULL) + wpa_printf(MSG_DEBUG, "WEXT: RFKILL status not available"); + drv->mlme_sock = -1; if (wpa_driver_wext_finish_drv_init(drv) < 0) @@ -741,6 +775,7 @@ void * wpa_driver_wext_init(void *ctx, const char *ifname) return drv; err3: + rfkill_deinit(drv->rfkill); netlink_deinit(drv->netlink); err2: close(drv->ioctl_sock); @@ -750,10 +785,28 @@ err1: } +static void wpa_driver_wext_send_rfkill(void *eloop_ctx, void *timeout_ctx) +{ + wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL); +} + + static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv) { - if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1) < 0) - return -1; + int send_rfkill_event = 0; + + if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1) < 0) { + if (rfkill_is_blocked(drv->rfkill)) { + wpa_printf(MSG_DEBUG, "WEXT: Could not yet enable " + "interface '%s' due to rfkill", + drv->ifname); + send_rfkill_event = 1; + } else { + wpa_printf(MSG_ERROR, "WEXT: Could not set " + "interface '%s' UP", drv->ifname); + return -1; + } + } /* * Make sure that the driver does not have any obsolete PMKID entries. @@ -795,6 +848,11 @@ static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv) netlink_send_oper_ifla(drv->netlink, drv->ifindex, 1, IF_OPER_DORMANT); + if (send_rfkill_event) { + eloop_register_timeout(0, 0, wpa_driver_wext_send_rfkill, + drv, drv->ctx); + } + return 0; } @@ -822,6 +880,7 @@ void wpa_driver_wext_deinit(void *priv) netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP); netlink_deinit(drv->netlink); + rfkill_deinit(drv->rfkill); if (drv->mlme_sock >= 0) eloop_unregister_read_sock(drv->mlme_sock); diff --git a/src/drivers/driver_wext.h b/src/drivers/driver_wext.h index 602c7e1f6..22d26a6b5 100644 --- a/src/drivers/driver_wext.h +++ b/src/drivers/driver_wext.h @@ -26,6 +26,7 @@ struct wpa_driver_wext_data { int ifindex; int ifindex2; int if_removed; + struct rfkill_data *rfkill; u8 *assoc_req_ies; size_t assoc_req_ies_len; u8 *assoc_resp_ies; diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak index b76b22953..b1b05cc63 100644 --- a/src/drivers/drivers.mak +++ b/src/drivers/drivers.mak @@ -31,6 +31,7 @@ NEED_SME=y NEED_AP_MLME=y NEED_NETLINK=y NEED_LINUX_IOCTL=y +NEED_RFKILL=y DRV_LIBS += -lnl ifdef CONFIG_LIBNL20 @@ -77,6 +78,7 @@ DRV_WPA_CFLAGS += -DCONFIG_DRIVER_WEXT CONFIG_WIRELESS_EXTENSION=y NEED_NETLINK=y NEED_LINUX_IOCTL=y +NEED_RFKILL=y endif ifdef CONFIG_DRIVER_HERMES @@ -162,6 +164,10 @@ ifdef NEED_LINUX_IOCTL DRV_OBJS += ../src/drivers/linux_ioctl.o endif +ifdef NEED_RFKILL +DRV_OBJS += ../src/drivers/rfkill.o +endif + ##### COMMON VARS DRV_BOTH_CFLAGS := $(DRV_CFLAGS) $(DRV_WPA_CFLAGS) $(DRV_AP_CFLAGS) diff --git a/src/drivers/rfkill.c b/src/drivers/rfkill.c new file mode 100644 index 000000000..88183110f --- /dev/null +++ b/src/drivers/rfkill.c @@ -0,0 +1,194 @@ +/* + * Linux rfkill helper functions for driver wrappers + * Copyright (c) 2010, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" +#include + +#include "utils/common.h" +#include "utils/eloop.h" +#include "rfkill.h" + +#define RFKILL_EVENT_SIZE_V1 8 + +struct rfkill_event { + u32 idx; + u8 type; + u8 op; + u8 soft; + u8 hard; +} STRUCT_PACKED; + +enum rfkill_operation { + RFKILL_OP_ADD = 0, + RFKILL_OP_DEL, + RFKILL_OP_CHANGE, + RFKILL_OP_CHANGE_ALL, +}; + +enum rfkill_type { + RFKILL_TYPE_ALL = 0, + RFKILL_TYPE_WLAN, + RFKILL_TYPE_BLUETOOTH, + RFKILL_TYPE_UWB, + RFKILL_TYPE_WIMAX, + RFKILL_TYPE_WWAN, + RFKILL_TYPE_GPS, + RFKILL_TYPE_FM, + NUM_RFKILL_TYPES, +}; + + +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; + struct rfkill_event event; + ssize_t len; + int new_blocked; + + len = read(rfkill->fd, &event, sizeof(event)); + if (len < 0) { + wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s", + strerror(errno)); + return; + } + if (len != RFKILL_EVENT_SIZE_V1) { + wpa_printf(MSG_DEBUG, "rfkill: Unexpected event size " + "%d (expected %d)", + (int) len, RFKILL_EVENT_SIZE_V1); + 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"); + new_blocked = 1; + } else if (event.soft) { + wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked"); + new_blocked = 1; + } else { + wpa_printf(MSG_INFO, "rfkill: WLAN unblocked"); + 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); + } +} + + +struct rfkill_data * rfkill_init(struct rfkill_config *cfg) +{ + struct rfkill_data *rfkill; + struct rfkill_event event; + ssize_t len; + + rfkill = os_zalloc(sizeof(*rfkill)); + if (rfkill == NULL) + return NULL; + + rfkill->cfg = cfg; + rfkill->fd = open("/dev/rfkill", O_RDONLY); + if (rfkill->fd < 0) { + wpa_printf(MSG_INFO, "rfkill: Cannot open RFKILL control " + "device"); + goto fail; + } + + if (fcntl(rfkill->fd, F_SETFL, O_NONBLOCK) < 0) { + wpa_printf(MSG_ERROR, "rfkill: Cannot set non-blocking mode: " + "%s", strerror(errno)); + goto fail2; + } + + for (;;) { + len = read(rfkill->fd, &event, sizeof(event)); + if (len < 0) { + if (errno == EAGAIN) + break; /* No more entries */ + wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s", + strerror(errno)); + break; + } + if (len != RFKILL_EVENT_SIZE_V1) { + wpa_printf(MSG_DEBUG, "rfkill: Unexpected event size " + "%d (expected %d)", + (int) len, RFKILL_EVENT_SIZE_V1); + 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; + 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; + } + } + + eloop_register_read_sock(rfkill->fd, rfkill_receive, rfkill, NULL); + + return rfkill; + +fail2: + close(rfkill->fd); +fail: + os_free(rfkill); + return NULL; +} + + +void rfkill_deinit(struct rfkill_data *rfkill) +{ + if (rfkill == NULL) + return; + + if (rfkill->fd >= 0) { + eloop_unregister_read_sock(rfkill->fd); + close(rfkill->fd); + } + + 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 new file mode 100644 index 000000000..7a984a631 --- /dev/null +++ b/src/drivers/rfkill.h @@ -0,0 +1,31 @@ +/* + * Linux rfkill helper functions for driver wrappers + * Copyright (c) 2010, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef RFKILL_H +#define RFKILL_H + +struct rfkill_data; + +struct rfkill_config { + void *ctx; + char ifname[IFNAMSIZ]; + void (*blocked_cb)(void *ctx); + void (*unblocked_cb)(void *ctx); +}; + +struct rfkill_data * rfkill_init(struct rfkill_config *cfg); +void rfkill_deinit(struct rfkill_data *rfkill); +int rfkill_is_blocked(struct rfkill_data *rfkill); + +#endif /* RFKILL_H */ diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 19fea29fd..d4383e799 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -1742,11 +1742,17 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strcmp(buf, "LOGOFF") == 0) { eapol_sm_notify_logoff(wpa_s->eapol, TRUE); } else if (os_strcmp(buf, "REASSOCIATE") == 0) { - wpa_s->disconnected = 0; - wpa_s->reassociate = 1; - wpa_supplicant_req_scan(wpa_s, 0, 0); + if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) + reply_len = -1; + else { + wpa_s->disconnected = 0; + wpa_s->reassociate = 1; + wpa_supplicant_req_scan(wpa_s, 0, 0); + } } else if (os_strcmp(buf, "RECONNECT") == 0) { - if (wpa_s->disconnected) { + if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) + reply_len = -1; + else if (wpa_s->disconnected) { wpa_s->disconnected = 0; wpa_s->reassociate = 1; wpa_supplicant_req_scan(wpa_s, 0, 0); @@ -1832,8 +1838,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); } else if (os_strcmp(buf, "SCAN") == 0) { - wpa_s->scan_req = 2; - wpa_supplicant_req_scan(wpa_s, 0, 0); + if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) + reply_len = -1; + else { + wpa_s->scan_req = 2; + wpa_supplicant_req_scan(wpa_s, 0, 0); + } } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) { reply_len = wpa_supplicant_ctrl_iface_scan_results( wpa_s, reply, reply_size); diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 2f3a303c4..d9801acfd 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -109,6 +109,9 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s) { int bssid_changed; + if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) + return; + wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); bssid_changed = !is_zero_ether_addr(wpa_s->bssid); os_memset(wpa_s->bssid, 0, ETH_ALEN); @@ -1583,6 +1586,14 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, struct wpa_supplicant *wpa_s = ctx; u16 reason_code = 0; + if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED && + event != EVENT_INTERFACE_ENABLED && + event != EVENT_INTERFACE_STATUS) { + wpa_printf(MSG_DEBUG, "Ignore event %d while interface is " + "disabled", event); + return; + } + switch (event) { case EVENT_AUTH: sme_event_auth(wpa_s, data); @@ -1726,6 +1737,19 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, bgscan_notify_signal_change( wpa_s, data->signal_change.above_threshold); break; + case EVENT_INTERFACE_ENABLED: + wpa_printf(MSG_DEBUG, "Interface was enabled"); + if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { + wpa_supplicant_set_state(wpa_s, + WPA_DISCONNECTED); + wpa_supplicant_req_scan(wpa_s, 0, 0); + } + break; + case EVENT_INTERFACE_DISABLED: + wpa_printf(MSG_DEBUG, "Interface was disabled"); + wpa_supplicant_mark_disassoc(wpa_s); + wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED); + break; default: wpa_printf(MSG_INFO, "Unknown event %d", event); break; diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index 458b98122..efbc3478e 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -251,6 +251,11 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) size_t max_ssids; enum wpa_states prev_state; + if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { + wpa_printf(MSG_DEBUG, "Skip scan - interface disabled"); + return; + } + if (wpa_s->disconnected && !wpa_s->scan_req) { wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); return; diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 5563f0bc4..6c0144482 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -489,6 +489,8 @@ const char * wpa_supplicant_state_txt(enum wpa_states state) return "DISCONNECTED"; case WPA_INACTIVE: return "INACTIVE"; + case WPA_INTERFACE_DISABLED: + return "INTERFACE_DISABLED"; case WPA_SCANNING: return "SCANNING"; case WPA_AUTHENTICATING: @@ -592,7 +594,8 @@ static void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s) wpa_s->group_cipher = 0; wpa_s->mgmt_group_cipher = 0; wpa_s->key_mgmt = 0; - wpa_s->wpa_state = WPA_DISCONNECTED; + if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED) + wpa_s->wpa_state = WPA_DISCONNECTED; if (wpa_s->wpa_state != old_state) wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);