1 /****************************************************************************** 2 * 3 * Copyright (C) 2009-2012 Broadcom Corporation 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at: 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 ******************************************************************************/ 18 19 /****************************************************************************** 20 * 21 * Filename: bte_conf.c 22 * 23 * Description: Contains functions to conduct run-time module configuration 24 * based on entries present in the .conf file 25 * 26 ******************************************************************************/ 27 28 #define LOG_TAG "bte_conf" 29 30 #include <utils/Log.h> 31 #include <stdio.h> 32 #include <string.h> 33 #include <stdlib.h> 34 #include <ctype.h> 35 36 #include "bt_target.h" 37 #include "bta_api.h" 38 39 /****************************************************************************** 40 ** Externs 41 ******************************************************************************/ 42 extern BOOLEAN hci_logging_enabled; 43 extern char hci_logfile[256]; 44 extern BOOLEAN trace_conf_enabled; 45 void bte_trace_conf(char *p_name, char *p_conf_value); 46 int device_name_cfg(char *p_conf_name, char *p_conf_value); 47 int device_class_cfg(char *p_conf_name, char *p_conf_value); 48 int logging_cfg_onoff(char *p_conf_name, char *p_conf_value); 49 int logging_set_filepath(char *p_conf_name, char *p_conf_value); 50 int trace_cfg_onoff(char *p_conf_name, char *p_conf_value); 51 52 BD_NAME local_device_default_name = BTM_DEF_LOCAL_NAME; 53 DEV_CLASS local_device_default_class = {0x40, 0x02, 0x0C}; 54 55 /****************************************************************************** 56 ** Local type definitions 57 ******************************************************************************/ 58 #define CONF_DBG 0 59 #define info(format, ...) ALOGI (format, ## __VA_ARGS__) 60 #define debug(format, ...) if (CONF_DBG) ALOGD (format, ## __VA_ARGS__) 61 #define error(format, ...) ALOGE (format, ## __VA_ARGS__) 62 63 #define CONF_KEY_LEN 32 64 #define CONF_VALUE_LEN 96 65 66 #define CONF_COMMENT '#' 67 #define CONF_DELIMITERS " =\n\r\t" 68 #define CONF_VALUES_DELIMITERS "\"=\n\r\t" 69 #define CONF_COD_DELIMITERS " {,}\t" 70 #define CONF_MAX_LINE_LEN 255 71 72 typedef int (conf_action_t)(char *p_conf_name, char *p_conf_value); 73 74 typedef struct { 75 const char *conf_entry; 76 conf_action_t *p_action; 77 } conf_entry_t; 78 79 typedef struct { 80 char key[CONF_KEY_LEN]; 81 char value[CONF_VALUE_LEN]; 82 } tKEY_VALUE_PAIRS; 83 84 enum { 85 CONF_DID, 86 CONF_DID_RECORD_NUM, 87 CONF_DID_PRIMARY_RECORD, 88 CONF_DID_VENDOR_ID, 89 CONF_DID_VENDOR_ID_SOURCE, 90 CONF_DID_PRODUCT_ID, 91 CONF_DID_VERSION, 92 CONF_DID_CLIENT_EXECUTABLE_URL, 93 CONF_DID_SERVICE_DESCRIPTION, 94 CONF_DID_DOCUMENTATION_URL, 95 CONF_DID_MAX 96 }; 97 typedef UINT8 tCONF_DID; 98 /****************************************************************************** 99 ** Static variables 100 ******************************************************************************/ 101 102 /* 103 * Current supported entries and corresponding action functions 104 */ 105 /* TODO: Name and Class are duplicated with NVRAM adapter_info. Need to be sorted out */ 106 static const conf_entry_t conf_table[] = { 107 /*{"Name", device_name_cfg}, 108 {"Class", device_class_cfg},*/ 109 {"BtSnoopLogOutput", logging_cfg_onoff}, 110 {"BtSnoopFileName", logging_set_filepath}, 111 {"TraceConf", trace_cfg_onoff}, 112 {(const char *) NULL, NULL} 113 }; 114 115 static tKEY_VALUE_PAIRS did_conf_pairs[CONF_DID_MAX] = { 116 { "[DID]", "" }, 117 { "recordNumber", "" }, 118 { "primaryRecord", "" }, 119 { "vendorId", "" }, 120 { "vendorIdSource", "" }, 121 { "productId", "" }, 122 { "version", "" }, 123 { "clientExecutableURL", "" }, 124 { "serviceDescription", "" }, 125 { "documentationURL", "" }, 126 }; 127 /***************************************************************************** 128 ** FUNCTIONS 129 *****************************************************************************/ 130 131 int device_name_cfg(char *p_conf_name, char *p_conf_value) 132 { 133 strcpy((char *)local_device_default_name, p_conf_value); 134 return 0; 135 } 136 137 int device_class_cfg(char *p_conf_name, char *p_conf_value) 138 { 139 char *p_token; 140 unsigned int x; 141 142 p_token = strtok(p_conf_value, CONF_COD_DELIMITERS); 143 sscanf(p_token, "%x", &x); 144 local_device_default_class[0] = (UINT8) x; 145 p_token = strtok(NULL, CONF_COD_DELIMITERS); 146 sscanf(p_token, "%x", &x); 147 local_device_default_class[1] = (UINT8) x; 148 p_token = strtok(NULL, CONF_COD_DELIMITERS); 149 sscanf(p_token, "%x", &x); 150 local_device_default_class[2] = (UINT8) x; 151 152 return 0; 153 } 154 155 int logging_cfg_onoff(char *p_conf_name, char *p_conf_value) 156 { 157 if (strcmp(p_conf_value, "true") == 0) 158 hci_logging_enabled = TRUE; 159 else 160 hci_logging_enabled = FALSE; 161 return 0; 162 } 163 164 int logging_set_filepath(char *p_conf_name, char *p_conf_value) 165 { 166 strcpy(hci_logfile, p_conf_value); 167 return 0; 168 } 169 170 int trace_cfg_onoff(char *p_conf_name, char *p_conf_value) 171 { 172 trace_conf_enabled = (strcmp(p_conf_value, "true") == 0) ? TRUE : FALSE; 173 return 0; 174 } 175 176 /***************************************************************************** 177 ** CONF INTERFACE FUNCTIONS 178 *****************************************************************************/ 179 180 /******************************************************************************* 181 ** 182 ** Function bte_load_conf 183 ** 184 ** Description Read conf entry from p_path file one by one and call 185 ** the corresponding config function 186 ** 187 ** Returns None 188 ** 189 *******************************************************************************/ 190 void bte_load_conf(const char *p_path) 191 { 192 FILE *p_file; 193 char *p_name; 194 char *p_value; 195 conf_entry_t *p_entry; 196 char line[CONF_MAX_LINE_LEN+1]; /* add 1 for \0 char */ 197 BOOLEAN name_matched; 198 199 ALOGI("Attempt to load stack conf from %s", p_path); 200 201 if ((p_file = fopen(p_path, "r")) != NULL) 202 { 203 /* read line by line */ 204 while (fgets(line, CONF_MAX_LINE_LEN+1, p_file) != NULL) 205 { 206 if (line[0] == CONF_COMMENT) 207 continue; 208 209 p_name = strtok(line, CONF_DELIMITERS); 210 211 if (NULL == p_name) 212 { 213 continue; 214 } 215 216 p_value = strtok(NULL, CONF_VALUES_DELIMITERS); 217 218 if (NULL == p_value) 219 { 220 ALOGW("bte_load_conf: missing value for name: %s", p_name); 221 continue; 222 } 223 224 name_matched = FALSE; 225 p_entry = (conf_entry_t *)conf_table; 226 227 while (p_entry->conf_entry != NULL) 228 { 229 if (strcmp(p_entry->conf_entry, (const char *)p_name) == 0) 230 { 231 name_matched = TRUE; 232 if (p_entry->p_action != NULL) 233 p_entry->p_action(p_name, p_value); 234 break; 235 } 236 237 p_entry++; 238 } 239 240 if ((name_matched == FALSE) && (trace_conf_enabled == TRUE)) 241 { 242 /* Check if this is a TRC config item */ 243 bte_trace_conf(p_name, p_value); 244 } 245 } 246 247 fclose(p_file); 248 } 249 else 250 { 251 ALOGI( "bte_load_conf file >%s< not found", p_path); 252 } 253 } 254 255 /******************************************************************************* 256 ** 257 ** Function bte_parse_did_conf 258 ** 259 ** Description Read conf entry from p_path file one by one and get 260 ** the corresponding config value 261 ** 262 ** Returns TRUE if success, else FALSE 263 ** 264 *******************************************************************************/ 265 static BOOLEAN bte_parse_did_conf (const char *p_path, UINT32 num, 266 tKEY_VALUE_PAIRS *conf_pairs, UINT32 conf_pairs_num) 267 { 268 UINT32 i, param_num=0, count=0, start_count=0, end_count=0, conf_num=0; 269 BOOLEAN key=TRUE, conf_found=FALSE; 270 271 FILE *p_file; 272 char *p; 273 char line[CONF_MAX_LINE_LEN+1]; /* add 1 for \0 char */ 274 275 ALOGI("Attempt to load did conf from %s", p_path); 276 277 if ((p_file = fopen(p_path, "r")) != NULL) 278 { 279 /* read line by line */ 280 while (fgets(line, CONF_MAX_LINE_LEN+1, p_file) != NULL) 281 { 282 count++; 283 if (line[0] == CONF_COMMENT) 284 continue; 285 286 if (conf_found && (conf_num == num) && (*line == '[')) { 287 conf_found = FALSE; 288 end_count = count-1; 289 break; 290 } 291 292 p = strtok(line, CONF_DELIMITERS); 293 while (p != NULL) { 294 if (conf_num <= num) { 295 if (key) { 296 if (!strcmp(p, conf_pairs[0].key)) { 297 if (++conf_num == num) { 298 conf_found = TRUE; 299 start_count = count; 300 strncpy(conf_pairs[0].value, "1", CONF_VALUE_LEN); 301 } 302 } else { 303 if (conf_num == num) { 304 for (i=1; i<conf_pairs_num; i++) { 305 if (!strcmp(p, conf_pairs[i].key)) { 306 param_num = i; 307 break; 308 } 309 } 310 if (i == conf_pairs_num) { 311 error("Attribute %s does not belong to %s configuration", 312 p, conf_pairs[0].key); 313 fclose(p_file); 314 return FALSE; 315 } 316 } 317 key = FALSE; 318 } 319 } else { 320 if ((conf_num == num) && param_num) { 321 strncpy(conf_pairs[param_num].value, p, CONF_VALUE_LEN-1); 322 param_num = 0; 323 } 324 key = TRUE; 325 } 326 } 327 p = strtok(NULL, CONF_DELIMITERS); 328 } 329 } 330 331 fclose(p_file); 332 } 333 else 334 { 335 ALOGI( "bte_parse_did_conf file >%s< not found", p_path); 336 } 337 if (!end_count) 338 end_count = count; 339 340 if (start_count) { 341 debug("Read %s configuration #%u from lines %u to %u in file %s", 342 conf_pairs[0].key, (unsigned int)num, (unsigned int)start_count, 343 (unsigned int)end_count, p_path); 344 return TRUE; 345 } 346 347 error("%s configuration not found in file %s", conf_pairs[0].key, p_path); 348 return FALSE; 349 } 350 351 /******************************************************************************* 352 ** 353 ** Function bte_load_did_conf 354 ** 355 ** Description Set local Device ID records, reading from configuration files 356 ** 357 ** Returns None 358 ** 359 *******************************************************************************/ 360 361 void bte_load_did_conf (const char *p_path) 362 { 363 tBTA_DI_RECORD rec; 364 UINT32 rec_num, i, j; 365 366 for (i=1; i<=BTA_DI_NUM_MAX; i++) { 367 for (j=0; j<CONF_DID_MAX; j++) { 368 *did_conf_pairs[j].value = 0; 369 } 370 371 if (bte_parse_did_conf(p_path, i, did_conf_pairs, CONF_DID_MAX)) { 372 memset(&rec, 0, sizeof(rec)); 373 374 if (*did_conf_pairs[CONF_DID_RECORD_NUM].value) { 375 rec_num = (UINT32)(strtoul(did_conf_pairs[CONF_DID_RECORD_NUM].value, NULL, 0)-1); 376 } else { 377 debug("[%d] Unknown %s", (unsigned int)i, did_conf_pairs[CONF_DID_RECORD_NUM].key); 378 continue; 379 } 380 381 if (*did_conf_pairs[CONF_DID_VENDOR_ID].value) { 382 rec.vendor = (UINT16)strtoul(did_conf_pairs[CONF_DID_VENDOR_ID].value, NULL, 0); 383 } else { 384 rec.vendor = LMP_COMPID_BROADCOM; 385 } 386 387 if (*did_conf_pairs[CONF_DID_VENDOR_ID_SOURCE].value) { 388 rec.vendor_id_source = (UINT16)strtoul(did_conf_pairs[CONF_DID_VENDOR_ID_SOURCE].value, NULL, 0); 389 } else { 390 rec.vendor_id_source = DI_VENDOR_ID_SOURCE_BTSIG; 391 } 392 393 if ((*did_conf_pairs[CONF_DID].value == 0) || 394 (rec_num >= BTA_DI_NUM_MAX) || 395 (!((rec.vendor_id_source >= DI_VENDOR_ID_SOURCE_BTSIG) && 396 (rec.vendor_id_source <= DI_VENDOR_ID_SOURCE_USBIF))) || 397 (rec.vendor == DI_VENDOR_ID_DEFAULT)) { 398 399 error("DID record #%u not set", (unsigned int)i); 400 for (j=0; j<CONF_DID_MAX; j++) { 401 error("%s:%s", did_conf_pairs[j].key, did_conf_pairs[j].value); 402 } 403 continue; 404 } 405 406 rec.product = (UINT16)strtoul(did_conf_pairs[CONF_DID_PRODUCT_ID].value, NULL, 0); 407 rec.version = (UINT16)strtoul(did_conf_pairs[CONF_DID_VERSION].value, NULL, 0); 408 409 strncpy(rec.client_executable_url, 410 did_conf_pairs[CONF_DID_CLIENT_EXECUTABLE_URL].value, 411 SDP_MAX_ATTR_LEN); 412 strncpy(rec.service_description, 413 did_conf_pairs[CONF_DID_SERVICE_DESCRIPTION].value, 414 SDP_MAX_ATTR_LEN); 415 strncpy(rec.documentation_url, 416 did_conf_pairs[CONF_DID_DOCUMENTATION_URL].value, 417 SDP_MAX_ATTR_LEN); 418 419 for (j=0; j<strlen(did_conf_pairs[CONF_DID_PRIMARY_RECORD].value); j++) { 420 did_conf_pairs[CONF_DID_PRIMARY_RECORD].value[j] = 421 tolower(did_conf_pairs[CONF_DID_PRIMARY_RECORD].value[j]); 422 } 423 if ((!strcmp(did_conf_pairs[CONF_DID_PRIMARY_RECORD].value, "true")) || 424 (!strcmp(did_conf_pairs[CONF_DID_PRIMARY_RECORD].value, "1"))) { 425 rec.primary_record = TRUE; 426 } else { 427 rec.primary_record = FALSE; 428 } 429 430 info("[%u] primary_record=%d vendor_id=0x%04X vendor_id_source=0x%04X product_id=0x%04X version=0x%04X", 431 (unsigned int)rec_num+1, rec.primary_record, rec.vendor, 432 rec.vendor_id_source, rec.product, rec.version); 433 if (*rec.client_executable_url) { 434 info(" client_executable_url=%s", rec.client_executable_url); 435 } 436 if (*rec.service_description) { 437 info(" service_description=%s", rec.service_description); 438 } 439 if (*rec.documentation_url) { 440 info(" documentation_url=%s", rec.documentation_url); 441 } 442 443 if (BTA_DmSetLocalDiRecord(&rec, &rec_num) != BTA_SUCCESS) { 444 error("SetLocalDiInfo failed for #%u!", (unsigned int)i); 445 } 446 } 447 } 448 } 449 450