agent.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733
  1. // SPDX-License-Identifier: LGPL-2.1-or-later
  2. /*
  3. *
  4. * BlueZ - Bluetooth protocol stack for Linux
  5. *
  6. * Copyright (C) 2018-2019 Intel Corporation. All rights reserved.
  7. *
  8. *
  9. */
  10. #ifdef HAVE_CONFIG_H
  11. #include <config.h>
  12. #endif
  13. #include <ell/ell.h>
  14. #include "mesh/mesh.h"
  15. #include "mesh/error.h"
  16. #include "mesh/dbus.h"
  17. #include "mesh/agent.h"
  18. typedef enum {
  19. MESH_AGENT_REQUEST_BLINK,
  20. MESH_AGENT_REQUEST_BEEP,
  21. MESH_AGENT_REQUEST_VIBRATE,
  22. MESH_AGENT_REQUEST_OUT_NUMERIC,
  23. MESH_AGENT_REQUEST_OUT_ALPHA,
  24. MESH_AGENT_REQUEST_PUSH,
  25. MESH_AGENT_REQUEST_TWIST,
  26. MESH_AGENT_REQUEST_IN_NUMERIC,
  27. MESH_AGENT_REQUEST_IN_ALPHA,
  28. MESH_AGENT_REQUEST_STATIC_OOB,
  29. MESH_AGENT_REQUEST_PRIVATE_KEY,
  30. MESH_AGENT_REQUEST_PUBLIC_KEY,
  31. MESH_AGENT_REQUEST_CAPABILITIES,
  32. } agent_request_type_t;
  33. struct agent_request {
  34. agent_request_type_t type;
  35. struct l_dbus_message *msg;
  36. void *cb;
  37. void *user_data;
  38. };
  39. struct mesh_agent {
  40. char *path;
  41. char *owner;
  42. struct mesh_agent_prov_caps caps;
  43. struct agent_request *req;
  44. };
  45. struct prov_action {
  46. const char *action;
  47. uint16_t output;
  48. uint16_t input;
  49. uint8_t size;
  50. };
  51. struct oob_info {
  52. const char *oob;
  53. uint16_t mask;
  54. };
  55. static struct prov_action cap_table[] = {
  56. {"blink", 0x0001, 0x0000, 1},
  57. {"beep", 0x0002, 0x0000, 1},
  58. {"vibrate", 0x0004, 0x0000, 1},
  59. {"out-numeric", 0x0008, 0x0000, 8},
  60. {"out-alpha", 0x0010, 0x0000, 8},
  61. {"push", 0x0000, 0x0001, 1},
  62. {"twist", 0x0000, 0x0002, 1},
  63. {"in-numeric", 0x0000, 0x0004, 8},
  64. {"in-alpha", 0x0000, 0x0008, 8}
  65. };
  66. static struct oob_info oob_table[] = {
  67. {"other", 0x0001},
  68. {"uri", 0x0002},
  69. {"machine-code-2d", 0x0004},
  70. {"barcode", 0x0008},
  71. {"nfc", 0x0010},
  72. {"number", 0x0020},
  73. {"string", 0x0040},
  74. {"on-box", 0x0800},
  75. {"in-box", 0x1000},
  76. {"on-paper", 0x2000},
  77. {"in-manual", 0x4000},
  78. {"on-device", 0x8000}
  79. };
  80. static struct l_queue *agents;
  81. static bool simple_match(const void *a, const void *b)
  82. {
  83. return a == b;
  84. }
  85. static bool parse_prov_caps(struct mesh_agent_prov_caps *caps,
  86. struct l_dbus_message_iter *property)
  87. {
  88. struct l_dbus_message_iter iter_caps;
  89. const char *str;
  90. uint32_t i;
  91. if (!l_dbus_message_iter_get_variant(property, "as", &iter_caps))
  92. return false;
  93. while (l_dbus_message_iter_next_entry(&iter_caps, &str)) {
  94. for (i = 0; i < L_ARRAY_SIZE(cap_table); i++) {
  95. if (strcmp(str, cap_table[i].action))
  96. continue;
  97. caps->output_action |= cap_table[i].output;
  98. if (cap_table[i].output &&
  99. caps->output_size < cap_table[i].size)
  100. caps->output_size = cap_table[i].size;
  101. caps->input_action |= cap_table[i].input;
  102. if (cap_table[i].input &&
  103. caps->input_size < cap_table[i].size)
  104. caps->input_size = cap_table[i].size;
  105. break;
  106. }
  107. if (!strcmp(str, "public-oob"))
  108. caps->pub_type = 1;
  109. else if (!strcmp(str, "static-oob"))
  110. caps->static_type = 1;
  111. }
  112. return true;
  113. }
  114. static bool parse_oob_info(struct mesh_agent_prov_caps *caps,
  115. struct l_dbus_message_iter *property)
  116. {
  117. struct l_dbus_message_iter iter_oob;
  118. uint32_t i;
  119. const char *str;
  120. if (!l_dbus_message_iter_get_variant(property, "as", &iter_oob))
  121. return false;
  122. while (l_dbus_message_iter_next_entry(&iter_oob, &str)) {
  123. for (i = 0; i < L_ARRAY_SIZE(oob_table); i++) {
  124. if (strcmp(str, oob_table[i].oob))
  125. continue;
  126. caps->oob_info |= oob_table[i].mask;
  127. }
  128. }
  129. return true;
  130. }
  131. static bool parse_properties(struct mesh_agent *agent,
  132. struct l_dbus_message_iter *properties)
  133. {
  134. const char *key, *uri_string;
  135. struct l_dbus_message_iter variant;
  136. memset(&agent->caps, 0, sizeof(agent->caps));
  137. while (l_dbus_message_iter_next_entry(properties, &key, &variant)) {
  138. if (!strcmp(key, "Capabilities")) {
  139. if (!parse_prov_caps(&agent->caps, &variant))
  140. return false;
  141. } else if (!strcmp(key, "URI")) {
  142. if (!l_dbus_message_iter_get_variant(&variant, "s",
  143. &uri_string))
  144. return false;
  145. /* TODO: compute hash */
  146. } else if (!strcmp(key, "OutOfBandInfo")) {
  147. if (!parse_oob_info(&agent->caps, &variant))
  148. return false;
  149. }
  150. }
  151. return true;
  152. }
  153. static void agent_free(void *agent_data)
  154. {
  155. struct mesh_agent *agent = agent_data;
  156. int err;
  157. mesh_agent_cb_t simple_cb;
  158. mesh_agent_key_cb_t key_cb;
  159. mesh_agent_number_cb_t number_cb;
  160. err = MESH_ERROR_DOES_NOT_EXIST;
  161. if (agent->req && agent->req->cb) {
  162. struct agent_request *req = agent->req;
  163. switch (req->type) {
  164. case MESH_AGENT_REQUEST_PUSH:
  165. case MESH_AGENT_REQUEST_TWIST:
  166. case MESH_AGENT_REQUEST_IN_NUMERIC:
  167. number_cb = req->cb;
  168. number_cb(req->user_data, err, 0);
  169. break;
  170. case MESH_AGENT_REQUEST_IN_ALPHA:
  171. case MESH_AGENT_REQUEST_STATIC_OOB:
  172. case MESH_AGENT_REQUEST_PRIVATE_KEY:
  173. case MESH_AGENT_REQUEST_PUBLIC_KEY:
  174. key_cb = req->cb;
  175. key_cb(req->user_data, err, NULL, 0);
  176. break;
  177. case MESH_AGENT_REQUEST_BLINK:
  178. case MESH_AGENT_REQUEST_BEEP:
  179. case MESH_AGENT_REQUEST_VIBRATE:
  180. case MESH_AGENT_REQUEST_OUT_NUMERIC:
  181. case MESH_AGENT_REQUEST_OUT_ALPHA:
  182. case MESH_AGENT_REQUEST_CAPABILITIES:
  183. simple_cb = agent->req->cb;
  184. simple_cb(req->user_data, err);
  185. default:
  186. break;
  187. }
  188. l_dbus_message_unref(req->msg);
  189. l_free(req);
  190. }
  191. l_free(agent->path);
  192. l_free(agent->owner);
  193. l_free(agent);
  194. }
  195. void mesh_agent_remove(struct mesh_agent *agent)
  196. {
  197. if (!agent)
  198. return;
  199. if (l_queue_remove(agents, agent))
  200. agent_free(agent);
  201. }
  202. void mesh_agent_cleanup(void)
  203. {
  204. if (!agents)
  205. return;
  206. l_queue_destroy(agents, agent_free);
  207. agents = NULL;
  208. }
  209. void mesh_agent_init(void)
  210. {
  211. if (!agents)
  212. agents = l_queue_new();
  213. }
  214. struct mesh_agent *mesh_agent_create(const char *path, const char *owner,
  215. struct l_dbus_message_iter *properties)
  216. {
  217. struct mesh_agent *agent;
  218. agent = l_new(struct mesh_agent, 1);
  219. agent->owner = l_strdup(owner);
  220. agent->path = l_strdup(path);
  221. if (!parse_properties(agent, properties)) {
  222. l_free(agent);
  223. return NULL;
  224. }
  225. l_queue_push_tail(agents, agent);
  226. return agent;
  227. }
  228. struct mesh_agent_prov_caps *mesh_agent_get_caps(struct mesh_agent *agent)
  229. {
  230. if (!agent || !l_queue_find(agents, simple_match, agent))
  231. return NULL;
  232. return &agent->caps;
  233. }
  234. static struct agent_request *create_request(agent_request_type_t type,
  235. void *cb, void *data)
  236. {
  237. struct agent_request *req;
  238. req = l_new(struct agent_request, 1);
  239. req->type = type;
  240. req->cb = cb;
  241. req->user_data = data;
  242. return req;
  243. }
  244. static int get_reply_error(struct l_dbus_message *reply)
  245. {
  246. const char *name, *desc;
  247. if (l_dbus_message_is_error(reply)) {
  248. l_dbus_message_get_error(reply, &name, &desc);
  249. l_error("Agent failed (%s), %s", name, desc);
  250. return MESH_ERROR_FAILED;
  251. }
  252. return MESH_ERROR_NONE;
  253. }
  254. static void properties_reply(struct l_dbus_message *reply, void *user_data)
  255. {
  256. struct mesh_agent *agent = user_data;
  257. struct agent_request *req;
  258. mesh_agent_cb_t cb;
  259. struct l_dbus_message_iter properties;
  260. int err;
  261. if (!l_queue_find(agents, simple_match, agent) || !agent->req)
  262. return;
  263. req = agent->req;
  264. err = get_reply_error(reply);
  265. if (err != MESH_ERROR_NONE)
  266. goto done;
  267. if (!l_dbus_message_get_arguments(reply, "a{sv}", &properties)) {
  268. err = MESH_ERROR_FAILED;
  269. goto done;
  270. }
  271. if (!parse_properties(agent, &properties))
  272. err = MESH_ERROR_FAILED;
  273. done:
  274. if (req->cb) {
  275. cb = req->cb;
  276. cb(req->user_data, err);
  277. }
  278. l_dbus_message_unref(req->msg);
  279. l_free(req);
  280. agent->req = NULL;
  281. }
  282. void mesh_agent_refresh(struct mesh_agent *agent, mesh_agent_cb_t cb,
  283. void *user_data)
  284. {
  285. struct l_dbus *dbus = dbus_get_bus();
  286. struct l_dbus_message *msg;
  287. struct l_dbus_message_builder *builder;
  288. agent->req = create_request(MESH_AGENT_REQUEST_CAPABILITIES, (void *)cb,
  289. user_data);
  290. msg = l_dbus_message_new_method_call(dbus, agent->owner, agent->path,
  291. L_DBUS_INTERFACE_PROPERTIES,
  292. "GetAll");
  293. builder = l_dbus_message_builder_new(msg);
  294. l_dbus_message_builder_append_basic(builder, 's',
  295. MESH_PROVISION_AGENT_INTERFACE);
  296. l_dbus_message_builder_finalize(builder);
  297. l_dbus_message_builder_destroy(builder);
  298. l_dbus_send_with_reply(dbus_get_bus(), msg, properties_reply, agent,
  299. NULL);
  300. agent->req->msg = l_dbus_message_ref(msg);
  301. }
  302. static void simple_reply(struct l_dbus_message *reply, void *user_data)
  303. {
  304. struct mesh_agent *agent = user_data;
  305. struct agent_request *req;
  306. mesh_agent_cb_t cb;
  307. int err;
  308. if (!l_queue_find(agents, simple_match, agent) || !agent->req)
  309. return;
  310. req = agent->req;
  311. err = get_reply_error(reply);
  312. l_dbus_message_unref(req->msg);
  313. if (req->cb) {
  314. cb = req->cb;
  315. cb(req->user_data, err);
  316. }
  317. l_free(req);
  318. agent->req = NULL;
  319. }
  320. static void numeric_reply(struct l_dbus_message *reply, void *user_data)
  321. {
  322. struct mesh_agent *agent = user_data;
  323. struct agent_request *req;
  324. mesh_agent_number_cb_t cb;
  325. uint32_t count;
  326. int err;
  327. if (!l_queue_find(agents, simple_match, agent) || !agent->req)
  328. return;
  329. req = agent->req;
  330. err = get_reply_error(reply);
  331. count = 0;
  332. if (err == MESH_ERROR_NONE) {
  333. if (!l_dbus_message_get_arguments(reply, "u", &count)) {
  334. l_error("Failed to retrieve numeric input");
  335. err = MESH_ERROR_FAILED;
  336. }
  337. }
  338. l_dbus_message_unref(req->msg);
  339. if (req->cb) {
  340. cb = req->cb;
  341. cb(req->user_data, err, count);
  342. }
  343. l_free(req);
  344. agent->req = NULL;
  345. }
  346. static void key_reply(struct l_dbus_message *reply, void *user_data)
  347. {
  348. struct mesh_agent *agent = user_data;
  349. struct agent_request *req;
  350. mesh_agent_key_cb_t cb;
  351. struct l_dbus_message_iter iter_array;
  352. uint32_t n = 0, expected_len = 0;
  353. uint8_t *buf = NULL;
  354. int err;
  355. if (!l_queue_find(agents, simple_match, agent) || !agent->req)
  356. return;
  357. req = agent->req;
  358. err = get_reply_error(reply);
  359. if (err != MESH_ERROR_NONE)
  360. goto done;
  361. if (!l_dbus_message_get_arguments(reply, "ay", &iter_array)) {
  362. l_error("Failed to retrieve key input");
  363. err = MESH_ERROR_FAILED;
  364. goto done;
  365. }
  366. if (!l_dbus_message_iter_get_fixed_array(&iter_array, &buf, &n)) {
  367. l_error("Failed to retrieve key input");
  368. err = MESH_ERROR_FAILED;
  369. goto done;
  370. }
  371. if (req->type == MESH_AGENT_REQUEST_PRIVATE_KEY)
  372. expected_len = 32;
  373. else if (req->type == MESH_AGENT_REQUEST_PUBLIC_KEY)
  374. expected_len = 64;
  375. else
  376. expected_len = 16;
  377. if (n != expected_len) {
  378. l_error("Bad response length: %u (need %u)", n, expected_len);
  379. err = MESH_ERROR_FAILED;
  380. n = 0;
  381. }
  382. done:
  383. if (req->cb) {
  384. cb = req->cb;
  385. cb(req->user_data, err, buf, n);
  386. }
  387. l_dbus_message_unref(req->msg);
  388. l_free(req);
  389. agent->req = NULL;
  390. }
  391. static int output_request(struct mesh_agent *agent, const char *action,
  392. agent_request_type_t type, uint32_t cnt,
  393. void *cb, void *user_data)
  394. {
  395. struct l_dbus *dbus = dbus_get_bus();
  396. struct l_dbus_message *msg;
  397. struct l_dbus_message_builder *builder;
  398. if (!l_queue_find(agents, simple_match, agent))
  399. return MESH_ERROR_DOES_NOT_EXIST;
  400. if (agent->req)
  401. return MESH_ERROR_BUSY;
  402. agent->req = create_request(type, cb, user_data);
  403. msg = l_dbus_message_new_method_call(dbus, agent->owner, agent->path,
  404. MESH_PROVISION_AGENT_INTERFACE,
  405. "DisplayNumeric");
  406. builder = l_dbus_message_builder_new(msg);
  407. l_dbus_message_builder_append_basic(builder, 's', action);
  408. l_dbus_message_builder_append_basic(builder, 'u', &cnt);
  409. l_dbus_message_builder_finalize(builder);
  410. l_dbus_message_builder_destroy(builder);
  411. l_debug("Send DisplayNumeric request to %s %s",
  412. agent->owner, agent->path);
  413. l_dbus_send_with_reply(dbus_get_bus(), msg, simple_reply, agent,
  414. NULL);
  415. agent->req->msg = l_dbus_message_ref(msg);
  416. return MESH_ERROR_NONE;
  417. }
  418. static int prompt_input(struct mesh_agent *agent, const char *action,
  419. agent_request_type_t type, bool numeric,
  420. void *cb, void *user_data)
  421. {
  422. struct l_dbus *dbus = dbus_get_bus();
  423. struct l_dbus_message *msg;
  424. struct l_dbus_message_builder *builder;
  425. const char *method_name;
  426. l_dbus_message_func_t reply_cb;
  427. if (!l_queue_find(agents, simple_match, agent))
  428. return MESH_ERROR_DOES_NOT_EXIST;
  429. if (agent->req)
  430. return MESH_ERROR_BUSY;
  431. agent->req = create_request(type, cb, user_data);
  432. method_name = numeric ? "PromptNumeric" : "PromptStatic";
  433. msg = l_dbus_message_new_method_call(dbus, agent->owner,
  434. agent->path,
  435. MESH_PROVISION_AGENT_INTERFACE,
  436. method_name);
  437. builder = l_dbus_message_builder_new(msg);
  438. l_dbus_message_builder_append_basic(builder, 's', action);
  439. l_dbus_message_builder_finalize(builder);
  440. l_dbus_message_builder_destroy(builder);
  441. l_debug("Send \"%s\" input request to %s %s", action,
  442. agent->owner, agent->path);
  443. reply_cb = numeric ? numeric_reply : key_reply;
  444. l_dbus_send_with_reply(dbus_get_bus(), msg, reply_cb, agent, NULL);
  445. agent->req->msg = l_dbus_message_ref(msg);
  446. return MESH_ERROR_NONE;
  447. }
  448. static int request_key(struct mesh_agent *agent,
  449. agent_request_type_t type,
  450. void *cb, void *user_data)
  451. {
  452. struct l_dbus *dbus = dbus_get_bus();
  453. struct l_dbus_message *msg;
  454. const char *method_name;
  455. if (!l_queue_find(agents, simple_match, agent))
  456. return MESH_ERROR_DOES_NOT_EXIST;
  457. if (agent->req)
  458. return MESH_ERROR_BUSY;
  459. agent->req = create_request(type, cb, user_data);
  460. method_name = (type == MESH_AGENT_REQUEST_PRIVATE_KEY) ?
  461. "PrivateKey" : "PublicKey";
  462. msg = l_dbus_message_new_method_call(dbus, agent->owner,
  463. agent->path,
  464. MESH_PROVISION_AGENT_INTERFACE,
  465. method_name);
  466. l_dbus_message_set_arguments(msg, "");
  467. l_debug("Send key request to %s %s", agent->owner, agent->path);
  468. l_dbus_send_with_reply(dbus_get_bus(), msg, key_reply, agent, NULL);
  469. agent->req->msg = l_dbus_message_ref(msg);
  470. return MESH_ERROR_NONE;
  471. }
  472. int mesh_agent_display_string(struct mesh_agent *agent, const char *str,
  473. mesh_agent_cb_t cb, void *user_data)
  474. {
  475. struct l_dbus *dbus = dbus_get_bus();
  476. struct l_dbus_message *msg;
  477. struct l_dbus_message_builder *builder;
  478. if (!l_queue_find(agents, simple_match, agent))
  479. return MESH_ERROR_DOES_NOT_EXIST;
  480. if (agent->req)
  481. return MESH_ERROR_BUSY;
  482. agent->req = create_request(MESH_AGENT_REQUEST_OUT_ALPHA,
  483. cb, user_data);
  484. msg = l_dbus_message_new_method_call(dbus, agent->owner, agent->path,
  485. MESH_PROVISION_AGENT_INTERFACE,
  486. "DisplayString");
  487. builder = l_dbus_message_builder_new(msg);
  488. l_dbus_message_builder_append_basic(builder, 's', str);
  489. l_dbus_message_builder_finalize(builder);
  490. l_dbus_message_builder_destroy(builder);
  491. l_debug("Send DisplayString request to %s %s",
  492. agent->owner, agent->path);
  493. l_dbus_send_with_reply(dbus_get_bus(), msg, simple_reply, agent,
  494. NULL);
  495. agent->req->msg = l_dbus_message_ref(msg);
  496. return MESH_ERROR_NONE;
  497. }
  498. int mesh_agent_display_number(struct mesh_agent *agent, bool initiator,
  499. uint8_t action, uint32_t count,
  500. mesh_agent_cb_t cb, void *user_data)
  501. {
  502. const char *str_type;
  503. agent_request_type_t type;
  504. type = action;
  505. if (initiator)
  506. type = action + MESH_AGENT_REQUEST_PUSH;
  507. if (type >= L_ARRAY_SIZE(cap_table))
  508. return MESH_ERROR_INVALID_ARGS;
  509. str_type = cap_table[type].action;
  510. return output_request(agent, str_type, type, count, cb, user_data);
  511. }
  512. int mesh_agent_prompt_number(struct mesh_agent *agent, bool initiator,
  513. uint8_t action,
  514. mesh_agent_number_cb_t cb,
  515. void *user_data)
  516. {
  517. const char *str_type;
  518. agent_request_type_t type;
  519. type = action;
  520. if (!initiator)
  521. type = action + MESH_AGENT_REQUEST_PUSH;
  522. if (type >= L_ARRAY_SIZE(cap_table))
  523. return MESH_ERROR_INVALID_ARGS;
  524. str_type = cap_table[type].action;
  525. return prompt_input(agent, str_type, type, true, cb, user_data);
  526. }
  527. int mesh_agent_prompt_alpha(struct mesh_agent *agent, bool initiator,
  528. mesh_agent_key_cb_t cb, void *user_data)
  529. {
  530. if (initiator)
  531. return prompt_input(agent,
  532. cap_table[MESH_AGENT_REQUEST_OUT_ALPHA].action,
  533. MESH_AGENT_REQUEST_OUT_ALPHA, false, cb,
  534. user_data);
  535. else
  536. return prompt_input(agent,
  537. cap_table[MESH_AGENT_REQUEST_IN_ALPHA].action,
  538. MESH_AGENT_REQUEST_IN_ALPHA, false, cb,
  539. user_data);
  540. }
  541. int mesh_agent_request_static(struct mesh_agent *agent, mesh_agent_key_cb_t cb,
  542. void *user_data)
  543. {
  544. return prompt_input(agent, "static-oob", MESH_AGENT_REQUEST_STATIC_OOB,
  545. false, cb, user_data);
  546. }
  547. int mesh_agent_request_private_key(struct mesh_agent *agent,
  548. mesh_agent_key_cb_t cb, void *user_data)
  549. {
  550. return request_key(agent, MESH_AGENT_REQUEST_PRIVATE_KEY, cb,
  551. user_data);
  552. }
  553. int mesh_agent_request_public_key(struct mesh_agent *agent,
  554. mesh_agent_key_cb_t cb, void *user_data)
  555. {
  556. return request_key(agent, MESH_AGENT_REQUEST_PUBLIC_KEY, cb,
  557. user_data);
  558. }
  559. void mesh_agent_cancel(struct mesh_agent *agent)
  560. {
  561. struct l_dbus *dbus = dbus_get_bus();
  562. struct l_dbus_message *msg;
  563. if (!l_queue_find(agents, simple_match, agent))
  564. return;
  565. msg = l_dbus_message_new_method_call(dbus, agent->owner, agent->path,
  566. MESH_PROVISION_AGENT_INTERFACE,
  567. "Cancel");
  568. l_dbus_message_set_arguments(msg, "");
  569. l_dbus_send(dbus, msg);
  570. }