gatt.c 74 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. *
  4. * BlueZ - Bluetooth protocol stack for Linux
  5. *
  6. * Copyright (C) 2014 Intel Corporation. All rights reserved.
  7. *
  8. *
  9. */
  10. #ifdef HAVE_CONFIG_H
  11. #include <config.h>
  12. #endif
  13. #define _GNU_SOURCE
  14. #include <stdio.h>
  15. #include <errno.h>
  16. #include <unistd.h>
  17. #include <stdlib.h>
  18. #include <stdbool.h>
  19. #include <sys/uio.h>
  20. #include <fcntl.h>
  21. #include <string.h>
  22. #include <sys/types.h>
  23. #include <sys/socket.h>
  24. #include <glib.h>
  25. #include "src/shared/util.h"
  26. #include "src/shared/queue.h"
  27. #include "src/shared/io.h"
  28. #include "src/shared/shell.h"
  29. #include "gdbus/gdbus.h"
  30. #include "gatt.h"
  31. #define APP_PATH "/org/bluez/app"
  32. #define DEVICE_INTERFACE "org.bluez.Device1"
  33. #define PROFILE_INTERFACE "org.bluez.GattProfile1"
  34. #define SERVICE_INTERFACE "org.bluez.GattService1"
  35. #define CHRC_INTERFACE "org.bluez.GattCharacteristic1"
  36. #define DESC_INTERFACE "org.bluez.GattDescriptor1"
  37. /* String display constants */
  38. #define COLORED_NEW COLOR_GREEN "NEW" COLOR_OFF
  39. #define COLORED_CHG COLOR_YELLOW "CHG" COLOR_OFF
  40. #define COLORED_DEL COLOR_RED "DEL" COLOR_OFF
  41. #define MAX_ATTR_VAL_LEN 512
  42. struct desc {
  43. struct chrc *chrc;
  44. char *path;
  45. uint16_t handle;
  46. char *uuid;
  47. char **flags;
  48. size_t value_len;
  49. unsigned int max_val_len;
  50. uint8_t *value;
  51. };
  52. struct chrc {
  53. struct service *service;
  54. GDBusProxy *proxy;
  55. char *path;
  56. uint16_t handle;
  57. char *uuid;
  58. char **flags;
  59. bool notifying;
  60. GList *descs;
  61. size_t value_len;
  62. unsigned int max_val_len;
  63. uint8_t *value;
  64. uint16_t mtu;
  65. struct io *write_io;
  66. struct io *notify_io;
  67. bool authorization_req;
  68. };
  69. struct service {
  70. DBusConnection *conn;
  71. GDBusProxy *proxy;
  72. char *path;
  73. uint16_t handle;
  74. char *uuid;
  75. bool primary;
  76. GList *chrcs;
  77. GList *inc;
  78. };
  79. static GList *local_services;
  80. static GList *services;
  81. static GList *characteristics;
  82. static GList *descriptors;
  83. static GList *managers;
  84. static GList *uuids;
  85. static DBusMessage *pending_message = NULL;
  86. struct sock_io {
  87. GDBusProxy *proxy;
  88. struct io *io;
  89. uint16_t mtu;
  90. };
  91. static struct sock_io write_io;
  92. static struct sock_io notify_io;
  93. static void print_service(struct service *service, const char *description)
  94. {
  95. const char *text;
  96. text = bt_uuidstr_to_str(service->uuid);
  97. if (!text)
  98. bt_shell_printf("%s%s%s%s Service (Handle 0x%04x)\n\t%s\n\t"
  99. "%s\n",
  100. description ? "[" : "",
  101. description ? : "",
  102. description ? "] " : "",
  103. service->primary ? "Primary" :
  104. "Secondary",
  105. service->handle, service->path,
  106. service->uuid);
  107. else
  108. bt_shell_printf("%s%s%s%s Service (Handle 0x%04x)\n\t%s\n\t%s"
  109. "\n\t%s\n",
  110. description ? "[" : "",
  111. description ? : "",
  112. description ? "] " : "",
  113. service->primary ? "Primary" :
  114. "Secondary",
  115. service->handle, service->path,
  116. service->uuid, text);
  117. }
  118. static void print_inc_service(struct service *service, const char *description)
  119. {
  120. const char *text;
  121. text = bt_uuidstr_to_str(service->uuid);
  122. if (!text)
  123. bt_shell_printf("%s%s%s%s Included Service (Handle 0x%04x)\n\t"
  124. "%s\n\t%s\n",
  125. description ? "[" : "",
  126. description ? : "",
  127. description ? "] " : "",
  128. service->primary ? "Primary" :
  129. "Secondary",
  130. service->handle, service->path,
  131. service->uuid);
  132. else
  133. bt_shell_printf("%s%s%s%s Included Service (Handle 0x%04x)\n\t"
  134. "%s\n\t%s\n\t%s\n",
  135. description ? "[" : "",
  136. description ? : "",
  137. description ? "] " : "",
  138. service->primary ? "Primary" :
  139. "Secondary",
  140. service->handle, service->path,
  141. service->uuid, text);
  142. }
  143. static void print_service_proxy(GDBusProxy *proxy, const char *description)
  144. {
  145. struct service service;
  146. DBusMessageIter iter;
  147. const char *uuid;
  148. dbus_bool_t primary;
  149. if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
  150. return;
  151. dbus_message_iter_get_basic(&iter, &uuid);
  152. if (g_dbus_proxy_get_property(proxy, "Primary", &iter) == FALSE)
  153. return;
  154. dbus_message_iter_get_basic(&iter, &primary);
  155. service.path = (char *) g_dbus_proxy_get_path(proxy);
  156. service.uuid = (char *) uuid;
  157. service.primary = primary;
  158. print_service(&service, description);
  159. }
  160. void gatt_add_service(GDBusProxy *proxy)
  161. {
  162. services = g_list_append(services, proxy);
  163. print_service_proxy(proxy, COLORED_NEW);
  164. }
  165. static struct service *remove_service_by_proxy(struct GDBusProxy *proxy)
  166. {
  167. GList *l;
  168. for (l = local_services; l; l = g_list_next(l)) {
  169. struct service *service = l->data;
  170. if (service->proxy == proxy) {
  171. local_services = g_list_delete_link(local_services, l);
  172. return service;
  173. }
  174. }
  175. return NULL;
  176. }
  177. void gatt_remove_service(GDBusProxy *proxy)
  178. {
  179. struct service *service;
  180. GList *l;
  181. l = g_list_find(services, proxy);
  182. if (!l)
  183. return;
  184. services = g_list_delete_link(services, l);
  185. print_service_proxy(proxy, COLORED_DEL);
  186. service = remove_service_by_proxy(proxy);
  187. if (service)
  188. g_dbus_unregister_interface(service->conn, service->path,
  189. SERVICE_INTERFACE);
  190. }
  191. static void print_chrc(struct chrc *chrc, const char *description)
  192. {
  193. const char *text;
  194. text = bt_uuidstr_to_str(chrc->uuid);
  195. if (!text)
  196. bt_shell_printf("%s%s%sCharacteristic (Handle 0x%04x)\n\t%s\n\t"
  197. "%s\n",
  198. description ? "[" : "",
  199. description ? : "",
  200. description ? "] " : "",
  201. chrc->handle, chrc->path, chrc->uuid);
  202. else
  203. bt_shell_printf("%s%s%sCharacteristic (Handle 0x%04x)\n\t%s\n\t"
  204. "%s\n\t%s\n",
  205. description ? "[" : "",
  206. description ? : "",
  207. description ? "] " : "",
  208. chrc->handle, chrc->path, chrc->uuid,
  209. text);
  210. }
  211. static void print_characteristic(GDBusProxy *proxy, const char *description)
  212. {
  213. struct chrc chrc;
  214. DBusMessageIter iter;
  215. const char *uuid;
  216. if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
  217. return;
  218. dbus_message_iter_get_basic(&iter, &uuid);
  219. chrc.path = (char *) g_dbus_proxy_get_path(proxy);
  220. chrc.uuid = (char *) uuid;
  221. print_chrc(&chrc, description);
  222. }
  223. static gboolean chrc_is_child(GDBusProxy *characteristic)
  224. {
  225. DBusMessageIter iter;
  226. const char *service;
  227. if (!g_dbus_proxy_get_property(characteristic, "Service", &iter))
  228. return FALSE;
  229. dbus_message_iter_get_basic(&iter, &service);
  230. return g_dbus_proxy_lookup(services, NULL, service,
  231. "org.bluez.GattService1") != NULL;
  232. }
  233. void gatt_add_characteristic(GDBusProxy *proxy)
  234. {
  235. if (!chrc_is_child(proxy))
  236. return;
  237. characteristics = g_list_append(characteristics, proxy);
  238. print_characteristic(proxy, COLORED_NEW);
  239. }
  240. static void notify_io_destroy(void)
  241. {
  242. io_destroy(notify_io.io);
  243. memset(&notify_io, 0, sizeof(notify_io));
  244. }
  245. static void write_io_destroy(void)
  246. {
  247. io_destroy(write_io.io);
  248. memset(&write_io, 0, sizeof(write_io));
  249. }
  250. void gatt_remove_characteristic(GDBusProxy *proxy)
  251. {
  252. GList *l;
  253. l = g_list_find(characteristics, proxy);
  254. if (!l)
  255. return;
  256. characteristics = g_list_delete_link(characteristics, l);
  257. print_characteristic(proxy, COLORED_DEL);
  258. if (write_io.proxy == proxy)
  259. write_io_destroy();
  260. else if (notify_io.proxy == proxy)
  261. notify_io_destroy();
  262. }
  263. static void print_desc(struct desc *desc, const char *description)
  264. {
  265. const char *text;
  266. text = bt_uuidstr_to_str(desc->uuid);
  267. if (!text)
  268. bt_shell_printf("%s%s%sDescriptor (Handle 0x%04x)\n\t%s\n\t"
  269. "%s\n",
  270. description ? "[" : "",
  271. description ? : "",
  272. description ? "] " : "",
  273. desc->handle, desc->path, desc->uuid);
  274. else
  275. bt_shell_printf("%s%s%sDescriptor (Handle 0x%04x)\n\t%s\n\t"
  276. "%s\n\t%s\n",
  277. description ? "[" : "",
  278. description ? : "",
  279. description ? "] " : "",
  280. desc->handle, desc->path, desc->uuid,
  281. text);
  282. }
  283. static void print_descriptor(GDBusProxy *proxy, const char *description)
  284. {
  285. struct desc desc;
  286. DBusMessageIter iter;
  287. const char *uuid;
  288. if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
  289. return;
  290. dbus_message_iter_get_basic(&iter, &uuid);
  291. desc.path = (char *) g_dbus_proxy_get_path(proxy);
  292. desc.uuid = (char *) uuid;
  293. print_desc(&desc, description);
  294. }
  295. static gboolean descriptor_is_child(GDBusProxy *characteristic)
  296. {
  297. GList *l;
  298. DBusMessageIter iter;
  299. const char *service, *path;
  300. if (!g_dbus_proxy_get_property(characteristic, "Characteristic", &iter))
  301. return FALSE;
  302. dbus_message_iter_get_basic(&iter, &service);
  303. for (l = characteristics; l; l = g_list_next(l)) {
  304. GDBusProxy *proxy = l->data;
  305. path = g_dbus_proxy_get_path(proxy);
  306. if (!strcmp(path, service))
  307. return TRUE;
  308. }
  309. return FALSE;
  310. }
  311. void gatt_add_descriptor(GDBusProxy *proxy)
  312. {
  313. if (!descriptor_is_child(proxy))
  314. return;
  315. descriptors = g_list_append(descriptors, proxy);
  316. print_descriptor(proxy, COLORED_NEW);
  317. }
  318. void gatt_remove_descriptor(GDBusProxy *proxy)
  319. {
  320. GList *l;
  321. l = g_list_find(descriptors, proxy);
  322. if (!l)
  323. return;
  324. descriptors = g_list_delete_link(descriptors, l);
  325. print_descriptor(proxy, COLORED_DEL);
  326. }
  327. static void list_attributes(const char *path, GList *source)
  328. {
  329. GList *l;
  330. for (l = source; l; l = g_list_next(l)) {
  331. GDBusProxy *proxy = l->data;
  332. const char *proxy_path;
  333. proxy_path = g_dbus_proxy_get_path(proxy);
  334. if (!g_str_has_prefix(proxy_path, path))
  335. continue;
  336. if (source == services) {
  337. print_service_proxy(proxy, NULL);
  338. list_attributes(proxy_path, characteristics);
  339. } else if (source == characteristics) {
  340. print_characteristic(proxy, NULL);
  341. list_attributes(proxy_path, descriptors);
  342. } else if (source == descriptors)
  343. print_descriptor(proxy, NULL);
  344. }
  345. }
  346. static void list_descs(GList *descs)
  347. {
  348. GList *l;
  349. for (l = descs; l; l = g_list_next(l)) {
  350. struct desc *desc = l->data;
  351. print_desc(desc, NULL);
  352. }
  353. }
  354. static void list_chrcs(GList *chrcs)
  355. {
  356. GList *l;
  357. for (l = chrcs; l; l = g_list_next(l)) {
  358. struct chrc *chrc = l->data;
  359. print_chrc(chrc, NULL);
  360. list_descs(chrc->descs);
  361. }
  362. }
  363. static void list_services(void)
  364. {
  365. GList *l;
  366. for (l = local_services; l; l = g_list_next(l)) {
  367. struct service *service = l->data;
  368. print_service(service, NULL);
  369. list_chrcs(service->chrcs);
  370. }
  371. }
  372. void gatt_list_attributes(const char *path)
  373. {
  374. if (path && !strcmp(path, "local")) {
  375. list_services();
  376. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  377. }
  378. list_attributes(path, services);
  379. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  380. }
  381. static GDBusProxy *select_attribute(const char *path)
  382. {
  383. GDBusProxy *proxy;
  384. proxy = g_dbus_proxy_lookup(services, NULL, path,
  385. "org.bluez.GattService1");
  386. if (proxy)
  387. return proxy;
  388. proxy = g_dbus_proxy_lookup(characteristics, NULL, path,
  389. "org.bluez.GattCharacteristic1");
  390. if (proxy)
  391. return proxy;
  392. return g_dbus_proxy_lookup(descriptors, NULL, path,
  393. "org.bluez.GattDescriptor1");
  394. }
  395. static GDBusProxy *select_proxy_by_uuid(GDBusProxy *parent, const char *uuid,
  396. GList *source)
  397. {
  398. GList *l;
  399. const char *value;
  400. DBusMessageIter iter;
  401. for (l = source; l; l = g_list_next(l)) {
  402. GDBusProxy *proxy = l->data;
  403. if (parent && !g_str_has_prefix(g_dbus_proxy_get_path(proxy),
  404. g_dbus_proxy_get_path(parent)))
  405. continue;
  406. if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
  407. continue;
  408. dbus_message_iter_get_basic(&iter, &value);
  409. if (strcasecmp(uuid, value) == 0)
  410. return proxy;
  411. if (strlen(uuid) == 4 && !strncasecmp(value + 4, uuid, 4))
  412. return proxy;
  413. }
  414. return NULL;
  415. }
  416. static GDBusProxy *select_attribute_by_uuid(GDBusProxy *parent,
  417. const char *uuid)
  418. {
  419. GDBusProxy *proxy;
  420. proxy = select_proxy_by_uuid(parent, uuid, services);
  421. if (proxy)
  422. return proxy;
  423. proxy = select_proxy_by_uuid(parent, uuid, characteristics);
  424. if (proxy)
  425. return proxy;
  426. return select_proxy_by_uuid(parent, uuid, descriptors);
  427. }
  428. GDBusProxy *gatt_select_attribute(GDBusProxy *parent, const char *arg)
  429. {
  430. if (arg[0] == '/')
  431. return select_attribute(arg);
  432. if (parent) {
  433. GDBusProxy *proxy = select_attribute_by_uuid(parent, arg);
  434. if (proxy)
  435. return proxy;
  436. }
  437. return select_attribute_by_uuid(NULL, arg);
  438. }
  439. static char *attribute_generator(const char *text, int state, GList *source)
  440. {
  441. static int index;
  442. if (!state) {
  443. index = 0;
  444. }
  445. return g_dbus_proxy_path_lookup(source, &index, text);
  446. }
  447. char *gatt_attribute_generator(const char *text, int state)
  448. {
  449. static GList *list = NULL;
  450. if (!state) {
  451. GList *list1;
  452. if (list) {
  453. g_list_free(list);
  454. list = NULL;
  455. }
  456. list1 = g_list_copy(characteristics);
  457. list1 = g_list_concat(list1, g_list_copy(descriptors));
  458. list = g_list_copy(services);
  459. list = g_list_concat(list, list1);
  460. }
  461. return attribute_generator(text, state, list);
  462. }
  463. static void read_reply(DBusMessage *message, void *user_data)
  464. {
  465. DBusError error;
  466. DBusMessageIter iter, array;
  467. uint8_t *value;
  468. int len;
  469. dbus_error_init(&error);
  470. if (dbus_set_error_from_message(&error, message) == TRUE) {
  471. bt_shell_printf("Failed to read: %s\n", error.name);
  472. dbus_error_free(&error);
  473. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  474. }
  475. dbus_message_iter_init(message, &iter);
  476. if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
  477. bt_shell_printf("Invalid response to read\n");
  478. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  479. }
  480. dbus_message_iter_recurse(&iter, &array);
  481. dbus_message_iter_get_fixed_array(&array, &value, &len);
  482. if (len < 0) {
  483. bt_shell_printf("Unable to parse value\n");
  484. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  485. }
  486. bt_shell_hexdump(value, len);
  487. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  488. }
  489. static void read_setup(DBusMessageIter *iter, void *user_data)
  490. {
  491. DBusMessageIter dict;
  492. uint16_t *offset = user_data;
  493. dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
  494. DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
  495. DBUS_TYPE_STRING_AS_STRING
  496. DBUS_TYPE_VARIANT_AS_STRING
  497. DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
  498. &dict);
  499. g_dbus_dict_append_entry(&dict, "offset", DBUS_TYPE_UINT16, offset);
  500. dbus_message_iter_close_container(iter, &dict);
  501. }
  502. static void read_attribute(GDBusProxy *proxy, uint16_t offset)
  503. {
  504. if (g_dbus_proxy_method_call(proxy, "ReadValue", read_setup, read_reply,
  505. &offset, NULL) == FALSE) {
  506. bt_shell_printf("Failed to read\n");
  507. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  508. }
  509. bt_shell_printf("Attempting to read %s\n", g_dbus_proxy_get_path(proxy));
  510. }
  511. void gatt_read_attribute(GDBusProxy *proxy, int argc, char *argv[])
  512. {
  513. const char *iface;
  514. uint16_t offset = 0;
  515. iface = g_dbus_proxy_get_interface(proxy);
  516. if (!strcmp(iface, "org.bluez.GattCharacteristic1") ||
  517. !strcmp(iface, "org.bluez.GattDescriptor1")) {
  518. if (argc == 2)
  519. offset = atoi(argv[1]);
  520. read_attribute(proxy, offset);
  521. return;
  522. }
  523. bt_shell_printf("Unable to read attribute %s\n",
  524. g_dbus_proxy_get_path(proxy));
  525. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  526. }
  527. static void write_reply(DBusMessage *message, void *user_data)
  528. {
  529. DBusError error;
  530. dbus_error_init(&error);
  531. if (dbus_set_error_from_message(&error, message) == TRUE) {
  532. bt_shell_printf("Failed to write: %s\n", error.name);
  533. dbus_error_free(&error);
  534. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  535. }
  536. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  537. }
  538. struct write_attribute_data {
  539. DBusMessage *msg;
  540. struct iovec iov;
  541. char *type;
  542. uint16_t offset;
  543. };
  544. static void write_setup(DBusMessageIter *iter, void *user_data)
  545. {
  546. struct write_attribute_data *wd = user_data;
  547. DBusMessageIter array, dict;
  548. dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array);
  549. dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
  550. &wd->iov.iov_base,
  551. wd->iov.iov_len);
  552. dbus_message_iter_close_container(iter, &array);
  553. dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
  554. DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
  555. DBUS_TYPE_STRING_AS_STRING
  556. DBUS_TYPE_VARIANT_AS_STRING
  557. DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
  558. &dict);
  559. if (wd->type)
  560. g_dbus_dict_append_entry(&dict, "type", DBUS_TYPE_STRING,
  561. &wd->type);
  562. g_dbus_dict_append_entry(&dict, "offset", DBUS_TYPE_UINT16,
  563. &wd->offset);
  564. dbus_message_iter_close_container(iter, &dict);
  565. }
  566. static int sock_send(struct io *io, struct iovec *iov, size_t iovlen)
  567. {
  568. struct msghdr msg;
  569. int ret;
  570. memset(&msg, 0, sizeof(msg));
  571. msg.msg_iov = iov;
  572. msg.msg_iovlen = iovlen;
  573. ret = sendmsg(io_get_fd(io), &msg, MSG_NOSIGNAL);
  574. if (ret < 0) {
  575. ret = -errno;
  576. bt_shell_printf("sendmsg: %s", strerror(-ret));
  577. }
  578. return ret;
  579. }
  580. static void write_attribute(GDBusProxy *proxy,
  581. struct write_attribute_data *data)
  582. {
  583. /* Write using the fd if it has been acquired and fit the MTU */
  584. if (proxy == write_io.proxy &&
  585. (write_io.io && write_io.mtu >= data->iov.iov_len)) {
  586. bt_shell_printf("Attempting to write fd %d\n",
  587. io_get_fd(write_io.io));
  588. if (sock_send(write_io.io, &data->iov, 1) < 0) {
  589. bt_shell_printf("Failed to write: %s", strerror(errno));
  590. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  591. }
  592. return;
  593. }
  594. if (g_dbus_proxy_method_call(proxy, "WriteValue", write_setup,
  595. write_reply, data, NULL) == FALSE) {
  596. bt_shell_printf("Failed to write\n");
  597. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  598. }
  599. bt_shell_printf("Attempting to write %s\n",
  600. g_dbus_proxy_get_path(proxy));
  601. }
  602. static uint8_t *str2bytearray(char *arg, size_t *val_len)
  603. {
  604. uint8_t value[MAX_ATTR_VAL_LEN];
  605. char *entry;
  606. unsigned int i;
  607. for (i = 0; (entry = strsep(&arg, " \t")) != NULL; i++) {
  608. long int val;
  609. char *endptr = NULL;
  610. if (*entry == '\0')
  611. continue;
  612. if (i >= G_N_ELEMENTS(value)) {
  613. bt_shell_printf("Too much data\n");
  614. return NULL;
  615. }
  616. val = strtol(entry, &endptr, 0);
  617. if (!endptr || *endptr != '\0' || val > UINT8_MAX) {
  618. bt_shell_printf("Invalid value at index %d\n", i);
  619. return NULL;
  620. }
  621. value[i] = val;
  622. }
  623. *val_len = i;
  624. return g_memdup(value, i);
  625. }
  626. void gatt_write_attribute(GDBusProxy *proxy, int argc, char *argv[])
  627. {
  628. const char *iface;
  629. struct write_attribute_data data;
  630. memset(&data, 0, sizeof(data));
  631. iface = g_dbus_proxy_get_interface(proxy);
  632. if (!strcmp(iface, "org.bluez.GattCharacteristic1") ||
  633. !strcmp(iface, "org.bluez.GattDescriptor1")) {
  634. data.iov.iov_base = str2bytearray(argv[1], &data.iov.iov_len);
  635. if (argc > 2)
  636. data.offset = atoi(argv[2]);
  637. if (argc > 3)
  638. data.type = argv[3];
  639. write_attribute(proxy, &data);
  640. return;
  641. }
  642. bt_shell_printf("Unable to write attribute %s\n",
  643. g_dbus_proxy_get_path(proxy));
  644. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  645. }
  646. static bool sock_read(struct io *io, void *user_data)
  647. {
  648. struct chrc *chrc = user_data;
  649. struct msghdr msg;
  650. struct iovec iov;
  651. uint8_t buf[MAX_ATTR_VAL_LEN];
  652. int fd = io_get_fd(io);
  653. ssize_t bytes_read;
  654. if (io != notify_io.io && !chrc)
  655. return true;
  656. iov.iov_base = buf;
  657. iov.iov_len = sizeof(buf);
  658. memset(&msg, 0, sizeof(msg));
  659. msg.msg_iov = &iov;
  660. msg.msg_iovlen = 1;
  661. bytes_read = recvmsg(fd, &msg, MSG_DONTWAIT);
  662. if (bytes_read < 0) {
  663. bt_shell_printf("recvmsg: %s", strerror(errno));
  664. return false;
  665. }
  666. if (!bytes_read)
  667. return false;
  668. if (chrc)
  669. bt_shell_printf("[" COLORED_CHG "] Attribute %s (%s) "
  670. "written:\n", chrc->path,
  671. bt_uuidstr_to_str(chrc->uuid));
  672. else
  673. bt_shell_printf("[" COLORED_CHG "] %s Notification:\n",
  674. g_dbus_proxy_get_path(notify_io.proxy));
  675. bt_shell_hexdump(buf, bytes_read);
  676. return true;
  677. }
  678. static bool sock_hup(struct io *io, void *user_data)
  679. {
  680. struct chrc *chrc = user_data;
  681. if (chrc) {
  682. bt_shell_printf("Attribute %s %s sock closed\n", chrc->path,
  683. io == chrc->write_io ? "Write" : "Notify");
  684. if (io == chrc->write_io) {
  685. io_destroy(chrc->write_io);
  686. chrc->write_io = NULL;
  687. } else {
  688. io_destroy(chrc->notify_io);
  689. chrc->notify_io = NULL;
  690. }
  691. return false;
  692. }
  693. bt_shell_printf("%s closed\n", io == notify_io.io ? "Notify" : "Write");
  694. if (io == notify_io.io)
  695. notify_io_destroy();
  696. else
  697. write_io_destroy();
  698. return false;
  699. }
  700. static struct io *sock_io_new(int fd, void *user_data)
  701. {
  702. struct io *io;
  703. io = io_new(fd);
  704. io_set_close_on_destroy(io, true);
  705. io_set_read_handler(io, sock_read, user_data, NULL);
  706. io_set_disconnect_handler(io, sock_hup, user_data, NULL);
  707. return io;
  708. }
  709. static void acquire_write_reply(DBusMessage *message, void *user_data)
  710. {
  711. DBusError error;
  712. int fd;
  713. dbus_error_init(&error);
  714. if (dbus_set_error_from_message(&error, message) == TRUE) {
  715. bt_shell_printf("Failed to acquire write: %s\n", error.name);
  716. dbus_error_free(&error);
  717. write_io.proxy = NULL;
  718. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  719. }
  720. if (write_io.io)
  721. write_io_destroy();
  722. if ((dbus_message_get_args(message, NULL, DBUS_TYPE_UNIX_FD, &fd,
  723. DBUS_TYPE_UINT16, &write_io.mtu,
  724. DBUS_TYPE_INVALID) == false)) {
  725. bt_shell_printf("Invalid AcquireWrite response\n");
  726. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  727. }
  728. bt_shell_printf("AcquireWrite success: fd %d MTU %u\n", fd,
  729. write_io.mtu);
  730. write_io.io = sock_io_new(fd, NULL);
  731. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  732. }
  733. static void acquire_setup(DBusMessageIter *iter, void *user_data)
  734. {
  735. DBusMessageIter dict;
  736. dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
  737. DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
  738. DBUS_TYPE_STRING_AS_STRING
  739. DBUS_TYPE_VARIANT_AS_STRING
  740. DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
  741. &dict);
  742. dbus_message_iter_close_container(iter, &dict);
  743. }
  744. void gatt_acquire_write(GDBusProxy *proxy, const char *arg)
  745. {
  746. const char *iface;
  747. iface = g_dbus_proxy_get_interface(proxy);
  748. if (strcmp(iface, "org.bluez.GattCharacteristic1")) {
  749. bt_shell_printf("Unable to acquire write: %s not a"
  750. " characteristic\n",
  751. g_dbus_proxy_get_path(proxy));
  752. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  753. }
  754. if (g_dbus_proxy_method_call(proxy, "AcquireWrite", acquire_setup,
  755. acquire_write_reply, NULL, NULL) == FALSE) {
  756. bt_shell_printf("Failed to AcquireWrite\n");
  757. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  758. }
  759. write_io.proxy = proxy;
  760. }
  761. void gatt_release_write(GDBusProxy *proxy, const char *arg)
  762. {
  763. if (proxy != write_io.proxy || !write_io.io) {
  764. bt_shell_printf("Write not acquired\n");
  765. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  766. }
  767. write_io_destroy();
  768. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  769. }
  770. static void acquire_notify_reply(DBusMessage *message, void *user_data)
  771. {
  772. DBusError error;
  773. int fd;
  774. dbus_error_init(&error);
  775. if (dbus_set_error_from_message(&error, message) == TRUE) {
  776. bt_shell_printf("Failed to acquire notify: %s\n", error.name);
  777. dbus_error_free(&error);
  778. write_io.proxy = NULL;
  779. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  780. }
  781. if (notify_io.io) {
  782. io_destroy(notify_io.io);
  783. notify_io.io = NULL;
  784. }
  785. notify_io.mtu = 0;
  786. if ((dbus_message_get_args(message, NULL, DBUS_TYPE_UNIX_FD, &fd,
  787. DBUS_TYPE_UINT16, &notify_io.mtu,
  788. DBUS_TYPE_INVALID) == false)) {
  789. bt_shell_printf("Invalid AcquireNotify response\n");
  790. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  791. }
  792. bt_shell_printf("AcquireNotify success: fd %d MTU %u\n", fd,
  793. notify_io.mtu);
  794. notify_io.io = sock_io_new(fd, NULL);
  795. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  796. }
  797. void gatt_acquire_notify(GDBusProxy *proxy, const char *arg)
  798. {
  799. const char *iface;
  800. iface = g_dbus_proxy_get_interface(proxy);
  801. if (strcmp(iface, "org.bluez.GattCharacteristic1")) {
  802. bt_shell_printf("Unable to acquire notify: %s not a"
  803. " characteristic\n",
  804. g_dbus_proxy_get_path(proxy));
  805. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  806. }
  807. if (g_dbus_proxy_method_call(proxy, "AcquireNotify", acquire_setup,
  808. acquire_notify_reply, NULL, NULL) == FALSE) {
  809. bt_shell_printf("Failed to AcquireNotify\n");
  810. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  811. }
  812. notify_io.proxy = proxy;
  813. }
  814. void gatt_release_notify(GDBusProxy *proxy, const char *arg)
  815. {
  816. if (proxy != notify_io.proxy || !notify_io.io) {
  817. bt_shell_printf("Notify not acquired\n");
  818. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  819. }
  820. notify_io_destroy();
  821. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  822. }
  823. static void notify_reply(DBusMessage *message, void *user_data)
  824. {
  825. bool enable = GPOINTER_TO_UINT(user_data);
  826. DBusError error;
  827. dbus_error_init(&error);
  828. if (dbus_set_error_from_message(&error, message) == TRUE) {
  829. bt_shell_printf("Failed to %s notify: %s\n",
  830. enable ? "start" : "stop", error.name);
  831. dbus_error_free(&error);
  832. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  833. }
  834. bt_shell_printf("Notify %s\n", enable == TRUE ? "started" : "stopped");
  835. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  836. }
  837. static void notify_attribute(GDBusProxy *proxy, bool enable)
  838. {
  839. const char *method;
  840. if (enable == TRUE)
  841. method = "StartNotify";
  842. else
  843. method = "StopNotify";
  844. if (g_dbus_proxy_method_call(proxy, method, NULL, notify_reply,
  845. GUINT_TO_POINTER(enable), NULL) == FALSE) {
  846. bt_shell_printf("Failed to %s notify\n",
  847. enable ? "start" : "stop");
  848. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  849. }
  850. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  851. }
  852. void gatt_notify_attribute(GDBusProxy *proxy, bool enable)
  853. {
  854. const char *iface;
  855. iface = g_dbus_proxy_get_interface(proxy);
  856. if (!strcmp(iface, "org.bluez.GattCharacteristic1")) {
  857. notify_attribute(proxy, enable);
  858. return;
  859. }
  860. bt_shell_printf("Unable to notify attribute %s\n",
  861. g_dbus_proxy_get_path(proxy));
  862. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  863. }
  864. static void register_app_setup(DBusMessageIter *iter, void *user_data)
  865. {
  866. DBusMessageIter opt;
  867. const char *path = "/";
  868. dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
  869. dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
  870. DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
  871. DBUS_TYPE_STRING_AS_STRING
  872. DBUS_TYPE_VARIANT_AS_STRING
  873. DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
  874. &opt);
  875. dbus_message_iter_close_container(iter, &opt);
  876. }
  877. static void register_app_reply(DBusMessage *message, void *user_data)
  878. {
  879. DBusError error;
  880. dbus_error_init(&error);
  881. if (dbus_set_error_from_message(&error, message) == TRUE) {
  882. bt_shell_printf("Failed to register application: %s\n",
  883. error.name);
  884. dbus_error_free(&error);
  885. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  886. }
  887. bt_shell_printf("Application registered\n");
  888. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  889. }
  890. void gatt_add_manager(GDBusProxy *proxy)
  891. {
  892. managers = g_list_append(managers, proxy);
  893. }
  894. void gatt_remove_manager(GDBusProxy *proxy)
  895. {
  896. managers = g_list_remove(managers, proxy);
  897. }
  898. static int match_proxy(const void *a, const void *b)
  899. {
  900. GDBusProxy *proxy1 = (void *) a;
  901. GDBusProxy *proxy2 = (void *) b;
  902. return strcmp(g_dbus_proxy_get_path(proxy1),
  903. g_dbus_proxy_get_path(proxy2));
  904. }
  905. static DBusMessage *release_profile(DBusConnection *conn,
  906. DBusMessage *msg, void *user_data)
  907. {
  908. g_dbus_unregister_interface(conn, APP_PATH, PROFILE_INTERFACE);
  909. return dbus_message_new_method_return(msg);
  910. }
  911. static const GDBusMethodTable methods[] = {
  912. { GDBUS_METHOD("Release", NULL, NULL, release_profile) },
  913. { }
  914. };
  915. static gboolean get_uuids(const GDBusPropertyTable *property,
  916. DBusMessageIter *iter, void *data)
  917. {
  918. DBusMessageIter entry;
  919. GList *uuid;
  920. dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
  921. DBUS_TYPE_STRING_AS_STRING, &entry);
  922. for (uuid = uuids; uuid; uuid = g_list_next(uuid->next))
  923. dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING,
  924. &uuid->data);
  925. dbus_message_iter_close_container(iter, &entry);
  926. return TRUE;
  927. }
  928. static const GDBusPropertyTable properties[] = {
  929. { "UUIDs", "as", get_uuids },
  930. { }
  931. };
  932. void gatt_register_app(DBusConnection *conn, GDBusProxy *proxy,
  933. int argc, char *argv[])
  934. {
  935. GList *l;
  936. int i;
  937. l = g_list_find_custom(managers, proxy, match_proxy);
  938. if (!l) {
  939. bt_shell_printf("Unable to find GattManager proxy\n");
  940. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  941. }
  942. for (i = 0; i < argc; i++)
  943. uuids = g_list_append(uuids, g_strdup(argv[i]));
  944. if (uuids) {
  945. if (g_dbus_register_interface(conn, APP_PATH,
  946. PROFILE_INTERFACE, methods,
  947. NULL, properties, NULL,
  948. NULL) == FALSE) {
  949. bt_shell_printf("Failed to register application"
  950. " object\n");
  951. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  952. }
  953. }
  954. if (g_dbus_proxy_method_call(l->data, "RegisterApplication",
  955. register_app_setup,
  956. register_app_reply, NULL,
  957. NULL) == FALSE) {
  958. bt_shell_printf("Failed register application\n");
  959. g_dbus_unregister_interface(conn, APP_PATH, PROFILE_INTERFACE);
  960. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  961. }
  962. }
  963. static void unregister_app_reply(DBusMessage *message, void *user_data)
  964. {
  965. DBusConnection *conn = user_data;
  966. DBusError error;
  967. dbus_error_init(&error);
  968. if (dbus_set_error_from_message(&error, message) == TRUE) {
  969. bt_shell_printf("Failed to unregister application: %s\n",
  970. error.name);
  971. dbus_error_free(&error);
  972. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  973. }
  974. bt_shell_printf("Application unregistered\n");
  975. if (!uuids)
  976. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  977. g_list_free_full(uuids, g_free);
  978. uuids = NULL;
  979. g_dbus_unregister_interface(conn, APP_PATH, PROFILE_INTERFACE);
  980. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  981. }
  982. static void unregister_app_setup(DBusMessageIter *iter, void *user_data)
  983. {
  984. const char *path = "/";
  985. dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
  986. }
  987. void gatt_unregister_app(DBusConnection *conn, GDBusProxy *proxy)
  988. {
  989. GList *l;
  990. l = g_list_find_custom(managers, proxy, match_proxy);
  991. if (!l) {
  992. bt_shell_printf("Unable to find GattManager proxy\n");
  993. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  994. }
  995. if (g_dbus_proxy_method_call(l->data, "UnregisterApplication",
  996. unregister_app_setup,
  997. unregister_app_reply, conn,
  998. NULL) == FALSE) {
  999. bt_shell_printf("Failed unregister profile\n");
  1000. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  1001. }
  1002. }
  1003. static void desc_free(void *data)
  1004. {
  1005. struct desc *desc = data;
  1006. g_free(desc->path);
  1007. g_free(desc->uuid);
  1008. g_strfreev(desc->flags);
  1009. g_free(desc->value);
  1010. g_free(desc);
  1011. }
  1012. static void desc_unregister(void *data)
  1013. {
  1014. struct desc *desc = data;
  1015. print_desc(desc, COLORED_DEL);
  1016. g_dbus_unregister_interface(desc->chrc->service->conn, desc->path,
  1017. DESC_INTERFACE);
  1018. }
  1019. static void chrc_free(void *data)
  1020. {
  1021. struct chrc *chrc = data;
  1022. g_list_free_full(chrc->descs, desc_unregister);
  1023. g_free(chrc->path);
  1024. g_free(chrc->uuid);
  1025. g_strfreev(chrc->flags);
  1026. g_free(chrc->value);
  1027. g_free(chrc);
  1028. }
  1029. static void chrc_unregister(void *data)
  1030. {
  1031. struct chrc *chrc = data;
  1032. print_chrc(chrc, COLORED_DEL);
  1033. g_dbus_unregister_interface(chrc->service->conn, chrc->path,
  1034. CHRC_INTERFACE);
  1035. }
  1036. static void inc_unregister(void *data)
  1037. {
  1038. char *path = data;
  1039. g_free(path);
  1040. }
  1041. static void service_free(void *data)
  1042. {
  1043. struct service *service = data;
  1044. g_list_free_full(service->chrcs, chrc_unregister);
  1045. g_list_free_full(service->inc, inc_unregister);
  1046. g_free(service->path);
  1047. g_free(service->uuid);
  1048. g_free(service);
  1049. }
  1050. static gboolean service_get_handle(const GDBusPropertyTable *property,
  1051. DBusMessageIter *iter, void *data)
  1052. {
  1053. struct service *service = data;
  1054. dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16,
  1055. &service->handle);
  1056. return TRUE;
  1057. }
  1058. static void service_set_handle(const GDBusPropertyTable *property,
  1059. DBusMessageIter *value, GDBusPendingPropertySet id,
  1060. void *data)
  1061. {
  1062. struct service *service = data;
  1063. if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_UINT16) {
  1064. g_dbus_pending_property_error(id, "org.bluez.InvalidArguments",
  1065. "Invalid arguments in method call");
  1066. return;
  1067. }
  1068. dbus_message_iter_get_basic(value, &service->handle);
  1069. print_service(service, COLORED_CHG);
  1070. g_dbus_pending_property_success(id);
  1071. }
  1072. static gboolean service_get_uuid(const GDBusPropertyTable *property,
  1073. DBusMessageIter *iter, void *data)
  1074. {
  1075. struct service *service = data;
  1076. dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &service->uuid);
  1077. return TRUE;
  1078. }
  1079. static gboolean service_get_primary(const GDBusPropertyTable *property,
  1080. DBusMessageIter *iter, void *data)
  1081. {
  1082. struct service *service = data;
  1083. dbus_bool_t primary;
  1084. primary = service->primary ? TRUE : FALSE;
  1085. dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &primary);
  1086. return TRUE;
  1087. }
  1088. static gboolean service_get_includes(const GDBusPropertyTable *property,
  1089. DBusMessageIter *iter, void *data)
  1090. {
  1091. DBusMessageIter array;
  1092. struct service *service = data;
  1093. char *inc = NULL;
  1094. GList *l;
  1095. if (service->inc) {
  1096. for (l = service->inc ; l; l = g_list_next(l)) {
  1097. inc = l->data;
  1098. dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
  1099. DBUS_TYPE_OBJECT_PATH_AS_STRING, &array);
  1100. dbus_message_iter_append_basic(&array,
  1101. DBUS_TYPE_OBJECT_PATH, &inc);
  1102. }
  1103. dbus_message_iter_close_container(iter, &array);
  1104. return TRUE;
  1105. }
  1106. return FALSE;
  1107. }
  1108. static gboolean service_exist_includes(const GDBusPropertyTable *property,
  1109. void *data)
  1110. {
  1111. struct service *service = data;
  1112. if (service->inc)
  1113. return TRUE;
  1114. else
  1115. return FALSE;
  1116. }
  1117. static const GDBusPropertyTable service_properties[] = {
  1118. { "Handle", "q", service_get_handle, service_set_handle },
  1119. { "UUID", "s", service_get_uuid },
  1120. { "Primary", "b", service_get_primary },
  1121. { "Includes", "ao", service_get_includes,
  1122. NULL, service_exist_includes },
  1123. { }
  1124. };
  1125. static void service_set_primary(const char *input, void *user_data)
  1126. {
  1127. struct service *service = user_data;
  1128. if (!strcmp(input, "yes"))
  1129. service->primary = true;
  1130. else if (!strcmp(input, "no")) {
  1131. service->primary = false;
  1132. } else {
  1133. bt_shell_printf("Invalid option: %s\n", input);
  1134. local_services = g_list_remove(local_services, service);
  1135. print_service(service, COLORED_DEL);
  1136. g_dbus_unregister_interface(service->conn, service->path,
  1137. SERVICE_INTERFACE);
  1138. }
  1139. }
  1140. void gatt_register_service(DBusConnection *conn, GDBusProxy *proxy,
  1141. int argc, char *argv[])
  1142. {
  1143. struct service *service;
  1144. bool primary = true;
  1145. service = g_new0(struct service, 1);
  1146. service->conn = conn;
  1147. service->uuid = g_strdup(argv[1]);
  1148. service->path = g_strdup_printf("%s/service%u", APP_PATH,
  1149. g_list_length(local_services));
  1150. service->primary = primary;
  1151. if (argc > 2)
  1152. service->handle = atoi(argv[2]);
  1153. if (g_dbus_register_interface(conn, service->path,
  1154. SERVICE_INTERFACE, NULL, NULL,
  1155. service_properties, service,
  1156. service_free) == FALSE) {
  1157. bt_shell_printf("Failed to register service object\n");
  1158. service_free(service);
  1159. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  1160. }
  1161. print_service(service, COLORED_NEW);
  1162. local_services = g_list_append(local_services, service);
  1163. bt_shell_prompt_input(service->path, "Primary (yes/no):",
  1164. service_set_primary, service);
  1165. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  1166. }
  1167. static struct service *service_find(const char *pattern)
  1168. {
  1169. GList *l;
  1170. for (l = local_services; l; l = g_list_next(l)) {
  1171. struct service *service = l->data;
  1172. /* match object path */
  1173. if (!strcmp(service->path, pattern))
  1174. return service;
  1175. /* match UUID */
  1176. if (!strcmp(service->uuid, pattern))
  1177. return service;
  1178. }
  1179. return NULL;
  1180. }
  1181. void gatt_unregister_service(DBusConnection *conn, GDBusProxy *proxy,
  1182. int argc, char *argv[])
  1183. {
  1184. struct service *service;
  1185. service = service_find(argv[1]);
  1186. if (!service) {
  1187. bt_shell_printf("Failed to unregister service object\n");
  1188. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  1189. }
  1190. local_services = g_list_remove(local_services, service);
  1191. print_service(service, COLORED_DEL);
  1192. g_dbus_unregister_interface(service->conn, service->path,
  1193. SERVICE_INTERFACE);
  1194. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  1195. }
  1196. static char *inc_find(struct service *serv, char *path)
  1197. {
  1198. GList *lc;
  1199. for (lc = serv->inc; lc; lc = g_list_next(lc)) {
  1200. char *incp = lc->data;
  1201. /* match object path */
  1202. if (!strcmp(incp, path))
  1203. return incp;
  1204. }
  1205. return NULL;
  1206. }
  1207. void gatt_register_include(DBusConnection *conn, GDBusProxy *proxy,
  1208. int argc, char *argv[])
  1209. {
  1210. struct service *service, *inc_service;
  1211. char *inc_path;
  1212. if (!local_services) {
  1213. bt_shell_printf("No service registered\n");
  1214. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  1215. }
  1216. service = g_list_last(local_services)->data;
  1217. inc_service = service_find(argv[1]);
  1218. if (!inc_service) {
  1219. bt_shell_printf("Failed to find service object\n");
  1220. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  1221. }
  1222. inc_path = g_strdup(service->path);
  1223. inc_service->inc = g_list_append(inc_service->inc, inc_path);
  1224. print_service(inc_service, COLORED_NEW);
  1225. print_inc_service(service, COLORED_NEW);
  1226. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  1227. }
  1228. void gatt_unregister_include(DBusConnection *conn, GDBusProxy *proxy,
  1229. int argc, char *argv[])
  1230. {
  1231. struct service *ser_inc, *service;
  1232. char *path = NULL;
  1233. service = service_find(argv[1]);
  1234. if (!service) {
  1235. bt_shell_printf("Failed to unregister include service"
  1236. " object\n");
  1237. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  1238. }
  1239. ser_inc = service_find(argv[2]);
  1240. if (!ser_inc) {
  1241. bt_shell_printf("Failed to find include service object\n");
  1242. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  1243. }
  1244. path = inc_find(service, ser_inc->path);
  1245. if (path) {
  1246. service->inc = g_list_remove(service->inc, path);
  1247. inc_unregister(path);
  1248. }
  1249. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  1250. }
  1251. static gboolean chrc_get_handle(const GDBusPropertyTable *property,
  1252. DBusMessageIter *iter, void *data)
  1253. {
  1254. struct chrc *chrc = data;
  1255. dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &chrc->handle);
  1256. return TRUE;
  1257. }
  1258. static void chrc_set_handle(const GDBusPropertyTable *property,
  1259. DBusMessageIter *value, GDBusPendingPropertySet id,
  1260. void *data)
  1261. {
  1262. struct chrc *chrc = data;
  1263. if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_UINT16) {
  1264. g_dbus_pending_property_error(id, "org.bluez.InvalidArguments",
  1265. "Invalid arguments in method call");
  1266. return;
  1267. }
  1268. dbus_message_iter_get_basic(value, &chrc->handle);
  1269. print_chrc(chrc, COLORED_CHG);
  1270. g_dbus_pending_property_success(id);
  1271. }
  1272. static gboolean chrc_get_uuid(const GDBusPropertyTable *property,
  1273. DBusMessageIter *iter, void *data)
  1274. {
  1275. struct chrc *chrc = data;
  1276. dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &chrc->uuid);
  1277. return TRUE;
  1278. }
  1279. static gboolean chrc_get_service(const GDBusPropertyTable *property,
  1280. DBusMessageIter *iter, void *data)
  1281. {
  1282. struct chrc *chrc = data;
  1283. dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
  1284. &chrc->service->path);
  1285. return TRUE;
  1286. }
  1287. static gboolean chrc_get_value(const GDBusPropertyTable *property,
  1288. DBusMessageIter *iter, void *data)
  1289. {
  1290. struct chrc *chrc = data;
  1291. DBusMessageIter array;
  1292. dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array);
  1293. dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
  1294. &chrc->value, chrc->value_len);
  1295. dbus_message_iter_close_container(iter, &array);
  1296. return TRUE;
  1297. }
  1298. static gboolean chrc_get_notifying(const GDBusPropertyTable *property,
  1299. DBusMessageIter *iter, void *data)
  1300. {
  1301. struct chrc *chrc = data;
  1302. dbus_bool_t value;
  1303. value = chrc->notifying ? TRUE : FALSE;
  1304. dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
  1305. return TRUE;
  1306. }
  1307. static gboolean chrc_get_flags(const GDBusPropertyTable *property,
  1308. DBusMessageIter *iter, void *data)
  1309. {
  1310. struct chrc *chrc = data;
  1311. int i;
  1312. DBusMessageIter array;
  1313. dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &array);
  1314. for (i = 0; chrc->flags[i]; i++)
  1315. dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING,
  1316. &chrc->flags[i]);
  1317. dbus_message_iter_close_container(iter, &array);
  1318. return TRUE;
  1319. }
  1320. static gboolean chrc_get_write_acquired(const GDBusPropertyTable *property,
  1321. DBusMessageIter *iter, void *data)
  1322. {
  1323. struct chrc *chrc = data;
  1324. dbus_bool_t value;
  1325. value = chrc->write_io ? TRUE : FALSE;
  1326. dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
  1327. return TRUE;
  1328. }
  1329. static gboolean chrc_write_acquired_exists(const GDBusPropertyTable *property,
  1330. void *data)
  1331. {
  1332. struct chrc *chrc = data;
  1333. int i;
  1334. if (chrc->proxy)
  1335. return FALSE;
  1336. for (i = 0; chrc->flags[i]; i++) {
  1337. if (!strcmp("write-without-response", chrc->flags[i]))
  1338. return TRUE;
  1339. }
  1340. return FALSE;
  1341. }
  1342. static gboolean chrc_get_notify_acquired(const GDBusPropertyTable *property,
  1343. DBusMessageIter *iter, void *data)
  1344. {
  1345. struct chrc *chrc = data;
  1346. dbus_bool_t value;
  1347. value = chrc->notify_io ? TRUE : FALSE;
  1348. dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
  1349. return TRUE;
  1350. }
  1351. static gboolean chrc_notify_acquired_exists(const GDBusPropertyTable *property,
  1352. void *data)
  1353. {
  1354. struct chrc *chrc = data;
  1355. int i;
  1356. if (chrc->proxy)
  1357. return FALSE;
  1358. for (i = 0; chrc->flags[i]; i++) {
  1359. if (!strcmp("notify", chrc->flags[i]))
  1360. return TRUE;
  1361. }
  1362. return FALSE;
  1363. }
  1364. static const GDBusPropertyTable chrc_properties[] = {
  1365. { "Handle", "q", chrc_get_handle, chrc_set_handle, NULL },
  1366. { "UUID", "s", chrc_get_uuid, NULL, NULL },
  1367. { "Service", "o", chrc_get_service, NULL, NULL },
  1368. { "Value", "ay", chrc_get_value, NULL, NULL },
  1369. { "Notifying", "b", chrc_get_notifying, NULL, NULL },
  1370. { "Flags", "as", chrc_get_flags, NULL, NULL },
  1371. { "WriteAcquired", "b", chrc_get_write_acquired, NULL,
  1372. chrc_write_acquired_exists },
  1373. { "NotifyAcquired", "b", chrc_get_notify_acquired, NULL,
  1374. chrc_notify_acquired_exists },
  1375. { }
  1376. };
  1377. static const char *path_to_address(const char *path)
  1378. {
  1379. GDBusProxy *proxy;
  1380. DBusMessageIter iter;
  1381. const char *address = path;
  1382. proxy = bt_shell_get_env(path);
  1383. if (g_dbus_proxy_get_property(proxy, "Address", &iter))
  1384. dbus_message_iter_get_basic(&iter, &address);
  1385. return address;
  1386. }
  1387. static int parse_options(DBusMessageIter *iter, uint16_t *offset, uint16_t *mtu,
  1388. char **device, char **link,
  1389. bool *prep_authorize)
  1390. {
  1391. DBusMessageIter dict;
  1392. if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
  1393. return -EINVAL;
  1394. dbus_message_iter_recurse(iter, &dict);
  1395. while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
  1396. const char *key;
  1397. DBusMessageIter value, entry;
  1398. int var;
  1399. dbus_message_iter_recurse(&dict, &entry);
  1400. dbus_message_iter_get_basic(&entry, &key);
  1401. dbus_message_iter_next(&entry);
  1402. dbus_message_iter_recurse(&entry, &value);
  1403. var = dbus_message_iter_get_arg_type(&value);
  1404. if (strcasecmp(key, "offset") == 0) {
  1405. if (var != DBUS_TYPE_UINT16)
  1406. return -EINVAL;
  1407. if (offset)
  1408. dbus_message_iter_get_basic(&value, offset);
  1409. } else if (strcasecmp(key, "MTU") == 0) {
  1410. if (var != DBUS_TYPE_UINT16)
  1411. return -EINVAL;
  1412. if (mtu)
  1413. dbus_message_iter_get_basic(&value, mtu);
  1414. } else if (strcasecmp(key, "device") == 0) {
  1415. if (var != DBUS_TYPE_OBJECT_PATH)
  1416. return -EINVAL;
  1417. if (device)
  1418. dbus_message_iter_get_basic(&value, device);
  1419. } else if (strcasecmp(key, "link") == 0) {
  1420. if (var != DBUS_TYPE_STRING)
  1421. return -EINVAL;
  1422. if (link)
  1423. dbus_message_iter_get_basic(&value, link);
  1424. } else if (strcasecmp(key, "prepare-authorize") == 0) {
  1425. if (var != DBUS_TYPE_BOOLEAN)
  1426. return -EINVAL;
  1427. if (prep_authorize) {
  1428. int tmp;
  1429. dbus_message_iter_get_basic(&value, &tmp);
  1430. *prep_authorize = !!tmp;
  1431. }
  1432. }
  1433. dbus_message_iter_next(&dict);
  1434. }
  1435. return 0;
  1436. }
  1437. static DBusMessage *read_value(DBusMessage *msg, uint8_t *value,
  1438. uint16_t value_len)
  1439. {
  1440. DBusMessage *reply;
  1441. DBusMessageIter iter, array;
  1442. reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
  1443. dbus_message_iter_init_append(reply, &iter);
  1444. dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "y", &array);
  1445. dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
  1446. &value, value_len);
  1447. dbus_message_iter_close_container(&iter, &array);
  1448. return reply;
  1449. }
  1450. struct authorize_attribute_data {
  1451. DBusConnection *conn;
  1452. void *attribute;
  1453. uint16_t offset;
  1454. };
  1455. static void authorize_read_response(const char *input, void *user_data)
  1456. {
  1457. struct authorize_attribute_data *aad = user_data;
  1458. struct chrc *chrc = aad->attribute;
  1459. DBusMessage *reply;
  1460. char *err;
  1461. if (!strcmp(input, "no")) {
  1462. err = "org.bluez.Error.NotAuthorized";
  1463. goto error;
  1464. }
  1465. if (aad->offset > chrc->value_len) {
  1466. err = "org.bluez.Error.InvalidOffset";
  1467. goto error;
  1468. }
  1469. reply = read_value(pending_message, &chrc->value[aad->offset],
  1470. chrc->value_len - aad->offset);
  1471. g_dbus_send_message(aad->conn, reply);
  1472. g_free(aad);
  1473. return;
  1474. error:
  1475. g_dbus_send_error(aad->conn, pending_message, err, NULL);
  1476. g_free(aad);
  1477. }
  1478. static bool is_device_trusted(const char *path)
  1479. {
  1480. GDBusProxy *proxy;
  1481. DBusMessageIter iter;
  1482. bool trusted = false;
  1483. proxy = bt_shell_get_env(path);
  1484. if (g_dbus_proxy_get_property(proxy, "Trusted", &iter))
  1485. dbus_message_iter_get_basic(&iter, &trusted);
  1486. return trusted;
  1487. }
  1488. struct read_attribute_data {
  1489. DBusMessage *msg;
  1490. uint16_t offset;
  1491. };
  1492. static void proxy_read_reply(DBusMessage *message, void *user_data)
  1493. {
  1494. struct read_attribute_data *data = user_data;
  1495. DBusConnection *conn = bt_shell_get_env("DBUS_CONNECTION");
  1496. DBusError error;
  1497. DBusMessageIter iter, array;
  1498. DBusMessage *reply;
  1499. uint8_t *value;
  1500. int len;
  1501. dbus_error_init(&error);
  1502. if (dbus_set_error_from_message(&error, message) == TRUE) {
  1503. bt_shell_printf("Failed to read: %s\n", error.name);
  1504. dbus_error_free(&error);
  1505. g_dbus_send_error(conn, data->msg, error.name, "%s",
  1506. error.message);
  1507. goto done;
  1508. }
  1509. dbus_message_iter_init(message, &iter);
  1510. if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
  1511. bt_shell_printf("Invalid response to read\n");
  1512. g_dbus_send_error(conn, data->msg,
  1513. "org.bluez.Error.InvalidArguments", NULL);
  1514. goto done;
  1515. }
  1516. dbus_message_iter_recurse(&iter, &array);
  1517. dbus_message_iter_get_fixed_array(&array, &value, &len);
  1518. if (len < 0) {
  1519. bt_shell_printf("Unable to parse value\n");
  1520. g_dbus_send_error(conn, data->msg,
  1521. "org.bluez.Error.InvalidArguments", NULL);
  1522. }
  1523. reply = read_value(data->msg, value, len);
  1524. g_dbus_send_message(conn, reply);
  1525. done:
  1526. dbus_message_unref(data->msg);
  1527. free(data);
  1528. }
  1529. static void proxy_read_setup(DBusMessageIter *iter, void *user_data)
  1530. {
  1531. DBusMessageIter dict;
  1532. struct read_attribute_data *data = user_data;
  1533. dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
  1534. DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
  1535. DBUS_TYPE_STRING_AS_STRING
  1536. DBUS_TYPE_VARIANT_AS_STRING
  1537. DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
  1538. &dict);
  1539. g_dbus_dict_append_entry(&dict, "offset", DBUS_TYPE_UINT16,
  1540. &data->offset);
  1541. dbus_message_iter_close_container(iter, &dict);
  1542. }
  1543. static DBusMessage *proxy_read_value(struct GDBusProxy *proxy, DBusMessage *msg,
  1544. uint16_t offset)
  1545. {
  1546. struct read_attribute_data *data;
  1547. data = new0(struct read_attribute_data, 1);
  1548. data->msg = dbus_message_ref(msg);
  1549. data->offset = offset;
  1550. if (g_dbus_proxy_method_call(proxy, "ReadValue", proxy_read_setup,
  1551. proxy_read_reply, data, NULL))
  1552. return NULL;
  1553. bt_shell_printf("Failed to read\n");
  1554. return g_dbus_create_error(msg, "org.bluez.Error.InvalidArguments",
  1555. NULL);
  1556. }
  1557. static DBusMessage *chrc_read_value(DBusConnection *conn, DBusMessage *msg,
  1558. void *user_data)
  1559. {
  1560. struct chrc *chrc = user_data;
  1561. DBusMessageIter iter;
  1562. uint16_t offset = 0;
  1563. char *device, *link;
  1564. char *str;
  1565. dbus_message_iter_init(msg, &iter);
  1566. if (parse_options(&iter, &offset, NULL, &device, &link, NULL))
  1567. return g_dbus_create_error(msg,
  1568. "org.bluez.Error.InvalidArguments",
  1569. NULL);
  1570. bt_shell_printf("[%s (%s)] ReadValue: %s offset %u link %s\n",
  1571. chrc->path, bt_uuidstr_to_str(chrc->uuid),
  1572. path_to_address(device), offset, link);
  1573. if (chrc->proxy) {
  1574. return proxy_read_value(chrc->proxy, msg, offset);
  1575. }
  1576. if (!is_device_trusted(device) && chrc->authorization_req) {
  1577. struct authorize_attribute_data *aad;
  1578. aad = g_new0(struct authorize_attribute_data, 1);
  1579. aad->conn = conn;
  1580. aad->attribute = chrc;
  1581. aad->offset = offset;
  1582. str = g_strdup_printf("Authorize attribute(%s) read (yes/no):",
  1583. chrc->path);
  1584. bt_shell_prompt_input("gatt", str, authorize_read_response,
  1585. aad);
  1586. g_free(str);
  1587. pending_message = dbus_message_ref(msg);
  1588. return NULL;
  1589. }
  1590. if (offset > chrc->value_len)
  1591. return g_dbus_create_error(msg, "org.bluez.Error.InvalidOffset",
  1592. NULL);
  1593. return read_value(msg, &chrc->value[offset], chrc->value_len - offset);
  1594. }
  1595. static int parse_value_arg(DBusMessageIter *iter, uint8_t **value, int *len)
  1596. {
  1597. DBusMessageIter array;
  1598. if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
  1599. return -EINVAL;
  1600. dbus_message_iter_recurse(iter, &array);
  1601. dbus_message_iter_get_fixed_array(&array, value, len);
  1602. return 0;
  1603. }
  1604. static int write_value(size_t *dst_len, uint8_t **dst_value, uint8_t *src_val,
  1605. size_t src_len, uint16_t offset, uint16_t max_len)
  1606. {
  1607. if ((offset + src_len) > max_len)
  1608. return -EOVERFLOW;
  1609. if ((offset + src_len) != *dst_len) {
  1610. *dst_len = offset + src_len;
  1611. *dst_value = g_realloc(*dst_value, *dst_len);
  1612. }
  1613. memcpy(*dst_value + offset, src_val, src_len);
  1614. return 0;
  1615. }
  1616. static void authorize_write_response(const char *input, void *user_data)
  1617. {
  1618. struct authorize_attribute_data *aad = user_data;
  1619. struct chrc *chrc = aad->attribute;
  1620. bool prep_authorize = false;
  1621. DBusMessageIter iter;
  1622. DBusMessage *reply;
  1623. int value_len;
  1624. uint8_t *value;
  1625. char *err;
  1626. dbus_message_iter_init(pending_message, &iter);
  1627. if (parse_value_arg(&iter, &value, &value_len)) {
  1628. err = "org.bluez.Error.InvalidArguments";
  1629. goto error;
  1630. }
  1631. dbus_message_iter_next(&iter);
  1632. if (parse_options(&iter, NULL, NULL, NULL, NULL, &prep_authorize)) {
  1633. err = "org.bluez.Error.InvalidArguments";
  1634. goto error;
  1635. }
  1636. if (!strcmp(input, "no")) {
  1637. err = "org.bluez.Error.NotAuthorized";
  1638. goto error;
  1639. }
  1640. if (aad->offset > chrc->value_len) {
  1641. err = "org.bluez.Error.InvalidOffset";
  1642. goto error;
  1643. }
  1644. /* Authorization check of prepare writes */
  1645. if (prep_authorize) {
  1646. reply = g_dbus_create_reply(pending_message, DBUS_TYPE_INVALID);
  1647. g_dbus_send_message(aad->conn, reply);
  1648. g_free(aad);
  1649. return;
  1650. }
  1651. if (write_value(&chrc->value_len, &chrc->value, value, value_len,
  1652. aad->offset, chrc->max_val_len)) {
  1653. err = "org.bluez.Error.InvalidValueLength";
  1654. goto error;
  1655. }
  1656. bt_shell_printf("[" COLORED_CHG "] Attribute %s (%s) written",
  1657. chrc->path, bt_uuidstr_to_str(chrc->uuid));
  1658. g_dbus_emit_property_changed(aad->conn, chrc->path, CHRC_INTERFACE,
  1659. "Value");
  1660. reply = g_dbus_create_reply(pending_message, DBUS_TYPE_INVALID);
  1661. g_dbus_send_message(aad->conn, reply);
  1662. g_free(aad);
  1663. return;
  1664. error:
  1665. g_dbus_send_error(aad->conn, pending_message, err, NULL);
  1666. g_free(aad);
  1667. }
  1668. static void proxy_write_reply(DBusMessage *message, void *user_data)
  1669. {
  1670. struct write_attribute_data *data = user_data;
  1671. DBusConnection *conn = bt_shell_get_env("DBUS_CONNECTION");
  1672. DBusError error;
  1673. dbus_error_init(&error);
  1674. if (dbus_set_error_from_message(&error, message)) {
  1675. bt_shell_printf("Failed to write: %s\n", error.name);
  1676. g_dbus_send_error(conn, data->msg, error.name, "%s",
  1677. error.message);
  1678. } else
  1679. g_dbus_send_reply(conn, data->msg, DBUS_TYPE_INVALID);
  1680. dbus_message_unref(data->msg);
  1681. free(data);
  1682. }
  1683. static DBusMessage *proxy_write_value(struct GDBusProxy *proxy,
  1684. DBusMessage *msg, uint8_t *value,
  1685. int value_len, uint16_t offset)
  1686. {
  1687. struct write_attribute_data *data;
  1688. data = new0(struct write_attribute_data, 1);
  1689. data->msg = dbus_message_ref(msg);
  1690. data->iov.iov_base = (void *) value;
  1691. data->iov.iov_len = value_len;
  1692. data->offset = offset;
  1693. if (g_dbus_proxy_method_call(proxy, "WriteValue", write_setup,
  1694. proxy_write_reply, data, NULL))
  1695. return NULL;
  1696. bt_shell_printf("Failed to write\n");
  1697. return g_dbus_create_error(msg, "org.bluez.Error.InvalidArguments",
  1698. NULL);
  1699. }
  1700. static DBusMessage *chrc_write_value(DBusConnection *conn, DBusMessage *msg,
  1701. void *user_data)
  1702. {
  1703. struct chrc *chrc = user_data;
  1704. uint16_t offset = 0;
  1705. bool prep_authorize = false;
  1706. char *device = NULL, *link = NULL;
  1707. DBusMessageIter iter;
  1708. int value_len;
  1709. uint8_t *value;
  1710. char *str;
  1711. dbus_message_iter_init(msg, &iter);
  1712. if (parse_value_arg(&iter, &value, &value_len))
  1713. return g_dbus_create_error(msg,
  1714. "org.bluez.Error.InvalidArguments", NULL);
  1715. dbus_message_iter_next(&iter);
  1716. if (parse_options(&iter, &offset, NULL, &device, &link,
  1717. &prep_authorize))
  1718. return g_dbus_create_error(msg,
  1719. "org.bluez.Error.InvalidArguments", NULL);
  1720. bt_shell_printf("[%s (%s)] WriteValue: %s offset %u link %s\n",
  1721. chrc->path, bt_uuidstr_to_str(chrc->uuid),
  1722. path_to_address(device), offset, link);
  1723. bt_shell_hexdump(value, value_len);
  1724. if (chrc->proxy)
  1725. return proxy_write_value(chrc->proxy, msg, value, value_len,
  1726. offset);
  1727. if (!is_device_trusted(device) && chrc->authorization_req) {
  1728. struct authorize_attribute_data *aad;
  1729. aad = g_new0(struct authorize_attribute_data, 1);
  1730. aad->conn = conn;
  1731. aad->attribute = chrc;
  1732. aad->offset = offset;
  1733. str = g_strdup_printf("Authorize attribute(%s) write (yes/no):",
  1734. chrc->path);
  1735. bt_shell_prompt_input("gatt", str, authorize_write_response,
  1736. aad);
  1737. g_free(str);
  1738. pending_message = dbus_message_ref(msg);
  1739. return NULL;
  1740. }
  1741. if (offset > chrc->value_len)
  1742. return g_dbus_create_error(msg,
  1743. "org.bluez.Error.InvalidOffset", NULL);
  1744. /* Authorization check of prepare writes */
  1745. if (prep_authorize)
  1746. return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
  1747. if (write_value(&chrc->value_len, &chrc->value, value, value_len,
  1748. offset, chrc->max_val_len))
  1749. return g_dbus_create_error(msg,
  1750. "org.bluez.Error.InvalidValueLength", NULL);
  1751. bt_shell_printf("[" COLORED_CHG "] Attribute %s (%s) written",
  1752. chrc->path, bt_uuidstr_to_str(chrc->uuid));
  1753. g_dbus_emit_property_changed(conn, chrc->path, CHRC_INTERFACE, "Value");
  1754. return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
  1755. }
  1756. static DBusMessage *create_sock(struct chrc *chrc, DBusMessage *msg)
  1757. {
  1758. int fds[2];
  1759. struct io *io;
  1760. bool dir;
  1761. DBusMessage *reply;
  1762. if (socketpair(AF_LOCAL, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC,
  1763. 0, fds) < 0)
  1764. return g_dbus_create_error(msg, "org.bluez.Error.Failed", "%s",
  1765. strerror(errno));
  1766. dir = dbus_message_has_member(msg, "AcquireWrite");
  1767. io = sock_io_new(fds[!dir], chrc);
  1768. if (!io) {
  1769. close(fds[0]);
  1770. close(fds[1]);
  1771. return g_dbus_create_error(msg, "org.bluez.Error.Failed", "%s",
  1772. strerror(errno));
  1773. }
  1774. reply = g_dbus_create_reply(msg, DBUS_TYPE_UNIX_FD, &fds[dir],
  1775. DBUS_TYPE_UINT16, &chrc->mtu,
  1776. DBUS_TYPE_INVALID);
  1777. close(fds[dir]);
  1778. if (dir)
  1779. chrc->write_io = io;
  1780. else
  1781. chrc->notify_io = io;
  1782. bt_shell_printf("[" COLORED_CHG "] Attribute %s %s sock acquired\n",
  1783. chrc->path, dir ? "Write" : "Notify");
  1784. return reply;
  1785. }
  1786. static DBusMessage *chrc_acquire_write(DBusConnection *conn, DBusMessage *msg,
  1787. void *user_data)
  1788. {
  1789. struct chrc *chrc = user_data;
  1790. DBusMessageIter iter;
  1791. DBusMessage *reply;
  1792. char *device = NULL, *link= NULL;
  1793. dbus_message_iter_init(msg, &iter);
  1794. if (chrc->write_io)
  1795. return g_dbus_create_error(msg,
  1796. "org.bluez.Error.NotPermitted",
  1797. NULL);
  1798. if (parse_options(&iter, NULL, &chrc->mtu, &device, &link, NULL))
  1799. return g_dbus_create_error(msg,
  1800. "org.bluez.Error.InvalidArguments",
  1801. NULL);
  1802. bt_shell_printf("AcquireWrite: %s link %s\n", path_to_address(device),
  1803. link);
  1804. reply = create_sock(chrc, msg);
  1805. if (chrc->write_io)
  1806. g_dbus_emit_property_changed(conn, chrc->path, CHRC_INTERFACE,
  1807. "WriteAcquired");
  1808. return reply;
  1809. }
  1810. static DBusMessage *chrc_acquire_notify(DBusConnection *conn, DBusMessage *msg,
  1811. void *user_data)
  1812. {
  1813. struct chrc *chrc = user_data;
  1814. DBusMessageIter iter;
  1815. DBusMessage *reply;
  1816. char *device = NULL, *link = NULL;
  1817. dbus_message_iter_init(msg, &iter);
  1818. if (chrc->notify_io)
  1819. return g_dbus_create_error(msg,
  1820. "org.bluez.Error.NotPermitted",
  1821. NULL);
  1822. if (parse_options(&iter, NULL, &chrc->mtu, &device, &link, NULL))
  1823. return g_dbus_create_error(msg,
  1824. "org.bluez.Error.InvalidArguments",
  1825. NULL);
  1826. bt_shell_printf("AcquireNotify: %s link %s\n", path_to_address(device),
  1827. link);
  1828. reply = create_sock(chrc, msg);
  1829. if (chrc->notify_io)
  1830. g_dbus_emit_property_changed(conn, chrc->path, CHRC_INTERFACE,
  1831. "NotifyAcquired");
  1832. return reply;
  1833. }
  1834. struct notify_attribute_data {
  1835. struct chrc *chrc;
  1836. DBusMessage *msg;
  1837. bool enable;
  1838. };
  1839. static void proxy_notify_reply(DBusMessage *message, void *user_data)
  1840. {
  1841. struct notify_attribute_data *data = user_data;
  1842. DBusConnection *conn = bt_shell_get_env("DBUS_CONNECTION");
  1843. DBusError error;
  1844. dbus_error_init(&error);
  1845. if (dbus_set_error_from_message(&error, message) == TRUE) {
  1846. bt_shell_printf("Failed to %s: %s\n",
  1847. data->enable ? "StartNotify" : "StopNotify",
  1848. error.name);
  1849. dbus_error_free(&error);
  1850. g_dbus_send_error(conn, data->msg, error.name, "%s",
  1851. error.message);
  1852. goto done;
  1853. }
  1854. g_dbus_send_reply(conn, data->msg, DBUS_TYPE_INVALID);
  1855. data->chrc->notifying = data->enable;
  1856. bt_shell_printf("[" COLORED_CHG "] Attribute %s (%s) "
  1857. "notifications %s\n",
  1858. data->chrc->path,
  1859. bt_uuidstr_to_str(data->chrc->uuid),
  1860. data->enable ? "enabled" : "disabled");
  1861. g_dbus_emit_property_changed(conn, data->chrc->path, CHRC_INTERFACE,
  1862. "Notifying");
  1863. done:
  1864. dbus_message_unref(data->msg);
  1865. free(data);
  1866. }
  1867. static DBusMessage *proxy_notify(struct chrc *chrc, DBusMessage *msg,
  1868. bool enable)
  1869. {
  1870. struct notify_attribute_data *data;
  1871. const char *method;
  1872. if (enable == TRUE)
  1873. method = "StartNotify";
  1874. else
  1875. method = "StopNotify";
  1876. data = new0(struct notify_attribute_data, 1);
  1877. data->chrc = chrc;
  1878. data->msg = dbus_message_ref(msg);
  1879. data->enable = enable;
  1880. if (g_dbus_proxy_method_call(chrc->proxy, method, NULL,
  1881. proxy_notify_reply, data, NULL))
  1882. return NULL;
  1883. return g_dbus_create_error(msg, "org.bluez.Error.InvalidArguments",
  1884. NULL);
  1885. }
  1886. static DBusMessage *chrc_start_notify(DBusConnection *conn, DBusMessage *msg,
  1887. void *user_data)
  1888. {
  1889. struct chrc *chrc = user_data;
  1890. if (chrc->notifying)
  1891. return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
  1892. if (chrc->proxy)
  1893. return proxy_notify(chrc, msg, true);
  1894. chrc->notifying = true;
  1895. bt_shell_printf("[" COLORED_CHG "] Attribute %s (%s) notifications "
  1896. "enabled", chrc->path, bt_uuidstr_to_str(chrc->uuid));
  1897. g_dbus_emit_property_changed(conn, chrc->path, CHRC_INTERFACE,
  1898. "Notifying");
  1899. return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
  1900. }
  1901. static DBusMessage *chrc_stop_notify(DBusConnection *conn, DBusMessage *msg,
  1902. void *user_data)
  1903. {
  1904. struct chrc *chrc = user_data;
  1905. if (!chrc->notifying)
  1906. return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
  1907. if (chrc->proxy)
  1908. return proxy_notify(chrc, msg, false);
  1909. chrc->notifying = false;
  1910. bt_shell_printf("[" COLORED_CHG "] Attribute %s (%s) notifications "
  1911. "disabled", chrc->path, bt_uuidstr_to_str(chrc->uuid));
  1912. g_dbus_emit_property_changed(conn, chrc->path, CHRC_INTERFACE,
  1913. "Notifying");
  1914. return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
  1915. }
  1916. static DBusMessage *chrc_confirm(DBusConnection *conn, DBusMessage *msg,
  1917. void *user_data)
  1918. {
  1919. struct chrc *chrc = user_data;
  1920. bt_shell_printf("Attribute %s (%s) indication confirm received",
  1921. chrc->path, bt_uuidstr_to_str(chrc->uuid));
  1922. return dbus_message_new_method_return(msg);
  1923. }
  1924. static const GDBusMethodTable chrc_methods[] = {
  1925. { GDBUS_ASYNC_METHOD("ReadValue", GDBUS_ARGS({ "options", "a{sv}" }),
  1926. GDBUS_ARGS({ "value", "ay" }),
  1927. chrc_read_value) },
  1928. { GDBUS_ASYNC_METHOD("WriteValue", GDBUS_ARGS({ "value", "ay" },
  1929. { "options", "a{sv}" }),
  1930. NULL, chrc_write_value) },
  1931. { GDBUS_METHOD("AcquireWrite", GDBUS_ARGS({ "options", "a{sv}" }),
  1932. NULL, chrc_acquire_write) },
  1933. { GDBUS_METHOD("AcquireNotify", GDBUS_ARGS({ "options", "a{sv}" }),
  1934. NULL, chrc_acquire_notify) },
  1935. { GDBUS_ASYNC_METHOD("StartNotify", NULL, NULL, chrc_start_notify) },
  1936. { GDBUS_METHOD("StopNotify", NULL, NULL, chrc_stop_notify) },
  1937. { GDBUS_METHOD("Confirm", NULL, NULL, chrc_confirm) },
  1938. { }
  1939. };
  1940. static void chrc_set_value(const char *input, void *user_data)
  1941. {
  1942. struct chrc *chrc = user_data;
  1943. g_free(chrc->value);
  1944. chrc->value = str2bytearray((char *) input, &chrc->value_len);
  1945. if (!chrc->value) {
  1946. print_chrc(chrc, COLORED_DEL);
  1947. chrc_unregister(chrc);
  1948. }
  1949. chrc->max_val_len = chrc->value_len;
  1950. }
  1951. static gboolean attr_authorization_flag_exists(char **flags)
  1952. {
  1953. int i;
  1954. for (i = 0; flags[i]; i++) {
  1955. if (!strcmp("authorize", flags[i]))
  1956. return TRUE;
  1957. }
  1958. return FALSE;
  1959. }
  1960. void gatt_register_chrc(DBusConnection *conn, GDBusProxy *proxy,
  1961. int argc, char *argv[])
  1962. {
  1963. struct service *service;
  1964. struct chrc *chrc;
  1965. if (!local_services) {
  1966. bt_shell_printf("No service registered\n");
  1967. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  1968. }
  1969. service = g_list_last(local_services)->data;
  1970. chrc = g_new0(struct chrc, 1);
  1971. chrc->service = service;
  1972. chrc->uuid = g_strdup(argv[1]);
  1973. chrc->path = g_strdup_printf("%s/chrc%u", service->path,
  1974. g_list_length(service->chrcs));
  1975. chrc->flags = g_strsplit(argv[2], ",", -1);
  1976. chrc->authorization_req = attr_authorization_flag_exists(chrc->flags);
  1977. if (argc > 3)
  1978. chrc->handle = atoi(argv[3]);
  1979. if (g_dbus_register_interface(conn, chrc->path, CHRC_INTERFACE,
  1980. chrc_methods, NULL, chrc_properties,
  1981. chrc, chrc_free) == FALSE) {
  1982. bt_shell_printf("Failed to register characteristic object\n");
  1983. chrc_free(chrc);
  1984. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  1985. }
  1986. service->chrcs = g_list_append(service->chrcs, chrc);
  1987. print_chrc(chrc, COLORED_NEW);
  1988. bt_shell_prompt_input(chrc->path, "Enter value:", chrc_set_value, chrc);
  1989. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  1990. }
  1991. static struct chrc *chrc_find(const char *pattern)
  1992. {
  1993. GList *l, *lc;
  1994. struct service *service;
  1995. struct chrc *chrc;
  1996. for (l = local_services; l; l = g_list_next(l)) {
  1997. service = l->data;
  1998. for (lc = service->chrcs; lc; lc = g_list_next(lc)) {
  1999. chrc = lc->data;
  2000. /* match object path */
  2001. if (!strcmp(chrc->path, pattern))
  2002. return chrc;
  2003. /* match UUID */
  2004. if (!strcmp(chrc->uuid, pattern))
  2005. return chrc;
  2006. }
  2007. }
  2008. return NULL;
  2009. }
  2010. void gatt_unregister_chrc(DBusConnection *conn, GDBusProxy *proxy,
  2011. int argc, char *argv[])
  2012. {
  2013. struct chrc *chrc;
  2014. chrc = chrc_find(argv[1]);
  2015. if (!chrc) {
  2016. bt_shell_printf("Failed to unregister characteristic object\n");
  2017. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  2018. }
  2019. chrc->service->chrcs = g_list_remove(chrc->service->chrcs, chrc);
  2020. chrc_unregister(chrc);
  2021. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  2022. }
  2023. static DBusMessage *desc_read_value(DBusConnection *conn, DBusMessage *msg,
  2024. void *user_data)
  2025. {
  2026. struct desc *desc = user_data;
  2027. DBusMessageIter iter;
  2028. uint16_t offset = 0;
  2029. char *device = NULL, *link = NULL;
  2030. dbus_message_iter_init(msg, &iter);
  2031. if (parse_options(&iter, &offset, NULL, &device, &link, NULL))
  2032. return g_dbus_create_error(msg,
  2033. "org.bluez.Error.InvalidArguments",
  2034. NULL);
  2035. bt_shell_printf("[%s (%s)] ReadValue: %s offset %u link %s\n",
  2036. desc->path, bt_uuidstr_to_str(desc->uuid),
  2037. path_to_address(device), offset, link);
  2038. if (offset > desc->value_len)
  2039. return g_dbus_create_error(msg, "org.bluez.Error.InvalidOffset",
  2040. NULL);
  2041. return read_value(msg, &desc->value[offset], desc->value_len - offset);
  2042. }
  2043. static DBusMessage *desc_write_value(DBusConnection *conn, DBusMessage *msg,
  2044. void *user_data)
  2045. {
  2046. struct desc *desc = user_data;
  2047. DBusMessageIter iter;
  2048. uint16_t offset = 0;
  2049. char *device = NULL, *link = NULL;
  2050. int value_len;
  2051. uint8_t *value;
  2052. dbus_message_iter_init(msg, &iter);
  2053. if (parse_value_arg(&iter, &value, &value_len))
  2054. return g_dbus_create_error(msg,
  2055. "org.bluez.Error.InvalidArguments", NULL);
  2056. dbus_message_iter_next(&iter);
  2057. if (parse_options(&iter, &offset, NULL, &device, &link, NULL))
  2058. return g_dbus_create_error(msg,
  2059. "org.bluez.Error.InvalidArguments", NULL);
  2060. if (offset > desc->value_len)
  2061. return g_dbus_create_error(msg,
  2062. "org.bluez.Error.InvalidOffset", NULL);
  2063. if (write_value(&desc->value_len, &desc->value, value,
  2064. value_len, offset, desc->max_val_len))
  2065. return g_dbus_create_error(msg,
  2066. "org.bluez.Error.InvalidValueLength", NULL);
  2067. bt_shell_printf("[%s (%s)] WriteValue: %s offset %u link %s\n",
  2068. desc->path, bt_uuidstr_to_str(desc->uuid),
  2069. path_to_address(device), offset, link);
  2070. bt_shell_printf("[" COLORED_CHG "] Attribute %s (%s) written",
  2071. desc->path, bt_uuidstr_to_str(desc->uuid));
  2072. g_dbus_emit_property_changed(conn, desc->path, CHRC_INTERFACE, "Value");
  2073. return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
  2074. }
  2075. static const GDBusMethodTable desc_methods[] = {
  2076. { GDBUS_ASYNC_METHOD("ReadValue", GDBUS_ARGS({ "options", "a{sv}" }),
  2077. GDBUS_ARGS({ "value", "ay" }),
  2078. desc_read_value) },
  2079. { GDBUS_ASYNC_METHOD("WriteValue", GDBUS_ARGS({ "value", "ay" },
  2080. { "options", "a{sv}" }),
  2081. NULL, desc_write_value) },
  2082. { }
  2083. };
  2084. static gboolean desc_get_handle(const GDBusPropertyTable *property,
  2085. DBusMessageIter *iter, void *data)
  2086. {
  2087. struct desc *desc = data;
  2088. dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &desc->handle);
  2089. return TRUE;
  2090. }
  2091. static void desc_set_handle(const GDBusPropertyTable *property,
  2092. DBusMessageIter *value, GDBusPendingPropertySet id,
  2093. void *data)
  2094. {
  2095. struct desc *desc = data;
  2096. if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_UINT16) {
  2097. g_dbus_pending_property_error(id, "org.bluez.InvalidArguments",
  2098. "Invalid arguments in method call");
  2099. return;
  2100. }
  2101. dbus_message_iter_get_basic(value, &desc->handle);
  2102. print_desc(desc, COLORED_CHG);
  2103. g_dbus_pending_property_success(id);
  2104. }
  2105. static gboolean desc_get_uuid(const GDBusPropertyTable *property,
  2106. DBusMessageIter *iter, void *data)
  2107. {
  2108. struct desc *desc = data;
  2109. dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &desc->uuid);
  2110. return TRUE;
  2111. }
  2112. static gboolean desc_get_chrc(const GDBusPropertyTable *property,
  2113. DBusMessageIter *iter, void *data)
  2114. {
  2115. struct desc *desc = data;
  2116. dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
  2117. &desc->chrc->path);
  2118. return TRUE;
  2119. }
  2120. static gboolean desc_get_value(const GDBusPropertyTable *property,
  2121. DBusMessageIter *iter, void *data)
  2122. {
  2123. struct desc *desc = data;
  2124. DBusMessageIter array;
  2125. dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array);
  2126. if (desc->value)
  2127. dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
  2128. &desc->value,
  2129. desc->value_len);
  2130. dbus_message_iter_close_container(iter, &array);
  2131. return TRUE;
  2132. }
  2133. static gboolean desc_get_flags(const GDBusPropertyTable *property,
  2134. DBusMessageIter *iter, void *data)
  2135. {
  2136. struct desc *desc = data;
  2137. int i;
  2138. DBusMessageIter array;
  2139. dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &array);
  2140. for (i = 0; desc->flags[i]; i++)
  2141. dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING,
  2142. &desc->flags[i]);
  2143. dbus_message_iter_close_container(iter, &array);
  2144. return TRUE;
  2145. }
  2146. static const GDBusPropertyTable desc_properties[] = {
  2147. { "Handle", "q", desc_get_handle, desc_set_handle, NULL },
  2148. { "UUID", "s", desc_get_uuid, NULL, NULL },
  2149. { "Characteristic", "o", desc_get_chrc, NULL, NULL },
  2150. { "Value", "ay", desc_get_value, NULL, NULL },
  2151. { "Flags", "as", desc_get_flags, NULL, NULL },
  2152. { }
  2153. };
  2154. static void desc_set_value(const char *input, void *user_data)
  2155. {
  2156. struct desc *desc = user_data;
  2157. g_free(desc->value);
  2158. desc->value = str2bytearray((char *) input, &desc->value_len);
  2159. if (!desc->value) {
  2160. print_desc(desc, COLORED_DEL);
  2161. desc_unregister(desc);
  2162. }
  2163. desc->max_val_len = desc->value_len;
  2164. }
  2165. void gatt_register_desc(DBusConnection *conn, GDBusProxy *proxy,
  2166. int argc, char *argv[])
  2167. {
  2168. struct service *service;
  2169. struct desc *desc;
  2170. if (!local_services) {
  2171. bt_shell_printf("No service registered\n");
  2172. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  2173. }
  2174. service = g_list_last(local_services)->data;
  2175. if (!service->chrcs) {
  2176. bt_shell_printf("No characteristic registered\n");
  2177. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  2178. }
  2179. desc = g_new0(struct desc, 1);
  2180. desc->chrc = g_list_last(service->chrcs)->data;
  2181. desc->uuid = g_strdup(argv[1]);
  2182. desc->path = g_strdup_printf("%s/desc%u", desc->chrc->path,
  2183. g_list_length(desc->chrc->descs));
  2184. desc->flags = g_strsplit(argv[2], ",", -1);
  2185. if (argc > 3)
  2186. desc->handle = atoi(argv[3]);
  2187. if (g_dbus_register_interface(conn, desc->path, DESC_INTERFACE,
  2188. desc_methods, NULL, desc_properties,
  2189. desc, desc_free) == FALSE) {
  2190. bt_shell_printf("Failed to register descriptor object\n");
  2191. desc_free(desc);
  2192. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  2193. }
  2194. desc->chrc->descs = g_list_append(desc->chrc->descs, desc);
  2195. print_desc(desc, COLORED_NEW);
  2196. bt_shell_prompt_input(desc->path, "Enter value:", desc_set_value, desc);
  2197. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  2198. }
  2199. static struct desc *desc_find(const char *pattern)
  2200. {
  2201. GList *l, *lc, *ld;
  2202. struct service *service;
  2203. struct chrc *chrc;
  2204. struct desc *desc;
  2205. for (l = local_services; l; l = g_list_next(l)) {
  2206. service = l->data;
  2207. for (lc = service->chrcs; lc; lc = g_list_next(lc)) {
  2208. chrc = lc->data;
  2209. for (ld = chrc->descs; ld; ld = g_list_next(ld)) {
  2210. desc = ld->data;
  2211. /* match object path */
  2212. if (!strcmp(desc->path, pattern))
  2213. return desc;
  2214. /* match UUID */
  2215. if (!strcmp(desc->uuid, pattern))
  2216. return desc;
  2217. }
  2218. }
  2219. }
  2220. return NULL;
  2221. }
  2222. void gatt_unregister_desc(DBusConnection *conn, GDBusProxy *proxy,
  2223. int argc, char *argv[])
  2224. {
  2225. struct desc *desc;
  2226. desc = desc_find(argv[1]);
  2227. if (!desc) {
  2228. bt_shell_printf("Failed to unregister descriptor object\n");
  2229. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  2230. }
  2231. desc->chrc->descs = g_list_remove(desc->chrc->descs, desc);
  2232. desc_unregister(desc);
  2233. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  2234. }
  2235. static GDBusProxy *select_service(GDBusProxy *proxy)
  2236. {
  2237. GList *l;
  2238. for (l = services; l; l = g_list_next(l)) {
  2239. GDBusProxy *p = l->data;
  2240. if (proxy == p || g_str_has_prefix(g_dbus_proxy_get_path(proxy),
  2241. g_dbus_proxy_get_path(p)))
  2242. return p;
  2243. }
  2244. return NULL;
  2245. }
  2246. static void proxy_property_changed(GDBusProxy *proxy, const char *name,
  2247. DBusMessageIter *iter, void *user_data)
  2248. {
  2249. DBusConnection *conn = bt_shell_get_env("DBUS_CONNECTION");
  2250. struct chrc *chrc = user_data;
  2251. bt_shell_printf("[" COLORED_CHG "] Attribute %s (%s) %s:\n",
  2252. chrc->path, bt_uuidstr_to_str(chrc->uuid), name);
  2253. if (!strcmp(name, "Value")) {
  2254. DBusMessageIter array;
  2255. uint8_t *value;
  2256. int len;
  2257. if (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_ARRAY) {
  2258. dbus_message_iter_recurse(iter, &array);
  2259. dbus_message_iter_get_fixed_array(&array, &value, &len);
  2260. write_value(&chrc->value_len, &chrc->value, value, len,
  2261. 0, chrc->max_val_len);
  2262. bt_shell_hexdump(value, len);
  2263. }
  2264. }
  2265. g_dbus_emit_property_changed(conn, chrc->path, CHRC_INTERFACE, name);
  2266. }
  2267. static void clone_chrc(struct GDBusProxy *proxy)
  2268. {
  2269. struct service *service;
  2270. struct chrc *chrc;
  2271. DBusMessageIter iter;
  2272. DBusMessageIter array;
  2273. const char *uuid;
  2274. char *flags[17];
  2275. int i;
  2276. if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
  2277. return;
  2278. dbus_message_iter_get_basic(&iter, &uuid);
  2279. if (g_dbus_proxy_get_property(proxy, "Flags", &iter) == FALSE)
  2280. return;
  2281. dbus_message_iter_recurse(&iter, &array);
  2282. for (i = 0; dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING;
  2283. i++) {
  2284. dbus_message_iter_get_basic(&array, &flags[i]);
  2285. dbus_message_iter_next(&array);
  2286. }
  2287. flags[i] = NULL;
  2288. service = g_list_last(local_services)->data;
  2289. chrc = g_new0(struct chrc, 1);
  2290. chrc->service = service;
  2291. chrc->proxy = proxy;
  2292. chrc->uuid = g_strdup(uuid);
  2293. chrc->path = g_strdup_printf("%s/chrc%u", service->path,
  2294. g_list_length(service->chrcs));
  2295. chrc->flags = g_strdupv(flags);
  2296. if (g_dbus_register_interface(service->conn, chrc->path, CHRC_INTERFACE,
  2297. chrc_methods, NULL, chrc_properties,
  2298. chrc, chrc_free) == FALSE) {
  2299. bt_shell_printf("Failed to register characteristic object\n");
  2300. chrc_free(chrc);
  2301. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  2302. }
  2303. g_dbus_proxy_set_property_watch(proxy, proxy_property_changed, chrc);
  2304. service->chrcs = g_list_append(service->chrcs, chrc);
  2305. print_chrc(chrc, COLORED_NEW);
  2306. }
  2307. static void clone_chrcs(struct GDBusProxy *proxy)
  2308. {
  2309. GList *l;
  2310. for (l = characteristics; l; l = g_list_next(l)) {
  2311. GDBusProxy *p = l->data;
  2312. if (g_str_has_prefix(g_dbus_proxy_get_path(p),
  2313. g_dbus_proxy_get_path(proxy)))
  2314. clone_chrc(p);
  2315. }
  2316. }
  2317. static void clone_service(struct GDBusProxy *proxy)
  2318. {
  2319. struct service *service;
  2320. DBusMessageIter iter;
  2321. const char *uuid;
  2322. dbus_bool_t primary;
  2323. if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
  2324. return;
  2325. dbus_message_iter_get_basic(&iter, &uuid);
  2326. if (g_dbus_proxy_get_property(proxy, "Primary", &iter) == FALSE)
  2327. return;
  2328. dbus_message_iter_get_basic(&iter, &primary);
  2329. if (!strcmp(uuid, "00001800-0000-1000-8000-00805f9b34fb") ||
  2330. !strcmp(uuid, "00001801-0000-1000-8000-00805f9b34fb"))
  2331. return;
  2332. service = g_new0(struct service, 1);
  2333. service->conn = bt_shell_get_env("DBUS_CONNECTION");
  2334. service->proxy = proxy;
  2335. service->path = g_strdup_printf("%s/service%u", APP_PATH,
  2336. g_list_length(local_services));
  2337. service->uuid = g_strdup(uuid);
  2338. service->primary = primary;
  2339. if (g_dbus_register_interface(service->conn, service->path,
  2340. SERVICE_INTERFACE, NULL, NULL,
  2341. service_properties, service,
  2342. service_free) == FALSE) {
  2343. bt_shell_printf("Failed to register service object\n");
  2344. service_free(service);
  2345. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  2346. }
  2347. print_service(service, COLORED_NEW);
  2348. local_services = g_list_append(local_services, service);
  2349. clone_chrcs(proxy);
  2350. }
  2351. static void clone_device(struct GDBusProxy *proxy)
  2352. {
  2353. GList *l;
  2354. for (l = services; l; l = g_list_next(l)) {
  2355. struct GDBusProxy *p = l->data;
  2356. if (g_str_has_prefix(g_dbus_proxy_get_path(p),
  2357. g_dbus_proxy_get_path(proxy)))
  2358. clone_service(p);
  2359. }
  2360. }
  2361. static void service_clone(const char *input, void *user_data)
  2362. {
  2363. struct GDBusProxy *proxy = user_data;
  2364. if (!strcmp(input, "yes"))
  2365. return clone_service(proxy);
  2366. else if (!strcmp(input, "no"))
  2367. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  2368. else if (!strcmp(input, "all"))
  2369. return clone_device(proxy);
  2370. bt_shell_printf("Invalid option: %s\n", input);
  2371. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  2372. }
  2373. static void device_clone(const char *input, void *user_data)
  2374. {
  2375. struct GDBusProxy *proxy = user_data;
  2376. if (!strcmp(input, "yes"))
  2377. return clone_device(proxy);
  2378. else if (!strcmp(input, "no"))
  2379. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  2380. bt_shell_printf("Invalid option: %s\n", input);
  2381. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  2382. }
  2383. static const char *proxy_get_name(struct GDBusProxy *proxy)
  2384. {
  2385. DBusMessageIter iter;
  2386. const char *uuid;
  2387. const char *str;
  2388. if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
  2389. return NULL;
  2390. dbus_message_iter_get_basic(&iter, &uuid);
  2391. str = bt_uuidstr_to_str(uuid);
  2392. return str ? str : uuid;
  2393. }
  2394. static const char *proxy_get_alias(struct GDBusProxy *proxy)
  2395. {
  2396. DBusMessageIter iter;
  2397. const char *alias;
  2398. if (g_dbus_proxy_get_property(proxy, "Alias", &iter) == FALSE)
  2399. return NULL;
  2400. dbus_message_iter_get_basic(&iter, &alias);
  2401. return alias;
  2402. }
  2403. void gatt_clone_attribute(GDBusProxy *proxy, int argc, char *argv[])
  2404. {
  2405. GDBusProxy *service = NULL;
  2406. if (argc > 1) {
  2407. proxy = gatt_select_attribute(proxy, argv[1]);
  2408. if (!proxy) {
  2409. bt_shell_printf("Unable to find attribute %s\n",
  2410. argv[1]);
  2411. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  2412. }
  2413. }
  2414. if (!strcmp(g_dbus_proxy_get_interface(proxy), DEVICE_INTERFACE)) {
  2415. bt_shell_prompt_input(proxy_get_alias(proxy),
  2416. "Clone (yes/no):",
  2417. device_clone, proxy);
  2418. }
  2419. /* Only clone services */
  2420. service = select_service(proxy);
  2421. if (service) {
  2422. bt_shell_prompt_input(proxy_get_name(proxy),
  2423. "Clone (yes/no/all):",
  2424. service_clone, service);
  2425. return;
  2426. }
  2427. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  2428. }