15d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/*
25d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Service Discover Protocol server for QEMU L2CAP devices
35d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
45d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Copyright (C) 2008 Andrzej Zaborowski  <balrog@zabor.org>
55d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
65d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * This program is free software; you can redistribute it and/or
75d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * modify it under the terms of the GNU General Public License as
85d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * published by the Free Software Foundation; either version 2 of
95d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * the License, or (at your option) any later version.
105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * This program is distributed in the hope that it will be useful,
125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * but WITHOUT ANY WARRANTY; without even the implied warranty of
135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * GNU General Public License for more details.
155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * You should have received a copy of the GNU General Public License along
17a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner * with this program; if not, see <http://www.gnu.org/licenses/>.
185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */
195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu-common.h"
215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "bt.h"
225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstruct bt_l2cap_sdp_state_s {
245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct bt_l2cap_conn_params_s *channel;
255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct sdp_service_record_s {
275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        int match;
285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        int *uuid;
305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        int uuids;
315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        struct sdp_service_attribute_s {
325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            int match;
335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            int attribute_id;
355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            int len;
365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            void *pair;
375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } *attribute_list;
385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        int attributes;
395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } *service_list;
405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int services;
415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner};
425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic ssize_t sdp_datalen(const uint8_t **element, ssize_t *left)
445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    size_t len = *(*element) ++ & SDP_DSIZE_MASK;
465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!*left)
485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    (*left) --;
505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (len < SDP_DSIZE_NEXT1)
525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 1 << len;
535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    else if (len == SDP_DSIZE_NEXT1) {
545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (*left < 1)
555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return -1;
565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        (*left) --;
575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return *(*element) ++;
595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else if (len == SDP_DSIZE_NEXT2) {
605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (*left < 2)
615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return -1;
625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        (*left) -= 2;
635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len = (*(*element) ++) << 8;
655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return len | (*(*element) ++);
665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (*left < 4)
685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return -1;
695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        (*left) -= 4;
705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len = (*(*element) ++) << 24;
725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len |= (*(*element) ++) << 16;
735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len |= (*(*element) ++) << 8;
745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return len | (*(*element) ++);
755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic const uint8_t bt_base_uuid[12] = {
795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner};
815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int sdp_uuid_match(struct sdp_service_record_s *record,
835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                const uint8_t *uuid, ssize_t datalen)
845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int *lo, hi, val;
865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (datalen == 16 || datalen == 4) {
885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (datalen == 16 && memcmp(uuid + 4, bt_base_uuid, 12))
895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return 0;
905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (uuid[0] | uuid[1])
925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return 0;
935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        uuid += 2;
945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    val = (uuid[0] << 8) | uuid[1];
975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    lo = record->uuid;
985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    hi = record->uuids;
995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (hi >>= 1)
1005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (lo[hi] <= val)
1015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            lo += hi;
1025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return *lo == val;
1045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
1055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define CONTINUATION_PARAM_SIZE	(1 + sizeof(int))
1075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define MAX_PDU_OUT_SIZE	96	/* Arbitrary */
1085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define PDU_HEADER_SIZE		5
1095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define MAX_RSP_PARAM_SIZE	(MAX_PDU_OUT_SIZE - PDU_HEADER_SIZE - \
1105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                CONTINUATION_PARAM_SIZE)
1115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int sdp_svc_match(struct bt_l2cap_sdp_state_s *sdp,
1135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                const uint8_t **req, ssize_t *len)
1145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
1155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    size_t datalen;
1165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i;
1175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if ((**req & ~SDP_DSIZE_MASK) != SDP_DTYPE_UUID)
1195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 1;
1205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    datalen = sdp_datalen(req, len);
1225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (datalen != 2 && datalen != 4 && datalen != 16)
1235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 1;
1245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (i = 0; i < sdp->services; i ++)
1265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (sdp_uuid_match(&sdp->service_list[i], *req, datalen))
1275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            sdp->service_list[i].match = 1;
1285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    (*req) += datalen;
1305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    (*len) -= datalen;
1315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
1335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
1345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic ssize_t sdp_svc_search(struct bt_l2cap_sdp_state_s *sdp,
1365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                uint8_t *rsp, const uint8_t *req, ssize_t len)
1375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
1385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ssize_t seqlen;
1395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i, count, start, end, max;
1405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int32_t handle;
1415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Perform the search */
1435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (i = 0; i < sdp->services; i ++)
1445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        sdp->service_list[i].match = 0;
1455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (len < 1)
1475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -SDP_INVALID_SYNTAX;
1485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) {
1495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        seqlen = sdp_datalen(&req, &len);
1505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (seqlen < 3 || len < seqlen)
1515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return -SDP_INVALID_SYNTAX;
1525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len -= seqlen;
1535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        while (seqlen)
1555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (sdp_svc_match(sdp, &req, &seqlen))
1565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                return -SDP_INVALID_SYNTAX;
1575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else if (sdp_svc_match(sdp, &req, &seqlen))
1585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -SDP_INVALID_SYNTAX;
1595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (len < 3)
1615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -SDP_INVALID_SYNTAX;
162a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner    max = (req[0] << 8) | req[1];
1635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    req += 2;
1645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    len -= 2;
1655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (*req) {
1675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (len <= sizeof(int))
1685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return -SDP_INVALID_SYNTAX;
1695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len -= sizeof(int);
1705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        memcpy(&start, req + 1, sizeof(int));
1715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else
1725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        start = 0;
1735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
174a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner    if (len > 1)
1755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -SDP_INVALID_SYNTAX;
1765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Output the results */
1785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    len = 4;
1795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    count = 0;
1805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    end = start;
1815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (i = 0; i < sdp->services; i ++)
1825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (sdp->service_list[i].match) {
1835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (count >= start && count < max && len + 4 < MAX_RSP_PARAM_SIZE) {
1845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                handle = i;
1855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                memcpy(rsp + len, &handle, 4);
1865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                len += 4;
1875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                end = count + 1;
1885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
1895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            count ++;
1915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
1925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    rsp[0] = count >> 8;
1945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    rsp[1] = count & 0xff;
1955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    rsp[2] = (end - start) >> 8;
1965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    rsp[3] = (end - start) & 0xff;
1975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (end < count) {
1995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        rsp[len ++] = sizeof(int);
2005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        memcpy(rsp + len, &end, sizeof(int));
2015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len += 4;
2025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else
2035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        rsp[len ++] = 0;
2045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return len;
2065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int sdp_attr_match(struct sdp_service_record_s *record,
2095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                const uint8_t **req, ssize_t *len)
2105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
2115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i, start, end;
2125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_2)) {
2145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        (*req) ++;
2155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (*len < 3)
2165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return 1;
2175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        start = (*(*req) ++) << 8;
2195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        start |= *(*req) ++;
2205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        end = start;
2215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        *len -= 3;
2225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_4)) {
2235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        (*req) ++;
2245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (*len < 5)
2255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return 1;
2265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        start = (*(*req) ++) << 8;
2285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        start |= *(*req) ++;
2295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        end = (*(*req) ++) << 8;
2305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        end |= *(*req) ++;
2315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        *len -= 5;
2325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else
2335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 1;
2345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (i = 0; i < record->attributes; i ++)
2365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (record->attribute_list[i].attribute_id >= start &&
2375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        record->attribute_list[i].attribute_id <= end)
2385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            record->attribute_list[i].match = 1;
2395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
2415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic ssize_t sdp_attr_get(struct bt_l2cap_sdp_state_s *sdp,
2445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                uint8_t *rsp, const uint8_t *req, ssize_t len)
2455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
2465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ssize_t seqlen;
2475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i, start, end, max;
2485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int32_t handle;
2495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct sdp_service_record_s *record;
2505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint8_t *lst;
2515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Perform the search */
2535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (len < 7)
2545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -SDP_INVALID_SYNTAX;
2555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    memcpy(&handle, req, 4);
2565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    req += 4;
2575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    len -= 4;
2585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (handle < 0 || handle > sdp->services)
2605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -SDP_INVALID_RECORD_HANDLE;
2615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    record = &sdp->service_list[handle];
2625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (i = 0; i < record->attributes; i ++)
2645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        record->attribute_list[i].match = 0;
2655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    max = (req[0] << 8) | req[1];
2675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    req += 2;
2685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    len -= 2;
2695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (max < 0x0007)
2705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -SDP_INVALID_SYNTAX;
2715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) {
2735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        seqlen = sdp_datalen(&req, &len);
2745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (seqlen < 3 || len < seqlen)
2755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return -SDP_INVALID_SYNTAX;
2765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len -= seqlen;
2775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        while (seqlen)
2795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (sdp_attr_match(record, &req, &seqlen))
2805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                return -SDP_INVALID_SYNTAX;
2815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else if (sdp_attr_match(record, &req, &seqlen))
2825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -SDP_INVALID_SYNTAX;
2835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (len < 1)
2855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -SDP_INVALID_SYNTAX;
2865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (*req) {
2885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (len <= sizeof(int))
2895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return -SDP_INVALID_SYNTAX;
2905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len -= sizeof(int);
2915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        memcpy(&start, req + 1, sizeof(int));
2925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else
2935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        start = 0;
2945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (len > 1)
2965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -SDP_INVALID_SYNTAX;
2975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Output the results */
2995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    lst = rsp + 2;
3005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    max = MIN(max, MAX_RSP_PARAM_SIZE);
3015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    len = 3 - start;
3025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    end = 0;
3035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (i = 0; i < record->attributes; i ++)
3045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (record->attribute_list[i].match) {
3055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (len >= 0 && len + record->attribute_list[i].len < max) {
3065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                memcpy(lst + len, record->attribute_list[i].pair,
3075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                record->attribute_list[i].len);
3085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                end = len + record->attribute_list[i].len;
3095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
3105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            len += record->attribute_list[i].len;
3115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
3125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (0 >= start) {
3135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner       lst[0] = SDP_DTYPE_SEQ | SDP_DSIZE_NEXT2;
3145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner       lst[1] = (len + start - 3) >> 8;
3155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner       lst[2] = (len + start - 3) & 0xff;
3165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
3175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    rsp[0] = end >> 8;
3195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    rsp[1] = end & 0xff;
3205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (end < len) {
3225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len = end + start;
3235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        lst[end ++] = sizeof(int);
3245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        memcpy(lst + end, &len, sizeof(int));
3255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        end += sizeof(int);
3265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else
3275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        lst[end ++] = 0;
3285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return end + 2;
3305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int sdp_svc_attr_match(struct bt_l2cap_sdp_state_s *sdp,
3335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                const uint8_t **req, ssize_t *len)
3345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i, j, start, end;
3365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct sdp_service_record_s *record;
3375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_2)) {
3395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        (*req) ++;
3405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (*len < 3)
3415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return 1;
3425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        start = (*(*req) ++) << 8;
3445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        start |= *(*req) ++;
3455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        end = start;
3465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        *len -= 3;
3475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_4)) {
3485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        (*req) ++;
3495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (*len < 5)
3505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return 1;
3515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        start = (*(*req) ++) << 8;
3535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        start |= *(*req) ++;
3545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        end = (*(*req) ++) << 8;
3555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        end |= *(*req) ++;
3565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        *len -= 5;
3575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else
3585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 1;
3595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (i = 0; i < sdp->services; i ++)
3615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if ((record = &sdp->service_list[i])->match)
3625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            for (j = 0; j < record->attributes; j ++)
3635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                if (record->attribute_list[j].attribute_id >= start &&
3645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                record->attribute_list[j].attribute_id <= end)
3655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    record->attribute_list[j].match = 1;
3665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
3685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic ssize_t sdp_svc_search_attr_get(struct bt_l2cap_sdp_state_s *sdp,
3715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                uint8_t *rsp, const uint8_t *req, ssize_t len)
3725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ssize_t seqlen;
3745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i, j, start, end, max;
3755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct sdp_service_record_s *record;
3765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint8_t *lst;
3775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Perform the search */
3795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (i = 0; i < sdp->services; i ++) {
3805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        sdp->service_list[i].match = 0;
3815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            for (j = 0; j < sdp->service_list[i].attributes; j ++)
3825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                sdp->service_list[i].attribute_list[j].match = 0;
3835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
3845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (len < 1)
3865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -SDP_INVALID_SYNTAX;
3875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) {
3885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        seqlen = sdp_datalen(&req, &len);
3895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (seqlen < 3 || len < seqlen)
3905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return -SDP_INVALID_SYNTAX;
3915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len -= seqlen;
3925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        while (seqlen)
3945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (sdp_svc_match(sdp, &req, &seqlen))
3955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                return -SDP_INVALID_SYNTAX;
3965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else if (sdp_svc_match(sdp, &req, &seqlen))
3975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -SDP_INVALID_SYNTAX;
3985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (len < 3)
4005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -SDP_INVALID_SYNTAX;
4015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    max = (req[0] << 8) | req[1];
4025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    req += 2;
4035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    len -= 2;
4045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (max < 0x0007)
4055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -SDP_INVALID_SYNTAX;
4065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) {
4085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        seqlen = sdp_datalen(&req, &len);
4095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (seqlen < 3 || len < seqlen)
4105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return -SDP_INVALID_SYNTAX;
4115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len -= seqlen;
4125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        while (seqlen)
4145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (sdp_svc_attr_match(sdp, &req, &seqlen))
4155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                return -SDP_INVALID_SYNTAX;
4165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else if (sdp_svc_attr_match(sdp, &req, &seqlen))
4175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -SDP_INVALID_SYNTAX;
4185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (len < 1)
4205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -SDP_INVALID_SYNTAX;
4215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (*req) {
4235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (len <= sizeof(int))
4245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return -SDP_INVALID_SYNTAX;
4255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len -= sizeof(int);
4265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        memcpy(&start, req + 1, sizeof(int));
4275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else
4285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        start = 0;
4295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (len > 1)
4315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -SDP_INVALID_SYNTAX;
4325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Output the results */
4345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* This assumes empty attribute lists are never to be returned even
4355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * for matching Service Records.  In practice this shouldn't happen
4365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * as the requestor will usually include the always present
4375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * ServiceRecordHandle AttributeID in AttributeIDList.  */
4385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    lst = rsp + 2;
4395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    max = MIN(max, MAX_RSP_PARAM_SIZE);
4405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    len = 3 - start;
4415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    end = 0;
4425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (i = 0; i < sdp->services; i ++)
4435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if ((record = &sdp->service_list[i])->match) {
4445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            len += 3;
4455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            seqlen = len;
4465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            for (j = 0; j < record->attributes; j ++)
4475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                if (record->attribute_list[j].match) {
4485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    if (len >= 0)
4495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        if (len + record->attribute_list[j].len < max) {
4505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                            memcpy(lst + len, record->attribute_list[j].pair,
4515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                            record->attribute_list[j].len);
4525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                            end = len + record->attribute_list[j].len;
4535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        }
4545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    len += record->attribute_list[j].len;
4555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                }
4565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (seqlen == len)
4575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                len -= 3;
4585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            else if (seqlen >= 3 && seqlen < max) {
4595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                lst[seqlen - 3] = SDP_DTYPE_SEQ | SDP_DSIZE_NEXT2;
4605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                lst[seqlen - 2] = (len - seqlen) >> 8;
4615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                lst[seqlen - 1] = (len - seqlen) & 0xff;
4625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
4635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
4645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (len == 3 - start)
4655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len -= 3;
4665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    else if (0 >= start) {
4675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner       lst[0] = SDP_DTYPE_SEQ | SDP_DSIZE_NEXT2;
4685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner       lst[1] = (len + start - 3) >> 8;
4695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner       lst[2] = (len + start - 3) & 0xff;
4705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
4715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    rsp[0] = end >> 8;
4735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    rsp[1] = end & 0xff;
4745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (end < len) {
4765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len = end + start;
4775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        lst[end ++] = sizeof(int);
4785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        memcpy(lst + end, &len, sizeof(int));
4795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        end += sizeof(int);
4805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else
4815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        lst[end ++] = 0;
4825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return end + 2;
4845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
4855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_l2cap_sdp_sdu_in(void *opaque, const uint8_t *data, int len)
4875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
4885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct bt_l2cap_sdp_state_s *sdp = opaque;
4895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    enum bt_sdp_cmd pdu_id;
4905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint8_t rsp[MAX_PDU_OUT_SIZE - PDU_HEADER_SIZE], *sdu_out;
4915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int transaction_id, plen;
4925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int err = 0;
4935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int rsp_len = 0;
4945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (len < 5) {
4965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "%s: short SDP PDU (%iB).\n", __FUNCTION__, len);
4975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
4985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
4995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    pdu_id = *data ++;
5015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    transaction_id = (data[0] << 8) | data[1];
5025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    plen = (data[2] << 8) | data[3];
5035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    data += 4;
5045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    len -= 5;
5055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (len != plen) {
5075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "%s: wrong SDP PDU length (%iB != %iB).\n",
5085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        __FUNCTION__, plen, len);
5095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        err = SDP_INVALID_PDU_SIZE;
5105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto respond;
5115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
5125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    switch (pdu_id) {
5145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case SDP_SVC_SEARCH_REQ:
5155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        rsp_len = sdp_svc_search(sdp, rsp, data, len);
5165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        pdu_id = SDP_SVC_SEARCH_RSP;
5175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
5185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case SDP_SVC_ATTR_REQ:
5205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        rsp_len = sdp_attr_get(sdp, rsp, data, len);
5215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        pdu_id = SDP_SVC_ATTR_RSP;
5225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
5235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case SDP_SVC_SEARCH_ATTR_REQ:
5255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        rsp_len = sdp_svc_search_attr_get(sdp, rsp, data, len);
5265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        pdu_id = SDP_SVC_SEARCH_ATTR_RSP;
5275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
5285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case SDP_ERROR_RSP:
5305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case SDP_SVC_ATTR_RSP:
5315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case SDP_SVC_SEARCH_RSP:
5325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case SDP_SVC_SEARCH_ATTR_RSP:
5335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    default:
5345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "%s: unexpected SDP PDU ID %02x.\n",
5355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        __FUNCTION__, pdu_id);
5365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        err = SDP_INVALID_SYNTAX;
5375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
5385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
5395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (rsp_len < 0) {
5415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        err = -rsp_len;
5425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        rsp_len = 0;
5435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
5445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerrespond:
5465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (err) {
5475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        pdu_id = SDP_ERROR_RSP;
5485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        rsp[rsp_len ++] = err >> 8;
5495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        rsp[rsp_len ++] = err & 0xff;
5505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
5515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sdu_out = sdp->channel->sdu_out(sdp->channel, rsp_len + PDU_HEADER_SIZE);
5535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sdu_out[0] = pdu_id;
5555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sdu_out[1] = transaction_id >> 8;
5565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sdu_out[2] = transaction_id & 0xff;
5575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sdu_out[3] = rsp_len >> 8;
5585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sdu_out[4] = rsp_len & 0xff;
5595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    memcpy(sdu_out + PDU_HEADER_SIZE, rsp, rsp_len);
5605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sdp->channel->sdu_submit(sdp->channel);
5625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
5635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_l2cap_sdp_close_ch(void *opaque)
5655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
5665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct bt_l2cap_sdp_state_s *sdp = opaque;
5675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i;
5685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (i = 0; i < sdp->services; i ++) {
5705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_free(sdp->service_list[i].attribute_list->pair);
5715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_free(sdp->service_list[i].attribute_list);
5725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_free(sdp->service_list[i].uuid);
5735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
5745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_free(sdp->service_list);
5755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_free(sdp);
5765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
5775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstruct sdp_def_service_s {
5795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint16_t class_uuid;
5805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct sdp_def_attribute_s {
5815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        uint16_t id;
5825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        struct sdp_def_data_element_s {
5835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            uint8_t type;
5845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            union {
5855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                uint32_t uint;
5865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                const char *str;
5875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                struct sdp_def_data_element_s *list;
5885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            } value;
5895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } data;
5905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } attributes[];
5915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner};
5925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* Calculate a safe byte count to allocate that will store the given
5945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * element, at the same time count elements of a UUID type.  */
5955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int sdp_attr_max_size(struct sdp_def_data_element_s *element,
5965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                int *uuids)
5975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
5985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int type = element->type & ~SDP_DSIZE_MASK;
5995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int len;
6005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (type == SDP_DTYPE_UINT || type == SDP_DTYPE_UUID ||
6025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    type == SDP_DTYPE_BOOL) {
6035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (type == SDP_DTYPE_UUID)
6045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            (*uuids) ++;
6055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 1 + (1 << (element->type & SDP_DSIZE_MASK));
6065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
6075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (type == SDP_DTYPE_STRING || type == SDP_DTYPE_URL) {
6095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (element->type & SDP_DSIZE_MASK) {
6105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            for (len = 0; element->value.str[len] |
6115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                            element->value.str[len + 1]; len ++);
6125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return len;
6135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else
6145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return 2 + strlen(element->value.str);
6155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
6165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (type != SDP_DTYPE_SEQ)
6185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        exit(-1);
6195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    len = 2;
6205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    element = element->value.list;
6215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (element->type)
6225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len += sdp_attr_max_size(element ++, uuids);
6235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (len > 255)
6245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        exit (-1);
6255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return len;
6275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int sdp_attr_write(uint8_t *data,
6305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                struct sdp_def_data_element_s *element, int **uuid)
6315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int type = element->type & ~SDP_DSIZE_MASK;
6335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int len = 0;
6345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (type == SDP_DTYPE_UINT || type == SDP_DTYPE_BOOL) {
6365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        data[len ++] = element->type;
6375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if ((element->type & SDP_DSIZE_MASK) == SDP_DSIZE_1)
6385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            data[len ++] = (element->value.uint >>  0) & 0xff;
6395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        else if ((element->type & SDP_DSIZE_MASK) == SDP_DSIZE_2) {
6405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            data[len ++] = (element->value.uint >>  8) & 0xff;
6415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            data[len ++] = (element->value.uint >>  0) & 0xff;
6425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else if ((element->type & SDP_DSIZE_MASK) == SDP_DSIZE_4) {
6435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            data[len ++] = (element->value.uint >>  24) & 0xff;
6445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            data[len ++] = (element->value.uint >>  16) & 0xff;
6455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            data[len ++] = (element->value.uint >>  8) & 0xff;
6465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            data[len ++] = (element->value.uint >>  0) & 0xff;
6475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
6485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return len;
6505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
6515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (type == SDP_DTYPE_UUID) {
6535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        *(*uuid) ++ = element->value.uint;
6545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        data[len ++] = element->type;
6565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        data[len ++] = (element->value.uint >>  24) & 0xff;
6575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        data[len ++] = (element->value.uint >>  16) & 0xff;
6585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        data[len ++] = (element->value.uint >>  8) & 0xff;
6595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        data[len ++] = (element->value.uint >>  0) & 0xff;
6605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        memcpy(data + len, bt_base_uuid, 12);
6615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return len + 12;
6635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
6645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    data[0] = type | SDP_DSIZE_NEXT1;
6665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (type == SDP_DTYPE_STRING || type == SDP_DTYPE_URL) {
6675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (element->type & SDP_DSIZE_MASK)
6685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            for (len = 0; element->value.str[len] |
6695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                            element->value.str[len + 1]; len ++);
6705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        else
6715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            len = strlen(element->value.str);
6725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        memcpy(data + 2, element->value.str, data[1] = len);
6735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return len + 2;
6755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
6765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    len = 2;
6785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    element = element->value.list;
6795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (element->type)
6805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len += sdp_attr_write(data + len, element ++, uuid);
6815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    data[1] = len - 2;
6825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return len;
6845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int sdp_attributeid_compare(const struct sdp_service_attribute_s *a,
6875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                const struct sdp_service_attribute_s *b)
6885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return (int) b->attribute_id - a->attribute_id;
6905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int sdp_uuid_compare(const int *a, const int *b)
6935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return *a - *b;
6955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void sdp_service_record_build(struct sdp_service_record_s *record,
6985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                struct sdp_def_service_s *def, int handle)
6995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
7005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int len = 0;
7015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint8_t *data;
7025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int *uuid;
7035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    record->uuids = 0;
7055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (def->attributes[record->attributes].data.type) {
7065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len += 3;
7075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len += sdp_attr_max_size(&def->attributes[record->attributes ++].data,
7085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        &record->uuids);
7095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
7105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    record->uuids = 1 << ffs(record->uuids - 1);
7115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    record->attribute_list =
7125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            qemu_mallocz(record->attributes * sizeof(*record->attribute_list));
7135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    record->uuid =
7145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            qemu_mallocz(record->uuids * sizeof(*record->uuid));
7155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    data = qemu_malloc(len);
7165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    record->attributes = 0;
7185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uuid = record->uuid;
7195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (def->attributes[record->attributes].data.type) {
7205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        record->attribute_list[record->attributes].pair = data;
7215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len = 0;
7235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        data[len ++] = SDP_DTYPE_UINT | SDP_DSIZE_2;
7245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        data[len ++] = def->attributes[record->attributes].id >> 8;
7255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        data[len ++] = def->attributes[record->attributes].id & 0xff;
7265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len += sdp_attr_write(data + len,
7275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        &def->attributes[record->attributes].data, &uuid);
7285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* Special case: assign a ServiceRecordHandle in sequence */
7305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (def->attributes[record->attributes].id == SDP_ATTR_RECORD_HANDLE)
7315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            def->attributes[record->attributes].data.value.uint = handle;
7325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* Note: we could also assign a ServiceDescription based on
7335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         * sdp->device.device->lmp_name.  */
7345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        record->attribute_list[record->attributes ++].len = len;
7365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        data += len;
7375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
7385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Sort the attribute list by the AttributeID */
7405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qsort(record->attribute_list, record->attributes,
7415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    sizeof(*record->attribute_list),
7425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    (void *) sdp_attributeid_compare);
7435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Sort the searchable UUIDs list for bisection */
7445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qsort(record->uuid, record->uuids,
7455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    sizeof(*record->uuid),
7465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    (void *) sdp_uuid_compare);
7475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
7485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void sdp_service_db_build(struct bt_l2cap_sdp_state_s *sdp,
7505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                struct sdp_def_service_s **service)
7515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
7525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sdp->services = 0;
7535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (service[sdp->services])
7545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        sdp->services ++;
7555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sdp->service_list =
7565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            qemu_mallocz(sdp->services * sizeof(*sdp->service_list));
7575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sdp->services = 0;
7595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (*service) {
7605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        sdp_service_record_build(&sdp->service_list[sdp->services],
7615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        *service, sdp->services);
7625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        service ++;
7635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        sdp->services ++;
7645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
7655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
7665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define LAST { .type = 0 }
7685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define SERVICE(name, attrs)				\
7695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    static struct sdp_def_service_s glue(glue(sdp_service_, name), _s) = { \
7705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        .attributes = { attrs { .data = LAST } },	\
7715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    };
7725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define ATTRIBUTE(attrid, val)	{ .id = glue(SDP_ATTR_, attrid), .data = val },
7735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define UINT8(val)	{				\
7745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        .type       = SDP_DTYPE_UINT | SDP_DSIZE_1,	\
7755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        .value.uint = val,				\
7765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    },
7775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define UINT16(val)	{				\
7785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        .type       = SDP_DTYPE_UINT | SDP_DSIZE_2,	\
7795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        .value.uint = val,				\
7805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    },
7815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define UINT32(val)	{				\
7825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        .type       = SDP_DTYPE_UINT | SDP_DSIZE_4,	\
7835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        .value.uint = val,				\
7845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    },
7855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define UUID128(val)	{				\
7865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        .type       = SDP_DTYPE_UUID | SDP_DSIZE_16,	\
7875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        .value.uint = val,				\
7885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    },
7895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define TRUE	{				\
7905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        .type       = SDP_DTYPE_BOOL | SDP_DSIZE_1,	\
7915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        .value.uint = 1,				\
7925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    },
7935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define FALSE	{				\
7945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        .type       = SDP_DTYPE_BOOL | SDP_DSIZE_1,	\
7955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        .value.uint = 0,				\
7965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    },
7975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define STRING(val)	{				\
7985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        .type       = SDP_DTYPE_STRING,			\
7995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        .value.str  = val,				\
8005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    },
8015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define ARRAY(...)	{				\
8025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        .type       = SDP_DTYPE_STRING | SDP_DSIZE_2,	\
8035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        .value.str  = (char []) { __VA_ARGS__, 0, 0 },	\
8045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    },
8055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define URL(val)	{				\
8065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        .type       = SDP_DTYPE_URL,			\
8075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        .value.str  = val,				\
8085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    },
8095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#if 1
8105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define LIST(val)	{				\
8115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        .type       = SDP_DTYPE_SEQ,			\
8125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        .value.list = (struct sdp_def_data_element_s []) { val LAST }, \
8135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    },
8145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
8155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* Try to keep each single attribute below MAX_PDU_OUT_SIZE bytes
8175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * in resulting SDP data representation size.  */
8185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerSERVICE(hid,
8205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(RECORD_HANDLE,   UINT32(0))	/* Filled in later */
8215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(SVCLASS_ID_LIST, LIST(UUID128(HID_SVCLASS_ID)))
8225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(RECORD_STATE,    UINT32(1))
8235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(PROTO_DESC_LIST, LIST(
8245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        LIST(UUID128(L2CAP_UUID) UINT16(BT_PSM_HID_CTRL))
8255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        LIST(UUID128(HIDP_UUID))
8265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ))
8275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(BROWSE_GRP_LIST, LIST(UUID128(0x1002)))
8285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(LANG_BASE_ATTR_ID_LIST, LIST(
8295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        UINT16(0x656e) UINT16(0x006a) UINT16(0x0100)
8305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ))
8315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(PFILE_DESC_LIST, LIST(
8325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        LIST(UUID128(HID_PROFILE_ID) UINT16(0x0100))
8335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ))
8345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(DOC_URL,         URL("http://bellard.org/qemu/user-doc.html"))
8355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(SVCNAME_PRIMARY, STRING("QEMU Bluetooth HID"))
8365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(SVCDESC_PRIMARY, STRING("QEMU Keyboard/Mouse"))
8375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU " QEMU_VERSION))
8385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Profile specific */
8405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(DEVICE_RELEASE_NUMBER,	UINT16(0x0091)) /* Deprecated, remove */
8415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(PARSER_VERSION,		UINT16(0x0111))
8425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* TODO: extract from l2cap_device->device.class[0] */
8435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(DEVICE_SUBCLASS,		UINT8(0x40))
8445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(COUNTRY_CODE,		UINT8(0x15))
8455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(VIRTUAL_CABLE,		TRUE)
8465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(RECONNECT_INITIATE,	FALSE)
8475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* TODO: extract from hid->usbdev->report_desc */
8485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(DESCRIPTOR_LIST,		LIST(
8495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        LIST(UINT8(0x22) ARRAY(
8505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0x05, 0x01,	/* Usage Page (Generic Desktop) */
8515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0x09, 0x06,	/* Usage (Keyboard) */
8525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0xa1, 0x01,	/* Collection (Application) */
8535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0x75, 0x01,	/*   Report Size (1) */
8545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0x95, 0x08,	/*   Report Count (8) */
8555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0x05, 0x07,	/*   Usage Page (Key Codes) */
8565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0x19, 0xe0,	/*   Usage Minimum (224) */
8575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0x29, 0xe7,	/*   Usage Maximum (231) */
8585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0x15, 0x00,	/*   Logical Minimum (0) */
8595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0x25, 0x01,	/*   Logical Maximum (1) */
8605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0x81, 0x02,	/*   Input (Data, Variable, Absolute) */
8615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0x95, 0x01,	/*   Report Count (1) */
8625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0x75, 0x08,	/*   Report Size (8) */
8635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0x81, 0x01,	/*   Input (Constant) */
8645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0x95, 0x05,	/*   Report Count (5) */
8655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0x75, 0x01,	/*   Report Size (1) */
8665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0x05, 0x08,	/*   Usage Page (LEDs) */
8675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0x19, 0x01,	/*   Usage Minimum (1) */
8685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0x29, 0x05,	/*   Usage Maximum (5) */
8695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0x91, 0x02,	/*   Output (Data, Variable, Absolute) */
8705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0x95, 0x01,	/*   Report Count (1) */
8715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0x75, 0x03,	/*   Report Size (3) */
8725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0x91, 0x01,	/*   Output (Constant) */
8735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0x95, 0x06,	/*   Report Count (6) */
8745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0x75, 0x08,	/*   Report Size (8) */
8755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0x15, 0x00,	/*   Logical Minimum (0) */
8765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0x25, 0xff,	/*   Logical Maximum (255) */
8775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0x05, 0x07,	/*   Usage Page (Key Codes) */
8785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0x19, 0x00,	/*   Usage Minimum (0) */
8795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0x29, 0xff,	/*   Usage Maximum (255) */
8805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0x81, 0x00,	/*   Input (Data, Array) */
8815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            0xc0	/* End Collection */
8825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ))))
8835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(LANG_ID_BASE_LIST,	LIST(
8845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        LIST(UINT16(0x0409) UINT16(0x0100))
8855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ))
8865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(SDP_DISABLE,		FALSE)
8875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(BATTERY_POWER,		TRUE)
8885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(REMOTE_WAKEUP,		TRUE)
8895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(BOOT_DEVICE,		TRUE)	/* XXX: untested */
8905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(SUPERVISION_TIMEOUT,	UINT16(0x0c80))
8915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(NORMALLY_CONNECTABLE,	TRUE)
8925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(PROFILE_VERSION,		UINT16(0x0100))
8935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner)
8945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerSERVICE(sdp,
8965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(RECORD_HANDLE,   UINT32(0))	/* Filled in later */
8975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(SVCLASS_ID_LIST, LIST(UUID128(SDP_SERVER_SVCLASS_ID)))
8985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(RECORD_STATE,    UINT32(1))
8995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(PROTO_DESC_LIST, LIST(
9005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        LIST(UUID128(L2CAP_UUID) UINT16(BT_PSM_SDP))
9015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        LIST(UUID128(SDP_UUID))
9025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ))
9035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(BROWSE_GRP_LIST, LIST(UUID128(0x1002)))
9045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(LANG_BASE_ATTR_ID_LIST, LIST(
9055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        UINT16(0x656e) UINT16(0x006a) UINT16(0x0100)
9065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ))
9075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(PFILE_DESC_LIST, LIST(
9085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        LIST(UUID128(SDP_SERVER_PROFILE_ID) UINT16(0x0100))
9095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ))
9105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(DOC_URL,         URL("http://bellard.org/qemu/user-doc.html"))
9115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU " QEMU_VERSION))
9125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Profile specific */
9145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(VERSION_NUM_LIST, LIST(UINT16(0x0100)))
9155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(SVCDB_STATE    , UINT32(1))
9165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner)
9175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerSERVICE(pnp,
9195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(RECORD_HANDLE,   UINT32(0))	/* Filled in later */
9205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(SVCLASS_ID_LIST, LIST(UUID128(PNP_INFO_SVCLASS_ID)))
9215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(RECORD_STATE,    UINT32(1))
9225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(PROTO_DESC_LIST, LIST(
9235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        LIST(UUID128(L2CAP_UUID) UINT16(BT_PSM_SDP))
9245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        LIST(UUID128(SDP_UUID))
9255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ))
9265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(BROWSE_GRP_LIST, LIST(UUID128(0x1002)))
9275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(LANG_BASE_ATTR_ID_LIST, LIST(
9285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        UINT16(0x656e) UINT16(0x006a) UINT16(0x0100)
9295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ))
9305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(PFILE_DESC_LIST, LIST(
9315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        LIST(UUID128(PNP_INFO_PROFILE_ID) UINT16(0x0100))
9325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ))
9335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(DOC_URL,         URL("http://bellard.org/qemu/user-doc.html"))
9345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU " QEMU_VERSION))
9355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Profile specific */
9375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(SPECIFICATION_ID, UINT16(0x0100))
9385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(VERSION,         UINT16(0x0100))
9395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ATTRIBUTE(PRIMARY_RECORD,  TRUE)
9405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner)
9415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int bt_l2cap_sdp_new_ch(struct bt_l2cap_device_s *dev,
9435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                struct bt_l2cap_conn_params_s *params)
9445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
9455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct bt_l2cap_sdp_state_s *sdp = qemu_mallocz(sizeof(*sdp));
9465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct sdp_def_service_s *services[] = {
9475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        &sdp_service_sdp_s,
9485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        &sdp_service_hid_s,
9495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        &sdp_service_pnp_s,
9505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        NULL,
9515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    };
9525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sdp->channel = params;
9545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sdp->channel->opaque = sdp;
9555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sdp->channel->close = bt_l2cap_sdp_close_ch;
9565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sdp->channel->sdu_in = bt_l2cap_sdp_sdu_in;
9575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sdp_service_db_build(sdp, services);
9595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
9615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
9625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid bt_l2cap_sdp_init(struct bt_l2cap_device_s *dev)
9645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
9655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    bt_l2cap_psm_register(dev, BT_PSM_SDP,
9665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    MAX_PDU_OUT_SIZE, bt_l2cap_sdp_new_ch);
9675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
968