Patchwork Export disconnect reason code to dbus

login
register
mail settings
Submitter Gary Morain
Date April 18, 2012, 7:16 p.m.
Message ID <20120418193750.EE5F080473@gary-pc2.mtv.corp.google.com>
Download mbox | patch
Permalink /patch/153570/
State Superseded
Headers show

Comments

Gary Morain - April 18, 2012, 7:16 p.m.
In the properties changed signal, added a new propery "DisconnectReason",
which carries the IEEE 802.11 reason code of the most recent
disassociation or deauthentication event.  The reason code is negative
if it is locally generated.  The property is sent to the DBUS
immediately so as to prevent it from being coalesced with other
disconnect events.
---
 wpa_supplicant/dbus/dbus_new.c          |   14 ++++++++++++++
 wpa_supplicant/dbus/dbus_new.h          |    1 +
 wpa_supplicant/dbus/dbus_new_handlers.c |   20 ++++++++++++++++++++
 wpa_supplicant/dbus/dbus_new_handlers.h |    4 ++++
 wpa_supplicant/events.c                 |    5 +++++
 wpa_supplicant/notify.c                 |    6 ++++++
 wpa_supplicant/notify.h                 |    1 +
 wpa_supplicant/wpa_supplicant_i.h       |    3 +++
 8 files changed, 54 insertions(+), 0 deletions(-)
Dan Williams - April 20, 2012, 2:42 p.m.
On Wed, 2012-04-18 at 12:16 -0700, Gary Morain wrote:
> In the properties changed signal, added a new propery "DisconnectReason",
> which carries the IEEE 802.11 reason code of the most recent
> disassociation or deauthentication event.  The reason code is negative
> if it is locally generated.  The property is sent to the DBUS
> immediately so as to prevent it from being coalesced with other
> disconnect events.

I guess I was hoping this could be pushed out with the state so we
wouldn't have this sort of disconnect; ie a new property that contained
both the new state and the reason for that state change in the same
property to ensure they were atomic.  But that got bogged down in a
discussion with Jouni where he didn't want the internal supplicant
states being exposed at all (like they currently are).  I'm not sure if
he's changed his mind on that or not.

One caveat with this approach is that the internal disconnect reason is
now public API; we depend on that being either standard 802.11 reason
codes or having a standard enum somewhere.  If that's not comfortable to
Jouni, then perhaps we should define a public API enum for reasons and
map the internal reason to the public enum one.  It looks like some of
the locally generated reason codes come directly from the kernel via
nl80211.  Other times it looks like they come directly from the 802.11
frame but are only marked locally generated based on BSSID comparisons
(ie, driver_nl80211.c mlme_event_deauth_disassoc()).

Dan

>  wpa_supplicant/dbus/dbus_new.c          |   14 ++++++++++++++
>  wpa_supplicant/dbus/dbus_new.h          |    1 +
>  wpa_supplicant/dbus/dbus_new_handlers.c |   20 ++++++++++++++++++++
>  wpa_supplicant/dbus/dbus_new_handlers.h |    4 ++++
>  wpa_supplicant/events.c                 |    5 +++++
>  wpa_supplicant/notify.c                 |    6 ++++++
>  wpa_supplicant/notify.h                 |    1 +
>  wpa_supplicant/wpa_supplicant_i.h       |    3 +++
>  8 files changed, 54 insertions(+), 0 deletions(-)
> 
> diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
> index 0c89d14..34282fa 100644
> --- a/wpa_supplicant/dbus/dbus_new.c
> +++ b/wpa_supplicant/dbus/dbus_new.c
> @@ -1700,10 +1700,12 @@ void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
>  				   enum wpas_dbus_prop property)
>  {
>  	char *prop;
> +	dbus_bool_t flush;
>  
>  	if (wpa_s->dbus_new_path == NULL)
>  		return; /* Skip signal since D-Bus setup is not yet ready */
>  
> +	flush = FALSE;
>  	switch (property) {
>  	case WPAS_DBUS_PROP_AP_SCAN:
>  		prop = "ApScan";
> @@ -1726,6 +1728,10 @@ void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
>  	case WPAS_DBUS_PROP_CURRENT_AUTH_MODE:
>  		prop = "CurrentAuthMode";
>  		break;
> +	case WPAS_DBUS_PROP_DISCONNECT_REASON:
> +		prop = "DisconnectReason";
> +		flush = TRUE;
> +		break;
>  	default:
>  		wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
>  			   __func__, property);
> @@ -1735,6 +1741,10 @@ void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
>  	wpa_dbus_mark_property_changed(wpa_s->global->dbus,
>  				       wpa_s->dbus_new_path,
>  				       WPAS_DBUS_NEW_IFACE_INTERFACE, prop);
> +	if (flush)
> +		wpa_dbus_flush_object_changed_properties(wpa_s->global->dbus->con,
> +							 wpa_s->dbus_new_path);
> +
>  }
>  
> 
> @@ -2702,6 +2712,10 @@ static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
>  	  NULL
>  	},
>  #endif /* CONFIG_P2P */
> +	{ "DisconnectReason", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
> +	  wpas_dbus_getter_disconnect_reason,
> +	  NULL
> +	},
>  	{ NULL, NULL, NULL, NULL, NULL }
>  };
>  
> diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
> index a2d7011..f4a4d2c 100644
> --- a/wpa_supplicant/dbus/dbus_new.h
> +++ b/wpa_supplicant/dbus/dbus_new.h
> @@ -34,6 +34,7 @@ enum wpas_dbus_prop {
>  	WPAS_DBUS_PROP_CURRENT_NETWORK,
>  	WPAS_DBUS_PROP_CURRENT_AUTH_MODE,
>  	WPAS_DBUS_PROP_BSSS,
> +	WPAS_DBUS_PROP_DISCONNECT_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 3a5bcab..74ea804 100644
> --- a/wpa_supplicant/dbus/dbus_new_handlers.c
> +++ b/wpa_supplicant/dbus/dbus_new_handlers.c
> @@ -2298,6 +2298,26 @@ dbus_bool_t wpas_dbus_setter_fast_reauth(DBusMessageIter *iter,
>  	return TRUE;
>  }
>  
> +/**
> + * wpas_dbus_getter_disconenct_reason - Get most recent reason for disconect
> + * @iter: Pointer to incoming dbus message iter
> + * @error: Location to store error on failure
> + * @user_data: Function specific data
> + * Returns: TRUE on success, FALSE on failure
> + *
> + * Getter for "DisconnectReason" property.  The reason is negative if it is
> + * locally generated.
> + */
> +dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter,
> +                                               DBusError *error,
> +                                               void *user_data)
> +{
> +	struct wpa_supplicant *const wpa_s = user_data;
> +	dbus_int32_t reason = wpa_s->disconnect_reason;
> +	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
> +						&reason, error);
> +}
> +
>  
>  /**
>   * wpas_dbus_getter_bss_expire_age - Get BSS entry expiration age
> diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
> index d78aa20..ff49c80 100644
> --- a/wpa_supplicant/dbus/dbus_new_handlers.h
> +++ b/wpa_supplicant/dbus/dbus_new_handlers.h
> @@ -147,6 +147,10 @@ dbus_bool_t wpas_dbus_setter_fast_reauth(DBusMessageIter *iter,
>  					 DBusError *error,
>  					 void *user_data);
>  
> +dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter,
> +                                               DBusError *error,
> +                                               void *user_data);
> +
>  dbus_bool_t wpas_dbus_getter_bss_expire_age(DBusMessageIter *iter,
>  					    DBusError *error, void *user_data);
>  
> diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
> index 8fdc544..8174513 100644
> --- a/wpa_supplicant/events.c
> +++ b/wpa_supplicant/events.c
> @@ -1659,6 +1659,11 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
>  	if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
>  		wpas_connection_failed(wpa_s, bssid);
>  	wpa_sm_notify_disassoc(wpa_s->wpa);
> +        wpa_s->disconnect_reason = reason_code;
> +        if (locally_generated) {
> +        	wpa_s->disconnect_reason = -wpa_s->disconnect_reason;
> +        }
> +        wpas_notify_disconnect_reason(wpa_s);
>  	if (!is_zero_ether_addr(bssid) ||
>  	    wpa_s->wpa_state >= WPA_AUTHENTICATING) {
>  		wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid=" MACSTR
> diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
> index d471dfb..bb9b0db 100644
> --- a/wpa_supplicant/notify.c
> +++ b/wpa_supplicant/notify.c
> @@ -97,6 +97,12 @@ void wpas_notify_state_changed(struct wpa_supplicant *wpa_s,
>  }
>  
> 
> +void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s)
> +{
> +	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_DISCONNECT_REASON);
> +}
> +
> +
>  void wpas_notify_network_changed(struct wpa_supplicant *wpa_s)
>  {
>  	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_CURRENT_NETWORK);
> diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
> index 0c483bc..9cfdd4f 100644
> --- a/wpa_supplicant/notify.h
> +++ b/wpa_supplicant/notify.h
> @@ -22,6 +22,7 @@ void wpas_notify_iface_removed(struct wpa_supplicant *wpa_s);
>  void wpas_notify_state_changed(struct wpa_supplicant *wpa_s,
>  			       enum wpa_states new_state,
>  			       enum wpa_states old_state);
> +void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s);
>  void wpas_notify_network_changed(struct wpa_supplicant *wpa_s);
>  void wpas_notify_ap_scan_changed(struct wpa_supplicant *wpa_s);
>  void wpas_notify_bssid_changed(struct wpa_supplicant *wpa_s);
> diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
> index b25116e..52c4dd9 100644
> --- a/wpa_supplicant/wpa_supplicant_i.h
> +++ b/wpa_supplicant/wpa_supplicant_i.h
> @@ -548,6 +548,9 @@ struct wpa_supplicant {
>  	} hw;
>  
>  	int pno;
> +
> +	// WLAN_REASON_* reason codes.  Negative if locally generated.
> +	int disconnect_reason;
>  };
>  
>
Gary Morain - April 20, 2012, 7:29 p.m.
[corrected the sender address]
On Fri, Apr 20, 2012 at 7:42 AM, Dan Williams <dcbw@redhat.com> wrote:

> On Wed, 2012-04-18 at 12:16 -0700, Gary Morain wrote:
> > In the properties changed signal, added a new propery "DisconnectReason",
> > which carries the IEEE 802.11 reason code of the most recent
> > disassociation or deauthentication event.  The reason code is negative
> > if it is locally generated.  The property is sent to the DBUS
> > immediately so as to prevent it from being coalesced with other
> > disconnect events.
>
> I guess I was hoping this could be pushed out with the state so we
> wouldn't have this sort of disconnect; ie a new property that contained
> both the new state and the reason for that state change in the same
> property to ensure they were atomic.  But that got bogged down in a
> discussion with Jouni where he didn't want the internal supplicant
> states being exposed at all (like they currently are).  I'm not sure if
> he's changed his mind on that or not.
>

I'm aware of that effort and that it did not succeed.  I'm hoping that this
more modest approach will have a better fate.


>
> One caveat with this approach is that the internal disconnect reason is
> now public API; we depend on that being either standard 802.11 reason
> codes or having a standard enum somewhere.  If that's not comfortable to
> Jouni, then perhaps we should define a public API enum for reasons and
> map the internal reason to the public enum one.  It looks like some of
> the locally generated reason codes come directly from the kernel via
> nl80211.  Other times it looks like they come directly from the 802.11
> frame but are only marked locally generated based on BSSID comparisons
> (ie, driver_nl80211.c mlme_event_deauth_disassoc()).
>

I thought all the disconnect reason codes were standard 802.11, as defined
in src/common/ieee802_11_defs.h in the WLAN_REASON_* macros.  Are there
exceptions?  I don't want to be exposing internal (non-standard) reason
codes.


>
> Dan
>
> >  wpa_supplicant/dbus/dbus_new.c          |   14 ++++++++++++++
> >  wpa_supplicant/dbus/dbus_new.h          |    1 +
> >  wpa_supplicant/dbus/dbus_new_handlers.c |   20 ++++++++++++++++++++
> >  wpa_supplicant/dbus/dbus_new_handlers.h |    4 ++++
> >  wpa_supplicant/events.c                 |    5 +++++
> >  wpa_supplicant/notify.c                 |    6 ++++++
> >  wpa_supplicant/notify.h                 |    1 +
> >  wpa_supplicant/wpa_supplicant_i.h       |    3 +++
> >  8 files changed, 54 insertions(+), 0 deletions(-)
> >
> > diff --git a/wpa_supplicant/dbus/dbus_new.c
> b/wpa_supplicant/dbus/dbus_new.c
> > index 0c89d14..34282fa 100644
> > --- a/wpa_supplicant/dbus/dbus_new.c
> > +++ b/wpa_supplicant/dbus/dbus_new.c
> > @@ -1700,10 +1700,12 @@ void wpas_dbus_signal_prop_changed(struct
> wpa_supplicant *wpa_s,
> >                                  enum wpas_dbus_prop property)
> >  {
> >       char *prop;
> > +     dbus_bool_t flush;
> >
> >       if (wpa_s->dbus_new_path == NULL)
> >               return; /* Skip signal since D-Bus setup is not yet ready
> */
> >
> > +     flush = FALSE;
> >       switch (property) {
> >       case WPAS_DBUS_PROP_AP_SCAN:
> >               prop = "ApScan";
> > @@ -1726,6 +1728,10 @@ void wpas_dbus_signal_prop_changed(struct
> wpa_supplicant *wpa_s,
> >       case WPAS_DBUS_PROP_CURRENT_AUTH_MODE:
> >               prop = "CurrentAuthMode";
> >               break;
> > +     case WPAS_DBUS_PROP_DISCONNECT_REASON:
> > +             prop = "DisconnectReason";
> > +             flush = TRUE;
> > +             break;
> >       default:
> >               wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value
> %d",
> >                          __func__, property);
> > @@ -1735,6 +1741,10 @@ void wpas_dbus_signal_prop_changed(struct
> wpa_supplicant *wpa_s,
> >       wpa_dbus_mark_property_changed(wpa_s->global->dbus,
> >                                      wpa_s->dbus_new_path,
> >                                      WPAS_DBUS_NEW_IFACE_INTERFACE,
> prop);
> > +     if (flush)
> > +
> wpa_dbus_flush_object_changed_properties(wpa_s->global->dbus->con,
> > +
>  wpa_s->dbus_new_path);
> > +
> >  }
> >
> >
> > @@ -2702,6 +2712,10 @@ static const struct wpa_dbus_property_desc
> wpas_dbus_interface_properties[] = {
> >         NULL
> >       },
> >  #endif /* CONFIG_P2P */
> > +     { "DisconnectReason", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
> > +       wpas_dbus_getter_disconnect_reason,
> > +       NULL
> > +     },
> >       { NULL, NULL, NULL, NULL, NULL }
> >  };
> >
> > diff --git a/wpa_supplicant/dbus/dbus_new.h
> b/wpa_supplicant/dbus/dbus_new.h
> > index a2d7011..f4a4d2c 100644
> > --- a/wpa_supplicant/dbus/dbus_new.h
> > +++ b/wpa_supplicant/dbus/dbus_new.h
> > @@ -34,6 +34,7 @@ enum wpas_dbus_prop {
> >       WPAS_DBUS_PROP_CURRENT_NETWORK,
> >       WPAS_DBUS_PROP_CURRENT_AUTH_MODE,
> >       WPAS_DBUS_PROP_BSSS,
> > +     WPAS_DBUS_PROP_DISCONNECT_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 3a5bcab..74ea804 100644
> > --- a/wpa_supplicant/dbus/dbus_new_handlers.c
> > +++ b/wpa_supplicant/dbus/dbus_new_handlers.c
> > @@ -2298,6 +2298,26 @@ dbus_bool_t
> wpas_dbus_setter_fast_reauth(DBusMessageIter *iter,
> >       return TRUE;
> >  }
> >
> > +/**
> > + * wpas_dbus_getter_disconenct_reason - Get most recent reason for
> disconect
> > + * @iter: Pointer to incoming dbus message iter
> > + * @error: Location to store error on failure
> > + * @user_data: Function specific data
> > + * Returns: TRUE on success, FALSE on failure
> > + *
> > + * Getter for "DisconnectReason" property.  The reason is negative if
> it is
> > + * locally generated.
> > + */
> > +dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter,
> > +                                               DBusError *error,
> > +                                               void *user_data)
> > +{
> > +     struct wpa_supplicant *const wpa_s = user_data;
> > +     dbus_int32_t reason = wpa_s->disconnect_reason;
> > +     return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
> > +                                             &reason, error);
> > +}
> > +
> >
> >  /**
> >   * wpas_dbus_getter_bss_expire_age - Get BSS entry expiration age
> > diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h
> b/wpa_supplicant/dbus/dbus_new_handlers.h
> > index d78aa20..ff49c80 100644
> > --- a/wpa_supplicant/dbus/dbus_new_handlers.h
> > +++ b/wpa_supplicant/dbus/dbus_new_handlers.h
> > @@ -147,6 +147,10 @@ dbus_bool_t
> wpas_dbus_setter_fast_reauth(DBusMessageIter *iter,
> >                                        DBusError *error,
> >                                        void *user_data);
> >
> > +dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter,
> > +                                               DBusError *error,
> > +                                               void *user_data);
> > +
> >  dbus_bool_t wpas_dbus_getter_bss_expire_age(DBusMessageIter *iter,
> >                                           DBusError *error, void
> *user_data);
> >
> > diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
> > index 8fdc544..8174513 100644
> > --- a/wpa_supplicant/events.c
> > +++ b/wpa_supplicant/events.c
> > @@ -1659,6 +1659,11 @@ static void wpa_supplicant_event_disassoc(struct
> wpa_supplicant *wpa_s,
> >       if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
> >               wpas_connection_failed(wpa_s, bssid);
> >       wpa_sm_notify_disassoc(wpa_s->wpa);
> > +        wpa_s->disconnect_reason = reason_code;
> > +        if (locally_generated) {
> > +             wpa_s->disconnect_reason = -wpa_s->disconnect_reason;
> > +        }
> > +        wpas_notify_disconnect_reason(wpa_s);
> >       if (!is_zero_ether_addr(bssid) ||
> >           wpa_s->wpa_state >= WPA_AUTHENTICATING) {
> >               wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid="
> MACSTR
> > diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
> > index d471dfb..bb9b0db 100644
> > --- a/wpa_supplicant/notify.c
> > +++ b/wpa_supplicant/notify.c
> > @@ -97,6 +97,12 @@ void wpas_notify_state_changed(struct wpa_supplicant
> *wpa_s,
> >  }
> >
> >
> > +void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s)
> > +{
> > +     wpas_dbus_signal_prop_changed(wpa_s,
> WPAS_DBUS_PROP_DISCONNECT_REASON);
> > +}
> > +
> > +
> >  void wpas_notify_network_changed(struct wpa_supplicant *wpa_s)
> >  {
> >       wpas_dbus_signal_prop_changed(wpa_s,
> WPAS_DBUS_PROP_CURRENT_NETWORK);
> > diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
> > index 0c483bc..9cfdd4f 100644
> > --- a/wpa_supplicant/notify.h
> > +++ b/wpa_supplicant/notify.h
> > @@ -22,6 +22,7 @@ void wpas_notify_iface_removed(struct wpa_supplicant
> *wpa_s);
> >  void wpas_notify_state_changed(struct wpa_supplicant *wpa_s,
> >                              enum wpa_states new_state,
> >                              enum wpa_states old_state);
> > +void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s);
> >  void wpas_notify_network_changed(struct wpa_supplicant *wpa_s);
> >  void wpas_notify_ap_scan_changed(struct wpa_supplicant *wpa_s);
> >  void wpas_notify_bssid_changed(struct wpa_supplicant *wpa_s);
> > diff --git a/wpa_supplicant/wpa_supplicant_i.h
> b/wpa_supplicant/wpa_supplicant_i.h
> > index b25116e..52c4dd9 100644
> > --- a/wpa_supplicant/wpa_supplicant_i.h
> > +++ b/wpa_supplicant/wpa_supplicant_i.h
> > @@ -548,6 +548,9 @@ struct wpa_supplicant {
> >       } hw;
> >
> >       int pno;
> > +
> > +     // WLAN_REASON_* reason codes.  Negative if locally generated.
> > +     int disconnect_reason;
> >  };
> >
> >
>
>
>
Jouni Malinen - April 21, 2012, 3:46 p.m.
On Wed, Apr 18, 2012 at 12:16:07PM -0700, Gary Morain wrote:
> In the properties changed signal, added a new propery "DisconnectReason",
> which carries the IEEE 802.11 reason code of the most recent
> disassociation or deauthentication event.  The reason code is negative
> if it is locally generated.  The property is sent to the DBUS
> immediately so as to prevent it from being coalesced with other
> disconnect events.

Thanks. The changes themselves look fine with some minor cleanup as
mentioned below. Could you please read the CONTRIBUTIONS file (*) and
submit a version of the patch with the Signed-hostap: tag in the commit
log?

(*)
http://w1.fi/gitweb/gitweb.cgi?p=hostap.git;a=blob_plain;f=CONTRIBUTIONS


> diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
> @@ -2298,6 +2298,26 @@ dbus_bool_t wpas_dbus_setter_fast_reauth(DBusMessageIter *iter,
> + * wpas_dbus_getter_disconenct_reason - Get most recent reason for disconect

Typo in the function name   ^^

> +dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter,

> diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
> index 8fdc544..8174513 100644
> --- a/wpa_supplicant/events.c
> +++ b/wpa_supplicant/events.c
> @@ -1659,6 +1659,11 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
>  	wpa_sm_notify_disassoc(wpa_s->wpa);
> +        wpa_s->disconnect_reason = reason_code;

Using tabs instead of eight spaces would be preferred for indentation.

> diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
> @@ -548,6 +548,9 @@ struct wpa_supplicant {
> +	// WLAN_REASON_* reason codes.  Negative if locally generated.
> +	int disconnect_reason;

/* ... */  would be preferred comment style.

Patch

diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index 0c89d14..34282fa 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -1700,10 +1700,12 @@  void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
 				   enum wpas_dbus_prop property)
 {
 	char *prop;
+	dbus_bool_t flush;
 
 	if (wpa_s->dbus_new_path == NULL)
 		return; /* Skip signal since D-Bus setup is not yet ready */
 
+	flush = FALSE;
 	switch (property) {
 	case WPAS_DBUS_PROP_AP_SCAN:
 		prop = "ApScan";
@@ -1726,6 +1728,10 @@  void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
 	case WPAS_DBUS_PROP_CURRENT_AUTH_MODE:
 		prop = "CurrentAuthMode";
 		break;
+	case WPAS_DBUS_PROP_DISCONNECT_REASON:
+		prop = "DisconnectReason";
+		flush = TRUE;
+		break;
 	default:
 		wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
 			   __func__, property);
@@ -1735,6 +1741,10 @@  void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
 	wpa_dbus_mark_property_changed(wpa_s->global->dbus,
 				       wpa_s->dbus_new_path,
 				       WPAS_DBUS_NEW_IFACE_INTERFACE, prop);
+	if (flush)
+		wpa_dbus_flush_object_changed_properties(wpa_s->global->dbus->con,
+							 wpa_s->dbus_new_path);
+
 }
 
 
@@ -2702,6 +2712,10 @@  static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
 	  NULL
 	},
 #endif /* CONFIG_P2P */
+	{ "DisconnectReason", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
+	  wpas_dbus_getter_disconnect_reason,
+	  NULL
+	},
 	{ NULL, NULL, NULL, NULL, NULL }
 };
 
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index a2d7011..f4a4d2c 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -34,6 +34,7 @@  enum wpas_dbus_prop {
 	WPAS_DBUS_PROP_CURRENT_NETWORK,
 	WPAS_DBUS_PROP_CURRENT_AUTH_MODE,
 	WPAS_DBUS_PROP_BSSS,
+	WPAS_DBUS_PROP_DISCONNECT_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 3a5bcab..74ea804 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -2298,6 +2298,26 @@  dbus_bool_t wpas_dbus_setter_fast_reauth(DBusMessageIter *iter,
 	return TRUE;
 }
 
+/**
+ * wpas_dbus_getter_disconenct_reason - Get most recent reason for disconect
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "DisconnectReason" property.  The reason is negative if it is
+ * locally generated.
+ */
+dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter,
+                                               DBusError *error,
+                                               void *user_data)
+{
+	struct wpa_supplicant *const wpa_s = user_data;
+	dbus_int32_t reason = wpa_s->disconnect_reason;
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
+						&reason, error);
+}
+
 
 /**
  * wpas_dbus_getter_bss_expire_age - Get BSS entry expiration age
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index d78aa20..ff49c80 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -147,6 +147,10 @@  dbus_bool_t wpas_dbus_setter_fast_reauth(DBusMessageIter *iter,
 					 DBusError *error,
 					 void *user_data);
 
+dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter,
+                                               DBusError *error,
+                                               void *user_data);
+
 dbus_bool_t wpas_dbus_getter_bss_expire_age(DBusMessageIter *iter,
 					    DBusError *error, void *user_data);
 
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 8fdc544..8174513 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1659,6 +1659,11 @@  static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
 	if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
 		wpas_connection_failed(wpa_s, bssid);
 	wpa_sm_notify_disassoc(wpa_s->wpa);
+        wpa_s->disconnect_reason = reason_code;
+        if (locally_generated) {
+        	wpa_s->disconnect_reason = -wpa_s->disconnect_reason;
+        }
+        wpas_notify_disconnect_reason(wpa_s);
 	if (!is_zero_ether_addr(bssid) ||
 	    wpa_s->wpa_state >= WPA_AUTHENTICATING) {
 		wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid=" MACSTR
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index d471dfb..bb9b0db 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -97,6 +97,12 @@  void wpas_notify_state_changed(struct wpa_supplicant *wpa_s,
 }
 
 
+void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s)
+{
+	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_DISCONNECT_REASON);
+}
+
+
 void wpas_notify_network_changed(struct wpa_supplicant *wpa_s)
 {
 	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_CURRENT_NETWORK);
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index 0c483bc..9cfdd4f 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -22,6 +22,7 @@  void wpas_notify_iface_removed(struct wpa_supplicant *wpa_s);
 void wpas_notify_state_changed(struct wpa_supplicant *wpa_s,
 			       enum wpa_states new_state,
 			       enum wpa_states old_state);
+void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s);
 void wpas_notify_network_changed(struct wpa_supplicant *wpa_s);
 void wpas_notify_ap_scan_changed(struct wpa_supplicant *wpa_s);
 void wpas_notify_bssid_changed(struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index b25116e..52c4dd9 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -548,6 +548,9 @@  struct wpa_supplicant {
 	} hw;
 
 	int pno;
+
+	// WLAN_REASON_* reason codes.  Negative if locally generated.
+	int disconnect_reason;
 };