1/*
2 * bluetooth.c
3 */
4
5/*-
6 * Copyright (c) 2001-2009 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.3 2003/05/20 23:04:30 max Exp $
31 * $FreeBSD$
32 */
33#define L2CAP_SOCKET_CHECKED
34#include <bluetooth.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38
39#define _PATH_BT_HOSTS		"/etc/bluetooth/hosts"
40#define _PATH_BT_PROTOCOLS	"/etc/bluetooth/protocols"
41#define MAXALIASES		 35
42
43static FILE		*hostf = NULL;
44static int		 host_stayopen = 0;
45static struct hostent	 host;
46static bdaddr_t		 host_addr;
47static char		*host_addr_ptrs[2];
48static char		*host_aliases[MAXALIASES];
49
50static FILE		*protof = NULL;
51static int		 proto_stayopen = 0;
52static struct protoent	 proto;
53static char		*proto_aliases[MAXALIASES];
54
55static char		 buf[BUFSIZ + 1];
56
57static int bt_hex_byte   (char const *str);
58static int bt_hex_nibble (char nibble);
59
60struct hostent *
61bt_gethostbyname(char const *name)
62{
63	struct hostent	*p;
64	char		**cp;
65
66	bt_sethostent(host_stayopen);
67	while ((p = bt_gethostent()) != NULL) {
68		if (strcasecmp(p->h_name, name) == 0)
69			break;
70		for (cp = p->h_aliases; *cp != NULL; cp++)
71			if (strcasecmp(*cp, name) == 0)
72				goto found;
73	}
74found:
75	bt_endhostent();
76
77	return (p);
78}
79
80struct hostent *
81bt_gethostbyaddr(char const *addr, int len, int type)
82{
83	struct hostent	*p;
84
85	if (type != AF_BLUETOOTH || len != sizeof(bdaddr_t)) {
86		h_errno = NO_RECOVERY;
87		return (NULL);
88	}
89
90	bt_sethostent(host_stayopen);
91	while ((p = bt_gethostent()) != NULL)
92		if (p->h_addrtype == type && bcmp(p->h_addr, addr, len) == 0)
93			break;
94	bt_endhostent();
95
96	return (p);
97}
98
99struct hostent *
100bt_gethostent(void)
101{
102	char	*p, *cp, **q;
103
104	if (hostf == NULL)
105		hostf = fopen(_PATH_BT_HOSTS, "r");
106
107	if (hostf == NULL) {
108		h_errno = NETDB_INTERNAL;
109		return (NULL);
110	}
111again:
112	if ((p = fgets(buf, sizeof(buf), hostf)) == NULL) {
113		h_errno = HOST_NOT_FOUND;
114		return (NULL);
115	}
116	if (*p == '#')
117		goto again;
118	if ((cp = strpbrk(p, "#\n")) == NULL)
119		goto again;
120	*cp = 0;
121	if ((cp = strpbrk(p, " \t")) == NULL)
122		goto again;
123	*cp++ = 0;
124	if (bt_aton(p, &host_addr) == 0)
125		goto again;
126	host_addr_ptrs[0] = (char *) &host_addr;
127	host_addr_ptrs[1] = NULL;
128	host.h_addr_list = host_addr_ptrs;
129	host.h_length = sizeof(host_addr);
130	host.h_addrtype = AF_BLUETOOTH;
131	while (*cp == ' ' || *cp == '\t')
132		cp++;
133	host.h_name = cp;
134	q = host.h_aliases = host_aliases;
135	if ((cp = strpbrk(cp, " \t")) != NULL)
136		*cp++ = 0;
137	while (cp != NULL && *cp != 0) {
138		if (*cp == ' ' || *cp == '\t') {
139			cp++;
140			continue;
141		}
142		if (q < &host_aliases[MAXALIASES - 1])
143			*q++ = cp;
144		if ((cp = strpbrk(cp, " \t")) != NULL)
145			*cp++ = 0;
146	}
147	*q = NULL;
148	h_errno = NETDB_SUCCESS;
149
150	return (&host);
151}
152
153void
154bt_sethostent(int stayopen)
155{
156	if (hostf == NULL)
157		hostf = fopen(_PATH_BT_HOSTS, "r");
158	else
159		rewind(hostf);
160
161	host_stayopen = stayopen;
162}
163
164void
165bt_endhostent(void)
166{
167	if (hostf != NULL && host_stayopen == 0) {
168		(void) fclose(hostf);
169		hostf = NULL;
170	}
171}
172
173struct protoent *
174bt_getprotobyname(char const *name)
175{
176	struct protoent	 *p;
177	char		**cp;
178
179	bt_setprotoent(proto_stayopen);
180	while ((p = bt_getprotoent()) != NULL) {
181		if (strcmp(p->p_name, name) == 0)
182			break;
183		for (cp = p->p_aliases; *cp != NULL; cp++)
184			if (strcmp(*cp, name) == 0)
185				goto found;
186	}
187found:
188	bt_endprotoent();
189
190	return (p);
191}
192
193struct protoent *
194bt_getprotobynumber(int proto)
195{
196	struct protoent	*p;
197
198	bt_setprotoent(proto_stayopen);
199	while ((p = bt_getprotoent()) != NULL)
200		if (p->p_proto == proto)
201			break;
202	bt_endprotoent();
203
204	return (p);
205}
206
207struct protoent *
208bt_getprotoent(void)
209{
210	char	*p, *cp, **q;
211
212	if (protof == NULL)
213		protof = fopen(_PATH_BT_PROTOCOLS, "r");
214
215	if (protof == NULL)
216		return (NULL);
217again:
218	if ((p = fgets(buf, sizeof(buf), protof)) == NULL)
219		return (NULL);
220	if (*p == '#')
221		goto again;
222	if ((cp = strpbrk(p, "#\n")) == NULL)
223		goto again;
224	*cp = '\0';
225	proto.p_name = p;
226	if ((cp = strpbrk(p, " \t")) == NULL)
227		goto again;
228	*cp++ = '\0';
229	while (*cp == ' ' || *cp == '\t')
230		cp++;
231	if ((p = strpbrk(cp, " \t")) != NULL)
232		*p++ = '\0';
233	proto.p_proto = atoi(cp);
234	q = proto.p_aliases = proto_aliases;
235	if (p != NULL) {
236		cp = p;
237		while (cp != NULL && *cp != 0) {
238			if (*cp == ' ' || *cp == '\t') {
239				cp++;
240				continue;
241			}
242			if (q < &proto_aliases[MAXALIASES - 1])
243				*q++ = cp;
244			if ((cp = strpbrk(cp, " \t")) != NULL)
245				*cp++ = '\0';
246		}
247	}
248	*q = NULL;
249
250	return (&proto);
251}
252
253void
254bt_setprotoent(int stayopen)
255{
256	if (protof == NULL)
257		protof = fopen(_PATH_BT_PROTOCOLS, "r");
258	else
259		rewind(protof);
260
261	proto_stayopen = stayopen;
262}
263
264void
265bt_endprotoent(void)
266{
267	if (protof != NULL) {
268		(void) fclose(protof);
269		protof = NULL;
270	}
271}
272
273char const *
274bt_ntoa(bdaddr_t const *ba, char *str)
275{
276	static char	buffer[24];
277
278	if (str == NULL)
279		str = buffer;
280
281	sprintf(str, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
282		ba->b[5], ba->b[4], ba->b[3], ba->b[2], ba->b[1], ba->b[0]);
283
284	return (str);
285}
286
287int
288bt_aton(char const *str, bdaddr_t *ba)
289{
290	int	 i, b;
291	char	*end = NULL;
292
293	memset(ba, 0, sizeof(*ba));
294
295	for (i = 5, end = strchr(str, ':');
296	     i > 0 && *str != '\0' && end != NULL;
297	     i --, str = end + 1, end = strchr(str, ':')) {
298		switch (end - str) {
299		case 1:
300			b = bt_hex_nibble(str[0]);
301			break;
302
303		case 2:
304			b = bt_hex_byte(str);
305			break;
306
307		default:
308			b = -1;
309			break;
310		}
311
312		if (b < 0)
313			return (0);
314
315		ba->b[i] = b;
316	}
317
318	if (i != 0 || end != NULL || *str == 0)
319		return (0);
320
321	switch (strlen(str)) {
322	case 1:
323		b = bt_hex_nibble(str[0]);
324		break;
325
326	case 2:
327		b = bt_hex_byte(str);
328		break;
329
330	default:
331		b = -1;
332		break;
333	}
334
335	if (b < 0)
336		return (0);
337
338	ba->b[i] = b;
339
340	return (1);
341}
342
343static int
344bt_hex_byte(char const *str)
345{
346	int	n1, n2;
347
348	if ((n1 = bt_hex_nibble(str[0])) < 0)
349		return (-1);
350
351	if ((n2 = bt_hex_nibble(str[1])) < 0)
352		return (-1);
353
354	return ((((n1 & 0x0f) << 4) | (n2 & 0x0f)) & 0xff);
355}
356
357static int
358bt_hex_nibble(char nibble)
359{
360	if ('0' <= nibble && nibble <= '9')
361		return (nibble - '0');
362
363	if ('a' <= nibble && nibble <= 'f')
364		return (nibble - 'a' + 0xa);
365
366	if ('A' <= nibble && nibble <= 'F')
367		return (nibble - 'A' + 0xa);
368
369	return (-1);
370}
371
372