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 while (l_dbus_message_iter_next_entry(properties, &key, &variant)) {
169 if (!strcmp(key, "Capabilities")) {
170 parse_prov_caps(&agent->caps, &variant);
171 } else if (!strcmp(key, "URI")) {
172 l_dbus_message_iter_get_variant(&variant, "s",
174 /* TODO: compute hash */
175 } else if (!strcmp(key, "OutOfBandInfo")) {
176 parse_oob_info(&agent->caps, &variant);
181 static void agent_free(void *agent_data)
183 struct mesh_agent *agent = agent_data;
185 mesh_agent_cb_t simple_cb;
186 mesh_agent_key_cb_t key_cb;
187 mesh_agent_number_cb_t number_cb;
189 if (!l_queue_find(agents, simple_match, agent))
192 err = MESH_ERROR_DOES_NOT_EXIST;
194 if (agent->req && agent->req->cb) {
195 struct agent_request *req = agent->req;
198 case MESH_AGENT_REQUEST_PUSH:
199 case MESH_AGENT_REQUEST_TWIST:
200 case MESH_AGENT_REQUEST_IN_NUMERIC:
202 number_cb(req->user_data, err, 0);
204 case MESH_AGENT_REQUEST_IN_ALPHA:
205 case MESH_AGENT_REQUEST_STATIC_OOB:
206 case MESH_AGENT_REQUEST_PRIVATE_KEY:
207 case MESH_AGENT_REQUEST_PUBLIC_KEY:
209 key_cb(req->user_data, err, NULL, 0);
211 case MESH_AGENT_REQUEST_BLINK:
212 case MESH_AGENT_REQUEST_BEEP:
213 case MESH_AGENT_REQUEST_VIBRATE:
214 case MESH_AGENT_REQUEST_OUT_NUMERIC:
215 case MESH_AGENT_REQUEST_OUT_ALPHA:
216 case MESH_AGENT_REQUEST_CAPABILITIES:
217 simple_cb = agent->req->cb;
218 simple_cb(req->user_data, err);
223 l_dbus_message_unref(req->msg);
228 l_free(agent->owner);
231 void mesh_agent_remove(struct mesh_agent *agent)
233 if (!agent || !l_queue_find(agents, simple_match, agent))
237 l_queue_remove(agents, agent);
240 void mesh_agent_cleanup(void)
245 l_queue_destroy(agents, agent_free);
249 void mesh_agent_init(void)
252 agents = l_queue_new();
255 struct mesh_agent *mesh_agent_create(const char *path, const char *owner,
256 struct l_dbus_message_iter *properties)
258 struct mesh_agent *agent;
260 agent = l_new(struct mesh_agent, 1);
261 agent->owner = l_strdup(owner);
262 agent->path = l_strdup(path);
264 parse_properties(agent, properties);
266 l_queue_push_tail(agents, agent);
271 struct mesh_agent_prov_caps *mesh_agent_get_caps(struct mesh_agent *agent)
273 if (!agent || !l_queue_find(agents, simple_match, agent))
279 static struct agent_request *create_request(agent_request_type_t type,
280 void *cb, void *data)
282 struct agent_request *req;
284 req = l_new(struct agent_request, 1);
288 req->user_data = data;
293 static int get_reply_error(struct l_dbus_message *reply)
295 const char *name, *desc;
297 if (l_dbus_message_is_error(reply)) {
299 l_dbus_message_get_error(reply, &name, &desc);
300 l_error("Agent failed (%s), %s", name, desc);
301 return MESH_ERROR_FAILED;
304 return MESH_ERROR_NONE;
307 static void properties_reply(struct l_dbus_message *reply, void *user_data)
309 struct mesh_agent *agent = user_data;
310 struct agent_request *req;
312 struct l_dbus_message_iter properties;
315 if (!l_queue_find(agents, simple_match, agent) || !agent->req)
320 err = get_reply_error(reply);
322 if (err != MESH_ERROR_NONE)
325 if (!l_dbus_message_get_arguments(reply, "a{sv}", &properties)) {
326 err = MESH_ERROR_FAILED;
330 parse_properties(agent, &properties);
334 cb(req->user_data, err);
337 l_dbus_message_unref(req->msg);
342 void mesh_agent_refresh(struct mesh_agent *agent, mesh_agent_cb_t cb,
345 struct l_dbus *dbus = dbus_get_bus();
346 struct l_dbus_message *msg;
347 struct l_dbus_message_builder *builder;
349 agent->req = create_request(MESH_AGENT_REQUEST_CAPABILITIES, (void *)cb,
352 msg = l_dbus_message_new_method_call(dbus, agent->owner, agent->path,
353 L_DBUS_INTERFACE_PROPERTIES,
356 builder = l_dbus_message_builder_new(msg);
357 l_dbus_message_builder_append_basic(builder, 's',
358 MESH_PROVISION_AGENT_INTERFACE);
359 l_dbus_message_builder_finalize(builder);
360 l_dbus_message_builder_destroy(builder);
362 l_dbus_send_with_reply(dbus_get_bus(), msg, properties_reply, agent,
365 agent->req->msg = l_dbus_message_ref(msg);
369 static void simple_reply(struct l_dbus_message *reply, void *user_data)
371 struct mesh_agent *agent = user_data;
372 struct agent_request *req;
376 if (!l_queue_find(agents, simple_match, agent) || !agent->req)
381 err = get_reply_error(reply);
383 l_dbus_message_unref(req->msg);
387 cb(req->user_data, err);
394 static void numeric_reply(struct l_dbus_message *reply, void *user_data)
396 struct mesh_agent *agent = user_data;
397 struct agent_request *req;
398 mesh_agent_number_cb_t cb;
402 if (!l_queue_find(agents, simple_match, agent) || !agent->req)
407 err = get_reply_error(reply);
411 if (err == MESH_ERROR_NONE) {
412 if (!l_dbus_message_get_arguments(reply, "u", &count)) {
413 l_error("Failed to retrieve numeric input");
414 err = MESH_ERROR_FAILED;
418 l_dbus_message_unref(req->msg);
422 cb(req->user_data, err, count);
429 static void key_reply(struct l_dbus_message *reply, void *user_data)
431 struct mesh_agent *agent = user_data;
432 struct agent_request *req;
433 mesh_agent_key_cb_t cb;
434 struct l_dbus_message_iter iter_array;
435 uint32_t n = 0, expected_len = 0;
439 if (!l_queue_find(agents, simple_match, agent) || !agent->req)
444 err = get_reply_error(reply);
446 if (err != MESH_ERROR_NONE)
449 if (!l_dbus_message_get_arguments(reply, "ay", &iter_array)) {
450 l_error("Failed to retrieve key input");
451 err = MESH_ERROR_FAILED;
455 if (!l_dbus_message_iter_get_fixed_array(&iter_array, &buf, &n)) {
456 l_error("Failed to retrieve key input");
457 err = MESH_ERROR_FAILED;
461 if (req->type == MESH_AGENT_REQUEST_PRIVATE_KEY)
463 else if (req->type == MESH_AGENT_REQUEST_PUBLIC_KEY)
468 if (n != expected_len) {
469 l_error("Bad response length: %u (need %u)", n, expected_len);
470 err = MESH_ERROR_FAILED;
477 cb(req->user_data, err, buf, n);
480 l_dbus_message_unref(req->msg);
486 static int output_request(struct mesh_agent *agent, const char *action,
487 agent_request_type_t type, uint32_t cnt,
488 void *cb, void *user_data)
490 struct l_dbus *dbus = dbus_get_bus();
491 struct l_dbus_message *msg;
492 struct l_dbus_message_builder *builder;
494 if (!l_queue_find(agents, simple_match, agent))
495 return MESH_ERROR_DOES_NOT_EXIST;
498 return MESH_ERROR_BUSY;
500 agent->req = create_request(type, cb, user_data);
501 msg = l_dbus_message_new_method_call(dbus, agent->owner, agent->path,
502 MESH_PROVISION_AGENT_INTERFACE,
505 builder = l_dbus_message_builder_new(msg);
506 l_dbus_message_builder_append_basic(builder, 's', action);
507 l_dbus_message_builder_append_basic(builder, 'u', &cnt);
508 l_dbus_message_builder_finalize(builder);
509 l_dbus_message_builder_destroy(builder);
511 l_debug("Send DisplayNumeric request to %s %s",
512 agent->owner, agent->path);
514 l_dbus_send_with_reply(dbus_get_bus(), msg, simple_reply, agent,
517 agent->req->msg = l_dbus_message_ref(msg);
519 return MESH_ERROR_NONE;
522 static int prompt_input(struct mesh_agent *agent, const char *action,
523 agent_request_type_t type, bool numeric,
524 void *cb, void *user_data)
526 struct l_dbus *dbus = dbus_get_bus();
527 struct l_dbus_message *msg;
528 struct l_dbus_message_builder *builder;
529 const char *method_name;
530 l_dbus_message_func_t reply_cb;
532 if (!l_queue_find(agents, simple_match, agent))
533 return MESH_ERROR_DOES_NOT_EXIST;
536 return MESH_ERROR_BUSY;
538 agent->req = create_request(type, cb, user_data);
540 method_name = numeric ? "PromptNumeric" : "PromptStatic";
542 msg = l_dbus_message_new_method_call(dbus, agent->owner,
544 MESH_PROVISION_AGENT_INTERFACE,
547 builder = l_dbus_message_builder_new(msg);
548 l_dbus_message_builder_append_basic(builder, 's', action);
549 l_dbus_message_builder_finalize(builder);
550 l_dbus_message_builder_destroy(builder);
552 l_debug("Send \"%s\" input request to %s %s", action,
553 agent->owner, agent->path);
555 reply_cb = numeric ? numeric_reply : key_reply;
557 l_dbus_send_with_reply(dbus_get_bus(), msg, reply_cb, agent, NULL);
559 agent->req->msg = l_dbus_message_ref(msg);
561 return MESH_ERROR_NONE;
564 static int request_key(struct mesh_agent *agent,
565 agent_request_type_t type,
566 void *cb, void *user_data)
568 struct l_dbus *dbus = dbus_get_bus();
569 struct l_dbus_message *msg;
570 const char *method_name;
572 if (!l_queue_find(agents, simple_match, agent))
573 return MESH_ERROR_DOES_NOT_EXIST;
576 return MESH_ERROR_BUSY;
578 agent->req = create_request(type, cb, user_data);
580 method_name = (type == MESH_AGENT_REQUEST_PRIVATE_KEY) ?
581 "PrivateKey" : "PublicKey";
583 msg = l_dbus_message_new_method_call(dbus, agent->owner,
585 MESH_PROVISION_AGENT_INTERFACE,
588 l_dbus_message_set_arguments(msg, "");
590 l_debug("Send key request to %s %s", agent->owner, agent->path);
592 l_dbus_send_with_reply(dbus_get_bus(), msg, key_reply, agent, NULL);
594 agent->req->msg = l_dbus_message_ref(msg);
596 return MESH_ERROR_NONE;
599 int mesh_agent_display_string(struct mesh_agent *agent, const char *str,
600 mesh_agent_cb_t cb, void *user_data)
602 struct l_dbus *dbus = dbus_get_bus();
603 struct l_dbus_message *msg;
604 struct l_dbus_message_builder *builder;
606 if (!l_queue_find(agents, simple_match, agent))
607 return MESH_ERROR_DOES_NOT_EXIST;
610 return MESH_ERROR_BUSY;
612 agent->req = create_request(MESH_AGENT_REQUEST_OUT_ALPHA,
614 msg = l_dbus_message_new_method_call(dbus, agent->owner, agent->path,
615 MESH_PROVISION_AGENT_INTERFACE,
618 builder = l_dbus_message_builder_new(msg);
619 l_dbus_message_builder_append_basic(builder, 's', str);
620 l_dbus_message_builder_finalize(builder);
621 l_dbus_message_builder_destroy(builder);
623 l_debug("Send DisplayString request to %s %s",
624 agent->owner, agent->path);
626 l_dbus_send_with_reply(dbus_get_bus(), msg, simple_reply, agent,
629 agent->req->msg = l_dbus_message_ref(msg);
631 return MESH_ERROR_NONE;
635 int mesh_agent_display_number(struct mesh_agent *agent, bool initiator,
636 uint8_t action, uint32_t count,
637 mesh_agent_cb_t cb, void *user_data)
639 const char *str_type;
640 agent_request_type_t type;
645 type = action + MESH_AGENT_REQUEST_PUSH;
647 if (type >= L_ARRAY_SIZE(cap_table))
648 return MESH_ERROR_INVALID_ARGS;
650 str_type = cap_table[type].action;
652 return output_request(agent, str_type, type, count, cb, user_data);
655 int mesh_agent_prompt_number(struct mesh_agent *agent, bool initiator,
657 mesh_agent_number_cb_t cb,
660 const char *str_type;
661 agent_request_type_t type;
666 type = action + MESH_AGENT_REQUEST_PUSH;
668 if (type >= L_ARRAY_SIZE(cap_table))
669 return MESH_ERROR_INVALID_ARGS;
671 str_type = cap_table[type].action;
673 return prompt_input(agent, str_type, type, true, cb, user_data);
676 int mesh_agent_prompt_alpha(struct mesh_agent *agent, bool initiator,
677 mesh_agent_key_cb_t cb, void *user_data)
680 return prompt_input(agent,
681 cap_table[MESH_AGENT_REQUEST_OUT_ALPHA].action,
682 MESH_AGENT_REQUEST_OUT_ALPHA, false, cb,
685 return prompt_input(agent,
686 cap_table[MESH_AGENT_REQUEST_IN_ALPHA].action,
687 MESH_AGENT_REQUEST_IN_ALPHA, false, cb,
691 int mesh_agent_request_static(struct mesh_agent *agent, mesh_agent_key_cb_t cb,
694 return prompt_input(agent, "static-oob", MESH_AGENT_REQUEST_STATIC_OOB,
695 false, cb, user_data);
698 int mesh_agent_request_private_key(struct mesh_agent *agent,
699 mesh_agent_key_cb_t cb, void *user_data)
701 return request_key(agent, MESH_AGENT_REQUEST_PRIVATE_KEY, cb,
706 int mesh_agent_request_public_key(struct mesh_agent *agent,
707 mesh_agent_key_cb_t cb, void *user_data)
709 return request_key(agent, MESH_AGENT_REQUEST_PUBLIC_KEY, cb,
713 void mesh_agent_cancel(struct mesh_agent *agent)
715 struct l_dbus *dbus = dbus_get_bus();
716 struct l_dbus_message *msg;
718 if (!l_queue_find(agents, simple_match, agent))
721 msg = l_dbus_message_new_method_call(dbus, agent->owner, agent->path,
722 MESH_PROVISION_AGENT_INTERFACE,
725 l_dbus_message_set_arguments(msg, "");
727 l_dbus_send(dbus, msg);