diff mbox series

[BlueZ,7/9] adv_monitor: Add the monitor Release reason

Message ID 20220320183445.BlueZ.7.I668ef2477efd8fcdd9c44975c5f7b9f32af966ca@changeid (mailing list archive)
State Superseded
Headers show
Series [BlueZ,1/9] adv_monitor: Disable RSSIHighTimeout for SW based filtering | expand

Checks

Context Check Description
tedd_an/pre-ci_am success Success
tedd_an/checkpatch success Checkpatch PASS
tedd_an/gitlint success Gitlint PASS

Commit Message

Manish Mandlik March 21, 2022, 1:37 a.m. UTC
Adv Monitor is released for various reasons. For example, incorrect RSSI
parameters, incorrect monitor type, non-overlapping RSSI thresholds,
etc.

Return this release reason along with the Release event for the better
visibility to clients.

Reviewed-by: Miao-chen Chou <mcchou@chromium.org>
---

 doc/advertisement-monitor-api.txt | 12 ++++++-
 src/adv_monitor.c                 | 56 ++++++++++++++++++++++++++++---
 2 files changed, 63 insertions(+), 5 deletions(-)

Comments

Luiz Augusto von Dentz March 22, 2022, 12:48 a.m. UTC | #1
Hi Manish,

On Sun, Mar 20, 2022 at 6:37 PM Manish Mandlik <mmandlik@google.com> wrote:
>
> Adv Monitor is released for various reasons. For example, incorrect RSSI
> parameters, incorrect monitor type, non-overlapping RSSI thresholds,
> etc.
>
> Return this release reason along with the Release event for the better
> visibility to clients.

Shouldn't this be sent as a reply to the method registering the monitor?

> Reviewed-by: Miao-chen Chou <mcchou@chromium.org>
> ---
>
>  doc/advertisement-monitor-api.txt | 12 ++++++-
>  src/adv_monitor.c                 | 56 ++++++++++++++++++++++++++++---
>  2 files changed, 63 insertions(+), 5 deletions(-)
>
> diff --git a/doc/advertisement-monitor-api.txt b/doc/advertisement-monitor-api.txt
> index 942d44b2f..fcbd9c5c2 100644
> --- a/doc/advertisement-monitor-api.txt
> +++ b/doc/advertisement-monitor-api.txt
> @@ -17,12 +17,22 @@ Service             org.bluez
>  Interface      org.bluez.AdvertisementMonitor1 [experimental]
>  Object path    freely definable
>
> -Methods                void Release() [noreply]
> +Methods                void Release(Int8 reason) [noreply]
>
>                         This gets called as a signal for a client to perform
>                         clean-up when (1)a monitor cannot be activated after it
>                         was exposed or (2)a monitor has been deactivated.
>
> +                       Possible reasons:  0  Unknown reason
> +                                          1  Invalid monitor type
> +                                          2  Invalid RSSI parameter(s)
> +                                          3  Invalid pattern(s)
> +                                          4  Monitor already exists
> +                                          5  Kernel failed to add monitor
> +                                          6  Kernel failed to remove monitor
> +                                          7  Monitor removed by kernel
> +                                          8  App unregistered/destroyed
> +
>                 void Activate() [noreply]
>
>                         After a monitor was exposed, this gets called as a
> diff --git a/src/adv_monitor.c b/src/adv_monitor.c
> index 85231557e..6ee3736d2 100644
> --- a/src/adv_monitor.c
> +++ b/src/adv_monitor.c
> @@ -90,6 +90,18 @@ enum monitor_state {
>         MONITOR_STATE_RELEASED, /* Dbus Object removed by app */
>  };
>
> +enum monitor_release_reason {
> +       REASON_UNKNOWN,
> +       REASON_INVALID_TYPE,
> +       REASON_INVALID_RSSI_PARAMS,
> +       REASON_INVALID_PATTERNS,
> +       REASON_ALREADY_EXISTS,
> +       REASON_FAILED_TO_ADD,
> +       REASON_FAILED_TO_REMOVE,
> +       REASON_REMOVED_BY_KERNEL,
> +       REASON_APP_DESTROYED,
> +};
> +
>  enum merged_pattern_state {
>         MERGED_PATTERN_STATE_ADDING,    /* Adding pattern to kernel */
>         MERGED_PATTERN_STATE_REMOVING,  /* Removing pattern from kernel */
> @@ -113,6 +125,7 @@ struct adv_monitor {
>         char *path;
>
>         enum monitor_state state;       /* MONITOR_STATE_* */
> +       enum monitor_release_reason release_reason;
>
>         struct rssi_parameters rssi;    /* RSSI parameter for this monitor */
>         struct adv_monitor_merged_pattern *merged_pattern;
> @@ -137,6 +150,7 @@ struct adv_monitor_merged_pattern {
>         struct queue *patterns;         /* List of bt_ad_pattern objects */
>         enum merged_pattern_state current_state; /* MERGED_PATTERN_STATE_* */
>         enum merged_pattern_state next_state;    /* MERGED_PATTERN_STATE_* */
> +       enum monitor_release_reason release_reason;
>  };
>
>  /* Some data like last_seen, timer/timeout values need to be maintained
> @@ -541,6 +555,18 @@ static void monitor_free(struct adv_monitor *monitor)
>         free(monitor);
>  }
>
> +/* Includes monitor release reason into the dbus message */
> +static void report_release_reason_setup(DBusMessageIter *iter, void *user_data)
> +{
> +       const struct adv_monitor *monitor = user_data;
> +       int8_t release_reason = REASON_UNKNOWN;
> +
> +       if (monitor)
> +               release_reason = monitor->release_reason;
> +
> +       dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE, &release_reason);
> +}
> +
>  /* Calls Release() method of the remote Adv Monitor */
>  static void monitor_release(struct adv_monitor *monitor)
>  {
> @@ -560,8 +586,9 @@ static void monitor_release(struct adv_monitor *monitor)
>         DBG("Calling Release() on Adv Monitor of owner %s at path %s",
>                 monitor->app->owner, monitor->path);
>
> -       g_dbus_proxy_method_call(monitor->proxy, "Release", NULL, NULL, NULL,
> -                                       NULL);
> +       g_dbus_proxy_method_call(monitor->proxy, "Release",
> +                                       report_release_reason_setup, NULL,
> +                                       monitor, NULL);
>  }
>
>  /* Removes monitor from the merged_pattern. This would result in removing it
> @@ -635,13 +662,20 @@ static void monitor_destroy(void *data)
>  static void app_destroy(void *data)
>  {
>         struct adv_monitor_app *app = data;
> +       const struct queue_entry *e;
>
>         if (!app)
>                 return;
>
>         DBG("Destroy Adv Monitor app %s at path %s", app->owner, app->path);
>
> -       queue_destroy(app->monitors, monitor_destroy);
> +       for (e = queue_get_entries(app->monitors); e; e = e->next) {
> +               struct adv_monitor *m = e->data;
> +
> +               m->release_reason = REASON_APP_DESTROYED;
> +               monitor_destroy(m);
> +       }
> +       queue_destroy(app->monitors, NULL);
>
>         if (app->reg) {
>                 app_reply_msg(app, btd_error_failed(app->reg,
> @@ -793,6 +827,7 @@ static bool parse_monitor_type(struct adv_monitor *monitor, const char *path)
>         }
>
>  failed:
> +       monitor->release_reason = REASON_INVALID_TYPE;
>         btd_error(adapter_id,
>                         "Invalid argument of property Type of the Adv Monitor "
>                         "at path %s", path);
> @@ -919,6 +954,7 @@ done:
>         return true;
>
>  failed:
> +       monitor->release_reason = REASON_INVALID_RSSI_PARAMS;
>         btd_error(adapter_id,
>                         "Invalid argument of RSSI thresholds and timeouts "
>                         "of the Adv Monitor at path %s",
> @@ -1005,6 +1041,7 @@ static bool parse_patterns(struct adv_monitor *monitor, const char *path)
>         return true;
>
>  failed:
> +       monitor->release_reason = REASON_INVALID_PATTERNS;
>         btd_error(adapter_id, "Invalid argument of property Patterns of the "
>                         "Adv Monitor at path %s", path);
>
> @@ -1053,6 +1090,7 @@ static void merged_pattern_destroy_monitors(
>                 struct adv_monitor *monitor = e->data;
>
>                 monitor->merged_pattern = NULL;
> +               monitor->release_reason = merged_pattern->release_reason;
>                 monitor_destroy(monitor);
>         }
>  }
> @@ -1086,6 +1124,7 @@ static void remove_adv_monitor_cb(uint8_t status, uint16_t length,
>         return;
>
>  fail:
> +       merged_pattern->release_reason = REASON_FAILED_TO_REMOVE;
>         merged_pattern_destroy_monitors(merged_pattern);
>         merged_pattern_free(merged_pattern);
>  }
> @@ -1142,6 +1181,7 @@ static void add_adv_patterns_monitor_cb(uint8_t status, uint16_t length,
>         return;
>
>  fail:
> +       merged_pattern->release_reason = REASON_FAILED_TO_ADD;
>         merged_pattern_destroy_monitors(merged_pattern);
>         merged_pattern_free(merged_pattern);
>  }
> @@ -1285,6 +1325,7 @@ static void monitor_proxy_added_cb(GDBusProxy *proxy, void *user_data)
>                 merged_pattern_add(monitor->merged_pattern);
>         } else {
>                 if (!merge_is_possible(existing_pattern, monitor)) {
> +                       monitor->release_reason = REASON_ALREADY_EXISTS;
>                         monitor_destroy(monitor);
>                         DBG("Adv Monitor at path %s released due to existing "
>                                 "monitor", path);
> @@ -1551,6 +1592,7 @@ static void remove_merged_pattern(void *data, void *user_data)
>  {
>         struct adv_monitor_merged_pattern *merged_pattern = data;
>         uint16_t *handle = user_data;
> +       const struct queue_entry *e;
>
>         if (!handle)
>                 return;
> @@ -1562,8 +1604,14 @@ static void remove_merged_pattern(void *data, void *user_data)
>         DBG("Adv monitor with handle:0x%04x removed by kernel",
>                 merged_pattern->monitor_handle);
>
> +       for (e = queue_get_entries(merged_pattern->monitors); e; e = e->next) {
> +               struct adv_monitor *m = e->data;
> +
> +               m->release_reason = REASON_REMOVED_BY_KERNEL;
> +               monitor_destroy(m);
> +       }
>         queue_foreach(merged_pattern->monitors, monitor_state_removed, NULL);
> -       queue_destroy(merged_pattern->monitors, monitor_destroy);
> +       queue_destroy(merged_pattern->monitors, NULL);
>         merged_pattern_free(merged_pattern);
>  }
>
> --
> 2.35.1.894.gb6a874cedc-goog
>
Luiz Augusto von Dentz April 13, 2022, 9:37 p.m. UTC | #2
Hi Manish,

On Wed, Apr 13, 2022 at 1:56 PM Manish Mandlik <mmandlik@google.com> wrote:
>
> Hi Luiz,
>
> On Mon, Mar 21, 2022 at 5:49 PM Luiz Augusto von Dentz <luiz.dentz@gmail.com> wrote:
>>
>> Hi Manish,
>>
>> On Sun, Mar 20, 2022 at 6:37 PM Manish Mandlik <mmandlik@google.com> wrote:
>> >
>> > Adv Monitor is released for various reasons. For example, incorrect RSSI
>> > parameters, incorrect monitor type, non-overlapping RSSI thresholds,
>> > etc.
>> >
>> > Return this release reason along with the Release event for the better
>> > visibility to clients.
>>
>> Shouldn't this be sent as a reply to the method registering the monitor?
>
> Applications can create an Advertisement Monitor D-Bus object any time before or after registering the root path with BlueZ. BlueZ processes monitors once it receives ProxyAdded callback from D-Bus once a Monitor is created on an already registered root path or once the root path is registered for already created monitors. So, monitor Activate/Release methods are called later asynchronously to notify applications about acceptance or rejection of the monitor.

We should probably document this then, so I suppose one can register
the root path without having any monitors so they can be added/removed
later?

>>
>>
>> > Reviewed-by: Miao-chen Chou <mcchou@chromium.org>
>> > ---
>> >
>> >  doc/advertisement-monitor-api.txt | 12 ++++++-
>> >  src/adv_monitor.c                 | 56 ++++++++++++++++++++++++++++---
>> >  2 files changed, 63 insertions(+), 5 deletions(-)
>> >
>> > diff --git a/doc/advertisement-monitor-api.txt b/doc/advertisement-monitor-api.txt
>> > index 942d44b2f..fcbd9c5c2 100644
>> > --- a/doc/advertisement-monitor-api.txt
>> > +++ b/doc/advertisement-monitor-api.txt
>> > @@ -17,12 +17,22 @@ Service             org.bluez
>> >  Interface      org.bluez.AdvertisementMonitor1 [experimental]
>> >  Object path    freely definable
>> >
>> > -Methods                void Release() [noreply]
>> > +Methods                void Release(Int8 reason) [noreply]
>> >
>> >                         This gets called as a signal for a client to perform
>> >                         clean-up when (1)a monitor cannot be activated after it
>> >                         was exposed or (2)a monitor has been deactivated.
>> >
>> > +                       Possible reasons:  0  Unknown reason
>> > +                                          1  Invalid monitor type
>> > +                                          2  Invalid RSSI parameter(s)
>> > +                                          3  Invalid pattern(s)
>> > +                                          4  Monitor already exists
>> > +                                          5  Kernel failed to add monitor
>> > +                                          6  Kernel failed to remove monitor
>> > +                                          7  Monitor removed by kernel
>> > +                                          8  App unregistered/destroyed
>> > +
>> >                 void Activate() [noreply]
>> >
>> >                         After a monitor was exposed, this gets called as a
>> > diff --git a/src/adv_monitor.c b/src/adv_monitor.c
>> > index 85231557e..6ee3736d2 100644
>> > --- a/src/adv_monitor.c
>> > +++ b/src/adv_monitor.c
>> > @@ -90,6 +90,18 @@ enum monitor_state {
>> >         MONITOR_STATE_RELEASED, /* Dbus Object removed by app */
>> >  };
>> >
>> > +enum monitor_release_reason {
>> > +       REASON_UNKNOWN,
>> > +       REASON_INVALID_TYPE,
>> > +       REASON_INVALID_RSSI_PARAMS,
>> > +       REASON_INVALID_PATTERNS,
>> > +       REASON_ALREADY_EXISTS,
>> > +       REASON_FAILED_TO_ADD,
>> > +       REASON_FAILED_TO_REMOVE,
>> > +       REASON_REMOVED_BY_KERNEL,
>> > +       REASON_APP_DESTROYED,
>> > +};
>> > +
>> >  enum merged_pattern_state {
>> >         MERGED_PATTERN_STATE_ADDING,    /* Adding pattern to kernel */
>> >         MERGED_PATTERN_STATE_REMOVING,  /* Removing pattern from kernel */
>> > @@ -113,6 +125,7 @@ struct adv_monitor {
>> >         char *path;
>> >
>> >         enum monitor_state state;       /* MONITOR_STATE_* */
>> > +       enum monitor_release_reason release_reason;
>> >
>> >         struct rssi_parameters rssi;    /* RSSI parameter for this monitor */
>> >         struct adv_monitor_merged_pattern *merged_pattern;
>> > @@ -137,6 +150,7 @@ struct adv_monitor_merged_pattern {
>> >         struct queue *patterns;         /* List of bt_ad_pattern objects */
>> >         enum merged_pattern_state current_state; /* MERGED_PATTERN_STATE_* */
>> >         enum merged_pattern_state next_state;    /* MERGED_PATTERN_STATE_* */
>> > +       enum monitor_release_reason release_reason;
>> >  };
>> >
>> >  /* Some data like last_seen, timer/timeout values need to be maintained
>> > @@ -541,6 +555,18 @@ static void monitor_free(struct adv_monitor *monitor)
>> >         free(monitor);
>> >  }
>> >
>> > +/* Includes monitor release reason into the dbus message */
>> > +static void report_release_reason_setup(DBusMessageIter *iter, void *user_data)
>> > +{
>> > +       const struct adv_monitor *monitor = user_data;
>> > +       int8_t release_reason = REASON_UNKNOWN;
>> > +
>> > +       if (monitor)
>> > +               release_reason = monitor->release_reason;
>> > +
>> > +       dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE, &release_reason);
>> > +}
>> > +
>> >  /* Calls Release() method of the remote Adv Monitor */
>> >  static void monitor_release(struct adv_monitor *monitor)
>> >  {
>> > @@ -560,8 +586,9 @@ static void monitor_release(struct adv_monitor *monitor)
>> >         DBG("Calling Release() on Adv Monitor of owner %s at path %s",
>> >                 monitor->app->owner, monitor->path);
>> >
>> > -       g_dbus_proxy_method_call(monitor->proxy, "Release", NULL, NULL, NULL,
>> > -                                       NULL);
>> > +       g_dbus_proxy_method_call(monitor->proxy, "Release",
>> > +                                       report_release_reason_setup, NULL,
>> > +                                       monitor, NULL);
>> >  }
>> >
>> >  /* Removes monitor from the merged_pattern. This would result in removing it
>> > @@ -635,13 +662,20 @@ static void monitor_destroy(void *data)
>> >  static void app_destroy(void *data)
>> >  {
>> >         struct adv_monitor_app *app = data;
>> > +       const struct queue_entry *e;
>> >
>> >         if (!app)
>> >                 return;
>> >
>> >         DBG("Destroy Adv Monitor app %s at path %s", app->owner, app->path);
>> >
>> > -       queue_destroy(app->monitors, monitor_destroy);
>> > +       for (e = queue_get_entries(app->monitors); e; e = e->next) {
>> > +               struct adv_monitor *m = e->data;
>> > +
>> > +               m->release_reason = REASON_APP_DESTROYED;
>> > +               monitor_destroy(m);
>> > +       }
>> > +       queue_destroy(app->monitors, NULL);
>> >
>> >         if (app->reg) {
>> >                 app_reply_msg(app, btd_error_failed(app->reg,
>> > @@ -793,6 +827,7 @@ static bool parse_monitor_type(struct adv_monitor *monitor, const char *path)
>> >         }
>> >
>> >  failed:
>> > +       monitor->release_reason = REASON_INVALID_TYPE;
>> >         btd_error(adapter_id,
>> >                         "Invalid argument of property Type of the Adv Monitor "
>> >                         "at path %s", path);
>> > @@ -919,6 +954,7 @@ done:
>> >         return true;
>> >
>> >  failed:
>> > +       monitor->release_reason = REASON_INVALID_RSSI_PARAMS;
>> >         btd_error(adapter_id,
>> >                         "Invalid argument of RSSI thresholds and timeouts "
>> >                         "of the Adv Monitor at path %s",
>> > @@ -1005,6 +1041,7 @@ static bool parse_patterns(struct adv_monitor *monitor, const char *path)
>> >         return true;
>> >
>> >  failed:
>> > +       monitor->release_reason = REASON_INVALID_PATTERNS;
>> >         btd_error(adapter_id, "Invalid argument of property Patterns of the "
>> >                         "Adv Monitor at path %s", path);
>> >
>> > @@ -1053,6 +1090,7 @@ static void merged_pattern_destroy_monitors(
>> >                 struct adv_monitor *monitor = e->data;
>> >
>> >                 monitor->merged_pattern = NULL;
>> > +               monitor->release_reason = merged_pattern->release_reason;
>> >                 monitor_destroy(monitor);
>> >         }
>> >  }
>> > @@ -1086,6 +1124,7 @@ static void remove_adv_monitor_cb(uint8_t status, uint16_t length,
>> >         return;
>> >
>> >  fail:
>> > +       merged_pattern->release_reason = REASON_FAILED_TO_REMOVE;
>> >         merged_pattern_destroy_monitors(merged_pattern);
>> >         merged_pattern_free(merged_pattern);
>> >  }
>> > @@ -1142,6 +1181,7 @@ static void add_adv_patterns_monitor_cb(uint8_t status, uint16_t length,
>> >         return;
>> >
>> >  fail:
>> > +       merged_pattern->release_reason = REASON_FAILED_TO_ADD;
>> >         merged_pattern_destroy_monitors(merged_pattern);
>> >         merged_pattern_free(merged_pattern);
>> >  }
>> > @@ -1285,6 +1325,7 @@ static void monitor_proxy_added_cb(GDBusProxy *proxy, void *user_data)
>> >                 merged_pattern_add(monitor->merged_pattern);
>> >         } else {
>> >                 if (!merge_is_possible(existing_pattern, monitor)) {
>> > +                       monitor->release_reason = REASON_ALREADY_EXISTS;
>> >                         monitor_destroy(monitor);
>> >                         DBG("Adv Monitor at path %s released due to existing "
>> >                                 "monitor", path);
>> > @@ -1551,6 +1592,7 @@ static void remove_merged_pattern(void *data, void *user_data)
>> >  {
>> >         struct adv_monitor_merged_pattern *merged_pattern = data;
>> >         uint16_t *handle = user_data;
>> > +       const struct queue_entry *e;
>> >
>> >         if (!handle)
>> >                 return;
>> > @@ -1562,8 +1604,14 @@ static void remove_merged_pattern(void *data, void *user_data)
>> >         DBG("Adv monitor with handle:0x%04x removed by kernel",
>> >                 merged_pattern->monitor_handle);
>> >
>> > +       for (e = queue_get_entries(merged_pattern->monitors); e; e = e->next) {
>> > +               struct adv_monitor *m = e->data;
>> > +
>> > +               m->release_reason = REASON_REMOVED_BY_KERNEL;
>> > +               monitor_destroy(m);
>> > +       }
>> >         queue_foreach(merged_pattern->monitors, monitor_state_removed, NULL);
>> > -       queue_destroy(merged_pattern->monitors, monitor_destroy);
>> > +       queue_destroy(merged_pattern->monitors, NULL);
>> >         merged_pattern_free(merged_pattern);
>> >  }
>> >
>> > --
>> > 2.35.1.894.gb6a874cedc-goog
>> >
>>
>>
>> --
>> Luiz Augusto von Dentz
>
>
> Regards,
> Manish.
>
diff mbox series

Patch

diff --git a/doc/advertisement-monitor-api.txt b/doc/advertisement-monitor-api.txt
index 942d44b2f..fcbd9c5c2 100644
--- a/doc/advertisement-monitor-api.txt
+++ b/doc/advertisement-monitor-api.txt
@@ -17,12 +17,22 @@  Service		org.bluez
 Interface	org.bluez.AdvertisementMonitor1 [experimental]
 Object path	freely definable
 
-Methods		void Release() [noreply]
+Methods		void Release(Int8 reason) [noreply]
 
 			This gets called as a signal for a client to perform
 			clean-up when (1)a monitor cannot be activated after it
 			was exposed or (2)a monitor has been deactivated.
 
+			Possible reasons:  0  Unknown reason
+					   1  Invalid monitor type
+					   2  Invalid RSSI parameter(s)
+					   3  Invalid pattern(s)
+					   4  Monitor already exists
+					   5  Kernel failed to add monitor
+					   6  Kernel failed to remove monitor
+					   7  Monitor removed by kernel
+					   8  App unregistered/destroyed
+
 		void Activate() [noreply]
 
 			After a monitor was exposed, this gets called as a
diff --git a/src/adv_monitor.c b/src/adv_monitor.c
index 85231557e..6ee3736d2 100644
--- a/src/adv_monitor.c
+++ b/src/adv_monitor.c
@@ -90,6 +90,18 @@  enum monitor_state {
 	MONITOR_STATE_RELEASED,	/* Dbus Object removed by app */
 };
 
+enum monitor_release_reason {
+	REASON_UNKNOWN,
+	REASON_INVALID_TYPE,
+	REASON_INVALID_RSSI_PARAMS,
+	REASON_INVALID_PATTERNS,
+	REASON_ALREADY_EXISTS,
+	REASON_FAILED_TO_ADD,
+	REASON_FAILED_TO_REMOVE,
+	REASON_REMOVED_BY_KERNEL,
+	REASON_APP_DESTROYED,
+};
+
 enum merged_pattern_state {
 	MERGED_PATTERN_STATE_ADDING,	/* Adding pattern to kernel */
 	MERGED_PATTERN_STATE_REMOVING,	/* Removing pattern from kernel */
@@ -113,6 +125,7 @@  struct adv_monitor {
 	char *path;
 
 	enum monitor_state state;	/* MONITOR_STATE_* */
+	enum monitor_release_reason release_reason;
 
 	struct rssi_parameters rssi;	/* RSSI parameter for this monitor */
 	struct adv_monitor_merged_pattern *merged_pattern;
@@ -137,6 +150,7 @@  struct adv_monitor_merged_pattern {
 	struct queue *patterns;		/* List of bt_ad_pattern objects */
 	enum merged_pattern_state current_state; /* MERGED_PATTERN_STATE_* */
 	enum merged_pattern_state next_state;	 /* MERGED_PATTERN_STATE_* */
+	enum monitor_release_reason release_reason;
 };
 
 /* Some data like last_seen, timer/timeout values need to be maintained
@@ -541,6 +555,18 @@  static void monitor_free(struct adv_monitor *monitor)
 	free(monitor);
 }
 
+/* Includes monitor release reason into the dbus message */
+static void report_release_reason_setup(DBusMessageIter *iter, void *user_data)
+{
+	const struct adv_monitor *monitor = user_data;
+	int8_t release_reason = REASON_UNKNOWN;
+
+	if (monitor)
+		release_reason = monitor->release_reason;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE, &release_reason);
+}
+
 /* Calls Release() method of the remote Adv Monitor */
 static void monitor_release(struct adv_monitor *monitor)
 {
@@ -560,8 +586,9 @@  static void monitor_release(struct adv_monitor *monitor)
 	DBG("Calling Release() on Adv Monitor of owner %s at path %s",
 		monitor->app->owner, monitor->path);
 
-	g_dbus_proxy_method_call(monitor->proxy, "Release", NULL, NULL, NULL,
-					NULL);
+	g_dbus_proxy_method_call(monitor->proxy, "Release",
+					report_release_reason_setup, NULL,
+					monitor, NULL);
 }
 
 /* Removes monitor from the merged_pattern. This would result in removing it
@@ -635,13 +662,20 @@  static void monitor_destroy(void *data)
 static void app_destroy(void *data)
 {
 	struct adv_monitor_app *app = data;
+	const struct queue_entry *e;
 
 	if (!app)
 		return;
 
 	DBG("Destroy Adv Monitor app %s at path %s", app->owner, app->path);
 
-	queue_destroy(app->monitors, monitor_destroy);
+	for (e = queue_get_entries(app->monitors); e; e = e->next) {
+		struct adv_monitor *m = e->data;
+
+		m->release_reason = REASON_APP_DESTROYED;
+		monitor_destroy(m);
+	}
+	queue_destroy(app->monitors, NULL);
 
 	if (app->reg) {
 		app_reply_msg(app, btd_error_failed(app->reg,
@@ -793,6 +827,7 @@  static bool parse_monitor_type(struct adv_monitor *monitor, const char *path)
 	}
 
 failed:
+	monitor->release_reason = REASON_INVALID_TYPE;
 	btd_error(adapter_id,
 			"Invalid argument of property Type of the Adv Monitor "
 			"at path %s", path);
@@ -919,6 +954,7 @@  done:
 	return true;
 
 failed:
+	monitor->release_reason = REASON_INVALID_RSSI_PARAMS;
 	btd_error(adapter_id,
 			"Invalid argument of RSSI thresholds and timeouts "
 			"of the Adv Monitor at path %s",
@@ -1005,6 +1041,7 @@  static bool parse_patterns(struct adv_monitor *monitor, const char *path)
 	return true;
 
 failed:
+	monitor->release_reason = REASON_INVALID_PATTERNS;
 	btd_error(adapter_id, "Invalid argument of property Patterns of the "
 			"Adv Monitor at path %s", path);
 
@@ -1053,6 +1090,7 @@  static void merged_pattern_destroy_monitors(
 		struct adv_monitor *monitor = e->data;
 
 		monitor->merged_pattern = NULL;
+		monitor->release_reason = merged_pattern->release_reason;
 		monitor_destroy(monitor);
 	}
 }
@@ -1086,6 +1124,7 @@  static void remove_adv_monitor_cb(uint8_t status, uint16_t length,
 	return;
 
 fail:
+	merged_pattern->release_reason = REASON_FAILED_TO_REMOVE;
 	merged_pattern_destroy_monitors(merged_pattern);
 	merged_pattern_free(merged_pattern);
 }
@@ -1142,6 +1181,7 @@  static void add_adv_patterns_monitor_cb(uint8_t status, uint16_t length,
 	return;
 
 fail:
+	merged_pattern->release_reason = REASON_FAILED_TO_ADD;
 	merged_pattern_destroy_monitors(merged_pattern);
 	merged_pattern_free(merged_pattern);
 }
@@ -1285,6 +1325,7 @@  static void monitor_proxy_added_cb(GDBusProxy *proxy, void *user_data)
 		merged_pattern_add(monitor->merged_pattern);
 	} else {
 		if (!merge_is_possible(existing_pattern, monitor)) {
+			monitor->release_reason = REASON_ALREADY_EXISTS;
 			monitor_destroy(monitor);
 			DBG("Adv Monitor at path %s released due to existing "
 				"monitor", path);
@@ -1551,6 +1592,7 @@  static void remove_merged_pattern(void *data, void *user_data)
 {
 	struct adv_monitor_merged_pattern *merged_pattern = data;
 	uint16_t *handle = user_data;
+	const struct queue_entry *e;
 
 	if (!handle)
 		return;
@@ -1562,8 +1604,14 @@  static void remove_merged_pattern(void *data, void *user_data)
 	DBG("Adv monitor with handle:0x%04x removed by kernel",
 		merged_pattern->monitor_handle);
 
+	for (e = queue_get_entries(merged_pattern->monitors); e; e = e->next) {
+		struct adv_monitor *m = e->data;
+
+		m->release_reason = REASON_REMOVED_BY_KERNEL;
+		monitor_destroy(m);
+	}
 	queue_foreach(merged_pattern->monitors, monitor_state_removed, NULL);
-	queue_destroy(merged_pattern->monitors, monitor_destroy);
+	queue_destroy(merged_pattern->monitors, NULL);
 	merged_pattern_free(merged_pattern);
 }