static void search_completed_cb(uint8_t type, uint16_t status, uint8_t *rsp, size_t size, void *user_data) { struct search_context *ctxt = user_data; sdp_list_t *recs = NULL; int scanned, seqlen = 0, bytesleft = size; uint8_t dataType; int err = 0; if (status || type != SDP_SVC_SEARCH_ATTR_RSP) { err = -EPROTO; goto done; } scanned = sdp_extract_seqtype(rsp, bytesleft, &dataType, &seqlen); if (!scanned || !seqlen) goto done; rsp += scanned; bytesleft -= scanned; do { sdp_record_t *rec; int recsize; recsize = 0; rec = sdp_extract_pdu(rsp, bytesleft, &recsize); if (!rec) break; if (!recsize) { sdp_record_free(rec); break; } scanned += recsize; rsp += recsize; bytesleft -= recsize; recs = sdp_list_append(recs, rec); } while (scanned < (ssize_t) size && bytesleft > 0); done: cache_sdp_session(&ctxt->src, &ctxt->dst, ctxt->session); if (ctxt->cb) ctxt->cb(recs, err, ctxt->user_data); if (recs) sdp_list_free(recs, (sdp_free_func_t) sdp_record_free); search_context_cleanup(ctxt); }
/* FIXME: refactor for server-side */ static sdp_record_t *extract_pdu_server(bdaddr_t *device, uint8_t *p, unsigned int bufsize, uint32_t handleExpected, int *scanned) { int extractStatus = -1, localExtractedLength = 0; uint8_t dtd; int seqlen = 0; sdp_record_t *rec = NULL; uint16_t attrId, lookAheadAttrId; sdp_data_t *pAttr = NULL; uint32_t handle = 0xffffffff; *scanned = sdp_extract_seqtype(p, bufsize, &dtd, &seqlen); p += *scanned; bufsize -= *scanned; if (bufsize < sizeof(uint8_t) + sizeof(uint8_t)) { SDPDBG("Unexpected end of packet"); return NULL; } lookAheadAttrId = bt_get_be16(p + sizeof(uint8_t)); SDPDBG("Look ahead attr id : %d", lookAheadAttrId); if (lookAheadAttrId == SDP_ATTR_RECORD_HANDLE) { if (bufsize < (sizeof(uint8_t) * 2) + sizeof(uint16_t) + sizeof(uint32_t)) { SDPDBG("Unexpected end of packet"); return NULL; } handle = bt_get_be32(p + sizeof(uint8_t) + sizeof(uint16_t) + sizeof(uint8_t)); SDPDBG("SvcRecHandle : 0x%x", handle); rec = sdp_record_find(handle); } else if (handleExpected != 0xffffffff) rec = sdp_record_find(handleExpected); if (!rec) { rec = sdp_record_alloc(); rec->attrlist = NULL; if (lookAheadAttrId == SDP_ATTR_RECORD_HANDLE) { rec->handle = handle; sdp_record_add(device, rec); } else if (handleExpected != 0xffffffff) { rec->handle = handleExpected; sdp_record_add(device, rec); } } else { sdp_list_free(rec->attrlist, (sdp_free_func_t) sdp_data_free); rec->attrlist = NULL; } while (localExtractedLength < seqlen) { int attrSize = sizeof(uint8_t); int attrValueLength = 0; if (bufsize < attrSize + sizeof(uint16_t)) { SDPDBG("Unexpected end of packet: Terminating extraction of attributes"); break; } SDPDBG("Extract PDU, sequenceLength: %d localExtractedLength: %d", seqlen, localExtractedLength); dtd = *(uint8_t *) p; attrId = bt_get_be16(p + attrSize); attrSize += sizeof(uint16_t); SDPDBG("DTD of attrId : %d Attr id : 0x%x", dtd, attrId); pAttr = sdp_extract_attr(p + attrSize, bufsize - attrSize, &attrValueLength, rec); SDPDBG("Attr id : 0x%x attrValueLength : %d", attrId, attrValueLength); attrSize += attrValueLength; if (pAttr == NULL) { SDPDBG("Terminating extraction of attributes"); break; } localExtractedLength += attrSize; p += attrSize; bufsize -= attrSize; sdp_attr_replace(rec, attrId, pAttr); extractStatus = 0; SDPDBG("Extract PDU, seqLength: %d localExtractedLength: %d", seqlen, localExtractedLength); } if (extractStatus == 0) { SDPDBG("Successful extracting of Svc Rec attributes"); #ifdef SDP_DEBUG sdp_print_service_attr(rec->attrlist); #endif *scanned += seqlen; } return rec; }
static void search_callback(uint8_t type, uint16_t status, uint8_t *rsp, size_t size, void *user_data) { struct bluetooth_session *session = user_data; unsigned int scanned, bytesleft = size; int seqlen = 0; uint8_t dataType; uint16_t port = 0; GError *gerr = NULL; if (status || type != SDP_SVC_SEARCH_ATTR_RSP) goto failed; scanned = sdp_extract_seqtype(rsp, bytesleft, &dataType, &seqlen); if (!scanned || !seqlen) goto failed; rsp += scanned; bytesleft -= scanned; do { sdp_record_t *rec; sdp_list_t *protos; sdp_data_t *data; int recsize, ch = -1; recsize = 0; rec = sdp_extract_pdu(rsp, bytesleft, &recsize); if (!rec) break; if (!recsize) { sdp_record_free(rec); break; } if (!sdp_get_access_protos(rec, &protos)) { ch = sdp_get_proto_port(protos, RFCOMM_UUID); sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL); sdp_list_free(protos, NULL); protos = NULL; } data = sdp_data_get(rec, 0x0200); /* PSM must be odd and lsb of upper byte must be 0 */ if (data != NULL && (data->val.uint16 & 0x0101) == 0x0001) ch = data->val.uint16; sdp_record_free(rec); if (ch > 0) { port = ch; break; } scanned += recsize; rsp += recsize; bytesleft -= recsize; } while (scanned < size && bytesleft > 0); if (port == 0) goto failed; session->port = port; g_io_channel_set_close_on_unref(session->io, FALSE); g_io_channel_unref(session->io); session->io = transport_connect(&session->src, &session->dst, port, transport_callback, session); if (session->io != NULL) { sdp_close(session->sdp); session->sdp = NULL; return; } failed: if (session->io != NULL) { g_io_channel_shutdown(session->io, TRUE, NULL); g_io_channel_unref(session->io); session->io = NULL; } g_set_error(&gerr, OBC_BT_ERROR, -EIO, "Unable to find service record"); if (session->func) session->func(session->io, gerr, session->user_data); g_clear_error(&gerr); session_destroy(session); }
/* * Generic data element sequence extractor. Builds * a list whose elements are those found in the * sequence. The data type of elements found in the * sequence is returned in the reference pDataType */ static int extract_des(uint8_t *buf, int len, sdp_list_t **svcReqSeq, uint8_t *pDataType, uint8_t expectedType) { uint8_t seqType; int scanned, data_size = 0; short numberOfElements = 0; int seqlen = 0; sdp_list_t *pSeq = NULL; uint8_t dataType; int status = 0; const uint8_t *p; size_t bufsize; scanned = sdp_extract_seqtype(buf, len, &seqType, &data_size); SDPDBG("Seq type : %d", seqType); if (!scanned || (seqType != SDP_SEQ8 && seqType != SDP_SEQ16)) { error("Unknown seq type"); return -1; } p = buf + scanned; bufsize = len - scanned; SDPDBG("Data size : %d", data_size); for (;;) { char *pElem = NULL; int localSeqLength = 0; if (bufsize < sizeof(uint8_t)) { SDPDBG("->Unexpected end of buffer"); goto failed; } dataType = *p; SDPDBG("Data type: 0x%02x", dataType); if (expectedType == SDP_TYPE_UUID) { if (dataType != SDP_UUID16 && dataType != SDP_UUID32 && dataType != SDP_UUID128) { SDPDBG("->Unexpected Data type (expected UUID_ANY)"); goto failed; } } else if (expectedType == SDP_TYPE_ATTRID && (dataType != SDP_UINT16 && dataType != SDP_UINT32)) { SDPDBG("->Unexpected Data type (expected 0x%02x or 0x%02x)", SDP_UINT16, SDP_UINT32); goto failed; } else if (expectedType != SDP_TYPE_ATTRID && dataType != expectedType) { SDPDBG("->Unexpected Data type (expected 0x%02x)", expectedType); goto failed; } switch (dataType) { case SDP_UINT16: p += sizeof(uint8_t); seqlen += sizeof(uint8_t); bufsize -= sizeof(uint8_t); if (bufsize < sizeof(uint16_t)) { SDPDBG("->Unexpected end of buffer"); goto failed; } if (expectedType == SDP_TYPE_ATTRID) { struct attrid *aid; aid = malloc(sizeof(struct attrid)); aid->dtd = dataType; bt_put_unaligned(ntohs(bt_get_unaligned((uint16_t *)p)), (uint16_t *)&aid->uint16); pElem = (char *) aid; } else { pElem = malloc(sizeof(uint16_t)); bt_put_unaligned(ntohs(bt_get_unaligned((uint16_t *)p)), (uint16_t *)pElem); } p += sizeof(uint16_t); seqlen += sizeof(uint16_t); bufsize -= sizeof(uint16_t); break; case SDP_UINT32: p += sizeof(uint8_t); seqlen += sizeof(uint8_t); bufsize -= sizeof(uint8_t); if (bufsize < (int)sizeof(uint32_t)) { SDPDBG("->Unexpected end of buffer"); goto failed; } if (expectedType == SDP_TYPE_ATTRID) { struct attrid *aid; aid = malloc(sizeof(struct attrid)); aid->dtd = dataType; bt_put_unaligned(ntohl(bt_get_unaligned((uint32_t *)p)), (uint32_t *)&aid->uint32); pElem = (char *) aid; } else { pElem = malloc(sizeof(uint32_t)); bt_put_unaligned(ntohl(bt_get_unaligned((uint32_t *)p)), (uint32_t *)pElem); } p += sizeof(uint32_t); seqlen += sizeof(uint32_t); bufsize -= sizeof(uint32_t); break; case SDP_UUID16: case SDP_UUID32: case SDP_UUID128: pElem = malloc(sizeof(uuid_t)); status = sdp_uuid_extract(p, bufsize, (uuid_t *) pElem, &localSeqLength); if (status < 0) { free(pElem); goto failed; } seqlen += localSeqLength; p += localSeqLength; bufsize -= localSeqLength; break; default: return -1; } if (status == 0) { pSeq = sdp_list_append(pSeq, pElem); numberOfElements++; SDPDBG("No of elements : %d", numberOfElements); if (seqlen == data_size) break; else if (seqlen > data_size || seqlen > len) goto failed; } else free(pElem); } *svcReqSeq = pSeq; scanned += seqlen; *pDataType = dataType; return scanned; failed: sdp_list_free(pSeq, free); return -1; }
static void search_callback(uint8_t type, uint16_t status, uint8_t *rsp, size_t size, void *user_data) { struct callback_data *callback = user_data; unsigned int scanned, bytesleft = size; int seqlen = 0; uint8_t dataType, channel = 0; GError *gerr = NULL; if (status || type != SDP_SVC_SEARCH_ATTR_RSP) goto failed; scanned = sdp_extract_seqtype(rsp, bytesleft, &dataType, &seqlen); if (!scanned || !seqlen) goto failed; rsp += scanned; bytesleft -= scanned; do { sdp_record_t *rec; sdp_list_t *protos; int recsize, ch = -1; recsize = 0; rec = sdp_extract_pdu(rsp, bytesleft, &recsize); if (!rec) break; if (!recsize) { sdp_record_free(rec); break; } if (!sdp_get_access_protos(rec, &protos)) { ch = sdp_get_proto_port(protos, RFCOMM_UUID); sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL); sdp_list_free(protos, NULL); protos = NULL; } sdp_record_free(rec); if (ch > 0) { channel = ch; break; } scanned += recsize; rsp += recsize; bytesleft -= recsize; } while (scanned < size && bytesleft > 0); if (channel == 0) goto failed; callback->session->channel = channel; callback->session->io = rfcomm_connect(&callback->session->src, &callback->session->dst, channel, rfcomm_callback, callback); if (callback->session->io != NULL) { sdp_close(callback->sdp); return; } failed: sdp_close(callback->sdp); g_set_error(&gerr, OBEX_IO_ERROR, -EIO, "Unable to find service record"); callback->func(callback->session, gerr, callback->data); g_clear_error(&gerr); session_unref(callback->session); g_free(callback); }
/* * Generic data element sequence extractor. Builds * a list whose elements are those found in the * sequence. The data type of elements found in the * sequence is returned in the reference pDataType */ static int extract_des(uint8_t *buf, int len, sdp_list_t **svcReqSeq, uint8_t *pDataType, uint8_t expectedType) { uint8_t seqType; int scanned, data_size = 0; short numberOfElements = 0; int seqlen = 0; sdp_list_t *pSeq = NULL; uint8_t dataType; int status = 0; const uint8_t *p; scanned = sdp_extract_seqtype(buf, &seqType, &data_size); debug("Seq type : %d", seqType); if (!scanned || (seqType != SDP_SEQ8 && seqType != SDP_SEQ16)) { error("Unknown seq type"); return -1; } p = buf + scanned; debug("Data size : %d", data_size); for (;;) { char *pElem = NULL; int localSeqLength = 0; dataType = *(uint8_t *)p; debug("Data type: 0x%02x", dataType); if (expectedType == SDP_TYPE_UUID) { if (dataType != SDP_UUID16 && dataType != SDP_UUID32 && dataType != SDP_UUID128) { debug("->Unexpected Data type (expected UUID_ANY)"); return -1; } } else if (expectedType != SDP_TYPE_ANY && dataType != expectedType) { debug("->Unexpected Data type (expected 0x%02x)", expectedType); return -1; } switch (dataType) { case SDP_UINT16: p += sizeof(uint8_t); seqlen += sizeof(uint8_t); pElem = malloc(sizeof(uint16_t)); bt_put_unaligned(ntohs(bt_get_unaligned((uint16_t *)p)), (uint16_t *)pElem); p += sizeof(uint16_t); seqlen += sizeof(uint16_t); break; case SDP_UINT32: p += sizeof(uint8_t); seqlen += sizeof(uint8_t); pElem = malloc(sizeof(uint32_t)); bt_put_unaligned(ntohl(bt_get_unaligned((uint32_t *)p)), (uint32_t *)pElem); p += sizeof(uint32_t); seqlen += sizeof(uint32_t); break; case SDP_UUID16: case SDP_UUID32: case SDP_UUID128: pElem = malloc(sizeof(uuid_t)); status = sdp_uuid_extract(p, (uuid_t *)pElem, &localSeqLength); if (status == 0) { seqlen += localSeqLength; p += localSeqLength; } break; default: return -1; } if (status == 0) { pSeq = sdp_list_append(pSeq, pElem); numberOfElements++; debug("No of elements : %d", numberOfElements); if (seqlen == data_size) break; else if (seqlen > data_size || seqlen > len) return -1; } else free(pElem); } *svcReqSeq = pSeq; scanned += seqlen; *pDataType = dataType; return scanned; }