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