From patchwork Thu Sep 17 06:19:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miao-chen Chou X-Patchwork-Id: 11781617 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 232C9139A for ; Thu, 17 Sep 2020 06:20:00 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E82C621973 for ; Thu, 17 Sep 2020 06:19:59 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="NaH8GR0w" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726180AbgIQGT7 (ORCPT ); Thu, 17 Sep 2020 02:19:59 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39282 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725267AbgIQGT6 (ORCPT ); Thu, 17 Sep 2020 02:19:58 -0400 Received: from mail-pg1-x544.google.com (mail-pg1-x544.google.com [IPv6:2607:f8b0:4864:20::544]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 523C4C06174A for ; Wed, 16 Sep 2020 23:19:56 -0700 (PDT) Received: by mail-pg1-x544.google.com with SMTP id y1so744195pgk.8 for ; Wed, 16 Sep 2020 23:19:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=/MBaGN18T5ClGzqvtrP9gRU0RypRFw+AxswImwVO7R4=; b=NaH8GR0wDG3D3HrHL+vUvMsnyBy+z1TdX7i5S0IeDebsOfhFfuOqo/BEmgQZG11jGm lcqoYEg0OHHx/VpH9Y5NMspkmh/dnemH24v64KPQVz6Fu7yets8jdX4kFH6YFYekG5T5 7oKIu8+FOpto/Brp5VkbPpElIPxcSPmqNvNgA= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=/MBaGN18T5ClGzqvtrP9gRU0RypRFw+AxswImwVO7R4=; b=CqXISSk6nus6FxX5aS2++kfh2uctfRNCXdmUYeng3/woh05jL0OVseuAVMD03ZAUqu klSH0OUnGxZfv8W78E9XjVSUUJl/aImVCf0rXqMUPPxASKtx9gW1Gf24g8xpFWOlYmyS Vhctim+4VNoKbvd2o0lC3cQaP+2EipHmqwUMwX3lVvtAo7hGmtYivj3o41tySjMPLI5w B4+OC0qm3jVzNztMEnTCKI2LIS+LNNJHtq2+dFjuKn40ToqHMbQeNJCEsoq82ZO0xmk0 9qd+iJFYyzZbZGYPEYO2D6yqDUAhDRhQj0GifFmwMmbtdtxnUfIeweUkbKQH1OyNjyUJ Junw== X-Gm-Message-State: AOAM532I6GY6YXXWsXr7NnMiWyD1QjR2eXKeatBzqqrqbo1GI2GOt7vZ NfnQJJ5QtkZikCm/omRveJBQ+t1z40hmsg== X-Google-Smtp-Source: ABdhPJzh4sqfwnEU9/q5izXWTdDybFXILcU/4n9EDD3ZTYe30RB1jaNHxLeRIpaIYGZYscxBEMGEkQ== X-Received: by 2002:a63:cc16:: with SMTP id x22mr20640481pgf.414.1600323595235; Wed, 16 Sep 2020 23:19:55 -0700 (PDT) Received: from mcchou0.mtv.corp.google.com ([2620:15c:202:201:de4a:3eff:fe75:1314]) by smtp.gmail.com with ESMTPSA id g23sm19264943pfh.133.2020.09.16.23.19.53 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 16 Sep 2020 23:19:54 -0700 (PDT) From: Miao-chen Chou To: Bluetooth Kernel Mailing List Cc: Marcel Holtmann , Howard Chung , Manish Mandlik , Alain Michaud , chromeos-bluetooth-upstreaming@chromium.org, Luiz Augusto von Dentz , Manish Mandlik , Abhishek Pandit-Subedi , Miao-chen Chou Subject: [BlueZ PATCH v2 1/8] adv_monitor: Implement RSSI Filter logic for background scanning Date: Wed, 16 Sep 2020 23:19:40 -0700 Message-Id: <20200916231935.BlueZ.v2.1.I2830b9c1212a64b062201ed9f2b71294f50ad22d@changeid> X-Mailer: git-send-email 2.26.2 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Manish Mandlik This patch implements the RSSI Filter logic for background scanning. This was unit-tested by running tests in unit/test-adv-monitor.c unit/test-adv-monitor.c file. Verified all tests PASS by running: USE="-bluez-next bluez-upstream" FEATURES=test emerge-hatch bluez Reviewed-by: Abhishek Pandit-Subedi Reviewed-by: Alain Michaud Reviewed-by: Miao-chen Chou Reviewed-by: Howard Chung --- (no changes since v1) doc/advertisement-monitor-api.txt | 5 + src/adapter.c | 1 + src/adv_monitor.c | 286 +++++++++++++++++++++++++++++- src/adv_monitor.h | 4 + 4 files changed, 292 insertions(+), 4 deletions(-) diff --git a/doc/advertisement-monitor-api.txt b/doc/advertisement-monitor-api.txt index e09b6fd25..92c8ffc38 100644 --- a/doc/advertisement-monitor-api.txt +++ b/doc/advertisement-monitor-api.txt @@ -70,6 +70,11 @@ Properties string Type [read-only] dBm indicates unset. The valid range of a timer is 1 to 300 seconds while 0 indicates unset. + If the peer device advertising interval is greater than the + HighRSSIThresholdTimer, the device will never be found. Similarly, + if it is greater than LowRSSIThresholdTimer, the device will be + considered as lost. Consider configuring these values accordingly. + array{(uint8, uint8, array{byte})} Patterns [read-only, optional] If Type is set to 0x01, this must exist and has at least diff --git a/src/adapter.c b/src/adapter.c index b2bd8b3f1..415d6e06b 100644 --- a/src/adapter.c +++ b/src/adapter.c @@ -1227,6 +1227,7 @@ void btd_adapter_remove_device(struct btd_adapter *adapter, adapter->connect_list = g_slist_remove(adapter->connect_list, dev); adapter->devices = g_slist_remove(adapter->devices, dev); + btd_adv_monitor_device_remove(adapter->adv_monitor_manager, dev); adapter->discovery_found = g_slist_remove(adapter->discovery_found, dev); diff --git a/src/adv_monitor.c b/src/adv_monitor.c index 737da1c90..7baa5317f 100644 --- a/src/adv_monitor.c +++ b/src/adv_monitor.c @@ -35,6 +35,7 @@ #include "adapter.h" #include "dbus-common.h" +#include "device.h" #include "log.h" #include "src/error.h" #include "src/shared/ad.h" @@ -44,6 +45,8 @@ #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" @@ -104,15 +107,36 @@ struct adv_monitor { enum monitor_state state; /* MONITOR_STATE_* */ - int8_t high_rssi; /* high RSSI threshold */ - uint16_t high_rssi_timeout; /* high RSSI threshold timeout */ - int8_t low_rssi; /* low RSSI threshold */ - uint16_t low_rssi_timeout; /* low RSSI threshold timeout */ + int8_t high_rssi; /* High RSSI threshold */ + uint16_t high_rssi_timeout; /* High RSSI threshold timeout */ + int8_t low_rssi; /* Low RSSI threshold */ + uint16_t low_rssi_timeout; /* Low RSSI threshold timeout */ + struct queue *devices; /* List of adv_monitor_device objects */ enum monitor_type type; /* MONITOR_TYPE_* */ struct queue *patterns; }; +/* Some data like last_seen, timer/timeout values need to be maintained + * per device. struct adv_monitor_device maintains such data. + */ +struct adv_monitor_device { + struct adv_monitor *monitor; + struct btd_device *device; + + time_t high_rssi_first_seen; /* Start time when RSSI climbs above + * the high RSSI threshold + */ + time_t low_rssi_first_seen; /* Start time when RSSI drops below + * the low RSSI threshold + */ + time_t last_seen; /* Time when last Adv was received */ + bool device_found; /* State of the device - lost/found */ + guint device_lost_timer; /* Timer to track if the device goes + * offline/out-of-range + */ +}; + struct app_match_data { const char *owner; const char *path; @@ -159,6 +183,9 @@ static void monitor_free(void *data) g_dbus_proxy_unref(monitor->proxy); g_free(monitor->path); + queue_destroy(monitor->devices, monitor_device_free); + monitor->devices = NULL; + queue_destroy(monitor->patterns, pattern_free); free(monitor); @@ -257,6 +284,7 @@ static struct adv_monitor *monitor_new(struct adv_monitor_app *app, monitor->high_rssi_timeout = ADV_MONITOR_UNSET_TIMER; monitor->low_rssi = ADV_MONITOR_UNSET_RSSI; monitor->low_rssi_timeout = ADV_MONITOR_UNSET_TIMER; + monitor->devices = queue_new(); monitor->type = MONITOR_TYPE_NONE; monitor->patterns = NULL; @@ -932,3 +960,253 @@ void btd_adv_monitor_manager_destroy(struct btd_adv_monitor_manager *manager) manager_destroy(manager); } + +/* Matches a device based on btd_device object */ +static bool monitor_device_match(const void *a, const void *b) +{ + const struct adv_monitor_device *dev = a; + const struct btd_device *device = b; + + if (!dev) + return false; + + if (dev->device != device) + return false; + + return true; +} + +/* Frees a monitor device object */ +static void monitor_device_free(void *data) +{ + struct adv_monitor_device *dev = data; + + if (!dev) + return; + + if (dev->device_lost_timer) { + g_source_remove(dev->device_lost_timer); + dev->device_lost_timer = 0; + } + + dev->monitor = NULL; + dev->device = NULL; + + g_free(dev); +} + +/* Removes a device from monitor->devices list */ +static void remove_device_from_monitor(void *data, void *user_data) +{ + struct adv_monitor *monitor = data; + struct btd_device *device = user_data; + struct adv_monitor_device *dev = NULL; + + if (!monitor) + return; + + dev = queue_remove_if(monitor->devices, monitor_device_match, device); + if (dev) { + DBG("Device removed from the Adv Monitor at path %s", + monitor->path); + monitor_device_free(dev); + } +} + +/* Removes a device from every monitor in an app */ +static void remove_device_from_app(void *data, void *user_data) +{ + struct adv_monitor_app *app = data; + struct btd_device *device = user_data; + + if (!app) + return; + + queue_foreach(app->monitors, remove_device_from_monitor, device); +} + +/* Removes a device from every monitor in all apps */ +void btd_adv_monitor_device_remove(struct btd_adv_monitor_manager *manager, + struct btd_device *device) +{ + if (!manager || !device) + return; + + queue_foreach(manager->apps, remove_device_from_app, device); +} + +/* Creates a device object to track the per-device information */ +static struct adv_monitor_device *monitor_device_create( + struct adv_monitor *monitor, + struct btd_device *device) +{ + struct adv_monitor_device *dev = NULL; + + dev = g_try_malloc0(sizeof(struct adv_monitor_device)); + if (!dev) + return NULL; + + dev->monitor = monitor; + dev->device = device; + + queue_push_tail(monitor->devices, dev); + + return dev; +} + +/* Includes found/lost device's object path into the dbus message */ +static void report_device_state_setup(DBusMessageIter *iter, void *user_data) +{ + const char *path = device_get_path(user_data); + + dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path); +} + +/* Handles a situation where the device goes offline/out-of-range */ +static gboolean handle_device_lost_timeout(gpointer user_data) +{ + struct adv_monitor_device *dev = user_data; + struct adv_monitor *monitor = dev->monitor; + time_t curr_time = time(NULL); + + DBG("Device Lost timeout triggered for device %p " + "for the Adv Monitor at path %s", dev->device, monitor->path); + + dev->device_lost_timer = 0; + + if (dev->device_found && dev->last_seen) { + /* We were tracking for the Low RSSI filter. Check if there is + * any Adv received after the timeout function is invoked. + * If not, report the Device Lost event. + */ + if (difftime(curr_time, dev->last_seen) >= + monitor->low_rssi_timeout) { + dev->device_found = false; + + DBG("Calling DeviceLost() on Adv Monitor of owner %s " + "at path %s", monitor->app->owner, monitor->path); + + g_dbus_proxy_method_call(monitor->proxy, "DeviceLost", + report_device_state_setup, + NULL, dev->device, NULL); + } + } + + return FALSE; +} + +/* Filters an Adv based on its RSSI value */ +static void adv_monitor_filter_rssi(struct adv_monitor *monitor, + struct btd_device *device, int8_t rssi) +{ + struct adv_monitor_device *dev = NULL; + time_t curr_time = time(NULL); + uint16_t adapter_id = monitor->app->manager->adapter_id; + + /* If the RSSI thresholds and timeouts are not specified, report the + * DeviceFound() event without tracking for the RSSI as the Adv has + * already matched the pattern filter. + */ + if (monitor->high_rssi == ADV_MONITOR_UNSET_RSSI && + monitor->low_rssi == ADV_MONITOR_UNSET_RSSI && + monitor->high_rssi_timeout == ADV_MONITOR_UNSET_TIMER && + monitor->low_rssi_timeout == ADV_MONITOR_UNSET_TIMER) { + DBG("Calling DeviceFound() on Adv Monitor of owner %s " + "at path %s", monitor->app->owner, monitor->path); + + g_dbus_proxy_method_call(monitor->proxy, "DeviceFound", + report_device_state_setup, NULL, + device, NULL); + + return; + } + + dev = queue_find(monitor->devices, monitor_device_match, device); + if (!dev) + dev = monitor_device_create(monitor, device); + if (!dev) { + btd_error(adapter_id, "Failed to create Adv Monitor " + "device object."); + return; + } + + if (dev->device_lost_timer) { + g_source_remove(dev->device_lost_timer); + dev->device_lost_timer = 0; + } + + /* Reset the timings of found/lost if a device has been offline for + * longer than the high/low timeouts. + */ + if (dev->last_seen) { + if (difftime(curr_time, dev->last_seen) > + monitor->high_rssi_timeout) { + dev->high_rssi_first_seen = 0; + } + + if (difftime(curr_time, dev->last_seen) > + monitor->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->device_found && rssi > monitor->high_rssi) { + if (dev->high_rssi_first_seen) { + if (difftime(curr_time, dev->high_rssi_first_seen) >= + monitor->high_rssi_timeout) { + dev->device_found = true; + + DBG("Calling DeviceFound() on Adv Monitor " + "of owner %s at path %s", + monitor->app->owner, monitor->path); + + g_dbus_proxy_method_call( + monitor->proxy, "DeviceFound", + report_device_state_setup, NULL, + dev->device, NULL); + } + } else { + dev->high_rssi_first_seen = curr_time; + } + } else { + dev->high_rssi_first_seen = 0; + } + + /* Check for the lost devices (only if the device is already found, as + * it doesn't make any sense to report the Device Lost event if the + * device is not found yet) + */ + if (dev->device_found && rssi < monitor->low_rssi) { + if (dev->low_rssi_first_seen) { + if (difftime(curr_time, dev->low_rssi_first_seen) >= + monitor->low_rssi_timeout) { + dev->device_found = false; + + DBG("Calling DeviceLost() on Adv Monitor " + "of owner %s at path %s", + monitor->app->owner, monitor->path); + + g_dbus_proxy_method_call( + monitor->proxy, "DeviceLost", + report_device_state_setup, NULL, + dev->device, NULL); + } + } else { + dev->low_rssi_first_seen = curr_time; + } + } else { + dev->low_rssi_first_seen = 0; + } + + /* Setup a timer to track if the device goes offline/out-of-range, only + * if we are tracking for the Low RSSI Threshold. If we are tracking + * the High RSSI Threshold, nothing needs to be done. + */ + if (dev->device_found) { + dev->device_lost_timer = + g_timeout_add_seconds(monitor->low_rssi_timeout, + handle_device_lost_timeout, dev); + } +} diff --git a/src/adv_monitor.h b/src/adv_monitor.h index 69ea348f8..14508e7d1 100644 --- a/src/adv_monitor.h +++ b/src/adv_monitor.h @@ -21,6 +21,7 @@ #define __ADV_MONITOR_H struct mgmt; +struct btd_device; struct btd_adapter; struct btd_adv_monitor_manager; @@ -29,4 +30,7 @@ struct btd_adv_monitor_manager *btd_adv_monitor_manager_create( struct mgmt *mgmt); void btd_adv_monitor_manager_destroy(struct btd_adv_monitor_manager *manager); +void btd_adv_monitor_device_remove(struct btd_adv_monitor_manager *manager, + struct btd_device *device); + #endif /* __ADV_MONITOR_H */ From patchwork Thu Sep 17 06:19:42 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miao-chen Chou X-Patchwork-Id: 11781621 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1A6E4139A for ; Thu, 17 Sep 2020 06:20:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E810C2137B for ; Thu, 17 Sep 2020 06:20:24 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="VI9UCeV5" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726186AbgIQGUS (ORCPT ); Thu, 17 Sep 2020 02:20:18 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39328 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725267AbgIQGUN (ORCPT ); Thu, 17 Sep 2020 02:20:13 -0400 Received: from mail-pf1-x441.google.com (mail-pf1-x441.google.com [IPv6:2607:f8b0:4864:20::441]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2957AC06174A for ; Wed, 16 Sep 2020 23:20:13 -0700 (PDT) Received: by mail-pf1-x441.google.com with SMTP id b124so539923pfg.13 for ; Wed, 16 Sep 2020 23:20:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=nWCXeK0FF/wh1L2v7xLpjjVFTYNjs8T1eeTnGvJ0r0Y=; b=VI9UCeV5wv8kTZmbw5xvdhwmJxqQa85YUscisadfKkzadXutrHdV2ZmkXFhyHh4e30 Ze1oWLgQzLkK4Se8YF+kZM0ApZLeOTjfUsJaDU/eA3deFtsWok0QmZ0QTRy5jZF6pej8 zarrLwTXxHyc/aRKRwr6YN7mEvrM5BPSE8e8A= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=nWCXeK0FF/wh1L2v7xLpjjVFTYNjs8T1eeTnGvJ0r0Y=; b=cbx3SEaN4qAhKp+FUrE8dvv7t8OXM3ku6ImAKVP9gXXXfDxhL+D15XB1PoLDU/HHCI BkwnMc7/JghLQqhHRyjgcTkuM+st3e4jQpXdnJ79prPC/kZW6nSLZqRMoYZf2lSGFgcV nKgzAtphfP4RsgqiHaHMFtgTb4SOEBthDiQnDSsOrYR1kDZRBsXvlKuSrw5uAPqbpHBX L9NFyvmMKsAIKvsINS+1shMvwimEw6tHbqNx1iWgl/S5nqly/OOEK4R24n7PbhzFaIFi ssdBaV0Vx5p0g5ayMjrBJLoMsJvAVdjYvI0coMx9roTYiXYJxBt37U6YM81f4jynUU6s n64Q== X-Gm-Message-State: AOAM533blBX7diVstZVPqoFIO89zt7Tk9fJDDBo8tnpCAoAorbis6pQ1 xPNJHsxhaxV/JhNx6m4xkPpvuB7h28rhOg== X-Google-Smtp-Source: ABdhPJzMKQpcxTlAD7FYp3sZv5iwT3Oof/zEU52BQJGOSCdCGRHIl0umSae6uNZOXyvRixiuhNYSYQ== X-Received: by 2002:a62:7a14:0:b029:13e:d13d:a0f5 with SMTP id v20-20020a627a140000b029013ed13da0f5mr25009487pfc.17.1600323612085; Wed, 16 Sep 2020 23:20:12 -0700 (PDT) Received: from mcchou0.mtv.corp.google.com ([2620:15c:202:201:de4a:3eff:fe75:1314]) by smtp.gmail.com with ESMTPSA id g23sm19264943pfh.133.2020.09.16.23.20.10 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 16 Sep 2020 23:20:11 -0700 (PDT) From: Miao-chen Chou To: Bluetooth Kernel Mailing List Cc: Marcel Holtmann , Howard Chung , Manish Mandlik , Alain Michaud , chromeos-bluetooth-upstreaming@chromium.org, Luiz Augusto von Dentz , Manish Mandlik , Miao-chen Chou Subject: [BlueZ PATCH v2 2/8] adv_monitor: Implement unit tests for RSSI Filter Date: Wed, 16 Sep 2020 23:19:42 -0700 Message-Id: <20200916231935.BlueZ.v2.2.I5ae05701b2b792a3ea2ca98f4a5d977645b1afc2@changeid> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200916231935.BlueZ.v2.1.I2830b9c1212a64b062201ed9f2b71294f50ad22d@changeid> References: <20200916231935.BlueZ.v2.1.I2830b9c1212a64b062201ed9f2b71294f50ad22d@changeid> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Manish Mandlik This patch implements unit tests for the background scanning RSSI Filtering logic. Verified all tests PASS by running tests in unit/test-adv-monitor.c USE="-bluez-next bluez-upstream" FEATURES=test emerge-hatch bluez Reviewed-by: Alain Michaud Reviewed-by: Miao-chen Chou --- Changes in v2: - Cast test data to void * Makefile.am | 9 + doc/test-coverage.txt | 3 +- src/adv_monitor.c | 79 ++++++++ src/adv_monitor.h | 10 + unit/test-adv-monitor.c | 391 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 491 insertions(+), 1 deletion(-) create mode 100644 unit/test-adv-monitor.c diff --git a/Makefile.am b/Makefile.am index 22b4fa30c..6918f02b0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -527,6 +527,15 @@ unit_test_gattrib_LDADD = lib/libbluetooth-internal.la \ src/libshared-glib.la \ $(GLIB_LIBS) $(DBUS_LIBS) -ldl -lrt +unit_tests += unit/test-adv-monitor + +unit_test_adv_monitor_SOURCES = unit/test-adv-monitor.c \ + src/adv_monitor.h src/adv_monitor.c \ + src/device.h src/device.c \ + src/log.h src/log.c +unit_test_adv_monitor_LDADD = gdbus/libgdbus-internal.la \ + src/libshared-glib.la $(GLIB_LIBS) $(DBUS_LIBS) + if MIDI unit_tests += unit/test-midi unit_test_midi_CPPFLAGS = $(AM_CPPFLAGS) $(ALSA_CFLAGS) -DMIDI_TEST diff --git a/doc/test-coverage.txt b/doc/test-coverage.txt index 741492a3e..5296983e6 100644 --- a/doc/test-coverage.txt +++ b/doc/test-coverage.txt @@ -30,8 +30,9 @@ test-gobex-transfer 36 OBEX transfer handling test-gdbus-client 13 D-Bus client handling test-gatt 180 GATT qualification test cases test-hog 6 HID Over GATT qualification test cases +test-adv-monitor 5 Advertisement Monitor test cases ----- - 761 + 766 Automated end-to-end testing diff --git a/src/adv_monitor.c b/src/adv_monitor.c index 7baa5317f..046f5953f 100644 --- a/src/adv_monitor.c +++ b/src/adv_monitor.c @@ -1210,3 +1210,82 @@ static void adv_monitor_filter_rssi(struct adv_monitor *monitor, handle_device_lost_timeout, dev); } } + +/* Creates the dummy adv_monitor object for unit tests */ +void *btd_adv_monitor_rssi_test_setup(int8_t high_rssi, uint16_t high_timeout, + int8_t low_rssi, uint16_t low_timeout) +{ + struct adv_monitor *test_monitor = NULL; + + test_monitor = g_new0(struct adv_monitor, 1); + if (!test_monitor) + return NULL; + + test_monitor->app = g_new0(struct adv_monitor_app, 1); + if (!test_monitor->app) + goto app_failed; + + test_monitor->app->manager = g_new0(struct btd_adv_monitor_manager, 1); + if (!test_monitor->app->manager) + goto manager_failed; + + test_monitor->high_rssi = high_rssi; + test_monitor->high_rssi_timeout = high_timeout; + test_monitor->low_rssi = low_rssi; + test_monitor->low_rssi_timeout = low_timeout; + test_monitor->devices = queue_new(); + + return test_monitor; + +manager_failed: + g_free(test_monitor->app); + +app_failed: + g_free(test_monitor); + + return NULL; +} + +/* Cleanup after unit test is done */ +void btd_adv_monitor_rssi_test_teardown(void *monitor_obj) +{ + struct adv_monitor *monitor = monitor_obj; + + if (!monitor) + return; + + queue_destroy(monitor->devices, monitor_device_free); + g_free(monitor); +} + +/* Returns the current state of device - found/lost, used in unit tests */ +bool btd_adv_monitor_test_device_state(void *monitor_obj, void *device_obj) +{ + struct adv_monitor *monitor = monitor_obj; + struct btd_device *device = device_obj; + struct adv_monitor_device *dev = NULL; + + if (!monitor || !device) + return false; + + dev = queue_find(monitor->devices, monitor_device_match, device); + if (!dev) + return false; + + return dev->device_found; +} + +/* Helper function for the RSSI Filter unit tests */ +bool btd_adv_monitor_test_rssi(void *monitor_obj, void *device_obj, + int8_t adv_rssi) +{ + struct adv_monitor *monitor = monitor_obj; + struct btd_device *device = device_obj; + + if (!monitor || !device) + return false; + + adv_monitor_filter_rssi(monitor, device, adv_rssi); + + return btd_adv_monitor_test_device_state(monitor, device); +} diff --git a/src/adv_monitor.h b/src/adv_monitor.h index 14508e7d1..351e7f9aa 100644 --- a/src/adv_monitor.h +++ b/src/adv_monitor.h @@ -33,4 +33,14 @@ void btd_adv_monitor_manager_destroy(struct btd_adv_monitor_manager *manager); void btd_adv_monitor_device_remove(struct btd_adv_monitor_manager *manager, struct btd_device *device); +/* Following functions are the helper functions used for RSSI Filter unit tests + * defined in unit/test-adv-monitor.c + */ +void *btd_adv_monitor_rssi_test_setup(int8_t high_rssi, uint16_t high_timeout, + int8_t low_rssi, uint16_t low_timeout); +void btd_adv_monitor_rssi_test_teardown(void *monitor_obj); +bool btd_adv_monitor_test_device_state(void *monitor_obj, void *device_obj); +bool btd_adv_monitor_test_rssi(void *monitor_obj, void *device_obj, + int8_t adv_rssi); + #endif /* __ADV_MONITOR_H */ diff --git a/unit/test-adv-monitor.c b/unit/test-adv-monitor.c new file mode 100644 index 000000000..970be84b0 --- /dev/null +++ b/unit/test-adv-monitor.c @@ -0,0 +1,391 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2020 Google LLC + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#define _GNU_SOURCE +#include +#include +#include +#include + +#include "src/log.h" +#include "src/shared/tester.h" + +#include "src/adv_monitor.h" + +#define define_test(name, type, data, setup_fn, test_fn, teardown_fn) \ + do { \ + static struct test_data test; \ + test.test_type = type; \ + test.test_name = g_strdup(name); \ + if (type == TEST_RSSI_FILTER) { \ + test.rssi_filter_test_data = (void *)&data; \ + test.rssi_filter_test_data->test_info = &test; \ + } \ + tester_add(name, &test, setup_fn, test_fn, teardown_fn);\ + } while (0) + +#define ADV_INTERVAL 1 /* Advertisement interval in seconds */ +#define OUT_OF_RANGE -128 +#define END_OF_RSSI_TEST {0} + +#define RSSI_TEST_DONE(test_step) \ + (!test_step.adv_rssi && !test_step.duration && !test_step.result) + +#define DUMMY_BTD_DEVICE_OBJ ((void *) 0xF00) + +enum test_type { + TEST_RSSI_FILTER = 0, + TEST_CONTENT_FILTER, +}; + +enum result { + RESULT_DEVICE_NOT_FOUND = false, /* Initial state of a device */ + RESULT_DEVICE_FOUND = true, /* Device state when the + * Content/RSSI Filter match + */ + RESULT_DEVICE_LOST = false, /* Device state when the Low + * RSSI Filter match or if it + * goes offline/out-of-range + */ +}; + +struct rssi_filter_test { + void *adv_monitor_obj; /* struct adv_monitor object */ + void *btd_device_obj; /* struct btd_device object */ + struct test_data *test_info; + + const struct { + int8_t high_rssi_threshold; /* High RSSI threshold */ + uint16_t high_rssi_timeout; /* High RSSI threshold timeout*/ + int8_t low_rssi_threshold; /* Low RSSI threshold */ + uint16_t low_rssi_timeout; /* Low RSSI threshold timeout */ + } rssi_filter; + + time_t start_time; /* Start time of the test */ + uint16_t resume_step; /* Store the current sub-step of the + * test before suspending that test + */ + guint out_of_range_timer; /* Timer to simulate device offline */ + + const struct { + int8_t adv_rssi; /* Advertisement RSSI */ + uint16_t duration; /* Advertisement duration in seconds */ + enum result result; /* Device state after every step */ + } test_steps[]; +}; + +/* Parent data structure to hold the test data and information, + * used by tester_* functions and callbacks. + */ +struct test_data { + enum test_type test_type; + char *test_name; + + union { + struct rssi_filter_test *rssi_filter_test_data; + }; +}; + +/* RSSI Filter Test 1: + * - The Device Lost event should NOT get triggered even if the Adv RSSI is + * lower than LowRSSIThresh for more than LowRSSITimeout before finding + * the device first. + * - Similarly, the Device Found event should NOT get triggered if the Adv RSSI + * is greater than LowRSSIThresh but lower than HighRSSIThresh. + */ +static struct rssi_filter_test rssi_data_1 = { + .rssi_filter = {-40, 5, -60, 5}, + .test_steps = { + {-70, 6, RESULT_DEVICE_NOT_FOUND}, + {-50, 6, RESULT_DEVICE_NOT_FOUND}, + END_OF_RSSI_TEST, + }, +}; + +/* RSSI Filter Test 2: + * - The Device Found event should get triggered when the Adv RSSI is higher + * than HighRSSIThresh for more than HighRSSITimeout. + * - Once the device is found, the Device Lost event should NOT get triggered + * if the Adv RSSI drops below HighRSSIThresh but it is not lower than + * LowRSSIThresh. + * - When the Adv RSSI drops below LowRSSIThresh for more than LowRSSITimeout, + * the Device Lost event should get triggered. + */ +static struct rssi_filter_test rssi_data_2 = { + .rssi_filter = {-40, 5, -60, 5}, + .test_steps = { + {-30, 6, RESULT_DEVICE_FOUND}, + {-50, 6, RESULT_DEVICE_FOUND}, + {-70, 6, RESULT_DEVICE_LOST}, + END_OF_RSSI_TEST, + }, +}; + +/* RSSI Filter Test 3: + * - The Device Found event should get triggered only when the Adv RSSI is + * higher than HighRSSIThresh for more than HighRSSITimeout. + * - If the Adv RSSI drops below HighRSSIThresh, timer should reset and start + * counting once the Adv RSSI is above HighRSSIThresh. + * - Similarly, when tracking the Low RSSI, timer should reset when the Adv RSSI + * goes above LowRSSIThresh. The Device Lost event should get triggered only + * when the Adv RSSI is lower than LowRSSIThresh for more than LowRSSITimeout. + */ +static struct rssi_filter_test rssi_data_3 = { + .rssi_filter = {-40, 5, -60, 5}, + .test_steps = { + {-30, 2, RESULT_DEVICE_NOT_FOUND}, + {-50, 6, RESULT_DEVICE_NOT_FOUND}, + {-30, 4, RESULT_DEVICE_NOT_FOUND}, + {-30, 2, RESULT_DEVICE_FOUND}, + {-70, 2, RESULT_DEVICE_FOUND}, + {-50, 6, RESULT_DEVICE_FOUND}, + {-70, 4, RESULT_DEVICE_FOUND}, + {-70, 2, RESULT_DEVICE_LOST}, + END_OF_RSSI_TEST, + }, +}; + +/* RSSI Filter Test 4: + * - While tracking the High RSSI, timer should reset if the device goes + * offline/out-of-range for more than HighRSSITimeout. + * - Once the device is found, if the device goes offline/out-of-range for + * more than LowRSSITimeout, the Device Lost event should get triggered. + */ +static struct rssi_filter_test rssi_data_4 = { + .rssi_filter = {-40, 5, -60, 5}, + .test_steps = { + { -30, 2, RESULT_DEVICE_NOT_FOUND}, + {OUT_OF_RANGE, 6, RESULT_DEVICE_NOT_FOUND}, + { -30, 4, RESULT_DEVICE_NOT_FOUND}, + { -30, 2, RESULT_DEVICE_FOUND}, + { -70, 2, RESULT_DEVICE_FOUND}, + {OUT_OF_RANGE, 6, RESULT_DEVICE_LOST}, + END_OF_RSSI_TEST, + }, +}; + +/* RSSI Filter Test 5: + * - The Device Found event should get triggered only once even if the Adv RSSI + * stays higher than HighRSSIThresh for a longer period of time. + * - Once the device is found, while tracking the Low RSSI, timer should reset + * when the Adv RSSI goes above LowRSSIThresh. + * - The timer should NOT reset if the device goes offline/out-of-range for + * a very short period of time and comes back online/in-range before + * the timeouts. + */ +static struct rssi_filter_test rssi_data_5 = { + .rssi_filter = {-40, 5, -60, 5}, + .test_steps = { + { -30, 2, RESULT_DEVICE_NOT_FOUND}, + {OUT_OF_RANGE, 2, RESULT_DEVICE_NOT_FOUND}, + { -30, 2, RESULT_DEVICE_FOUND}, + { -30, 3, RESULT_DEVICE_FOUND}, + { -30, 3, RESULT_DEVICE_FOUND}, + { -70, 2, RESULT_DEVICE_FOUND}, + {OUT_OF_RANGE, 2, RESULT_DEVICE_FOUND}, + { -50, 6, RESULT_DEVICE_FOUND}, + { -70, 2, RESULT_DEVICE_FOUND}, + {OUT_OF_RANGE, 2, RESULT_DEVICE_FOUND}, + { -70, 2, RESULT_DEVICE_LOST}, + END_OF_RSSI_TEST, + }, +}; + +/* Initialize the data required for RSSI Filter test */ +static void setup_rssi_filter_test(gpointer data) +{ + struct rssi_filter_test *test = data; + + test->adv_monitor_obj = btd_adv_monitor_rssi_test_setup( + test->rssi_filter.high_rssi_threshold, + test->rssi_filter.high_rssi_timeout, + test->rssi_filter.low_rssi_threshold, + test->rssi_filter.low_rssi_timeout); + + /* The RSSI Filter logic uses btd_device object only as a key in the + * adv_monitor->devices list, it is never dereferenced nor used to + * perform any operations related to btd_device. So we can use any + * dummy address for unit testing. + */ + test->btd_device_obj = DUMMY_BTD_DEVICE_OBJ; + + tester_setup_complete(); +} + +/* Cleanup after the RSSI Filter test is done */ +static void teardown_rssi_filter_test(gpointer data) +{ + struct rssi_filter_test *test = data; + + btd_adv_monitor_rssi_test_teardown(test->adv_monitor_obj); + + tester_teardown_complete(); +} + +/* Execute the sub-steps of RSSI Filter test */ +static gboolean test_rssi_filter(gpointer data) +{ + struct rssi_filter_test *test = data; + time_t start_time = time(NULL); + bool ret = false; + + uint16_t i = 0; + uint16_t j = 0; + + /* If this is not the beginning of test, return to the sub-step + * before that test was suspended + */ + if (test->resume_step) { + start_time = test->start_time; + i = test->resume_step; + + /* Clear the test resume timer */ + g_source_remove(test->out_of_range_timer); + test->out_of_range_timer = 0; + + /* Check state of the device - found/lost, while device was + * offline/out-of-range + */ + ret = btd_adv_monitor_test_device_state(test->adv_monitor_obj, + test->btd_device_obj); + tester_debug("%s: [t=%.0lf, step=%d] Test resume, " + "device_found = %s", + test->test_info->test_name, + difftime(time(NULL), start_time), i, + ret ? "true" : "false"); + g_assert(ret == test->test_steps[i].result); + + i++; + } + + while (!RSSI_TEST_DONE(test->test_steps[i])) { + if (test->test_steps[i].adv_rssi == OUT_OF_RANGE) { + /* Simulate device offline/out-of-range by suspending + * the test. + * + * Note: All tester_* functions run sequentially by + * adding a next function to the main loop using + * g_idle_add(). If a timeout function is added using + * g_timeout_add_*(), it doesn't really get invoked as + * soon as the timer expires. Instead, it is invoked + * once the current function returns and the timer has + * expired. So, to give handle_device_lost_timeout() + * function a chance to run at the correct time, we + * must save the current state and exit from this + * function while we simulate the device offline. We can + * come back later to continue with the remaining steps. + */ + test->resume_step = i; + test->start_time = start_time; + test->out_of_range_timer = g_timeout_add_seconds( + test->test_steps[i].duration, + test_rssi_filter, data); + + /* Check the device state before suspending the test */ + ret = btd_adv_monitor_test_device_state( + test->adv_monitor_obj, + test->btd_device_obj); + tester_debug("%s: [t=%.0lf, step=%d] Test suspend, " + "device_found = %s", + test->test_info->test_name, + difftime(time(NULL), start_time), i, + ret ? "true" : "false"); + return FALSE; + } + + for (j = 0; j < test->test_steps[i].duration; j++) { + ret = btd_adv_monitor_test_rssi( + test->adv_monitor_obj, + test->btd_device_obj, + test->test_steps[i].adv_rssi); + tester_debug("%s: [t=%.0lf, step=%d] Test " + "advertisement RSSI %d, device_found = %s", + test->test_info->test_name, + difftime(time(NULL), start_time), i, + test->test_steps[i].adv_rssi, + ret ? "true" : "false"); + + /* Sleep for a second to simulate receiving + * advertisement once every second + */ + sleep(ADV_INTERVAL); + } + g_assert(ret == test->test_steps[i].result); + + i++; + } + + tester_debug("%s: [t=%.0lf] Test done", test->test_info->test_name, + difftime(time(NULL), start_time)); + + tester_test_passed(); + + return FALSE; +} + +/* Handler function to prepare for a test */ +static void setup_handler(gconstpointer data) +{ + const struct test_data *test = data; + + if (test->test_type == TEST_RSSI_FILTER) + setup_rssi_filter_test(test->rssi_filter_test_data); +} + +/* Handler function to cleanup after the test is done */ +static void teardown_handler(gconstpointer data) +{ + const struct test_data *test = data; + + if (test->test_type == TEST_RSSI_FILTER) + teardown_rssi_filter_test(test->rssi_filter_test_data); +} + +/* Handler function to execute a test with the given data set */ +static void test_handler(gconstpointer data) +{ + const struct test_data *test = data; + + if (test->test_type == TEST_RSSI_FILTER) + test_rssi_filter(test->rssi_filter_test_data); +} + +int main(int argc, char *argv[]) +{ + tester_init(&argc, &argv); + + __btd_log_init("*", 0); + + define_test("/advmon/rssi/1", TEST_RSSI_FILTER, rssi_data_1, + setup_handler, test_handler, teardown_handler); + define_test("/advmon/rssi/2", TEST_RSSI_FILTER, rssi_data_2, + setup_handler, test_handler, teardown_handler); + define_test("/advmon/rssi/3", TEST_RSSI_FILTER, rssi_data_3, + setup_handler, test_handler, teardown_handler); + define_test("/advmon/rssi/4", TEST_RSSI_FILTER, rssi_data_4, + setup_handler, test_handler, teardown_handler); + define_test("/advmon/rssi/5", TEST_RSSI_FILTER, rssi_data_5, + setup_handler, test_handler, teardown_handler); + + return tester_run(); +} From patchwork Thu Sep 17 06:19:44 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miao-chen Chou X-Patchwork-Id: 11781623 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1AA136CA for ; Thu, 17 Sep 2020 06:20:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id ED8AF21973 for ; Thu, 17 Sep 2020 06:20:34 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="hzYL6RjJ" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726191AbgIQGUe (ORCPT ); Thu, 17 Sep 2020 02:20:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39370 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725267AbgIQGU3 (ORCPT ); Thu, 17 Sep 2020 02:20:29 -0400 Received: from mail-pg1-x541.google.com (mail-pg1-x541.google.com [IPv6:2607:f8b0:4864:20::541]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1C8BBC06174A for ; Wed, 16 Sep 2020 23:20:29 -0700 (PDT) Received: by mail-pg1-x541.google.com with SMTP id 67so734874pgd.12 for ; Wed, 16 Sep 2020 23:20:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=WRB9d8sFpm7OeJs49fmtNU3aVk+UhWdaM5u0PPyaIgI=; b=hzYL6RjJ2Zz+9OWHEU/OsTYKM88urF4Q3CpOM8PuwD3cMrHrCu1wtahX4DJCuMvmI0 SuGeoA/fC3yqipkHHp/6nEa9BrQsxN1DGg+m6QhWX0D+7wmMOAjE679ShmsjsihmgjGN xlNXea3mK9FA0/Q7Eo/Qz83SpNDZ7cS6Kgt00= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=WRB9d8sFpm7OeJs49fmtNU3aVk+UhWdaM5u0PPyaIgI=; b=hMQGv9bdY0lhOod8p2OAr68E9fQnaAAqBLnLjmsekP5iCjZaaOWR7oiuSd27onhPRF 3PvyVmZQEqRlUuamMA0NesDZ0YIoYO0y6UhMwbK6+VklKoOuTykqd6qmxH5E4fov7E5S brqxxkVWrFWgoFwpdNUywD6kt0b0HeEgBjF1NoQ5lY3r24B2TMZSQeaCqPSzu5WL2uQX 3C4gcZAhwPoxl9Mw32vt3m0ZHl8SneEVVQwexy6NwhTpVkc1lP6nl6J7GE82vQbFjSmJ klHynZrT4ezoTS4yqLFbqRXK7CtGbKW12sQlroTw9hnDZ8UJDc/1z2q4u9SkPhakS6xk X6xQ== X-Gm-Message-State: AOAM533dRReZG3d4OdbZn/Uzz0P5MyrHfyYJ1Qg8B5zM+oc8ezslzcqG 9WXZAAe4cGOdiWtb2Vn73qEDGgTn8jAG6A== X-Google-Smtp-Source: ABdhPJwBf9Takk8G0nQ3oixpPzvzfJpPsLAwjBRtsNdRMnEc371bVroVN2EOsmlFi30iv9SZi4rD/w== X-Received: by 2002:a63:c543:: with SMTP id g3mr21693999pgd.203.1600323628141; Wed, 16 Sep 2020 23:20:28 -0700 (PDT) Received: from mcchou0.mtv.corp.google.com ([2620:15c:202:201:de4a:3eff:fe75:1314]) by smtp.gmail.com with ESMTPSA id g23sm19264943pfh.133.2020.09.16.23.20.27 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 16 Sep 2020 23:20:27 -0700 (PDT) From: Miao-chen Chou To: Bluetooth Kernel Mailing List Cc: Marcel Holtmann , Howard Chung , Manish Mandlik , Alain Michaud , chromeos-bluetooth-upstreaming@chromium.org, Luiz Augusto von Dentz , Miao-chen Chou , Abhishek Pandit-Subedi Subject: [BlueZ PATCH v2 3/8] adv_monitor: Implement Adv matching based on stored monitors Date: Wed, 16 Sep 2020 23:19:44 -0700 Message-Id: <20200916231935.BlueZ.v2.3.I578ae5e76fcf7243206a27d4f5a25783662a5f14@changeid> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200916231935.BlueZ.v2.1.I2830b9c1212a64b062201ed9f2b71294f50ad22d@changeid> References: <20200916231935.BlueZ.v2.1.I2830b9c1212a64b062201ed9f2b71294f50ad22d@changeid> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org 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 Reviewed-by: Alain Michaud Reviewed-by: Manish Mandlik --- (no changes since v1) src/adapter.c | 35 +++++-- src/adv_monitor.c | 238 +++++++++++++++++++++++++++++++++++++++++----- src/adv_monitor.h | 19 ++++ 3 files changed, 260 insertions(+), 32 deletions(-) diff --git a/src/adapter.c b/src/adapter.c index 415d6e06b..d33ce7124 100644 --- a/src/adapter.c +++ b/src/adapter.c @@ -6614,6 +6614,15 @@ static void update_found_devices(struct btd_adapter *adapter, bool name_known, discoverable; char addr[18]; bool duplicate = false; + GSList *matched_monitors; + + /* During the background scanning, update the device only when the data + * match at least one Adv monitor + */ + matched_monitors = btd_adv_monitor_content_filter( + adapter->adv_monitor_manager, data, data_len); + if (!adapter->discovering && !matched_monitors) + return; memset(&eir_data, 0, sizeof(eir_data)); eir_parse(&eir_data, data, data_len); @@ -6659,18 +6668,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; } @@ -6727,6 +6740,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); + g_slist_free(matched_monitors); + 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 046f5953f..4f86384e9 100644 --- a/src/adv_monitor.c +++ b/src/adv_monitor.c @@ -38,15 +38,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" @@ -93,7 +90,7 @@ enum monitor_state { MONITOR_STATE_HONORED, /* Accepted by kernel */ }; -struct pattern { +struct btd_adv_monitor_pattern { uint8_t ad_type; uint8_t offset; uint8_t length; @@ -142,6 +139,23 @@ struct app_match_data { const char *path; }; +struct adv_content_filter_info { + uint8_t eir_len; + const uint8_t *eir; + + bool matched; /* Intermediate state per monitor */ + GSList *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; @@ -164,7 +178,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; + struct btd_adv_monitor_pattern *pattern = data; if (!pattern) return; @@ -172,6 +186,12 @@ static void pattern_free(void *data) free(pattern); } +void btd_adv_monitor_test_pattern_destroy( + struct btd_adv_monitor_pattern *pattern) +{ + pattern_free(pattern); +} + /* Frees a monitor object */ static void monitor_free(void *data) { @@ -444,6 +464,42 @@ failed: return false; } +/* Allocates and initiates a pattern with the given content */ +static struct btd_adv_monitor_pattern *pattern_create( + uint8_t ad_type, uint8_t offset, uint8_t length, const uint8_t *value) +{ + struct btd_adv_monitor_pattern *pattern; + + if (offset > BT_AD_MAX_DATA_LEN - 1) + return NULL; + + if ((ad_type > BT_AD_3D_INFO_DATA && + ad_type != BT_AD_MANUFACTURER_DATA) || + ad_type < BT_AD_FLAGS) { + return NULL; + } + + if (!value || !length || offset + length > BT_AD_MAX_DATA_LEN) + return NULL; + + pattern = new0(struct btd_adv_monitor_pattern, 1); + if (!pattern) + return NULL; + + pattern->ad_type = ad_type; + pattern->offset = offset; + pattern->length = length; + memcpy(pattern->value, value, pattern->length); + + return pattern; +} + +struct btd_adv_monitor_pattern *btd_adv_monitor_test_pattern_create( + uint8_t ad_type, uint8_t offset, uint8_t length, const uint8_t *value) +{ + return pattern_create(ad_type, offset, length, value); +} + /* Retrieves Patterns from the remote Adv Monitor object, verifies the values * and update the local Adv Monitor */ @@ -473,7 +529,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 btd_adv_monitor_pattern *pattern; DBusMessageIter struct_iter, value_iter; dbus_message_iter_recurse(&array_iter, &struct_iter); @@ -505,28 +561,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 = pattern_create(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); @@ -961,6 +999,156 @@ void btd_adv_monitor_manager_destroy(struct btd_adv_monitor_manager *manager) manager_destroy(manager); } +/* Matches the content based on the given pattern */ +bool btd_adv_monitor_pattern_match( + const uint8_t *eir, uint8_t eir_len, + const struct btd_adv_monitor_pattern *pattern) +{ + const uint8_t *data; + uint8_t idx = 0; + uint8_t field_len, data_len, data_type; + + while (idx < eir_len - 1) { + field_len = eir[0]; + + /* Check for the end of EIR */ + if (field_len == 0) + break; + + idx += field_len + 1; + + /* Do not continue filtering if got incorrect length */ + if (idx >= eir_len) + break; + + data = &eir[2]; + data_type = eir[1]; + data_len = field_len - 1; + + eir += field_len + 1; + + if (data_type != pattern->ad_type) + continue; + + if (data_len < pattern->offset + pattern->length) + continue; + + if (pattern->offset + pattern->length > BT_AD_MAX_DATA_LEN) + continue; + + if (!memcmp(data + pattern->offset, pattern->value, + pattern->length)) + return true; + } + + return false; +} + +/* Processes the content matching based on a pattern */ +static void adv_match_per_pattern(void *data, void *user_data) +{ + struct btd_adv_monitor_pattern *pattern = data; + struct adv_content_filter_info *info = user_data; + const uint8_t *eir = info->eir; + + if (!pattern || info->matched) + return; + + info->matched = btd_adv_monitor_pattern_match(info->eir, info->eir_len, + pattern); +} + +/* 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 && monitor->state != MONITOR_STATE_HONORED) + return; + + /* Reset the intermediate matched status */ + info->matched = false; + + if (monitor->type == MONITOR_TYPE_OR_PATTERNS) { + queue_foreach(monitor->patterns, adv_match_per_pattern, info); + if (info->matched) + goto matched; + } + + return; + +matched: + info->matched_monitors = g_slist_prepend(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) + 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 data. + * Returns the list of monitors whose content match eir. + */ +GSList *btd_adv_monitor_content_filter(struct btd_adv_monitor_manager *manager, + const uint8_t *eir, uint8_t eir_len) +{ + if (!manager || !eir || !eir_len) + return NULL; + + struct adv_content_filter_info info = { + .eir_len = eir_len, + .eir = eir, + .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(gpointer a, gpointer b) +{ + struct adv_monitor *monitor = a; + struct adv_rssi_filter_info *info = b; + + 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, + GSList *matched_monitors) +{ + if (!manager || !device || !matched_monitors) + return; + + struct adv_rssi_filter_info info = { + .device = device, + .rssi = rssi, + }; + + g_slist_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 351e7f9aa..b660f5941 100644 --- a/src/adv_monitor.h +++ b/src/adv_monitor.h @@ -20,16 +20,28 @@ #ifndef __ADV_MONITOR_H #define __ADV_MONITOR_H +#include + +#include "src/shared/ad.h" + struct mgmt; 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); +GSList *btd_adv_monitor_content_filter(struct btd_adv_monitor_manager *manager, + const uint8_t *eir, uint8_t eir_len); + +void btd_adv_monitor_notify_monitors(struct btd_adv_monitor_manager *manager, + struct btd_device *device, int8_t rssi, + GSList *matched_monitors); + void btd_adv_monitor_device_remove(struct btd_adv_monitor_manager *manager, struct btd_device *device); @@ -42,5 +54,12 @@ void btd_adv_monitor_rssi_test_teardown(void *monitor_obj); bool btd_adv_monitor_test_device_state(void *monitor_obj, void *device_obj); bool btd_adv_monitor_test_rssi(void *monitor_obj, void *device_obj, int8_t adv_rssi); +struct btd_adv_monitor_pattern *btd_adv_monitor_test_pattern_create( + uint8_t ad_type, uint8_t offset, uint8_t length, const uint8_t *value); +void btd_adv_monitor_test_pattern_destroy( + struct btd_adv_monitor_pattern *pattern); +bool btd_adv_monitor_pattern_match( + const uint8_t *eir, uint8_t eir_len, + const struct btd_adv_monitor_pattern *pattern); #endif /* __ADV_MONITOR_H */ From patchwork Thu Sep 17 06:19:46 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miao-chen Chou X-Patchwork-Id: 11781625 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B2738112E for ; Thu, 17 Sep 2020 06:20:42 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9586721973 for ; Thu, 17 Sep 2020 06:20:42 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="i5xl7K0C" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726196AbgIQGUl (ORCPT ); Thu, 17 Sep 2020 02:20:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39398 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725267AbgIQGUk (ORCPT ); Thu, 17 Sep 2020 02:20:40 -0400 Received: from mail-pf1-x42b.google.com (mail-pf1-x42b.google.com [IPv6:2607:f8b0:4864:20::42b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2F412C06174A for ; Wed, 16 Sep 2020 23:20:40 -0700 (PDT) Received: by mail-pf1-x42b.google.com with SMTP id w7so564558pfi.4 for ; Wed, 16 Sep 2020 23:20:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=urxZ2rQiREysBZDsBfYv1mq1DlCqCzpkhYSxNmpbsOc=; b=i5xl7K0C5CNXkzayq3ed0y1+AXkzc7WG1UWoTzALh69qcaL4WNAyfVqICaxRAdrMzk rwj1bFQl3EL/OGtZFbcV8JypJhXBrY9hYuJdn/SPFWYkUZq+6gLQ44JqlTiiU3Vc9LmG wVtZRdiQkcF0BzGTHQdWRo1TnpTP+jotb4aLI= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=urxZ2rQiREysBZDsBfYv1mq1DlCqCzpkhYSxNmpbsOc=; b=YZFjMcIHkmiifKVM8zxGqidxBUV4evCeupYfpkZfFekoI/1V2f1vokilr7J88aguAS YcRI5X4h3mv1B+DtAh/r+CbGDhFDdmdeCWKMzyaqxN8sXe4aVHlVID2LnQcwdKG1iVVZ MSYYLN4m7bEMcAj64zoFCxxgnKN85dAVfXo5JgngV1BO+Rtm4ZiqJwkznAE21iMY39Sd z/eJpHwMpmeezAED4ge6s3eFS0AzpFMTkEGGfyXx10SV7apmYhmnOXc4tpQEEiX2JwQ9 r187eQyU7EoFvzVBsB39oJy10Clqf3hk8wvqC0CxreZQ1b3l1wYKHJUdcjKM0mGkK2lF DzRw== X-Gm-Message-State: AOAM531Zh0lkI3akWkC3iWWok+c2KKzDSEYDaDn33h3MTECs/MnIymNF mGyZUP/YyCGxcLCxatDpbf0C2enuWDSrdA== X-Google-Smtp-Source: ABdhPJxiML9PQ3edHPyKvJFZQ+AgtCY8EQG5tkuqV+in1yHbEJOBc55w5RN1BZIriYADSl36t58d1Q== X-Received: by 2002:a63:4d48:: with SMTP id n8mr22118848pgl.70.1600323639161; Wed, 16 Sep 2020 23:20:39 -0700 (PDT) Received: from mcchou0.mtv.corp.google.com ([2620:15c:202:201:de4a:3eff:fe75:1314]) by smtp.gmail.com with ESMTPSA id g23sm19264943pfh.133.2020.09.16.23.20.38 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 16 Sep 2020 23:20:38 -0700 (PDT) From: Miao-chen Chou To: Bluetooth Kernel Mailing List Cc: Marcel Holtmann , Howard Chung , Manish Mandlik , Alain Michaud , chromeos-bluetooth-upstreaming@chromium.org, Luiz Augusto von Dentz , Miao-chen Chou , Abhishek Pandit-Subedi Subject: [BlueZ PATCH v2 4/8] adv_monitor: Implement unit tests for content filter Date: Wed, 16 Sep 2020 23:19:46 -0700 Message-Id: <20200916231935.BlueZ.v2.4.I7f88b6e4c63c14d77974438eb2f07326aedbfd9b@changeid> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200916231935.BlueZ.v2.1.I2830b9c1212a64b062201ed9f2b71294f50ad22d@changeid> References: <20200916231935.BlueZ.v2.1.I2830b9c1212a64b062201ed9f2b71294f50ad22d@changeid> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org This implements the unit tests for verifying the correctness of advertisement data fields matching against a pattern. Reviewed-by: Abhishek Pandit-Subedi Reviewed-by: Alain Michaud Reviewed-by: Manish Mandlik --- Changes in v2: - Cast test data to void * doc/test-coverage.txt | 4 +- unit/test-adv-monitor.c | 144 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+), 2 deletions(-) diff --git a/doc/test-coverage.txt b/doc/test-coverage.txt index 5296983e6..e15474a44 100644 --- a/doc/test-coverage.txt +++ b/doc/test-coverage.txt @@ -30,9 +30,9 @@ test-gobex-transfer 36 OBEX transfer handling test-gdbus-client 13 D-Bus client handling test-gatt 180 GATT qualification test cases test-hog 6 HID Over GATT qualification test cases -test-adv-monitor 5 Advertisement Monitor test cases +test-adv-monitor 9 Advertisement Monitor test cases ----- - 766 + 770 Automated end-to-end testing diff --git a/unit/test-adv-monitor.c b/unit/test-adv-monitor.c index 970be84b0..a19a3092b 100644 --- a/unit/test-adv-monitor.c +++ b/unit/test-adv-monitor.c @@ -40,6 +40,8 @@ if (type == TEST_RSSI_FILTER) { \ test.rssi_filter_test_data = (void *)&data; \ test.rssi_filter_test_data->test_info = &test; \ + } else if (type == TEST_CONTENT_FILTER) { \ + test.content_filter_test_data = (void *)&data; \ } \ tester_add(name, &test, setup_fn, test_fn, teardown_fn);\ } while (0) @@ -94,6 +96,22 @@ struct rssi_filter_test { } test_steps[]; }; +struct content_filter_test { + void *advmon_pattern; /* btd_adv_monitor_pattern */ + + bool expected_match; + + const struct { + uint8_t ad_type; + uint8_t offset; + uint8_t length; + uint8_t value[BT_AD_MAX_DATA_LEN]; + } pattern; + + uint8_t eir_len; + uint8_t eir[]; +}; + /* Parent data structure to hold the test data and information, * used by tester_* functions and callbacks. */ @@ -103,6 +121,7 @@ struct test_data { union { struct rssi_filter_test *rssi_filter_test_data; + struct content_filter_test *content_filter_test_data; }; }; @@ -211,6 +230,62 @@ static struct rssi_filter_test rssi_data_5 = { }, }; +/* Content Filter Test 1: + * The valid EIR data contains the given pattern whose content is a UUID16 AD + * data. + */ +static struct content_filter_test content_data_1 = { + .expected_match = true, + .pattern = {0x03, 0x02, 0x02, {0x09, 0x18} }, + .eir_len = 20, + .eir = {0x02, 0x01, 0x02, // flags + 0x06, 0xff, 0x96, 0xfd, 0xab, 0xcd, 0xef, // Mfr. Data + 0x05, 0x03, 0x0d, 0x18, 0x09, 0x18, // 16-bit UUIDs + 0x05, 0x16, 0x0d, 0x18, 0x12, 0x34}, // Service Data +}; + +/* Content Filter Test 2: + * The valid EIR data does not match the given pattern whose content is a UUID16 + * AD data. + */ +static struct content_filter_test content_data_2 = { + .expected_match = false, + .pattern = {0x03, 0x02, 0x02, {0x0d, 0x18} }, + .eir_len = 20, + .eir = {0x02, 0x01, 0x02, // flags + 0x06, 0xff, 0x96, 0xfd, 0xab, 0xcd, 0xef, // Mfr. Data + 0x05, 0x03, 0x0d, 0x18, 0x09, 0x18, // 16-bit UUIDs + 0x05, 0x16, 0x0d, 0x18, 0x12, 0x34}, // Service Data +}; + +/* Content Filter Test 3: + * The valid EIR data does not have the given pattern whose content is a UUID32 + * AD data. + */ +static struct content_filter_test content_data_3 = { + .expected_match = false, + .pattern = {0x05, 0x00, 0x04, {0x09, 0x18, 0x00, 0x00} }, + .eir_len = 20, + .eir = {0x02, 0x01, 0x02, // flags + 0x06, 0xff, 0x96, 0xfd, 0xab, 0xcd, 0xef, // Mfr. Data + 0x05, 0x03, 0x0d, 0x18, 0x09, 0x18, // 16-bit UUIDs + 0x05, 0x16, 0x0d, 0x18, 0x12, 0x34}, // Service Data +}; + +/* Content Filter Test 4: + * The valid EIR data does not match the given pattern whose content is a + * UUID16 AD data due to invalid starting position of matching. + */ +static struct content_filter_test content_data_4 = { + .expected_match = false, + .pattern = {0x03, 0x02, 0x02, {0x09, 0x18} }, + .eir_len = 20, + .eir = {0x02, 0x01, 0x02, // flags + 0x06, 0xff, 0x96, 0xfd, 0xab, 0xcd, 0xef, // Mfr. Data + 0x03, 0x03, 0x09, 0x18, // 16-bit UUIDs + 0x05, 0x16, 0x0d, 0x18, 0x12, 0x34}, // Service Data +}; + /* Initialize the data required for RSSI Filter test */ static void setup_rssi_filter_test(gpointer data) { @@ -343,6 +418,60 @@ static gboolean test_rssi_filter(gpointer data) return FALSE; } +/* Initialize the data required for Content Filter test */ +static void setup_content_filter_test(gpointer data) +{ + struct content_filter_test *test = data; + struct btd_adv_monitor_pattern *pattern = NULL; + + pattern = btd_adv_monitor_test_pattern_create(test->pattern.ad_type, + test->pattern.offset, + test->pattern.length, + test->pattern.value); + if (!pattern) { + tester_setup_failed(); + return; + } + + test->advmon_pattern = pattern; + tester_setup_complete(); +} + +/* Cleanup after the Content Filter test is done */ +static void teardown_content_filter_test(gpointer data) +{ + struct content_filter_test *test = data; + + if (!test) + tester_teardown_complete(); + + btd_adv_monitor_test_pattern_destroy(test->advmon_pattern); + test->advmon_pattern = NULL; + + tester_teardown_complete(); +} + +/* Execute the sub-steps of Content Filter test */ +static void test_content_filter(gpointer data) +{ + struct content_filter_test *test = data; + struct btd_adv_monitor_pattern *pattern = test->advmon_pattern; + + if (!pattern) { + tester_test_abort(); + return; + } + + if (btd_adv_monitor_pattern_match(test->eir, test->eir_len, + test->advmon_pattern) == + test->expected_match) { + tester_test_passed(); + return; + } + + tester_test_failed(); +} + /* Handler function to prepare for a test */ static void setup_handler(gconstpointer data) { @@ -350,6 +479,8 @@ static void setup_handler(gconstpointer data) if (test->test_type == TEST_RSSI_FILTER) setup_rssi_filter_test(test->rssi_filter_test_data); + else if (test->test_type == TEST_CONTENT_FILTER) + setup_content_filter_test(test->content_filter_test_data); } /* Handler function to cleanup after the test is done */ @@ -359,6 +490,8 @@ static void teardown_handler(gconstpointer data) if (test->test_type == TEST_RSSI_FILTER) teardown_rssi_filter_test(test->rssi_filter_test_data); + else if (test->test_type == TEST_CONTENT_FILTER) + teardown_content_filter_test(test->content_filter_test_data); } /* Handler function to execute a test with the given data set */ @@ -368,6 +501,8 @@ static void test_handler(gconstpointer data) if (test->test_type == TEST_RSSI_FILTER) test_rssi_filter(test->rssi_filter_test_data); + else if (test->test_type == TEST_CONTENT_FILTER) + test_content_filter(test->content_filter_test_data); } int main(int argc, char *argv[]) @@ -387,5 +522,14 @@ int main(int argc, char *argv[]) define_test("/advmon/rssi/5", TEST_RSSI_FILTER, rssi_data_5, setup_handler, test_handler, teardown_handler); + define_test("/advmon/content/1", TEST_CONTENT_FILTER, content_data_1, + setup_handler, test_handler, teardown_handler); + define_test("/advmon/content/2", TEST_CONTENT_FILTER, content_data_2, + setup_handler, test_handler, teardown_handler); + define_test("/advmon/content/3", TEST_CONTENT_FILTER, content_data_3, + setup_handler, test_handler, teardown_handler); + define_test("/advmon/content/4", TEST_CONTENT_FILTER, content_data_4, + setup_handler, test_handler, teardown_handler); + return tester_run(); } From patchwork Thu Sep 17 06:19:48 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miao-chen Chou X-Patchwork-Id: 11781629 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4ABFA112E for ; Thu, 17 Sep 2020 06:21:13 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 30C1F2137B for ; Thu, 17 Sep 2020 06:21:13 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="JzMmoTcW" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726180AbgIQGVF (ORCPT ); Thu, 17 Sep 2020 02:21:05 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39452 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725267AbgIQGVA (ORCPT ); Thu, 17 Sep 2020 02:21:00 -0400 Received: from mail-pj1-x1041.google.com (mail-pj1-x1041.google.com [IPv6:2607:f8b0:4864:20::1041]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 98B68C06174A for ; Wed, 16 Sep 2020 23:20:59 -0700 (PDT) Received: by mail-pj1-x1041.google.com with SMTP id gf14so687217pjb.5 for ; Wed, 16 Sep 2020 23:20:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=u+E1bUX0uVxPcQEsE71u1Ro0+1uBNDa00K7AzDVg6ww=; b=JzMmoTcWN8r9fSmiCYVyLPGHh/4yWvxDpYqk069/aA0JUhS+nsf6IGucPO3ltdzFJf jASugceVLWrXVfiKMemt1bQEDNMTQMYzcqxO9sljNItL71/ackDP1tql0loY1YvzdZ64 /6lCuBdKbw81qjgDCBt1Ma4YGQDcBXd8gt8RI= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=u+E1bUX0uVxPcQEsE71u1Ro0+1uBNDa00K7AzDVg6ww=; b=GBKqUpsIqgmMz6hE7xKd1a1SUflt95085FsNLZKMd3LWIw41iEcu0O/o8+5EYUTBnb ne10RvCNadO/6k6WRYUb3L6safW6ISa9r/Do3BFPlqB4XtoguLehhsFnRueTVOztvEmr mw7vDvXQvoHD9Dzle48hODoGaeiEuBBdFnqJlvYtg58rRcfKsCMALJybQyrNw7DBmmGa akhDhVA5FjKTNw+QaxrssaYfn0D5BovkkO2xCTLElw6DRpmU33oeaoNGP1VqcY9N+t7q zd1wcKM8rai8OJxY7bPMqZiWNs5YV+9nQMiErJfdibYD9mjwTixplO9yPI19jKSj6uH5 pnlg== X-Gm-Message-State: AOAM532r4YpaUBrZVBW/Yz6IbZLBP3g7Wh2fOK569oQcJAXwvT7zdkV6 NXM3JaJp3yG6KMkH4mNRaBb7UVwULJyCbA== X-Google-Smtp-Source: ABdhPJxDipMIHXKpm3c6DmFyUw4IIzmnEx8rFamxqZGXE0sjF0YXtQziINFn+lAgKiCQcbITt0UhEg== X-Received: by 2002:a17:90a:297:: with SMTP id w23mr6897687pja.44.1600323658882; Wed, 16 Sep 2020 23:20:58 -0700 (PDT) Received: from mcchou0.mtv.corp.google.com ([2620:15c:202:201:de4a:3eff:fe75:1314]) by smtp.gmail.com with ESMTPSA id g23sm19264943pfh.133.2020.09.16.23.20.57 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 16 Sep 2020 23:20:58 -0700 (PDT) From: Miao-chen Chou To: Bluetooth Kernel Mailing List Cc: Marcel Holtmann , Howard Chung , Manish Mandlik , Alain Michaud , chromeos-bluetooth-upstreaming@chromium.org, Luiz Augusto von Dentz , Miao-chen Chou Subject: [BlueZ PATCH v2 5/8] adapter: Clear all Adv monitors upon bring-up Date: Wed, 16 Sep 2020 23:19:48 -0700 Message-Id: <20200916231935.BlueZ.v2.5.Id6bfe7838831ae01fddc8605689dd77b51673960@changeid> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200916231935.BlueZ.v2.1.I2830b9c1212a64b062201ed9f2b71294f50ad22d@changeid> References: <20200916231935.BlueZ.v2.1.I2830b9c1212a64b062201ed9f2b71294f50ad22d@changeid> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org This clears all Adv monitors upon daemon bring-up by issuing MGMT_OP_REMOVE_ADV_MONITOR command with monitor_handle 0. The following test was performed: - Add an Adv Monitor using btmgmt, restart bluetoothd and observe the monitor got removed. Reviewed-by: Alain Michaud Reviewed-by: Manish Mandlik Reviewed-by: Howard Chung --- (no changes since v1) src/adapter.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/adapter.c b/src/adapter.c index d33ce7124..191467048 100644 --- a/src/adapter.c +++ b/src/adapter.c @@ -9513,6 +9513,43 @@ failed: btd_adapter_unref(adapter); } +static void reset_adv_monitors_complete(uint8_t status, uint16_t length, + const void *param, void *user_data) +{ + struct mgmt_rp_remove_adv_monitor *rp = param; + + if (status != MGMT_STATUS_SUCCESS) { + error("Failed to reset Adv Monitors: %s (0x%02x)", + mgmt_errstr(status), status); + return; + } + + if (length < sizeof(*rp)) { + error("Wrong size of remove Adv Monitor response for reset " + "all Adv Monitors"); + return; + } + + DBG("Removed all Adv Monitors"); +} + +static void reset_adv_monitors(uint16_t index) +{ + struct mgmt_cp_remove_adv_monitor cp; + + DBG("sending remove Adv Monitor command with handle 0"); + + /* Handle 0 indicates to remove all */ + cp.monitor_handle = 0; + if (mgmt_send(mgmt_master, MGMT_OP_REMOVE_ADV_MONITOR, index, + sizeof(cp), &cp, reset_adv_monitors_complete, NULL, + NULL) > 0) { + return; + } + + error("Failed to reset Adv Monitors"); +} + static void index_added(uint16_t index, uint16_t length, const void *param, void *user_data) { @@ -9527,6 +9564,8 @@ static void index_added(uint16_t index, uint16_t length, const void *param, return; } + reset_adv_monitors(index); + adapter = btd_adapter_new(index); if (!adapter) { btd_error(index, From patchwork Thu Sep 17 06:19:50 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miao-chen Chou X-Patchwork-Id: 11781631 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 95FA06CA for ; Thu, 17 Sep 2020 06:21:14 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7DC6F21974 for ; Thu, 17 Sep 2020 06:21:14 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="THOmwBKw" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726198AbgIQGVO (ORCPT ); Thu, 17 Sep 2020 02:21:14 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39484 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725267AbgIQGVL (ORCPT ); Thu, 17 Sep 2020 02:21:11 -0400 Received: from mail-pg1-x52b.google.com (mail-pg1-x52b.google.com [IPv6:2607:f8b0:4864:20::52b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 74837C06174A for ; Wed, 16 Sep 2020 23:21:11 -0700 (PDT) Received: by mail-pg1-x52b.google.com with SMTP id y1so745935pgk.8 for ; Wed, 16 Sep 2020 23:21:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=nI1lwirMpvm4vWon80g2srfXuKwwNNQq9kNumv3r5qY=; b=THOmwBKwB518USHayCzZrRr6x/02THcFpkMElLTjp/ufUahUJfK30pwOyJZVXd5qPn OnIKrS7HkMPcUt1fKWkIRbKRu5umCUlN8DJhNzNxAbHB5JgqFgP/vzRoQwOLba/bfJbM rXMoBpVeor3inCxIIeNmfGQ5G05F/HlYn6P8U= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=nI1lwirMpvm4vWon80g2srfXuKwwNNQq9kNumv3r5qY=; b=ZEITvzUR13LKI+X5I78ImR3SiMeLFxGmpMmERzTP6xws7LLbW5wkQQWp3AuIfxB3Q9 1yvNqGZf8lUeYVPN6jl7MZGxLdIArxINZow7lUvJZzxrwJFOOKT9RkBc4/Tqpo7tucbb x+3f0O+93geem6JUXzq+BW7bqxrtJF74yvOJxluOSD8GBo6ywsqIP2qpU1KOwINElTgP ++rXL67qvx8Z0x/26i+fGkF10aRpgmcgtK3sfy9dLhEzhlYLRHJ18PIEO+lVKASgUE3s as6weLPonyMYi2EO0KLtf/5GYAj07MDpPf59mBoRyF9TdieYKtiu/AWisl9PYvsi8LkB mUuQ== X-Gm-Message-State: AOAM5328QFbm6+koL9vgkaXEXYesT0gqC7H4xBH7EB3bNvyAEL6fVffx ySm48waEBOA5b7q1gOl0200AQLBcJj96tA== X-Google-Smtp-Source: ABdhPJxDpG0XjkjxYIVQTvZGbLfHSPGwHaS7+nvDjI+36+/0QTYfmrxRKoLe68xxm3B4pvN9YbY/tw== X-Received: by 2002:a63:c543:: with SMTP id g3mr21695867pgd.203.1600323670533; Wed, 16 Sep 2020 23:21:10 -0700 (PDT) Received: from mcchou0.mtv.corp.google.com ([2620:15c:202:201:de4a:3eff:fe75:1314]) by smtp.gmail.com with ESMTPSA id g23sm19264943pfh.133.2020.09.16.23.21.09 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 16 Sep 2020 23:21:09 -0700 (PDT) From: Miao-chen Chou To: Bluetooth Kernel Mailing List Cc: Marcel Holtmann , Howard Chung , Manish Mandlik , Alain Michaud , chromeos-bluetooth-upstreaming@chromium.org, Luiz Augusto von Dentz , Miao-chen Chou Subject: [BlueZ PATCH v2 6/8] adv_monitor: Implement Add Adv Patterns Monitor cmd handler Date: Wed, 16 Sep 2020 23:19:50 -0700 Message-Id: <20200916231935.BlueZ.v2.6.Ibbcb11712b613ef95c31b41207c3ea945c830018@changeid> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200916231935.BlueZ.v2.1.I2830b9c1212a64b062201ed9f2b71294f50ad22d@changeid> References: <20200916231935.BlueZ.v2.1.I2830b9c1212a64b062201ed9f2b71294f50ad22d@changeid> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Howard Chung - Send the MGMT_OP command to kernel upon registration of a Adv patterns monitor. - Call Activate() or Release() to client depending on the reply from kernel the call through syslog Reviewed-by: Alain Michaud Reviewed-by: Miao-chen Chou Reviewed-by: Manish Mandlik --- (no changes since v1) src/adv_monitor.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/src/adv_monitor.c b/src/adv_monitor.c index 4f86384e9..bce99eace 100644 --- a/src/adv_monitor.c +++ b/src/adv_monitor.c @@ -609,11 +609,59 @@ done: return monitor->state != MONITOR_STATE_FAILED; } +/* Handles the callback of Add Adv Patterns Monitor command */ +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; + + if (status != MGMT_STATUS_SUCCESS || !param) { + btd_error(adapter_id, "Failed to Add Adv Patterns Monitor " + "with status 0x%02x", status); + monitor_release(monitor, NULL); + return; + } + + if (length < sizeof(*rp)) { + btd_error(adapter_id, "Wrong size of Add Adv Patterns Monitor " + "response"); + monitor_release(monitor, NULL); + return; + } + + monitor->state = MONITOR_STATE_HONORED; + + 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); + + DBG("Adv Monitor with handle:0x%04x added", + le16_to_cpu(rp->monitor_handle)); +} + +static void monitor_copy_patterns(void *data, void *user_data) +{ + struct btd_adv_monitor_pattern *pattern = data; + struct mgmt_cp_add_adv_monitor *cp = user_data; + + if (!pattern) + return; + + memcpy(cp->patterns + cp->pattern_count, pattern, sizeof(*pattern)); + cp->pattern_count++; +} + /* 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 mgmt_cp_add_adv_monitor *cp = NULL; + uint8_t pattern_count, cp_len; 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); @@ -646,7 +694,24 @@ static void monitor_proxy_added_cb(GDBusProxy *proxy, void *user_data) queue_push_tail(app->monitors, monitor); + pattern_count = queue_length(monitor->patterns); + cp_len = sizeof(struct mgmt_cp_add_adv_monitor) + + pattern_count * sizeof(struct mgmt_adv_pattern); + + cp = malloc0(cp_len); + queue_foreach(monitor->patterns, monitor_copy_patterns, cp); + + if (!mgmt_send(app->manager->mgmt, MGMT_OP_ADD_ADV_PATTERNS_MONITOR, + adapter_id, cp_len, cp, add_adv_patterns_monitor_cb, + monitor, NULL)) { + error("Unable to send Add Adv Patterns Monitor command"); + goto done; + } + DBG("Adv Monitor allocated for the object at path %s", path); + +done: + free(cp); } /* Handles the removal of an Adv Monitor D-Bus proxy */ @@ -1064,7 +1129,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; - if (!monitor && monitor->state != MONITOR_STATE_HONORED) + if (!monitor || monitor->state != MONITOR_STATE_HONORED) return; /* Reset the intermediate matched status */ From patchwork Thu Sep 17 06:19:52 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miao-chen Chou X-Patchwork-Id: 11781635 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 68C4A112E for ; Thu, 17 Sep 2020 06:21:26 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5039921D1B for ; Thu, 17 Sep 2020 06:21:26 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="axSQUbfy" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726241AbgIQGVZ (ORCPT ); Thu, 17 Sep 2020 02:21:25 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39510 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725267AbgIQGVW (ORCPT ); Thu, 17 Sep 2020 02:21:22 -0400 Received: from mail-pj1-x1044.google.com (mail-pj1-x1044.google.com [IPv6:2607:f8b0:4864:20::1044]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0945DC06174A for ; Wed, 16 Sep 2020 23:21:22 -0700 (PDT) Received: by mail-pj1-x1044.google.com with SMTP id kk9so694501pjb.2 for ; Wed, 16 Sep 2020 23:21:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=rfbzG45/ZVPfYtToxz75HKregAJxFeEORwOPk5JyveQ=; b=axSQUbfyl9x3BKPvQg2jJ3Ksay0a3BAIYeOe8Yrle7yEPBSq2vlysygzIO4jNNOE7V PZWHYREG/LbBBUGDAYuDctfolhRjELn7fj35SCoU+MMRokBoPAw4nJUlgbdgXfSR3vQN o9XrlDW2zvrGGBiOBnAucQ7Xq+J+fZACJWxN0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=rfbzG45/ZVPfYtToxz75HKregAJxFeEORwOPk5JyveQ=; b=VmxItUPHTAK+FJCrtt0GqE1mypV9nYn4/XzQin7121XWR9oMzaKpruZYLK9AtIqJDw jNb4f4FsF+LBA9kUsrS2UaZeGpoDkJl8Yrv3/OqA7nGt72AnYqOYYagop4QKro1wjNuN gtr3pmLGwI1mGdLOYKAVkVBxRlk8+5bSVjt4o4z1N3FFCkNqwQwOx/jsm0iQOSPV9pMZ x7AwxqYINb4i9OSI6oPhLHO24TTNM5Kzdh1TTorw5YeKOkD6Xu/lr+bPweu5ggETiLI4 +CGvdg7nZMoinLXdsprIviS5kdIvSKp2fNHTg+losdgrAjQPyTHRctutd6zUuhd+Bo5C DLXw== X-Gm-Message-State: AOAM531i6uwdfkkE6j+P8kl7pfLl7DKKQmClF4nivfIArOzLzmicm3bp gbjKz4EUpsRDFsKX/b3RVX1NdnZPH/JATQ== X-Google-Smtp-Source: ABdhPJzJw1cyvl6uNDprStCioRfBpLRgwLsRU164kN/g6Dl/VjaL6zhzlxbv+TtL4lhKXpZG5Pe3CA== X-Received: by 2002:a17:902:a585:b029:d0:afd3:d851 with SMTP id az5-20020a170902a585b02900d0afd3d851mr27942255plb.2.1600323681292; Wed, 16 Sep 2020 23:21:21 -0700 (PDT) Received: from mcchou0.mtv.corp.google.com ([2620:15c:202:201:de4a:3eff:fe75:1314]) by smtp.gmail.com with ESMTPSA id g23sm19264943pfh.133.2020.09.16.23.21.20 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 16 Sep 2020 23:21:20 -0700 (PDT) From: Miao-chen Chou To: Bluetooth Kernel Mailing List Cc: Marcel Holtmann , Howard Chung , Manish Mandlik , Alain Michaud , chromeos-bluetooth-upstreaming@chromium.org, Luiz Augusto von Dentz , Miao-chen Chou Subject: [BlueZ PATCH v2 7/8] adv_monitor: Fix return type of RegisterMonitor() method Date: Wed, 16 Sep 2020 23:19:52 -0700 Message-Id: <20200916231935.BlueZ.v2.7.Ic8dbe9115e82704b4c0c860eee27ad897db13237@changeid> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200916231935.BlueZ.v2.1.I2830b9c1212a64b062201ed9f2b71294f50ad22d@changeid> References: <20200916231935.BlueZ.v2.1.I2830b9c1212a64b062201ed9f2b71294f50ad22d@changeid> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org This modifies the D-Bus call return type to be asynchronous for RegisterMonitor() method call. The following test was performed: - Enter bluetoothctl, exit the console and re-enter the console without AlreadyExist error for RegisterMonitor() upon bring-up of the console. Reviewed-by: Howard Chung Reviewed-by: Manish Mandlik --- (no changes since v1) src/adv_monitor.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/adv_monitor.c b/src/adv_monitor.c index bce99eace..6dfb777b2 100644 --- a/src/adv_monitor.c +++ b/src/adv_monitor.c @@ -758,6 +758,8 @@ static struct adv_monitor_app *app_create(DBusConnection *conn, app->monitors = queue_new(); + app->reg = dbus_message_ref(msg); + g_dbus_client_set_disconnect_watch(app->client, app_disconnect_cb, app); /* Note that any property changes on a monitor object would not affect @@ -769,8 +771,6 @@ static struct adv_monitor_app *app_create(DBusConnection *conn, g_dbus_client_set_ready_watch(app->client, app_ready_cb, app); - app->reg = dbus_message_ref(msg); - return app; } @@ -864,7 +864,7 @@ static DBusMessage *unregister_monitor(DBusConnection *conn, } static const GDBusMethodTable adv_monitor_methods[] = { - { GDBUS_EXPERIMENTAL_METHOD("RegisterMonitor", + { GDBUS_EXPERIMENTAL_ASYNC_METHOD("RegisterMonitor", GDBUS_ARGS({ "application", "o" }), NULL, register_monitor) }, { GDBUS_EXPERIMENTAL_ASYNC_METHOD("UnregisterMonitor", From patchwork Thu Sep 17 06:19:54 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miao-chen Chou X-Patchwork-Id: 11781637 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C6D8F6CA for ; Thu, 17 Sep 2020 06:21:39 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A6C8B2137B for ; Thu, 17 Sep 2020 06:21:39 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="R5W+KZCr" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726249AbgIQGVj (ORCPT ); Thu, 17 Sep 2020 02:21:39 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39552 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726245AbgIQGVj (ORCPT ); Thu, 17 Sep 2020 02:21:39 -0400 Received: from mail-pl1-x62c.google.com (mail-pl1-x62c.google.com [IPv6:2607:f8b0:4864:20::62c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4E3C3C06174A for ; Wed, 16 Sep 2020 23:21:38 -0700 (PDT) Received: by mail-pl1-x62c.google.com with SMTP id c3so575893plz.5 for ; Wed, 16 Sep 2020 23:21:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=vhAjw9iYH+HwEhcHX+OUR7w1h7BFvlaDCjF8rrfdvdM=; b=R5W+KZCr0YguQHAnaPX5jjriJ4OCgJMBhAZr/sT5PKf4+g33RBzu/Wnl1RxxvaQl1K FSMwVUEW2xn7JbgR1TG1MW6G2tRokr93jSOT8XX6+ejY16Cq/gCGN1w9LKneixnpmGFx FBCMN9bidR1crblkL/K8IdVMHm5xggqwB/3QM= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=vhAjw9iYH+HwEhcHX+OUR7w1h7BFvlaDCjF8rrfdvdM=; b=kDTKnOeEJXptPnS3e5BRGyKxJGBV8oT76xyZpxCx0CBWpN+rKW/GMpCrBGxQ5pd3YO eo6g3K4q+16Vqi8rIiJ8r+CVqO7Q5RqcBXcRwLDbY8u84+234MUq3geEIkvutmIXrZhM Zhu9VLQXLIXziCvp2qAxLLBHB2pn8+pUVpU4ONI5ZpqxyPLQK6XAf8H6iSR/RFx2s5Uy 6JAwlVu1uE/4Xtni3O0pJLjNEnh6Tq6mp7Y+GGhFjfga186+1XAw9ixWwNVaBJ6GIKPB RK2hVxPLrIb9LK1kR/fBB9d2XPDhbH2wioood06zGNU9ZOB2JfuX7mrvGtsOdhVm7igi gdpg== X-Gm-Message-State: AOAM530dk/dth+5iKgPX2cwbvQ65DCVIQUdUYzLG73HsmPWUJZHFfQXq wzStNUJQgxSTGRzkNGtv0Rqyw1gilfFfmA== X-Google-Smtp-Source: ABdhPJxIN6D0htTeJ/ubYGsmvTOl2KqoPfw7/P7eJzygFeK9TAnRZjBo1DwbrusgxKWvPMhr8iKk+A== X-Received: by 2002:a17:902:a509:b029:d0:cb2d:f26e with SMTP id s9-20020a170902a509b02900d0cb2df26emr26192755plq.7.1600323696144; Wed, 16 Sep 2020 23:21:36 -0700 (PDT) Received: from mcchou0.mtv.corp.google.com ([2620:15c:202:201:de4a:3eff:fe75:1314]) by smtp.gmail.com with ESMTPSA id g23sm19264943pfh.133.2020.09.16.23.21.35 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 16 Sep 2020 23:21:35 -0700 (PDT) From: Miao-chen Chou To: Bluetooth Kernel Mailing List Cc: Marcel Holtmann , Howard Chung , Manish Mandlik , Alain Michaud , chromeos-bluetooth-upstreaming@chromium.org, Luiz Augusto von Dentz Subject: [BlueZ PATCH v2 8/8] adv_monitor: Issue Remove Adv Monitor mgmt call Date: Wed, 16 Sep 2020 23:19:54 -0700 Message-Id: <20200916231935.BlueZ.v2.8.Ifda683c92ff520bf58ac37c02dc40b8d9598d1b0@changeid> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200916231935.BlueZ.v2.1.I2830b9c1212a64b062201ed9f2b71294f50ad22d@changeid> References: <20200916231935.BlueZ.v2.1.I2830b9c1212a64b062201ed9f2b71294f50ad22d@changeid> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Alain Michaud This calls Remove Adv Monitor command to kernel and handles the callback during a monitor removal initiated by a D-Bus client. This also registers callback for getting notified on Adv Monitor Removed event, so that the Adv monitor manager can invalidate the monitor by calling Release() on its proxy. The following tests were performed. - In bluetoothctl console, add a monitor and remove the monitor by its index and verify the removal in both the output of btmgmt and syslog. - In bluetoothctl console, add a monitor, remove the monitor via btmgmt and verify the removal in syslog. Reviewed-by: Howard Chung --- (no changes since v1) src/adv_monitor.c | 129 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 121 insertions(+), 8 deletions(-) diff --git a/src/adv_monitor.c b/src/adv_monitor.c index 6dfb777b2..d599e91c2 100644 --- a/src/adv_monitor.c +++ b/src/adv_monitor.c @@ -88,6 +88,7 @@ enum monitor_state { MONITOR_STATE_FAILED, /* Failed to be init'ed */ MONITOR_STATE_INITED, /* Init'ed but not yet sent to kernel */ MONITOR_STATE_HONORED, /* Accepted by kernel */ + MONITOR_STATE_REMOVING, /* Removing from kernel */ }; struct btd_adv_monitor_pattern { @@ -103,6 +104,7 @@ struct adv_monitor { char *path; enum monitor_state state; /* MONITOR_STATE_* */ + uint16_t monitor_handle; /* Kernel Monitor Handle */ int8_t high_rssi; /* High RSSI threshold */ uint16_t high_rssi_timeout; /* High RSSI threshold timeout */ @@ -631,6 +633,7 @@ static void add_adv_patterns_monitor_cb(uint8_t status, uint16_t length, return; } + monitor->monitor_handle = le16_to_cpu(rp->monitor_handle); monitor->state = MONITOR_STATE_HONORED; DBG("Calling Activate() on Adv Monitor of owner %s at path %s", @@ -639,8 +642,7 @@ static void add_adv_patterns_monitor_cb(uint8_t status, uint16_t length, g_dbus_proxy_method_call(monitor->proxy, "Activate", NULL, NULL, NULL, NULL); - DBG("Adv Monitor with handle:0x%04x added", - le16_to_cpu(rp->monitor_handle)); + DBG("Adv monitor with handle:0x%04x added", monitor->monitor_handle); } static void monitor_copy_patterns(void *data, void *user_data) @@ -714,20 +716,78 @@ done: free(cp); } +/* 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) +{ + struct adv_monitor *monitor = user_data; + const struct mgmt_rp_remove_adv_monitor *rp = param; + uint16_t adapter_id = monitor->app->manager->adapter_id; + + if (status != MGMT_STATUS_SUCCESS || !param) { + btd_error(adapter_id, "Failed to Remove Adv Monitor with " + "status 0x%02x", status); + goto done; + } + + if (length < sizeof(*rp)) { + btd_error(adapter_id, "Wrong size of Remove Adv Monitor " + "response"); + goto done; + } + +done: + queue_remove(monitor->app->monitors, monitor); + + DBG("Adv Monitor removed with handle:0x%04x, path %s", + monitor->monitor_handle, monitor->path); + + monitor_free(monitor); +} + + /* Handles the removal of an Adv Monitor D-Bus proxy */ static void monitor_proxy_removed_cb(GDBusProxy *proxy, void *user_data) { struct adv_monitor *monitor; + struct mgmt_cp_remove_adv_monitor cp; struct adv_monitor_app *app = user_data; + uint16_t adapter_id = app->manager->adapter_id; + const char *path = g_dbus_proxy_get_path(proxy); - monitor = queue_remove_if(app->monitors, monitor_match, proxy); - if (monitor) { - DBG("Adv Monitor removed for the object at path %s", - monitor->path); + monitor = queue_find(app->monitors, monitor_match, proxy); - /* The object was gone, so we don't need to call Release() */ - monitor_free(monitor); + /* A monitor removed event from kernel can remove a monitor and notify + * the app on Release() where this callback can be invoked, so we + * simply skip here. + */ + if (!monitor) + return; + + if (monitor->state != MONITOR_STATE_HONORED) + goto done; + + monitor->state = MONITOR_STATE_REMOVING; + + 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, + monitor, NULL)) { + btd_error(adapter_id, "Unable to send Remove Advt Monitor " + "command"); + goto done; } + + return; + +done: + queue_remove(app->monitors, monitor); + + DBG("Adv Monitor removed in state %02x with path %s", monitor->state, + monitor->path); + + monitor_free(monitor); } /* Creates an app object, initiates it and sets D-Bus event handlers */ @@ -936,6 +996,55 @@ static const GDBusPropertyTable adv_monitor_properties[] = { { } }; +/* Matches a monitor based on its handle */ +static bool removed_monitor_match(void *data, void *user_data) +{ + struct adv_monitor *monitor = data; + struct mgmt_ev_adv_monitor_removed *ev = user_data; + + return monitor->monitor_handle == ev->monitor_handle; +} + +/* Remove the matched monitor and reports the removal to the app */ +static void app_remove_monitor(void *data, void *user_data) +{ + struct adv_monitor_app *app = data; + struct adv_monitor *monitor; + + monitor = queue_find(app->monitors, removed_monitor_match, user_data); + if (monitor) { + if (monitor->state == MONITOR_STATE_HONORED) + monitor_release(monitor, NULL); + + queue_remove(app->monitors, monitor); + + DBG("Adv Monitor at path %s removed", monitor->path); + + monitor_free(monitor); + } +} + +/* Processes Adv Monitor removed event from kernel */ +static void adv_monitor_removed_callback(uint16_t index, uint16_t length, + const void *param, void *user_data) +{ + struct mgmt_ev_adv_monitor_removed *ev = param; + struct btd_adv_monitor_manager *manager = user_data; + const uint16_t adapter_id = manager->adapter_id; + + if (length < sizeof(*ev)) { + btd_error(adapter_id, "Wrong size of Adv Monitor Removed " + "event"); + return; + } + + /* Traverse the apps to find the monitor */ + queue_foreach(manager->apps, app_remove_monitor, ev); + + DBG("Adv Monitor removed event with handle 0x%04x processed", + ev->monitor_handle); +} + /* Allocates a manager object */ static struct btd_adv_monitor_manager *manager_new( struct btd_adapter *adapter, @@ -955,6 +1064,10 @@ static struct btd_adv_monitor_manager *manager_new( manager->adapter_id = btd_adapter_get_index(adapter); manager->apps = queue_new(); + mgmt_register(manager->mgmt, MGMT_EV_ADV_MONITOR_REMOVED, + manager->adapter_id, adv_monitor_removed_callback, + manager, NULL); + return manager; }