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