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: bluedroidtest.c
22 *
23 * Description: Bluedroid Test application
24 *
25 ***********************************************************************************/
26
27 #include <stdio.h>
28 #include <dlfcn.h>
29 #include <stdlib.h>
30 #include <errno.h>
31 #include <string.h>
32 #include <pthread.h>
33 #include <unistd.h>
34 #include <ctype.h>
35 #include <fcntl.h>
36 #include <sys/prctl.h>
37 #include <linux/capability.h>
38
39 #include <arpa/inet.h>
40 #include <netinet/in.h>
41 #include <netdb.h>
42
43 #include <private/android_filesystem_config.h>
44 #include <android/log.h>
45
46 #include <hardware/hardware.h>
47 #include <hardware/bluetooth.h>
48
49 /************************************************************************************
50 ** Constants & Macros
51 ************************************************************************************/
52
53 #define PID_FILE "/data/.bdt_pid"
54
55 #ifndef MAX
56 #define MAX(x, y) ((x) > (y) ? (x) : (y))
57 #endif
58
59 #define CASE_RETURN_STR(const) case const: return #const;
60
61 /************************************************************************************
62 ** Local type definitions
63 ************************************************************************************/
64
65 /************************************************************************************
66 ** Static variables
67 ************************************************************************************/
68
69 static unsigned char main_done = 0;
70 static bt_status_t status;
71
72 /* Main API */
73 static bluetooth_device_t* bt_device;
74
75 const bt_interface_t* sBtInterface = NULL;
76
77 static gid_t groups[] = { AID_NET_BT, AID_INET, AID_NET_BT_ADMIN,
78 AID_SYSTEM, AID_MISC, AID_SDCARD_RW,
79 AID_NET_ADMIN, AID_VPN};
80
81 /* Set to 1 when the Bluedroid stack is enabled */
82 static unsigned char bt_enabled = 0;
83
84 /************************************************************************************
85 ** Static functions
86 ************************************************************************************/
87
88 static void process_cmd(char *p, unsigned char is_job);
89 static void job_handler(void *param);
90 static void bdt_log(const char *fmt_str, ...);
91
92
93 /************************************************************************************
94 ** Externs
95 ************************************************************************************/
96
97 /************************************************************************************
98 ** Functions
99 ************************************************************************************/
100
101
102 /************************************************************************************
103 ** Shutdown helper functions
104 ************************************************************************************/
105
bdt_shutdown(void)106 static void bdt_shutdown(void)
107 {
108 bdt_log("shutdown bdroid test app\n");
109 main_done = 1;
110 }
111
112
113 /*****************************************************************************
114 ** Android's init.rc does not yet support applying linux capabilities
115 *****************************************************************************/
116
config_permissions(void)117 static void config_permissions(void)
118 {
119 struct __user_cap_header_struct header;
120 struct __user_cap_data_struct cap;
121
122 bdt_log("set_aid_and_cap : pid %d, uid %d gid %d", getpid(), getuid(), getgid());
123
124 header.pid = 0;
125
126 prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
127
128 setuid(AID_BLUETOOTH);
129 setgid(AID_BLUETOOTH);
130
131 header.version = _LINUX_CAPABILITY_VERSION;
132
133 cap.effective = cap.permitted = cap.inheritable =
134 1 << CAP_NET_RAW |
135 1 << CAP_NET_ADMIN |
136 1 << CAP_NET_BIND_SERVICE |
137 1 << CAP_SYS_RAWIO |
138 1 << CAP_SYS_NICE |
139 1 << CAP_SETGID;
140
141 capset(&header, &cap);
142 setgroups(sizeof(groups)/sizeof(groups[0]), groups);
143 }
144
145
146
147 /*****************************************************************************
148 ** Logger API
149 *****************************************************************************/
150
bdt_log(const char * fmt_str,...)151 void bdt_log(const char *fmt_str, ...)
152 {
153 static char buffer[1024];
154 va_list ap;
155
156 va_start(ap, fmt_str);
157 vsnprintf(buffer, 1024, fmt_str, ap);
158 va_end(ap);
159
160 fprintf(stdout, "%s\n", buffer);
161 }
162
163 /*******************************************************************************
164 ** Misc helper functions
165 *******************************************************************************/
dump_bt_status(bt_status_t status)166 static const char* dump_bt_status(bt_status_t status)
167 {
168 switch(status)
169 {
170 CASE_RETURN_STR(BT_STATUS_SUCCESS)
171 CASE_RETURN_STR(BT_STATUS_FAIL)
172 CASE_RETURN_STR(BT_STATUS_NOT_READY)
173 CASE_RETURN_STR(BT_STATUS_NOMEM)
174 CASE_RETURN_STR(BT_STATUS_BUSY)
175 CASE_RETURN_STR(BT_STATUS_UNSUPPORTED)
176
177 default:
178 return "unknown status code";
179 }
180 }
181
hex_dump(char * msg,void * data,int size,int trunc)182 static void hex_dump(char *msg, void *data, int size, int trunc)
183 {
184 unsigned char *p = data;
185 unsigned char c;
186 int n;
187 char bytestr[4] = {0};
188 char addrstr[10] = {0};
189 char hexstr[ 16*3 + 5] = {0};
190 char charstr[16*1 + 5] = {0};
191
192 bdt_log("%s \n", msg);
193
194 /* truncate */
195 if(trunc && (size>32))
196 size = 32;
197
198 for(n=1;n<=size;n++) {
199 if (n%16 == 1) {
200 /* store address for this line */
201 snprintf(addrstr, sizeof(addrstr), "%.4x",
202 ((unsigned int)p-(unsigned int)data) );
203 }
204
205 c = *p;
206 if (isalnum(c) == 0) {
207 c = '.';
208 }
209
210 /* store hex str (for left side) */
211 snprintf(bytestr, sizeof(bytestr), "%02X ", *p);
212 strncat(hexstr, bytestr, sizeof(hexstr)-strlen(hexstr)-1);
213
214 /* store char str (for right side) */
215 snprintf(bytestr, sizeof(bytestr), "%c", c);
216 strncat(charstr, bytestr, sizeof(charstr)-strlen(charstr)-1);
217
218 if(n%16 == 0) {
219 /* line completed */
220 bdt_log("[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr);
221 hexstr[0] = 0;
222 charstr[0] = 0;
223 } else if(n%8 == 0) {
224 /* half line: add whitespaces */
225 strncat(hexstr, " ", sizeof(hexstr)-strlen(hexstr)-1);
226 strncat(charstr, " ", sizeof(charstr)-strlen(charstr)-1);
227 }
228 p++; /* next byte */
229 }
230
231 if (strlen(hexstr) > 0) {
232 /* print rest of buffer if not empty */
233 bdt_log("[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr);
234 }
235 }
236
237 /*******************************************************************************
238 ** Console helper functions
239 *******************************************************************************/
240
skip_blanks(char ** p)241 void skip_blanks(char **p)
242 {
243 while (**p == ' ')
244 (*p)++;
245 }
246
get_int(char ** p,int DefaultValue)247 uint32_t get_int(char **p, int DefaultValue)
248 {
249 uint32_t Value = 0;
250 unsigned char UseDefault;
251
252 UseDefault = 1;
253 skip_blanks(p);
254
255 while ( ((**p)<= '9' && (**p)>= '0') )
256 {
257 Value = Value * 10 + (**p) - '0';
258 UseDefault = 0;
259 (*p)++;
260 }
261
262 if (UseDefault)
263 return DefaultValue;
264 else
265 return Value;
266 }
267
get_signed_int(char ** p,int DefaultValue)268 int get_signed_int(char **p, int DefaultValue)
269 {
270 int Value = 0;
271 unsigned char UseDefault;
272 unsigned char NegativeNum = 0;
273
274 UseDefault = 1;
275 skip_blanks(p);
276
277 if ( (**p) == '-')
278 {
279 NegativeNum = 1;
280 (*p)++;
281 }
282 while ( ((**p)<= '9' && (**p)>= '0') )
283 {
284 Value = Value * 10 + (**p) - '0';
285 UseDefault = 0;
286 (*p)++;
287 }
288
289 if (UseDefault)
290 return DefaultValue;
291 else
292 return ((NegativeNum == 0)? Value : -Value);
293 }
294
get_str(char ** p,char * Buffer)295 void get_str(char **p, char *Buffer)
296 {
297 skip_blanks(p);
298
299 while (**p != 0 && **p != ' ')
300 {
301 *Buffer = **p;
302 (*p)++;
303 Buffer++;
304 }
305
306 *Buffer = 0;
307 }
308
get_hex(char ** p,int DefaultValue)309 uint32_t get_hex(char **p, int DefaultValue)
310 {
311 uint32_t Value = 0;
312 unsigned char UseDefault;
313
314 UseDefault = 1;
315 skip_blanks(p);
316
317 while ( ((**p)<= '9' && (**p)>= '0') ||
318 ((**p)<= 'f' && (**p)>= 'a') ||
319 ((**p)<= 'F' && (**p)>= 'A') )
320 {
321 if (**p >= 'a')
322 Value = Value * 16 + (**p) - 'a' + 10;
323 else if (**p >= 'A')
324 Value = Value * 16 + (**p) - 'A' + 10;
325 else
326 Value = Value * 16 + (**p) - '0';
327 UseDefault = 0;
328 (*p)++;
329 }
330
331 if (UseDefault)
332 return DefaultValue;
333 else
334 return Value;
335 }
336
get_bdaddr(const char * str,bt_bdaddr_t * bd)337 void get_bdaddr(const char *str, bt_bdaddr_t *bd) {
338 char *d = ((char *)bd), *endp;
339 int i;
340 for(i = 0; i < 6; i++) {
341 *d++ = strtol(str, &endp, 16);
342 if (*endp != ':' && i != 5) {
343 memset(bd, 0, sizeof(bt_bdaddr_t));
344 return;
345 }
346 str = endp + 1;
347 }
348 }
349
350 #define is_cmd(str) ((strlen(str) == strlen(cmd)) && strncmp((const char *)&cmd, str, strlen(str)) == 0)
351 #define if_cmd(str) if (is_cmd(str))
352
353 typedef void (t_console_cmd_handler) (char *p);
354
355 typedef struct {
356 const char *name;
357 t_console_cmd_handler *handler;
358 const char *help;
359 unsigned char is_job;
360 } t_cmd;
361
362
363 const t_cmd console_cmd_list[];
364 static int console_cmd_maxlen = 0;
365
cmdjob_handler(void * param)366 static void cmdjob_handler(void *param)
367 {
368 char *job_cmd = (char*)param;
369
370 bdt_log("cmdjob starting (%s)", job_cmd);
371
372 process_cmd(job_cmd, 1);
373
374 bdt_log("cmdjob terminating");
375
376 free(job_cmd);
377 }
378
create_cmdjob(char * cmd)379 static int create_cmdjob(char *cmd)
380 {
381 pthread_t thread_id;
382 char *job_cmd;
383
384 job_cmd = malloc(strlen(cmd)+1); /* freed in job handler */
385 strcpy(job_cmd, cmd);
386
387 if (pthread_create(&thread_id, NULL,
388 (void*)cmdjob_handler, (void*)job_cmd)!=0)
389 perror("pthread_create");
390
391 return 0;
392 }
393
394 /*******************************************************************************
395 ** Load stack lib
396 *******************************************************************************/
397
HAL_load(void)398 int HAL_load(void)
399 {
400 int err = 0;
401
402 hw_module_t* module;
403 hw_device_t* device;
404
405 bdt_log("Loading HAL lib + extensions");
406
407 err = hw_get_module(BT_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
408 if (err == 0)
409 {
410 err = module->methods->open(module, BT_HARDWARE_MODULE_ID, &device);
411 if (err == 0) {
412 bt_device = (bluetooth_device_t *)device;
413 sBtInterface = bt_device->get_bluetooth_interface();
414 }
415 }
416
417 bdt_log("HAL library loaded (%s)", strerror(err));
418
419 return err;
420 }
421
HAL_unload(void)422 int HAL_unload(void)
423 {
424 int err = 0;
425
426 bdt_log("Unloading HAL lib");
427
428 sBtInterface = NULL;
429
430 bdt_log("HAL library unloaded (%s)", strerror(err));
431
432 return err;
433 }
434
435 /*******************************************************************************
436 ** HAL test functions & callbacks
437 *******************************************************************************/
438
setup_test_env(void)439 void setup_test_env(void)
440 {
441 int i = 0;
442
443 while (console_cmd_list[i].name != NULL)
444 {
445 console_cmd_maxlen = MAX(console_cmd_maxlen, (int)strlen(console_cmd_list[i].name));
446 i++;
447 }
448 }
449
check_return_status(bt_status_t status)450 void check_return_status(bt_status_t status)
451 {
452 if (status != BT_STATUS_SUCCESS)
453 {
454 bdt_log("HAL REQUEST FAILED status : %d (%s)", status, dump_bt_status(status));
455 }
456 else
457 {
458 bdt_log("HAL REQUEST SUCCESS");
459 }
460 }
461
adapter_state_changed(bt_state_t state)462 static void adapter_state_changed(bt_state_t state)
463 {
464 bdt_log("ADAPTER STATE UPDATED : %s", (state == BT_STATE_OFF)?"OFF":"ON");
465 if (state == BT_STATE_ON) {
466 bt_enabled = 1;
467 } else {
468 bt_enabled = 0;
469 }
470 }
471
dut_mode_recv(uint16_t opcode,uint8_t * buf,uint8_t len)472 static void dut_mode_recv(uint16_t opcode, uint8_t *buf, uint8_t len)
473 {
474 bdt_log("DUT MODE RECV : NOT IMPLEMENTED");
475 }
476
477 static bt_callbacks_t bt_callbacks = {
478 sizeof(bt_callbacks_t),
479 adapter_state_changed,
480 NULL, /*adapter_properties_cb */
481 NULL, /* remote_device_properties_cb */
482 NULL, /* device_found_cb */
483 NULL, /* discovery_state_changed_cb */
484 NULL, /* pin_request_cb */
485 NULL, /* ssp_request_cb */
486 NULL, /*bond_state_changed_cb */
487 NULL, /* acl_state_changed_cb */
488 NULL, /* thread_evt_cb */
489 dut_mode_recv, /*dut_mode_recv_cb */
490 };
491
bdt_init(void)492 void bdt_init(void)
493 {
494 bdt_log("INIT BT ");
495 status = sBtInterface->init(&bt_callbacks);
496 check_return_status(status);
497 }
498
bdt_enable(void)499 void bdt_enable(void)
500 {
501 bdt_log("ENABLE BT");
502 if (bt_enabled) {
503 bdt_log("Bluetooth is already enabled");
504 return;
505 }
506 status = sBtInterface->enable();
507
508 check_return_status(status);
509 }
510
bdt_disable(void)511 void bdt_disable(void)
512 {
513 bdt_log("DISABLE BT");
514 if (!bt_enabled) {
515 bdt_log("Bluetooth is already disabled");
516 return;
517 }
518 status = sBtInterface->disable();
519
520 check_return_status(status);
521 }
bdt_dut_mode_configure(char * p)522 void bdt_dut_mode_configure(char *p)
523 {
524 int32_t mode = -1;
525
526 bdt_log("BT DUT MODE CONFIGURE");
527 if (!bt_enabled) {
528 bdt_log("Bluetooth must be enabled for test_mode to work.");
529 return;
530 }
531 mode = get_signed_int(&p, mode);
532 if ((mode != 0) && (mode != 1)) {
533 bdt_log("Please specify mode: 1 to enter, 0 to exit");
534 return;
535 }
536 status = sBtInterface->dut_mode_configure(mode);
537
538 check_return_status(status);
539 }
540
bdt_cleanup(void)541 void bdt_cleanup(void)
542 {
543 bdt_log("CLEANUP");
544 sBtInterface->cleanup();
545 }
546
547 /*******************************************************************************
548 ** Console commands
549 *******************************************************************************/
550
do_help(char * p)551 void do_help(char *p)
552 {
553 int i = 0;
554 int max = 0;
555 char line[128];
556 int pos = 0;
557
558 while (console_cmd_list[i].name != NULL)
559 {
560 pos = sprintf(line, "%s", (char*)console_cmd_list[i].name);
561 bdt_log("%s %s\n", (char*)line, (char*)console_cmd_list[i].help);
562 i++;
563 }
564 }
565
do_quit(char * p)566 void do_quit(char *p)
567 {
568 bdt_shutdown();
569 }
570
571 /*******************************************************************
572 *
573 * BT TEST CONSOLE COMMANDS
574 *
575 * Parses argument lists and passes to API test function
576 *
577 */
578
do_init(char * p)579 void do_init(char *p)
580 {
581 bdt_init();
582 }
583
do_enable(char * p)584 void do_enable(char *p)
585 {
586 bdt_enable();
587 }
588
do_disable(char * p)589 void do_disable(char *p)
590 {
591 bdt_disable();
592 }
do_dut_mode_configure(char * p)593 void do_dut_mode_configure(char *p)
594 {
595 bdt_dut_mode_configure(p);
596 }
597
do_cleanup(char * p)598 void do_cleanup(char *p)
599 {
600 bdt_cleanup();
601 }
602
603 /*******************************************************************
604 *
605 * CONSOLE COMMAND TABLE
606 *
607 */
608
609 const t_cmd console_cmd_list[] =
610 {
611 /*
612 * INTERNAL
613 */
614
615 { "help", do_help, "lists all available console commands", 0 },
616 { "quit", do_quit, "", 0},
617
618 /*
619 * API CONSOLE COMMANDS
620 */
621
622 /* Init and Cleanup shall be called automatically */
623 { "enable", do_enable, ":: enables bluetooth", 0 },
624 { "disable", do_disable, ":: disables bluetooth", 0 },
625 { "dut_mode_configure", do_dut_mode_configure, ":: DUT mode - 1 to enter,0 to exit", 0 },
626
627 /* add here */
628
629 /* last entry */
630 {NULL, NULL, "", 0},
631 };
632
633 /*
634 * Main console command handler
635 */
636
process_cmd(char * p,unsigned char is_job)637 static void process_cmd(char *p, unsigned char is_job)
638 {
639 char cmd[64];
640 int i = 0;
641 char *p_saved = p;
642
643 get_str(&p, cmd);
644
645 /* table commands */
646 while (console_cmd_list[i].name != NULL)
647 {
648 if (is_cmd(console_cmd_list[i].name))
649 {
650 if (!is_job && console_cmd_list[i].is_job)
651 create_cmdjob(p_saved);
652 else
653 {
654 console_cmd_list[i].handler(p);
655 }
656 return;
657 }
658 i++;
659 }
660 bdt_log("%s : unknown command\n", p_saved);
661 do_help(NULL);
662 }
663
main(int argc,char * argv[])664 int main (int argc, char * argv[])
665 {
666 int opt;
667 char cmd[128];
668 int args_processed = 0;
669 int pid = -1;
670
671 config_permissions();
672 bdt_log("\n:::::::::::::::::::::::::::::::::::::::::::::::::::");
673 bdt_log(":: Bluedroid test app starting");
674
675 if ( HAL_load() < 0 ) {
676 perror("HAL failed to initialize, exit\n");
677 unlink(PID_FILE);
678 exit(0);
679 }
680
681 setup_test_env();
682
683 /* Automatically perform the init */
684 bdt_init();
685
686 while(!main_done)
687 {
688 char line[128];
689
690 /* command prompt */
691 printf( ">" );
692 fflush(stdout);
693
694 fgets (line, 128, stdin);
695
696 if (line[0]!= '\0')
697 {
698 /* remove linefeed */
699 line[strlen(line)-1] = 0;
700
701 process_cmd(line, 0);
702 memset(line, '\0', 128);
703 }
704 }
705
706 /* FIXME: Commenting this out as for some reason, the application does not exit otherwise*/
707 //bdt_cleanup();
708
709 HAL_unload();
710
711 bdt_log(":: Bluedroid test app terminating");
712
713 return 0;
714 }
715