From patchwork Sat Oct 31 00:52: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: 11871029 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.8 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 27351C388F9 for ; Sat, 31 Oct 2020 00:53:05 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id ABDED208B6 for ; Sat, 31 Oct 2020 00:53:04 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="HbiX8TpW" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1725800AbgJaAxE (ORCPT ); Fri, 30 Oct 2020 20:53:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47234 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725562AbgJaAxE (ORCPT ); Fri, 30 Oct 2020 20:53:04 -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 F1B90C0613D5 for ; Fri, 30 Oct 2020 17:53:03 -0700 (PDT) Received: by mail-pj1-x1044.google.com with SMTP id a17so157127pju.1 for ; Fri, 30 Oct 2020 17:53:03 -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=spIOXxEMAUaAi3lOJE/X7NHFHQM+sHFb8zQsSOCKb8k=; b=HbiX8TpWOGg9HTGYfSsYg6rLlPCFZN42eDXxmd11vnzQeg6tjeMJ/GGsBnd+tBIxnw XpUq4VfkCrOrs5VlUPRn6mdXGdJTI1DB105bsK3gHCLvDMswvbgrYKw7EOKvtuT+FhKu Nk0+kSnRY8Kv6GzbfWBsr79WAq6I0bqppdirY= 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=spIOXxEMAUaAi3lOJE/X7NHFHQM+sHFb8zQsSOCKb8k=; b=mGQmRSshqyFjZWCL30NIPlID/3DPOrGbimxLunDYaTnWcW4QtJzkLoEmp9g/DKXfi+ br4nXXevgyAwK3X8ggRTn+UlFKD4pQRJSyMhLdtkBlGL5jLtJ3oQ+FSUixQ2O+HhS9jZ ANVG4s5ywiVPBsd9RJcLMOX6aiPIu/zwoSnO2LD8NaQGbKXjFW0ypjFCCU0c4sRNMWRU CjFARDXYG6hMjwgbV9c2vz5vv4CY6qQlx2HWPy+9W1VU82ndh7w1sp1natZx4+j5+I4m ryjrU1ous6niICttu/gTXymDLWO2yzpley9qVqlKzIAzbsigIS98AEt2P+uXZb3vaUyq FtNA== X-Gm-Message-State: AOAM533v3tDjQGsZOL2E2H61A1q11kpCNiU1HhsTmjosmusbw9rL9mn7 dipRNvwWzz1Q4mYnqtLpkw4DnwUiAVaoCA== X-Google-Smtp-Source: ABdhPJzsZPKMZFVv0FL5Q6B154ZYVHu8Ntc80aSbghTvp53XiSDCc7J2OrJ4iCE3KNLYe/r4PWxsLA== X-Received: by 2002:a17:90a:341:: with SMTP id 1mr5913856pjf.189.1604105583053; Fri, 30 Oct 2020 17:53:03 -0700 (PDT) Received: from mcchou0.mtv.corp.google.com ([2620:15c:202:201:de4a:3eff:fe75:1314]) by smtp.gmail.com with ESMTPSA id p22sm4394292pju.48.2020.10.30.17.53.01 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 30 Oct 2020 17:53:02 -0700 (PDT) From: Miao-chen Chou To: Bluetooth Kernel Mailing List Cc: Alain Michaud , Manish Mandlik , Marcel Holtmann , chromeos-bluetooth-upstreaming@chromium.org, Howard Chung , Luiz Augusto von Dentz , Miao-chen Chou , Archie Pusaka , Sonny Sasaka Subject: [BlueZ PATCH v8 1/6] shared/ad: Add support of bt_ad_pattern Date: Fri, 30 Oct 2020 17:52:46 -0700 Message-Id: <20201030175219.BlueZ.v8.1.Ie670925d87068d24a6e5c2e7dd9dd0e88c89a7da@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 This adds struct bt_ad_pattern and helpers functions to facilitate pattern matching. Reviewed-by: Archie Pusaka Reviewed-by: Sonny Sasaka Reviewed-by: Howard Chung --- Changes in v8: - Modify signature of ad_replace_data() to avoid memory copy src/shared/ad.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++- src/shared/ad.h | 16 +++++ 2 files changed, 166 insertions(+), 1 deletion(-) diff --git a/src/shared/ad.c b/src/shared/ad.c index a34d7a147..23c8c34f4 100644 --- a/src/shared/ad.c +++ b/src/shared/ad.c @@ -31,6 +31,12 @@ struct bt_ad { struct queue *data; }; +struct pattern_match_info { + struct bt_ad *ad; + struct bt_ad_pattern *current_pattern; + struct bt_ad_pattern *matched_pattern; +}; + struct bt_ad *bt_ad_new(void) { struct bt_ad *ad; @@ -46,6 +52,65 @@ struct bt_ad *bt_ad_new(void) return bt_ad_ref(ad); } +static bool ad_replace_data(struct bt_ad *ad, uint8_t type, const void *data, + size_t len); + +static bool ad_is_type_valid(uint8_t type) +{ + if (type > BT_AD_3D_INFO_DATA && type != BT_AD_MANUFACTURER_DATA) + return false; + if (type < BT_AD_FLAGS) + return false; + + return true; +} + +struct bt_ad *bt_ad_new_with_data(size_t len, const uint8_t *data) +{ + struct bt_ad *ad; + uint16_t parsed_len = 0; + + if (data == NULL || !len) + return NULL; + + ad = bt_ad_new(); + if (!ad) + return NULL; + + while (parsed_len < len - 1) { + uint8_t d_len; + uint8_t d_type; + const uint8_t *d; + uint8_t field_len = data[0]; + + if (field_len == 0) + break; + + parsed_len += field_len + 1; + + if (parsed_len > len) + break; + + d = &data[2]; + d_type = data[1]; + d_len = field_len - 1; + + if (!ad_is_type_valid(d_type)) + goto failed; + + if (!ad_replace_data(ad, d_type, d, d_len)) + goto failed; + + data += field_len + 1; + } + + return ad; + +failed: + bt_ad_unref(ad); + return NULL; +} + struct bt_ad *bt_ad_ref(struct bt_ad *ad) { if (!ad) @@ -126,7 +191,7 @@ static bool data_type_match(const void *data, const void *user_data) return a->type == type; } -static bool ad_replace_data(struct bt_ad *ad, uint8_t type, void *data, +static bool ad_replace_data(struct bt_ad *ad, uint8_t type, const void *data, size_t len) { struct bt_ad_data *new_data; @@ -994,3 +1059,87 @@ void bt_ad_clear_data(struct bt_ad *ad) queue_remove_all(ad->data, NULL, NULL, data_destroy); } + +struct bt_ad_pattern *bt_ad_pattern_new(uint8_t type, size_t offset, size_t len, + const uint8_t *data) +{ + struct bt_ad_pattern *pattern; + + if (!data || !len || offset >= BT_AD_MAX_DATA_LEN || + len > BT_AD_MAX_DATA_LEN || offset + len > BT_AD_MAX_DATA_LEN) { + return NULL; + } + + if (!ad_is_type_valid(type)) + return NULL; + + pattern = new0(struct bt_ad_pattern, 1); + if (!pattern) + return NULL; + + pattern->len = len; + pattern->type = type; + pattern->offset = offset; + memcpy(pattern->data, data, len); + + return pattern; +} + +static void pattern_ad_data_match(void *data, void *user_data) +{ + struct bt_ad_data *ad_data = data; + struct pattern_match_info *info = user_data; + struct bt_ad_pattern *pattern; + + if (!ad_data || !info) + return; + + if (info->matched_pattern) + return; + + pattern = info->current_pattern; + + if (!pattern || ad_data->type != pattern->type) + return; + + if (ad_data->len < pattern->offset + pattern->len) + return; + + if (!memcmp(ad_data->data + pattern->offset, pattern->data, + pattern->len)) { + info->matched_pattern = pattern; + } +} + +static void pattern_match(void *data, void *user_data) +{ + struct bt_ad_pattern *pattern = data; + struct pattern_match_info *info = user_data; + + if (!pattern || !info) + return; + + if (info->matched_pattern) + return; + + info->current_pattern = pattern; + + bt_ad_foreach_data(info->ad, pattern_ad_data_match, info); +} + +struct bt_ad_pattern *bt_ad_pattern_match(struct bt_ad *ad, + struct queue *patterns) +{ + struct pattern_match_info info; + + if (!ad || queue_isempty(patterns)) + return NULL; + + info.ad = ad; + info.matched_pattern = NULL; + info.current_pattern = NULL; + + queue_foreach(patterns, pattern_match, &info); + + return info.matched_pattern; +} diff --git a/src/shared/ad.h b/src/shared/ad.h index 83eacab66..13adcb406 100644 --- a/src/shared/ad.h +++ b/src/shared/ad.h @@ -68,6 +68,7 @@ typedef void (*bt_ad_func_t)(void *data, void *user_data); struct bt_ad; +struct queue; struct bt_ad_manufacturer_data { uint16_t manufacturer_id; @@ -87,8 +88,17 @@ struct bt_ad_data { size_t len; }; +struct bt_ad_pattern { + uint8_t type; + uint8_t offset; + uint8_t len; + uint8_t data[BT_AD_MAX_DATA_LEN]; +}; + struct bt_ad *bt_ad_new(void); +struct bt_ad *bt_ad_new_with_data(size_t len, const uint8_t *data); + struct bt_ad *bt_ad_ref(struct bt_ad *ad); void bt_ad_unref(struct bt_ad *ad); @@ -156,3 +166,9 @@ void bt_ad_foreach_data(struct bt_ad *ad, bt_ad_func_t func, void *user_data); bool bt_ad_remove_data(struct bt_ad *ad, uint8_t type); void bt_ad_clear_data(struct bt_ad *ad); + +struct bt_ad_pattern *bt_ad_pattern_new(uint8_t type, size_t offset, + size_t len, const uint8_t *data); + +struct bt_ad_pattern *bt_ad_pattern_match(struct bt_ad *ad, + struct queue *patterns); From patchwork Sat Oct 31 00:52: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: 11871031 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.8 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 28A9AC00A89 for ; Sat, 31 Oct 2020 00:53:47 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A9FC2208B6 for ; Sat, 31 Oct 2020 00:53:46 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="DTrti4d9" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1725856AbgJaAxq (ORCPT ); Fri, 30 Oct 2020 20:53:46 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47346 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725536AbgJaAxq (ORCPT ); Fri, 30 Oct 2020 20:53:46 -0400 Received: from mail-pl1-x644.google.com (mail-pl1-x644.google.com [IPv6:2607:f8b0:4864:20::644]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DE174C0613D5 for ; Fri, 30 Oct 2020 17:53:45 -0700 (PDT) Received: by mail-pl1-x644.google.com with SMTP id p17so3788710pli.13 for ; Fri, 30 Oct 2020 17:53:45 -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=mJFigMo5EVxTjfOJtnz2Tv+fqutb00rMLRe9RV1oomg=; b=DTrti4d9RHChTOVaHbv16GGDcEZQQ/i4bAHTBw0nKA3ynMkAroYmTfQagEWa261YGb Ji9PT/ec4Y8qpimR8/krDXP5mUCQpgcLFzLDCCcK1I6GFnoG80HsBfb2/Gugrn0xA7Jy zre5pwX/Y3VaQS7jNnXefW/gY+hciDNFyhigc= 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=mJFigMo5EVxTjfOJtnz2Tv+fqutb00rMLRe9RV1oomg=; b=PTobtEYtdywpTCU4Syzgn7ndk+VuIjoKGOnjs2RVt/tBhUFA+v2Pyhjnk18Utgz1wW 1lY/9nc4zwAoUAnHMICp0VyFCiMFtPm6zsi1hRIIXwsks8enWk8ndjXrrdXY2VfoMmAG 2r6ONBFaEUJ/yPHz/60rCvg3DoyZ8G8QvWNZROhG8wVbj6cq+IYQy+g2JcG8flJ3gKCr 2ULq6++DAYuCeJBwlcXBJ9wwtVRcTV6CizOCvfk3AW6tmiwFHYXhHoSBlmNhrPDJaQF1 CRHWAQ/v7Ulm1Fe2HOgJ1Ya4M1WLYufJJJNq3OkB3Hlg7QFYQUL793AYfGxgescAK1ko ZYlw== X-Gm-Message-State: AOAM530eXSSNF/LoXfucMw51Z3qJL3f6odLwjZkkmYaelJKQxJJDMoZS sSwLej2TYU96+wM8ZhsFEck8kzKloWR36Q== X-Google-Smtp-Source: ABdhPJykeW9i60DcMDeVN0DTTfCH09EQj+oTlhGhAaxIqMzhbetsy5CbgNuSyZ86rhJLucizocgkTA== X-Received: by 2002:a17:90a:5892:: with SMTP id j18mr4582720pji.101.1604105624882; Fri, 30 Oct 2020 17:53:44 -0700 (PDT) Received: from mcchou0.mtv.corp.google.com ([2620:15c:202:201:de4a:3eff:fe75:1314]) by smtp.gmail.com with ESMTPSA id p22sm4394292pju.48.2020.10.30.17.53.43 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 30 Oct 2020 17:53:44 -0700 (PDT) From: Miao-chen Chou To: Bluetooth Kernel Mailing List Cc: Alain Michaud , Manish Mandlik , Marcel Holtmann , chromeos-bluetooth-upstreaming@chromium.org, Howard Chung , Luiz Augusto von Dentz , Manish Mandlik , Miao-chen Chou , Abhishek Pandit-Subedi Subject: [BlueZ PATCH v8 2/6] adv_monitor: Implement RSSI filtering and content matching Date: Fri, 30 Oct 2020 17:52:48 -0700 Message-Id: <20201030175219.BlueZ.v8.2.I2830b9c1212a64b062201ed9f2b71294f50ad22d@changeid> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20201030175219.BlueZ.v8.1.Ie670925d87068d24a6e5c2e7dd9dd0e88c89a7da@changeid> References: <20201030175219.BlueZ.v8.1.Ie670925d87068d24a6e5c2e7dd9dd0e88c89a7da@changeid> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Manish Mandlik This implements the following logic for background scanning. - Implement RSSI tracking based on high/low RSSI thresholds and timers. - Create an entry point in adapter to start the matching of Adv based on all monitors and invoke the RSSI tracking for Adv reporting. Co-authored-by: Miao-chen Chou Reviewed-by: Abhishek Pandit-Subedi Reviewed-by: Alain Michaud Reviewed-by: Howard Chung --- Changes in v8: - Merge the content matching patch to this commit. Changes in v7: - Add logs to NULL check of objects to reveal potential bugs - Rename some members of struct adv_monitor_device - Replace the use of GSList with struct queue - Adopt bt_ad_pattern from shared/ad Changes in v6: - Fix the termination condition of AD data paring and remove unnecessary length check Changes in v5: - Remove the use of unit test in commit message - Remove unittest helper functions Changes in v3: - Fix commit message - Remove unused variables - Fix signature of queue_find() doc/advertisement-monitor-api.txt | 5 + src/adapter.c | 45 ++- src/adv_monitor.c | 443 +++++++++++++++++++++++++++--- src/adv_monitor.h | 18 ++ 4 files changed, 467 insertions(+), 44 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 c0053000a..0e3fd57f3 100644 --- a/src/adapter.c +++ b/src/adapter.c @@ -1214,6 +1214,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); @@ -6596,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); @@ -6645,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; } @@ -6713,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 e441a5566..9a04da6e1 100644 --- a/src/adv_monitor.c +++ b/src/adv_monitor.c @@ -26,9 +26,9 @@ #include "adapter.h" #include "dbus-common.h" +#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" @@ -81,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; @@ -95,13 +88,34 @@ 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; + struct queue *patterns; /* List of bt_ad_pattern objects */ +}; + +/* 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 found; /* State of the device - lost/found */ + guint lost_timer; /* Timer to track if the device goes + * offline/out-of-range + */ }; struct app_match_data { @@ -109,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; @@ -131,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); } @@ -150,6 +175,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); @@ -248,6 +276,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; @@ -436,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); @@ -468,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); @@ -923,3 +934,361 @@ 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) +{ + const struct adv_monitor_device *dev = a; + const struct btd_device *device = b; + + if (!dev) { + error("Unexpected NULL adv_monitor_device object upon match"); + 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) { + error("Unexpected NULL adv_monitor_device object upon free"); + return; + } + + if (dev->lost_timer) { + g_source_remove(dev->lost_timer); + dev->lost_timer = 0; + } + + dev->monitor = NULL; + dev->device = NULL; + + 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) { + error("Unexpected NULL adv_monitor object upon device remove"); + 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) { + error("Unexpected NULL adv_monitor_app object upon device " + "remove"); + 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 = new0(struct adv_monitor_device, 1); + 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->lost_timer = 0; + + if (dev->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->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->lost_timer) { + g_source_remove(dev->lost_timer); + dev->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->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->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->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->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->found) { + dev->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 5cb372217..2b4f68abf 100644 --- a/src/adv_monitor.h +++ b/src/adv_monitor.h @@ -11,13 +11,31 @@ #ifndef __ADV_MONITOR_H #define __ADV_MONITOR_H +#include + +#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); + #endif /* __ADV_MONITOR_H */ From patchwork Sat Oct 31 00:52: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: 11871033 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.9 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6DCF2C00A89 for ; Sat, 31 Oct 2020 00:54:17 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1D7B0208B6 for ; Sat, 31 Oct 2020 00:54:17 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="HQqR9mmN" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1725899AbgJaAyQ (ORCPT ); Fri, 30 Oct 2020 20:54:16 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47420 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725536AbgJaAyQ (ORCPT ); Fri, 30 Oct 2020 20:54:16 -0400 Received: from mail-pl1-x632.google.com (mail-pl1-x632.google.com [IPv6:2607:f8b0:4864:20::632]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 28C31C0613D5 for ; Fri, 30 Oct 2020 17:54:15 -0700 (PDT) Received: by mail-pl1-x632.google.com with SMTP id r3so3822545plo.1 for ; Fri, 30 Oct 2020 17:54:15 -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=QbH7X4Il4bbJD/ePRdn06r3YRB9WAND3qaqaTTHKOcY=; b=HQqR9mmNqsNRFBSi4bGHA7uMRsb8ob2gIBtiQLjTq58TtWLcAtoH8prhXrNPMDUx6e r27C9hG7X7iI756Se6a7BluQORygXASFgg30wKf335wlAja/otqcqJ0owzTIacMPOak9 524G/Dv32ubsrnsJFpXf0P3yUiFBOfddbfPl4= 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=QbH7X4Il4bbJD/ePRdn06r3YRB9WAND3qaqaTTHKOcY=; b=Nmtkh03Ha6MK+7x3KrXImK0AeXmAvLKeK0xiXM+IR2CWx+a5efR8MIUD9n3KffVK/h 9y571rt65Onqa/RIaK8LM1exaaiAf4t6vwActGV5YGzgl49ptY7YtAJyUkCifbLLVyPJ rSoG0tnLxtjCQDdlNkHnGb6TO3T4OqwPa320Paj2b4VvITGgCauTf9ZzDd9bJm6YZDuV A/chXesEDEzjTn+xWJ9mJ8nPuYKnaWY7wSB3+9sF4aYAOrL/V/oMsqtzbqBPOq44zffJ wAYcirp6SODcYaYHpAMQbV/NbvMUfGJBymHGeQ2ACKjIcGYdZCnZ89DNVo4wuQw1gJho h7ug== X-Gm-Message-State: AOAM532pwIoH9SC1AgMSrwI6jFcUznoLoa10+kWYyciQZsNpWNS3xxki e6EuqJOKZtqpayozmOJcAw6Rb3GBZh1lTg== X-Google-Smtp-Source: ABdhPJxhqTVpINamM24MD4iYxl9k7w59eczXXkSnRM9UmaO+0HstqlocccEI428xpUusROqMAKOq5w== X-Received: by 2002:a17:90b:3501:: with SMTP id ls1mr5642978pjb.26.1604105654462; Fri, 30 Oct 2020 17:54:14 -0700 (PDT) Received: from mcchou0.mtv.corp.google.com ([2620:15c:202:201:de4a:3eff:fe75:1314]) by smtp.gmail.com with ESMTPSA id p22sm4394292pju.48.2020.10.30.17.54.13 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 30 Oct 2020 17:54:13 -0700 (PDT) From: Miao-chen Chou To: Bluetooth Kernel Mailing List Cc: Alain Michaud , Manish Mandlik , Marcel Holtmann , chromeos-bluetooth-upstreaming@chromium.org, Howard Chung , Luiz Augusto von Dentz , Miao-chen Chou Subject: [BlueZ PATCH v8 3/6] adapter: Clear all Adv monitors upon bring-up Date: Fri, 30 Oct 2020 17:52:50 -0700 Message-Id: <20201030175219.BlueZ.v8.3.Id6bfe7838831ae01fddc8605689dd77b51673960@changeid> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20201030175219.BlueZ.v8.1.Ie670925d87068d24a6e5c2e7dd9dd0e88c89a7da@changeid> References: <20201030175219.BlueZ.v8.1.Ie670925d87068d24a6e5c2e7dd9dd0e88c89a7da@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 0e3fd57f3..0f855d848 100644 --- a/src/adapter.c +++ b/src/adapter.c @@ -9509,6 +9509,43 @@ failed: btd_adapter_unref(adapter); } +static void reset_adv_monitors_complete(uint8_t status, uint16_t length, + const void *param, void *user_data) +{ + const struct mgmt_rp_remove_adv_monitor *rp = param; + + if (status != MGMT_STATUS_SUCCESS) { + 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) { @@ -9523,6 +9560,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 Sat Oct 31 00:52: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: 11871035 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.8 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D28F3C00A89 for ; Sat, 31 Oct 2020 00:54:38 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 667AF208B6 for ; Sat, 31 Oct 2020 00:54:38 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="FZWxAOq0" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1725929AbgJaAyi (ORCPT ); Fri, 30 Oct 2020 20:54:38 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47480 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725536AbgJaAyh (ORCPT ); Fri, 30 Oct 2020 20:54:37 -0400 Received: from mail-pf1-x431.google.com (mail-pf1-x431.google.com [IPv6:2607:f8b0:4864:20::431]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C4A1FC0613D5 for ; Fri, 30 Oct 2020 17:54:37 -0700 (PDT) Received: by mail-pf1-x431.google.com with SMTP id j18so6745593pfa.0 for ; Fri, 30 Oct 2020 17:54:37 -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=Vbm2G0CMB9LM7u+swDDvdXCapbs/ILYy5Hy3KLSMPmg=; b=FZWxAOq0RxWCvVLNbbh6yafIrVPD3E/rKvYX80Aqn0x0HxnfL4HyvVshFZrSThbfu+ QIohAS/O06CuGLnSU3XVSS1MduFJQdWc/MwzhSH051eZEy0BG/mSXAC2SIh6TIKKajB9 zbYFf3gqKW31OGfGBf74tEdltH8pseV/S2FAA= 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=Vbm2G0CMB9LM7u+swDDvdXCapbs/ILYy5Hy3KLSMPmg=; b=s1wbrMY0mC6Aq4z1xeSgEA61FQxKZZITIWkiJ9DqZFLGOFJVQ3/EfxI5l7HsTznTqK 9B5h/lcWeR1BWzKdPKzLWRNBXucvCZUl+h7hkk0ERjC2X5botmXIHKvimTAm9p43EoFU cOG0mtuQEe6sK+55x2Kx9qm6+PYpuMl+jfEXSUTsKrT9RSWKRqMIJgiKF1+nMmgvIiD3 tTfUsjjiGt10bBZbwExXO0TFpT9yrhdDkwALHg9nsPN2S+wZEbSYM06DsYFPuznIlyCB Cth6AcjncJdk4PXW2tLPMP958r/HglCsVIDIqSB5/KcffxwOXafh+jNnVKJgfSgEIW70 G+xw== X-Gm-Message-State: AOAM533cXjUgq+qo+miM+VfBNleIe81BxyJ+DZRcDQMpXGNYmhyadouy dQbUi8Bp4OfFA3TLB3lc/6C2eBKCCB2+wA== X-Google-Smtp-Source: ABdhPJyMXo5OqbKUJB2Kjug4XIbqjs+Uwyn/sCwSLaTZI+S3dXQ54hcem6kY4/KT9VQA1Zhv9APKSA== X-Received: by 2002:a63:ea0f:: with SMTP id c15mr4286796pgi.367.1604105677045; Fri, 30 Oct 2020 17:54:37 -0700 (PDT) Received: from mcchou0.mtv.corp.google.com ([2620:15c:202:201:de4a:3eff:fe75:1314]) by smtp.gmail.com with ESMTPSA id p22sm4394292pju.48.2020.10.30.17.54.35 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 30 Oct 2020 17:54:36 -0700 (PDT) From: Miao-chen Chou To: Bluetooth Kernel Mailing List Cc: Alain Michaud , Manish Mandlik , Marcel Holtmann , chromeos-bluetooth-upstreaming@chromium.org, Howard Chung , Luiz Augusto von Dentz , Miao-chen Chou Subject: [BlueZ PATCH v8 4/6] adv_monitor: mplement Add Adv Patterns Monitor cmd handler Date: Fri, 30 Oct 2020 17:52:52 -0700 Message-Id: <20201030175219.BlueZ.v8.4.Ibbcb11712b613ef95c31b41207c3ea945c830018@changeid> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20201030175219.BlueZ.v8.1.Ie670925d87068d24a6e5c2e7dd9dd0e88c89a7da@changeid> References: <20201030175219.BlueZ.v8.1.Ie670925d87068d24a6e5c2e7dd9dd0e88c89a7da@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 Reviewed-by: Alain Michaud Reviewed-by: Miao-chen Chou Reviewed-by: Manish Mandlik --- (no changes since v7) Changes in v7: - Rename MONITOR_STATE_HONORED to MONITOR_STATE_ACTIVE - Rebase on the adoption of bt_ad_pattern src/adv_monitor.c | 69 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/src/adv_monitor.c b/src/adv_monitor.c index 9a04da6e1..9d2a400a3 100644 --- a/src/adv_monitor.c +++ b/src/adv_monitor.c @@ -78,7 +78,7 @@ enum monitor_state { MONITOR_STATE_NEW, /* New but not yet init'ed with actual values */ 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_ACTIVE, /* Accepted by kernel */ }; struct adv_monitor { @@ -545,11 +545,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_ACTIVE; + + DBG("Calling Activate() on Adv Monitor of owner %s at path %s", + monitor->app->owner, monitor->path); + + g_dbus_proxy_method_call(monitor->proxy, "Activate", NULL, NULL, NULL, + NULL); + + 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 bt_ad_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); @@ -582,7 +630,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 */ @@ -946,7 +1011,7 @@ static void adv_match_per_monitor(void *data, void *user_data) return; } - if (monitor->state != MONITOR_STATE_HONORED) + if (monitor->state != MONITOR_STATE_ACTIVE) return; if (monitor->type == MONITOR_TYPE_OR_PATTERNS && From patchwork Sat Oct 31 00:52: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: 11871037 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.8 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C3F9DC00A89 for ; Sat, 31 Oct 2020 00:54:59 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7C4A7208B6 for ; Sat, 31 Oct 2020 00:54:59 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="gxPM4jB/" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1725959AbgJaAy7 (ORCPT ); Fri, 30 Oct 2020 20:54:59 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47532 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725536AbgJaAy7 (ORCPT ); Fri, 30 Oct 2020 20:54:59 -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 9131CC0613D5 for ; Fri, 30 Oct 2020 17:54:57 -0700 (PDT) Received: by mail-pj1-x1044.google.com with SMTP id a3so157741pjh.1 for ; Fri, 30 Oct 2020 17:54:57 -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=DZl3oN00arRcB58FBKAJ5c/slPFqplS5wnLF/UKMxhY=; b=gxPM4jB/KDfsNp7nG1JfjGSV7C4YlJfdE/xqs8+BtTxTUx71ehfLKviJWoAYM6hhNe +5qXdoSVQVPf+8A8w6/QRhZvbgO8Z/nwYnYieyPCHQXxLjmTVLxaO2tXK3QZwYbbBxXv Wk0WKWey2KBpPK/RMEu2QY9VhZBSWE6I8QuUM= 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=DZl3oN00arRcB58FBKAJ5c/slPFqplS5wnLF/UKMxhY=; b=ZouHNc13nbFp/QRGylqwiIl8rX8D/NLdDnGixGvNCLeHg4IfsLHZEwaPdBBYrvw1K0 fvuTlK/nhUPC65DAis8AJ5tVVFqrC8fEKamerIpLoNRohYYELA2tPg3/8WiDUgQ7Laww GQ/cWIs4A0iXXLdhto1b+kVjqpzBRk6XndS0OUGp8fXeQha9FGnDBzo7DXRyDkSVxgZJ nlj+LnPRfGfeYhDeYlMI6x+QLCkKyGY0fCHfHtGbzc36EujQDc0+78q95k5gITdm23Y/ VGjUlxylEHrM8qbCoTHnWq1Q4hsFcs+DJjWKt4lOAsoFAFRSKOxjlhHllGh9HE4pdQJo cUjA== X-Gm-Message-State: AOAM5326AjT5aTGDmRz8n39Vrpbl25Fyg8gDSRvSC1ocW4t035YV5ATw jSvKN8SawKF7p4jHcgtCksrBupwx2cer/A== X-Google-Smtp-Source: ABdhPJzUu2Xx8enU857WMjcBo66SJNxdZ1uM4OjcWsJdVPHXGer6amLTre1IrHeY25jkHvl8k8Dtlg== X-Received: by 2002:a17:902:b111:b029:d4:cf7c:2ff1 with SMTP id q17-20020a170902b111b02900d4cf7c2ff1mr11699802plr.59.1604105696857; Fri, 30 Oct 2020 17:54:56 -0700 (PDT) Received: from mcchou0.mtv.corp.google.com ([2620:15c:202:201:de4a:3eff:fe75:1314]) by smtp.gmail.com with ESMTPSA id p22sm4394292pju.48.2020.10.30.17.54.55 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 30 Oct 2020 17:54:56 -0700 (PDT) From: Miao-chen Chou To: Bluetooth Kernel Mailing List Cc: Alain Michaud , Manish Mandlik , Marcel Holtmann , chromeos-bluetooth-upstreaming@chromium.org, Howard Chung , Luiz Augusto von Dentz , Miao-chen Chou Subject: [BlueZ PATCH v8 5/6] adv_monitor: Fix return type of RegisterMonitor() method Date: Fri, 30 Oct 2020 17:52:54 -0700 Message-Id: <20201030175219.BlueZ.v8.5.Ic8dbe9115e82704b4c0c860eee27ad897db13237@changeid> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20201030175219.BlueZ.v8.1.Ie670925d87068d24a6e5c2e7dd9dd0e88c89a7da@changeid> References: <20201030175219.BlueZ.v8.1.Ie670925d87068d24a6e5c2e7dd9dd0e88c89a7da@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 9d2a400a3..dbc3b2a92 100644 --- a/src/adv_monitor.c +++ b/src/adv_monitor.c @@ -694,6 +694,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 @@ -705,8 +707,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; } @@ -800,7 +800,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 Sat Oct 31 00:52:56 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: 11871041 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.8 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3A214C00A89 for ; Sat, 31 Oct 2020 00:55:51 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B1DE1221EB for ; Sat, 31 Oct 2020 00:55:50 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="drnWc/4/" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1725929AbgJaAzu (ORCPT ); Fri, 30 Oct 2020 20:55:50 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47668 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725446AbgJaAzt (ORCPT ); Fri, 30 Oct 2020 20:55:49 -0400 Received: from mail-pg1-x543.google.com (mail-pg1-x543.google.com [IPv6:2607:f8b0:4864:20::543]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CEA18C0613D5 for ; Fri, 30 Oct 2020 17:55:49 -0700 (PDT) Received: by mail-pg1-x543.google.com with SMTP id r10so6549775pgb.10 for ; Fri, 30 Oct 2020 17:55:49 -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=vdaUfJz7jmPFx2W5HccvMKbsFaBAEhWGV3O/WxZs7oI=; b=drnWc/4/MtEWrmmqokp7IdUs/SXhYoPoVNnhtRsnx7jNh4dbqtAtXUwNEWsve76+n9 3PX3zAg3aRefdv/wWxVoMtq4kN1tkZGhshwy7CWLN3nE2lgqNRSuOs5womGD57isKu1/ //OQcI0AA07BIJ7QcC+1hTy9kcqE8Y6t0AWCw= 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=vdaUfJz7jmPFx2W5HccvMKbsFaBAEhWGV3O/WxZs7oI=; b=tiyrYclakxXoivEMIb4oG7rCu5bBiETxYDLZjLRc0YzO4GDRNw7QDfrkbTHV0uCGQF 4DNYYtecqD+ZCrbXXCOaEwpqSxYdjX2Zhj+nOPjGjlWanHWgmJXUWW8YgJ9SGWT3/xtn 3s1BBrxVxMC/hlfDhB9k6JLjWCCASGe+Hvth3pQeWsPu8NcFn+9rFJLz10jqHpZWwPu7 j1sEuIhHNoyY7ykuLBM7qP5yTqTWxLByXbDricaRNMTlS5QHAasUrq9rx4Pe2b2osu1R ZU+hoRonX5bKXzQFaU56HfERTS87XCtU5jq0R0mKxdD0502Lsx7O9xTs4KYcCiO3Yn6y Lyug== X-Gm-Message-State: AOAM533rR9Tj+C6hT5gxd9NYhCFoLo6BLyH3QtbN4Smwwn5KOejqyLMd 6v0aAYg54l4Rx90GDyuqBkIn7Xsoxpzt6w== X-Google-Smtp-Source: ABdhPJzXVHmhegh4q4aJbuuRXI8ZTgpGXjD7a/E5GNucvzN1GyEYw7mG0E/GlZD7EwK+yoz7nt/w1A== X-Received: by 2002:a63:731e:: with SMTP id o30mr4257264pgc.179.1604105748955; Fri, 30 Oct 2020 17:55:48 -0700 (PDT) Received: from mcchou0.mtv.corp.google.com ([2620:15c:202:201:de4a:3eff:fe75:1314]) by smtp.gmail.com with ESMTPSA id p22sm4394292pju.48.2020.10.30.17.55.47 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 30 Oct 2020 17:55:48 -0700 (PDT) From: Miao-chen Chou To: Bluetooth Kernel Mailing List Cc: Alain Michaud , Manish Mandlik , Marcel Holtmann , chromeos-bluetooth-upstreaming@chromium.org, Howard Chung , Luiz Augusto von Dentz Subject: [BlueZ PATCH v8 6/6] adv_monitor: Issue Remove Adv Monitor mgmt call Date: Fri, 30 Oct 2020 17:52:56 -0700 Message-Id: <20201030175219.BlueZ.v8.6.Ifda683c92ff520bf58ac37c02dc40b8d9598d1b0@changeid> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20201030175219.BlueZ.v8.1.Ie670925d87068d24a6e5c2e7dd9dd0e88c89a7da@changeid> References: <20201030175219.BlueZ.v8.1.Ie670925d87068d24a6e5c2e7dd9dd0e88c89a7da@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 Reviewed-by: Alain Michaud --- (no changes since v7) Changes in v7: - Rename MONITOR_STATE_HONORED to MONITOR_STATE_ACTIVE Changes in v4: - Fix build error Changes in v3: - Fix const qualifier of a pointer src/adv_monitor.c | 132 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 124 insertions(+), 8 deletions(-) diff --git a/src/adv_monitor.c b/src/adv_monitor.c index dbc3b2a92..c786015c8 100644 --- a/src/adv_monitor.c +++ b/src/adv_monitor.c @@ -79,6 +79,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_ACTIVE, /* Accepted by kernel */ + MONITOR_STATE_REMOVING, /* Removing from kernel */ }; struct adv_monitor { @@ -87,6 +88,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 */ @@ -567,6 +569,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_ACTIVE; DBG("Calling Activate() on Adv Monitor of owner %s at path %s", @@ -575,8 +578,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) @@ -650,20 +652,77 @@ 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; - 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_ACTIVE) + 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 */ @@ -872,6 +931,59 @@ static const GDBusPropertyTable adv_monitor_properties[] = { { } }; +/* Matches a monitor based on its handle */ +static bool removed_monitor_match(const void *data, const void *user_data) +{ + const uint16_t *handle = user_data; + const struct adv_monitor *monitor = data; + + if (!data || !handle) + return false; + + return monitor->monitor_handle == *handle; +} + +/* 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_ACTIVE) + 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 btd_adv_monitor_manager *manager = user_data; + const struct mgmt_ev_adv_monitor_removed *ev = param; + uint16_t handle = ev->monitor_handle; + 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, &handle); + + 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, @@ -891,6 +1003,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; }