1 /* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2007-2010 Marcel Holtmann <marcel (at) holtmann.org> 6 * 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21 * 22 */ 23 24 #ifdef HAVE_CONFIG_H 25 #include <config.h> 26 #endif 27 28 #include <stdio.h> 29 #include <errno.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <getopt.h> 33 34 #include <dbus/dbus.h> 35 36 #define BLUEZ_SERVICE "org.bluez" 37 38 #define MANAGER_PATH "/" 39 #define MANAGER_INTF BLUEZ_SERVICE ".Manager" 40 #define ADAPTER_INTF BLUEZ_SERVICE ".Adapter" 41 42 static char *get_adapter(DBusConnection *conn) 43 { 44 DBusMessage *message, *reply; 45 DBusError error; 46 const char *path; 47 char *result = NULL; 48 49 message = dbus_message_new_method_call(BLUEZ_SERVICE, MANAGER_PATH, 50 MANAGER_INTF, "DefaultAdapter"); 51 if (!message) 52 return NULL; 53 54 dbus_error_init(&error); 55 56 reply = dbus_connection_send_with_reply_and_block(conn, 57 message, -1, &error); 58 59 dbus_message_unref(message); 60 61 if (!reply) { 62 if (dbus_error_is_set(&error) == TRUE) { 63 fprintf(stderr, "%s\n", error.message); 64 dbus_error_free(&error); 65 } else 66 fprintf(stderr, "Failed to set property\n"); 67 return NULL; 68 } 69 70 if (dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, &path, 71 DBUS_TYPE_INVALID) == FALSE) 72 goto done; 73 74 printf("Using default adapter %s\n", path); 75 76 result = strdup(path); 77 78 done: 79 dbus_message_unref(reply); 80 81 return result; 82 } 83 84 static char *find_device(DBusConnection *conn, const char *adapter, 85 const char *address) 86 { 87 DBusMessage *message, *reply; 88 DBusError error; 89 const char *path; 90 char *result = NULL; 91 92 message = dbus_message_new_method_call(BLUEZ_SERVICE, adapter, 93 ADAPTER_INTF, "FindDevice"); 94 if (!message) 95 return NULL; 96 97 dbus_message_append_args(message, DBUS_TYPE_STRING, &address, 98 DBUS_TYPE_INVALID); 99 100 dbus_error_init(&error); 101 102 reply = dbus_connection_send_with_reply_and_block(conn, 103 message, -1, &error); 104 105 dbus_message_unref(message); 106 107 if (!reply) { 108 if (dbus_error_is_set(&error) == TRUE) { 109 fprintf(stderr, "%s\n", error.message); 110 dbus_error_free(&error); 111 } else 112 fprintf(stderr, "Failed to set property\n"); 113 return NULL; 114 } 115 116 if (dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, &path, 117 DBUS_TYPE_INVALID) == FALSE) 118 goto done; 119 120 printf("Using device %s for address %s\n", path, address); 121 122 result = strdup(path); 123 124 done: 125 dbus_message_unref(reply); 126 127 return result; 128 } 129 130 static int remove_device(DBusConnection *conn, const char *adapter, 131 const char *device) 132 { 133 DBusMessage *message, *reply; 134 DBusError error; 135 136 message = dbus_message_new_method_call(BLUEZ_SERVICE, adapter, 137 ADAPTER_INTF, "RemoveDevice"); 138 if (!message) 139 return -ENOMEM; 140 141 dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &device, 142 DBUS_TYPE_INVALID); 143 144 dbus_error_init(&error); 145 146 reply = dbus_connection_send_with_reply_and_block(conn, 147 message, -1, &error); 148 149 dbus_message_unref(message); 150 151 if (!reply) { 152 if (dbus_error_is_set(&error) == TRUE) { 153 fprintf(stderr, "%s\n", error.message); 154 dbus_error_free(&error); 155 } else 156 fprintf(stderr, "Failed to set property\n"); 157 return -EIO; 158 } 159 160 dbus_message_unref(reply); 161 162 printf("Removed device %s\n", device); 163 164 return 0; 165 } 166 167 static int set_property(DBusConnection *conn, const char *adapter, 168 const char *key, int type, void *val) 169 { 170 DBusMessage *message, *reply; 171 DBusMessageIter array, value; 172 DBusError error; 173 const char *signature; 174 175 message = dbus_message_new_method_call(BLUEZ_SERVICE, adapter, 176 ADAPTER_INTF, "SetProperty"); 177 if (!message) 178 return -ENOMEM; 179 180 switch (type) { 181 case DBUS_TYPE_BOOLEAN: 182 signature = DBUS_TYPE_BOOLEAN_AS_STRING; 183 break; 184 case DBUS_TYPE_UINT32: 185 signature = DBUS_TYPE_UINT32_AS_STRING; 186 break; 187 default: 188 return -EILSEQ; 189 } 190 191 dbus_message_iter_init_append(message, &array); 192 193 dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING, &key); 194 195 dbus_message_iter_open_container(&array, DBUS_TYPE_VARIANT, 196 signature, &value); 197 dbus_message_iter_append_basic(&value, type, val); 198 dbus_message_iter_close_container(&array, &value); 199 200 dbus_error_init(&error); 201 202 reply = dbus_connection_send_with_reply_and_block(conn, 203 message, -1, &error); 204 205 dbus_message_unref(message); 206 207 if (!reply) { 208 if (dbus_error_is_set(&error) == TRUE) { 209 fprintf(stderr, "%s\n", error.message); 210 dbus_error_free(&error); 211 } else 212 fprintf(stderr, "Failed to set property\n"); 213 return -EIO; 214 } 215 216 dbus_message_unref(reply); 217 218 printf("Set property %s for %s\n", key, adapter); 219 220 return 0; 221 } 222 223 static void usage(void) 224 { 225 printf("gaptest - GAP testing\n" 226 "Usage:\n"); 227 printf("\tgaptest [options]\n"); 228 printf("Options:\n" 229 "\t-T <timeout> Set timeout\n" 230 "\t-P <powered> Set powered\n" 231 "\t-D <discoverable> Set discoverable\n" 232 "\t-B <pairable> Set pairable\n" 233 "\t-C <address> Create device\n" 234 "\t-R <address> Remove device\n"); 235 } 236 237 int main(int argc, char *argv[]) 238 { 239 DBusConnection *conn; 240 char *adapter, *device; 241 const char *create = NULL, *remove = NULL; 242 int opt, timeout = -1, powered = -1, discoverable = -1, pairable = -1; 243 244 while ((opt = getopt(argc, argv, "T:P:D:B:C:R:h")) != EOF) { 245 switch (opt) { 246 case 'T': 247 timeout = atoi(optarg); 248 break; 249 case 'P': 250 powered = atoi(optarg); 251 break; 252 case 'D': 253 discoverable = atoi(optarg); 254 break; 255 case 'B': 256 pairable = atoi(optarg); 257 break; 258 case 'C': 259 create = optarg; 260 break; 261 case 'R': 262 remove = optarg; 263 break; 264 case 'h': 265 usage(); 266 exit(0); 267 default: 268 usage(); 269 exit(1); 270 } 271 } 272 273 conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); 274 if (!conn) { 275 fprintf(stderr, "Can't get on system bus\n"); 276 exit(1); 277 } 278 279 adapter = get_adapter(conn); 280 if (!adapter) { 281 fprintf(stderr, "Can't get default adapter\n"); 282 exit(1); 283 } 284 285 if (powered >= 0) { 286 set_property(conn, adapter, "Powered", 287 DBUS_TYPE_BOOLEAN, &powered); 288 } 289 290 if (discoverable >= 0) { 291 set_property(conn, adapter, "Discoverable", 292 DBUS_TYPE_BOOLEAN, &discoverable); 293 294 if (timeout >= 0) 295 set_property(conn, adapter, "DiscoverableTimeout", 296 DBUS_TYPE_UINT32, &timeout); 297 } 298 299 if (pairable >= 0) { 300 set_property(conn, adapter, "Pairable", 301 DBUS_TYPE_BOOLEAN, &pairable); 302 303 if (timeout >= 0) 304 set_property(conn, adapter, "PairableTimeout", 305 DBUS_TYPE_UINT32, &timeout); 306 } 307 308 if (create) { 309 device = find_device(conn, adapter, create); 310 if (!device) { 311 fprintf(stderr, "Can't find device\n"); 312 exit(1); 313 } 314 315 free(device); 316 } 317 318 if (remove) { 319 device = find_device(conn, adapter, remove); 320 if (!device) { 321 fprintf(stderr, "Can't find device\n"); 322 exit(1); 323 } 324 325 remove_device(conn, adapter, device); 326 327 free(device); 328 } 329 330 free(adapter); 331 332 dbus_connection_unref(conn); 333 334 return 0; 335 } 336