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 <sys/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#define UNUSED __attribute__((unused))
62
63/************************************************************************************
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)((uintptr_t)p-(uintptr_t)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
474static void dut_mode_recv(uint16_t UNUSED opcode, uint8_t UNUSED *buf, uint8_t UNUSED len)
475{
476    bdt_log("DUT MODE RECV : NOT IMPLEMENTED");
477}
478
479static 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
484static 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 */
497#if BLE_INCLUDED == TRUE
498    le_test_mode, /* le_test_mode_cb */
499#else
500    NULL, /* le_test_mode_cb */
501#endif
502    NULL /* energy_info_cb */
503};
504
505static bool set_wake_alarm(uint64_t delay_millis, bool should_wake, alarm_cb cb, void *data) {
506  static timer_t timer;
507  static bool timer_created;
508
509  if (!timer_created) {
510    struct sigevent sigevent;
511    memset(&sigevent, 0, sizeof(sigevent));
512    sigevent.sigev_notify = SIGEV_THREAD;
513    sigevent.sigev_notify_function = (void (*)(union sigval))cb;
514    sigevent.sigev_value.sival_ptr = data;
515    timer_create(CLOCK_MONOTONIC, &sigevent, &timer);
516    timer_created = true;
517  }
518
519  struct itimerspec new_value;
520  new_value.it_value.tv_sec = delay_millis / 1000;
521  new_value.it_value.tv_nsec = (delay_millis % 1000) * 1000 * 1000;
522  new_value.it_interval.tv_sec = 0;
523  new_value.it_interval.tv_nsec = 0;
524  timer_settime(timer, 0, &new_value, NULL);
525
526  return true;
527}
528
529static int acquire_wake_lock(const char *lock_name) {
530  return BT_STATUS_SUCCESS;
531}
532
533static int release_wake_lock(const char *lock_name) {
534  return BT_STATUS_SUCCESS;
535}
536
537static bt_os_callouts_t callouts = {
538    sizeof(bt_os_callouts_t),
539    set_wake_alarm,
540    acquire_wake_lock,
541    release_wake_lock,
542};
543
544void bdt_init(void)
545{
546    bdt_log("INIT BT ");
547    status = sBtInterface->init(&bt_callbacks);
548
549    if (status == BT_STATUS_SUCCESS) {
550        status = sBtInterface->set_os_callouts(&callouts);
551    }
552
553    check_return_status(status);
554}
555
556void bdt_enable(void)
557{
558    bdt_log("ENABLE BT");
559    if (bt_enabled) {
560        bdt_log("Bluetooth is already enabled");
561        return;
562    }
563    status = sBtInterface->enable();
564
565    check_return_status(status);
566}
567
568void bdt_disable(void)
569{
570    bdt_log("DISABLE BT");
571    if (!bt_enabled) {
572        bdt_log("Bluetooth is already disabled");
573        return;
574    }
575    status = sBtInterface->disable();
576
577    check_return_status(status);
578}
579void bdt_dut_mode_configure(char *p)
580{
581    int32_t mode = -1;
582
583    bdt_log("BT DUT MODE CONFIGURE");
584    if (!bt_enabled) {
585        bdt_log("Bluetooth must be enabled for test_mode to work.");
586        return;
587    }
588    mode = get_signed_int(&p, mode);
589    if ((mode != 0) && (mode != 1)) {
590        bdt_log("Please specify mode: 1 to enter, 0 to exit");
591        return;
592    }
593    status = sBtInterface->dut_mode_configure(mode);
594
595    check_return_status(status);
596}
597
598#define HCI_LE_RECEIVER_TEST_OPCODE 0x201D
599#define HCI_LE_TRANSMITTER_TEST_OPCODE 0x201E
600#define HCI_LE_END_TEST_OPCODE 0x201F
601
602void bdt_le_test_mode(char *p)
603{
604    int cmd;
605    unsigned char buf[3];
606    int arg1, arg2, arg3;
607
608    bdt_log("BT LE TEST MODE");
609    if (!bt_enabled) {
610        bdt_log("Bluetooth must be enabled for le_test to work.");
611        return;
612    }
613
614    memset(buf, 0, sizeof(buf));
615    cmd = get_int(&p, 0);
616    switch (cmd)
617    {
618        case 0x1: /* RX TEST */
619           arg1 = get_int(&p, -1);
620           if (arg1 < 0) bdt_log("%s Invalid arguments", __FUNCTION__);
621           buf[0] = arg1;
622           status = sBtInterface->le_test_mode(HCI_LE_RECEIVER_TEST_OPCODE, buf, 1);
623           break;
624        case 0x2: /* TX TEST */
625            arg1 = get_int(&p, -1);
626            arg2 = get_int(&p, -1);
627            arg3 = get_int(&p, -1);
628            if ((arg1 < 0) || (arg2 < 0) || (arg3 < 0))
629                bdt_log("%s Invalid arguments", __FUNCTION__);
630            buf[0] = arg1;
631            buf[1] = arg2;
632            buf[2] = arg3;
633            status = sBtInterface->le_test_mode(HCI_LE_TRANSMITTER_TEST_OPCODE, buf, 3);
634           break;
635        case 0x3: /* END TEST */
636            status = sBtInterface->le_test_mode(HCI_LE_END_TEST_OPCODE, buf, 0);
637           break;
638        default:
639            bdt_log("Unsupported command");
640            return;
641            break;
642    }
643    if (status != BT_STATUS_SUCCESS)
644    {
645        bdt_log("%s Test 0x%x Failed with status:0x%x", __FUNCTION__, cmd, status);
646    }
647    return;
648}
649
650void bdt_cleanup(void)
651{
652    bdt_log("CLEANUP");
653    sBtInterface->cleanup();
654}
655
656/*******************************************************************************
657 ** Console commands
658 *******************************************************************************/
659
660void do_help(char UNUSED *p)
661{
662    int i = 0;
663    int max = 0;
664    char line[128];
665    int pos = 0;
666
667    while (console_cmd_list[i].name != NULL)
668    {
669        pos = sprintf(line, "%s", (char*)console_cmd_list[i].name);
670        bdt_log("%s %s\n", (char*)line, (char*)console_cmd_list[i].help);
671        i++;
672    }
673}
674
675void do_quit(char UNUSED *p)
676{
677    bdt_shutdown();
678}
679
680/*******************************************************************
681 *
682 *  BT TEST  CONSOLE COMMANDS
683 *
684 *  Parses argument lists and passes to API test function
685 *
686*/
687
688void do_init(char UNUSED *p)
689{
690    bdt_init();
691}
692
693void do_enable(char UNUSED *p)
694{
695    bdt_enable();
696}
697
698void do_disable(char UNUSED *p)
699{
700    bdt_disable();
701}
702void do_dut_mode_configure(char *p)
703{
704    bdt_dut_mode_configure(p);
705}
706
707void do_le_test_mode(char *p)
708{
709    bdt_le_test_mode(p);
710}
711
712void do_cleanup(char UNUSED *p)
713{
714    bdt_cleanup();
715}
716
717/*******************************************************************
718 *
719 *  CONSOLE COMMAND TABLE
720 *
721*/
722
723const t_cmd console_cmd_list[] =
724{
725    /*
726     * INTERNAL
727     */
728
729    { "help", do_help, "lists all available console commands", 0 },
730    { "quit", do_quit, "", 0},
731
732    /*
733     * API CONSOLE COMMANDS
734     */
735
736     /* Init and Cleanup shall be called automatically */
737    { "enable", do_enable, ":: enables bluetooth", 0 },
738    { "disable", do_disable, ":: disables bluetooth", 0 },
739    { "dut_mode_configure", do_dut_mode_configure, ":: DUT mode - 1 to enter,0 to exit", 0 },
740    { "le_test_mode", do_le_test_mode, ":: LE Test Mode - RxTest - 1 <rx_freq>, \n\t \
741                      TxTest - 2 <tx_freq> <test_data_len> <payload_pattern>, \n\t \
742                      End Test - 3 <no_args>", 0 },
743    /* add here */
744
745    /* last entry */
746    {NULL, NULL, "", 0},
747};
748
749/*
750 * Main console command handler
751*/
752
753static void process_cmd(char *p, unsigned char is_job)
754{
755    char cmd[64];
756    int i = 0;
757    char *p_saved = p;
758
759    get_str(&p, cmd);
760
761    /* table commands */
762    while (console_cmd_list[i].name != NULL)
763    {
764        if (is_cmd(console_cmd_list[i].name))
765        {
766            if (!is_job && console_cmd_list[i].is_job)
767                create_cmdjob(p_saved);
768            else
769            {
770                console_cmd_list[i].handler(p);
771            }
772            return;
773        }
774        i++;
775    }
776    bdt_log("%s : unknown command\n", p_saved);
777    do_help(NULL);
778}
779
780int main (int UNUSED argc, char UNUSED *argv[])
781{
782    int opt;
783    char cmd[128];
784    int args_processed = 0;
785    int pid = -1;
786
787    config_permissions();
788    bdt_log("\n:::::::::::::::::::::::::::::::::::::::::::::::::::");
789    bdt_log(":: Bluedroid test app starting");
790
791    if ( HAL_load() < 0 ) {
792        perror("HAL failed to initialize, exit\n");
793        unlink(PID_FILE);
794        exit(0);
795    }
796
797    setup_test_env();
798
799    /* Automatically perform the init */
800    bdt_init();
801
802    while(!main_done)
803    {
804        char line[128];
805
806        /* command prompt */
807        printf( ">" );
808        fflush(stdout);
809
810        fgets (line, 128, stdin);
811
812        if (line[0]!= '\0')
813        {
814            /* remove linefeed */
815            line[strlen(line)-1] = 0;
816
817            process_cmd(line, 0);
818            memset(line, '\0', 128);
819        }
820    }
821
822    /* FIXME: Commenting this out as for some reason, the application does not exit otherwise*/
823    //bdt_cleanup();
824
825    HAL_unload();
826
827    bdt_log(":: Bluedroid test app terminating");
828
829    return 0;
830}
831