1124758Semax/*
2124758Semax * service.c
3124758Semax *
4124758Semax * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
5124758Semax * All rights reserved.
6124758Semax *
7124758Semax * Redistribution and use in source and binary forms, with or without
8124758Semax * modification, are permitted provided that the following conditions
9124758Semax * are met:
10124758Semax * 1. Redistributions of source code must retain the above copyright
11124758Semax *    notice, this list of conditions and the following disclaimer.
12124758Semax * 2. Redistributions in binary form must reproduce the above copyright
13124758Semax *    notice, this list of conditions and the following disclaimer in the
14124758Semax *    documentation and/or other materials provided with the distribution.
15124758Semax *
16124758Semax * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17124758Semax * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18124758Semax * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19124758Semax * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20124758Semax * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21124758Semax * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22124758Semax * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23124758Semax * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24124758Semax * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25124758Semax * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26124758Semax * SUCH DAMAGE.
27124758Semax *
28124758Semax * $Id: service.c,v 1.1 2004/01/13 19:32:36 max Exp $
29124758Semax * $FreeBSD$
30124758Semax */
31124758Semax
32124758Semax#include <sys/uio.h>
33124758Semax#include <netinet/in.h>
34124758Semax#include <arpa/inet.h>
35124758Semax#include <bluetooth.h>
36124758Semax#include <errno.h>
37124758Semax#include <string.h>
38124758Semax#include <unistd.h>
39124758Semax
40124758Semax#include <sdp-int.h>
41124758Semax#include <sdp.h>
42124758Semax
43124758Semaxstatic int32_t sdp_receive_error_pdu(sdp_session_p ss);
44124758Semax
45124758Semaxint32_t
46124758Semaxsdp_register_service(void *xss, uint16_t uuid, bdaddr_p const bdaddr,
47124758Semax		uint8_t const *data, uint32_t datalen, uint32_t *handle)
48124758Semax{
49124758Semax	sdp_session_p	ss = (sdp_session_p) xss;
50124758Semax	struct iovec	iov[4];
51124758Semax	sdp_pdu_t	pdu;
52124758Semax	int32_t		len;
53124758Semax
54124758Semax	if (ss == NULL)
55124758Semax		return (-1);
56124758Semax	if (bdaddr == NULL || data == NULL ||
57124758Semax	    datalen == 0 || !(ss->flags & SDP_SESSION_LOCAL)) {
58124758Semax		ss->error = EINVAL;
59124758Semax		return (-1);
60124758Semax	}
61124758Semax	if (sizeof(pdu)+sizeof(uuid)+sizeof(*bdaddr)+datalen > SDP_LOCAL_MTU) {
62124758Semax		ss->error = EMSGSIZE;
63124758Semax		return (-1);
64124758Semax	}
65124758Semax
66124758Semax	pdu.pid = SDP_PDU_SERVICE_REGISTER_REQUEST;
67124758Semax	pdu.tid = htons(++ss->tid);
68124758Semax	pdu.len = htons(sizeof(uuid) + sizeof(*bdaddr) + datalen);
69124758Semax
70124758Semax	uuid = htons(uuid);
71124758Semax
72124758Semax	iov[0].iov_base = (void *) &pdu;
73124758Semax	iov[0].iov_len = sizeof(pdu);
74124758Semax
75124758Semax	iov[1].iov_base = (void *) &uuid;
76124758Semax	iov[1].iov_len = sizeof(uuid);
77124758Semax
78124758Semax	iov[2].iov_base = (void *) bdaddr;
79124758Semax	iov[2].iov_len = sizeof(*bdaddr);
80124758Semax
81124758Semax	iov[3].iov_base = (void *) data;
82124758Semax	iov[3].iov_len = datalen;
83124758Semax
84124758Semax	do {
85124758Semax		len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
86124758Semax	} while (len < 0 && errno == EINTR);
87124758Semax
88124758Semax	if (len < 0) {
89124758Semax		ss->error = errno;
90124758Semax		return (-1);
91124758Semax	}
92124758Semax
93124758Semax	len = sdp_receive_error_pdu(ss);
94124758Semax	if (len < 0)
95124758Semax		return (-1);
96124758Semax	if (len != sizeof(pdu) + sizeof(uint16_t) + sizeof(uint32_t)) {
97124758Semax		ss->error = EIO;
98124758Semax		return (-1);
99124758Semax	}
100124758Semax
101124758Semax	if (handle != NULL) {
102124758Semax		*handle  = (uint32_t) ss->rsp[--len];
103124758Semax		*handle |= (uint32_t) ss->rsp[--len] << 8;
104124758Semax		*handle |= (uint32_t) ss->rsp[--len] << 16;
105124758Semax		*handle |= (uint32_t) ss->rsp[--len] << 24;
106124758Semax	}
107124758Semax
108124758Semax	return (0);
109124758Semax}
110124758Semax
111124758Semaxint32_t
112124758Semaxsdp_unregister_service(void *xss, uint32_t handle)
113124758Semax{
114124758Semax	sdp_session_p	ss = (sdp_session_p) xss;
115124758Semax	struct iovec	iov[2];
116124758Semax	sdp_pdu_t	pdu;
117124758Semax	int32_t		len;
118124758Semax
119124758Semax	if (ss == NULL)
120124758Semax		return (-1);
121124758Semax	if (!(ss->flags & SDP_SESSION_LOCAL)) {
122124758Semax		ss->error = EINVAL;
123124758Semax		return (-1);
124124758Semax	}
125124758Semax	if (sizeof(pdu) + sizeof(handle) > SDP_LOCAL_MTU) {
126124758Semax		ss->error = EMSGSIZE;
127124758Semax		return (-1);
128124758Semax	}
129124758Semax
130124758Semax	pdu.pid = SDP_PDU_SERVICE_UNREGISTER_REQUEST;
131124758Semax	pdu.tid = htons(++ss->tid);
132124758Semax	pdu.len = htons(sizeof(handle));
133124758Semax
134124758Semax	handle = htonl(handle);
135124758Semax
136124758Semax	iov[0].iov_base = (void *) &pdu;
137124758Semax	iov[0].iov_len = sizeof(pdu);
138124758Semax
139124758Semax	iov[1].iov_base = (void *) &handle;
140124758Semax	iov[1].iov_len = sizeof(handle);
141124758Semax
142124758Semax	do {
143124758Semax		len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
144124758Semax	} while (len < 0 && errno == EINTR);
145124758Semax
146124758Semax	if (len < 0) {
147124758Semax		ss->error = errno;
148124758Semax		return (-1);
149124758Semax	}
150124758Semax
151124758Semax	return ((sdp_receive_error_pdu(ss) < 0)? -1 : 0);
152124758Semax}
153124758Semax
154124758Semaxint32_t
155124758Semaxsdp_change_service(void *xss, uint32_t handle,
156124758Semax		uint8_t const *data, uint32_t datalen)
157124758Semax{
158124758Semax	sdp_session_p	ss = (sdp_session_p) xss;
159124758Semax	struct iovec	iov[3];
160124758Semax	sdp_pdu_t	pdu;
161124758Semax	int32_t		len;
162124758Semax
163124758Semax	if (ss == NULL)
164124758Semax		return (-1);
165124758Semax	if (data == NULL || datalen == 0 || !(ss->flags & SDP_SESSION_LOCAL)) {
166124758Semax		ss->error = EINVAL;
167124758Semax		return (-1);
168124758Semax	}
169124758Semax	if (sizeof(pdu) + sizeof(handle) + datalen > SDP_LOCAL_MTU) {
170124758Semax		ss->error = EMSGSIZE;
171124758Semax		return (-1);
172124758Semax	}
173124758Semax
174124758Semax	pdu.pid = SDP_PDU_SERVICE_CHANGE_REQUEST;
175124758Semax	pdu.tid = htons(++ss->tid);
176124758Semax	pdu.len = htons(sizeof(handle) + datalen);
177124758Semax
178124758Semax	handle = htons(handle);
179124758Semax
180124758Semax	iov[0].iov_base = (void *) &pdu;
181124758Semax	iov[0].iov_len = sizeof(pdu);
182124758Semax
183124758Semax	iov[1].iov_base = (void *) &handle;
184124758Semax	iov[1].iov_len = sizeof(handle);
185124758Semax
186124758Semax	iov[2].iov_base = (void *) data;
187124758Semax	iov[2].iov_len = datalen;
188124758Semax
189124758Semax	do {
190124758Semax		len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
191124758Semax	} while (len < 0 && errno == EINTR);
192124758Semax
193124758Semax	if (len < 0) {
194124758Semax		ss->error = errno;
195124758Semax		return (-1);
196124758Semax	}
197124758Semax
198124758Semax	return ((sdp_receive_error_pdu(ss) < 0)? -1 : 0);
199124758Semax}
200124758Semax
201124758Semaxstatic int32_t
202124758Semaxsdp_receive_error_pdu(sdp_session_p ss)
203124758Semax{
204124758Semax	sdp_pdu_p	pdu;
205124758Semax	int32_t		len;
206124758Semax	uint16_t	error;
207124758Semax
208124758Semax	do {
209124758Semax		len = read(ss->s, ss->rsp, ss->rsp_e - ss->rsp);
210124758Semax	} while (len < 0 && errno == EINTR);
211124758Semax
212124758Semax	if (len < 0) {
213124758Semax		ss->error = errno;
214124758Semax		return (-1);
215124758Semax	}
216124758Semax
217124758Semax	pdu = (sdp_pdu_p) ss->rsp;
218124758Semax	pdu->tid = ntohs(pdu->tid);
219124758Semax	pdu->len = ntohs(pdu->len);
220124758Semax
221124758Semax	if (pdu->pid != SDP_PDU_ERROR_RESPONSE || pdu->tid != ss->tid ||
222124758Semax	    pdu->len < 2 || pdu->len != len - sizeof(*pdu)) {
223124758Semax		ss->error = EIO;
224124758Semax		return (-1);
225124758Semax	}
226124758Semax
227124758Semax	error  = (uint16_t) ss->rsp[sizeof(pdu)] << 8;
228124758Semax	error |= (uint16_t) ss->rsp[sizeof(pdu) + 1];
229124758Semax
230124758Semax	if (error != 0) {
231124758Semax		ss->error = EIO;
232124758Semax		return (-1);
233124758Semax	}
234124758Semax
235124758Semax	return (len);
236124758Semax}
237124758Semax
238