[PATCH] dbus_new: add property to track reason for a state change

mukesh agrawal quiche
Mon Oct 24 15:54:59 PDT 2011


In the connection manager, it is sometimes useful to disambiguate the
reason for a connection failure. For example, if a connection attempt
fails due to WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT, it is more likely
that the connection manager has the wrong key than if the connection
attempt fails due to WLAN_REASON_DEAUTH_LEAVING.

This patch
- adds a new D-Bus property, "StateChangeReason"
- adds a reason_code argument to wpa_supplicant_set_state
- modifies wpa_supplicant_event_disassoc to pass the disconnect_reason
  down to wpa_supplicant_set_state (via wpa_supplicant_mark_disassoc)
- modifies sme_event_assoc_reject to pass the status_code down to
  wpa_supplicant_set_state (via sme_deauth)
- modifies wpa_supplicant_disassociate and wpa_supplicant_deauthenticate
  to pass the reason_code down to wpa_supplicant_set_state
  (via wpa_supplicant_clear_connection and wpa_supplicant_mark_disassoc)
- sets the state change reason to -1 in all other cases (where no reason
  is readily available)

Change-Id: I91e17f02d79c841c0a81ea71a547857bad2a7a27
---
 wpa_supplicant/ap.c                     |    2 +-
 wpa_supplicant/dbus/dbus_new.c          |    9 ++++++
 wpa_supplicant/dbus/dbus_new.h          |    1 +
 wpa_supplicant/dbus/dbus_new_handlers.c |   17 ++++++++++++
 wpa_supplicant/dbus/dbus_new_handlers.h |    3 ++
 wpa_supplicant/events.c                 |   42 +++++++++++++++++++-----------
 wpa_supplicant/notify.c                 |    2 +
 wpa_supplicant/scan.c                   |   12 ++++++---
 wpa_supplicant/sme.c                    |   20 ++++++++------
 wpa_supplicant/wpa_supplicant.c         |   34 +++++++++++++++++-------
 wpa_supplicant/wpa_supplicant_i.h       |    9 +++++-
 wpa_supplicant/wpas_glue.c              |   10 ++++---
 12 files changed, 115 insertions(+), 46 deletions(-)

diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 95279d3..494ea76 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -297,7 +297,7 @@ static void wpas_ap_configured_cb(void *ctx)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 
-	wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+	wpa_supplicant_set_state(wpa_s, WPA_COMPLETED, LOCAL_REASON_UNKNOWN);
 
 	if (wpa_s->ap_configured_cb)
 		wpa_s->ap_configured_cb(wpa_s->ap_configured_cb_ctx,
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index 49a0895..377e0da 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -700,6 +700,11 @@ void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
 			wpas_dbus_getter_current_auth_mode;
 		prop = "CurrentAuthMode";
 		break;
+	case WPAS_DBUS_PROP_STATE_CHANGE_REASON:
+		getter = (WPADBusPropertyAccessor)
+			wpas_dbus_getter_state_change_reason;
+		prop = "StateChangeReason";
+		break;
 	default:
 		wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
 			   __func__, property);
@@ -1444,6 +1449,10 @@ static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
 	  RW
 	},
 #endif /* CONFIG_WPS */
+	{ "StateChangeReason", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
+	  (WPADBusPropertyAccessor) wpas_dbus_getter_state_change_reason,
+	  NULL, R
+	},
 	{ NULL, NULL, NULL, NULL, NULL, 0 }
 };
 
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index 377e381..eab8406 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -32,6 +32,7 @@ enum wpas_dbus_prop {
 	WPAS_DBUS_PROP_CURRENT_NETWORK,
 	WPAS_DBUS_PROP_CURRENT_AUTH_MODE,
 	WPAS_DBUS_PROP_BSSS,
+	WPAS_DBUS_PROP_STATE_CHANGE_REASON,
 };
 
 enum wpas_dbus_bss_prop {
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index e954020..26975b2 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -2459,6 +2459,23 @@ DBusMessage * wpas_dbus_getter_current_auth_mode(DBusMessage *message,
 
 
 /**
+ * wpas_dbus_getter_state_change_reason - Get reason code for last state change
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A message containing value of state_change_reason variable. Value
+ * is -1 if reason is unknown to wpa_supplicant.
+ *
+ * Getter for "StateChangeReason" property.
+ */
+DBusMessage * wpas_dbus_getter_state_change_reason(DBusMessage *message,
+						   struct wpa_supplicant *wpa_s)
+{
+	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_INT32,
+						&wpa_s->state_change_reason);
+}
+
+
+/**
  * wpas_dbus_getter_bridge_ifname - Get interface name
  * @message: Pointer to incoming dbus message
  * @wpa_s: wpa_supplicant structure for a network interface
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index 742d33c..97274e9 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -152,6 +152,9 @@ DBusMessage * wpas_dbus_getter_current_network(DBusMessage *message,
 DBusMessage * wpas_dbus_getter_current_auth_mode(DBusMessage *message,
 						 struct wpa_supplicant *wpa_s);
 
+DBusMessage * wpas_dbus_getter_state_change_reason(DBusMessage *message,
+						   struct wpa_supplicant *wpa_s);
+
 DBusMessage * wpas_dbus_getter_bsss(DBusMessage *message,
 				    struct wpa_supplicant *wpa_s);
 
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 69d2191..3ee87d0 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -109,7 +109,8 @@ static void wpa_supplicant_stop_countermeasures(void *eloop_ctx,
 }
 
 
-void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
+void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s,
+				  int32_t reason_code)
 {
 	int bssid_changed;
 
@@ -121,7 +122,7 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
 	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
 		return;
 
-	wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+	wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED, reason_code);
 	bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
 	os_memset(wpa_s->bssid, 0, ETH_ALEN);
 	os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
@@ -672,7 +673,8 @@ static void wpa_supplicant_req_new_scan(struct wpa_supplicant *wpa_s,
 		 * we don't wait timeout seconds before transitioning
 		 * to INACTIVE state.
 		 */
-		wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
+		wpa_supplicant_set_state(wpa_s, WPA_INACTIVE,
+					 LOCAL_REASON_UNKNOWN);
 		return;
 	}
 	wpa_supplicant_req_scan(wpa_s, timeout_sec, timeout_usec);
@@ -931,7 +933,8 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
 	}
 
 	if (wpa_s->disconnected) {
-		wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+		wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED,
+					 LOCAL_REASON_UNKNOWN);
 		wpa_scan_results_free(scan_res);
 		return 0;
 	}
@@ -960,7 +963,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
 		 */
 		wpa_printf(MSG_INFO, "Fast reconnect failed");
 		wpa_scan_results_free(scan_res);
-		wpa_supplicant_mark_disassoc(wpa_s);
+		wpa_supplicant_mark_disassoc(wpa_s, LOCAL_REASON_UNKNOWN);
 	} else {
 		wpa_scan_results_free(scan_res);
 		wpa_dbg(wpa_s, MSG_DEBUG, "No suitable network found");
@@ -1218,7 +1221,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
 	if (data && wpa_supplicant_event_associnfo(wpa_s, data) < 0)
 		return;
 
-	wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATED);
+	wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATED, LOCAL_REASON_UNKNOWN);
 	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
 		os_memcpy(bssid, wpa_s->bssid, ETH_ALEN);
 	if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) ||
@@ -1293,7 +1296,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
 	    (wpa_s->current_ssid &&
 	     wpa_s->current_ssid->mode == IEEE80211_MODE_IBSS)) {
 		wpa_supplicant_cancel_auth_timeout(wpa_s);
-		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED,
+					 LOCAL_REASON_UNKNOWN);
 	} else if (!ft_completed) {
 		/* Timeout for receiving the first EAPOL packet */
 		wpa_supplicant_req_auth_timeout(wpa_s, 10, 0);
@@ -1307,7 +1311,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
 		 * handshake.
 		 */
 		wpa_supplicant_cancel_auth_timeout(wpa_s);
-		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED,
+					 LOCAL_REASON_UNKNOWN);
 		eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
 		eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
 	} else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
@@ -1324,7 +1329,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
 		 * up in authenticated.
 		 */
 		wpa_supplicant_cancel_auth_timeout(wpa_s);
-		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED,
+					 LOCAL_REASON_UNKNOWN);
 		eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
 		eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
 	}
@@ -1500,7 +1506,7 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
 		wpa_printf(MSG_DEBUG, "Fast reconnect: Failed to trigger scan");
 		wpa_supplicant_req_scan(wpa_s, 0, 100000);
 	}
-	wpa_supplicant_mark_disassoc(wpa_s);
+	wpa_supplicant_mark_disassoc(wpa_s, reason_code);
 
 	if (authenticating && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME))
 		sme_disassoc_while_authenticating(wpa_s, prev_pending_bssid);
@@ -1648,7 +1654,7 @@ wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s,
 	case EVENT_INTERFACE_REMOVED:
 		wpa_dbg(wpa_s, MSG_DEBUG, "Configured interface was removed");
 		wpa_s->interface_removed = 1;
-		wpa_supplicant_mark_disassoc(wpa_s);
+		wpa_supplicant_mark_disassoc(wpa_s, LOCAL_REASON_UNKNOWN);
 		l2_packet_deinit(wpa_s->l2);
 		wpa_s->l2 = NULL;
 #ifdef CONFIG_IBSS_RSN
@@ -2206,21 +2212,25 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 #ifdef CONFIG_AP
 			if (!wpa_s->ap_iface) {
 				wpa_supplicant_set_state(wpa_s,
-							 WPA_DISCONNECTED);
+							 WPA_DISCONNECTED,
+							 LOCAL_REASON_UNKNOWN);
 				wpa_supplicant_req_scan(wpa_s, 0, 0);
 			} else
 				wpa_supplicant_set_state(wpa_s,
-							 WPA_COMPLETED);
+							 WPA_COMPLETED,
+							 LOCAL_REASON_UNKNOWN);
 #else /* CONFIG_AP */
-			wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+			wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED,
+						 LOCAL_REASON_UNKNOWN);
 			wpa_supplicant_req_scan(wpa_s, 0, 0);
 #endif /* CONFIG_AP */
 		}
 		break;
 	case EVENT_INTERFACE_DISABLED:
 		wpa_dbg(wpa_s, MSG_DEBUG, "Interface was disabled");
-		wpa_supplicant_mark_disassoc(wpa_s);
-		wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
+		wpa_supplicant_mark_disassoc(wpa_s, LOCAL_REASON_UNKNOWN);
+		wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED,
+					 LOCAL_REASON_UNKNOWN);
 		break;
 	case EVENT_CHANNEL_LIST_CHANGED:
 		if (wpa_s->drv_priv == NULL)
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 2053c3d..d3bb6b0 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -83,6 +83,8 @@ void wpas_notify_state_changed(struct wpa_supplicant *wpa_s,
 
 	/* notify the new DBus API */
 	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_STATE);
+	wpas_dbus_signal_prop_changed(wpa_s,
+				      WPAS_DBUS_PROP_STATE_CHANGE_REASON);
 
 #ifdef CONFIG_P2P
 	if (new_state == WPA_COMPLETED)
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 4fb9bef..e9e2bc0 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -260,14 +260,16 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
 	}
 
 	if (wpa_s->disconnected && !wpa_s->scan_req) {
-		wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+		wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED,
+					 LOCAL_REASON_UNKNOWN);
 		return;
 	}
 
 	if (!wpa_supplicant_enabled_networks(wpa_s->conf) &&
 	    !wpa_s->scan_req) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks - do not scan");
-		wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
+		wpa_supplicant_set_state(wpa_s, WPA_INACTIVE,
+					 LOCAL_REASON_UNKNOWN);
 		return;
 	}
 
@@ -305,7 +307,8 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
 	prev_state = wpa_s->wpa_state;
 	if (wpa_s->wpa_state == WPA_DISCONNECTED ||
 	    wpa_s->wpa_state == WPA_INACTIVE)
-		wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
+		wpa_supplicant_set_state(wpa_s, WPA_SCANNING,
+					 LOCAL_REASON_UNKNOWN);
 
 	/* Find the starting point from which to continue scanning */
 	ssid = wpa_s->conf->ssid;
@@ -472,7 +475,8 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
 	if (ret) {
 		wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan");
 		if (prev_state != wpa_s->wpa_state)
-			wpa_supplicant_set_state(wpa_s, prev_state);
+			wpa_supplicant_set_state(wpa_s, prev_state,
+						 LOCAL_REASON_UNKNOWN);
 		wpa_supplicant_req_scan(wpa_s, 1, 0);
 	}
 }
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 325ffc5..4393b29 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -244,7 +244,8 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
 		wpa_ssid_txt(params.ssid, params.ssid_len), params.freq);
 
 	wpa_clear_keys(wpa_s, bss->bssid);
-	wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING);
+	wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING,
+				 LOCAL_REASON_UNKNOWN);
 	old_ssid = wpa_s->current_ssid;
 	wpa_s->current_ssid = ssid;
 	wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
@@ -384,7 +385,7 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
 		params.ssid ? wpa_ssid_txt(params.ssid, params.ssid_len) : "",
 		params.freq);
 
-	wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
+	wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING, LOCAL_REASON_UNKNOWN);
 
 	if (params.wpa_ie == NULL ||
 	    ieee802_11_parse_elems(params.wpa_ie, params.wpa_ie_len, &elems, 0)
@@ -446,7 +447,7 @@ int sme_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md,
 }
 
 
-static void sme_deauth(struct wpa_supplicant *wpa_s)
+static void sme_deauth(struct wpa_supplicant *wpa_s, int32_t reason_code)
 {
 	int bssid_changed;
 
@@ -460,7 +461,7 @@ static void sme_deauth(struct wpa_supplicant *wpa_s)
 	wpa_s->sme.prev_bssid_set = 0;
 
 	wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
-	wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+	wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED, reason_code);
 	os_memset(wpa_s->bssid, 0, ETH_ALEN);
 	os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
 	if (bssid_changed)
@@ -484,7 +485,7 @@ void sme_event_assoc_reject(struct wpa_supplicant *wpa_s,
 	 * benefit from using the previous authentication, so this could be
 	 * optimized in the future.
 	 */
-	sme_deauth(wpa_s);
+	sme_deauth(wpa_s, data->assoc_reject.status_code);
 }
 
 
@@ -501,7 +502,7 @@ void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s,
 {
 	wpa_dbg(wpa_s, MSG_DEBUG, "SME: Association timed out");
 	wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
-	wpa_supplicant_mark_disassoc(wpa_s);
+	wpa_supplicant_mark_disassoc(wpa_s, LOCAL_REASON_UNKNOWN);
 }
 
 
@@ -530,7 +531,7 @@ static void sme_auth_timer(void *eloop_ctx, void *timeout_ctx)
 	struct wpa_supplicant *wpa_s = eloop_ctx;
 	if (wpa_s->wpa_state == WPA_AUTHENTICATING) {
 		wpa_msg(wpa_s, MSG_DEBUG, "SME: Authentication timeout");
-		sme_deauth(wpa_s);
+		sme_deauth(wpa_s, LOCAL_REASON_UNKNOWN);
 	}
 }
 
@@ -540,7 +541,7 @@ static void sme_assoc_timer(void *eloop_ctx, void *timeout_ctx)
 	struct wpa_supplicant *wpa_s = eloop_ctx;
 	if (wpa_s->wpa_state == WPA_ASSOCIATING) {
 		wpa_msg(wpa_s, MSG_DEBUG, "SME: Association timeout");
-		sme_deauth(wpa_s);
+		sme_deauth(wpa_s, LOCAL_REASON_UNKNOWN);
 	}
 }
 
@@ -565,7 +566,8 @@ void sme_disassoc_while_authenticating(struct wpa_supplicant *wpa_s,
 	 */
 	wpa_dbg(wpa_s, MSG_DEBUG, "SME: Allow pending authentication "
 		"to proceed after disconnection event");
-	wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING);
+	wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING,
+				 LOCAL_REASON_UNKNOWN);
 	os_memcpy(wpa_s->pending_bssid, prev_pending_bssid, ETH_ALEN);
 
 	/*
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index d8c2a2c..fc647fe 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -562,18 +562,29 @@ static void wpa_supplicant_stop_bgscan(struct wpa_supplicant *wpa_s)
  * wpa_supplicant_set_state - Set current connection state
  * @wpa_s: Pointer to wpa_supplicant data
  * @state: The new connection state
+ * @reason_code: IEEE 802.11 reason code, or LOCAL_REASON_UNKNOWN
  *
  * This function is called whenever the connection state changes, e.g.,
  * association is completed for WPA/WPA2 4-Way Handshake is started.
  */
 void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
-			      enum wpa_states state)
+			      enum wpa_states state,
+			      int32_t reason_code)
 {
 	enum wpa_states old_state = wpa_s->wpa_state;
 
-	wpa_dbg(wpa_s, MSG_DEBUG, "State: %s -> %s",
+	wpa_dbg(wpa_s, MSG_DEBUG, "State: %s -> %s (reason %d)",
 		wpa_supplicant_state_txt(wpa_s->wpa_state),
-		wpa_supplicant_state_txt(state));
+		wpa_supplicant_state_txt(state),
+		reason_code);
+
+	/*
+	 * NB: only update state_change_reason on true state change, to
+	 * avoid clobbering state_change_reason when we deauthenticate
+	 * following a disassociate event. see sme_event_disassoc.
+	 */
+	if (state != wpa_s->wpa_state)
+		wpa_s->state_change_reason = reason_code;
 
 	if (state != WPA_SCANNING)
 		wpa_supplicant_notify_scanning(wpa_s, 0);
@@ -1294,7 +1305,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
 		wpa_supplicant_set_wpa_none_key(wpa_s, ssid);
 	}
 
-	wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
+	wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING, LOCAL_REASON_UNKNOWN);
 	if (bss) {
 		params.bssid = bss->bssid;
 		params.ssid = bss->ssid;
@@ -1387,7 +1398,8 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
 		/* No need to timeout authentication since there is no key
 		 * management. */
 		wpa_supplicant_cancel_auth_timeout(wpa_s);
-		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED,
+					 LOCAL_REASON_UNKNOWN);
 #ifdef CONFIG_IBSS_RSN
 	} else if (ssid->mode == WPAS_MODE_IBSS &&
 		   wpa_s->key_mgmt != WPA_KEY_MGMT_NONE &&
@@ -1436,12 +1448,13 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
 
 
 static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s,
-					    const u8 *addr)
+					    const u8 *addr,
+					    int32_t reason_code)
 {
 	struct wpa_ssid *old_ssid;
 
 	wpa_clear_keys(wpa_s, addr);
-	wpa_supplicant_mark_disassoc(wpa_s);
+	wpa_supplicant_mark_disassoc(wpa_s, reason_code);
 	old_ssid = wpa_s->current_ssid;
 	wpa_s->current_ssid = NULL;
 	wpa_s->current_bss = NULL;
@@ -1474,7 +1487,7 @@ void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
 		addr = wpa_s->bssid;
 	}
 
-	wpa_supplicant_clear_connection(wpa_s, addr);
+	wpa_supplicant_clear_connection(wpa_s, addr, reason_code);
 }
 
 
@@ -1500,7 +1513,7 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
 		addr = wpa_s->bssid;
 	}
 
-	wpa_supplicant_clear_connection(wpa_s, addr);
+	wpa_supplicant_clear_connection(wpa_s, addr, reason_code);
 }
 
 
@@ -2047,7 +2060,8 @@ int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
 		wpa_supplicant_req_scan(wpa_s, interface_count, 100000);
 		interface_count++;
 	} else
-		wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
+		wpa_supplicant_set_state(wpa_s, WPA_INACTIVE,
+					 LOCAL_REASON_UNKNOWN);
 
 	return 0;
 }
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index eaabe0f..71a7d0a 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -546,6 +546,7 @@ struct wpa_supplicant {
 	unsigned int wps_freq;
 	int wps_fragment_size;
 	int auto_reconnect_disabled;
+	int32_t state_change_reason;
 
 	 /* Channel preferences for AP/P2P GO use */
 	int best_24_freq;
@@ -555,6 +556,8 @@ struct wpa_supplicant {
 
 
 /* wpa_supplicant.c */
+#define LOCAL_REASON_UNKNOWN (-1)
+
 int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
 
 int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s);
@@ -574,7 +577,8 @@ void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr);
 void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
 				     int sec, int usec);
 void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
-			      enum wpa_states state);
+			      enum wpa_states state,
+			      int32_t reason_code);
 struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s);
 const char * wpa_supplicant_get_eap_mode(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s);
@@ -625,7 +629,8 @@ void ieee80211_sta_free_hw_features(struct hostapd_hw_modes *hw_features,
 void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid);
 
 /* events.c */
-void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s,
+				  int32_t reason_code);
 void wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
 			    struct wpa_bss *selected,
 			    struct wpa_ssid *ssid);
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 2662eec..6eb5db1 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -295,7 +295,7 @@ static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol, int success,
 
 	wpa_supplicant_cancel_scan(wpa_s);
 	wpa_supplicant_cancel_auth_timeout(wpa_s);
-	wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+	wpa_supplicant_set_state(wpa_s, WPA_COMPLETED, LOCAL_REASON_UNKNOWN);
 
 }
 
@@ -305,10 +305,12 @@ static void wpa_supplicant_notify_eapol_done(void *ctx)
 	struct wpa_supplicant *wpa_s = ctx;
 	wpa_msg(wpa_s, MSG_DEBUG, "WPA: EAPOL processing complete");
 	if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
-		wpa_supplicant_set_state(wpa_s, WPA_4WAY_HANDSHAKE);
+		wpa_supplicant_set_state(wpa_s, WPA_4WAY_HANDSHAKE,
+					 LOCAL_REASON_UNKNOWN);
 	} else {
 		wpa_supplicant_cancel_auth_timeout(wpa_s);
-		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED,
+					 LOCAL_REASON_UNKNOWN);
 	}
 }
 
@@ -391,7 +393,7 @@ static void _wpa_supplicant_cancel_auth_timeout(void *wpa_s)
 
 static void _wpa_supplicant_set_state(void *wpa_s, enum wpa_states state)
 {
-	wpa_supplicant_set_state(wpa_s, state);
+	wpa_supplicant_set_state(wpa_s, state, LOCAL_REASON_UNKNOWN);
 }
 
 
-- 
1.7.3.1




More information about the Hostap mailing list