1 /* Copyright (c) 2013 The Chromium Authors. All rights reserved.
2  * Use of this source code is governed by a BSD-style license that can be
3  * found in the LICENSE file.
4  */
5 
6 #include <dbus/dbus.h>
7 
8 #include <errno.h>
9 #include <stdint.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <syslog.h>
13 #include <sys/socket.h>
14 #include <sys/ioctl.h>
15 
16 #include "bluetooth.h"
17 #include "cras_bt_adapter.h"
18 #include "cras_bt_constants.h"
19 #include "utlist.h"
20 
21 struct cras_bt_adapter {
22 	char *object_path;
23 	char *address;
24 	char *name;
25 	uint32_t bluetooth_class;
26 	int powered;
27 	int bus_type;
28 
29 	struct cras_bt_adapter *prev, *next;
30 };
31 
32 static struct cras_bt_adapter *adapters;
33 
cras_bt_adapter_query_bus_type(struct cras_bt_adapter * adapter)34 static int cras_bt_adapter_query_bus_type(struct cras_bt_adapter *adapter)
35 {
36 	static const char *hci_str = "hci";
37 	struct hci_dev_info dev_info;
38 	char *pos;
39 	int ctl, err;
40 
41 	/* Object path [variable prefix]/{hci0,hci1,...} */
42 	pos = strstr(adapter->object_path, hci_str);
43 	if (!pos)
44 		return -1;
45 
46 	ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
47 	if (ctl < 0) {
48 		syslog(LOG_ERR, "Error creating HCI ctl socket");
49 		return -1;
50 	}
51 
52 	/* dev_id = 0 for hci0 */
53 	dev_info.type = 0;
54 	dev_info.dev_id = atoi(pos + 3);
55 	err = ioctl(ctl, HCIGETDEVINFO, (void *)&dev_info);
56 	if (err) {
57 		syslog(LOG_ERR, "HCI get dev info error %s", strerror(errno));
58 		close(ctl);
59 		return -1;
60 	}
61 	if ((dev_info.type & 0x0f) < HCI_BUS_MAX)
62 		adapter->bus_type = (dev_info.type & 0x0f);
63 
64 	close(ctl);
65 	return 0;
66 }
67 
cras_bt_adapter_create(const char * object_path)68 struct cras_bt_adapter *cras_bt_adapter_create(const char *object_path)
69 {
70 	struct cras_bt_adapter *adapter;
71 
72 	adapter = calloc(1, sizeof(*adapter));
73 	if (adapter == NULL)
74 		return NULL;
75 
76 	adapter->object_path = strdup(object_path);
77 	if (adapter->object_path == NULL) {
78 		free(adapter);
79 		return NULL;
80 	}
81 
82 	DL_APPEND(adapters, adapter);
83 
84 	/* Set bus type to USB as default when query fails. */
85 	if (cras_bt_adapter_query_bus_type(adapter))
86 		adapter->bus_type = HCI_USB;
87 
88 	return adapter;
89 }
90 
cras_bt_adapter_destroy(struct cras_bt_adapter * adapter)91 void cras_bt_adapter_destroy(struct cras_bt_adapter *adapter)
92 {
93 	DL_DELETE(adapters, adapter);
94 
95 	free(adapter->object_path);
96 	free(adapter->address);
97 	free(adapter->name);
98 	free(adapter);
99 }
100 
cras_bt_adapter_reset()101 void cras_bt_adapter_reset()
102 {
103 	while (adapters) {
104 		syslog(LOG_INFO, "Bluetooth Adapter: %s removed",
105 		       adapters->address);
106 		cras_bt_adapter_destroy(adapters);
107 	}
108 }
109 
110 
cras_bt_adapter_get(const char * object_path)111 struct cras_bt_adapter *cras_bt_adapter_get(const char *object_path)
112 {
113 	struct cras_bt_adapter *adapter;
114 
115 	if (object_path == NULL)
116 		return NULL;
117 
118 	DL_FOREACH(adapters, adapter) {
119 		if (strcmp(adapter->object_path, object_path) == 0)
120 			return adapter;
121 	}
122 
123 	return NULL;
124 }
125 
cras_bt_adapter_get_list(struct cras_bt_adapter *** adapter_list_out)126 size_t cras_bt_adapter_get_list(struct cras_bt_adapter ***adapter_list_out)
127 {
128 	struct cras_bt_adapter *adapter;
129 	struct cras_bt_adapter **adapter_list = NULL;
130 	size_t num_adapters = 0;
131 
132 	DL_FOREACH(adapters, adapter) {
133 		struct cras_bt_adapter **tmp;
134 
135 		tmp = realloc(adapter_list,
136 			      sizeof(adapter_list[0]) * (num_adapters + 1));
137 		if (!tmp) {
138 			free(adapter_list);
139 			return -ENOMEM;
140 		}
141 
142 		adapter_list = tmp;
143 		adapter_list[num_adapters++] = adapter;
144 	}
145 
146 	*adapter_list_out = adapter_list;
147 	return num_adapters;
148 }
149 
cras_bt_adapter_object_path(const struct cras_bt_adapter * adapter)150 const char *cras_bt_adapter_object_path(const struct cras_bt_adapter *adapter)
151 {
152 	return adapter->object_path;
153 }
154 
cras_bt_adapter_address(const struct cras_bt_adapter * adapter)155 const char *cras_bt_adapter_address(const struct cras_bt_adapter *adapter)
156 {
157 	return adapter->address;
158 }
159 
cras_bt_adapter_name(const struct cras_bt_adapter * adapter)160 const char *cras_bt_adapter_name(const struct cras_bt_adapter *adapter)
161 {
162 	return adapter->name;
163 }
164 
cras_bt_adapter_powered(const struct cras_bt_adapter * adapter)165 int cras_bt_adapter_powered(const struct cras_bt_adapter *adapter)
166 {
167 	return adapter->powered;
168 }
169 
170 
cras_bt_adapter_update_properties(struct cras_bt_adapter * adapter,DBusMessageIter * properties_array_iter,DBusMessageIter * invalidated_array_iter)171 void cras_bt_adapter_update_properties(struct cras_bt_adapter *adapter,
172 				       DBusMessageIter *properties_array_iter,
173 				       DBusMessageIter *invalidated_array_iter)
174 {
175 	while (dbus_message_iter_get_arg_type(properties_array_iter) !=
176 	       DBUS_TYPE_INVALID) {
177 		DBusMessageIter properties_dict_iter, variant_iter;
178 		const char *key;
179 		int type;
180 
181 		dbus_message_iter_recurse(properties_array_iter,
182 					  &properties_dict_iter);
183 
184 		dbus_message_iter_get_basic(&properties_dict_iter, &key);
185 		dbus_message_iter_next(&properties_dict_iter);
186 
187 		dbus_message_iter_recurse(&properties_dict_iter, &variant_iter);
188 		type = dbus_message_iter_get_arg_type(&variant_iter);
189 
190 		if (type == DBUS_TYPE_STRING) {
191 			const char *value;
192 
193 			dbus_message_iter_get_basic(&variant_iter, &value);
194 
195 			if (strcmp(key, "Address") == 0) {
196 				free(adapter->address);
197 				adapter->address = strdup(value);
198 
199 			} else if (strcmp(key, "Alias") == 0) {
200 				free(adapter->name);
201 				adapter->name = strdup(value);
202 
203 			}
204 
205 		} else if (type == DBUS_TYPE_UINT32) {
206 			uint32_t value;
207 
208 			dbus_message_iter_get_basic(&variant_iter, &value);
209 
210 			if (strcmp(key, "Class") == 0)
211 				adapter->bluetooth_class = value;
212 
213 		} else if (type == DBUS_TYPE_BOOLEAN) {
214 			int value;
215 
216 			dbus_message_iter_get_basic(&variant_iter, &value);
217 
218 			if (strcmp(key, "Powered") == 0)
219 				adapter->powered = value;
220 
221 		}
222 
223 		dbus_message_iter_next(properties_array_iter);
224 	}
225 
226 	while (invalidated_array_iter &&
227 	       dbus_message_iter_get_arg_type(invalidated_array_iter) !=
228 	       DBUS_TYPE_INVALID) {
229 		const char *key;
230 
231 		dbus_message_iter_get_basic(invalidated_array_iter, &key);
232 
233 		if (strcmp(key, "Address") == 0) {
234 			free(adapter->address);
235 			adapter->address = NULL;
236 		} else if (strcmp(key, "Alias") == 0) {
237 			free(adapter->name);
238 			adapter->name = NULL;
239 		} else if (strcmp(key, "Class") == 0) {
240 			adapter->bluetooth_class = 0;
241 		} else if (strcmp(key, "Powered") == 0) {
242 			adapter->powered = 0;
243 		}
244 
245 		dbus_message_iter_next(invalidated_array_iter);
246 	}
247 }
248 
cras_bt_adapter_on_usb(struct cras_bt_adapter * adapter)249 int cras_bt_adapter_on_usb(struct cras_bt_adapter *adapter)
250 {
251 	return !!(adapter->bus_type == HCI_USB);
252 }