bluedroidtest.c revision 6dae552ef8d82b30fa66efab9c6f75644a805bbe
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)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
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//    NULL, /*authorize_request_cb */
498#if BLE_INCLUDED == TRUE
499    le_test_mode /* le_test_mode_cb */
500#else
501    NULL
502#endif
503};
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
554#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
606void bdt_cleanup(void)
607{
608    bdt_log("CLEANUP");
609    sBtInterface->cleanup();
610}
611
612/*******************************************************************************
613 ** Console commands
614 *******************************************************************************/
615
616void do_help(char UNUSED *p)
617{
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
631void do_quit(char UNUSED *p)
632{
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
644void do_init(char UNUSED *p)
645{
646    bdt_init();
647}
648
649void do_enable(char UNUSED *p)
650{
651    bdt_enable();
652}
653
654void do_disable(char UNUSED *p)
655{
656    bdt_disable();
657}
658void do_dut_mode_configure(char *p)
659{
660    bdt_dut_mode_configure(p);
661}
662
663void do_le_test_mode(char *p)
664{
665    bdt_le_test_mode(p);
666}
667
668void do_cleanup(char UNUSED *p)
669{
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 },
696    { "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 },
699    /* 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
736int main (int UNUSED argc, char UNUSED *argv[])
737{
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}
787