Re: [Bluez PATCH v2 2/2] adv_monitor: merge monitors with the same pattern

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Archie,

On Fri, Mar 19, 2021 at 12:56 AM Archie Pusaka <apusaka@xxxxxxxxxx> wrote:
>
> From: Archie Pusaka <apusaka@xxxxxxxxxxxx>
>
> Some bluetooth chipset (e.g. Intel) doesn't support MSFT extension
> monitors with the same pattern. In order to make them work, and also
> to generally make their task easier, we merge monitors with the same
> pattern in the userspace. Therefore, each monitor sent to the kernel
> will all have different patterns.
>
> If the merged monitor have different RSSI parameter, we would choose
> the most lenient parameter of the two, since we can still do
> additional filtering in the userspace. This way, we wouldn't miss any
> information and can still get the benefit of offloading the filtering.
>
> Reviewed-by: Miao-chen Chou <mcchou@xxxxxxxxxxxx>
> ---
>
> Changes in v2:
> * Remove unnecessary variable
>
>  src/adv_monitor.c | 663 +++++++++++++++++++++++++++++++++++++---------
>  1 file changed, 536 insertions(+), 127 deletions(-)
>
> diff --git a/src/adv_monitor.c b/src/adv_monitor.c
> index 131dc80039..67c7025700 100644
> --- a/src/adv_monitor.c
> +++ b/src/adv_monitor.c
> @@ -62,6 +62,7 @@ struct btd_adv_monitor_manager {
>         uint8_t max_num_patterns;
>
>         struct queue *apps;     /* apps who registered for Adv monitoring */
> +       struct queue *merged_patterns;
>  };
>
>  struct adv_monitor_app {
> @@ -89,6 +90,12 @@ enum monitor_state {
>         MONITOR_STATE_RELEASED, /* Dbus Object removed by app */
>  };
>
> +enum merged_pattern_state {
> +       MERGED_PATTERN_STATE_ADDING,    /* Adding pattern to kernel */
> +       MERGED_PATTERN_STATE_REMOVING,  /* Removing pattern from kernel */
> +       MERGED_PATTERN_STATE_STABLE,    /* Idle */
> +};
> +
>  struct rssi_parameters {
>         int8_t high_rssi;               /* High RSSI threshold */
>         uint16_t high_rssi_timeout;     /* High RSSI threshold timeout */
> @@ -106,13 +113,30 @@ struct adv_monitor {
>         char *path;
>
>         enum monitor_state state;       /* MONITOR_STATE_* */
> -       uint16_t monitor_handle;        /* Kernel Monitor Handle */
>
>         struct rssi_parameters rssi;    /* RSSI parameter for this monitor */
> +       struct adv_monitor_merged_pattern *merged_pattern;
> +
>         struct queue *devices;          /* List of adv_monitor_device objects */
> +};
>
> +/* Some chipsets doesn't support multiple monitors with the same pattern.
> + * To solve that and to generally ease their task, we merge monitors with the
> + * same pattern, so those monitors will only be sent once to the kernel.
> + */
> +struct adv_monitor_merged_pattern {
> +       struct btd_adv_monitor_manager *manager;
> +       uint16_t monitor_handle;        /* Kernel Monitor Handle */
> +       struct rssi_parameters rssi;    /* Merged RSSI parameter for |monitors|,
> +                                        * this will be sent to the kernel.
> +                                        */
> +       struct queue *monitors;         /* List of adv_monitor objects which
> +                                        * have this pattern
> +                                        */
>         enum monitor_type type;         /* MONITOR_TYPE_* */
>         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_* */
>  };
>
>  /* Some data like last_seen, timer/timeout values need to be maintained
> @@ -154,6 +178,11 @@ static void monitor_device_free(void *data);
>  static void adv_monitor_filter_rssi(struct adv_monitor *monitor,
>                                         struct btd_device *device, int8_t rssi);
>
> +static void merged_pattern_send_add(
> +                       struct adv_monitor_merged_pattern *merged_pattern);
> +static void merged_pattern_send_remove(
> +                       struct adv_monitor_merged_pattern *merged_pattern);
> +
>  const struct adv_monitor_type {
>         enum monitor_type type;
>         const char *name;
> @@ -199,6 +228,278 @@ static void pattern_free(void *data)
>         free(pattern);
>  }
>
> +static void merged_pattern_free(void *data)
> +{
> +       struct adv_monitor_merged_pattern *merged_pattern = data;
> +
> +       queue_destroy(merged_pattern->patterns, pattern_free);
> +       queue_destroy(merged_pattern->monitors, NULL);
> +
> +       if (merged_pattern->manager)
> +               queue_remove(merged_pattern->manager->merged_patterns,
> +                                                       merged_pattern);
> +       free(merged_pattern);
> +}
> +
> +/* Returns the smaller of the two integers |a| and |b| which is not equal to the
> + * |unset| value. If both are unset, return unset.
> + */
> +static int get_smaller_not_unset(int a, int b, int unset)
> +{
> +       if (a == unset)
> +               return b;
> +       if (b == unset)
> +               return a;
> +
> +       return a < b ? a : b;
> +}
> +
> +/* Merges two RSSI parameters, return the result. The result is chosen to be
> + * whichever is more lenient of the two inputs, so we can pass that to the
> + * kernel and still do additional filtering in the user space without loss of
> + * information while still receiving benefit from offloading some filtering to
> + * the hardware.
> + * It is allowed for |a|, |b|, and |merged| to point to the same object.
> + */
> +static void merge_rssi(const struct rssi_parameters *a,
> +                       const struct rssi_parameters *b,
> +                       struct rssi_parameters *merged)
> +{
> +       /* For low rssi, low_timeout, and high_rssi, choose the minimum of the
> +        * two values. Filtering the higher values is done on userspace.
> +        */
> +       merged->low_rssi = get_smaller_not_unset(a->low_rssi, b->low_rssi,
> +                                               ADV_MONITOR_UNSET_RSSI);
> +       merged->high_rssi = get_smaller_not_unset(a->high_rssi, b->high_rssi,
> +                                               ADV_MONITOR_UNSET_RSSI);
> +       merged->low_rssi_timeout = get_smaller_not_unset(a->low_rssi_timeout,
> +                                               b->low_rssi_timeout,
> +                                               ADV_MONITOR_UNSET_TIMEOUT);
> +
> +       /* High timeout doesn't matter for now, it will be zeroed when it is
> +        * forwarded to kernel anyway.
> +        */
> +       merged->high_rssi_timeout = 0;
> +
> +       /* Sampling period is not implemented yet in userspace. There is no
> +        * good value if the two values are different, so just choose 0 for
> +        * always reporting, to avoid missing packets.
> +        */
> +       if (a->sampling_period != b->sampling_period)
> +               merged->sampling_period = 0;
> +       else
> +               merged->sampling_period = a->sampling_period;
> +}
> +
> +/* Two merged_pattern are considered equal if all the following are true:
> + * (1) both has the same monitor_type
> + * (2) both has exactly the same pattern in the same order
> + * Therefore, patterns A+B and B+A are considered different, as well as patterns
> + * A and A+A. This shouldn't cause any issue, but solving this issue is a
> + * potential improvement.
> + */
> +static bool merged_pattern_is_equal(struct adv_monitor_merged_pattern *a,
> +                                       struct adv_monitor_merged_pattern *b)
> +{
> +       const struct queue_entry *a_entry, *b_entry;
> +       struct bt_ad_pattern *a_data, *b_data;
> +
> +       if (a->type != b->type)
> +               return false;
> +
> +       if (queue_length(a->patterns) != queue_length(b->patterns))
> +               return false;
> +
> +       a_entry = queue_get_entries(a->patterns);
> +       b_entry = queue_get_entries(b->patterns);
> +
> +       while (a_entry) {
> +               a_data = a_entry->data;
> +               b_data = b_entry->data;
> +
> +               if (a_data->type != b_data->type ||
> +                   a_data->offset != b_data->offset ||
> +                   a_data->len != b_data->len ||
> +                   memcmp(a_data->data, b_data->data, a_data->len) != 0)
> +                       return false;
> +
> +               a_entry = a_entry->next;
> +               b_entry = b_entry->next;
> +       }
> +
> +       return true;
> +}
> +
> +/* Finds a merged_pattern in manager with a specific pattern/type */

You can probably replace this with queue_find passing
merged_pattern_is_equal instead of manually iterating with
queue_get_entries.

> +static struct adv_monitor_merged_pattern *merged_pattern_find(
> +                       struct btd_adv_monitor_manager *manager,
> +                       struct adv_monitor_merged_pattern *merged_pattern)
> +{
> +       const struct queue_entry *e;
> +       struct adv_monitor_merged_pattern *p;
> +
> +       for (e = queue_get_entries(manager->merged_patterns); e; e = e->next) {
> +               p = e->data;
> +
> +               if (merged_pattern_is_equal(p, merged_pattern))
> +                       return p;
> +       }
> +
> +       return NULL;
> +}
> +
> +static char *get_merged_pattern_state_name(enum merged_pattern_state state)
> +{
> +       switch (state) {
> +       case MERGED_PATTERN_STATE_ADDING:
> +               return "Adding";
> +       case MERGED_PATTERN_STATE_REMOVING:
> +               return "Removing";
> +       case MERGED_PATTERN_STATE_STABLE:
> +               return "Stable";
> +       }
> +
> +       return NULL;
> +}
> +
> +/* Adds a new merged pattern */
> +static void merged_pattern_add(
> +                       struct adv_monitor_merged_pattern *merged_pattern)
> +{
> +       /* This is only called when no merged_pattern found. Therefore, the
> +        * state must be stable.
> +        */
> +       if (merged_pattern->current_state != MERGED_PATTERN_STATE_STABLE) {
> +               btd_error(merged_pattern->manager->adapter_id,
> +                       "Add merged_pattern request when state is not stable");
> +               return;
> +       }
> +
> +       merged_pattern->current_state = MERGED_PATTERN_STATE_ADDING;
> +       merged_pattern_send_add(merged_pattern);
> +
> +       DBG("Monitor state: %s -> %s",
> +               get_merged_pattern_state_name(merged_pattern->current_state),
> +               get_merged_pattern_state_name(merged_pattern->next_state));
> +}
> +
> +/* Removes merged pattern, or queues for removal if busy */
> +static void merged_pattern_remove(
> +                       struct adv_monitor_merged_pattern *merged_pattern)
> +{
> +       rssi_unset(&merged_pattern->rssi);
> +
> +       /* If we currently are removing, cancel subsequent ADD command if any */
> +       if (merged_pattern->current_state == MERGED_PATTERN_STATE_REMOVING) {
> +               merged_pattern->next_state = MERGED_PATTERN_STATE_STABLE;
> +               goto print_state;
> +       }
> +
> +       /* If stable, we can proceed with removal right away */
> +       if (merged_pattern->current_state == MERGED_PATTERN_STATE_STABLE) {
> +               merged_pattern->current_state = MERGED_PATTERN_STATE_REMOVING;
> +               merged_pattern_send_remove(merged_pattern);
> +       } else {
> +               /* otherwise queue the removal */
> +               merged_pattern->next_state = MERGED_PATTERN_STATE_REMOVING;
> +       }
> +
> +print_state:
> +       DBG("Monitor state: %s -> %s",
> +               get_merged_pattern_state_name(merged_pattern->current_state),
> +               get_merged_pattern_state_name(merged_pattern->next_state));
> +}
> +
> +/* Replaces (removes and re-adds) merged pattern, or queues it if busy */
> +static void merged_pattern_replace(
> +                       struct adv_monitor_merged_pattern *merged_pattern,
> +                       const struct rssi_parameters *rssi)
> +{
> +       /* If the RSSI are the same then nothing needs to be done, except on
> +        * the case where pattern is being removed. In that case, we need to
> +        * re-add the pattern.
> +        * high_rssi_timeout is purposedly left out in the comparison since
> +        * the value is ignored upon submission to kernel.
> +        */
> +       if (merged_pattern->rssi.high_rssi == rssi->high_rssi &&
> +           merged_pattern->rssi.low_rssi == rssi->low_rssi &&
> +           merged_pattern->rssi.low_rssi_timeout == rssi->low_rssi_timeout &&
> +           merged_pattern->rssi.sampling_period == rssi->sampling_period &&
> +           merged_pattern->current_state != MERGED_PATTERN_STATE_REMOVING)
> +               return;
> +
> +       merged_pattern->rssi = *rssi;
> +
> +       /* If stable, we can proceed with replacement. */
> +       if (merged_pattern->current_state == MERGED_PATTERN_STATE_STABLE) {
> +               /* Replacement is done by first removing, then re-adding */
> +               merged_pattern->current_state = MERGED_PATTERN_STATE_REMOVING;
> +               merged_pattern->next_state = MERGED_PATTERN_STATE_ADDING;
> +               merged_pattern_send_remove(merged_pattern);
> +       } else {
> +               /* otherwise queue the replacement */
> +               merged_pattern->next_state = MERGED_PATTERN_STATE_ADDING;
> +       }
> +
> +       DBG("Monitor state: %s -> %s",
> +               get_merged_pattern_state_name(merged_pattern->current_state),
> +               get_merged_pattern_state_name(merged_pattern->next_state));
> +}
> +
> +/* Current_state of merged_pattern is done, proceed to the next_state */
> +static void merged_pattern_process_next_step(
> +                                       struct adv_monitor_merged_pattern *mp)
> +{
> +       if (mp->current_state == MERGED_PATTERN_STATE_STABLE) {
> +               btd_error(mp->manager->adapter_id,
> +                               "Merged pattern invalid current state");
> +               return;
> +       }
> +
> +       if (mp->current_state == MERGED_PATTERN_STATE_REMOVING) {
> +               /* We might need to follow-up with re-adding the pattern */
> +               if (mp->next_state == MERGED_PATTERN_STATE_ADDING) {
> +                       mp->current_state = MERGED_PATTERN_STATE_ADDING;
> +                       mp->next_state = MERGED_PATTERN_STATE_STABLE;
> +                       merged_pattern_send_add(mp);
> +                       goto print_state;
> +               }
> +
> +               /* We should never end up with remove-remove sequence */
> +               if (mp->next_state == MERGED_PATTERN_STATE_REMOVING)
> +                       btd_error(mp->manager->adapter_id,
> +                               "Merged pattern can't be removed again");
> +
> +               /* No more operations */
> +               mp->current_state = MERGED_PATTERN_STATE_STABLE;
> +               mp->next_state = MERGED_PATTERN_STATE_STABLE;
> +               goto print_state;
> +       }
> +
> +       /* current_state == MERGED_PATTERN_STATE_ADDING */
> +       if (mp->next_state == MERGED_PATTERN_STATE_REMOVING) {
> +               mp->current_state = MERGED_PATTERN_STATE_REMOVING;
> +               mp->next_state = MERGED_PATTERN_STATE_STABLE;
> +               merged_pattern_send_remove(mp);
> +               goto print_state;
> +       } else if (mp->next_state == MERGED_PATTERN_STATE_ADDING) {
> +               /* To re-add a just added pattern, we need to remove it first */
> +               mp->current_state = MERGED_PATTERN_STATE_REMOVING;
> +               mp->next_state = MERGED_PATTERN_STATE_ADDING;
> +               merged_pattern_send_remove(mp);
> +               goto print_state;
> +       }
> +
> +       /* No more operations */
> +       mp->current_state = MERGED_PATTERN_STATE_STABLE;
> +       mp->next_state = MERGED_PATTERN_STATE_STABLE;
> +
> +print_state:
> +       DBG("Monitor state: %s -> %s",
> +                       get_merged_pattern_state_name(mp->current_state),
> +                       get_merged_pattern_state_name(mp->next_state));
> +}
> +
>  /* Frees a monitor object */
>  static void monitor_free(struct adv_monitor *monitor)
>  {
> @@ -208,8 +509,6 @@ static void monitor_free(struct adv_monitor *monitor)
>         queue_destroy(monitor->devices, monitor_device_free);
>         monitor->devices = NULL;
>
> -       queue_destroy(monitor->patterns, pattern_free);
> -
>         free(monitor);
>  }
>
> @@ -218,10 +517,12 @@ static void monitor_release(struct adv_monitor *monitor)
>  {
>         /* Release() method on a monitor can be called when -
>          * 1. monitor initialization failed
> -        * 2. app calls UnregisterMonitor and monitors held by app are released
> +        * 2. app calls UnregisterMonitor and monitors held by app are released,
> +        *    it may or may not be activated at this point
>          * 3. monitor is removed by kernel
>          */
>         if (monitor->state != MONITOR_STATE_FAILED &&
> +           monitor->state != MONITOR_STATE_INITED &&
>             monitor->state != MONITOR_STATE_ACTIVE &&
>             monitor->state != MONITOR_STATE_REMOVED) {
>                 return;
> @@ -234,53 +535,56 @@ static void monitor_release(struct adv_monitor *monitor)
>                                         NULL);
>  }
>
> -/* Handles the callback of Remove Adv Monitor command */
> -static void remove_adv_monitor_cb(uint8_t status, uint16_t length,
> -                               const void *param, void *user_data)
> -{
> -       const struct mgmt_rp_remove_adv_monitor *rp = param;
> -
> -       if (status != MGMT_STATUS_SUCCESS || !param) {
> -               error("Failed to Remove Adv Monitor with status 0x%02x",
> -                               status);
> -               return;
> -       }
> -
> -       if (length < sizeof(*rp)) {
> -               error("Wrong size of Remove Adv Monitor response");
> -               return;
> -       }
> -
> -       DBG("Adv monitor with handle:0x%04x removed from kernel",
> -               le16_to_cpu(rp->monitor_handle));
> -}
> -
> -/* Sends Remove Adv Monitor command to the kernel */
> +/* Removes monitor from the merged_pattern. This would result in removing it
> + * from the kernel if there is only one such monitor with that pattern.
> + */
>  static void monitor_remove(struct adv_monitor *monitor)
>  {
>         struct adv_monitor_app *app = monitor->app;
>         uint16_t adapter_id = app->manager->adapter_id;
> -       struct mgmt_cp_remove_adv_monitor cp;
> +       struct adv_monitor_merged_pattern *merged_pattern;
> +       const struct queue_entry *e;
> +       struct rssi_parameters rssi;
>
>         /* Monitor from kernel can be removed when -
> -        * 1. already activated monitor object is deleted by app
> +        * 1. monitor object is deleted by app - may or may not be activated
>          * 2. app is destroyed and monitors held by app are marked as released
>          */
> -       if (monitor->state != MONITOR_STATE_ACTIVE &&
> +       if (monitor->state != MONITOR_STATE_INITED &&
> +           monitor->state != MONITOR_STATE_ACTIVE &&
>             monitor->state != MONITOR_STATE_RELEASED) {
>                 return;
>         }
>
>         monitor->state = MONITOR_STATE_REMOVED;
>
> -       cp.monitor_handle = cpu_to_le16(monitor->monitor_handle);
> -
> -       if (!mgmt_send(app->manager->mgmt, MGMT_OP_REMOVE_ADV_MONITOR,
> -                       adapter_id, sizeof(cp), &cp, remove_adv_monitor_cb,
> -                       app->manager, NULL)) {
> +       if (!monitor->merged_pattern) {
>                 btd_error(adapter_id,
> -                               "Unable to send Remove Advt Monitor command");
> +                       "Merged_pattern not found when removing monitor");
> +               return;
> +       }
> +
> +       merged_pattern = monitor->merged_pattern;
> +       monitor->merged_pattern = NULL;
> +       queue_remove(merged_pattern->monitors, monitor);
> +
> +       /* No more monitors - just remove the pattern entirely */
> +       if (queue_length(merged_pattern->monitors) == 0) {
> +               merged_pattern_remove(merged_pattern);
> +               return;
> +       }
> +
> +       /* Calculate the merge result of the RSSIs of the monitors with the
> +        * same pattern, minus the monitor being removed.
> +        */
> +       rssi_unset(&rssi);
> +       for (e = queue_get_entries(merged_pattern->monitors); e; e = e->next) {
> +               struct adv_monitor *m = e->data;
> +
> +               merge_rssi(&rssi, &m->rssi, &rssi);
>         }
> +
> +       merged_pattern_replace(merged_pattern, &rssi);
>  }
>
>  /* Destroys monitor object */
> @@ -334,7 +638,8 @@ static void monitor_state_released(void *data, void *user_data)
>  {
>         struct adv_monitor *monitor = data;
>
> -       if (!monitor && monitor->state != MONITOR_STATE_ACTIVE)
> +       if (!monitor && monitor->state != MONITOR_STATE_INITED
> +                               && monitor->state != MONITOR_STATE_ACTIVE)
>                 return;
>
>         monitor->state = MONITOR_STATE_RELEASED;
> @@ -394,9 +699,6 @@ static struct adv_monitor *monitor_new(struct adv_monitor_app *app,
>         rssi_unset(&monitor->rssi);
>         monitor->devices = queue_new();
>
> -       monitor->type = MONITOR_TYPE_NONE;
> -       monitor->patterns = NULL;
> -
>         return monitor;
>  }
>
> @@ -439,7 +741,7 @@ static bool parse_monitor_type(struct adv_monitor *monitor, const char *path)
>
>         for (t = supported_types; t->name; t++) {
>                 if (strcmp(t->name, type_str) == 0) {
> -                       monitor->type = t->type;
> +                       monitor->merged_pattern->type = t->type;
>                         return true;
>                 }
>         }
> @@ -560,6 +862,8 @@ done:
>                 monitor->rssi.low_rssi, monitor->rssi.low_rssi_timeout,
>                 monitor->rssi.sampling_period);
>
> +       monitor->merged_pattern->rssi = monitor->rssi;
> +
>         return true;
>
>  failed:
> @@ -586,14 +890,14 @@ static bool parse_patterns(struct adv_monitor *monitor, const char *path)
>                 return false;
>         }
>
> -       monitor->patterns = queue_new();
> -
>         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY ||
>                 dbus_message_iter_get_element_type(&array) !=
>                 DBUS_TYPE_STRUCT) {
>                 goto failed;
>         }
>
> +       monitor->merged_pattern->patterns = queue_new();
> +
>         dbus_message_iter_recurse(&array, &array_iter);
>
>         while (dbus_message_iter_get_arg_type(&array_iter) ==
> @@ -637,21 +941,18 @@ static bool parse_patterns(struct adv_monitor *monitor, const char *path)
>                 if (!pattern)
>                         goto failed;
>
> -               queue_push_tail(monitor->patterns, pattern);
> +               queue_push_tail(monitor->merged_pattern->patterns, pattern);
>
>                 dbus_message_iter_next(&array_iter);
>         }
>
>         /* There must be at least one pattern. */
> -       if (queue_isempty(monitor->patterns))
> +       if (queue_isempty(monitor->merged_pattern->patterns))
>                 goto failed;
>
>         return true;
>
>  failed:
> -       queue_destroy(monitor->patterns, pattern_free);
> -       monitor->patterns = NULL;
> -
>         btd_error(adapter_id, "Invalid argument of property Patterns of the "
>                         "Adv Monitor at path %s", path);
>
> @@ -659,26 +960,99 @@ failed:
>  }
>
>  /* Processes the content of the remote Adv Monitor */
> -static bool monitor_process(struct adv_monitor *monitor,
> -                               struct adv_monitor_app *app)
> +static bool monitor_process(struct adv_monitor *monitor)
>  {
>         const char *path = g_dbus_proxy_get_path(monitor->proxy);
>
>         monitor->state = MONITOR_STATE_FAILED;
>
> +       monitor->merged_pattern = malloc0(sizeof(*monitor->merged_pattern));
> +       monitor->merged_pattern->current_state = MERGED_PATTERN_STATE_STABLE;
> +       monitor->merged_pattern->next_state = MERGED_PATTERN_STATE_STABLE;
> +
>         if (!parse_monitor_type(monitor, path))
> -               goto done;
> +               goto fail;
>
>         if (!parse_rssi_and_timeout(monitor, path))
> -               goto done;
> +               goto fail;
>
> -       if (monitor->type == MONITOR_TYPE_OR_PATTERNS &&
> -               parse_patterns(monitor, path)) {
> -               monitor->state = MONITOR_STATE_INITED;
> +       if (monitor->merged_pattern->type != MONITOR_TYPE_OR_PATTERNS ||
> +                                       !parse_patterns(monitor, path))
> +               goto fail;
> +
> +       monitor->state = MONITOR_STATE_INITED;
> +       monitor->merged_pattern->monitors = queue_new();
> +       queue_push_tail(monitor->merged_pattern->monitors, monitor);
> +
> +       return true;
> +
> +fail:
> +       merged_pattern_free(monitor->merged_pattern);
> +       monitor->merged_pattern = NULL;
> +       return false;
> +}
> +
> +static void merged_pattern_destroy_monitors(
> +                       struct adv_monitor_merged_pattern *merged_pattern)
> +{
> +       const struct queue_entry *e;
> +
> +       for (e = queue_get_entries(merged_pattern->monitors); e; e = e->next) {
> +               struct adv_monitor *monitor = e->data;
> +
> +               monitor->merged_pattern = NULL;
> +               monitor_destroy(monitor);
>         }
> +}
>
> -done:
> -       return monitor->state != MONITOR_STATE_FAILED;
> +/* Handles the callback of Remove Adv Monitor command */
> +static void remove_adv_monitor_cb(uint8_t status, uint16_t length,
> +                               const void *param, void *user_data)
> +{
> +       const struct mgmt_rp_remove_adv_monitor *rp = param;
> +       struct adv_monitor_merged_pattern *merged_pattern = user_data;
> +
> +       if (status != MGMT_STATUS_SUCCESS || !param) {
> +               error("Failed to Remove Adv Monitor with status 0x%02x",
> +                               status);
> +               goto fail;
> +       }
> +
> +       if (length < sizeof(*rp)) {
> +               error("Wrong size of Remove Adv Monitor response");
> +               goto fail;
> +       }
> +
> +       DBG("Adv monitor with handle:0x%04x removed from kernel",
> +               le16_to_cpu(rp->monitor_handle));
> +
> +       merged_pattern_process_next_step(merged_pattern);
> +
> +       if (merged_pattern->current_state == MERGED_PATTERN_STATE_STABLE)
> +               merged_pattern_free(merged_pattern);
> +
> +       return;
> +
> +fail:
> +       merged_pattern_destroy_monitors(merged_pattern);
> +       merged_pattern_free(merged_pattern);
> +}
> +
> +/* sends MGMT_OP_REMOVE_ADV_MONITOR */
> +static void merged_pattern_send_remove(
> +                       struct adv_monitor_merged_pattern *merged_pattern)
> +{
> +       struct mgmt_cp_remove_adv_monitor cp;
> +       struct btd_adv_monitor_manager *manager = merged_pattern->manager;
> +
> +       cp.monitor_handle = cpu_to_le16(merged_pattern->monitor_handle);
> +
> +       if (!mgmt_send(manager->mgmt, MGMT_OP_REMOVE_ADV_MONITOR,
> +                       manager->adapter_id, sizeof(cp), &cp,
> +                       remove_adv_monitor_cb, merged_pattern, NULL)) {
> +               btd_error(merged_pattern->manager->adapter_id,
> +                               "Unable to send Remove Advt Monitor command");
> +       }
>  }
>
>  /* Handles the callback of Add Adv Patterns Monitor command */
> @@ -686,64 +1060,81 @@ static void add_adv_patterns_monitor_cb(uint8_t status, uint16_t length,
>                                         const void *param, void *user_data)
>  {
>         const struct mgmt_rp_add_adv_patterns_monitor *rp = param;
> -       struct adv_monitor *monitor = user_data;
> -       uint16_t adapter_id = monitor->app->manager->adapter_id;
> +       struct adv_monitor_merged_pattern *merged_pattern = user_data;
> +       uint16_t adapter_id = merged_pattern->manager->adapter_id;
> +       const struct queue_entry *e;
>
>         if (status != MGMT_STATUS_SUCCESS || !param) {
>                 btd_error(adapter_id,
>                                 "Failed to Add Adv Patterns Monitor with status"
>                                 " 0x%02x", status);
> -               monitor->state = MONITOR_STATE_FAILED;
> -               monitor_destroy(monitor);
> -               return;
> +               goto fail;
>         }
>
>         if (length < sizeof(*rp)) {
>                 btd_error(adapter_id, "Wrong size of Add Adv Patterns Monitor "
>                                 "response");
> -               monitor->state = MONITOR_STATE_FAILED;
> -               monitor_destroy(monitor);
> -               return;
> +               goto fail;
>         }
>
> -       monitor->monitor_handle = le16_to_cpu(rp->monitor_handle);
> -       monitor->state = MONITOR_STATE_ACTIVE;
> +       merged_pattern->monitor_handle = le16_to_cpu(rp->monitor_handle);
> +       DBG("Adv monitor with handle:0x%04x added",
> +                                               merged_pattern->monitor_handle);
>
> -       DBG("Calling Activate() on Adv Monitor of owner %s at path %s",
> -               monitor->app->owner, monitor->path);
> +       merged_pattern_process_next_step(merged_pattern);
>
> -       g_dbus_proxy_method_call(monitor->proxy, "Activate", NULL, NULL, NULL,
> -                                       NULL);
> +       if (merged_pattern->current_state != MERGED_PATTERN_STATE_STABLE)
> +               return;
> +
> +       for (e = queue_get_entries(merged_pattern->monitors); e; e = e->next) {
> +               struct adv_monitor *monitor = e->data;
> +
> +               if (monitor->state != MONITOR_STATE_INITED)
> +                       continue;
> +
> +               monitor->state = MONITOR_STATE_ACTIVE;
> +
> +               DBG("Calling Activate() on Adv Monitor of owner %s at path %s",
> +                       monitor->app->owner, monitor->path);
> +
> +               g_dbus_proxy_method_call(monitor->proxy, "Activate", NULL,
> +                                       NULL, NULL, NULL);
> +       }
> +
> +       return;
>
> -       DBG("Adv monitor with handle:0x%04x added", monitor->monitor_handle);
> +fail:
> +       merged_pattern_destroy_monitors(merged_pattern);
> +       merged_pattern_free(merged_pattern);
>  }
>
>  /* sends MGMT_OP_ADD_ADV_PATTERNS_MONITOR */
> -static bool monitor_send_add_pattern(struct adv_monitor *monitor)
> +static bool merged_pattern_send_add_pattern(
> +                       struct adv_monitor_merged_pattern *merged_pattern)
>  {
>         struct mgmt_cp_add_adv_monitor *cp = NULL;
>         uint8_t pattern_count, cp_len;
>         const struct queue_entry *e;
>         bool success = true;
>
> -       pattern_count = queue_length(monitor->patterns);
> +       pattern_count = queue_length(merged_pattern->patterns);
>         cp_len = sizeof(*cp) + pattern_count * sizeof(struct mgmt_adv_pattern);
>
>         cp = malloc0(cp_len);
>         if (!cp)
>                 return false;
>
> -       for (e = queue_get_entries(monitor->patterns); e; e = e->next) {
> +       for (e = queue_get_entries(merged_pattern->patterns); e; e = e->next) {
>                 struct bt_ad_pattern *pattern = e->data;
>
>                 memcpy(&cp->patterns[cp->pattern_count++], pattern,
>                                                         sizeof(*pattern));
>         }
>
> -       if (!mgmt_send(monitor->app->manager->mgmt,
> +       if (!mgmt_send(merged_pattern->manager->mgmt,
>                         MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
> -                       monitor->app->manager->adapter_id, cp_len, cp,
> -                       add_adv_patterns_monitor_cb, monitor, NULL)) {
> +                       merged_pattern->manager->adapter_id, cp_len, cp,
> +                       add_adv_patterns_monitor_cb, merged_pattern, NULL)) {
>                 error("Unable to send Add Adv Patterns Monitor command");
>                 success = false;
>         }
> @@ -753,38 +1144,40 @@ static bool monitor_send_add_pattern(struct adv_monitor *monitor)
>  }
>
>  /* sends MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI */
> -static bool monitor_send_add_pattern_rssi(struct adv_monitor *monitor)
> +static bool merged_pattern_send_add_pattern_rssi(
> +                       struct adv_monitor_merged_pattern *merged_pattern)
>  {
>         struct mgmt_cp_add_adv_patterns_monitor_rssi *cp = NULL;
>         uint8_t pattern_count, cp_len;
>         const struct queue_entry *e;
>         bool success = true;
>
> -       pattern_count = queue_length(monitor->patterns);
> +       pattern_count = queue_length(merged_pattern->patterns);
>         cp_len = sizeof(*cp) + pattern_count * sizeof(struct mgmt_adv_pattern);
>
>         cp = malloc0(cp_len);
>         if (!cp)
>                 return false;
>
> -       cp->rssi.high_threshold = monitor->rssi.high_rssi;
> +       cp->rssi.high_threshold = merged_pattern->rssi.high_rssi;
>         /* High threshold timeout is unsupported in kernel. Value must be 0. */
>         cp->rssi.high_threshold_timeout = 0;
> -       cp->rssi.low_threshold = monitor->rssi.low_rssi;
> -       cp->rssi.low_threshold_timeout = htobs(monitor->rssi.low_rssi_timeout);
> -       cp->rssi.sampling_period = monitor->rssi.sampling_period;
> +       cp->rssi.low_threshold = merged_pattern->rssi.low_rssi;
> +       cp->rssi.low_threshold_timeout =
> +                               htobs(merged_pattern->rssi.low_rssi_timeout);
> +       cp->rssi.sampling_period = merged_pattern->rssi.sampling_period;
>
> -       for (e = queue_get_entries(monitor->patterns); e; e = e->next) {
> +       for (e = queue_get_entries(merged_pattern->patterns); e; e = e->next) {
>                 struct bt_ad_pattern *pattern = e->data;
>
>                 memcpy(&cp->patterns[cp->pattern_count++], pattern,
>                                                         sizeof(*pattern));
>         }
>
> -       if (!mgmt_send(monitor->app->manager->mgmt,
> +       if (!mgmt_send(merged_pattern->manager->mgmt,
>                         MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI,
> -                       monitor->app->manager->adapter_id, cp_len, cp,
> -                       add_adv_patterns_monitor_cb, monitor, NULL)) {
> +                       merged_pattern->manager->adapter_id, cp_len, cp,
> +                       add_adv_patterns_monitor_cb, merged_pattern, NULL)) {
>                 error("Unable to send Add Adv Patterns Monitor RSSI command");
>                 success = false;
>         }
> @@ -793,14 +1186,26 @@ static bool monitor_send_add_pattern_rssi(struct adv_monitor *monitor)
>         return success;
>  }
>
> +/* Sends mgmt command to kernel for adding monitor */
> +static void merged_pattern_send_add(
> +                       struct adv_monitor_merged_pattern *merged_pattern)
> +{
> +       if (rssi_is_unset(&merged_pattern->rssi))
> +               merged_pattern_send_add_pattern(merged_pattern);
> +       else
> +               merged_pattern_send_add_pattern_rssi(merged_pattern);
> +}
> +
>  /* Handles an Adv Monitor D-Bus proxy added event */
>  static void monitor_proxy_added_cb(GDBusProxy *proxy, void *user_data)
>  {
>         struct adv_monitor *monitor;
>         struct adv_monitor_app *app = user_data;
> +       struct adv_monitor_merged_pattern *existing_pattern;
>         uint16_t adapter_id = app->manager->adapter_id;
>         const char *path = g_dbus_proxy_get_path(proxy);
>         const char *iface = g_dbus_proxy_get_interface(proxy);
> +       struct rssi_parameters rssi;
>
>         if (strcmp(iface, ADV_MONITOR_INTERFACE) != 0 ||
>                 !g_str_has_prefix(path, app->path)) {
> @@ -822,7 +1227,7 @@ static void monitor_proxy_added_cb(GDBusProxy *proxy, void *user_data)
>                 return;
>         }
>
> -       if (!monitor_process(monitor, app)) {
> +       if (!monitor_process(monitor)) {
>                 monitor_destroy(monitor);
>                 DBG("Adv Monitor at path %s released due to invalid content",
>                         path);
> @@ -831,10 +1236,23 @@ static void monitor_proxy_added_cb(GDBusProxy *proxy, void *user_data)
>
>         queue_push_tail(app->monitors, monitor);
>
> -       if (rssi_is_unset(&monitor->rssi))
> -               monitor_send_add_pattern(monitor);
> -       else
> -               monitor_send_add_pattern_rssi(monitor);
> +       existing_pattern = merged_pattern_find(monitor->app->manager,
> +                                               monitor->merged_pattern);
> +
> +       if (!existing_pattern) {
> +               monitor->merged_pattern->manager = monitor->app->manager;
> +               queue_push_tail(monitor->app->manager->merged_patterns,
> +                                               monitor->merged_pattern);
> +               merged_pattern_add(monitor->merged_pattern);
> +       } else {
> +               /* Since there is a matching pattern, abandon the one we have */
> +               merged_pattern_free(monitor->merged_pattern);
> +               monitor->merged_pattern = existing_pattern;
> +               queue_push_tail(existing_pattern->monitors, monitor);
> +
> +               merge_rssi(&existing_pattern->rssi, &monitor->rssi, &rssi);
> +               merged_pattern_replace(existing_pattern, &rssi);
> +       }
>
>         DBG("Adv Monitor allocated for the object at path %s", path);
>  }
> @@ -1064,54 +1482,38 @@ static const GDBusPropertyTable adv_monitor_properties[] = {
>         { }
>  };
>
> -/* Matches a monitor based on its handle */
> -static bool removed_monitor_match(const void *data, const void *user_data)
> -{
> -       const uint16_t *handle = user_data;
> -       const struct adv_monitor *monitor = data;
> -
> -       if (!data || !handle)
> -               return false;
> -
> -       return monitor->monitor_handle == *handle;
> -}
> -
>  /* Updates monitor state to 'removed' */
>  static void monitor_state_removed(void *data, void *user_data)
>  {
>         struct adv_monitor *monitor = data;
>
> -       if (!monitor && monitor->state != MONITOR_STATE_ACTIVE)
> +       if (!monitor && monitor->state != MONITOR_STATE_INITED
> +                               && monitor->state != MONITOR_STATE_ACTIVE)
>                 return;
>
>         monitor->state = MONITOR_STATE_REMOVED;
> -
> -       DBG("Adv monitor with handle:0x%04x removed by kernel",
> -               monitor->monitor_handle);
> +       monitor->merged_pattern = NULL;
>  }
>
> -/* Remove the matched monitor and reports the removal to the app */
> -static void app_remove_monitor(void *data, void *user_data)
> +/* Remove the matched merged_pattern and remove the monitors */
> +static void remove_merged_pattern(void *data, void *user_data)
>  {
> -       struct adv_monitor_app *app = data;
> -       struct adv_monitor *monitor;
> +       struct adv_monitor_merged_pattern *merged_pattern = data;
>         uint16_t *handle = user_data;
>
> -       if (handle && *handle == 0) {
> -               /* handle = 0 indicates kernel has removed all monitors */
> -               queue_foreach(app->monitors, monitor_state_removed, NULL);
> -               queue_destroy(app->monitors, monitor_destroy);
> +       if (!handle)
> +               return;
>
> +       /* handle = 0 indicates kernel has removed all monitors */
> +       if (handle != 0 && *handle != merged_pattern->monitor_handle)
>                 return;
> -       }
>
> -       monitor = queue_find(app->monitors, removed_monitor_match, handle);
> -       if (monitor) {
> -               DBG("Adv Monitor at path %s removed", monitor->path);
> +       DBG("Adv monitor with handle:0x%04x removed by kernel",
> +               merged_pattern->monitor_handle);
>
> -               monitor_state_removed(monitor, NULL);
> -               monitor_destroy(monitor);
> -       }
> +       queue_foreach(merged_pattern->monitors, monitor_state_removed, NULL);
> +       queue_destroy(merged_pattern->monitors, monitor_destroy);
> +       merged_pattern_free(merged_pattern);
>  }
>
>  /* Processes Adv Monitor removed event from kernel */
> @@ -1129,8 +1531,8 @@ static void adv_monitor_removed_callback(uint16_t index, uint16_t length,
>                 return;
>         }
>
> -       /* Traverse the apps to find the monitor */
> -       queue_foreach(manager->apps, app_remove_monitor, &handle);
> +       /* Traverse the merged_patterns to find matching pattern */
> +       queue_foreach(manager->merged_patterns, remove_merged_pattern, &handle);
>
>         DBG("Adv Monitor removed event with handle 0x%04x processed",
>                 ev->monitor_handle);
> @@ -1154,6 +1556,7 @@ static struct btd_adv_monitor_manager *manager_new(
>         manager->mgmt = mgmt_ref(mgmt);
>         manager->adapter_id = btd_adapter_get_index(adapter);
>         manager->apps = queue_new();
> +       manager->merged_patterns = queue_new();
>
>         mgmt_register(manager->mgmt, MGMT_EV_ADV_MONITOR_REMOVED,
>                         manager->adapter_id, adv_monitor_removed_callback,
> @@ -1168,6 +1571,7 @@ static void manager_free(struct btd_adv_monitor_manager *manager)
>         mgmt_unref(manager->mgmt);
>
>         queue_destroy(manager->apps, app_destroy);
> +       queue_destroy(manager->merged_patterns, merged_pattern_free);
>
>         free(manager);
>  }
> @@ -1274,6 +1678,7 @@ static void adv_match_per_monitor(void *data, void *user_data)
>  {
>         struct adv_monitor *monitor = data;
>         struct adv_content_filter_info *info = user_data;
> +       struct queue *patterns;
>
>         if (!monitor) {
>                 error("Unexpected NULL adv_monitor object upon match");
> @@ -1283,8 +1688,12 @@ static void adv_match_per_monitor(void *data, void *user_data)
>         if (monitor->state != MONITOR_STATE_ACTIVE)
>                 return;
>
> -       if (monitor->type == MONITOR_TYPE_OR_PATTERNS &&
> -               bt_ad_pattern_match(info->ad, monitor->patterns)) {
> +       if (!monitor->merged_pattern)
> +               return;
> +
> +       patterns = monitor->merged_pattern->patterns;
> +       if (monitor->merged_pattern->type == MONITOR_TYPE_OR_PATTERNS &&
> +                               bt_ad_pattern_match(info->ad, patterns)) {
>                 goto matched;
>         }
>
> --
> 2.31.0.rc2.261.g7f71774620-goog
>


-- 
Luiz Augusto von Dentz



[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux