db.c revision 1.4 1 1.4 pavel /* $NetBSD: db.c,v 1.4 2007/08/17 17:59:16 pavel 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.4 pavel __RCSID("$NetBSD: db.c,v 1.4 2007/08/17 17:59:16 pavel 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.1 plunky switch(prop_number_integer_value(obj)) {
79 1.3 plunky case 0: db_update0();
80 1.3 plunky case 1: db_update1();
81 1.1 plunky case BTDEVCTL_VERSION:
82 1.1 plunky break;
83 1.1 plunky
84 1.1 plunky default:
85 1.1 plunky errx(EXIT_FAILURE, "unknown btdevctl-version");
86 1.1 plunky }
87 1.1 plunky }
88 1.1 plunky }
89 1.1 plunky
90 1.1 plunky ldev = prop_dictionary_get(db, bt_ntoa(laddr, NULL));
91 1.1 plunky if (prop_object_type(ldev) != PROP_TYPE_DICTIONARY)
92 1.1 plunky return NULL;
93 1.1 plunky
94 1.1 plunky rdev = prop_dictionary_get(ldev, bt_ntoa(raddr, NULL));
95 1.1 plunky if (prop_object_type(rdev) != PROP_TYPE_DICTIONARY)
96 1.1 plunky return NULL;
97 1.1 plunky
98 1.1 plunky dev = prop_dictionary_get(rdev, service);
99 1.1 plunky if (prop_object_type(dev) != PROP_TYPE_DICTIONARY)
100 1.1 plunky return NULL;
101 1.1 plunky
102 1.1 plunky return dev;
103 1.1 plunky }
104 1.1 plunky
105 1.1 plunky /*
106 1.1 plunky * store dictionary in database at laddr/raddr/service
107 1.1 plunky */
108 1.1 plunky int
109 1.1 plunky db_set(prop_dictionary_t dev, bdaddr_t *laddr, bdaddr_t *raddr, const char *service)
110 1.1 plunky {
111 1.1 plunky prop_dictionary_t ldev, rdev;
112 1.1 plunky prop_number_t version;
113 1.1 plunky
114 1.1 plunky ldev = prop_dictionary_get(db, bt_ntoa(laddr, NULL));
115 1.1 plunky if (ldev == NULL) {
116 1.1 plunky ldev = prop_dictionary_create();
117 1.1 plunky if (ldev == NULL)
118 1.1 plunky return 0;
119 1.1 plunky
120 1.1 plunky if (!prop_dictionary_set(db, bt_ntoa(laddr, NULL), ldev))
121 1.1 plunky return 0;
122 1.1 plunky
123 1.1 plunky prop_object_release(ldev);
124 1.1 plunky }
125 1.1 plunky
126 1.1 plunky rdev = prop_dictionary_get(ldev, bt_ntoa(raddr, NULL));
127 1.1 plunky if (rdev == NULL) {
128 1.1 plunky rdev = prop_dictionary_create();
129 1.1 plunky if (rdev == NULL)
130 1.1 plunky return 0;
131 1.1 plunky
132 1.1 plunky if (!prop_dictionary_set(ldev, bt_ntoa(raddr, NULL), rdev))
133 1.1 plunky return 0;
134 1.1 plunky
135 1.1 plunky prop_object_release(rdev);
136 1.1 plunky }
137 1.1 plunky
138 1.1 plunky if (!prop_dictionary_set(rdev, service, dev))
139 1.1 plunky return 0;
140 1.1 plunky
141 1.4 pavel if (db_flush == true) {
142 1.1 plunky version = prop_number_create_integer(BTDEVCTL_VERSION);
143 1.1 plunky if (version == NULL)
144 1.1 plunky err(EXIT_FAILURE, "prop_number_create_integer");
145 1.1 plunky
146 1.1 plunky if (!prop_dictionary_set(db, "btdevctl-version", version))
147 1.1 plunky err(EXIT_FAILURE, "prop_dictionary_set");
148 1.1 plunky
149 1.1 plunky prop_object_release(version);
150 1.1 plunky
151 1.1 plunky if (!prop_dictionary_externalize_to_file(db, BTDEVCTL_PLIST))
152 1.1 plunky warn("%s", BTDEVCTL_PLIST);
153 1.1 plunky }
154 1.1 plunky
155 1.1 plunky return 1;
156 1.1 plunky }
157 1.1 plunky
158 1.1 plunky /*
159 1.1 plunky * update database from version 0. This was a flat file using
160 1.1 plunky * btdevN as an index, and local-bdaddr and remote-bdaddr stored
161 1.1 plunky * as data objects. Step through and add them to the new dictionary.
162 1.1 plunky * We have to generate the service, but only HID, HF and HSET
163 1.1 plunky * were supported, so thats not too difficult.
164 1.1 plunky */
165 1.1 plunky static void
166 1.1 plunky db_update0(void)
167 1.1 plunky {
168 1.1 plunky prop_dictionary_t old, dev;
169 1.1 plunky prop_dictionary_keysym_t key;
170 1.1 plunky prop_object_iterator_t iter;
171 1.1 plunky prop_object_t obj;
172 1.1 plunky bdaddr_t laddr, raddr;
173 1.2 plunky const char *service;
174 1.1 plunky
175 1.4 pavel db_flush = false; /* no write on set */
176 1.1 plunky old = db;
177 1.1 plunky
178 1.1 plunky db = prop_dictionary_create();
179 1.1 plunky if (db == NULL)
180 1.1 plunky err(EXIT_FAILURE, "prop_dictionary_create");
181 1.1 plunky
182 1.1 plunky iter = prop_dictionary_iterator(old);
183 1.1 plunky if (iter == NULL)
184 1.1 plunky err(EXIT_FAILURE, "prop_dictionary_iterator");
185 1.1 plunky
186 1.1 plunky while ((key = prop_object_iterator_next(iter)) != NULL) {
187 1.1 plunky dev = prop_dictionary_get_keysym(old, key);
188 1.1 plunky if (prop_object_type(dev) != PROP_TYPE_DICTIONARY)
189 1.1 plunky errx(EXIT_FAILURE, "invalid device dictionary");
190 1.1 plunky
191 1.1 plunky obj = prop_dictionary_get(dev, BTDEVladdr);
192 1.1 plunky if (prop_data_size(obj) != sizeof(laddr))
193 1.1 plunky errx(EXIT_FAILURE, "invalid %s", BTDEVladdr);
194 1.1 plunky
195 1.1 plunky bdaddr_copy(&laddr, prop_data_data_nocopy(obj));
196 1.1 plunky prop_dictionary_remove(dev, BTDEVladdr);
197 1.1 plunky
198 1.1 plunky obj = prop_dictionary_get(dev, BTDEVraddr);
199 1.1 plunky if (prop_data_size(obj) != sizeof(raddr))
200 1.1 plunky errx(EXIT_FAILURE, "invalid %s", BTDEVraddr);
201 1.1 plunky
202 1.1 plunky bdaddr_copy(&raddr, prop_data_data_nocopy(obj));
203 1.1 plunky prop_dictionary_remove(dev, BTDEVraddr);
204 1.1 plunky
205 1.1 plunky obj = prop_dictionary_get(dev, BTDEVtype);
206 1.1 plunky if (prop_string_equals_cstring(obj, "bthidev"))
207 1.1 plunky service = "HID";
208 1.1 plunky else if (prop_string_equals_cstring(obj, "btsco")) {
209 1.1 plunky obj = prop_dictionary_get(dev, BTSCOlisten);
210 1.1 plunky if (prop_bool_true(obj))
211 1.1 plunky service = "HF";
212 1.1 plunky else
213 1.1 plunky service = "HSET";
214 1.1 plunky } else
215 1.1 plunky errx(EXIT_FAILURE, "invalid %s", BTDEVtype);
216 1.1 plunky
217 1.1 plunky if (!db_set(dev, &laddr, &raddr, service))
218 1.1 plunky err(EXIT_FAILURE, "service store failed");
219 1.1 plunky }
220 1.1 plunky
221 1.1 plunky prop_object_iterator_release(iter);
222 1.1 plunky prop_object_release(old);
223 1.1 plunky
224 1.4 pavel db_flush = true; /* write on set */
225 1.1 plunky }
226 1.3 plunky
227 1.3 plunky /*
228 1.3 plunky * update database from version 1. Link Mode capability was added.
229 1.3 plunky * By default, we request authentication for HIDs, and encryption
230 1.3 plunky * is enabled for keyboards.
231 1.3 plunky */
232 1.3 plunky static void
233 1.3 plunky db_update1(void)
234 1.3 plunky {
235 1.3 plunky prop_dictionary_t ldev, rdev, srv;
236 1.3 plunky prop_object_iterator_t iter0, iter1;
237 1.3 plunky prop_dictionary_keysym_t key;
238 1.3 plunky prop_object_t obj;
239 1.3 plunky bdaddr_t bdaddr;
240 1.3 plunky
241 1.3 plunky iter0 = prop_dictionary_iterator(db);
242 1.3 plunky if (iter0 == NULL)
243 1.3 plunky err(EXIT_FAILURE, "prop_dictionary_iterator");
244 1.3 plunky
245 1.3 plunky while ((key = prop_object_iterator_next(iter0)) != NULL) {
246 1.3 plunky ldev = prop_dictionary_get_keysym(db, key);
247 1.3 plunky if (prop_object_type(ldev) != PROP_TYPE_DICTIONARY
248 1.3 plunky || !bt_aton(prop_dictionary_keysym_cstring_nocopy(key), &bdaddr))
249 1.3 plunky continue;
250 1.3 plunky
251 1.3 plunky iter1 = prop_dictionary_iterator(ldev);
252 1.3 plunky if (iter1 == NULL)
253 1.3 plunky err(EXIT_FAILURE, "prop_dictionary_iterator");
254 1.3 plunky
255 1.3 plunky while ((key = prop_object_iterator_next(iter1)) != NULL) {
256 1.3 plunky rdev = prop_dictionary_get_keysym(ldev, key);
257 1.3 plunky if (prop_object_type(rdev) != PROP_TYPE_DICTIONARY
258 1.3 plunky || !bt_aton(prop_dictionary_keysym_cstring_nocopy(key), &bdaddr))
259 1.3 plunky continue;
260 1.3 plunky
261 1.3 plunky srv = prop_dictionary_get(rdev, "HID");
262 1.3 plunky if (prop_object_type(srv) != PROP_TYPE_DICTIONARY)
263 1.3 plunky continue;
264 1.3 plunky
265 1.3 plunky obj = prop_dictionary_get(srv, BTHIDEVdescriptor);
266 1.3 plunky if (prop_object_type(obj) != PROP_TYPE_DATA)
267 1.3 plunky continue;
268 1.3 plunky
269 1.3 plunky obj = prop_string_create_cstring_nocopy(hid_mode(obj));
270 1.3 plunky if (obj == NULL || !prop_dictionary_set(srv, BTDEVmode, obj))
271 1.3 plunky err(EXIT_FAILURE, "Cannot set %s", BTDEVmode);
272 1.3 plunky
273 1.3 plunky prop_object_release(obj);
274 1.3 plunky }
275 1.3 plunky
276 1.3 plunky prop_object_iterator_release(iter1);
277 1.3 plunky }
278 1.3 plunky
279 1.3 plunky prop_object_iterator_release(iter0);
280 1.3 plunky }
281