/*
 * Copyright 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "metrics_allowlist.h"

#include <cstdint>
#include <cstring>

namespace bluetooth {
namespace metrics {

namespace {

static constexpr int device_info_allow_list_sig[][2] = {
        /* Ericsson Technology Licensing */
        {0, 52},
        /* Motorola */
        {8, 11905},
        /* Qualcomm Technologies International, Ltd. (QTIL) */
        {10, 65535},
        /* Texas Instruments Inc. */
        {13, 0},
        /* Broadcom Corporation. */
        {15, 4608},
        /* Qualcomm */
        {29, 4608},
        /* Integrated System Solution Corp. */
        {57, 5028},
        {57, 5506},
        /* MediaTek, Inc. */
        {70, 4608},
        /* Apple, Inc. */
        {76, 8194},
        {76, 8198},
        {76, 8201},
        {76, 8203},
        {76, 8204},
        {76, 8206},
        {76, 8207},
        {76, 8208},
        {76, 8211},
        /* Harman International Industries, Inc. */
        {87, 35},
        {87, 7977},
        /* Realtek Semiconductor Corporation */
        {93, 8763},
        /* Samsung Electronics Co. Ltd. */
        {117, 256},
        {117, 40977},
        {117, 40978},
        {117, 40979},
        /* Airoha Technology Corp. */
        {148, 4},
        {148, 291},
        /* LG Electronics​ */
        {196, 5025},
        /* Google */
        {224, 0},
        {224, 4608},
        {224, 12288},
        {224, 12289},
        {224, 12290},
        {224, 12291},
        {224, 12292},
        {224, 12544},
        {224, 50181},
        /* Amazon.com Services, LLC */
        {369, 384},
        /* Bestechnic(Shanghai),Ltd */
        {688, 0},
        /* LEGO System A/S */
        {919, 1},
        /* Actions (Zhuhai) Technology Co., Limited */
        {992, 12298},
        /* STABILO International */
        {1256, 32896},
        /* GoerTek Dynaudio Co., Ltd. */
        {1452, 544},
        /* Zhuhai Jieli technology Co.,Ltd */
        {1494, 10}};

static constexpr int device_info_allow_list_usb[][2] = {
        /* Unknown */
        {14, 13330},
        /* Unknown */
        {97, 1},
        /* Unknown  */
        {125, 628},
        /* HP, Inc */
        {1008, 2124},
        {1008, 588},
        /* Unknown  */
        {1014, 40961},
        /* Microsoft Corp. */
        {1118, 736},
        {1118, 765},
        {1118, 1954},
        {1118, 2053},
        {1118, 2054},
        {1118, 2087},
        {1118, 2095},
        {1118, 2326},
        {1118, 2354},
        {1118, 2397},
        {1118, 2835},
        {1118, 2848},
        /* Primax Electronics, Ltd */
        {1121, 20206},
        {1121, 20207},
        /* Logitech, Inc. */
        {1133, 45072},
        {1133, 45076},
        {1133, 45077},
        {1133, 45078},
        {1133, 45081},
        {1133, 45082},
        {1133, 45083},
        {1133, 45089},
        {1133, 45091},
        {1133, 45093},
        {1133, 45094},
        {1133, 45095},
        {1133, 45883},
        {1133, 45885},
        {1133, 45890},
        {1133, 45901},
        {1133, 45915},
        {1133, 45917},
        {1133, 45890},
        /* Samsung Electronics Co., Ltd */
        {1256, 28705},
        /* Sony Corp. */
        {1356, 1476},
        {1356, 2508},
        {1356, 3302},
        /* Wacom Co., Ltd */
        {1386, 887},
        /* Nintendo Co., Ltd */
        {1406, 8198},
        {1406, 8199},
        {1406, 8201},
        /* Apple, Inc. */
        {1452, 544},
        {1452, 556},
        {1452, 569},
        {1452, 591},
        {1452, 597},
        {1452, 781},
        {1452, 12850},
        /* Zippy Technology Corp. */
        {2458, 1280},
        /* Broadcom Corp. */
        {2652, 1},
        {2652, 17667},
        {2652, 63369},
        /* Microdia */
        {3141, 32270},
        /* Focusrite-Novation */
        {4661, 43554},
        /* Razer USA, Ltd */
        {5426, 130},
        /* Nordic Semiconductor ASA */
        {6421, 64},
        /* Lab126, Inc. */
        {6473, 1026},
        /* Anker Innovations Limited */
        {10522, 34050},
        /* Unknown */
        {12994, 1},
        /* Fuji Yusoki Kogyo Co., Ltd. */
        {44580, 34328},
};

enum Transport {
  USB = 1,
  UART = 2,
  SDIO = 3,
};

/* Below chipset info allowlists are generated by the script:
 * go/cros-chipset-allowlist-generator
 * and feeds with the data in tsv format
 * go/cros-chipset-info-0512
 */
static constexpr int chipset_info_allow_list_vidpid[][3] = {
        /* Intel */
        {USB, 0x8086, 0x095a},  // INTEL-AC7265
        {USB, 0x8086, 0x31dc},  // INTEL-AC9560
        {USB, 0x8086, 0x4df0},  // INTEL-AX201
        {USB, 0x8086, 0x095b},  // INTEL-AC7265
        {USB, 0x8086, 0x02f0},  // INTEL-AX201
        {USB, 0x8086, 0x51f0},
        {USB, 0x8086, 0xa0f0},  // INTEL-AX201
        {USB, 0x8086, 0x2526},  // INTEL-AC9260
        {USB, 0x8086, 0x3165},
        {USB, 0x8086, 0x2723},  // INTEL-AX200
        {USB, 0x8086, 0x08b1},  // INTEL-AC7260
        {USB, 0x8086, 0x24fd},
        {USB, 0x8086, 0x9df0},  // INTEL-AC9560
        {USB, 0x8086, 0x08b3},
        {USB, 0x8086, 0x24fb},
        {USB, 0x8086, 0x3166},
        {USB, 0x8086, 0x24f3},
        {USB, 0x8086, 0x08b2},  // INTEL-AC7260
        {USB, 0x8086, 0x08b4},
        {USB, 0x8086, 0x0887},
        {USB, 0x8086, 0x4232},
        {USB, 0x8086, 0x088e},
        {USB, 0x8086, 0x0085},
        {USB, 0x8086, 0x0082},
        {USB, 0x8086, 0x4239},
        {USB, 0x8086, 0x4238},
        {USB, 0x8086, 0x4222},
        {USB, 0x8086, 0x008a},
        {USB, 0x8086, 0xa370},
        {USB, 0x8086, 0x54f0},
        {USB, 0x8086, 0x422c},
        {USB, 0x8086, 0x4237},
        {USB, 0x8086, 0x4229},
        /* Qualcomm */
        {USB, 0x168c, 0x003e},   // QCA-6174A-5
        {UART, 0x0271, 0x050a},  // QCA-6174A-3
        {USB, 0x168c, 0x0042},
        {USB, 0x168c, 0x0036},
        {USB, 0x168c, 0x0032},
        {USB, 0x168c, 0x002b},
        {USB, 0x168c, 0x0034},
        {USB, 0x168c, 0x002a},
        {USB, 0x168c, 0x0030},
        /* Realtek */
        {USB, 0x10ec, 0xc822},  // Realtek-RTL8822C-USB
        {USB, 0x10ec, 0xb723},
        {USB, 0x10ec, 0xc821},
        {USB, 0x10ec, 0x8821},
        {USB, 0x10ec, 0xb822},
        {USB, 0x10ec, 0x8852},  // Realtek-RTL8852A-USB
        {USB, 0x10ec, 0x8723},
        {USB, 0x10ec, 0x8176},
        {UART, 0x10ec, 0xc822},  // Realtek-RTL8822C-UART
        {USB, 0x10ec, 0xc82f},
        /* Marvell */
        {SDIO, 0x02df, 0x912d},  // MVL-8897
        {USB, 0x1b4b, 0x2b42},   // MVL-8997
        /* Unknown */
        {USB, 0x14e4, 0x4365},
        {USB, 0x14e4, 0x43a0},
        {USB, 0x1814, 0x3090},
        /* MediaTek */
        {USB, 0x14c3, 0x7961},   // Mediatek-MTK7921-USB
        {SDIO, 0x037a, 0x7901},  // Mediatek-MTK7921-SDIO
};

static constexpr struct chipstr_transport {
  int transport;
  uint64_t hash_value;
  const char* str;
} chipset_info_allow_list_str[] = {
        {USB, 0x676651522ac38489ULL, "usb:v8087p0AAAd0002dcE0dsc01dp01icE0isc01ip01in00"},
        {UART, 0x0f7029c4e4bee5c2ULL, "of:NbluetoothT(null)Cqcom,wcn3991-bt"},
        {USB, 0xc87adddb3473cef2ULL, "usb:v8087p0033d0000dcE0dsc01dp01icE0isc01ip01in00"},
        {USB, 0xd4af1ceff203aa54ULL, "usb:v8087p0A2Ad0003dcE0dsc01dp01icE0isc01ip01in00"},
        {USB, 0x67ff2e0860c6088cULL, "usb:v8087p0026d0002dcE0dsc01dp01icE0isc01ip01in00"},
        {USB, 0x5ea49b43333b6757ULL, "usb:v0BDApB009d0200dcE0dsc01dp01icE0isc01ip01in00"},
        {USB, 0xae4252633a7fc378ULL, "usb:v0A12p0001d8891dcE0dsc01dp01icE0isc01ip01in00"},
        {USB, 0xe8b1d7dcab4a9180ULL, "usb:v05ACp821Fd0156dcFFdsc01dp01icFFisc01ip01in00"},
        {USB, 0xf2fc524b34906492ULL, "usb:v413Cp8160d0173dcE0dsc01dp01icE0isc01ip01in00"},
        {USB, 0xa16695ffe3ebcf8eULL, "usb:v0BDApB00Cd0000dcE0dsc01dp01icE0isc01ip01in00"},
        {USB, 0x45fa5f31f455c161ULL, "usb:v05ACp821Ad0042dcFFdsc01dp01icFFisc01ip01in00"},
        {USB, 0xed0707b5f055458dULL, "usb:v05ACp821Dd0156dcFFdsc01dp01icFFisc01ip01in00"},
        {UART, 0x645c8874e1a27038ULL, "of:NbluetoothT(null)Cqcom,wcn6750-bt"},
        {USB, 0xf8feae883f843f61ULL, "usb:v0A5Cp21BCd0761dcE0dsc01dp01icE0isc01ip01in00"},
        {USB, 0x3db1b39b76523e6fULL, "usb:v0A5Cp219Cd0628dcE0dsc01dp01icE0isc01ip01in00"},
        {USB, 0xa4fec7094cdb7bedULL, "usb:v05ACp8205d1965dcE0dsc01dp01icE0isc01ip01in00"},
        {USB, 0x952ae80214a19dd9ULL, "usb:v05ACp828Ad0150dcFFdsc01dp01icFFisc01ip01in00"},
        {USB, 0x40e84e9cf6844c32ULL, "usb:v8087p0025d0002dcE0dsc01dp01icE0isc01ip01in00"},
        {USB, 0x6b037999f75bc6ceULL, "usb:v0A5Cp21F1d0112dcFFdsc01dp01icFFisc01ip01in00"},
        {USB, 0x91be30aba4f17b7eULL, "usb:v8087p0A2Ad0001dcE0dsc01dp01icE0isc01ip01in00"},
        {USB, 0xd393d6690ca2c212ULL, "usb:v0BDApB720d0200dcEFdsc02dp01icE0isc01ip01in00"},
};

}  // namespace

bool IsDeviceInfoInAllowlist(int vendor_id_source, int vendor_id, int product_id) {
  if (vendor_id_source == 1) {
    for (int i = 0; i < sizeof(device_info_allow_list_sig) / sizeof(device_info_allow_list_sig[0]);
         i++) {
      if (vendor_id == device_info_allow_list_sig[i][0] &&
          product_id == device_info_allow_list_sig[i][1]) {
        return true;
      }
    }
  } else if (vendor_id_source == 2) {
    for (int i = 0; i < sizeof(device_info_allow_list_usb) / sizeof(device_info_allow_list_usb[0]);
         i++) {
      if (vendor_id == device_info_allow_list_usb[i][0] &&
          product_id == device_info_allow_list_usb[i][1]) {
        return true;
      }
    }
  }

  return false;
}

bool IsChipsetInfoInAllowList(int vendor_id, int product_id, int transport,
                              const char* chipset_string, uint64_t* hval) {
  if (vendor_id != 0 && product_id != 0) {
    for (int i = 0;
         i < sizeof(chipset_info_allow_list_vidpid) / sizeof(chipset_info_allow_list_vidpid[0]);
         i++) {
      const int* record = chipset_info_allow_list_vidpid[i];

      if (transport == record[0] && vendor_id == record[1] && product_id == record[2]) {
        return true;
      }
    }
  } else if (!!chipset_string && !!strlen(chipset_string)) {
    for (int i = 0;
         i < sizeof(chipset_info_allow_list_str) / sizeof(chipset_info_allow_list_str[0]); i++) {
      const struct chipstr_transport* record = &chipset_info_allow_list_str[i];

      if (strcmp(chipset_string, record->str) == 0 && transport == record->transport) {
        *hval = record->hash_value;
        return true;
      }
    }
  }

  return false;
}

}  // namespace metrics
}  // namespace bluetooth
