1 /* $NetBSD: provider.c,v 1.2 2007/11/09 20:08:41 plunky Exp $ */
2 /* $DragonFly: src/usr.sbin/sdpd/provider.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
3
4 /*
5 * provider.c
6 *
7 * Copyright (c) 2004 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: provider.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
32 * $FreeBSD: src/usr.sbin/bluetooth/sdpd/provider.c,v 1.1 2004/01/20 20:48:26 emax Exp $
33 */
34
35 #include <sys/queue.h>
36 #include <bluetooth.h>
37 #include <sdp.h>
38 #include <string.h>
39 #include <stdlib.h>
40 #include "profile.h"
41 #include "provider.h"
42 #include "uuid-private.h"
43
44 static TAILQ_HEAD(, provider) providers = TAILQ_HEAD_INITIALIZER(providers);
45 static uint32_t change_state = 0;
46 static uint32_t next_handle = 0;
47
48 /*
49 * Register Service Discovery provider.
50 * Should not be called more the once.
51 */
52
53 int32_t
provider_register_sd(int32_t fd)54 provider_register_sd(int32_t fd)
55 {
56 extern profile_t sd_profile_descriptor;
57 extern profile_t bgd_profile_descriptor;
58
59 provider_p sd = calloc(1, sizeof(*sd));
60 provider_p bgd = calloc(1, sizeof(*bgd));
61
62 if (sd == NULL || bgd == NULL) {
63 if (sd != NULL)
64 free(sd);
65
66 if (bgd != NULL)
67 free(bgd);
68
69 return (-1);
70 }
71
72 sd->profile = &sd_profile_descriptor;
73 bgd->handle = 0;
74 sd->fd = fd;
75 TAILQ_INSERT_HEAD(&providers, sd, provider_next);
76
77 bgd->profile = &bgd_profile_descriptor;
78 bgd->handle = 1;
79 sd->fd = fd;
80 TAILQ_INSERT_AFTER(&providers, sd, bgd, provider_next);
81
82 change_state ++;
83
84 return (0);
85 }
86
87 /*
88 * Register new provider for a given profile, bdaddr and session.
89 */
90
91 provider_p
provider_register(profile_p const profile,bdaddr_t const * bdaddr,int32_t fd,uint8_t const * data,uint32_t datalen)92 provider_register(profile_p const profile, bdaddr_t const *bdaddr, int32_t fd,
93 uint8_t const *data, uint32_t datalen)
94 {
95 provider_p provider = calloc(1, sizeof(*provider));
96
97 if (provider != NULL) {
98 provider->data = malloc(datalen);
99 if (provider->data != NULL) {
100 provider->profile = profile;
101 memcpy(provider->data, data, datalen);
102
103 /*
104 * Record handles 0x0 and 0x1 are reserved
105 * for SDP itself
106 */
107
108 if (++ next_handle <= 1)
109 next_handle = 2;
110
111 provider->handle = next_handle;
112
113 memcpy(&provider->bdaddr, bdaddr,
114 sizeof(provider->bdaddr));
115 provider->fd = fd;
116
117 TAILQ_INSERT_TAIL(&providers, provider, provider_next);
118 change_state ++;
119 } else {
120 free(provider);
121 provider = NULL;
122 }
123 }
124
125 return (provider);
126 }
127
128 /*
129 * Unregister provider
130 */
131
132 void
provider_unregister(provider_p provider)133 provider_unregister(provider_p provider)
134 {
135 TAILQ_REMOVE(&providers, provider, provider_next);
136 if (provider->data != NULL)
137 free(provider->data);
138 free(provider);
139 change_state ++;
140 }
141
142 /*
143 * Update provider data
144 */
145
146 int32_t
provider_update(provider_p provider,uint8_t const * data,uint32_t datalen)147 provider_update(provider_p provider, uint8_t const *data, uint32_t datalen)
148 {
149 uint8_t *new_data = (uint8_t *) realloc(provider->data, datalen);
150
151 if (new_data == NULL)
152 return (-1);
153
154 memcpy(new_data, data, datalen);
155 provider->data = new_data;
156
157 return (0);
158 }
159
160 /*
161 * Get a provider for given record handle
162 */
163
164 provider_p
provider_by_handle(uint32_t handle)165 provider_by_handle(uint32_t handle)
166 {
167 provider_p provider = NULL;
168
169 TAILQ_FOREACH(provider, &providers, provider_next)
170 if (provider->handle == handle)
171 break;
172
173 return (provider);
174 }
175
176 /*
177 * Cursor access
178 */
179
180 provider_p
provider_get_first(void)181 provider_get_first(void)
182 {
183 return (TAILQ_FIRST(&providers));
184 }
185
186 provider_p
provider_get_next(provider_p provider)187 provider_get_next(provider_p provider)
188 {
189 return (TAILQ_NEXT(provider, provider_next));
190 }
191
192 /*
193 * Return change state
194 */
195
196 uint32_t
provider_get_change_state(void)197 provider_get_change_state(void)
198 {
199 return (change_state);
200 }
201
202 /*
203 * Match provider to UUID list
204 *
205 * all UUIDs in list must match one of the
206 * provider UUIDs or the PublicBrowseGroup
207 */
208
209 int
provider_match_uuid(provider_p provider,uint128_t * uuid,int ucount)210 provider_match_uuid(provider_p provider, uint128_t *uuid, int ucount)
211 {
212 uint128_t puuid;
213 int num, max;
214
215 max = provider->profile->usize / sizeof(provider->profile->uuid[0]);
216
217 for (; ucount-- > 0 ; uuid++) {
218 if (memcmp(uuid, &uuid_public_browse_group, sizeof(*uuid)) == 0)
219 continue;
220
221 for (num = 0 ; ; num++) {
222 if (num == max)
223 return 0;
224
225 memcpy(&puuid, &uuid_base, sizeof(puuid));
226 puuid.b[2] = provider->profile->uuid[num] >> 8;
227 puuid.b[3] = provider->profile->uuid[num];
228
229 if (memcmp(uuid, &puuid, sizeof(*uuid)) == 0)
230 break;
231 }
232 }
233
234 return 1;
235 }
236