Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7ca643f3 authored by Sharvil Nanavati's avatar Sharvil Nanavati
Browse files

Clean up DID configuration parsing.

Change-Id: Iba77c9924c1f4fe926a7e59653b80e9d836c4fc5
parent 1e87b0b4
Loading
Loading
Loading
Loading
+3 −12
Original line number Diff line number Diff line
# Device ID (DID) configuration
[DID]

# Record Number: 1, 2 or 3 - maximum of 3 records
recordNumber = 1
[DID1]

# Primary Record - true or false (default)
# There can be only one primary record
@@ -31,10 +28,7 @@ version = 0x1436

#=================================================================================================#
# Device ID (DID) configuration
[DID]

# Record number: 1, 2 or 3 - maximum of 3 records
#recordNumber = 2
[DID2]

# Primary Record - true or false (default)
# There can be only one primary record
@@ -63,10 +57,7 @@ version = 0x1436

#=================================================================================================#
# Device ID (DID) configuration
[DID]

# Record number: 1, 2 or 3 - maximum of 3 records
#recordNumber = 3
[DID3]

# Primary Record - true or false (default)
# There can be only one primary record
+52 −359
Original line number Diff line number Diff line
@@ -16,189 +16,24 @@
 *
 ******************************************************************************/

/******************************************************************************
 *
 *  Filename:      bte_conf.c
 *
 *  Description:   Contains functions to conduct run-time module configuration
 *                 based on entries present in the .conf file
 *
 ******************************************************************************/

#define LOG_TAG "bte_conf"

#include <assert.h>
#include <utils/Log.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <utils/Log.h>

#include "bt_target.h"
#include "bta_api.h"
#include "bt_utils.h"
#include "config.h"

/******************************************************************************
**  Externs
******************************************************************************/
extern BOOLEAN hci_logging_enabled;
// TODO: eliminate these global variables.
extern char hci_logfile[256];
extern BOOLEAN hci_logging_enabled;
extern BOOLEAN trace_conf_enabled;
void bte_trace_conf(const char *p_name, const char *p_conf_value);
void bte_trace_conf_config(const config_t *config);
int device_name_cfg(const char *p_conf_name, const char *p_conf_value);
int device_class_cfg(const char *p_conf_name, const char *p_conf_value);
int logging_cfg_onoff(const char *p_conf_name, const char *p_conf_value);
int logging_set_filepath(const char *p_conf_name, const char *p_conf_value);
int trace_cfg_onoff(const char *p_conf_name, const char *p_conf_value);

BD_NAME local_device_default_name = BTM_DEF_LOCAL_NAME;
DEV_CLASS local_device_default_class = {0x40, 0x02, 0x0C};

/******************************************************************************
**  Local type definitions
******************************************************************************/
#define CONF_DBG          0
#define info(format, ...) ALOGI (format, ## __VA_ARGS__)
#define debug(format, ...) if (CONF_DBG) ALOGD (format, ## __VA_ARGS__)
#define error(format, ...) ALOGE (format, ## __VA_ARGS__)

#define CONF_KEY_LEN   32
#define CONF_VALUE_LEN 96

#define CONF_COMMENT '#'
#define CONF_DELIMITERS " =\n\r\t"
#define CONF_VALUES_DELIMITERS "\"=\n\r\t"
#define CONF_COD_DELIMITERS " {,}\t"
#define CONF_MAX_LINE_LEN 255

typedef int (conf_action_t)(const char *p_conf_name, const char *p_conf_value);

typedef struct {
    const char *key_name;
    conf_action_t *p_action;
} conf_entry_t;

typedef struct {
    char key[CONF_KEY_LEN];
    char value[CONF_VALUE_LEN];
} tKEY_VALUE_PAIRS;

enum {
    CONF_DID,
    CONF_DID_RECORD_NUM,
    CONF_DID_PRIMARY_RECORD,
    CONF_DID_VENDOR_ID,
    CONF_DID_VENDOR_ID_SOURCE,
    CONF_DID_PRODUCT_ID,
    CONF_DID_VERSION,
    CONF_DID_CLIENT_EXECUTABLE_URL,
    CONF_DID_SERVICE_DESCRIPTION,
    CONF_DID_DOCUMENTATION_URL,
    CONF_DID_MAX
};
typedef UINT8 tCONF_DID;
/******************************************************************************
**  Static variables
******************************************************************************/

/*
 * Current supported entries and corresponding action functions
 */
/* TODO: Name and Class are duplicated with NVRAM adapter_info. Need to be sorted out */
static const conf_entry_t conf_table[] = {
    /*{"Name", device_name_cfg},
    {"Class", device_class_cfg},*/
    {"BtSnoopLogOutput", logging_cfg_onoff},
    {"BtSnoopFileName", logging_set_filepath},
    {"TraceConf", trace_cfg_onoff},
    {(const char *) NULL, NULL}
};

static tKEY_VALUE_PAIRS did_conf_pairs[CONF_DID_MAX] = {
    { "[DID]",               "" },
    { "recordNumber",        "" },
    { "primaryRecord",       "" },
    { "vendorId",            "" },
    { "vendorIdSource",      "" },
    { "productId",           "" },
    { "version",             "" },
    { "clientExecutableURL", "" },
    { "serviceDescription",  "" },
    { "documentationURL",    "" },
};
/*****************************************************************************
**   FUNCTIONS
*****************************************************************************/

int device_name_cfg(const char *p_conf_name, const char *p_conf_value)
{
    UNUSED(p_conf_name);
    strcpy((char *)local_device_default_name, p_conf_value);
    return 0;
}

int device_class_cfg(const char *p_conf_name, const char *p_conf_value)
{
    char *p_token;
    unsigned int x;
    char tmp[1024] = { 0 };
    strncpy(tmp, p_conf_value, sizeof(tmp) - 1);

    UNUSED(p_conf_name);

    p_token = strtok(tmp, CONF_COD_DELIMITERS);
    sscanf(p_token, "%x", &x);
    local_device_default_class[0] = (UINT8) x;
    p_token = strtok(NULL, CONF_COD_DELIMITERS);
    sscanf(p_token, "%x", &x);
    local_device_default_class[1] = (UINT8) x;
    p_token = strtok(NULL, CONF_COD_DELIMITERS);
    sscanf(p_token, "%x", &x);
    local_device_default_class[2] = (UINT8) x;

    return 0;
}

int logging_cfg_onoff(const char *p_conf_name, const char *p_conf_value)
{
    UNUSED(p_conf_name);
    if (strcmp(p_conf_value, "true") == 0)
        hci_logging_enabled = TRUE;
    else
        hci_logging_enabled = FALSE;
    return 0;
}

int logging_set_filepath(const char *p_conf_name, const char *p_conf_value)
{
    UNUSED(p_conf_name);
    strcpy(hci_logfile, p_conf_value);
    return 0;
}

int trace_cfg_onoff(const char *p_conf_name, const char *p_conf_value)
{
    UNUSED(p_conf_name);
    trace_conf_enabled = (strcmp(p_conf_value, "true") == 0) ? TRUE : FALSE;
    return 0;
}

/*****************************************************************************
**   CONF INTERFACE FUNCTIONS
*****************************************************************************/

/*******************************************************************************
**
** Function        bte_load_conf
**
** Description     Read conf entry from path file one by one and call
**                 the corresponding config function
**
** Returns         None
**
*******************************************************************************/
// Reads the stack configuration file and populates global variables with
// the contents of the file.
void bte_load_conf(const char *path) {
  assert(path != NULL);

@@ -210,207 +45,65 @@ void bte_load_conf(const char *path) {
    return;
  }

  for (const conf_entry_t *entry = &conf_table[0]; entry->key_name; ++entry) {
    const char *value = config_get_string(config, CONFIG_DEFAULT_SECTION, entry->key_name, NULL);
    if (value)
      entry->p_action(entry->key_name, value);
  }
  strlcpy(hci_logfile, config_get_string(config, CONFIG_DEFAULT_SECTION, "BtSnoopFileName", ""), sizeof(hci_logfile));
  hci_logging_enabled = config_get_bool(config, CONFIG_DEFAULT_SECTION, "BtSnoopLogOutput", false);
  trace_conf_enabled = config_get_bool(config, CONFIG_DEFAULT_SECTION, "TraceConf", false);

  bte_trace_conf_config(config);
  config_free(config);
}

/*******************************************************************************
**
** Function        bte_parse_did_conf
**
** Description     Read conf entry from p_path file one by one and get
**                 the corresponding config value
**
** Returns         TRUE if success, else FALSE
**
*******************************************************************************/
static BOOLEAN bte_parse_did_conf (const char *p_path, UINT32 num,
    tKEY_VALUE_PAIRS *conf_pairs, UINT32 conf_pairs_num)
{
    UINT32 i, param_num=0, count=0, start_count=0, end_count=0, conf_num=0;
    BOOLEAN key=TRUE, conf_found=FALSE;

    FILE    *p_file;
    char    *p;
    char    line[CONF_MAX_LINE_LEN+1]; /* add 1 for \0 char */

    ALOGI("Attempt to load did conf from %s", p_path);

    if ((p_file = fopen(p_path, "r")) != NULL)
    {
        /* read line by line */
        while (fgets(line, CONF_MAX_LINE_LEN+1, p_file) != NULL)
        {
            count++;
            if (line[0] == CONF_COMMENT)
                continue;

            if (conf_found && (conf_num == num) && (*line == '[')) {
                conf_found = FALSE;
                end_count = count-1;
                break;
            }

            p = strtok(line, CONF_DELIMITERS);
            while (p != NULL) {
                if (conf_num <= num) {
                    if (key) {
                        if (!strcmp(p, conf_pairs[0].key)) {
                            if (++conf_num == num) {
                                conf_found = TRUE;
                                start_count = count;
                                strncpy(conf_pairs[0].value, "1", CONF_VALUE_LEN);
                            }
                        } else {
                            if (conf_num == num) {
                                for (i=1; i<conf_pairs_num; i++) {
                                    if (!strcmp(p, conf_pairs[i].key)) {
                                        param_num = i;
                                        break;
                                    }
                                }
                                if (i == conf_pairs_num) {
                                    error("Attribute %s does not belong to %s configuration",
                                        p, conf_pairs[0].key);
                                    fclose(p_file);
                                    return FALSE;
                                }
                            }
                            key = FALSE;
                        }
                    } else {
                        if ((conf_num == num) && param_num) {
                            strncpy(conf_pairs[param_num].value, p, CONF_VALUE_LEN-1);
                            param_num = 0;
                        }
                        key = TRUE;
                    }
                }
                p = strtok(NULL, CONF_DELIMITERS);
            }
        }

        fclose(p_file);
   }
   else
   {
        ALOGI( "bte_parse_did_conf file >%s< not found", p_path);
   }
   if (!end_count)
       end_count = count;

   if (start_count) {
        debug("Read %s configuration #%u from lines %u to %u in file %s",
            conf_pairs[0].key, (unsigned int)num, (unsigned int)start_count,
            (unsigned int)end_count, p_path);
        return TRUE;
   }

   error("%s configuration not found in file %s", conf_pairs[0].key, p_path);
        return FALSE;
}

/*******************************************************************************
**
** Function        bte_load_did_conf
**
** Description     Set local Device ID records, reading from configuration files
**
** Returns         None
**
*******************************************************************************/

void bte_load_did_conf (const char *p_path)
{
    tBTA_DI_RECORD rec;
    UINT32 rec_num, i, j;

    for (i=1; i<=BTA_DI_NUM_MAX; i++) {
        for (j=0; j<CONF_DID_MAX; j++) {
            *did_conf_pairs[j].value = 0;
        }
// Parses the specified Device ID configuration file and registers the
// Device ID records with SDP.
void bte_load_did_conf(const char *p_path) {
    assert(p_path != NULL);

        if (bte_parse_did_conf(p_path, i, did_conf_pairs, CONF_DID_MAX)) {
            memset(&rec, 0, sizeof(rec));

            if (*did_conf_pairs[CONF_DID_RECORD_NUM].value) {
                rec_num = (UINT32)(strtoul(did_conf_pairs[CONF_DID_RECORD_NUM].value, NULL, 0)-1);
            } else {
                debug("[%d] Unknown %s", (unsigned int)i, did_conf_pairs[CONF_DID_RECORD_NUM].key);
                continue;
    config_t *config = config_new(p_path);
    if (!config) {
        ALOGE("%s unable to load DID config '%s'.", __func__, p_path);
        return;
    }

            if (*did_conf_pairs[CONF_DID_VENDOR_ID].value) {
                rec.vendor = (UINT16)strtoul(did_conf_pairs[CONF_DID_VENDOR_ID].value, NULL, 0);
            } else {
                rec.vendor = LMP_COMPID_BROADCOM;
            }
    for (int i = 1; i <= BTA_DI_NUM_MAX; ++i) {
        char section_name[16] = { 0 };
        snprintf(section_name, sizeof(section_name), "DID%d", i);

            if (*did_conf_pairs[CONF_DID_VENDOR_ID_SOURCE].value) {
                rec.vendor_id_source = (UINT16)strtoul(did_conf_pairs[CONF_DID_VENDOR_ID_SOURCE].value, NULL, 0);
            } else {
                rec.vendor_id_source = DI_VENDOR_ID_SOURCE_BTSIG;
        if (!config_has_section(config, section_name)) {
            ALOGD("%s no section named %s.", __func__, section_name);
            break;
        }

            if ((*did_conf_pairs[CONF_DID].value == 0) ||
                (rec_num >= BTA_DI_NUM_MAX) ||
                (!((rec.vendor_id_source >= DI_VENDOR_ID_SOURCE_BTSIG) &&
                   (rec.vendor_id_source <= DI_VENDOR_ID_SOURCE_USBIF))) ||
                (rec.vendor == DI_VENDOR_ID_DEFAULT)) {
        tBTA_DI_RECORD record;
        record.vendor = config_get_int(config, section_name, "vendorId", LMP_COMPID_BROADCOM);
        record.vendor_id_source = config_get_int(config, section_name, "vendorIdSource", DI_VENDOR_ID_SOURCE_BTSIG);
        record.product = config_get_int(config, section_name, "productId", 0);
        record.version = config_get_int(config, section_name, "version", 0);
        record.primary_record = config_get_bool(config, section_name, "primaryRecord", false);
        strlcpy(record.client_executable_url, config_get_string(config, section_name, "clientExecutableURL", ""), sizeof(record.client_executable_url));
        strlcpy(record.service_description, config_get_string(config, section_name, "serviceDescription", ""), sizeof(record.service_description));
        strlcpy(record.documentation_url, config_get_string(config, section_name, "documentationURL", ""), sizeof(record.documentation_url));

                error("DID record #%u not set", (unsigned int)i);
                for (j=0; j<CONF_DID_MAX; j++) {
                    error("%s:%s", did_conf_pairs[j].key, did_conf_pairs[j].value);
                }
        if (record.vendor_id_source != DI_VENDOR_ID_SOURCE_BTSIG &&
            record.vendor_id_source != DI_VENDOR_ID_SOURCE_USBIF) {
            ALOGE("%s invalid vendor id source %d; ignoring DID record %d.", __func__, record.vendor_id_source, i);
            continue;
        }

            rec.product = (UINT16)strtoul(did_conf_pairs[CONF_DID_PRODUCT_ID].value, NULL, 0);
            rec.version = (UINT16)strtoul(did_conf_pairs[CONF_DID_VERSION].value, NULL, 0);

            strncpy(rec.client_executable_url,
                did_conf_pairs[CONF_DID_CLIENT_EXECUTABLE_URL].value,
                SDP_MAX_ATTR_LEN);
            strncpy(rec.service_description,
                did_conf_pairs[CONF_DID_SERVICE_DESCRIPTION].value,
                SDP_MAX_ATTR_LEN);
            strncpy(rec.documentation_url,
                did_conf_pairs[CONF_DID_DOCUMENTATION_URL].value,
                SDP_MAX_ATTR_LEN);
        ALOGD("Device ID record %d : %s", i, (record.primary_record ? "primary" : "not primary"));
        ALOGD("  vendorId            = %04x", record.vendor);
        ALOGD("  vendorIdSource      = %04x", record.vendor_id_source);
        ALOGD("  product             = %04x", record.product);
        ALOGD("  version             = %04x", record.version);
        ALOGD("  clientExecutableURL = %s", record.client_executable_url);
        ALOGD("  serviceDescription  = %s", record.service_description);
        ALOGD("  documentationURL    = %s", record.documentation_url);

            for (j=0; j<strlen(did_conf_pairs[CONF_DID_PRIMARY_RECORD].value); j++) {
                did_conf_pairs[CONF_DID_PRIMARY_RECORD].value[j] =
                    tolower(did_conf_pairs[CONF_DID_PRIMARY_RECORD].value[j]);
        uint32_t record_handle;
        tBTA_STATUS status = BTA_DmSetLocalDiRecord(&record, &record_handle);
        if (status != BTA_SUCCESS) {
            ALOGE("%s unable to set device ID record %d: error %d.", __func__, i, status);
        }
            if ((!strcmp(did_conf_pairs[CONF_DID_PRIMARY_RECORD].value, "true")) ||
                (!strcmp(did_conf_pairs[CONF_DID_PRIMARY_RECORD].value, "1"))) {
                rec.primary_record = TRUE;
            } else {
                rec.primary_record = FALSE;
    }

            info("[%u] primary_record=%d vendor_id=0x%04X vendor_id_source=0x%04X product_id=0x%04X version=0x%04X",
                (unsigned int)rec_num+1, rec.primary_record, rec.vendor,
                rec.vendor_id_source, rec.product, rec.version);
            if (*rec.client_executable_url) {
                info(" client_executable_url=%s", rec.client_executable_url);
            }
            if (*rec.service_description) {
                info(" service_description=%s", rec.service_description);
            }
            if (*rec.documentation_url) {
                info(" documentation_url=%s", rec.documentation_url);
            }

            if (BTA_DmSetLocalDiRecord(&rec, &rec_num) != BTA_SUCCESS) {
                error("SetLocalDiInfo failed for #%u!", (unsigned int)i);
            }
        }
    }
    config_free(config);
}