diff mbox series

[BlueZ,v8,1/6] shared/ad: Add support of bt_ad_pattern

Message ID 20201030175219.BlueZ.v8.1.Ie670925d87068d24a6e5c2e7dd9dd0e88c89a7da@changeid (mailing list archive)
State Accepted
Headers show
Series [BlueZ,v8,1/6] shared/ad: Add support of bt_ad_pattern | expand

Commit Message

Miao-chen Chou Oct. 31, 2020, 12:52 a.m. UTC
This adds struct bt_ad_pattern and helpers functions to facilitate
pattern matching.

Reviewed-by: Archie Pusaka <apusaka@chromium.org>
Reviewed-by: Sonny Sasaka <sonnysasaka@chromium.org>
Reviewed-by: Howard Chung <howardchung@google.com>
---

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(-)

Comments

Luiz Augusto von Dentz Nov. 2, 2020, 5:55 p.m. UTC | #1
Hi Miao,

On Fri, Oct 30, 2020 at 5:56 PM Miao-chen Chou <mcchou@chromium.org> wrote:
>
> This adds struct bt_ad_pattern and helpers functions to facilitate
> pattern matching.
>
> Reviewed-by: Archie Pusaka <apusaka@chromium.org>
> Reviewed-by: Sonny Sasaka <sonnysasaka@chromium.org>
> Reviewed-by: Howard Chung <howardchung@google.com>
> ---
>
> 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);
> --
> 2.26.2

Applied, thanks.
diff mbox series

Patch

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);