interop: Add support for Version based Blacklisting

Add support for Version based blacklisting to IOP database.

CRs-Fixed: 2432078
Change-Id: I6bf26fd511f7378a2e537ffde49b086207449b9a
diff --git a/system_bt_ext/conf/interop_database.conf b/system_bt_ext/conf/interop_database.conf
index 05f2d89..d909adf 100644
--- a/system_bt_ext/conf/interop_database.conf
+++ b/system_bt_ext/conf/interop_database.conf
@@ -8,7 +8,7 @@
 #1. Below are the four tags for blacklist
 #   A. Address_Based   C. Manufacturer_based
 #   B. Name_Based      D. Vndr_Prdt_Based
-#   E. SSR_Max_Lat_Based
+#   E. SSR_Max_Lat_Based F: Version_Based
 ##
 #   A. Address_Based :  This tag refers to Address based blacklist
 #   Input Type       :   Input value should be only 3 to 6 bytes of BD address
@@ -28,16 +28,21 @@
 #####
 #   D. Vndr_Prdt_Based : This tag refers to vendor and product based blacklist
 #   Input type  : Input should be in Hexadecimal value
-#   Format Type : 4 bytes hex value( 2bytes of vendor  and 2 bytes of product),
+#   Format Type : 4 bytes hex value( 2 bytes of vendor  and 2 bytes of product),
 #                 Vendor and product hex values should be separated with delimiter(-).
 #   Examples    : 0X00AB-0X00BC = Vndr_Prdt_Based
 #####
-#   E. SSR_Max_Lat_Based : This tag refers to SSR Max LAtency based blacklist
+#   E. SSR_Max_Lat_Based : This tag refers to SSR Max Latency based blacklist
 #   Input type  : Input value should be combination of first 3 bytes of BD address and
 #                 Hexadecimal value of SSR Max Latency
 #   Format Type : Address should be in XX:XX:XX format followed by 2 bytes hex value
 #                 of max latency Address and Max Latency should be separated with delimiter(-).
 #   Examples    : 00:01:03-0X00AB = SSR_Max_Lat_Based
+#####
+#   F. Version_Based : This tag refers to DID Version based blacklist
+#   Input type  : Input value should be Hexadecimal value
+#   Format Type : 2 bytes hex value
+#   Examples    : 0X00AB = Version_Based
 # ******************************* Start of Blacklist Database ********************************
 #Disable secure connections
 #This is for pre BT 4.1/2 devices that do not handle secure mode very well.
diff --git a/system_bt_ext/device/include/interop_config.h b/system_bt_ext/device/include/interop_config.h
index a2c5e62..35f3e8c 100644
--- a/system_bt_ext/device/include/interop_config.h
+++ b/system_bt_ext/device/include/interop_config.h
@@ -34,6 +34,7 @@
 void interop_database_add_vndr_prdt(const interop_feature_t feature, uint16_t vendor_id, uint16_t product_id);
 void interop_database_add_addr_max_lat(const interop_feature_t feature, const RawAddress *addr,
           size_t length, uint16_t max_lat);
+void interop_database_add_version(const interop_feature_t feature, uint16_t version);
 
 // API's for removing entries from dynamic interop database
 bool interop_database_remove_addr(const interop_feature_t feature, const RawAddress *addr);
@@ -42,6 +43,7 @@
 bool interop_database_remove_vndr_prdt(const interop_feature_t feature, uint16_t vendor_id, uint16_t product_id);
 bool interop_database_remove_addr_max_lat(const interop_feature_t feature,
           const RawAddress *addr, size_t length, uint16_t max_lat);
+bool interop_database_remove_version(const interop_feature_t feature, uint16_t version);
 
 // API's to match entries with in dynamic interop database
 bool interop_database_match_addr(const interop_feature_t feature, const RawAddress *addr);
@@ -50,4 +52,5 @@
 bool interop_database_match_vndr_prdt(const interop_feature_t feature, uint16_t vendor_id, uint16_t product_id);
 bool interop_database_match_addr_get_max_lat(const interop_feature_t feature,
           const RawAddress *addr, uint16_t *max_lat);
+bool interop_database_match_version(const interop_feature_t feature, uint16_t version);
 
diff --git a/system_bt_ext/device/src/interop.cc b/system_bt_ext/device/src/interop.cc
index 637fe44..2381669 100644
--- a/system_bt_ext/device/src/interop.cc
+++ b/system_bt_ext/device/src/interop.cc
@@ -69,6 +69,7 @@
 #define VALID_VNDR_PRDT_LEN   (13)
 #define VALID_MNFR_STR_LEN    (6)
 #define VALID_SSR_LAT_LEN   (15)
+#define VALID_VERSION_LEN   (6)
 #define VENDOR_VALUE_SEPARATOR  "-"
 
 #define ADDR_BASED    "Address_Based"
@@ -76,6 +77,7 @@
 #define MNFR_BASED    "Manufacturer_Based"
 #define VNDR_PRDT_BASED   "Vndr_Prdt_Based"
 #define SSR_MAX_LAT_BASED   "SSR_Max_Lat_Based"
+#define VERSION_BASED   "Version_Based"
 
 struct config_t {
   list_t *sections;
@@ -98,12 +100,18 @@
   interop_feature_t feature;
 } interop_hid_ssr_max_lat_t;
 
+typedef struct {
+  uint16_t version;
+  interop_feature_t feature;
+} interop_version_t;
+
 typedef enum {
     INTEROP_BL_TYPE_ADDR = 0,
     INTEROP_BL_TYPE_NAME,
     INTEROP_BL_TYPE_MANUFACTURE,
     INTEROP_BL_TYPE_VNDR_PRDT,
     INTEROP_BL_TYPE_SSR_MAX_LAT,
+    INTEROP_BL_TYPE_VERSION,
 
 } interop_bl_type;
 
@@ -123,6 +131,7 @@
         interop_manufacturer_t mnfr_entry;
         interop_hid_multitouch_t vnr_pdt_entry;
         interop_hid_ssr_max_lat_t ssr_max_lat_entry;
+        interop_version_t version_entry;
     } entry_type;
 
 } interop_db_entry_t;
@@ -488,6 +497,18 @@
         interop_config_flush();
         break;
       }
+    case INTEROP_BL_TYPE_VERSION:
+      {
+        interop_feature_t feature =
+          db_entry->entry_type.version_entry.feature;
+        char m_vendor[KEY_MAX_LENGTH] = { '\0' };
+        snprintf(m_vendor, sizeof(m_vendor), "0x%04x",
+            db_entry->entry_type.version_entry.version);
+        interop_config_set_str(interop_feature_string_(feature),
+            m_vendor, VERSION_BASED);
+        interop_config_flush();
+        break;
+      }
   }
 }
 
@@ -594,6 +615,20 @@
           }
           break;
         }
+      case INTEROP_BL_TYPE_VERSION:
+        {
+          interop_version_t *src = &entry->entry_type.version_entry;
+          interop_version_t *cur = &db_entry->entry_type.version_entry;
+
+          if ((src->feature == cur->feature) &&
+              (src->version == cur->version)) {
+            if (ret_entry) {
+              *ret_entry = db_entry;
+            }
+            found = true;
+          }
+          break;
+        }
     }
 
     if (found) {
@@ -690,6 +725,19 @@
         interop_config_flush();
         break;
       }
+    case INTEROP_BL_TYPE_VERSION:
+      {
+        interop_version_t *src = &entry->entry_type.version_entry;
+
+        interop_feature_t feature = src->feature;
+        char m_version[KEY_MAX_LENGTH] = { '\0' };
+        snprintf(m_version, sizeof(m_version), "0x%04x",
+            src->version);
+        interop_config_remove(interop_feature_string_(feature),
+            m_version);
+        interop_config_flush();
+        break;
+      }
     default:
     status = false;
   }
@@ -923,6 +971,28 @@
     entry->entry_type.ssr_max_lat_entry.length = len;
     entry->entry_type.ssr_max_lat_entry.max_lat = max_lat;
     interop_database_add_(entry, false);
+  } else if ( !strncasecmp( value, VERSION_BASED, strlen(VERSION_BASED))) {
+
+    uint16_t version;
+    char *e;
+
+    if ( strlen(key) != VALID_VERSION_LEN ) {
+      LOG_WARN(LOG_TAG,
+      " ignoring %s due to invalid version in config file", key);
+      return false;
+    }
+
+    version = (uint16_t)strtoul(key, &e, 16);
+    errno = 0;
+    if( *e || errno == EINVAL || errno == ERANGE )
+       return false;
+
+    interop_db_entry_t *entry = (interop_db_entry_t *)osi_calloc(sizeof(interop_db_entry_t));
+    entry->bl_type = INTEROP_BL_TYPE_VERSION;
+    entry->bl_entry_type = entry_type;
+    entry->entry_type.version_entry.feature = (interop_feature_t)feature;
+    entry->entry_type.version_entry.version = version;
+    interop_database_add_(entry, false);
   }
   LOG_WARN(LOG_TAG, " feature:: %d, key :: %s, value :: %s",
                     feature, key, value);
@@ -1065,6 +1135,17 @@
   interop_database_add_(entry, true);
 }
 
+void interop_database_add_version(const interop_feature_t feature, uint16_t version)
+{
+
+  interop_db_entry_t *entry = (interop_db_entry_t *)osi_calloc(sizeof(interop_db_entry_t));
+  entry->bl_type = INTEROP_BL_TYPE_VERSION;
+  entry->bl_entry_type = INTEROP_ENTRY_TYPE_DYNAMIC;
+  entry->entry_type.version_entry.feature = (interop_feature_t)feature;
+  entry->entry_type.version_entry.version = version;
+  interop_database_add_(entry, true);
+}
+
 bool interop_database_match_manufacturer(const interop_feature_t feature,
                       uint16_t manufacturer)
 {
@@ -1178,6 +1259,27 @@
   return false;
 }
 
+bool interop_database_match_version(const interop_feature_t feature, uint16_t version)
+{
+
+  interop_db_entry_t entry;
+  interop_db_entry_t *ret_entry = NULL;
+
+  entry.bl_type = INTEROP_BL_TYPE_VERSION;
+
+  entry.entry_type.version_entry.feature = (interop_feature_t)feature;
+  entry.entry_type.version_entry.version = version;
+  if (interop_database_match_(&entry, &ret_entry,  (interop_entry_type)(INTEROP_ENTRY_TYPE_STATIC  |
+    INTEROP_ENTRY_TYPE_DYNAMIC))) {
+    LOG_WARN(LOG_TAG,
+      "%s() Device with version: 0x%04x is a match for interop workaround %s", __func__, version,
+      interop_feature_string_(feature));
+    return true;
+  }
+
+  return false;
+}
+
 bool interop_database_remove_name( const interop_feature_t feature, const char *name)
 {
   assert(name);
@@ -1291,3 +1393,25 @@
   return false;
 }
 
+bool interop_database_remove_version(const interop_feature_t feature, uint16_t version)
+{
+
+  interop_db_entry_t entry;
+
+  entry.bl_type = INTEROP_BL_TYPE_VERSION;
+  entry.bl_entry_type = INTEROP_ENTRY_TYPE_DYNAMIC;
+
+  entry.entry_type.version_entry.feature = (interop_feature_t)feature;
+  entry.entry_type.version_entry.version = version;
+
+  if (interop_database_remove_(&entry)) {
+    LOG_WARN(LOG_TAG,
+      "%s() Device with version: 0x%04x is removed from"
+      "interop workaround %s", __func__, version,
+      interop_feature_string_(feature));
+    return true;
+  }
+  return false;
+}
+
+