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