/* * Remove a registered service record */ int service_remove_req(sdp_req_t *req, sdp_buf_t *rsp) { uint8_t *p = req->buf + sizeof(sdp_pdu_hdr_t); uint32_t handle = bt_get_be32(p); sdp_record_t *rec; int status = 0; /* extract service record handle */ rec = sdp_record_find(handle); if (rec) { sdp_svcdb_collect(rec); status = sdp_record_remove(handle); sdp_record_free(rec); if (status == 0) update_db_timestamp(); } else { status = SDP_INVALID_RECORD_HANDLE; SDPDBG("Could not find record : 0x%x", handle); } p = rsp->data; bt_put_be16(status, p); rsp->data_size = sizeof(uint16_t); return status; }
uint32_t sdp_next_handle(void) { uint32_t handle = 0x10000; while (sdp_record_find(handle)) handle++; return handle; }
int remove_record_from_server(uint32_t handle) { sdp_record_t *rec; DBG("Removing record with handle 0x%05x", handle); rec = sdp_record_find(handle); if (!rec) return -ENOENT; if (sdp_record_remove(handle) == 0) update_db_timestamp(); sdp_record_free(rec); return 0; }
int add_record_to_server(const bdaddr_t *src, sdp_record_t *rec) { sdp_data_t *data; sdp_list_t *pattern; if (rec->handle == 0xffffffff) { rec->handle = sdp_next_handle(); if (rec->handle < 0x10000) return -ENOSPC; } else { if (sdp_record_find(rec->handle)) return -EEXIST; } DBG("Adding record with handle 0x%05x", rec->handle); sdp_record_add(src, rec); data = sdp_data_alloc(SDP_UINT32, &rec->handle); sdp_attr_replace(rec, SDP_ATTR_RECORD_HANDLE, data); if (sdp_data_get(rec, SDP_ATTR_BROWSE_GRP_LIST) == NULL) { uuid_t uuid; sdp_uuid16_create(&uuid, PUBLIC_BROWSE_GROUP); sdp_pattern_add_uuid(rec, &uuid); } for (pattern = rec->pattern; pattern; pattern = pattern->next) { char uuid[32]; if (pattern->data == NULL) continue; sdp_uuid2strn((uuid_t *) pattern->data, uuid, sizeof(uuid)); DBG("Record pattern UUID %s", uuid); } update_db_timestamp(); return 0; }
int remove_record_from_server(uint32_t handle) { sdp_record_t *rec; /* Refuse to remove the server's own record */ if (handle == SDP_SERVER_RECORD_HANDLE) return -EINVAL; DBG("Removing record with handle 0x%05x", handle); rec = sdp_record_find(handle); if (!rec) return -ENOENT; if (sdp_record_remove(handle) == 0) update_db_timestamp(); sdp_record_free(rec); return 0; }
void sdp_init_services_list(bdaddr_t *device) { sdp_list_t *p; DBG(""); for (p = access_db; p != NULL; p = p->next) { sdp_access_t *access = p->data; sdp_record_t *rec; if (bacmp(BDADDR_ANY, &access->device)) continue; rec = sdp_record_find(access->handle); if (rec == NULL) continue; SDPDBG("adding record with handle %x", access->handle); adapter_foreach(adapter_service_insert, rec); } }
/* * Update a service record */ int service_update_req(sdp_req_t *req, sdp_buf_t *rsp) { sdp_record_t *orec, *nrec; int status = 0, scanned = 0; uint8_t *p = req->buf + sizeof(sdp_pdu_hdr_t); int bufsize = req->len - sizeof(sdp_pdu_hdr_t); uint32_t handle = bt_get_be32(p); SDPDBG("Svc Rec Handle: 0x%x", handle); p += sizeof(uint32_t); bufsize -= sizeof(uint32_t); orec = sdp_record_find(handle); SDPDBG("SvcRecOld: %p", orec); if (!orec) { status = SDP_INVALID_RECORD_HANDLE; goto done; } nrec = extract_pdu_server(BDADDR_ANY, p, bufsize, handle, &scanned); if (!nrec) { status = SDP_INVALID_SYNTAX; goto done; } assert(nrec == orec); update_db_timestamp(); done: p = rsp->data; bt_put_be16(status, p); rsp->data_size = sizeof(uint16_t); return status; }
/* * Add the newly created service record to the service repository */ int service_register_req(sdp_req_t *req, sdp_buf_t *rsp) { int scanned = 0; sdp_data_t *handle; uint8_t *p = req->buf + sizeof(sdp_pdu_hdr_t); int bufsize = req->len - sizeof(sdp_pdu_hdr_t); sdp_record_t *rec; req->flags = *p++; if (req->flags & SDP_DEVICE_RECORD) { bacpy(&req->device, (bdaddr_t *) p); p += sizeof(bdaddr_t); bufsize -= sizeof(bdaddr_t); } /* save image of PDU: we need it when clients request this attribute */ rec = extract_pdu_server(&req->device, p, bufsize, 0xffffffff, &scanned); if (!rec) goto invalid; if (rec->handle == 0xffffffff) { rec->handle = sdp_next_handle(); if (rec->handle < 0x10000) { sdp_record_free(rec); goto invalid; } } else { if (sdp_record_find(rec->handle)) { /* extract_pdu_server will add the record handle * if it is missing. So instead of failing, skip * the record adding to avoid duplication. */ goto success; } } sdp_record_add(&req->device, rec); if (!(req->flags & SDP_RECORD_PERSIST)) sdp_svcdb_set_collectable(rec, req->sock); handle = sdp_data_alloc(SDP_UINT32, &rec->handle); sdp_attr_replace(rec, SDP_ATTR_RECORD_HANDLE, handle); success: /* if the browse group descriptor is NULL, * ensure that the record belongs to the ROOT group */ if (sdp_data_get(rec, SDP_ATTR_BROWSE_GRP_LIST) == NULL) { uuid_t uuid; sdp_uuid16_create(&uuid, PUBLIC_BROWSE_GROUP); sdp_pattern_add_uuid(rec, &uuid); } update_db_timestamp(); /* Build a rsp buffer */ bt_put_be32(rec->handle, rsp->data); rsp->data_size = sizeof(uint32_t); return 0; invalid: bt_put_be16(SDP_INVALID_SYNTAX, rsp->data); rsp->data_size = sizeof(uint16_t); return -1; }
/* 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 DBusMessage *request_authorization(DBusConnection *conn, DBusMessage *msg, void *data) { struct record_data *user_record; struct service_adapter *serv_adapter = data; sdp_record_t *record; sdp_list_t *services; const char *sender; dbus_uint32_t handle; const char *address; struct pending_auth *auth; char uuid_str[MAX_LEN_UUID_STR]; uuid_t *uuid, *uuid128; bdaddr_t src; if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address, DBUS_TYPE_UINT32, &handle, DBUS_TYPE_INVALID) == FALSE) return NULL; sender = dbus_message_get_sender(msg); if (find_pending_by_sender(serv_adapter, sender)) return btd_error_does_not_exist(msg); user_record = find_record(serv_adapter, handle, sender); if (!user_record) { user_record = find_record(serv_adapter_any, handle, sender); if (!user_record) return btd_error_not_authorized(msg); } record = sdp_record_find(user_record->handle); if (record == NULL) return btd_error_not_authorized(msg); if (sdp_get_service_classes(record, &services) < 0) { sdp_record_free(record); return btd_error_not_authorized(msg); } if (services == NULL) return btd_error_not_authorized(msg); uuid = services->data; uuid128 = sdp_uuid_to_uuid128(uuid); sdp_list_free(services, bt_free); if (sdp_uuid2strn(uuid128, uuid_str, MAX_LEN_UUID_STR) < 0) { bt_free(uuid128); return btd_error_not_authorized(msg); } bt_free(uuid128); auth = g_new0(struct pending_auth, 1); auth->msg = dbus_message_ref(msg); auth->conn = dbus_connection_ref(connection); auth->sender = user_record->sender; memcpy(auth->uuid, uuid_str, MAX_LEN_UUID_STR); str2ba(address, &auth->dst); serv_adapter->pending_list = g_slist_append(serv_adapter->pending_list, auth); auth = next_pending(serv_adapter); if (auth == NULL) return btd_error_does_not_exist(msg); if (serv_adapter->adapter) adapter_get_address(serv_adapter->adapter, &src); else bacpy(&src, BDADDR_ANY); if (btd_request_authorization(&src, &auth->dst, auth->uuid, auth_cb, serv_adapter) < 0) { serv_adapter->pending_list = g_slist_remove(serv_adapter->pending_list, auth); g_free(auth); return btd_error_not_authorized(msg); } return NULL; }