3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2018-2019 Intel Corporation. All rights reserved.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
26 #include "mesh/mesh.h"
27 #include "mesh/error.h"
28 #include "mesh/dbus.h"
29 #include "mesh/agent.h"
32 MESH_AGENT_REQUEST_BLINK,
33 MESH_AGENT_REQUEST_BEEP,
34 MESH_AGENT_REQUEST_VIBRATE,
35 MESH_AGENT_REQUEST_OUT_NUMERIC,
36 MESH_AGENT_REQUEST_OUT_ALPHA,
37 MESH_AGENT_REQUEST_PUSH,
38 MESH_AGENT_REQUEST_TWIST,
39 MESH_AGENT_REQUEST_IN_NUMERIC,
40 MESH_AGENT_REQUEST_IN_ALPHA,
41 MESH_AGENT_REQUEST_STATIC_OOB,
42 MESH_AGENT_REQUEST_PRIVATE_KEY,
43 MESH_AGENT_REQUEST_PUBLIC_KEY,
44 MESH_AGENT_REQUEST_CAPABILITIES,
45 } agent_request_type_t;
47 struct agent_request {
48 agent_request_type_t type;
49 struct l_dbus_message *msg;
57 struct mesh_agent_prov_caps caps;
58 struct agent_request *req;
73 static struct prov_action cap_table[] = {
74 {"blink", 0x0001, 0x0000, 1},
75 {"beep", 0x0002, 0x0000, 1},
76 {"vibrate", 0x0004, 0x0000, 1},
77 {"out-numeric", 0x0008, 0x0000, 8},
78 {"out-alpha", 0x0010, 0x0000, 8},
79 {"push", 0x0000, 0x0001, 1},
80 {"twist", 0x0000, 0x0002, 1},
81 {"in-numeric", 0x0000, 0x0004, 8},
82 {"in-alpha", 0x0000, 0x0008, 8}
85 static struct oob_info oob_table[] = {
88 {"machine-code-2d", 0x0004},
96 {"in-manual", 0x4000},
100 static struct l_queue *agents;
102 static bool simple_match(const void *a, const void *b)
107 static void parse_prov_caps(struct mesh_agent_prov_caps *caps,
108 struct l_dbus_message_iter *property)
110 struct l_dbus_message_iter iter_caps;
114 if (!l_dbus_message_iter_get_variant(property, "as", &iter_caps))
117 while (l_dbus_message_iter_next_entry(&iter_caps, &str)) {
118 for (i = 0; i < L_ARRAY_SIZE(cap_table); i++) {
119 if (strcmp(str, cap_table[i].action))
122 caps->output_action |= cap_table[i].output;
123 if (cap_table[i].output &&
124 caps->output_size < cap_table[i].size)
125 caps->output_size = cap_table[i].size;
127 caps->input_action |= cap_table[i].input;
128 if (cap_table[i].input &&
129 caps->input_size < cap_table[i].size)
130 caps->input_size = cap_table[i].size;
135 if (!strcmp(str, "public-oob"))
137 else if (!strcmp(str, "static-oob"))
138 caps->static_type = 1;
143 static void parse_oob_info(struct mesh_agent_prov_caps *caps,
144 struct l_dbus_message_iter *property)
146 struct l_dbus_message_iter iter_oob;
150 if (!l_dbus_message_iter_get_variant(property, "as", &iter_oob))
153 while (l_dbus_message_iter_next_entry(&iter_oob, &str)) {
154 for (i = 0; i < L_ARRAY_SIZE(oob_table); i++) {
155 if (strcmp(str, oob_table[i].oob))
157 caps->oob_info |= oob_table[i].mask;
162 static void parse_properties(struct mesh_agent *agent,
163 struct l_dbus_message_iter *properties)
165 const char *key, *uri_string;
166 struct l_dbus_message_iter variant;
168 memset(&agent->caps, 0, sizeof(agent->caps));
170 while (l_dbus_message_iter_next_entry(properties, &key, &variant)) {
171 if (!strcmp(key, "Capabilities")) {
172 parse_prov_caps(&agent->caps, &variant);
173 } else if (!strcmp(key, "URI")) {
174 l_dbus_message_iter_get_variant(&variant, "s",
176 /* TODO: compute hash */
177 } else if (!strcmp(key, "OutOfBandInfo")) {
178 parse_oob_info(&agent->caps, &variant);
183 static void agent_free(void *agent_data)
185 struct mesh_agent *agent = agent_data;
187 mesh_agent_cb_t simple_cb;
188 mesh_agent_key_cb_t key_cb;
189 mesh_agent_number_cb_t number_cb;
191 if (!l_queue_find(agents, simple_match, agent))
194 err = MESH_ERROR_DOES_NOT_EXIST;
196 if (agent->req && agent->req->cb) {
197 struct agent_request *req = agent->req;
200 case MESH_AGENT_REQUEST_PUSH:
201 case MESH_AGENT_REQUEST_TWIST:
202 case MESH_AGENT_REQUEST_IN_NUMERIC:
204 number_cb(req->user_data, err, 0);
206 case MESH_AGENT_REQUEST_IN_ALPHA:
207 case MESH_AGENT_REQUEST_STATIC_OOB:
208 case MESH_AGENT_REQUEST_PRIVATE_KEY:
209 case MESH_AGENT_REQUEST_PUBLIC_KEY:
211 key_cb(req->user_data, err, NULL, 0);
213 case MESH_AGENT_REQUEST_BLINK:
214 case MESH_AGENT_REQUEST_BEEP:
215 case MESH_AGENT_REQUEST_VIBRATE:
216 case MESH_AGENT_REQUEST_OUT_NUMERIC:
217 case MESH_AGENT_REQUEST_OUT_ALPHA:
218 case MESH_AGENT_REQUEST_CAPABILITIES:
219 simple_cb = agent->req->cb;
220 simple_cb(req->user_data, err);
225 l_dbus_message_unref(req->msg);
230 l_free(agent->owner);
233 void mesh_agent_remove(struct mesh_agent *agent)
235 if (!agent || !l_queue_find(agents, simple_match, agent))
239 l_queue_remove(agents, agent);
242 void mesh_agent_cleanup(void)
247 l_queue_destroy(agents, agent_free);
251 void mesh_agent_init(void)
254 agents = l_queue_new();
257 struct mesh_agent *mesh_agent_create(const char *path, const char *owner,
258 struct l_dbus_message_iter *properties)
260 struct mesh_agent *agent;
262 agent = l_new(struct mesh_agent, 1);
263 agent->owner = l_strdup(owner);
264 agent->path = l_strdup(path);
266 parse_properties(agent, properties);
268 l_queue_push_tail(agents, agent);
273 struct mesh_agent_prov_caps *mesh_agent_get_caps(struct mesh_agent *agent)
275 if (!agent || !l_queue_find(agents, simple_match, agent))
281 static struct agent_request *create_request(agent_request_type_t type,
282 void *cb, void *data)
284 struct agent_request *req;
286 req = l_new(struct agent_request, 1);
290 req->user_data = data;
295 static int get_reply_error(struct l_dbus_message *reply)
297 const char *name, *desc;
299 if (l_dbus_message_is_error(reply)) {
301 l_dbus_message_get_error(reply, &name, &desc);
302 l_error("Agent failed (%s), %s", name, desc);
303 return MESH_ERROR_FAILED;
306 return MESH_ERROR_NONE;
309 static void properties_reply(struct l_dbus_message *reply, void *user_data)
311 struct mesh_agent *agent = user_data;
312 struct agent_request *req;
314 struct l_dbus_message_iter properties;
317 if (!l_queue_find(agents, simple_match, agent) || !agent->req)
322 err = get_reply_error(reply);
324 if (err != MESH_ERROR_NONE)
327 if (!l_dbus_message_get_arguments(reply, "a{sv}", &properties)) {
328 err = MESH_ERROR_FAILED;
332 parse_properties(agent, &properties);
336 cb(req->user_data, err);
339 l_dbus_message_unref(req->msg);
344 void mesh_agent_refresh(struct mesh_agent *agent, mesh_agent_cb_t cb,
347 struct l_dbus *dbus = dbus_get_bus();
348 struct l_dbus_message *msg;
349 struct l_dbus_message_builder *builder;
351 agent->req = create_request(MESH_AGENT_REQUEST_CAPABILITIES, (void *)cb,
354 msg = l_dbus_message_new_method_call(dbus, agent->owner, agent->path,
355 L_DBUS_INTERFACE_PROPERTIES,
358 builder = l_dbus_message_builder_new(msg);
359 l_dbus_message_builder_append_basic(builder, 's',
360 MESH_PROVISION_AGENT_INTERFACE);
361 l_dbus_message_builder_finalize(builder);
362 l_dbus_message_builder_destroy(builder);
364 l_dbus_send_with_reply(dbus_get_bus(), msg, properties_reply, agent,
367 agent->req->msg = l_dbus_message_ref(msg);
371 static void simple_reply(struct l_dbus_message *reply, void *user_data)
373 struct mesh_agent *agent = user_data;
374 struct agent_request *req;
378 if (!l_queue_find(agents, simple_match, agent) || !agent->req)
383 err = get_reply_error(reply);
385 l_dbus_message_unref(req->msg);
389 cb(req->user_data, err);
396 static void numeric_reply(struct l_dbus_message *reply, void *user_data)
398 struct mesh_agent *agent = user_data;
399 struct agent_request *req;
400 mesh_agent_number_cb_t cb;
404 if (!l_queue_find(agents, simple_match, agent) || !agent->req)
409 err = get_reply_error(reply);
413 if (err == MESH_ERROR_NONE) {
414 if (!l_dbus_message_get_arguments(reply, "u", &count)) {
415 l_error("Failed to retrieve numeric input");
416 err = MESH_ERROR_FAILED;
420 l_dbus_message_unref(req->msg);
424 cb(req->user_data, err, count);
431 static void key_reply(struct l_dbus_message *reply, void *user_data)
433 struct mesh_agent *agent = user_data;
434 struct agent_request *req;
435 mesh_agent_key_cb_t cb;
436 struct l_dbus_message_iter iter_array;
437 uint32_t n = 0, expected_len = 0;
441 if (!l_queue_find(agents, simple_match, agent) || !agent->req)
446 err = get_reply_error(reply);
448 if (err != MESH_ERROR_NONE)
451 if (!l_dbus_message_get_arguments(reply, "ay", &iter_array)) {
452 l_error("Failed to retrieve key input");
453 err = MESH_ERROR_FAILED;
457 if (!l_dbus_message_iter_get_fixed_array(&iter_array, &buf, &n)) {
458 l_error("Failed to retrieve key input");
459 err = MESH_ERROR_FAILED;
463 if (req->type == MESH_AGENT_REQUEST_PRIVATE_KEY)
465 else if (req->type == MESH_AGENT_REQUEST_PUBLIC_KEY)
470 if (n != expected_len) {
471 l_error("Bad response length: %u (need %u)", n, expected_len);
472 err = MESH_ERROR_FAILED;
479 cb(req->user_data, err, buf, n);
482 l_dbus_message_unref(req->msg);
488 static int output_request(struct mesh_agent *agent, const char *action,
489 agent_request_type_t type, uint32_t cnt,
490 void *cb, void *user_data)
492 struct l_dbus *dbus = dbus_get_bus();
493 struct l_dbus_message *msg;
494 struct l_dbus_message_builder *builder;
496 if (!l_queue_find(agents, simple_match, agent))
497 return MESH_ERROR_DOES_NOT_EXIST;
500 return MESH_ERROR_BUSY;
502 agent->req = create_request(type, cb, user_data);
503 msg = l_dbus_message_new_method_call(dbus, agent->owner, agent->path,
504 MESH_PROVISION_AGENT_INTERFACE,
507 builder = l_dbus_message_builder_new(msg);
508 l_dbus_message_builder_append_basic(builder, 's', action);
509 l_dbus_message_builder_append_basic(builder, 'u', &cnt);
510 l_dbus_message_builder_finalize(builder);
511 l_dbus_message_builder_destroy(builder);
513 l_debug("Send DisplayNumeric request to %s %s",
514 agent->owner, agent->path);
516 l_dbus_send_with_reply(dbus_get_bus(), msg, simple_reply, agent,
519 agent->req->msg = l_dbus_message_ref(msg);
521 return MESH_ERROR_NONE;
524 static int prompt_input(struct mesh_agent *agent, const char *action,
525 agent_request_type_t type, bool numeric,
526 void *cb, void *user_data)
528 struct l_dbus *dbus = dbus_get_bus();
529 struct l_dbus_message *msg;
530 struct l_dbus_message_builder *builder;
531 const char *method_name;
532 l_dbus_message_func_t reply_cb;
534 if (!l_queue_find(agents, simple_match, agent))
535 return MESH_ERROR_DOES_NOT_EXIST;
538 return MESH_ERROR_BUSY;
540 agent->req = create_request(type, cb, user_data);
542 method_name = numeric ? "PromptNumeric" : "PromptStatic";
544 msg = l_dbus_message_new_method_call(dbus, agent->owner,
546 MESH_PROVISION_AGENT_INTERFACE,
549 builder = l_dbus_message_builder_new(msg);
550 l_dbus_message_builder_append_basic(builder, 's', action);
551 l_dbus_message_builder_finalize(builder);
552 l_dbus_message_builder_destroy(builder);
554 l_debug("Send \"%s\" input request to %s %s", action,
555 agent->owner, agent->path);
557 reply_cb = numeric ? numeric_reply : key_reply;
559 l_dbus_send_with_reply(dbus_get_bus(), msg, reply_cb, agent, NULL);
561 agent->req->msg = l_dbus_message_ref(msg);
563 return MESH_ERROR_NONE;
566 static int request_key(struct mesh_agent *agent,
567 agent_request_type_t type,
568 void *cb, void *user_data)
570 struct l_dbus *dbus = dbus_get_bus();
571 struct l_dbus_message *msg;
572 const char *method_name;
574 if (!l_queue_find(agents, simple_match, agent))
575 return MESH_ERROR_DOES_NOT_EXIST;
578 return MESH_ERROR_BUSY;
580 agent->req = create_request(type, cb, user_data);
582 method_name = (type == MESH_AGENT_REQUEST_PRIVATE_KEY) ?
583 "PrivateKey" : "PublicKey";
585 msg = l_dbus_message_new_method_call(dbus, agent->owner,
587 MESH_PROVISION_AGENT_INTERFACE,
590 l_dbus_message_set_arguments(msg, "");
592 l_debug("Send key request to %s %s", agent->owner, agent->path);
594 l_dbus_send_with_reply(dbus_get_bus(), msg, key_reply, agent, NULL);
596 agent->req->msg = l_dbus_message_ref(msg);
598 return MESH_ERROR_NONE;
601 int mesh_agent_display_string(struct mesh_agent *agent, const char *str,
602 mesh_agent_cb_t cb, void *user_data)
604 struct l_dbus *dbus = dbus_get_bus();
605 struct l_dbus_message *msg;
606 struct l_dbus_message_builder *builder;
608 if (!l_queue_find(agents, simple_match, agent))
609 return MESH_ERROR_DOES_NOT_EXIST;
612 return MESH_ERROR_BUSY;
614 agent->req = create_request(MESH_AGENT_REQUEST_OUT_ALPHA,
616 msg = l_dbus_message_new_method_call(dbus, agent->owner, agent->path,
617 MESH_PROVISION_AGENT_INTERFACE,
620 builder = l_dbus_message_builder_new(msg);
621 l_dbus_message_builder_append_basic(builder, 's', str);
622 l_dbus_message_builder_finalize(builder);
623 l_dbus_message_builder_destroy(builder);
625 l_debug("Send DisplayString request to %s %s",
626 agent->owner, agent->path);
628 l_dbus_send_with_reply(dbus_get_bus(), msg, simple_reply, agent,
631 agent->req->msg = l_dbus_message_ref(msg);
633 return MESH_ERROR_NONE;
637 int mesh_agent_display_number(struct mesh_agent *agent, bool initiator,
638 uint8_t action, uint32_t count,
639 mesh_agent_cb_t cb, void *user_data)
641 const char *str_type;
642 agent_request_type_t type;
647 type = action + MESH_AGENT_REQUEST_PUSH;
649 if (type >= L_ARRAY_SIZE(cap_table))
650 return MESH_ERROR_INVALID_ARGS;
652 str_type = cap_table[type].action;
654 return output_request(agent, str_type, type, count, cb, user_data);
657 int mesh_agent_prompt_number(struct mesh_agent *agent, bool initiator,
659 mesh_agent_number_cb_t cb,
662 const char *str_type;
663 agent_request_type_t type;
668 type = action + MESH_AGENT_REQUEST_PUSH;
670 if (type >= L_ARRAY_SIZE(cap_table))
671 return MESH_ERROR_INVALID_ARGS;
673 str_type = cap_table[type].action;
675 return prompt_input(agent, str_type, type, true, cb, user_data);
678 int mesh_agent_prompt_alpha(struct mesh_agent *agent, bool initiator,
679 mesh_agent_key_cb_t cb, void *user_data)
682 return prompt_input(agent,
683 cap_table[MESH_AGENT_REQUEST_OUT_ALPHA].action,
684 MESH_AGENT_REQUEST_OUT_ALPHA, false, cb,
687 return prompt_input(agent,
688 cap_table[MESH_AGENT_REQUEST_IN_ALPHA].action,
689 MESH_AGENT_REQUEST_IN_ALPHA, false, cb,
693 int mesh_agent_request_static(struct mesh_agent *agent, mesh_agent_key_cb_t cb,
696 return prompt_input(agent, "static-oob", MESH_AGENT_REQUEST_STATIC_OOB,
697 false, cb, user_data);
700 int mesh_agent_request_private_key(struct mesh_agent *agent,
701 mesh_agent_key_cb_t cb, void *user_data)
703 return request_key(agent, MESH_AGENT_REQUEST_PRIVATE_KEY, cb,
708 int mesh_agent_request_public_key(struct mesh_agent *agent,
709 mesh_agent_key_cb_t cb, void *user_data)
711 return request_key(agent, MESH_AGENT_REQUEST_PUBLIC_KEY, cb,
715 void mesh_agent_cancel(struct mesh_agent *agent)
717 struct l_dbus *dbus = dbus_get_bus();
718 struct l_dbus_message *msg;
720 if (!l_queue_find(agents, simple_match, agent))
723 msg = l_dbus_message_new_method_call(dbus, agent->owner, agent->path,
724 MESH_PROVISION_AGENT_INTERFACE,
727 l_dbus_message_set_arguments(msg, "");
729 l_dbus_send(dbus, msg);