PageRenderTime 47ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/connman/plugins/bluetooth.c

https://github.com/lpotter/connman
C | 971 lines | 712 code | 235 blank | 24 comment | 115 complexity | ac539ed251df13098ed75a6afb4db786 MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. *
  3. * Connection Manager
  4. *
  5. * Copyright (C) 2013 Intel Corporation. All rights reserved.
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2 as
  9. * published by the Free Software Foundation.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  19. *
  20. */
  21. #ifdef HAVE_CONFIG_H
  22. #include <config.h>
  23. #endif
  24. #include <errno.h>
  25. #include <string.h>
  26. #define CONNMAN_API_SUBJECT_TO_CHANGE
  27. #include <connman/plugin.h>
  28. #include <connman/dbus.h>
  29. #include <connman/technology.h>
  30. #include <connman/device.h>
  31. #include <connman/inet.h>
  32. #include <gdbus.h>
  33. #define BLUEZ_SERVICE "org.bluez"
  34. #define BLUEZ_PATH "/org/bluez"
  35. #define BLUETOOTH_PAN_NAP "00001116-0000-1000-8000-00805f9b34fb"
  36. #define BLUETOOTH_ADDR_LEN 6
  37. static DBusConnection *connection;
  38. static GDBusClient *client;
  39. static GHashTable *devices;
  40. static GHashTable *networks;
  41. static bool bluetooth_tethering;
  42. struct bluetooth_pan {
  43. struct connman_network *network;
  44. GDBusProxy *btdevice_proxy;
  45. GDBusProxy *btnetwork_proxy;
  46. };
  47. static void address2ident(const char *address, char *ident)
  48. {
  49. int i;
  50. for (i = 0; i < BLUETOOTH_ADDR_LEN; i++) {
  51. ident[i * 2] = address[i * 3];
  52. ident[i * 2 + 1] = address[i * 3 + 1];
  53. }
  54. ident[BLUETOOTH_ADDR_LEN * 2] = '\0';
  55. }
  56. static const char *proxy_get_string(GDBusProxy *proxy, const char *property)
  57. {
  58. DBusMessageIter iter;
  59. const char *str;
  60. if (!g_dbus_proxy_get_property(proxy, property, &iter))
  61. return NULL;
  62. dbus_message_iter_get_basic(&iter, &str);
  63. return str;
  64. }
  65. static bool proxy_get_bool(GDBusProxy *proxy, const char *property)
  66. {
  67. DBusMessageIter iter;
  68. dbus_bool_t value;
  69. if (!g_dbus_proxy_get_property(proxy, property, &iter))
  70. return false;
  71. dbus_message_iter_get_basic(&iter, &value);
  72. return value;
  73. }
  74. static bool proxy_get_nap(GDBusProxy *proxy)
  75. {
  76. DBusMessageIter iter, value;
  77. if (!proxy)
  78. return false;
  79. if (!g_dbus_proxy_get_property(proxy, "UUIDs", &iter))
  80. return false;
  81. dbus_message_iter_recurse(&iter, &value);
  82. while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING) {
  83. const char *uuid;
  84. dbus_message_iter_get_basic(&value, &uuid);
  85. if (strcmp(uuid, BLUETOOTH_PAN_NAP) == 0)
  86. return true;
  87. dbus_message_iter_next(&value);
  88. }
  89. return false;
  90. }
  91. static int bluetooth_pan_probe(struct connman_network *network)
  92. {
  93. GHashTableIter iter;
  94. gpointer key, value;
  95. DBG("network %p", network);
  96. g_hash_table_iter_init(&iter, networks);
  97. while (g_hash_table_iter_next(&iter, &key, &value)) {
  98. struct bluetooth_pan *pan = value;
  99. if (network == pan->network)
  100. return 0;
  101. }
  102. return -EOPNOTSUPP;
  103. }
  104. static void pan_remove_nap(struct bluetooth_pan *pan)
  105. {
  106. struct connman_device *device;
  107. struct connman_network *network = pan->network;
  108. DBG("network %p pan %p", pan->network, pan);
  109. if (!network)
  110. return;
  111. pan->network = NULL;
  112. connman_network_set_data(network, NULL);
  113. device = connman_network_get_device(network);
  114. if (device)
  115. connman_device_remove_network(device, network);
  116. connman_network_unref(network);
  117. }
  118. static void bluetooth_pan_remove(struct connman_network *network)
  119. {
  120. struct bluetooth_pan *pan = connman_network_get_data(network);
  121. DBG("network %p pan %p", network, pan);
  122. connman_network_set_data(network, NULL);
  123. if (pan)
  124. pan_remove_nap(pan);
  125. }
  126. static bool pan_connect(struct bluetooth_pan *pan,
  127. const char *iface)
  128. {
  129. int index;
  130. if (!iface) {
  131. if (!proxy_get_bool(pan->btnetwork_proxy, "Connected"))
  132. return false;
  133. iface = proxy_get_string(pan->btnetwork_proxy, "Interface");
  134. }
  135. if (!iface)
  136. return false;
  137. index = connman_inet_ifindex(iface);
  138. if (index < 0) {
  139. DBG("network %p invalid index %d", pan->network, index);
  140. return false;
  141. }
  142. connman_network_set_index(pan->network, index);
  143. connman_network_set_connected(pan->network, true);
  144. return true;
  145. }
  146. static void pan_connect_cb(DBusMessage *message, void *user_data)
  147. {
  148. const char *path = user_data;
  149. const char *iface = NULL;
  150. struct bluetooth_pan *pan;
  151. DBusMessageIter iter;
  152. pan = g_hash_table_lookup(networks, path);
  153. if (!pan) {
  154. DBG("network already removed");
  155. return;
  156. }
  157. if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) {
  158. const char *dbus_error = dbus_message_get_error_name(message);
  159. DBG("network %p %s", pan->network, dbus_error);
  160. if (strcmp(dbus_error,
  161. "org.bluez.Error.AlreadyConnected") != 0) {
  162. connman_network_set_error(pan->network,
  163. CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
  164. return;
  165. }
  166. } else {
  167. if (dbus_message_iter_init(message, &iter) &&
  168. dbus_message_iter_get_arg_type(&iter) ==
  169. DBUS_TYPE_STRING)
  170. dbus_message_iter_get_basic(&iter, &iface);
  171. }
  172. DBG("network %p interface %s", pan->network, iface);
  173. pan_connect(pan, iface);
  174. }
  175. static void pan_connect_append(DBusMessageIter *iter,
  176. void *user_data)
  177. {
  178. const char *role = BLUETOOTH_PAN_NAP;
  179. dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &role);
  180. }
  181. static int bluetooth_pan_connect(struct connman_network *network)
  182. {
  183. struct bluetooth_pan *pan = connman_network_get_data(network);
  184. const char *path;
  185. DBG("network %p", network);
  186. if (!pan)
  187. return -EINVAL;
  188. path = g_dbus_proxy_get_path(pan->btnetwork_proxy);
  189. if (!g_dbus_proxy_method_call(pan->btnetwork_proxy, "Connect",
  190. pan_connect_append, pan_connect_cb,
  191. g_strdup(path), g_free))
  192. return -EIO;
  193. connman_network_set_associating(pan->network, true);
  194. return -EINPROGRESS;
  195. }
  196. static void pan_disconnect_cb(DBusMessage *message, void *user_data)
  197. {
  198. const char *path = user_data;
  199. struct bluetooth_pan *pan;
  200. pan = g_hash_table_lookup(networks, path);
  201. if (!pan) {
  202. DBG("network already removed");
  203. return;
  204. }
  205. if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) {
  206. const char *dbus_error = dbus_message_get_error_name(message);
  207. DBG("network %p %s", pan->network, dbus_error);
  208. }
  209. DBG("network %p", pan->network);
  210. connman_network_set_connected(pan->network, false);
  211. }
  212. static int bluetooth_pan_disconnect(struct connman_network *network)
  213. {
  214. struct bluetooth_pan *pan = connman_network_get_data(network);
  215. const char *path;
  216. DBG("network %p", network);
  217. if (!pan)
  218. return -EINVAL;
  219. path = g_dbus_proxy_get_path(pan->btnetwork_proxy);
  220. if (!g_dbus_proxy_method_call(pan->btnetwork_proxy, "Disconnect",
  221. NULL, pan_disconnect_cb, g_strdup(path), g_free))
  222. return -EIO;
  223. return -EINPROGRESS;
  224. }
  225. static void btnetwork_property_change(GDBusProxy *proxy, const char *name,
  226. DBusMessageIter *iter, void *user_data)
  227. {
  228. struct bluetooth_pan *pan;
  229. dbus_bool_t connected;
  230. bool proxy_connected, network_connected;
  231. if (strcmp(name, "Connected") != 0)
  232. return;
  233. pan = g_hash_table_lookup(networks, g_dbus_proxy_get_path(proxy));
  234. if (!pan || !pan->network)
  235. return;
  236. dbus_message_iter_get_basic(iter, &connected);
  237. proxy_connected = connected;
  238. network_connected = connman_network_get_connected(pan->network);
  239. DBG("network %p network connected %d proxy connected %d",
  240. pan->network, network_connected, proxy_connected);
  241. if (network_connected != proxy_connected)
  242. connman_network_set_connected(pan->network, proxy_connected);
  243. }
  244. static void pan_create_nap(struct bluetooth_pan *pan)
  245. {
  246. struct connman_device *device;
  247. if (!proxy_get_nap(pan->btdevice_proxy)) {
  248. pan_remove_nap(pan);
  249. return;
  250. }
  251. device = g_hash_table_lookup(devices,
  252. proxy_get_string(pan->btdevice_proxy, "Adapter"));
  253. if (!device || !connman_device_get_powered(device))
  254. return;
  255. if (!pan->network) {
  256. const char *address;
  257. char ident[BLUETOOTH_ADDR_LEN * 2 + 1];
  258. const char *name, *path;
  259. address = proxy_get_string(pan->btdevice_proxy, "Address");
  260. if (!address) {
  261. connman_warn("Bluetooth device address missing");
  262. return;
  263. }
  264. address2ident(address, ident);
  265. pan->network = connman_network_create(ident,
  266. CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN);
  267. name = proxy_get_string(pan->btdevice_proxy, "Alias");
  268. path = g_dbus_proxy_get_path(pan->btnetwork_proxy);
  269. DBG("network %p %s %s", pan->network, path, name);
  270. if (!pan->network) {
  271. connman_warn("Bluetooth network %s creation failed",
  272. path);
  273. return;
  274. }
  275. connman_network_set_data(pan->network, pan);
  276. connman_network_set_name(pan->network, name);
  277. connman_network_set_group(pan->network, ident);
  278. }
  279. connman_device_add_network(device, pan->network);
  280. if (pan_connect(pan, NULL))
  281. DBG("network %p already connected", pan->network);
  282. }
  283. static void btdevice_property_change(GDBusProxy *proxy, const char *name,
  284. DBusMessageIter *iter, void *user_data)
  285. {
  286. struct bluetooth_pan *pan;
  287. bool pan_nap = false;
  288. if (strcmp(name, "UUIDs") != 0)
  289. return;
  290. pan = g_hash_table_lookup(networks, g_dbus_proxy_get_path(proxy));
  291. if (!pan)
  292. return;
  293. if (pan->network &&
  294. connman_network_get_device(pan->network))
  295. pan_nap = true;
  296. DBG("network %p network nap %d proxy nap %d", pan->network, pan_nap,
  297. proxy_get_nap(pan->btdevice_proxy));
  298. if (proxy_get_nap(pan->btdevice_proxy) == pan_nap)
  299. return;
  300. pan_create_nap(pan);
  301. }
  302. static void pan_free(gpointer data)
  303. {
  304. struct bluetooth_pan *pan = data;
  305. if (pan->btnetwork_proxy) {
  306. g_dbus_proxy_unref(pan->btnetwork_proxy);
  307. pan->btnetwork_proxy = NULL;
  308. }
  309. if (pan->btdevice_proxy) {
  310. g_dbus_proxy_unref(pan->btdevice_proxy);
  311. pan->btdevice_proxy = NULL;
  312. }
  313. pan_remove_nap(pan);
  314. g_free(pan);
  315. }
  316. static void pan_create(GDBusProxy *network_proxy)
  317. {
  318. const char *path = g_dbus_proxy_get_path(network_proxy);
  319. struct bluetooth_pan *pan;
  320. pan = g_try_new0(struct bluetooth_pan, 1);
  321. if (!pan) {
  322. connman_error("Out of memory creating PAN NAP");
  323. return;
  324. }
  325. g_hash_table_replace(networks, g_strdup(path), pan);
  326. pan->btnetwork_proxy = g_dbus_proxy_ref(network_proxy);
  327. pan->btdevice_proxy = g_dbus_proxy_new(client, path,
  328. "org.bluez.Device1");
  329. if (!pan->btdevice_proxy) {
  330. connman_error("Cannot create BT PAN watcher %s", path);
  331. g_hash_table_remove(networks, path);
  332. return;
  333. }
  334. g_dbus_proxy_set_property_watch(pan->btnetwork_proxy,
  335. btnetwork_property_change, NULL);
  336. g_dbus_proxy_set_property_watch(pan->btdevice_proxy,
  337. btdevice_property_change, NULL);
  338. DBG("pan %p %s nap %d", pan, path, proxy_get_nap(pan->btdevice_proxy));
  339. pan_create_nap(pan);
  340. }
  341. static struct connman_network_driver network_driver = {
  342. .name = "bluetooth",
  343. .type = CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN,
  344. .probe = bluetooth_pan_probe,
  345. .remove = bluetooth_pan_remove,
  346. .connect = bluetooth_pan_connect,
  347. .disconnect = bluetooth_pan_disconnect,
  348. };
  349. static void enable_device(struct connman_device *device, const char *path)
  350. {
  351. GHashTableIter iter;
  352. gpointer key, value;
  353. DBG("device %p %s", device, path);
  354. connman_device_set_powered(device, true);
  355. g_hash_table_iter_init(&iter, networks);
  356. while (g_hash_table_iter_next(&iter, &key, &value)) {
  357. struct bluetooth_pan *pan = value;
  358. if (g_strcmp0(proxy_get_string(pan->btdevice_proxy, "Adapter"),
  359. path) == 0) {
  360. DBG("enable network %p", pan->network);
  361. pan_create_nap(pan);
  362. }
  363. }
  364. }
  365. static void device_enable_cb(const DBusError *error, void *user_data)
  366. {
  367. char *path = user_data;
  368. struct connman_device *device;
  369. device = g_hash_table_lookup(devices, path);
  370. if (!device) {
  371. DBG("device already removed");
  372. goto out;
  373. }
  374. if (dbus_error_is_set(error)) {
  375. connman_warn("Bluetooth device %s not enabled %s",
  376. path, error->message);
  377. goto out;
  378. }
  379. enable_device(device, path);
  380. out:
  381. g_free(path);
  382. }
  383. static int bluetooth_device_enable(struct connman_device *device)
  384. {
  385. GDBusProxy *proxy = connman_device_get_data(device);
  386. dbus_bool_t device_powered = TRUE;
  387. const char *path;
  388. if (!proxy)
  389. return 0;
  390. path = g_dbus_proxy_get_path(proxy);
  391. if (proxy_get_bool(proxy, "Powered")) {
  392. DBG("already enabled %p %s", device, path);
  393. return -EALREADY;
  394. }
  395. DBG("device %p %s", device, path);
  396. g_dbus_proxy_set_property_basic(proxy, "Powered",
  397. DBUS_TYPE_BOOLEAN, &device_powered,
  398. device_enable_cb, g_strdup(path), NULL);
  399. return -EINPROGRESS;
  400. }
  401. static void disable_device(struct connman_device *device, const char *path)
  402. {
  403. GHashTableIter iter;
  404. gpointer key, value;
  405. DBG("device %p %s", device, path);
  406. connman_device_set_powered(device, false);
  407. g_hash_table_iter_init(&iter, networks);
  408. while (g_hash_table_iter_next(&iter, &key, &value)) {
  409. struct bluetooth_pan *pan = value;
  410. if (pan->network && connman_network_get_device(pan->network)
  411. == device) {
  412. DBG("disable network %p", pan->network);
  413. connman_device_remove_network(device, pan->network);
  414. }
  415. }
  416. }
  417. static void device_disable_cb(const DBusError *error, void *user_data)
  418. {
  419. char *path = user_data;
  420. struct connman_device *device;
  421. device = g_hash_table_lookup(devices, path);
  422. if (!device) {
  423. DBG("device already removed");
  424. goto out;
  425. }
  426. if (dbus_error_is_set(error)) {
  427. connman_warn("Bluetooth device %s not disabled: %s",
  428. path, error->message);
  429. goto out;
  430. }
  431. disable_device(device, path);
  432. out:
  433. g_free(path);
  434. }
  435. static int bluetooth_device_disable(struct connman_device *device)
  436. {
  437. GDBusProxy *proxy = connman_device_get_data(device);
  438. dbus_bool_t device_powered = FALSE;
  439. const char *path;
  440. if (!proxy)
  441. return 0;
  442. path = g_dbus_proxy_get_path(proxy);
  443. if (!proxy_get_bool(proxy, "Powered")) {
  444. DBG("already disabled %p %s", device, path);
  445. return -EALREADY;
  446. }
  447. DBG("device %p %s", device, path);
  448. g_dbus_proxy_set_property_basic(proxy, "Powered",
  449. DBUS_TYPE_BOOLEAN, &device_powered,
  450. device_disable_cb, g_strdup(path), NULL);
  451. return -EINPROGRESS;
  452. }
  453. static void adapter_property_change(GDBusProxy *proxy, const char *name,
  454. DBusMessageIter *iter, void *user_data)
  455. {
  456. struct connman_device *device;
  457. const char *path;
  458. bool adapter_powered, device_powered;
  459. if (strcmp(name, "Powered") != 0)
  460. return;
  461. path = g_dbus_proxy_get_path(proxy);
  462. device = g_hash_table_lookup(devices, path);
  463. adapter_powered = proxy_get_bool(proxy, "Powered");
  464. device_powered = connman_device_get_powered(device);
  465. DBG("device %p %s device powered %d adapter powered %d", device, path,
  466. device_powered, adapter_powered);
  467. if (device_powered != adapter_powered) {
  468. if (adapter_powered)
  469. enable_device(device, path);
  470. else
  471. disable_device(device, path);
  472. }
  473. }
  474. static void device_free(gpointer data)
  475. {
  476. struct connman_device *device = data;
  477. GDBusProxy *proxy = connman_device_get_data(device);
  478. connman_device_set_data(device, NULL);
  479. if (proxy)
  480. g_dbus_proxy_unref(proxy);
  481. connman_device_unregister(device);
  482. connman_device_unref(device);
  483. }
  484. struct tethering_info {
  485. struct connman_technology *technology;
  486. char *bridge;
  487. bool enable;
  488. };
  489. static void tethering_free(void *user_data)
  490. {
  491. struct tethering_info *tethering = user_data;
  492. g_free(tethering->bridge);
  493. g_free(tethering);
  494. }
  495. static void tethering_create_cb(DBusMessage *message, void *user_data)
  496. {
  497. struct tethering_info *tethering = user_data;
  498. if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) {
  499. const char *dbus_error = dbus_message_get_error_name(message);
  500. DBG("%s tethering failed: %s",
  501. tethering->enable ? "enable" : "disable",
  502. dbus_error);
  503. return;
  504. }
  505. DBG("bridge %s %s", tethering->bridge, tethering->enable ?
  506. "enabled": "disabled");
  507. if (tethering->technology)
  508. connman_technology_tethering_notify(tethering->technology,
  509. tethering->enable);
  510. }
  511. static void tethering_append(DBusMessageIter *iter, void *user_data)
  512. {
  513. struct tethering_info *tethering = user_data;
  514. const char *nap = "nap";
  515. dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &nap);
  516. if (tethering->enable)
  517. dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
  518. &tethering->bridge);
  519. }
  520. static bool tethering_create(const char *path,
  521. struct connman_technology *technology, const char *bridge,
  522. bool enabled)
  523. {
  524. struct tethering_info *tethering = g_new0(struct tethering_info, 1);
  525. GDBusProxy *proxy;
  526. const char *method;
  527. bool result;
  528. DBG("path %s bridge %s", path, bridge);
  529. if (!bridge)
  530. return -EINVAL;
  531. proxy = g_dbus_proxy_new(client, path, "org.bluez.NetworkServer1");
  532. if (!proxy)
  533. return false;
  534. tethering->technology = technology;
  535. tethering->bridge = g_strdup(bridge);
  536. tethering->enable = enabled;
  537. if (tethering->enable)
  538. method = "Register";
  539. else
  540. method = "Unregister";
  541. result = g_dbus_proxy_method_call(proxy, method, tethering_append,
  542. tethering_create_cb, tethering, tethering_free);
  543. g_dbus_proxy_unref(proxy);
  544. return result;
  545. }
  546. static void device_create(GDBusProxy *proxy)
  547. {
  548. struct connman_device *device = NULL;
  549. const char *path = g_dbus_proxy_get_path(proxy);
  550. const char *address;
  551. char ident[BLUETOOTH_ADDR_LEN * 2 + 1];
  552. bool powered;
  553. address = proxy_get_string(proxy, "Address");
  554. if (!address)
  555. return;
  556. address2ident(address, ident);
  557. device = connman_device_create("bluetooth",
  558. CONNMAN_DEVICE_TYPE_BLUETOOTH);
  559. if (!device)
  560. return;
  561. connman_device_set_data(device, g_dbus_proxy_ref(proxy));
  562. connman_device_set_ident(device, ident);
  563. g_hash_table_replace(devices, g_strdup(path), device);
  564. DBG("device %p %s device powered %d adapter powered %d", device,
  565. path, connman_device_get_powered(device),
  566. proxy_get_bool(proxy, "Powered"));
  567. if (connman_device_register(device) < 0) {
  568. g_hash_table_remove(devices, device);
  569. return;
  570. }
  571. g_dbus_proxy_set_property_watch(proxy, adapter_property_change, NULL);
  572. powered = proxy_get_bool(proxy, "Powered");
  573. connman_device_set_powered(device, powered);
  574. if (proxy_get_nap(proxy) && !bluetooth_tethering)
  575. tethering_create(path, NULL, NULL, false);
  576. }
  577. static void object_added(GDBusProxy *proxy, void *user_data)
  578. {
  579. const char *interface;
  580. interface = g_dbus_proxy_get_interface(proxy);
  581. if (!interface) {
  582. connman_warn("Interface or proxy missing when adding "
  583. "bluetooth object");
  584. return;
  585. }
  586. if (strcmp(interface, "org.bluez.Adapter1") == 0) {
  587. DBG("%s %s", interface, g_dbus_proxy_get_path(proxy));
  588. device_create(proxy);
  589. return;
  590. }
  591. if (strcmp(interface, "org.bluez.Network1") == 0) {
  592. DBG("%s %s", interface, g_dbus_proxy_get_path(proxy));
  593. pan_create(proxy);
  594. return;
  595. }
  596. }
  597. static void object_removed(GDBusProxy *proxy, void *user_data)
  598. {
  599. const char *interface, *path;
  600. interface = g_dbus_proxy_get_interface(proxy);
  601. if (!interface) {
  602. connman_warn("Interface or proxy missing when removing "
  603. "bluetooth object");
  604. return;
  605. }
  606. if (strcmp(interface, "org.bluez.Adapter1") == 0) {
  607. path = g_dbus_proxy_get_path(proxy);
  608. DBG("%s %s", interface, path);
  609. g_hash_table_remove(devices, path);
  610. }
  611. if (strcmp(interface, "org.bluez.Network1") == 0) {
  612. path = g_dbus_proxy_get_path(proxy);
  613. DBG("%s %s", interface, path);
  614. g_hash_table_remove(networks, path);
  615. }
  616. }
  617. static int bluetooth_device_probe(struct connman_device *device)
  618. {
  619. GHashTableIter iter;
  620. gpointer key, value;
  621. g_hash_table_iter_init(&iter, devices);
  622. while (g_hash_table_iter_next(&iter, &key, &value)) {
  623. struct connman_device *known = value;
  624. if (device == known)
  625. return 0;
  626. }
  627. return -EOPNOTSUPP;
  628. }
  629. static void bluetooth_device_remove(struct connman_device *device)
  630. {
  631. DBG("%p", device);
  632. }
  633. static struct connman_device_driver device_driver = {
  634. .name = "bluetooth",
  635. .type = CONNMAN_DEVICE_TYPE_BLUETOOTH,
  636. .probe = bluetooth_device_probe,
  637. .remove = bluetooth_device_remove,
  638. .enable = bluetooth_device_enable,
  639. .disable = bluetooth_device_disable,
  640. };
  641. static int bluetooth_tech_probe(struct connman_technology *technology)
  642. {
  643. return 0;
  644. }
  645. static void bluetooth_tech_remove(struct connman_technology *technology)
  646. {
  647. }
  648. static int bluetooth_tech_set_tethering(struct connman_technology *technology,
  649. const char *identifier, const char *passphrase,
  650. const char *bridge, bool enabled)
  651. {
  652. GHashTableIter hash_iter;
  653. gpointer key, value;
  654. int i = 0;
  655. bluetooth_tethering = enabled;
  656. g_hash_table_iter_init(&hash_iter, devices);
  657. while (g_hash_table_iter_next(&hash_iter, &key, &value)) {
  658. const char *path = key;
  659. struct connman_device *device = value;
  660. DBG("device %p", device);
  661. if (tethering_create(path, technology, bridge, enabled)
  662. )
  663. i++;
  664. }
  665. DBG("%s %d device(s)", enabled ? "enabled" : "disabled", i);
  666. if (i == 0)
  667. return -ENODEV;
  668. return -EINPROGRESS;
  669. }
  670. static struct connman_technology_driver tech_driver = {
  671. .name = "bluetooth",
  672. .type = CONNMAN_SERVICE_TYPE_BLUETOOTH,
  673. .probe = bluetooth_tech_probe,
  674. .remove = bluetooth_tech_remove,
  675. .set_tethering = bluetooth_tech_set_tethering,
  676. };
  677. static int bluetooth_init(void)
  678. {
  679. connection = connman_dbus_get_connection();
  680. if (!connection)
  681. goto out;
  682. if (connman_technology_driver_register(&tech_driver) < 0) {
  683. connman_warn("Failed to initialize technology for Bluez 5");
  684. goto out;
  685. }
  686. devices = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
  687. device_free);
  688. if (connman_device_driver_register(&device_driver) < 0) {
  689. connman_warn("Failed to initialize device driver for "
  690. BLUEZ_SERVICE);
  691. connman_technology_driver_unregister(&tech_driver);
  692. goto out;
  693. }
  694. if (connman_network_driver_register(&network_driver) < 0) {
  695. connman_technology_driver_unregister(&tech_driver);
  696. connman_device_driver_unregister(&device_driver);
  697. goto out;
  698. }
  699. networks = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
  700. pan_free);
  701. client = g_dbus_client_new(connection, BLUEZ_SERVICE, BLUEZ_PATH);
  702. if (!client) {
  703. connman_warn("Failed to initialize D-Bus client for "
  704. BLUEZ_SERVICE);
  705. goto out;
  706. }
  707. g_dbus_client_set_proxy_handlers(client, object_added, object_removed,
  708. NULL, NULL);
  709. return 0;
  710. out:
  711. if (networks)
  712. g_hash_table_destroy(networks);
  713. if (devices)
  714. g_hash_table_destroy(devices);
  715. if (client)
  716. g_dbus_client_unref(client);
  717. if (connection)
  718. dbus_connection_unref(connection);
  719. return -EIO;
  720. }
  721. static void bluetooth_exit(void)
  722. {
  723. /*
  724. * We unset the disabling of the Bluetooth device when shutting down
  725. * so that non-PAN BT connections are not affected.
  726. */
  727. device_driver.disable = NULL;
  728. connman_network_driver_unregister(&network_driver);
  729. g_hash_table_destroy(networks);
  730. connman_device_driver_unregister(&device_driver);
  731. g_hash_table_destroy(devices);
  732. connman_technology_driver_unregister(&tech_driver);
  733. dbus_connection_unref(connection);
  734. }
  735. CONNMAN_PLUGIN_DEFINE(bluetooth, "Bluetooth technology plugin", VERSION,
  736. CONNMAN_PLUGIN_PRIORITY_DEFAULT, bluetooth_init, bluetooth_exit)