• 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:      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