shared/ad: Add support of bt_ad_pattern
authorMiao-chen Chou <mcchou@chromium.org>
Sat, 31 Oct 2020 00:52:46 +0000 (17:52 -0700)
committerAyush Garg <ayush.garg@samsung.com>
Fri, 11 Mar 2022 13:38:33 +0000 (19:08 +0530)
This adds struct bt_ad_pattern and helpers functions to facilitate
pattern matching.

Signed-off-by: Anuj Jain <anuj01.jain@samsung.com>
Signed-off-by: Ayush Garg <ayush.garg@samsung.com>
src/shared/ad.c
src/shared/ad.h

index b989c31..5cc1088 100755 (executable)
@@ -25,6 +25,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;
@@ -40,6 +46,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)
@@ -120,7 +185,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;
@@ -988,3 +1053,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;
+}
index 83eacab..13adcb4 100755 (executable)
@@ -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);