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/************************************************************************************
62**  Local type definitions
63************************************************************************************/
64
65/************************************************************************************
66**  Static variables
67************************************************************************************/
68
69static unsigned char main_done = 0;
70static bt_status_t status;
71
72/* Main API */
73static bluetooth_device_t* bt_device;
74
75const bt_interface_t* sBtInterface = NULL;
76
77static 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 */
82static unsigned char bt_enabled = 0;
83
84/************************************************************************************
85**  Static functions
86************************************************************************************/
87
88static void process_cmd(char *p, unsigned char is_job);
89static void job_handler(void *param);
90static 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
106static 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
117static 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
151void 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 *******************************************************************************/
166static 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
182static 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
241void skip_blanks(char **p)
242{
243  while (**p == ' ')
244    (*p)++;
245}
246
247uint32_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
268int 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
295void 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
309uint32_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
337void 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
353typedef void (t_console_cmd_handler) (char *p);
354
355typedef 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
363const t_cmd console_cmd_list[];
364static int console_cmd_maxlen = 0;
365
366static 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
379static 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
398int 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
422int 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
439void 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
450void 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
462static 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
472static void dut_mode_recv(uint16_t opcode, uint8_t *buf, uint8_t len)
473{
474    bdt_log("DUT MODE RECV : NOT IMPLEMENTED");
475}
476
477static void le_test_mode(bt_status_t status, uint16_t packet_count)
478{
479    bdt_log("LE TEST MODE END status:%s number_of_packets:%d", dump_bt_status(status), packet_count);
480}
481
482static bt_callbacks_t bt_callbacks = {
483    sizeof(bt_callbacks_t),
484    adapter_state_changed,
485    NULL, /*adapter_properties_cb */
486    NULL, /* remote_device_properties_cb */
487    NULL, /* device_found_cb */
488    NULL, /* discovery_state_changed_cb */
489    NULL, /* pin_request_cb  */
490    NULL, /* ssp_request_cb  */
491    NULL, /*bond_state_changed_cb */
492    NULL, /* acl_state_changed_cb */
493    NULL, /* thread_evt_cb */
494    dut_mode_recv, /*dut_mode_recv_cb */
495//    NULL, /*authorize_request_cb */
496#if BLE_INCLUDED == TRUE
497    le_test_mode /* le_test_mode_cb */
498#else
499    NULL
500#endif
501};
502
503void bdt_init(void)
504{
505    bdt_log("INIT BT ");
506    status = sBtInterface->init(&bt_callbacks);
507    check_return_status(status);
508}
509
510void bdt_enable(void)
511{
512    bdt_log("ENABLE BT");
513    if (bt_enabled) {
514        bdt_log("Bluetooth is already enabled");
515        return;
516    }
517    status = sBtInterface->enable();
518
519    check_return_status(status);
520}
521
522void bdt_disable(void)
523{
524    bdt_log("DISABLE BT");
525    if (!bt_enabled) {
526        bdt_log("Bluetooth is already disabled");
527        return;
528    }
529    status = sBtInterface->disable();
530
531    check_return_status(status);
532}
533void bdt_dut_mode_configure(char *p)
534{
535    int32_t mode = -1;
536
537    bdt_log("BT DUT MODE CONFIGURE");
538    if (!bt_enabled) {
539        bdt_log("Bluetooth must be enabled for test_mode to work.");
540        return;
541    }
542    mode = get_signed_int(&p, mode);
543    if ((mode != 0) && (mode != 1)) {
544        bdt_log("Please specify mode: 1 to enter, 0 to exit");
545        return;
546    }
547    status = sBtInterface->dut_mode_configure(mode);
548
549    check_return_status(status);
550}
551
552#define HCI_LE_RECEIVER_TEST_OPCODE 0x201D
553#define HCI_LE_TRANSMITTER_TEST_OPCODE 0x201E
554#define HCI_LE_END_TEST_OPCODE 0x201F
555
556void bdt_le_test_mode(char *p)
557{
558    int cmd;
559    unsigned char buf[3];
560    int arg1, arg2, arg3;
561
562    bdt_log("BT LE TEST MODE");
563    if (!bt_enabled) {
564        bdt_log("Bluetooth must be enabled for le_test to work.");
565        return;
566    }
567
568    memset(buf, 0, sizeof(buf));
569    cmd = get_int(&p, 0);
570    switch (cmd)
571    {
572        case 0x1: /* RX TEST */
573           arg1 = get_int(&p, -1);
574           if (arg1 < 0) bdt_log("%s Invalid arguments", __FUNCTION__);
575           buf[0] = arg1;
576           status = sBtInterface->le_test_mode(HCI_LE_RECEIVER_TEST_OPCODE, buf, 1);
577           break;
578        case 0x2: /* TX TEST */
579            arg1 = get_int(&p, -1);
580            arg2 = get_int(&p, -1);
581            arg3 = get_int(&p, -1);
582            if ((arg1 < 0) || (arg2 < 0) || (arg3 < 0))
583                bdt_log("%s Invalid arguments", __FUNCTION__);
584            buf[0] = arg1;
585            buf[1] = arg2;
586            buf[2] = arg3;
587            status = sBtInterface->le_test_mode(HCI_LE_TRANSMITTER_TEST_OPCODE, buf, 3);
588           break;
589        case 0x3: /* END TEST */
590            status = sBtInterface->le_test_mode(HCI_LE_END_TEST_OPCODE, buf, 0);
591           break;
592        default:
593            bdt_log("Unsupported command");
594            return;
595            break;
596    }
597    if (status != BT_STATUS_SUCCESS)
598    {
599        bdt_log("%s Test 0x%x Failed with status:0x%x", __FUNCTION__, cmd, status);
600    }
601    return;
602}
603
604void bdt_cleanup(void)
605{
606    bdt_log("CLEANUP");
607    sBtInterface->cleanup();
608}
609
610/*******************************************************************************
611 ** Console commands
612 *******************************************************************************/
613
614void do_help(char *p)
615{
616    int i = 0;
617    int max = 0;
618    char line[128];
619    int pos = 0;
620
621    while (console_cmd_list[i].name != NULL)
622    {
623        pos = sprintf(line, "%s", (char*)console_cmd_list[i].name);
624        bdt_log("%s %s\n", (char*)line, (char*)console_cmd_list[i].help);
625        i++;
626    }
627}
628
629void do_quit(char *p)
630{
631    bdt_shutdown();
632}
633
634/*******************************************************************
635 *
636 *  BT TEST  CONSOLE COMMANDS
637 *
638 *  Parses argument lists and passes to API test function
639 *
640*/
641
642void do_init(char *p)
643{
644    bdt_init();
645}
646
647void do_enable(char *p)
648{
649    bdt_enable();
650}
651
652void do_disable(char *p)
653{
654    bdt_disable();
655}
656void do_dut_mode_configure(char *p)
657{
658    bdt_dut_mode_configure(p);
659}
660
661void do_le_test_mode(char *p)
662{
663    bdt_le_test_mode(p);
664}
665
666void do_cleanup(char *p)
667{
668    bdt_cleanup();
669}
670
671/*******************************************************************
672 *
673 *  CONSOLE COMMAND TABLE
674 *
675*/
676
677const t_cmd console_cmd_list[] =
678{
679    /*
680     * INTERNAL
681     */
682
683    { "help", do_help, "lists all available console commands", 0 },
684    { "quit", do_quit, "", 0},
685
686    /*
687     * API CONSOLE COMMANDS
688     */
689
690     /* Init and Cleanup shall be called automatically */
691    { "enable", do_enable, ":: enables bluetooth", 0 },
692    { "disable", do_disable, ":: disables bluetooth", 0 },
693    { "dut_mode_configure", do_dut_mode_configure, ":: DUT mode - 1 to enter,0 to exit", 0 },
694    { "le_test_mode", do_le_test_mode, ":: LE Test Mode - RxTest - 1 <rx_freq>, \n\t \
695                      TxTest - 2 <tx_freq> <test_data_len> <payload_pattern>, \n\t \
696                      End Test - 3 <no_args>", 0 },
697    /* add here */
698
699    /* last entry */
700    {NULL, NULL, "", 0},
701};
702
703/*
704 * Main console command handler
705*/
706
707static void process_cmd(char *p, unsigned char is_job)
708{
709    char cmd[64];
710    int i = 0;
711    char *p_saved = p;
712
713    get_str(&p, cmd);
714
715    /* table commands */
716    while (console_cmd_list[i].name != NULL)
717    {
718        if (is_cmd(console_cmd_list[i].name))
719        {
720            if (!is_job && console_cmd_list[i].is_job)
721                create_cmdjob(p_saved);
722            else
723            {
724                console_cmd_list[i].handler(p);
725            }
726            return;
727        }
728        i++;
729    }
730    bdt_log("%s : unknown command\n", p_saved);
731    do_help(NULL);
732}
733
734int main (int argc, char * argv[])
735{
736    int opt;
737    char cmd[128];
738    int args_processed = 0;
739    int pid = -1;
740
741    config_permissions();
742    bdt_log("\n:::::::::::::::::::::::::::::::::::::::::::::::::::");
743    bdt_log(":: Bluedroid test app starting");
744
745    if ( HAL_load() < 0 ) {
746        perror("HAL failed to initialize, exit\n");
747        unlink(PID_FILE);
748        exit(0);
749    }
750
751    setup_test_env();
752
753    /* Automatically perform the init */
754    bdt_init();
755
756    while(!main_done)
757    {
758        char line[128];
759
760        /* command prompt */
761        printf( ">" );
762        fflush(stdout);
763
764        fgets (line, 128, stdin);
765
766        if (line[0]!= '\0')
767        {
768            /* remove linefeed */
769            line[strlen(line)-1] = 0;
770
771            process_cmd(line, 0);
772            memset(line, '\0', 128);
773        }
774    }
775
776    /* FIXME: Commenting this out as for some reason, the application does not exit otherwise*/
777    //bdt_cleanup();
778
779    HAL_unload();
780
781    bdt_log(":: Bluedroid test app terminating");
782
783    return 0;
784}
785