db.c revision 1.6 1 1.6 thorpej /* $NetBSD: db.c,v 1.6 2020/06/07 00:12:00 thorpej Exp $ */
2 1.1 plunky
3 1.1 plunky /*-
4 1.1 plunky * Copyright (c) 2006 Itronix Inc.
5 1.1 plunky * All rights reserved.
6 1.1 plunky *
7 1.1 plunky * Written by Iain Hibbert for Itronix Inc.
8 1.1 plunky *
9 1.1 plunky * Redistribution and use in source and binary forms, with or without
10 1.1 plunky * modification, are permitted provided that the following conditions
11 1.1 plunky * are met:
12 1.1 plunky * 1. Redistributions of source code must retain the above copyright
13 1.1 plunky * notice, this list of conditions and the following disclaimer.
14 1.1 plunky * 2. Redistributions in binary form must reproduce the above copyright
15 1.1 plunky * notice, this list of conditions and the following disclaimer in the
16 1.1 plunky * documentation and/or other materials provided with the distribution.
17 1.1 plunky * 3. The name of Itronix Inc. may not be used to endorse
18 1.1 plunky * or promote products derived from this software without specific
19 1.1 plunky * prior written permission.
20 1.1 plunky *
21 1.1 plunky * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
22 1.1 plunky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 1.1 plunky * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 1.1 plunky * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
25 1.1 plunky * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 1.1 plunky * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 1.1 plunky * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28 1.1 plunky * ON ANY THEORY OF LIABILITY, WHETHER IN
29 1.1 plunky * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 1.1 plunky * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 1.1 plunky * POSSIBILITY OF SUCH DAMAGE.
32 1.1 plunky */
33 1.1 plunky
34 1.1 plunky #include <sys/cdefs.h>
35 1.6 thorpej __RCSID("$NetBSD: db.c,v 1.6 2020/06/07 00:12:00 thorpej Exp $");
36 1.1 plunky
37 1.1 plunky #include <bluetooth.h>
38 1.1 plunky #include <err.h>
39 1.1 plunky #include <stdlib.h>
40 1.4 pavel #include <stdbool.h>
41 1.1 plunky
42 1.1 plunky #include <prop/proplib.h>
43 1.1 plunky
44 1.1 plunky #include <dev/bluetooth/btdev.h>
45 1.3 plunky #include <dev/bluetooth/bthidev.h>
46 1.1 plunky #include <dev/bluetooth/btsco.h>
47 1.1 plunky
48 1.1 plunky #include "btdevctl.h"
49 1.1 plunky
50 1.1 plunky #define BTDEVCTL_PLIST "/var/db/btdevctl.plist"
51 1.3 plunky #define BTDEVCTL_VERSION 2
52 1.1 plunky
53 1.1 plunky static prop_dictionary_t db = NULL;
54 1.4 pavel static bool db_flush = true; /* write db on set */
55 1.1 plunky
56 1.1 plunky static void db_update0(void);
57 1.3 plunky static void db_update1(void);
58 1.1 plunky
59 1.1 plunky /*
60 1.1 plunky * lookup laddr/raddr/service in database and return dictionary
61 1.1 plunky */
62 1.1 plunky prop_dictionary_t
63 1.1 plunky db_get(bdaddr_t *laddr, bdaddr_t *raddr, const char *service)
64 1.1 plunky {
65 1.1 plunky prop_dictionary_t ldev, rdev, dev;
66 1.1 plunky prop_object_t obj;
67 1.1 plunky
68 1.1 plunky if (db == NULL) {
69 1.1 plunky db = prop_dictionary_internalize_from_file(BTDEVCTL_PLIST);
70 1.1 plunky if (db == NULL) {
71 1.1 plunky db = prop_dictionary_create();
72 1.1 plunky if (db == NULL)
73 1.1 plunky err(EXIT_FAILURE, "prop_dictionary_create");
74 1.1 plunky
75 1.1 plunky return NULL;
76 1.1 plunky } else {
77 1.1 plunky obj = prop_dictionary_get(db, "btdevctl-version");
78 1.6 thorpej switch(prop_number_signed_value(obj)) {
79 1.3 plunky case 0: db_update0();
80 1.5 mrg /* FALLTHROUGH */
81 1.3 plunky case 1: db_update1();
82 1.5 mrg /* FALLTHROUGH */
83 1.1 plunky case BTDEVCTL_VERSION:
84 1.1 plunky break;
85 1.1 plunky
86 1.1 plunky default:
87 1.1 plunky errx(EXIT_FAILURE, "unknown btdevctl-version");
88 1.1 plunky }
89 1.1 plunky }
90 1.1 plunky }
91 1.1 plunky
92 1.1 plunky ldev = prop_dictionary_get(db, bt_ntoa(laddr, NULL));
93 1.1 plunky if (prop_object_type(ldev) != PROP_TYPE_DICTIONARY)
94 1.1 plunky return NULL;
95 1.1 plunky
96 1.1 plunky rdev = prop_dictionary_get(ldev, bt_ntoa(raddr, NULL));
97 1.1 plunky if (prop_object_type(rdev) != PROP_TYPE_DICTIONARY)
98 1.1 plunky return NULL;
99 1.1 plunky
100 1.1 plunky dev = prop_dictionary_get(rdev, service);
101 1.1 plunky if (prop_object_type(dev) != PROP_TYPE_DICTIONARY)
102 1.1 plunky return NULL;
103 1.1 plunky
104 1.1 plunky return dev;
105 1.1 plunky }
106 1.1 plunky
107 1.1 plunky /*
108 1.1 plunky * store dictionary in database at laddr/raddr/service
109 1.1 plunky */
110 1.1 plunky int
111 1.1 plunky db_set(prop_dictionary_t dev, bdaddr_t *laddr, bdaddr_t *raddr, const char *service)
112 1.1 plunky {
113 1.1 plunky prop_dictionary_t ldev, rdev;
114 1.1 plunky
115 1.1 plunky ldev = prop_dictionary_get(db, bt_ntoa(laddr, NULL));
116 1.1 plunky if (ldev == NULL) {
117 1.1 plunky ldev = prop_dictionary_create();
118 1.1 plunky if (ldev == NULL)
119 1.1 plunky return 0;
120 1.1 plunky
121 1.1 plunky if (!prop_dictionary_set(db, bt_ntoa(laddr, NULL), ldev))
122 1.1 plunky return 0;
123 1.1 plunky
124 1.1 plunky prop_object_release(ldev);
125 1.1 plunky }
126 1.1 plunky
127 1.1 plunky rdev = prop_dictionary_get(ldev, bt_ntoa(raddr, NULL));
128 1.1 plunky if (rdev == NULL) {
129 1.1 plunky rdev = prop_dictionary_create();
130 1.1 plunky if (rdev == NULL)
131 1.1 plunky return 0;
132 1.1 plunky
133 1.1 plunky if (!prop_dictionary_set(ldev, bt_ntoa(raddr, NULL), rdev))
134 1.1 plunky return 0;
135 1.1 plunky
136 1.1 plunky prop_object_release(rdev);
137 1.1 plunky }
138 1.1 plunky
139 1.1 plunky if (!prop_dictionary_set(rdev, service, dev))
140 1.1 plunky return 0;
141 1.1 plunky
142 1.4 pavel if (db_flush == true) {
143 1.6 thorpej if (!prop_dictionary_set_int(db, "btdevctl-version",
144 1.6 thorpej BTDEVCTL_VERSION))
145 1.6 thorpej err(EXIT_FAILURE, "prop_dictionary_set_int");
146 1.1 plunky
147 1.1 plunky if (!prop_dictionary_externalize_to_file(db, BTDEVCTL_PLIST))
148 1.1 plunky warn("%s", BTDEVCTL_PLIST);
149 1.1 plunky }
150 1.1 plunky
151 1.1 plunky return 1;
152 1.1 plunky }
153 1.1 plunky
154 1.1 plunky /*
155 1.1 plunky * update database from version 0. This was a flat file using
156 1.1 plunky * btdevN as an index, and local-bdaddr and remote-bdaddr stored
157 1.1 plunky * as data objects. Step through and add them to the new dictionary.
158 1.1 plunky * We have to generate the service, but only HID, HF and HSET
159 1.1 plunky * were supported, so thats not too difficult.
160 1.1 plunky */
161 1.1 plunky static void
162 1.1 plunky db_update0(void)
163 1.1 plunky {
164 1.1 plunky prop_dictionary_t old, dev;
165 1.1 plunky prop_dictionary_keysym_t key;
166 1.1 plunky prop_object_iterator_t iter;
167 1.1 plunky prop_object_t obj;
168 1.1 plunky bdaddr_t laddr, raddr;
169 1.2 plunky const char *service;
170 1.1 plunky
171 1.4 pavel db_flush = false; /* no write on set */
172 1.1 plunky old = db;
173 1.1 plunky
174 1.1 plunky db = prop_dictionary_create();
175 1.1 plunky if (db == NULL)
176 1.1 plunky err(EXIT_FAILURE, "prop_dictionary_create");
177 1.1 plunky
178 1.1 plunky iter = prop_dictionary_iterator(old);
179 1.1 plunky if (iter == NULL)
180 1.1 plunky err(EXIT_FAILURE, "prop_dictionary_iterator");
181 1.1 plunky
182 1.1 plunky while ((key = prop_object_iterator_next(iter)) != NULL) {
183 1.1 plunky dev = prop_dictionary_get_keysym(old, key);
184 1.1 plunky if (prop_object_type(dev) != PROP_TYPE_DICTIONARY)
185 1.1 plunky errx(EXIT_FAILURE, "invalid device dictionary");
186 1.1 plunky
187 1.1 plunky obj = prop_dictionary_get(dev, BTDEVladdr);
188 1.1 plunky if (prop_data_size(obj) != sizeof(laddr))
189 1.1 plunky errx(EXIT_FAILURE, "invalid %s", BTDEVladdr);
190 1.1 plunky
191 1.6 thorpej bdaddr_copy(&laddr, prop_data_value(obj));
192 1.1 plunky prop_dictionary_remove(dev, BTDEVladdr);
193 1.1 plunky
194 1.1 plunky obj = prop_dictionary_get(dev, BTDEVraddr);
195 1.1 plunky if (prop_data_size(obj) != sizeof(raddr))
196 1.1 plunky errx(EXIT_FAILURE, "invalid %s", BTDEVraddr);
197 1.1 plunky
198 1.6 thorpej bdaddr_copy(&raddr, prop_data_value(obj));
199 1.1 plunky prop_dictionary_remove(dev, BTDEVraddr);
200 1.1 plunky
201 1.1 plunky obj = prop_dictionary_get(dev, BTDEVtype);
202 1.6 thorpej if (prop_string_equals_string(obj, "bthidev"))
203 1.1 plunky service = "HID";
204 1.6 thorpej else if (prop_string_equals_string(obj, "btsco")) {
205 1.1 plunky obj = prop_dictionary_get(dev, BTSCOlisten);
206 1.1 plunky if (prop_bool_true(obj))
207 1.1 plunky service = "HF";
208 1.1 plunky else
209 1.1 plunky service = "HSET";
210 1.1 plunky } else
211 1.1 plunky errx(EXIT_FAILURE, "invalid %s", BTDEVtype);
212 1.1 plunky
213 1.1 plunky if (!db_set(dev, &laddr, &raddr, service))
214 1.1 plunky err(EXIT_FAILURE, "service store failed");
215 1.1 plunky }
216 1.1 plunky
217 1.1 plunky prop_object_iterator_release(iter);
218 1.1 plunky prop_object_release(old);
219 1.1 plunky
220 1.4 pavel db_flush = true; /* write on set */
221 1.1 plunky }
222 1.3 plunky
223 1.3 plunky /*
224 1.3 plunky * update database from version 1. Link Mode capability was added.
225 1.3 plunky * By default, we request authentication for HIDs, and encryption
226 1.3 plunky * is enabled for keyboards.
227 1.3 plunky */
228 1.3 plunky static void
229 1.3 plunky db_update1(void)
230 1.3 plunky {
231 1.3 plunky prop_dictionary_t ldev, rdev, srv;
232 1.3 plunky prop_object_iterator_t iter0, iter1;
233 1.3 plunky prop_dictionary_keysym_t key;
234 1.3 plunky prop_object_t obj;
235 1.3 plunky bdaddr_t bdaddr;
236 1.3 plunky
237 1.3 plunky iter0 = prop_dictionary_iterator(db);
238 1.3 plunky if (iter0 == NULL)
239 1.3 plunky err(EXIT_FAILURE, "prop_dictionary_iterator");
240 1.3 plunky
241 1.3 plunky while ((key = prop_object_iterator_next(iter0)) != NULL) {
242 1.3 plunky ldev = prop_dictionary_get_keysym(db, key);
243 1.3 plunky if (prop_object_type(ldev) != PROP_TYPE_DICTIONARY
244 1.6 thorpej || !bt_aton(prop_dictionary_keysym_value(key), &bdaddr))
245 1.3 plunky continue;
246 1.3 plunky
247 1.3 plunky iter1 = prop_dictionary_iterator(ldev);
248 1.3 plunky if (iter1 == NULL)
249 1.3 plunky err(EXIT_FAILURE, "prop_dictionary_iterator");
250 1.3 plunky
251 1.3 plunky while ((key = prop_object_iterator_next(iter1)) != NULL) {
252 1.3 plunky rdev = prop_dictionary_get_keysym(ldev, key);
253 1.3 plunky if (prop_object_type(rdev) != PROP_TYPE_DICTIONARY
254 1.6 thorpej || !bt_aton(prop_dictionary_keysym_value(key), &bdaddr))
255 1.3 plunky continue;
256 1.3 plunky
257 1.3 plunky srv = prop_dictionary_get(rdev, "HID");
258 1.3 plunky if (prop_object_type(srv) != PROP_TYPE_DICTIONARY)
259 1.3 plunky continue;
260 1.3 plunky
261 1.3 plunky obj = prop_dictionary_get(srv, BTHIDEVdescriptor);
262 1.3 plunky if (prop_object_type(obj) != PROP_TYPE_DATA)
263 1.3 plunky continue;
264 1.3 plunky
265 1.6 thorpej if (!prop_dictionary_set_string_nocopy(srv, BTDEVmode,
266 1.6 thorpej hid_mode(obj)))
267 1.3 plunky err(EXIT_FAILURE, "Cannot set %s", BTDEVmode);
268 1.3 plunky }
269 1.3 plunky
270 1.3 plunky prop_object_iterator_release(iter1);
271 1.3 plunky }
272 1.3 plunky
273 1.3 plunky prop_object_iterator_release(iter0);
274 1.3 plunky }
275