• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
device_name_cfg(char * p_conf_name,char * p_conf_value)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 
device_class_cfg(char * p_conf_name,char * p_conf_value)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 
logging_cfg_onoff(char * p_conf_name,char * p_conf_value)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 
logging_set_filepath(char * p_conf_name,char * p_conf_value)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 
trace_cfg_onoff(char * p_conf_name,char * p_conf_value)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 *******************************************************************************/
bte_load_conf(const char * p_path)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 *******************************************************************************/
bte_parse_did_conf(const char * p_path,UINT32 num,tKEY_VALUE_PAIRS * conf_pairs,UINT32 conf_pairs_num)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 
bte_load_did_conf(const char * p_path)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