xref: /freebsd-src/lib/libsdp/service.c (revision 42b388439bd3795e09258c57a74ce9eec3651c7b)
15e53a4f9SPedro F. Giffuni /*-
207be7a6cSMaksim Yevmenkin  * service.c
307be7a6cSMaksim Yevmenkin  *
4*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
55e53a4f9SPedro F. Giffuni  *
607be7a6cSMaksim Yevmenkin  * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
707be7a6cSMaksim Yevmenkin  * All rights reserved.
807be7a6cSMaksim Yevmenkin  *
907be7a6cSMaksim Yevmenkin  * Redistribution and use in source and binary forms, with or without
1007be7a6cSMaksim Yevmenkin  * modification, are permitted provided that the following conditions
1107be7a6cSMaksim Yevmenkin  * are met:
1207be7a6cSMaksim Yevmenkin  * 1. Redistributions of source code must retain the above copyright
1307be7a6cSMaksim Yevmenkin  *    notice, this list of conditions and the following disclaimer.
1407be7a6cSMaksim Yevmenkin  * 2. Redistributions in binary form must reproduce the above copyright
1507be7a6cSMaksim Yevmenkin  *    notice, this list of conditions and the following disclaimer in the
1607be7a6cSMaksim Yevmenkin  *    documentation and/or other materials provided with the distribution.
1707be7a6cSMaksim Yevmenkin  *
1807be7a6cSMaksim Yevmenkin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1907be7a6cSMaksim Yevmenkin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2007be7a6cSMaksim Yevmenkin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2107be7a6cSMaksim Yevmenkin  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2207be7a6cSMaksim Yevmenkin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2307be7a6cSMaksim Yevmenkin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2407be7a6cSMaksim Yevmenkin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2507be7a6cSMaksim Yevmenkin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2607be7a6cSMaksim Yevmenkin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2707be7a6cSMaksim Yevmenkin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2807be7a6cSMaksim Yevmenkin  * SUCH DAMAGE.
2907be7a6cSMaksim Yevmenkin  *
3007be7a6cSMaksim Yevmenkin  * $Id: service.c,v 1.1 2004/01/13 19:32:36 max Exp $
3107be7a6cSMaksim Yevmenkin  */
3207be7a6cSMaksim Yevmenkin 
3307be7a6cSMaksim Yevmenkin #include <sys/uio.h>
3407be7a6cSMaksim Yevmenkin #include <netinet/in.h>
3507be7a6cSMaksim Yevmenkin #include <arpa/inet.h>
368d6f425dSTakanori Watanabe #define L2CAP_SOCKET_CHECKED
3707be7a6cSMaksim Yevmenkin #include <bluetooth.h>
3807be7a6cSMaksim Yevmenkin #include <errno.h>
3907be7a6cSMaksim Yevmenkin #include <string.h>
4007be7a6cSMaksim Yevmenkin #include <unistd.h>
4107be7a6cSMaksim Yevmenkin 
4207be7a6cSMaksim Yevmenkin #include <sdp-int.h>
4307be7a6cSMaksim Yevmenkin #include <sdp.h>
4407be7a6cSMaksim Yevmenkin 
4507be7a6cSMaksim Yevmenkin static int32_t sdp_receive_error_pdu(sdp_session_p ss);
4607be7a6cSMaksim Yevmenkin 
4707be7a6cSMaksim Yevmenkin int32_t
sdp_register_service(void * xss,uint16_t uuid,bdaddr_p const bdaddr,uint8_t const * data,uint32_t datalen,uint32_t * handle)4807be7a6cSMaksim Yevmenkin sdp_register_service(void *xss, uint16_t uuid, bdaddr_p const bdaddr,
4907be7a6cSMaksim Yevmenkin 		uint8_t const *data, uint32_t datalen, uint32_t *handle)
5007be7a6cSMaksim Yevmenkin {
5107be7a6cSMaksim Yevmenkin 	sdp_session_p	ss = (sdp_session_p) xss;
5207be7a6cSMaksim Yevmenkin 	struct iovec	iov[4];
5307be7a6cSMaksim Yevmenkin 	sdp_pdu_t	pdu;
5407be7a6cSMaksim Yevmenkin 	int32_t		len;
5507be7a6cSMaksim Yevmenkin 
5607be7a6cSMaksim Yevmenkin 	if (ss == NULL)
5707be7a6cSMaksim Yevmenkin 		return (-1);
5807be7a6cSMaksim Yevmenkin 	if (bdaddr == NULL || data == NULL ||
5907be7a6cSMaksim Yevmenkin 	    datalen == 0 || !(ss->flags & SDP_SESSION_LOCAL)) {
6007be7a6cSMaksim Yevmenkin 		ss->error = EINVAL;
6107be7a6cSMaksim Yevmenkin 		return (-1);
6207be7a6cSMaksim Yevmenkin 	}
6307be7a6cSMaksim Yevmenkin 	if (sizeof(pdu)+sizeof(uuid)+sizeof(*bdaddr)+datalen > SDP_LOCAL_MTU) {
6407be7a6cSMaksim Yevmenkin 		ss->error = EMSGSIZE;
6507be7a6cSMaksim Yevmenkin 		return (-1);
6607be7a6cSMaksim Yevmenkin 	}
6707be7a6cSMaksim Yevmenkin 
6807be7a6cSMaksim Yevmenkin 	pdu.pid = SDP_PDU_SERVICE_REGISTER_REQUEST;
6907be7a6cSMaksim Yevmenkin 	pdu.tid = htons(++ss->tid);
7007be7a6cSMaksim Yevmenkin 	pdu.len = htons(sizeof(uuid) + sizeof(*bdaddr) + datalen);
7107be7a6cSMaksim Yevmenkin 
7207be7a6cSMaksim Yevmenkin 	uuid = htons(uuid);
7307be7a6cSMaksim Yevmenkin 
7407be7a6cSMaksim Yevmenkin 	iov[0].iov_base = (void *) &pdu;
7507be7a6cSMaksim Yevmenkin 	iov[0].iov_len = sizeof(pdu);
7607be7a6cSMaksim Yevmenkin 
7707be7a6cSMaksim Yevmenkin 	iov[1].iov_base = (void *) &uuid;
7807be7a6cSMaksim Yevmenkin 	iov[1].iov_len = sizeof(uuid);
7907be7a6cSMaksim Yevmenkin 
8007be7a6cSMaksim Yevmenkin 	iov[2].iov_base = (void *) bdaddr;
8107be7a6cSMaksim Yevmenkin 	iov[2].iov_len = sizeof(*bdaddr);
8207be7a6cSMaksim Yevmenkin 
8307be7a6cSMaksim Yevmenkin 	iov[3].iov_base = (void *) data;
8407be7a6cSMaksim Yevmenkin 	iov[3].iov_len = datalen;
8507be7a6cSMaksim Yevmenkin 
8607be7a6cSMaksim Yevmenkin 	do {
8707be7a6cSMaksim Yevmenkin 		len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
8807be7a6cSMaksim Yevmenkin 	} while (len < 0 && errno == EINTR);
8907be7a6cSMaksim Yevmenkin 
9007be7a6cSMaksim Yevmenkin 	if (len < 0) {
9107be7a6cSMaksim Yevmenkin 		ss->error = errno;
9207be7a6cSMaksim Yevmenkin 		return (-1);
9307be7a6cSMaksim Yevmenkin 	}
9407be7a6cSMaksim Yevmenkin 
9507be7a6cSMaksim Yevmenkin 	len = sdp_receive_error_pdu(ss);
9607be7a6cSMaksim Yevmenkin 	if (len < 0)
9707be7a6cSMaksim Yevmenkin 		return (-1);
9807be7a6cSMaksim Yevmenkin 	if (len != sizeof(pdu) + sizeof(uint16_t) + sizeof(uint32_t)) {
9907be7a6cSMaksim Yevmenkin 		ss->error = EIO;
10007be7a6cSMaksim Yevmenkin 		return (-1);
10107be7a6cSMaksim Yevmenkin 	}
10207be7a6cSMaksim Yevmenkin 
10307be7a6cSMaksim Yevmenkin 	if (handle != NULL) {
10407be7a6cSMaksim Yevmenkin 		*handle  = (uint32_t) ss->rsp[--len];
10507be7a6cSMaksim Yevmenkin 		*handle |= (uint32_t) ss->rsp[--len] << 8;
10607be7a6cSMaksim Yevmenkin 		*handle |= (uint32_t) ss->rsp[--len] << 16;
10707be7a6cSMaksim Yevmenkin 		*handle |= (uint32_t) ss->rsp[--len] << 24;
10807be7a6cSMaksim Yevmenkin 	}
10907be7a6cSMaksim Yevmenkin 
11007be7a6cSMaksim Yevmenkin 	return (0);
11107be7a6cSMaksim Yevmenkin }
11207be7a6cSMaksim Yevmenkin 
11307be7a6cSMaksim Yevmenkin int32_t
sdp_unregister_service(void * xss,uint32_t handle)11407be7a6cSMaksim Yevmenkin sdp_unregister_service(void *xss, uint32_t handle)
11507be7a6cSMaksim Yevmenkin {
11607be7a6cSMaksim Yevmenkin 	sdp_session_p	ss = (sdp_session_p) xss;
11707be7a6cSMaksim Yevmenkin 	struct iovec	iov[2];
11807be7a6cSMaksim Yevmenkin 	sdp_pdu_t	pdu;
11907be7a6cSMaksim Yevmenkin 	int32_t		len;
12007be7a6cSMaksim Yevmenkin 
12107be7a6cSMaksim Yevmenkin 	if (ss == NULL)
12207be7a6cSMaksim Yevmenkin 		return (-1);
12307be7a6cSMaksim Yevmenkin 	if (!(ss->flags & SDP_SESSION_LOCAL)) {
12407be7a6cSMaksim Yevmenkin 		ss->error = EINVAL;
12507be7a6cSMaksim Yevmenkin 		return (-1);
12607be7a6cSMaksim Yevmenkin 	}
12707be7a6cSMaksim Yevmenkin 	if (sizeof(pdu) + sizeof(handle) > SDP_LOCAL_MTU) {
12807be7a6cSMaksim Yevmenkin 		ss->error = EMSGSIZE;
12907be7a6cSMaksim Yevmenkin 		return (-1);
13007be7a6cSMaksim Yevmenkin 	}
13107be7a6cSMaksim Yevmenkin 
13207be7a6cSMaksim Yevmenkin 	pdu.pid = SDP_PDU_SERVICE_UNREGISTER_REQUEST;
13307be7a6cSMaksim Yevmenkin 	pdu.tid = htons(++ss->tid);
13407be7a6cSMaksim Yevmenkin 	pdu.len = htons(sizeof(handle));
13507be7a6cSMaksim Yevmenkin 
13607be7a6cSMaksim Yevmenkin 	handle = htonl(handle);
13707be7a6cSMaksim Yevmenkin 
13807be7a6cSMaksim Yevmenkin 	iov[0].iov_base = (void *) &pdu;
13907be7a6cSMaksim Yevmenkin 	iov[0].iov_len = sizeof(pdu);
14007be7a6cSMaksim Yevmenkin 
14107be7a6cSMaksim Yevmenkin 	iov[1].iov_base = (void *) &handle;
14207be7a6cSMaksim Yevmenkin 	iov[1].iov_len = sizeof(handle);
14307be7a6cSMaksim Yevmenkin 
14407be7a6cSMaksim Yevmenkin 	do {
14507be7a6cSMaksim Yevmenkin 		len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
14607be7a6cSMaksim Yevmenkin 	} while (len < 0 && errno == EINTR);
14707be7a6cSMaksim Yevmenkin 
14807be7a6cSMaksim Yevmenkin 	if (len < 0) {
14907be7a6cSMaksim Yevmenkin 		ss->error = errno;
15007be7a6cSMaksim Yevmenkin 		return (-1);
15107be7a6cSMaksim Yevmenkin 	}
15207be7a6cSMaksim Yevmenkin 
15307be7a6cSMaksim Yevmenkin 	return ((sdp_receive_error_pdu(ss) < 0)? -1 : 0);
15407be7a6cSMaksim Yevmenkin }
15507be7a6cSMaksim Yevmenkin 
15607be7a6cSMaksim Yevmenkin int32_t
sdp_change_service(void * xss,uint32_t handle,uint8_t const * data,uint32_t datalen)15707be7a6cSMaksim Yevmenkin sdp_change_service(void *xss, uint32_t handle,
15807be7a6cSMaksim Yevmenkin 		uint8_t const *data, uint32_t datalen)
15907be7a6cSMaksim Yevmenkin {
16007be7a6cSMaksim Yevmenkin 	sdp_session_p	ss = (sdp_session_p) xss;
16107be7a6cSMaksim Yevmenkin 	struct iovec	iov[3];
16207be7a6cSMaksim Yevmenkin 	sdp_pdu_t	pdu;
16307be7a6cSMaksim Yevmenkin 	int32_t		len;
16407be7a6cSMaksim Yevmenkin 
16507be7a6cSMaksim Yevmenkin 	if (ss == NULL)
16607be7a6cSMaksim Yevmenkin 		return (-1);
16707be7a6cSMaksim Yevmenkin 	if (data == NULL || datalen == 0 || !(ss->flags & SDP_SESSION_LOCAL)) {
16807be7a6cSMaksim Yevmenkin 		ss->error = EINVAL;
16907be7a6cSMaksim Yevmenkin 		return (-1);
17007be7a6cSMaksim Yevmenkin 	}
17107be7a6cSMaksim Yevmenkin 	if (sizeof(pdu) + sizeof(handle) + datalen > SDP_LOCAL_MTU) {
17207be7a6cSMaksim Yevmenkin 		ss->error = EMSGSIZE;
17307be7a6cSMaksim Yevmenkin 		return (-1);
17407be7a6cSMaksim Yevmenkin 	}
17507be7a6cSMaksim Yevmenkin 
17607be7a6cSMaksim Yevmenkin 	pdu.pid = SDP_PDU_SERVICE_CHANGE_REQUEST;
17707be7a6cSMaksim Yevmenkin 	pdu.tid = htons(++ss->tid);
17807be7a6cSMaksim Yevmenkin 	pdu.len = htons(sizeof(handle) + datalen);
17907be7a6cSMaksim Yevmenkin 
18007be7a6cSMaksim Yevmenkin 	handle = htons(handle);
18107be7a6cSMaksim Yevmenkin 
18207be7a6cSMaksim Yevmenkin 	iov[0].iov_base = (void *) &pdu;
18307be7a6cSMaksim Yevmenkin 	iov[0].iov_len = sizeof(pdu);
18407be7a6cSMaksim Yevmenkin 
18507be7a6cSMaksim Yevmenkin 	iov[1].iov_base = (void *) &handle;
18607be7a6cSMaksim Yevmenkin 	iov[1].iov_len = sizeof(handle);
18707be7a6cSMaksim Yevmenkin 
18807be7a6cSMaksim Yevmenkin 	iov[2].iov_base = (void *) data;
18907be7a6cSMaksim Yevmenkin 	iov[2].iov_len = datalen;
19007be7a6cSMaksim Yevmenkin 
19107be7a6cSMaksim Yevmenkin 	do {
19207be7a6cSMaksim Yevmenkin 		len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
19307be7a6cSMaksim Yevmenkin 	} while (len < 0 && errno == EINTR);
19407be7a6cSMaksim Yevmenkin 
19507be7a6cSMaksim Yevmenkin 	if (len < 0) {
19607be7a6cSMaksim Yevmenkin 		ss->error = errno;
19707be7a6cSMaksim Yevmenkin 		return (-1);
19807be7a6cSMaksim Yevmenkin 	}
19907be7a6cSMaksim Yevmenkin 
20007be7a6cSMaksim Yevmenkin 	return ((sdp_receive_error_pdu(ss) < 0)? -1 : 0);
20107be7a6cSMaksim Yevmenkin }
20207be7a6cSMaksim Yevmenkin 
20307be7a6cSMaksim Yevmenkin static int32_t
sdp_receive_error_pdu(sdp_session_p ss)20407be7a6cSMaksim Yevmenkin sdp_receive_error_pdu(sdp_session_p ss)
20507be7a6cSMaksim Yevmenkin {
20607be7a6cSMaksim Yevmenkin 	sdp_pdu_p	pdu;
20707be7a6cSMaksim Yevmenkin 	int32_t		len;
20807be7a6cSMaksim Yevmenkin 	uint16_t	error;
20907be7a6cSMaksim Yevmenkin 
21007be7a6cSMaksim Yevmenkin 	do {
21107be7a6cSMaksim Yevmenkin 		len = read(ss->s, ss->rsp, ss->rsp_e - ss->rsp);
21207be7a6cSMaksim Yevmenkin 	} while (len < 0 && errno == EINTR);
21307be7a6cSMaksim Yevmenkin 
21407be7a6cSMaksim Yevmenkin 	if (len < 0) {
21507be7a6cSMaksim Yevmenkin 		ss->error = errno;
21607be7a6cSMaksim Yevmenkin 		return (-1);
21707be7a6cSMaksim Yevmenkin 	}
21807be7a6cSMaksim Yevmenkin 
21907be7a6cSMaksim Yevmenkin 	pdu = (sdp_pdu_p) ss->rsp;
22007be7a6cSMaksim Yevmenkin 	pdu->tid = ntohs(pdu->tid);
22107be7a6cSMaksim Yevmenkin 	pdu->len = ntohs(pdu->len);
22207be7a6cSMaksim Yevmenkin 
22307be7a6cSMaksim Yevmenkin 	if (pdu->pid != SDP_PDU_ERROR_RESPONSE || pdu->tid != ss->tid ||
22407be7a6cSMaksim Yevmenkin 	    pdu->len < 2 || pdu->len != len - sizeof(*pdu)) {
22507be7a6cSMaksim Yevmenkin 		ss->error = EIO;
22607be7a6cSMaksim Yevmenkin 		return (-1);
22707be7a6cSMaksim Yevmenkin 	}
22807be7a6cSMaksim Yevmenkin 
22907be7a6cSMaksim Yevmenkin 	error  = (uint16_t) ss->rsp[sizeof(pdu)] << 8;
23007be7a6cSMaksim Yevmenkin 	error |= (uint16_t) ss->rsp[sizeof(pdu) + 1];
23107be7a6cSMaksim Yevmenkin 
23207be7a6cSMaksim Yevmenkin 	if (error != 0) {
23307be7a6cSMaksim Yevmenkin 		ss->error = EIO;
23407be7a6cSMaksim Yevmenkin 		return (-1);
23507be7a6cSMaksim Yevmenkin 	}
23607be7a6cSMaksim Yevmenkin 
23707be7a6cSMaksim Yevmenkin 	return (len);
23807be7a6cSMaksim Yevmenkin }
23907be7a6cSMaksim Yevmenkin 
240