bluetooth.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. *
  4. * OBEX Server
  5. *
  6. * Copyright (C) 2007-2010 Nokia Corporation
  7. * Copyright (C) 2007-2010 Marcel Holtmann <marcel@holtmann.org>
  8. *
  9. *
  10. */
  11. #ifdef HAVE_CONFIG_H
  12. #include <config.h>
  13. #endif
  14. #include <errno.h>
  15. #include <string.h>
  16. #include <unistd.h>
  17. #include <inttypes.h>
  18. #include <fcntl.h>
  19. #include <sys/socket.h>
  20. #include <glib.h>
  21. #include "lib/bluetooth.h"
  22. #include "lib/uuid.h"
  23. #include "gdbus/gdbus.h"
  24. #include "btio/btio.h"
  25. #include "obexd/src/obexd.h"
  26. #include "obexd/src/plugin.h"
  27. #include "obexd/src/server.h"
  28. #include "obexd/src/obex.h"
  29. #include "obexd/src/transport.h"
  30. #include "obexd/src/service.h"
  31. #include "obexd/src/log.h"
  32. #define BT_RX_MTU 32767
  33. #define BT_TX_MTU 32767
  34. struct bluetooth_profile {
  35. struct obex_server *server;
  36. struct obex_service_driver *driver;
  37. char *uuid;
  38. char *path;
  39. };
  40. static GSList *profiles = NULL;
  41. static DBusConnection *connection = NULL;
  42. static DBusMessage *profile_release(DBusConnection *conn, DBusMessage *msg,
  43. void *data)
  44. {
  45. return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
  46. }
  47. static void connect_event(GIOChannel *io, GError *err, void *user_data)
  48. {
  49. int sk = g_io_channel_unix_get_fd(io);
  50. struct bluetooth_profile *profile = user_data;
  51. struct obex_server *server = profile->server;
  52. int type;
  53. uint16_t omtu = BT_TX_MTU;
  54. uint16_t imtu = BT_RX_MTU;
  55. gboolean stream = TRUE;
  56. socklen_t len = sizeof(int);
  57. if (err)
  58. goto drop;
  59. if (getsockopt(sk, SOL_SOCKET, SO_TYPE, &type, &len) < 0)
  60. goto done;
  61. if (type != SOCK_SEQPACKET)
  62. goto done;
  63. stream = FALSE;
  64. /* Read MTU if io is an L2CAP socket */
  65. bt_io_get(io, NULL, BT_IO_OPT_OMTU, &omtu, BT_IO_OPT_IMTU, &imtu,
  66. BT_IO_OPT_INVALID);
  67. done:
  68. if (obex_server_new_connection(server, io, omtu, imtu, stream) < 0)
  69. g_io_channel_shutdown(io, TRUE, NULL);
  70. return;
  71. drop:
  72. error("%s", err->message);
  73. g_io_channel_shutdown(io, TRUE, NULL);
  74. return;
  75. }
  76. static DBusMessage *invalid_args(DBusMessage *msg)
  77. {
  78. return g_dbus_create_error(msg, "org.bluez.Error.InvalidArguments",
  79. "Invalid arguments in method call");
  80. }
  81. static DBusMessage *profile_new_connection(DBusConnection *conn,
  82. DBusMessage *msg, void *data)
  83. {
  84. DBusMessageIter args;
  85. const char *device;
  86. int fd;
  87. GIOChannel *io;
  88. dbus_message_iter_init(msg, &args);
  89. if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
  90. return invalid_args(msg);
  91. dbus_message_iter_get_basic(&args, &device);
  92. dbus_message_iter_next(&args);
  93. if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_UNIX_FD)
  94. return invalid_args(msg);
  95. dbus_message_iter_get_basic(&args, &fd);
  96. if (fd < 0) {
  97. error("bluetooth: NewConnection invalid fd");
  98. return invalid_args(msg);
  99. }
  100. /* Read fd flags to make sure it can be used */
  101. if (fcntl(fd, F_GETFD) < 0) {
  102. error("bluetooth: fcntl(%d, F_GETFD): %s (%d)", fd,
  103. strerror(errno), errno);
  104. close(fd);
  105. return invalid_args(msg);
  106. }
  107. io = g_io_channel_unix_new(fd);
  108. if (io == NULL) {
  109. close(fd);
  110. return invalid_args(msg);
  111. }
  112. DBG("device %s", device);
  113. connect_event(io, NULL, data);
  114. g_io_channel_unref(io);
  115. return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
  116. }
  117. static DBusMessage *profile_request_disconnection(DBusConnection *conn,
  118. DBusMessage *msg, void *data)
  119. {
  120. return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
  121. }
  122. static DBusMessage *profile_cancel(DBusConnection *conn,
  123. DBusMessage *msg, void *data)
  124. {
  125. return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
  126. }
  127. static const GDBusMethodTable profile_methods[] = {
  128. { GDBUS_METHOD("Release",
  129. NULL, NULL,
  130. profile_release) },
  131. { GDBUS_METHOD("NewConnection",
  132. GDBUS_ARGS({ "device", "o" }, { "fd", "h" },
  133. { "options", "a{sv}" }), NULL,
  134. profile_new_connection) },
  135. { GDBUS_METHOD("RequestDisconnection",
  136. GDBUS_ARGS({ "device", "o" }), NULL,
  137. profile_request_disconnection) },
  138. { GDBUS_METHOD("Cancel",
  139. NULL, NULL,
  140. profile_cancel) },
  141. { }
  142. };
  143. static void unregister_profile(struct bluetooth_profile *profile)
  144. {
  145. g_dbus_unregister_interface(connection, profile->path,
  146. "org.bluez.Profile1");
  147. g_free(profile->path);
  148. profile->path = NULL;
  149. }
  150. static void register_profile_reply(DBusPendingCall *call, void *user_data)
  151. {
  152. struct bluetooth_profile *profile = user_data;
  153. DBusMessage *reply = dbus_pending_call_steal_reply(call);
  154. DBusError derr;
  155. dbus_error_init(&derr);
  156. if (!dbus_set_error_from_message(&derr, reply)) {
  157. DBG("Profile %s registered", profile->path);
  158. goto done;
  159. }
  160. unregister_profile(profile);
  161. error("bluetooth: RequestProfile error: %s, %s", derr.name,
  162. derr.message);
  163. dbus_error_free(&derr);
  164. done:
  165. dbus_message_unref(reply);
  166. }
  167. static void profile_free(void *data)
  168. {
  169. struct bluetooth_profile *profile = data;
  170. if (profile->path != NULL)
  171. unregister_profile(profile);
  172. g_free(profile->uuid);
  173. g_free(profile);
  174. }
  175. static int register_profile(struct bluetooth_profile *profile)
  176. {
  177. DBusMessage *msg;
  178. DBusMessageIter iter, opt;
  179. DBusPendingCall *call;
  180. dbus_bool_t auto_connect = FALSE;
  181. char *xml;
  182. int ret = 0;
  183. profile->path = g_strconcat("/org/bluez/obex/", profile->uuid, NULL);
  184. g_strdelimit(profile->path, "-", '_');
  185. if (!g_dbus_register_interface(connection, profile->path,
  186. "org.bluez.Profile1", profile_methods,
  187. NULL, NULL,
  188. profile, NULL)) {
  189. error("D-Bus failed to register %s", profile->path);
  190. g_free(profile->path);
  191. profile->path = NULL;
  192. return -1;
  193. }
  194. msg = dbus_message_new_method_call("org.bluez", "/org/bluez",
  195. "org.bluez.ProfileManager1",
  196. "RegisterProfile");
  197. dbus_message_iter_init_append(msg, &iter);
  198. dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
  199. &profile->path);
  200. dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
  201. &profile->uuid);
  202. dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
  203. DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
  204. DBUS_TYPE_STRING_AS_STRING
  205. DBUS_TYPE_VARIANT_AS_STRING
  206. DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
  207. &opt);
  208. g_dbus_dict_append_entry(&opt, "AutoConnect", DBUS_TYPE_BOOLEAN,
  209. &auto_connect);
  210. if (profile->driver->record) {
  211. if (profile->driver->port != 0)
  212. xml = g_markup_printf_escaped(profile->driver->record,
  213. profile->driver->channel,
  214. profile->driver->name,
  215. profile->driver->port);
  216. else
  217. xml = g_markup_printf_escaped(profile->driver->record,
  218. profile->driver->channel,
  219. profile->driver->name);
  220. g_dbus_dict_append_entry(&opt, "ServiceRecord",
  221. DBUS_TYPE_STRING, &xml);
  222. g_free(xml);
  223. }
  224. dbus_message_iter_close_container(&iter, &opt);
  225. if (!g_dbus_send_message_with_reply(connection, msg, &call, -1)) {
  226. ret = -1;
  227. unregister_profile(profile);
  228. goto failed;
  229. }
  230. dbus_pending_call_set_notify(call, register_profile_reply, profile,
  231. NULL);
  232. dbus_pending_call_unref(call);
  233. failed:
  234. dbus_message_unref(msg);
  235. return ret;
  236. }
  237. static const char *service2uuid(uint16_t service)
  238. {
  239. switch (service) {
  240. case OBEX_OPP:
  241. return OBEX_OPP_UUID;
  242. case OBEX_FTP:
  243. return OBEX_FTP_UUID;
  244. case OBEX_PBAP:
  245. return OBEX_PSE_UUID;
  246. case OBEX_IRMC:
  247. return OBEX_SYNC_UUID;
  248. case OBEX_PCSUITE:
  249. return "00005005-0000-1000-8000-0002ee000001";
  250. case OBEX_SYNCEVOLUTION:
  251. return "00000002-0000-1000-8000-0002ee000002";
  252. case OBEX_MAS:
  253. return OBEX_MAS_UUID;
  254. case OBEX_MNS:
  255. return OBEX_MNS_UUID;
  256. }
  257. return NULL;
  258. }
  259. static void name_acquired(DBusConnection *conn, void *user_data)
  260. {
  261. GSList *l;
  262. DBG("org.bluez appeared");
  263. for (l = profiles; l; l = l->next) {
  264. struct bluetooth_profile *profile = l->data;
  265. if (profile->path != NULL)
  266. continue;
  267. if (register_profile(profile) < 0) {
  268. error("bluetooth: Failed to register profile %s",
  269. profile->path);
  270. g_free(profile->path);
  271. profile->path = NULL;
  272. }
  273. }
  274. }
  275. static void name_released(DBusConnection *conn, void *user_data)
  276. {
  277. GSList *l;
  278. DBG("org.bluez disappered");
  279. for (l = profiles; l; l = l->next) {
  280. struct bluetooth_profile *profile = l->data;
  281. if (profile->path == NULL)
  282. continue;
  283. unregister_profile(profile);
  284. }
  285. }
  286. static void *bluetooth_start(struct obex_server *server, int *err)
  287. {
  288. const GSList *l;
  289. for (l = server->drivers; l; l = l->next) {
  290. struct obex_service_driver *driver = l->data;
  291. struct bluetooth_profile *profile;
  292. const char *uuid;
  293. uuid = service2uuid(driver->service);
  294. if (uuid == NULL)
  295. continue;
  296. profile = g_new0(struct bluetooth_profile, 1);
  297. profile->driver = driver;
  298. profile->server = server;
  299. profile->uuid = g_strdup(uuid);
  300. profiles = g_slist_prepend(profiles, profile);
  301. }
  302. return profiles;
  303. }
  304. static void bluetooth_stop(void *data)
  305. {
  306. g_slist_free_full(profiles, profile_free);
  307. profiles = NULL;
  308. }
  309. static int bluetooth_getpeername(GIOChannel *io, char **name)
  310. {
  311. GError *gerr = NULL;
  312. char address[18];
  313. bt_io_get(io, &gerr, BT_IO_OPT_DEST, address, BT_IO_OPT_INVALID);
  314. if (gerr) {
  315. error("%s", gerr->message);
  316. g_error_free(gerr);
  317. return -EINVAL;
  318. }
  319. *name = g_strdup(address);
  320. return 0;
  321. }
  322. static int bluetooth_getsockname(GIOChannel *io, char **name)
  323. {
  324. GError *gerr = NULL;
  325. char address[18];
  326. bt_io_get(io, &gerr, BT_IO_OPT_SOURCE, address, BT_IO_OPT_INVALID);
  327. if (gerr) {
  328. error("%s", gerr->message);
  329. g_error_free(gerr);
  330. return -EINVAL;
  331. }
  332. *name = g_strdup(address);
  333. return 0;
  334. }
  335. static struct obex_transport_driver driver = {
  336. .name = "bluetooth",
  337. .start = bluetooth_start,
  338. .getpeername = bluetooth_getpeername,
  339. .getsockname = bluetooth_getsockname,
  340. .stop = bluetooth_stop
  341. };
  342. static unsigned int listener_id = 0;
  343. static int bluetooth_init(void)
  344. {
  345. connection = g_dbus_setup_private(DBUS_BUS_SYSTEM, NULL, NULL);
  346. if (connection == NULL)
  347. return -EPERM;
  348. listener_id = g_dbus_add_service_watch(connection, "org.bluez",
  349. name_acquired, name_released, NULL, NULL);
  350. return obex_transport_driver_register(&driver);
  351. }
  352. static void bluetooth_exit(void)
  353. {
  354. g_dbus_remove_watch(connection, listener_id);
  355. g_slist_free_full(profiles, profile_free);
  356. if (connection)
  357. dbus_connection_unref(connection);
  358. obex_transport_driver_unregister(&driver);
  359. }
  360. OBEX_PLUGIN_DEFINE(bluetooth, bluetooth_init, bluetooth_exit)