26ccc3ec88b9d067553b71f5d8dc89a893b0f592
[platform/upstream/bluez.git] / mesh / agent.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2018-2019  Intel Corporation. All rights reserved.
6  *
7  *
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.
12  *
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.
17  *
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <ell/ell.h>
25
26 #include "mesh/mesh.h"
27 #include "mesh/error.h"
28 #include "mesh/dbus.h"
29 #include "mesh/agent.h"
30
31 typedef enum {
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;
46
47 struct agent_request {
48         agent_request_type_t type;
49         struct l_dbus_message *msg;
50         void *cb;
51         void *user_data;
52 };
53
54 struct mesh_agent {
55         char *path;
56         char *owner;
57         struct mesh_agent_prov_caps caps;
58         struct agent_request *req;
59 };
60
61 struct prov_action {
62         const char *action;
63         uint16_t output;
64         uint16_t input;
65         uint8_t size;
66 };
67
68 struct oob_info {
69         const char *oob;
70         uint16_t mask;
71 };
72
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}
83 };
84
85 static struct oob_info oob_table[] = {
86         {"other", 0x0001},
87         {"uri", 0x0002},
88         {"machine-code-2d", 0x0004},
89         {"barcode", 0x0008},
90         {"nfc", 0x0010},
91         {"number", 0x0020},
92         {"string", 0x0040},
93         {"on-box", 0x0800},
94         {"in-box", 0x1000},
95         {"on-paper", 0x2000},
96         {"in-manual", 0x4000},
97         {"on-device", 0x8000}
98 };
99
100 static struct l_queue *agents;
101
102 static bool simple_match(const void *a, const void *b)
103 {
104         return a == b;
105 }
106
107 static void parse_prov_caps(struct mesh_agent_prov_caps *caps,
108                                 struct l_dbus_message_iter *property)
109 {
110         struct l_dbus_message_iter iter_caps;
111         const char *str;
112         uint32_t i;
113
114         if (!l_dbus_message_iter_get_variant(property, "as", &iter_caps))
115                 return;
116
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))
120                                 continue;
121
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;
126
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;
131
132                         break;
133                 }
134
135                 if (!strcmp(str, "public-oob"))
136                         caps->pub_type = 1;
137                 else if (!strcmp(str, "static-oob"))
138                         caps->static_type = 1;
139         }
140
141 }
142
143 static void parse_oob_info(struct mesh_agent_prov_caps *caps,
144                                 struct l_dbus_message_iter *property)
145 {
146         struct l_dbus_message_iter iter_oob;
147         uint32_t i;
148         const char *str;
149
150         if (!l_dbus_message_iter_get_variant(property, "as", &iter_oob))
151                 return;
152
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))
156                                 continue;
157                         caps->oob_info |= oob_table[i].mask;
158                 }
159         }
160 }
161
162 static void parse_properties(struct mesh_agent *agent,
163                                         struct l_dbus_message_iter *properties)
164 {
165         const char *key, *uri_string;
166         struct l_dbus_message_iter variant;
167
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",
173                                                                 &uri_string);
174                         /* TODO: compute hash */
175                 } else if (!strcmp(key, "OutOfBandInfo")) {
176                         parse_oob_info(&agent->caps, &variant);
177                 }
178         }
179 }
180
181 static void agent_free(void *agent_data)
182 {
183         struct mesh_agent *agent = agent_data;
184         int err;
185         mesh_agent_cb_t simple_cb;
186         mesh_agent_key_cb_t key_cb;
187         mesh_agent_number_cb_t number_cb;
188
189         if (!l_queue_find(agents, simple_match, agent))
190                 return;
191
192         err = MESH_ERROR_DOES_NOT_EXIST;
193
194         if (agent->req && agent->req->cb) {
195                 struct agent_request *req = agent->req;
196
197                 switch (req->type) {
198                 case MESH_AGENT_REQUEST_PUSH:
199                 case MESH_AGENT_REQUEST_TWIST:
200                 case MESH_AGENT_REQUEST_IN_NUMERIC:
201                         number_cb = req->cb;
202                         number_cb(req->user_data, err, 0);
203                         break;
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:
208                         key_cb = req->cb;
209                         key_cb(req->user_data, err, NULL, 0);
210                         break;
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);
219                 default:
220                         break;
221                 }
222
223                 l_dbus_message_unref(req->msg);
224                 l_free(req);
225         }
226
227         l_free(agent->path);
228         l_free(agent->owner);
229 }
230
231 void mesh_agent_remove(struct mesh_agent *agent)
232 {
233         if (!agent || !l_queue_find(agents, simple_match, agent))
234                 return;
235
236         agent_free(agent);
237         l_queue_remove(agents, agent);
238 }
239
240 void mesh_agent_cleanup(void)
241 {
242         if (!agents)
243                 return;
244
245         l_queue_destroy(agents, agent_free);
246
247 }
248
249 void mesh_agent_init(void)
250 {
251         if (!agents)
252                 agents = l_queue_new();
253 }
254
255 struct mesh_agent *mesh_agent_create(const char *path, const char *owner,
256                                         struct l_dbus_message_iter *properties)
257 {
258         struct mesh_agent *agent;
259
260         agent = l_new(struct mesh_agent, 1);
261         agent->owner = l_strdup(owner);
262         agent->path = l_strdup(path);
263
264         parse_properties(agent, properties);
265
266         l_queue_push_tail(agents, agent);
267
268         return agent;
269 }
270
271 struct mesh_agent_prov_caps *mesh_agent_get_caps(struct mesh_agent *agent)
272 {
273         if (!agent || !l_queue_find(agents, simple_match, agent))
274                 return NULL;
275
276         return &agent->caps;
277 }
278
279 static struct agent_request *create_request(agent_request_type_t type,
280                                                 void *cb, void *data)
281 {
282         struct agent_request *req;
283
284         req = l_new(struct agent_request, 1);
285
286         req->type = type;
287         req->cb = cb;
288         req->user_data = data;
289
290         return req;
291 }
292
293 static int get_reply_error(struct l_dbus_message *reply)
294 {
295         const char *name, *desc;
296
297         if (l_dbus_message_is_error(reply)) {
298
299                 l_dbus_message_get_error(reply, &name, &desc);
300                 l_error("Agent failed (%s), %s", name, desc);
301                 return MESH_ERROR_FAILED;
302         }
303
304         return MESH_ERROR_NONE;
305 }
306
307 static void properties_reply(struct l_dbus_message *reply, void *user_data)
308 {
309         struct mesh_agent *agent = user_data;
310         struct agent_request *req;
311         mesh_agent_cb_t cb;
312         struct l_dbus_message_iter properties;
313         int err;
314
315         if (!l_queue_find(agents, simple_match, agent) || !agent->req)
316                 return;
317
318         req = agent->req;
319
320         err = get_reply_error(reply);
321
322         if (err != MESH_ERROR_NONE)
323                 goto fail;
324
325         if (!l_dbus_message_get_arguments(reply, "a{sv}", &properties)) {
326                 err = MESH_ERROR_FAILED;
327                 goto fail;
328         }
329
330         parse_properties(agent, &properties);
331 fail:
332         if (req->cb) {
333                 cb = req->cb;
334                 cb(req->user_data, err);
335         }
336
337         l_dbus_message_unref(req->msg);
338         l_free(req);
339         agent->req = NULL;
340 }
341
342 void mesh_agent_refresh(struct mesh_agent *agent, mesh_agent_cb_t cb,
343                                                         void *user_data)
344 {
345         struct l_dbus *dbus = dbus_get_bus();
346         struct l_dbus_message *msg;
347         struct l_dbus_message_builder *builder;
348
349         agent->req = create_request(MESH_AGENT_REQUEST_CAPABILITIES, (void *)cb,
350                                                                 user_data);
351
352         msg = l_dbus_message_new_method_call(dbus, agent->owner, agent->path,
353                                                 L_DBUS_INTERFACE_PROPERTIES,
354                                                 "GetAll");
355
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);
361
362         l_dbus_send_with_reply(dbus_get_bus(), msg, properties_reply, agent,
363                                                                         NULL);
364
365         agent->req->msg = l_dbus_message_ref(msg);
366 }
367
368
369 static void simple_reply(struct l_dbus_message *reply, void *user_data)
370 {
371         struct mesh_agent *agent = user_data;
372         struct agent_request *req;
373         mesh_agent_cb_t cb;
374         int err;
375
376         if (!l_queue_find(agents, simple_match, agent) || !agent->req)
377                 return;
378
379         req = agent->req;
380
381         err = get_reply_error(reply);
382
383         l_dbus_message_unref(req->msg);
384
385         if (req->cb) {
386                 cb = req->cb;
387                 cb(req->user_data, err);
388         }
389
390         l_free(req);
391         agent->req = NULL;
392 }
393
394 static void numeric_reply(struct l_dbus_message *reply, void *user_data)
395 {
396         struct mesh_agent *agent = user_data;
397         struct agent_request *req;
398         mesh_agent_number_cb_t cb;
399         uint32_t count;
400         int err;
401
402         if (!l_queue_find(agents, simple_match, agent) || !agent->req)
403                 return;
404
405         req = agent->req;
406
407         err = get_reply_error(reply);
408
409         count = 0;
410
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;
415                 }
416         }
417
418         l_dbus_message_unref(req->msg);
419
420         if (req->cb) {
421                 cb = req->cb;
422                 cb(req->user_data, err, count);
423         }
424
425         l_free(req);
426         agent->req = NULL;
427 }
428
429 static void key_reply(struct l_dbus_message *reply, void *user_data)
430 {
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;
436         uint8_t *buf;
437         int err;
438
439         if (!l_queue_find(agents, simple_match, agent) || !agent->req)
440                 return;
441
442         req = agent->req;
443
444         err = get_reply_error(reply);
445
446         if (err != MESH_ERROR_NONE)
447                 goto done;
448
449         if (!l_dbus_message_get_arguments(reply, "ay", &iter_array)) {
450                 l_error("Failed to retrieve key input");
451                 err = MESH_ERROR_FAILED;
452                 goto done;
453         }
454
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;
458                 goto done;
459         }
460
461         if (req->type == MESH_AGENT_REQUEST_PRIVATE_KEY)
462                 expected_len = 32;
463         else if (req->type == MESH_AGENT_REQUEST_PUBLIC_KEY)
464                 expected_len = 64;
465         else
466                 expected_len = 16;
467
468         if (n != expected_len) {
469                 l_error("Bad response length: %u (need %u)", n, expected_len);
470                 err = MESH_ERROR_FAILED;
471                 n = 0;
472         }
473
474 done:
475         if (req->cb) {
476                 cb = req->cb;
477                 cb(req->user_data, err, buf, n);
478         }
479
480         l_dbus_message_unref(req->msg);
481
482         l_free(req);
483         agent->req = NULL;
484 }
485
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)
489 {
490         struct l_dbus *dbus = dbus_get_bus();
491         struct l_dbus_message *msg;
492         struct l_dbus_message_builder *builder;
493
494         if (!l_queue_find(agents, simple_match, agent))
495                 return MESH_ERROR_DOES_NOT_EXIST;
496
497         if (agent->req)
498                 return MESH_ERROR_BUSY;
499
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,
503                                                 "DisplayNumeric");
504
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);
510
511         l_debug("Send DisplayNumeric request to %s %s",
512                                                 agent->owner, agent->path);
513
514         l_dbus_send_with_reply(dbus_get_bus(), msg, simple_reply, agent,
515                                                                         NULL);
516
517         agent->req->msg = l_dbus_message_ref(msg);
518
519         return MESH_ERROR_NONE;
520 }
521
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)
525 {
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;
531
532         if (!l_queue_find(agents, simple_match, agent))
533                 return MESH_ERROR_DOES_NOT_EXIST;
534
535         if (agent->req)
536                 return MESH_ERROR_BUSY;
537
538         agent->req = create_request(type, cb, user_data);
539
540         method_name = numeric ? "PromptNumeric" : "PromptStatic";
541
542         msg = l_dbus_message_new_method_call(dbus, agent->owner,
543                                                 agent->path,
544                                                 MESH_PROVISION_AGENT_INTERFACE,
545                                                 method_name);
546
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);
551
552         l_debug("Send \"%s\" input request to %s %s", action,
553                                                 agent->owner, agent->path);
554
555         reply_cb = numeric ? numeric_reply : key_reply;
556
557         l_dbus_send_with_reply(dbus_get_bus(), msg, reply_cb, agent, NULL);
558
559         agent->req->msg = l_dbus_message_ref(msg);
560
561         return MESH_ERROR_NONE;
562 }
563
564 static int request_key(struct mesh_agent *agent,
565                                         agent_request_type_t type,
566                                         void *cb, void *user_data)
567 {
568         struct l_dbus *dbus = dbus_get_bus();
569         struct l_dbus_message *msg;
570         const char *method_name;
571
572         if (!l_queue_find(agents, simple_match, agent))
573                 return MESH_ERROR_DOES_NOT_EXIST;
574
575         if (agent->req)
576                 return MESH_ERROR_BUSY;
577
578         agent->req = create_request(type, cb, user_data);
579
580         method_name = (type == MESH_AGENT_REQUEST_PRIVATE_KEY) ?
581                                                 "PrivateKey" : "PublicKey";
582
583         msg = l_dbus_message_new_method_call(dbus, agent->owner,
584                                                 agent->path,
585                                                 MESH_PROVISION_AGENT_INTERFACE,
586                                                 method_name);
587
588         l_dbus_message_set_arguments(msg, "");
589
590         l_debug("Send key request to %s %s", agent->owner, agent->path);
591
592         l_dbus_send_with_reply(dbus_get_bus(), msg, key_reply, agent, NULL);
593
594         agent->req->msg = l_dbus_message_ref(msg);
595
596         return MESH_ERROR_NONE;
597 }
598
599 int mesh_agent_display_string(struct mesh_agent *agent, const char *str,
600                                 mesh_agent_cb_t cb, void *user_data)
601 {
602         struct l_dbus *dbus = dbus_get_bus();
603         struct l_dbus_message *msg;
604         struct l_dbus_message_builder *builder;
605
606         if (!l_queue_find(agents, simple_match, agent))
607                 return MESH_ERROR_DOES_NOT_EXIST;
608
609         if (agent->req)
610                 return MESH_ERROR_BUSY;
611
612         agent->req = create_request(MESH_AGENT_REQUEST_OUT_ALPHA,
613                                                                 cb, user_data);
614         msg = l_dbus_message_new_method_call(dbus, agent->owner, agent->path,
615                                                 MESH_PROVISION_AGENT_INTERFACE,
616                                                 "DisplayString");
617
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);
622
623         l_debug("Send DisplayString request to %s %s",
624                                                 agent->owner, agent->path);
625
626         l_dbus_send_with_reply(dbus_get_bus(), msg, simple_reply, agent,
627                                                                         NULL);
628
629         agent->req->msg = l_dbus_message_ref(msg);
630
631         return MESH_ERROR_NONE;
632
633 }
634
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)
638 {
639         const char *str_type;
640         agent_request_type_t type;
641
642         type = action;
643
644         if (initiator)
645                 type = action + MESH_AGENT_REQUEST_PUSH;
646
647         if (type >= L_ARRAY_SIZE(cap_table))
648                 return MESH_ERROR_INVALID_ARGS;
649
650         str_type = cap_table[type].action;
651
652         return output_request(agent, str_type, type, count, cb, user_data);
653 }
654
655 int mesh_agent_prompt_number(struct mesh_agent *agent, bool initiator,
656                                                 uint8_t action,
657                                                 mesh_agent_number_cb_t cb,
658                                                 void *user_data)
659 {
660         const char *str_type;
661         agent_request_type_t type;
662
663         type = action;
664
665         if (!initiator)
666                 type = action + MESH_AGENT_REQUEST_PUSH;
667
668         if (type >= L_ARRAY_SIZE(cap_table))
669                 return MESH_ERROR_INVALID_ARGS;
670
671         str_type = cap_table[type].action;
672
673         return prompt_input(agent, str_type, type, true, cb, user_data);
674 }
675
676 int mesh_agent_prompt_alpha(struct mesh_agent *agent, bool initiator,
677                                         mesh_agent_key_cb_t cb, void *user_data)
678 {
679         if (initiator)
680                 return prompt_input(agent,
681                                 cap_table[MESH_AGENT_REQUEST_OUT_ALPHA].action,
682                                 MESH_AGENT_REQUEST_OUT_ALPHA, false, cb,
683                                 user_data);
684         else
685                 return prompt_input(agent,
686                                 cap_table[MESH_AGENT_REQUEST_IN_ALPHA].action,
687                                 MESH_AGENT_REQUEST_IN_ALPHA, false, cb,
688                                 user_data);
689 }
690
691 int mesh_agent_request_static(struct mesh_agent *agent, mesh_agent_key_cb_t cb,
692                                                                 void *user_data)
693 {
694         return prompt_input(agent, "static-oob", MESH_AGENT_REQUEST_STATIC_OOB,
695                                                         false, cb, user_data);
696 }
697
698 int mesh_agent_request_private_key(struct mesh_agent *agent,
699                                 mesh_agent_key_cb_t cb, void *user_data)
700 {
701         return request_key(agent, MESH_AGENT_REQUEST_PRIVATE_KEY, cb,
702                                                                 user_data);
703
704 }
705
706 int mesh_agent_request_public_key(struct mesh_agent *agent,
707                                 mesh_agent_key_cb_t cb, void *user_data)
708 {
709         return request_key(agent, MESH_AGENT_REQUEST_PUBLIC_KEY, cb,
710                                                                 user_data);
711 }
712
713 void mesh_agent_cancel(struct mesh_agent *agent)
714 {
715         struct l_dbus *dbus = dbus_get_bus();
716         struct l_dbus_message *msg;
717
718         if (!l_queue_find(agents, simple_match, agent))
719                 return;
720
721         msg = l_dbus_message_new_method_call(dbus, agent->owner, agent->path,
722                                                 MESH_PROVISION_AGENT_INTERFACE,
723                                                 "Cancel");
724
725         l_dbus_message_set_arguments(msg, "");
726
727         l_dbus_send(dbus, msg);
728 }