Hi Luiz, On Thu, Oct 29, 2020 at 10:25 AM Luiz Augusto von Dentz <luiz.dentz@xxxxxxxxx> wrote: > > Hi Miao, > > On Thu, Oct 29, 2020 at 12:54 AM Miao-chen Chou <mcchou@xxxxxxxxxxxx> wrote: > > > > This implements create an entry point in adapter to start the matching of > > Adv based on all monitors and invoke the RSSI tracking for Adv reporting. > > > > Reviewed-by: Abhishek Pandit-Subedi <abhishekpandit@xxxxxxxxxxxx> > > Reviewed-by: Alain Michaud <alainm@xxxxxxxxxxxx> > > Reviewed-by: Manish Mandlik <mmandlik@xxxxxxxxxxxx> > > --- > > > > Changes in v7: > > - Replace the use of GSList with struct queue > > - Adopt bt_ad_pattern from shared/ad > > - Add error logs > > > > Changes in v6: > > - Fix the termination condition of AD data paring and remove unnecessary > > length check > > > > Changes in v5: > > - Remove unittest helper functions > > > > Changes in v3: > > - Remove unused variables > > - Fix signature of queue_find() > > > > src/adapter.c | 44 +++++++++++--- > > src/adv_monitor.c | 151 +++++++++++++++++++++++++++++++++++----------- > > src/adv_monitor.h | 14 +++++ > > 3 files changed, 167 insertions(+), 42 deletions(-) > > > > diff --git a/src/adapter.c b/src/adapter.c > > index 6d0114a6b..0e3fd57f3 100644 > > --- a/src/adapter.c > > +++ b/src/adapter.c > > @@ -6597,10 +6597,28 @@ static void update_found_devices(struct btd_adapter *adapter, > > const uint8_t *data, uint8_t data_len) > > { > > struct btd_device *dev; > > + struct bt_ad *ad = NULL; > > struct eir_data eir_data; > > bool name_known, discoverable; > > char addr[18]; > > bool duplicate = false; > > + struct queue *matched_monitors = NULL; > > + > > + if (bdaddr_type != BDADDR_BREDR) > > + ad = bt_ad_new_with_data(data_len, data); > > + > > + /* During the background scanning, update the device only when the data > > + * match at least one Adv monitor > > + */ > > + if (ad) { > > + matched_monitors = btd_adv_monitor_content_filter( > > + adapter->adv_monitor_manager, ad); > > + bt_ad_unref(ad); > > + ad = NULL; > > + } > > + > > + if (!adapter->discovering && !matched_monitors) > > + return; > > > > memset(&eir_data, 0, sizeof(eir_data)); > > eir_parse(&eir_data, data, data_len); > > @@ -6646,18 +6664,22 @@ static void update_found_devices(struct btd_adapter *adapter, > > device_store_cached_name(dev, eir_data.name); > > > > /* > > - * Only skip devices that are not connected, are temporary and there > > - * is no active discovery session ongoing. > > + * Only skip devices that are not connected, are temporary, and there > > + * is no active discovery session ongoing and no matched Adv monitors > > */ > > - if (!btd_device_is_connected(dev) && (device_is_temporary(dev) && > > - !adapter->discovery_list)) { > > + if (!btd_device_is_connected(dev) && > > + (device_is_temporary(dev) && !adapter->discovery_list) && > > + !matched_monitors) { > > eir_data_free(&eir_data); > > return; > > } > > > > - /* Don't continue if not discoverable or if filter don't match */ > > - if (!discoverable || (adapter->filtered_discovery && > > - !is_filter_match(adapter->discovery_list, &eir_data, rssi))) { > > + /* If there is no matched Adv monitors, don't continue if not > > + * discoverable or if active discovery filter don't match. > > + */ > > + if (!matched_monitors && (!discoverable || > > + (adapter->filtered_discovery && !is_filter_match( > > + adapter->discovery_list, &eir_data, rssi)))) { > > eir_data_free(&eir_data); > > return; > > } > > @@ -6714,6 +6736,14 @@ static void update_found_devices(struct btd_adapter *adapter, > > > > eir_data_free(&eir_data); > > > > + /* After the device is updated, notify the matched Adv monitors */ > > + if (matched_monitors) { > > + btd_adv_monitor_notify_monitors(adapter->adv_monitor_manager, > > + dev, rssi, matched_monitors); > > + queue_destroy(matched_monitors, NULL); > > + matched_monitors = NULL; > > + } > > + > > /* > > * Only if at least one client has requested discovery, maintain > > * list of found devices and name confirming for legacy devices. > > diff --git a/src/adv_monitor.c b/src/adv_monitor.c > > index 74351d91e..9a04da6e1 100644 > > --- a/src/adv_monitor.c > > +++ b/src/adv_monitor.c > > @@ -29,15 +29,12 @@ > > #include "device.h" > > #include "log.h" > > #include "src/error.h" > > -#include "src/shared/ad.h" > > #include "src/shared/mgmt.h" > > #include "src/shared/queue.h" > > #include "src/shared/util.h" > > > > #include "adv_monitor.h" > > > > -static void monitor_device_free(void *data); > > - > > #define ADV_MONITOR_INTERFACE "org.bluez.AdvertisementMonitor1" > > #define ADV_MONITOR_MGR_INTERFACE "org.bluez.AdvertisementMonitorManager1" > > > > @@ -84,13 +81,6 @@ enum monitor_state { > > MONITOR_STATE_HONORED, /* Accepted by kernel */ > > }; > > > > -struct pattern { > > - uint8_t ad_type; > > - uint8_t offset; > > - uint8_t length; > > - uint8_t value[BT_AD_MAX_DATA_LEN]; > > -}; > > - > > struct adv_monitor { > > struct adv_monitor_app *app; > > GDBusProxy *proxy; > > @@ -105,7 +95,7 @@ struct adv_monitor { > > struct queue *devices; /* List of adv_monitor_device objects */ > > > > enum monitor_type type; /* MONITOR_TYPE_* */ > > - struct queue *patterns; > > + struct queue *patterns; /* List of bt_ad_pattern objects */ > > }; > > > > /* Some data like last_seen, timer/timeout values need to be maintained > > @@ -133,6 +123,20 @@ struct app_match_data { > > const char *path; > > }; > > > > +struct adv_content_filter_info { > > + struct bt_ad *ad; > > + struct queue *matched_monitors; /* List of matched monitors */ > > +}; > > + > > +struct adv_rssi_filter_info { > > + struct btd_device *device; > > + int8_t rssi; > > +}; > > + > > +static void monitor_device_free(void *data); > > +static void adv_monitor_filter_rssi(struct adv_monitor *monitor, > > + struct btd_device *device, int8_t rssi); > > + > > const struct adv_monitor_type { > > enum monitor_type type; > > const char *name; > > @@ -155,10 +159,7 @@ static void app_reply_msg(struct adv_monitor_app *app, DBusMessage *reply) > > /* Frees a pattern */ > > static void pattern_free(void *data) > > { > > - struct pattern *pattern = data; > > - > > - if (!pattern) > > - return; > > + struct bt_ad_pattern *pattern = data; > > > > free(pattern); > > } > > @@ -464,7 +465,7 @@ static bool parse_patterns(struct adv_monitor *monitor, const char *path) > > int value_len; > > uint8_t *value; > > uint8_t offset, ad_type; > > - struct pattern *pattern; > > + struct bt_ad_pattern *pattern; > > DBusMessageIter struct_iter, value_iter; > > > > dbus_message_iter_recurse(&array_iter, &struct_iter); > > @@ -496,28 +497,10 @@ static bool parse_patterns(struct adv_monitor *monitor, const char *path) > > dbus_message_iter_get_fixed_array(&value_iter, &value, > > &value_len); > > > > - // Verify the values > > - if (offset > BT_AD_MAX_DATA_LEN - 1) > > - goto failed; > > - > > - if ((ad_type > BT_AD_3D_INFO_DATA && > > - ad_type != BT_AD_MANUFACTURER_DATA) || > > - ad_type < BT_AD_FLAGS) { > > - goto failed; > > - } > > - > > - if (!value || value_len <= 0 || value_len > BT_AD_MAX_DATA_LEN) > > - goto failed; > > - > > - pattern = new0(struct pattern, 1); > > + pattern = bt_ad_pattern_new(ad_type, offset, value_len, value); > > if (!pattern) > > goto failed; > > > > - pattern->ad_type = ad_type; > > - pattern->offset = offset; > > - pattern->length = value_len; > > - memcpy(pattern->value, value, pattern->length); > > - > > queue_push_tail(monitor->patterns, pattern); > > > > dbus_message_iter_next(&array_iter); > > @@ -952,6 +935,104 @@ void btd_adv_monitor_manager_destroy(struct btd_adv_monitor_manager *manager) > > manager_destroy(manager); > > } > > > > +/* Processes the content matching based pattern(s) of a monitor */ > > +static void adv_match_per_monitor(void *data, void *user_data) > > +{ > > + struct adv_monitor *monitor = data; > > + struct adv_content_filter_info *info = user_data; > > + > > + if (!monitor) { > > + error("Unexpected NULL adv_monitor object upon match"); > > + return; > > + } > > + > > + if (monitor->state != MONITOR_STATE_HONORED) > > + return; > > + > > + if (monitor->type == MONITOR_TYPE_OR_PATTERNS && > > + bt_ad_pattern_match(info->ad, monitor->patterns)) { > > + goto matched; > > + } > > + > > + return; > > + > > +matched: > > + if (!info->matched_monitors) > > + info->matched_monitors = queue_new(); > > + > > + queue_push_tail(info->matched_monitors, monitor); > > +} > > + > > +/* Processes the content matching for the monitor(s) of an app */ > > +static void adv_match_per_app(void *data, void *user_data) > > +{ > > + struct adv_monitor_app *app = data; > > + > > + if (!app) { > > + error("Unexpected NULL adv_monitor_app object upon match"); > > + return; > > + } > > + > > + queue_foreach(app->monitors, adv_match_per_monitor, user_data); > > +} > > + > > +/* Processes the content matching for every app without RSSI filtering and > > + * notifying monitors. The caller is responsible of releasing the memory of the > > + * list but not the ad data. > > + * Returns the list of monitors whose content match the ad data. > > + */ > > +struct queue *btd_adv_monitor_content_filter( > > + struct btd_adv_monitor_manager *manager, > > + struct bt_ad *ad) > > +{ > > + struct adv_content_filter_info info; > > + > > + if (!manager || !ad) > > + return NULL; > > + > > + info.ad = ad; > > + info.matched_monitors = NULL; > > + > > + queue_foreach(manager->apps, adv_match_per_app, &info); > > + > > + return info.matched_monitors; > > +} > > + > > +/* Wraps adv_monitor_filter_rssi() to processes the content-matched monitor with > > + * RSSI filtering and notifies it on device found/lost event > > + */ > > +static void monitor_filter_rssi(void *data, void *user_data) > > +{ > > + struct adv_monitor *monitor = data; > > + struct adv_rssi_filter_info *info = user_data; > > + > > + if (!monitor || !info) > > + return; > > + > > + adv_monitor_filter_rssi(monitor, info->device, info->rssi); > > +} > > + > > +/* Processes every content-matched monitor with RSSI filtering and notifies on > > + * device found/lost event. The caller is responsible of releasing the memory > > + * of matched_monitors list but not its data. > > + */ > > +void btd_adv_monitor_notify_monitors(struct btd_adv_monitor_manager *manager, > > + struct btd_device *device, int8_t rssi, > > + struct queue *matched_monitors) > > +{ > > + struct adv_rssi_filter_info info; > > + > > + if (!manager || !device || !matched_monitors || > > + queue_isempty(matched_monitors)) { > > + return; > > + } > > + > > + info.device = device; > > + info.rssi = rssi; > > + > > + queue_foreach(matched_monitors, monitor_filter_rssi, &info); > > +} > > + > > /* Matches a device based on btd_device object */ > > static bool monitor_device_match(const void *a, const void *b) > > { > > diff --git a/src/adv_monitor.h b/src/adv_monitor.h > > index 13d5d7282..2b4f68abf 100644 > > --- a/src/adv_monitor.h > > +++ b/src/adv_monitor.h > > @@ -11,16 +11,30 @@ > > #ifndef __ADV_MONITOR_H > > #define __ADV_MONITOR_H > > > > +#include <glib.h> > > + > > +#include "src/shared/ad.h" > > + > > struct mgmt; > > +struct queue; > > struct btd_device; > > struct btd_adapter; > > struct btd_adv_monitor_manager; > > +struct btd_adv_monitor_pattern; > > > > struct btd_adv_monitor_manager *btd_adv_monitor_manager_create( > > struct btd_adapter *adapter, > > struct mgmt *mgmt); > > void btd_adv_monitor_manager_destroy(struct btd_adv_monitor_manager *manager); > > > > +struct queue *btd_adv_monitor_content_filter( > > + struct btd_adv_monitor_manager *manager, > > + struct bt_ad *ad); > > + > > +void btd_adv_monitor_notify_monitors(struct btd_adv_monitor_manager *manager, > > + struct btd_device *device, int8_t rssi, > > + struct queue *matched_monitors); > > + > > void btd_adv_monitor_device_remove(struct btd_adv_monitor_manager *manager, > > struct btd_device *device); > > > > -- > > 2.26.2 > > If I compile patch by patch this one fails: > > [detached HEAD 5a221084c] adv_monitor: Implement Adv matching based on > stored monitors > Author: Miao-chen Chou <mcchou@xxxxxxxxxxxx> > Date: Wed Oct 28 16:05:30 2020 -0700 > 3 files changed, 167 insertions(+), 42 deletions(-) > Executing: make -j12 > make --no-print-directory all-am > CC src/bluetoothd-adapter.o > CC src/bluetoothd-adv_monitor.o > src/adv_monitor.c:137:13: error: ‘adv_monitor_filter_rssi’ used but > never defined [-Werror] > 137 | static void adv_monitor_filter_rssi(struct adv_monitor *monitor, > | ^~~~~~~~~~~~~~~~~~~~~~~ > cc1: all warnings being treated as errors > > You might want to move these functions to the patch they start use > them so we don't break bisect, you can test them with something like: > > git rebase -i origin/master --exec=make > > @An, Tedd We should probably update the CI to do something like the > above so it can detect when a set would introduce a patch that doesn't > build. > Since the RSSI filtering patch introduces some functions that will be used by the following patch, so I merge this commit with the other one where it is used in v8. > -- > Luiz Augusto von Dentz Thanks, Miao