Merge from vendor branch NETGRAPH:
[dragonfly.git] / lib / libbluetooth / bluetooth.c
1 /* $NetBSD: bluetooth.c,v 1.1 2006/06/19 15:44:36 gdamore Exp $ */
2 /* $DragonFly: src/lib/libbluetooth/bluetooth.c,v 1.1 2008/01/03 11:47:52 hasso Exp $ */
3
4 /*
5  * bluetooth.c
6  *
7  * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  * $Id: bluetooth.c,v 1.1 2006/06/19 15:44:36 gdamore Exp $
32  * $FreeBSD: src/lib/libbluetooth/bluetooth.c,v 1.2 2004/03/05 08:10:17 markm Exp $
33  */
34
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
44 static FILE             *hostf = NULL;
45 static int               host_stayopen = 0;
46 static struct hostent    host;
47 static bdaddr_t          host_addr;
48 static char             *host_addr_ptrs[2];
49 static char             *host_aliases[MAXALIASES];
50
51 static FILE             *protof = NULL;
52 static int               proto_stayopen = 0;
53 static struct protoent   proto;
54 static char             *proto_aliases[MAXALIASES];
55
56 static char              buf[BUFSIZ + 1];
57
58 static int bt_hex_byte   (char const *str);
59 static int bt_hex_nibble (char nibble);
60
61 struct hostent *
62 bt_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 != 0; cp++)
72                         if (strcasecmp(*cp, name) == 0)
73                                 goto found;
74         }
75 found:
76         bt_endhostent();
77
78         return (p);
79 }
80
81 struct hostent *
82 bt_gethostbyaddr(char const *addr, socklen_t 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 && memcmp(p->h_addr, addr, len) == 0)
94                         break;
95         bt_endhostent();
96
97         return (p);
98 }
99
100 struct hostent *
101 bt_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         }
112 again:
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
154 void
155 bt_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
165 void
166 bt_endhostent(void)
167 {
168         if (hostf != NULL && host_stayopen == 0) {
169                 (void) fclose(hostf);
170                 hostf = NULL;
171         }
172 }
173
174 struct protoent *
175 bt_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 != 0; cp++)
185                         if (strcmp(*cp, name) == 0)
186                                 goto found;
187         }
188 found:
189         bt_endprotoent();
190
191         return (p);
192 }
193
194 struct protoent *
195 bt_getprotobynumber(int num)
196 {
197         struct protoent *p;
198
199         bt_setprotoent(proto_stayopen);
200         while ((p = bt_getprotoent()) != NULL)
201                 if (p->p_proto == num)
202                         break;
203         bt_endprotoent();
204
205         return (p);
206 }
207
208 struct protoent *
209 bt_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);
218 again:
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 = (int)strtol(cp, NULL, 0);
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
254 void
255 bt_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
265 void
266 bt_endprotoent(void)
267 {
268         if (protof != NULL) {
269                 (void) fclose(protof);
270                 protof = NULL;
271         }
272 }
273
274 char const *
275 bt_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
288 int
289 bt_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
344 static int
345 bt_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
358 static int
359 bt_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 }