Message ID | 20210319155542.Bluez.v2.1.I8797a75fcc7c1e997f177b08dc23a1df0272e0a5@changeid |
---|---|
State | Superseded |
Headers | show |
Series | [Bluez,v2,1/2] adv_monitor: split rssi_parameters into its own struct | expand |
Hi Archie, On Fri, Mar 19, 2021 at 12:56 AM Archie Pusaka <apusaka@google.com> wrote: > > From: Archie Pusaka <apusaka@chromium.org> > > 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@chromium.org> > --- > > 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 >
Hi Luiz, Thanks for the suggestion! I removed merged_pattern_find and directly use queue_find instead. Please give v3 another look. Thanks, Archie On Sat, 20 Mar 2021 at 03:13, Luiz Augusto von Dentz <luiz.dentz@gmail.com> wrote: > > Hi Archie, > > On Fri, Mar 19, 2021 at 12:56 AM Archie Pusaka <apusaka@google.com> wrote: > > > > From: Archie Pusaka <apusaka@chromium.org> > > > > 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@chromium.org> > > --- > > > > 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
diff --git a/src/adv_monitor.c b/src/adv_monitor.c index 33e7c8454d..131dc80039 100644 --- a/src/adv_monitor.c +++ b/src/adv_monitor.c @@ -89,14 +89,7 @@ enum monitor_state { MONITOR_STATE_RELEASED, /* Dbus Object removed by app */ }; -struct adv_monitor { - struct adv_monitor_app *app; - GDBusProxy *proxy; - char *path; - - enum monitor_state state; /* MONITOR_STATE_* */ - uint16_t monitor_handle; /* Kernel Monitor Handle */ - +struct rssi_parameters { int8_t high_rssi; /* High RSSI threshold */ uint16_t high_rssi_timeout; /* High RSSI threshold timeout */ int8_t low_rssi; /* Low RSSI threshold */ @@ -105,6 +98,17 @@ struct adv_monitor { * Currenly unimplemented in user space. * Used only to pass data to kernel. */ +}; + +struct adv_monitor { + struct adv_monitor_app *app; + GDBusProxy *proxy; + 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 queue *devices; /* List of adv_monitor_device objects */ enum monitor_type type; /* MONITOR_TYPE_* */ @@ -158,6 +162,24 @@ const struct adv_monitor_type { { }, }; +static void rssi_unset(struct rssi_parameters *rssi) +{ + rssi->high_rssi = ADV_MONITOR_UNSET_RSSI; + rssi->high_rssi_timeout = ADV_MONITOR_UNSET_TIMEOUT; + rssi->low_rssi = ADV_MONITOR_UNSET_RSSI; + rssi->low_rssi_timeout = ADV_MONITOR_UNSET_TIMEOUT; + rssi->sampling_period = ADV_MONITOR_UNSET_SAMPLING_PERIOD; +} + +static bool rssi_is_unset(const struct rssi_parameters *rssi) +{ + return rssi->high_rssi == ADV_MONITOR_UNSET_RSSI && + rssi->low_rssi == ADV_MONITOR_UNSET_RSSI && + rssi->high_rssi_timeout == ADV_MONITOR_UNSET_TIMEOUT && + rssi->low_rssi_timeout == ADV_MONITOR_UNSET_TIMEOUT && + rssi->sampling_period == ADV_MONITOR_UNSET_SAMPLING_PERIOD; +} + /* Replies to an app's D-Bus message and unref it */ static void app_reply_msg(struct adv_monitor_app *app, DBusMessage *reply) { @@ -369,11 +391,7 @@ static struct adv_monitor *monitor_new(struct adv_monitor_app *app, monitor->state = MONITOR_STATE_NEW; - monitor->high_rssi = ADV_MONITOR_UNSET_RSSI; - monitor->high_rssi_timeout = ADV_MONITOR_UNSET_TIMEOUT; - monitor->low_rssi = ADV_MONITOR_UNSET_RSSI; - monitor->low_rssi_timeout = ADV_MONITOR_UNSET_TIMEOUT; - monitor->sampling_period = ADV_MONITOR_UNSET_SAMPLING_PERIOD; + rssi_unset(&monitor->rssi); monitor->devices = queue_new(); monitor->type = MONITOR_TYPE_NONE; @@ -528,19 +546,19 @@ static bool parse_rssi_and_timeout(struct adv_monitor *monitor, if (sampling_period > ADV_MONITOR_MAX_SAMPLING_PERIOD) goto failed; - monitor->high_rssi = h_rssi; - monitor->low_rssi = l_rssi; - monitor->high_rssi_timeout = h_rssi_timeout; - monitor->low_rssi_timeout = l_rssi_timeout; - monitor->sampling_period = sampling_period; + monitor->rssi.high_rssi = h_rssi; + monitor->rssi.low_rssi = l_rssi; + monitor->rssi.high_rssi_timeout = h_rssi_timeout; + monitor->rssi.low_rssi_timeout = l_rssi_timeout; + monitor->rssi.sampling_period = sampling_period; done: DBG("Adv Monitor at %s initiated with high RSSI threshold %d, high " "RSSI threshold timeout %d, low RSSI threshold %d, low RSSI " "threshold timeout %d, sampling period %d", path, - monitor->high_rssi, monitor->high_rssi_timeout, - monitor->low_rssi, monitor->low_rssi_timeout, - monitor->sampling_period); + monitor->rssi.high_rssi, monitor->rssi.high_rssi_timeout, + monitor->rssi.low_rssi, monitor->rssi.low_rssi_timeout, + monitor->rssi.sampling_period); return true; @@ -700,15 +718,6 @@ static void add_adv_patterns_monitor_cb(uint8_t status, uint16_t length, DBG("Adv monitor with handle:0x%04x added", monitor->monitor_handle); } -static bool monitor_rssi_is_unset(struct adv_monitor *monitor) -{ - return monitor->high_rssi == ADV_MONITOR_UNSET_RSSI && - monitor->low_rssi == ADV_MONITOR_UNSET_RSSI && - monitor->high_rssi_timeout == ADV_MONITOR_UNSET_TIMEOUT && - monitor->low_rssi_timeout == ADV_MONITOR_UNSET_TIMEOUT && - monitor->sampling_period == ADV_MONITOR_UNSET_SAMPLING_PERIOD; -} - /* sends MGMT_OP_ADD_ADV_PATTERNS_MONITOR */ static bool monitor_send_add_pattern(struct adv_monitor *monitor) { @@ -758,12 +767,12 @@ static bool monitor_send_add_pattern_rssi(struct adv_monitor *monitor) if (!cp) return false; - cp->rssi.high_threshold = monitor->high_rssi; + cp->rssi.high_threshold = monitor->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->low_rssi; - cp->rssi.low_threshold_timeout = htobs(monitor->low_rssi_timeout); - cp->rssi.sampling_period = monitor->sampling_period; + 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; for (e = queue_get_entries(monitor->patterns); e; e = e->next) { struct bt_ad_pattern *pattern = e->data; @@ -822,7 +831,7 @@ static void monitor_proxy_added_cb(GDBusProxy *proxy, void *user_data) queue_push_tail(app->monitors, monitor); - if (monitor_rssi_is_unset(monitor)) + if (rssi_is_unset(&monitor->rssi)) monitor_send_add_pattern(monitor); else monitor_send_add_pattern_rssi(monitor); @@ -1486,7 +1495,7 @@ static bool handle_device_lost_timeout(gpointer user_data) * If not, report the Device Lost event. */ if (difftime(curr_time, dev->last_seen) >= - monitor->low_rssi_timeout) { + monitor->rssi.low_rssi_timeout) { dev->found = false; DBG("Calling DeviceLost() on Adv Monitor of owner %s " @@ -1513,7 +1522,7 @@ static void adv_monitor_filter_rssi(struct adv_monitor *monitor, * DeviceFound() event without tracking for the RSSI as the Adv has * already matched the pattern filter. */ - if (monitor_rssi_is_unset(monitor)) { + if (rssi_is_unset(&monitor->rssi)) { DBG("Calling DeviceFound() on Adv Monitor of owner %s " "at path %s", monitor->app->owner, monitor->path); @@ -1544,22 +1553,22 @@ static void adv_monitor_filter_rssi(struct adv_monitor *monitor, */ if (dev->last_seen) { if (difftime(curr_time, dev->last_seen) > - monitor->high_rssi_timeout) { + monitor->rssi.high_rssi_timeout) { dev->high_rssi_first_seen = 0; } if (difftime(curr_time, dev->last_seen) > - monitor->low_rssi_timeout) { + monitor->rssi.low_rssi_timeout) { dev->low_rssi_first_seen = 0; } } dev->last_seen = curr_time; /* Check for the found devices (if the device is not already found) */ - if (!dev->found && rssi > monitor->high_rssi) { + if (!dev->found && rssi > monitor->rssi.high_rssi) { if (dev->high_rssi_first_seen) { if (difftime(curr_time, dev->high_rssi_first_seen) >= - monitor->high_rssi_timeout) { + monitor->rssi.high_rssi_timeout) { dev->found = true; DBG("Calling DeviceFound() on Adv Monitor " @@ -1582,10 +1591,10 @@ static void adv_monitor_filter_rssi(struct adv_monitor *monitor, * it doesn't make any sense to report the Device Lost event if the * device is not found yet) */ - if (dev->found && rssi < monitor->low_rssi) { + if (dev->found && rssi < monitor->rssi.low_rssi) { if (dev->low_rssi_first_seen) { if (difftime(curr_time, dev->low_rssi_first_seen) >= - monitor->low_rssi_timeout) { + monitor->rssi.low_rssi_timeout) { dev->found = false; DBG("Calling DeviceLost() on Adv Monitor " @@ -1610,8 +1619,8 @@ static void adv_monitor_filter_rssi(struct adv_monitor *monitor, */ if (dev->found) { dev->lost_timer = - timeout_add_seconds(monitor->low_rssi_timeout, + timeout_add_seconds(monitor->rssi.low_rssi_timeout, handle_device_lost_timeout, dev, - NULL); + NULL); } }