1 /* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2006-2007 Nokia Corporation 6 * Copyright (C) 2004-2009 Marcel Holtmann <marcel (at) holtmann.org> 7 * Copyright (C) 2005-2007 Johan Hedberg <johan.hedberg (at) nokia.com> 8 * 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 * 24 */ 25 26 #ifdef HAVE_CONFIG_H 27 #include <config.h> 28 #endif 29 30 #include <stdio.h> 31 #include <errno.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <unistd.h> 35 #include <sys/ioctl.h> 36 37 #include <bluetooth/bluetooth.h> 38 #include <bluetooth/hci.h> 39 #include <bluetooth/l2cap.h> 40 41 #include <glib.h> 42 #include <dbus/dbus.h> 43 #include <gdbus.h> 44 45 #include "logging.h" 46 47 #include "manager.h" 48 #include "adapter.h" 49 #include "dbus-hci.h" 50 #include "dbus-common.h" 51 52 #define BLUEZ_NAME "org.bluez" 53 54 #define RECONNECT_RETRY_TIMEOUT 5000 55 56 static gboolean system_bus_reconnect(void *data) 57 { 58 DBusConnection *conn = get_dbus_connection(); 59 struct hci_dev_list_req *dl = NULL; 60 struct hci_dev_req *dr; 61 int sk, i; 62 gboolean ret_val = TRUE; 63 64 if (conn) { 65 if (dbus_connection_get_is_connected(conn)) 66 return FALSE; 67 } 68 69 if (hcid_dbus_init() < 0) 70 return TRUE; 71 72 /* Create and bind HCI socket */ 73 sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); 74 if (sk < 0) { 75 error("Can't open HCI socket: %s (%d)", 76 strerror(errno), errno); 77 return TRUE; 78 } 79 80 dl = g_malloc0(HCI_MAX_DEV * sizeof(*dr) + sizeof(*dl)); 81 82 dl->dev_num = HCI_MAX_DEV; 83 dr = dl->dev_req; 84 85 if (ioctl(sk, HCIGETDEVLIST, (void *) dl) < 0) { 86 info("Can't get device list: %s (%d)", 87 strerror(errno), errno); 88 goto failed; 89 } 90 91 /* reset the default device */ 92 manager_set_default_adapter(-1); 93 94 /* FIXME: it shouldn't be needed to register adapters again */ 95 for (i = 0; i < dl->dev_num; i++, dr++) 96 manager_register_adapter(dr->dev_id, TRUE); 97 98 ret_val = FALSE; 99 100 failed: 101 if (sk >= 0) 102 close(sk); 103 104 g_free(dl); 105 106 return ret_val; 107 } 108 109 static void disconnect_callback(DBusConnection *conn, void *user_data) 110 { 111 set_dbus_connection(NULL); 112 113 g_timeout_add(RECONNECT_RETRY_TIMEOUT, 114 system_bus_reconnect, NULL); 115 } 116 117 void hcid_dbus_unregister(void) 118 { 119 DBusConnection *conn = get_dbus_connection(); 120 char **children; 121 int i; 122 uint16_t dev_id; 123 124 if (!conn || !dbus_connection_get_is_connected(conn)) 125 return; 126 127 /* Unregister all paths in Adapter path hierarchy */ 128 if (!dbus_connection_list_registered(conn, "/", &children)) 129 return; 130 131 for (i = 0; children[i]; i++) { 132 char path[MAX_PATH_LENGTH]; 133 struct btd_adapter *adapter; 134 135 if (children[i][0] != 'h') 136 continue; 137 138 snprintf(path, sizeof(path), "/%s", children[i]); 139 140 adapter = manager_find_adapter_by_path(path); 141 if (!adapter) 142 continue; 143 144 dev_id = adapter_get_dev_id(adapter); 145 manager_unregister_adapter(dev_id); 146 } 147 148 dbus_free_string_array(children); 149 } 150 151 void hcid_dbus_exit(void) 152 { 153 DBusConnection *conn = get_dbus_connection(); 154 155 if (!conn || !dbus_connection_get_is_connected(conn)) 156 return; 157 158 manager_cleanup(conn, "/"); 159 160 set_dbus_connection(NULL); 161 162 dbus_connection_unref(conn); 163 } 164 165 int hcid_dbus_init(void) 166 { 167 DBusConnection *conn; 168 DBusError err; 169 170 dbus_error_init(&err); 171 172 conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, BLUEZ_NAME, &err); 173 if (!conn) { 174 if (dbus_error_is_set(&err)) { 175 dbus_error_free(&err); 176 return -EIO; 177 } 178 return -EALREADY; 179 } 180 181 if (g_dbus_set_disconnect_function(conn, disconnect_callback, 182 NULL, NULL) == FALSE) { 183 dbus_connection_unref(conn); 184 return -EIO; 185 } 186 187 if (!manager_init(conn, "/")) 188 return -EIO; 189 190 set_dbus_connection(conn); 191 192 return 0; 193 } 194 195 static void append_variant(DBusMessageIter *iter, int type, void *val) 196 { 197 DBusMessageIter value; 198 char sig[2] = { type, '\0' }; 199 200 dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, sig, &value); 201 202 dbus_message_iter_append_basic(&value, type, val); 203 204 dbus_message_iter_close_container(iter, &value); 205 } 206 207 static void append_array_variant(DBusMessageIter *iter, int type, void *val) 208 { 209 DBusMessageIter variant, array; 210 char type_sig[2] = { type, '\0' }; 211 char array_sig[3] = { DBUS_TYPE_ARRAY, type, '\0' }; 212 const char ***str_array = val; 213 int i; 214 215 dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, 216 array_sig, &variant); 217 218 dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, 219 type_sig, &array); 220 221 for (i = 0; (*str_array)[i]; i++) 222 dbus_message_iter_append_basic(&array, type, 223 &((*str_array)[i])); 224 225 dbus_message_iter_close_container(&variant, &array); 226 227 dbus_message_iter_close_container(iter, &variant); 228 } 229 230 void dict_append_entry(DBusMessageIter *dict, 231 const char *key, int type, void *val) 232 { 233 DBusMessageIter entry; 234 235 if (type == DBUS_TYPE_STRING) { 236 const char *str = *((const char **) val); 237 if (str == NULL) 238 return; 239 } 240 241 dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, 242 NULL, &entry); 243 244 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); 245 246 append_variant(&entry, type, val); 247 248 dbus_message_iter_close_container(dict, &entry); 249 } 250 251 void dict_append_array(DBusMessageIter *dict, const char *key, int type, 252 void *val, int n_elements) 253 { 254 DBusMessageIter entry; 255 256 dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, 257 NULL, &entry); 258 259 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); 260 261 append_array_variant(&entry, type, val); 262 263 dbus_message_iter_close_container(dict, &entry); 264 } 265 266 dbus_bool_t emit_property_changed(DBusConnection *conn, 267 const char *path, 268 const char *interface, 269 const char *name, 270 int type, void *value) 271 { 272 DBusMessage *signal; 273 DBusMessageIter iter; 274 275 signal = dbus_message_new_signal(path, interface, "PropertyChanged"); 276 277 if (!signal) { 278 error("Unable to allocate new %s.PropertyChanged signal", 279 interface); 280 return FALSE; 281 } 282 283 dbus_message_iter_init_append(signal, &iter); 284 285 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name); 286 287 append_variant(&iter, type, value); 288 289 return g_dbus_send_message(conn, signal); 290 } 291 292 dbus_bool_t emit_array_property_changed(DBusConnection *conn, 293 const char *path, 294 const char *interface, 295 const char *name, 296 int type, void *value) 297 { 298 DBusMessage *signal; 299 DBusMessageIter iter; 300 301 signal = dbus_message_new_signal(path, interface, "PropertyChanged"); 302 303 if (!signal) { 304 error("Unable to allocate new %s.PropertyChanged signal", 305 interface); 306 return FALSE; 307 } 308 309 dbus_message_iter_init_append(signal, &iter); 310 311 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name); 312 313 append_array_variant(&iter, type, value); 314 315 return g_dbus_send_message(conn, signal); 316 } 317