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