OSDN Git Service

Advertisement parsing fix for zero padding
authorJakub Pawlowski <jpawlowski@google.com>
Fri, 4 Aug 2017 15:56:53 +0000 (08:56 -0700)
committerAndre Eisenbach <eisenbach@google.com>
Mon, 7 Aug 2017 21:10:59 +0000 (21:10 +0000)
When AD data is zero padded, and Scan Response is appended at end, data
becomes invalid. Instead, zero paddning must be removed first.

Test: AdvertiseDataParserTest.RemoveTrailingZeros
Bug: 38489707
Change-Id: I229ca3db6c92bc06bc1429e72412417010721063
Merged-In: I229ca3db6c92bc06bc1429e72412417010721063
(cherry picked from commit 35a9ea352d59e6d261eba1254814f7238e3ed022)

stack/btm/btm_ble_gap.cc
stack/include/advertise_data_parser.h
stack/test/ad_parser_unittest.cc

index be12e61..fe093e2 100644 (file)
@@ -2103,11 +2103,14 @@ static void btm_ble_process_adv_pkt_cont(
   bool is_scannable = ble_evt_type_is_scannable(evt_type);
   bool is_scan_resp = ble_evt_type_is_scan_resp(evt_type);
 
+  bool is_start =
+      ble_evt_type_is_legacy(evt_type) && is_scannable && !is_scan_resp;
+
+  if (is_start) AdvertiseDataParser::RemoveTrailingZeros(tmp);
+
   // We might have send scan request to this device before, but didn't get the
   // response. In such case make sure data is put at start, not appended to
   // already existing data.
-  bool is_start =
-      ble_evt_type_is_legacy(evt_type) && is_scannable && !is_scan_resp;
   std::vector<uint8_t> const& adv_data =
       is_start ? cache.Set(addr_type, bda, std::move(tmp))
                : cache.Append(addr_type, bda, std::move(tmp));
index 1c5f99f..0efac4f 100644 (file)
 
 class AdvertiseDataParser {
  public:
+  static void RemoveTrailingZeros(std::vector<uint8_t>& ad) {
+    size_t position = 0;
+
+    size_t ad_len = ad.size();
+    while (position != ad_len) {
+      uint8_t len = ad[position];
+
+      // A field length of 0 would be invalid as it should at least contain the
+      // EIR field type. However, some existing devices send zero padding at the
+      // end of advertisement. If this is the case, cut the zero padding from
+      // end of the packet. Otherwise i.e. gluing scan response to advertise
+      // data will result in data with zero padding in the middle.
+      if (len == 0) {
+        size_t zeros_start = position;
+        for (size_t i = position + 1; i < ad_len; i++) {
+          if (ad[i] != 0) return;
+        }
+
+        ad.erase(ad.begin() + zeros_start, ad.end());
+        return;
+      }
+
+      if (position + len >= ad_len) {
+        return;
+      }
+
+      position += len + 1;
+    }
+  }
+
   /**
    * Return true if this |ad| represent properly formatted advertising data.
    */
index 3202130..ab6df56 100644 (file)
@@ -100,4 +100,25 @@ TEST(AdvertiseDataParserTest, GetFieldByType) {
   data = AdvertiseDataParser::GetFieldByType(data1, 0x03, &p_length);
   EXPECT_EQ(nullptr, data);
   EXPECT_EQ(0, p_length);
+}
+
+// This test makes sure that RemoveTrailingZeros is working correctly. It does
+// run the RemoveTrailingZeros for ad data, then glue scan response at end of
+// it, and checks that the resulting data is good.
+TEST(AdvertiseDataParserTest, RemoveTrailingZeros) {
+  std::vector<uint8_t> podo_ad_data{
+      0x02, 0x01, 0x02, 0x11, 0x06, 0x66, 0x9a, 0x0c, 0x20, 0x00, 0x08,
+      0x37, 0xa8, 0xe5, 0x11, 0x81, 0x8b, 0xd0, 0xf0, 0xf0, 0xf0, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+  const std::vector<uint8_t> podo_scan_resp{
+      0x03, 0x19, 0x00, 0x80, 0x09, 0x09, 0x50, 0x6f, 0x64, 0x6f, 0x51,
+      0x35, 0x56, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+  AdvertiseDataParser::RemoveTrailingZeros(podo_ad_data);
+
+  std::vector<uint8_t> glued(podo_ad_data);
+  glued.insert(glued.end(), podo_ad_data.begin(), podo_ad_data.end());
+
+  EXPECT_TRUE(AdvertiseDataParser::IsValid(glued));
 }
\ No newline at end of file