1/*	$NetBSD: bluetooth.c$	*/
2
3/*
4 * bluetooth.c
5 *
6 * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * $Id: bluetooth.c,v 1.1 2006/06/19 15:44:36 gdamore Exp $
31 * $FreeBSD: src/lib/libbluetooth/bluetooth.c,v 1.2 2004/03/05 08:10:17 markm Exp $
32 */
33
34#include <sys/cdefs.h>
35__RCSID("$NetBSD: bluetooth.c$");
36
37#include <bluetooth.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41
42#define _PATH_BT_HOSTS		"/etc/bluetooth/hosts"
43#define _PATH_BT_PROTOCOLS	"/etc/bluetooth/protocols"
44#define MAXALIASES		 35
45
46static FILE		*hostf = NULL;
47static int		 host_stayopen = 0;
48static struct hostent	 host;
49static bdaddr_t		 host_addr;
50static char		*host_addr_ptrs[2];
51static char		*host_aliases[MAXALIASES];
52
53static FILE		*protof = NULL;
54static int		 proto_stayopen = 0;
55static struct protoent	 proto;
56static char		*proto_aliases[MAXALIASES];
57
58static char		 buf[BUFSIZ + 1];
59
60static int bt_hex_byte   (char const *str);
61static int bt_hex_nibble (char nibble);
62
63struct hostent *
64bt_gethostbyname(char const *name)
65{
66	struct hostent	*p;
67	char		**cp;
68
69	bt_sethostent(host_stayopen);
70	while ((p = bt_gethostent()) != NULL) {
71		if (strcasecmp(p->h_name, name) == 0)
72			break;
73		for (cp = p->h_aliases; *cp != 0; cp++)
74			if (strcasecmp(*cp, name) == 0)
75				goto found;
76	}
77found:
78	bt_endhostent();
79
80	return (p);
81}
82
83struct hostent *
84bt_gethostbyaddr(char const *addr, socklen_t len, int type)
85{
86	struct hostent	*p;
87
88	if (type != AF_BLUETOOTH || len != sizeof(bdaddr_t)) {
89		h_errno = NO_RECOVERY;
90		return (NULL);
91	}
92
93	bt_sethostent(host_stayopen);
94	while ((p = bt_gethostent()) != NULL)
95		if (p->h_addrtype == type && memcmp(p->h_addr, addr, len) == 0)
96			break;
97	bt_endhostent();
98
99	return (p);
100}
101
102struct hostent *
103bt_gethostent(void)
104{
105	char	*p, *cp, **q;
106
107	if (hostf == NULL)
108		hostf = fopen(_PATH_BT_HOSTS, "r");
109
110	if (hostf == NULL) {
111		h_errno = NETDB_INTERNAL;
112		return (NULL);
113	}
114again:
115	if ((p = fgets(buf, sizeof(buf), hostf)) == NULL) {
116		h_errno = HOST_NOT_FOUND;
117		return (NULL);
118	}
119	if (*p == '#')
120		goto again;
121	if ((cp = strpbrk(p, "#\n")) == NULL)
122		goto again;
123	*cp = 0;
124	if ((cp = strpbrk(p, " \t")) == NULL)
125		goto again;
126	*cp++ = 0;
127	if (bt_aton(p, &host_addr) == 0)
128		goto again;
129	host_addr_ptrs[0] = (char *) &host_addr;
130	host_addr_ptrs[1] = NULL;
131	host.h_addr_list = host_addr_ptrs;
132	host.h_length = sizeof(host_addr);
133	host.h_addrtype = AF_BLUETOOTH;
134	while (*cp == ' ' || *cp == '\t')
135		cp++;
136	host.h_name = cp;
137	q = host.h_aliases = host_aliases;
138	if ((cp = strpbrk(cp, " \t")) != NULL)
139		*cp++ = 0;
140	while (cp != NULL && *cp != 0) {
141		if (*cp == ' ' || *cp == '\t') {
142			cp++;
143			continue;
144		}
145		if (q < &host_aliases[MAXALIASES - 1])
146			*q++ = cp;
147		if ((cp = strpbrk(cp, " \t")) != NULL)
148			*cp++ = 0;
149	}
150	*q = NULL;
151	h_errno = NETDB_SUCCESS;
152
153	return (&host);
154}
155
156void
157bt_sethostent(int stayopen)
158{
159	if (hostf == NULL)
160		hostf = fopen(_PATH_BT_HOSTS, "r");
161	else
162		rewind(hostf);
163
164	host_stayopen = stayopen;
165}
166
167void
168bt_endhostent(void)
169{
170	if (hostf != NULL && host_stayopen == 0) {
171		(void) fclose(hostf);
172		hostf = NULL;
173	}
174}
175
176struct protoent *
177bt_getprotobyname(char const *name)
178{
179	struct protoent	 *p;
180	char		**cp;
181
182	bt_setprotoent(proto_stayopen);
183	while ((p = bt_getprotoent()) != NULL) {
184		if (strcmp(p->p_name, name) == 0)
185			break;
186		for (cp = p->p_aliases; *cp != 0; cp++)
187			if (strcmp(*cp, name) == 0)
188				goto found;
189	}
190found:
191	bt_endprotoent();
192
193	return (p);
194}
195
196struct protoent *
197bt_getprotobynumber(int num)
198{
199	struct protoent	*p;
200
201	bt_setprotoent(proto_stayopen);
202	while ((p = bt_getprotoent()) != NULL)
203		if (p->p_proto == num)
204			break;
205	bt_endprotoent();
206
207	return (p);
208}
209
210struct protoent *
211bt_getprotoent(void)
212{
213	char	*p, *cp, **q;
214
215	if (protof == NULL)
216		protof = fopen(_PATH_BT_PROTOCOLS, "r");
217
218	if (protof == NULL)
219		return (NULL);
220again:
221	if ((p = fgets(buf, sizeof(buf), protof)) == NULL)
222		return (NULL);
223	if (*p == '#')
224		goto again;
225	if ((cp = strpbrk(p, "#\n")) == NULL)
226		goto again;
227	*cp = '\0';
228	proto.p_name = p;
229	if ((cp = strpbrk(p, " \t")) == NULL)
230		goto again;
231	*cp++ = '\0';
232	while (*cp == ' ' || *cp == '\t')
233		cp++;
234	if ((p = strpbrk(cp, " \t")) != NULL)
235		*p++ = '\0';
236	proto.p_proto = (int)strtol(cp, NULL, 0);
237	q = proto.p_aliases = proto_aliases;
238	if (p != NULL) {
239		cp = p;
240		while (cp != NULL && *cp != 0) {
241			if (*cp == ' ' || *cp == '\t') {
242				cp++;
243				continue;
244			}
245			if (q < &proto_aliases[MAXALIASES - 1])
246				*q++ = cp;
247			if ((cp = strpbrk(cp, " \t")) != NULL)
248				*cp++ = '\0';
249		}
250	}
251	*q = NULL;
252
253	return (&proto);
254}
255
256void
257bt_setprotoent(int stayopen)
258{
259	if (protof == NULL)
260		protof = fopen(_PATH_BT_PROTOCOLS, "r");
261	else
262		rewind(protof);
263
264	proto_stayopen = stayopen;
265}
266
267void
268bt_endprotoent(void)
269{
270	if (protof != NULL) {
271		(void) fclose(protof);
272		protof = NULL;
273	}
274}
275
276char const *
277bt_ntoa(bdaddr_t const *ba, char *str)
278{
279	static char	buffer[24];
280
281	if (str == NULL)
282		str = buffer;
283
284	sprintf(str, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
285		ba->b[5], ba->b[4], ba->b[3], ba->b[2], ba->b[1], ba->b[0]);
286
287	return (str);
288}
289
290int
291bt_aton(char const *str, bdaddr_t *ba)
292{
293	int	 i, b;
294	char	*end = NULL;
295
296	memset(ba, 0, sizeof(*ba));
297
298	for (i = 5, end = strchr(str, ':');
299	     i > 0 && *str != '\0' && end != NULL;
300	     i --, str = end + 1, end = strchr(str, ':')) {
301		switch (end - str) {
302		case 1:
303			b = bt_hex_nibble(str[0]);
304			break;
305
306		case 2:
307			b = bt_hex_byte(str);
308			break;
309
310		default:
311			b = -1;
312			break;
313		}
314
315		if (b < 0)
316			return (0);
317
318		ba->b[i] = b;
319	}
320
321	if (i != 0 || end != NULL || *str == 0)
322		return (0);
323
324	switch (strlen(str)) {
325	case 1:
326		b = bt_hex_nibble(str[0]);
327		break;
328
329	case 2:
330		b = bt_hex_byte(str);
331		break;
332
333	default:
334		b = -1;
335		break;
336	}
337
338	if (b < 0)
339		return (0);
340
341	ba->b[i] = b;
342
343	return (1);
344}
345
346static int
347bt_hex_byte(char const *str)
348{
349	int	n1, n2;
350
351	if ((n1 = bt_hex_nibble(str[0])) < 0)
352		return (-1);
353
354	if ((n2 = bt_hex_nibble(str[1])) < 0)
355		return (-1);
356
357	return ((((n1 & 0x0f) << 4) | (n2 & 0x0f)) & 0xff);
358}
359
360static int
361bt_hex_nibble(char nibble)
362{
363	if ('0' <= nibble && nibble <= '9')
364		return (nibble - '0');
365
366	if ('a' <= nibble && nibble <= 'f')
367		return (nibble - 'a' + 0xa);
368
369	if ('A' <= nibble && nibble <= 'F')
370		return (nibble - 'A' + 0xa);
371
372	return (-1);
373}
374