1 /****************************************************************************** 2 * 3 * Copyright (C) 2014 Google, Inc. 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 #include <getopt.h> 20 #include <signal.h> 21 #include <stdlib.h> 22 #include <unistd.h> 23 24 #include "btcore/include/bdaddr.h" 25 #include "btcore/include/property.h" 26 #include "osi/include/osi.h" 27 #include "test/suite/support/callbacks.h" 28 #include "test/suite/support/hal.h" 29 30 static const bt_uuid_t HFP_UUID = {{ 0x00, 0x00, 0x11, 0x1E, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB }}; 31 static const bt_uuid_t HFP_AG_UUID = {{ 0x00, 0x00, 0x11, 0x1F, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB }}; 32 33 const bt_interface_t *bt_interface; 34 35 bt_bdaddr_t bt_remote_bdaddr; 36 37 static int f_verbose; 38 static bool discover = false; 39 static bool discoverable = false; 40 static bool bond = false; 41 static bool up = false; 42 static bool get_name = false; 43 static bool set_name = false; 44 static bool sco_listen = false; 45 static bool sco_connect = false; 46 47 static int timeout_in_sec = 30; 48 static char *bd_name; 49 50 static struct option long_options[] = { 51 {"bdaddr", required_argument, 0, 0 }, 52 {"discover", no_argument, 0, 0 }, 53 {"discoverable", no_argument, 0, 0 }, 54 {"time", required_argument, 0, 0 }, 55 {"bond", no_argument, 0, 0 }, 56 {"up", no_argument, 0, 0 }, 57 {"verbose", no_argument, 0, 0 }, 58 {"get_name", no_argument, 0, 0 }, 59 {"set_name", required_argument, 0, 0 }, 60 {"sco_listen", no_argument, 0, 0 }, 61 {"sco_connect", no_argument, 0, 0 }, 62 {0, 0, 0, 0 } 63 }; 64 65 static void usage(const char *name); 66 static bool parse_args(int argc, char **argv); 67 static void sig_handler(int signo); 68 69 bt_property_t *adapter_get_property(bt_property_type_t type); 70 71 int main(int argc, char **argv) { 72 if (!parse_args(argc, argv)) { 73 usage(argv[0]); 74 } 75 76 if (bond && discoverable) { 77 fprintf(stderr, "Can only select either bond or discoverable, not both\n"); 78 usage(argv[0]); 79 } 80 81 if (sco_listen && sco_connect) { 82 fprintf(stderr, "Can only select either sco_listen or sco_connect, not both\n"); 83 usage(argv[0]); 84 } 85 86 if (!bond && !discover && !discoverable && !up && !get_name && !set_name && !sco_listen && !sco_connect) { 87 fprintf(stderr, "Must specify one command\n"); 88 usage(argv[0]); 89 } 90 91 if (signal(SIGINT, sig_handler) == SIG_ERR) { 92 fprintf(stderr, "Will be unable to catch signals\n"); 93 } 94 95 fprintf(stdout, "Bringing up bluetooth adapter\n"); 96 if (!hal_open(callbacks_get_adapter_struct())) { 97 fprintf(stderr, "Unable to open Bluetooth HAL.\n"); 98 return 1; 99 } 100 101 if (discover) { 102 CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed); 103 fprintf(stdout, "BT adapter is up\n"); 104 105 fprintf(stdout, "Starting to start discovery\n"); 106 CALL_AND_WAIT(bt_interface->start_discovery(), discovery_state_changed); 107 fprintf(stdout, "Started discovery for %d seconds\n", timeout_in_sec); 108 109 sleep(timeout_in_sec); 110 111 fprintf(stdout, "Starting to cancel discovery\n"); 112 CALL_AND_WAIT(bt_interface->cancel_discovery(), discovery_state_changed); 113 fprintf(stdout, "Cancelled discovery after %d seconds\n", timeout_in_sec); 114 } 115 116 if (discoverable) { 117 CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed); 118 fprintf(stdout, "BT adapter is up\n"); 119 120 bt_property_t *property = property_new_scan_mode(BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE); 121 122 int rc = bt_interface->set_adapter_property(property); 123 fprintf(stdout, "Set rc:%d device as discoverable for %d seconds\n", rc, timeout_in_sec); 124 125 sleep(timeout_in_sec); 126 127 property_free(property); 128 } 129 130 if (bond) { 131 if (bdaddr_is_empty(&bt_remote_bdaddr)) { 132 fprintf(stderr, "Must specify a remote device address [ --bdaddr=xx:yy:zz:aa:bb:cc ]\n"); 133 exit(1); 134 } 135 136 CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed); 137 fprintf(stdout, "BT adapter is up\n"); 138 139 int rc = bt_interface->create_bond(&bt_remote_bdaddr, 0 /* UNKNOWN; Currently not documented :( */); 140 fprintf(stdout, "Started bonding:%d for %d seconds\n", rc, timeout_in_sec); 141 142 sleep(timeout_in_sec); 143 } 144 145 if (up) { 146 CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed); 147 fprintf(stdout, "BT adapter is up\n"); 148 149 fprintf(stdout, "Waiting for %d seconds\n", timeout_in_sec); 150 sleep(timeout_in_sec); 151 } 152 153 if (get_name) { 154 CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed); 155 fprintf(stdout, "BT adapter is up\n"); 156 int error; 157 CALL_AND_WAIT(error = bt_interface->get_adapter_property(BT_PROPERTY_BDNAME), adapter_properties); 158 if (error != BT_STATUS_SUCCESS) { 159 fprintf(stderr, "Unable to get adapter property\n"); 160 exit(1); 161 } 162 bt_property_t *property = adapter_get_property(BT_PROPERTY_BDNAME); 163 const bt_bdname_t *name = property_as_name(property); 164 if (name) 165 printf("Queried bluetooth device name:%s\n", name->name); 166 else 167 printf("No name\n"); 168 } 169 170 if (set_name) { 171 CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed); 172 fprintf(stdout, "BT adapter is up\n"); 173 174 bt_property_t *property = property_new_name(bd_name); 175 printf("Setting bluetooth device name to:%s\n", bd_name); 176 int error; 177 CALL_AND_WAIT(error = bt_interface->set_adapter_property(property), adapter_properties); 178 if (error != BT_STATUS_SUCCESS) { 179 fprintf(stderr, "Unable to set adapter property\n"); 180 exit(1); 181 } 182 CALL_AND_WAIT(error = bt_interface->get_adapter_property(BT_PROPERTY_BDNAME), adapter_properties); 183 if (error != BT_STATUS_SUCCESS) { 184 fprintf(stderr, "Unable to get adapter property\n"); 185 exit(1); 186 } 187 property_free(property); 188 sleep(timeout_in_sec); 189 } 190 191 if (sco_listen) { 192 CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed); 193 fprintf(stdout, "BT adapter is up\n"); 194 195 bt_property_t *property = property_new_scan_mode(BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE); 196 CALL_AND_WAIT(bt_interface->set_adapter_property(property), adapter_properties); 197 property_free(property); 198 199 const btsock_interface_t *sock = bt_interface->get_profile_interface(BT_PROFILE_SOCKETS_ID); 200 201 int rfcomm_fd = INVALID_FD; 202 int error = sock->listen(BTSOCK_RFCOMM, "meow", (const uint8_t *)&HFP_AG_UUID, 0, &rfcomm_fd, 0); 203 if (error != BT_STATUS_SUCCESS) { 204 fprintf(stderr, "Unable to listen for incoming RFCOMM socket: %d\n", error); 205 exit(1); 206 } 207 208 int sock_fd = INVALID_FD; 209 error = sock->listen(BTSOCK_SCO, NULL, NULL, 5, &sock_fd, 0); 210 if (error != BT_STATUS_SUCCESS) { 211 fprintf(stderr, "Unable to listen for incoming SCO sockets: %d\n", error); 212 exit(1); 213 } 214 fprintf(stdout, "Waiting for incoming SCO connections...\n"); 215 sleep(timeout_in_sec); 216 } 217 218 if (sco_connect) { 219 if (bdaddr_is_empty(&bt_remote_bdaddr)) { 220 fprintf(stderr, "Must specify a remote device address [ --bdaddr=xx:yy:zz:aa:bb:cc ]\n"); 221 exit(1); 222 } 223 224 CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed); 225 fprintf(stdout, "BT adapter is up\n"); 226 227 const btsock_interface_t *sock = bt_interface->get_profile_interface(BT_PROFILE_SOCKETS_ID); 228 229 int rfcomm_fd = INVALID_FD; 230 int error = sock->connect(&bt_remote_bdaddr, BTSOCK_RFCOMM, (const uint8_t *)&HFP_AG_UUID, 0, &rfcomm_fd, 0); 231 if (error != BT_STATUS_SUCCESS) { 232 fprintf(stderr, "Unable to connect to RFCOMM socket: %d.\n", error); 233 exit(1); 234 } 235 236 WAIT(acl_state_changed); 237 238 fprintf(stdout, "Establishing SCO connection...\n"); 239 240 int sock_fd = INVALID_FD; 241 error = sock->connect(&bt_remote_bdaddr, BTSOCK_SCO, NULL, 5, &sock_fd, 0); 242 if (error != BT_STATUS_SUCCESS) { 243 fprintf(stderr, "Unable to connect to SCO socket: %d.\n", error); 244 exit(1); 245 } 246 sleep(timeout_in_sec); 247 } 248 249 CALL_AND_WAIT(bt_interface->disable(), adapter_state_changed); 250 fprintf(stdout, "BT adapter is down\n"); 251 } 252 253 static void sig_handler(int signo) { 254 if (signo == SIGINT) { 255 fprintf(stderr, "Received SIGINT\n"); 256 CALL_AND_WAIT(bt_interface->disable(), adapter_state_changed); 257 fprintf(stderr, "BT adapter is down\n"); 258 exit(1); 259 } 260 } 261 262 static void usage(const char *name) { 263 fprintf(stderr, "Usage: %s [--bond|--discover|--discoverable|--up|--sco_listen|--sco_connect] [--bdaddr=<bdaddr>] [--time=<time_in_sec>] --verbose\n", name); 264 fprintf(stderr, " bond: Discover actively advertising devices\n"); 265 fprintf(stderr, " discover: Discover actively advertising devices\n"); 266 fprintf(stderr, " discoverable: Set into a connectable and discoverable mode\n"); 267 fprintf(stderr, " up: Only bring up stack\n"); 268 fprintf(stderr, " sco_listen: Listen for incoming SCO connections\n"); 269 fprintf(stderr, " sco_connect: Establish a SCO connection with another device\n"); 270 fprintf(stderr, " time: Time to hold in the specified mode\n"); 271 exit(1); 272 } 273 274 static bool parse_args(int argc, char **argv) { 275 while (1) { 276 int option_index = 0; 277 int c = getopt_long_only(argc, argv, "", long_options, &option_index); 278 if (c != 0) 279 break; 280 281 switch (c) { 282 case 0: 283 if (option_index == 0) { 284 if (!string_to_bdaddr(optarg, &bt_remote_bdaddr)) { 285 return false; 286 } 287 } 288 if (option_index == 1) { 289 discover = true; 290 } 291 if (option_index == 2) { 292 discoverable = true; 293 } 294 if (option_index == 3) { 295 timeout_in_sec = atoi(optarg); 296 } 297 if (option_index == 4) { 298 bond = true; 299 } 300 if (option_index == 5) { 301 up = true; 302 } 303 if (option_index == 6) { 304 f_verbose++; 305 } 306 if (option_index == 7) { 307 get_name = true; 308 } 309 if (option_index == 8) { 310 bd_name = (char *)optarg; 311 set_name = true; 312 } 313 if (option_index == 9) { 314 sco_listen = true; 315 } 316 if (option_index == 10) { 317 sco_connect = true; 318 } 319 break; 320 321 default: 322 fprintf(stderr, "?? getopt returned character code 0%o ??\n", c); 323 } 324 } 325 326 if (optind < argc) { 327 fprintf(stderr, "non-option ARGV-elements: "); 328 while (optind < argc) 329 fprintf(stderr, "%s ", argv[optind++]); 330 fprintf(stderr, "\n"); 331 return false; 332 } 333 return true; 334 } 335