static sdp_record_t *a2dp_record(void) { sdp_list_t *svclass_id, *pfseq, *apseq, *root; uuid_t root_uuid, l2cap_uuid, avdtp_uuid, a2dp_uuid; sdp_profile_desc_t profile[1]; sdp_list_t *aproto, *proto[2]; sdp_record_t *record; sdp_data_t *psm, *version, *features; uint16_t lp = AVDTP_UUID; uint16_t a2dp_ver = 0x0103, avdtp_ver = 0x0103, feat = 0x000f; record = sdp_record_alloc(); if (!record) return NULL; sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); root = sdp_list_append(NULL, &root_uuid); sdp_set_browse_groups(record, root); sdp_uuid16_create(&a2dp_uuid, AUDIO_SOURCE_SVCLASS_ID); svclass_id = sdp_list_append(NULL, &a2dp_uuid); sdp_set_service_classes(record, svclass_id); sdp_uuid16_create(&profile[0].uuid, ADVANCED_AUDIO_PROFILE_ID); profile[0].version = a2dp_ver; pfseq = sdp_list_append(NULL, &profile[0]); sdp_set_profile_descs(record, pfseq); sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); proto[0] = sdp_list_append(NULL, &l2cap_uuid); psm = sdp_data_alloc(SDP_UINT16, &lp); proto[0] = sdp_list_append(proto[0], psm); apseq = sdp_list_append(NULL, proto[0]); sdp_uuid16_create(&avdtp_uuid, AVDTP_UUID); proto[1] = sdp_list_append(NULL, &avdtp_uuid); version = sdp_data_alloc(SDP_UINT16, &avdtp_ver); proto[1] = sdp_list_append(proto[1], version); apseq = sdp_list_append(apseq, proto[1]); aproto = sdp_list_append(NULL, apseq); sdp_set_access_protos(record, aproto); features = sdp_data_alloc(SDP_UINT16, &feat); sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features); sdp_set_info_attr(record, "Audio Source", NULL, NULL); sdp_data_free(psm); sdp_data_free(version); sdp_list_free(proto[0], NULL); sdp_list_free(proto[1], NULL); sdp_list_free(apseq, NULL); sdp_list_free(pfseq, NULL); sdp_list_free(aproto, NULL); sdp_list_free(root, NULL); sdp_list_free(svclass_id, NULL); return record; }
static sdp_list_t *mdeps_to_sdp_features(struct mdep_cfg *mdep) { sdp_data_t *mdepid, *dtype = NULL, *role = NULL, *descr = NULL; sdp_list_t *f_list = NULL; DBG(""); mdepid = sdp_data_alloc(SDP_UINT8, &mdep->id); if (!mdepid) return NULL; dtype = sdp_data_alloc(SDP_UINT16, &mdep->data_type); if (!dtype) goto fail; role = sdp_data_alloc(SDP_UINT8, &mdep->role); if (!role) goto fail; if (mdep->descr) { descr = sdp_data_alloc(SDP_TEXT_STR8, mdep->descr); if (!descr) goto fail; } f_list = sdp_list_append(NULL, mdepid); if (!f_list) goto fail; if (!sdp_list_append(f_list, dtype)) goto fail; if (!sdp_list_append(f_list, role)) goto fail; if (descr && !sdp_list_append(f_list, descr)) goto fail; return f_list; fail: sdp_list_free(f_list, NULL); if (mdepid) sdp_data_free(mdepid); if (dtype) sdp_data_free(dtype); if (role) sdp_data_free(role); if (descr) sdp_data_free(descr); return NULL; }
static sdp_list_t *app_to_sdplist(struct hdp_application *app) { sdp_data_t *mdepid, *dtype = NULL, *role = NULL, *desc = NULL; sdp_list_t *f_list = NULL; mdepid = sdp_data_alloc(SDP_UINT8, &app->id); if (mdepid == NULL) return NULL; dtype = sdp_data_alloc(SDP_UINT16, &app->data_type); if (dtype == NULL) goto fail; role = sdp_data_alloc(SDP_UINT8, &app->role); if (role == NULL) goto fail; if (app->description != NULL) { desc = sdp_data_alloc(SDP_TEXT_STR8, app->description); if (desc == NULL) goto fail; } f_list = sdp_list_append(NULL, mdepid); if (f_list == NULL) goto fail; if (sdp_list_append(f_list, dtype) == NULL) goto fail; if (sdp_list_append(f_list, role) == NULL) goto fail; if (desc != NULL) if (sdp_list_append(f_list, desc) == NULL) goto fail; return f_list; fail: if (f_list != NULL) sdp_list_free(f_list, NULL); if (mdepid != NULL) sdp_data_free(mdepid); if (dtype != NULL) sdp_data_free(dtype); if (role != NULL) sdp_data_free(role); if (desc != NULL) sdp_data_free(desc); return NULL; }
static sdp_list_t *app_to_sdplist(struct mcap_application *app) { DBG(""); sdp_data_t *mdepid, *dtype = NULL, *role = NULL, *desc = NULL; sdp_list_t *f_list = NULL; mdepid = sdp_data_alloc(SDP_UINT8, &app->id); if (!mdepid) return NULL; dtype = sdp_data_alloc(SDP_UINT16, &app->data_type); if (!dtype) goto fail; role = sdp_data_alloc(SDP_UINT8, &app->role); if (!role) goto fail; if (app->description) { desc = sdp_data_alloc(SDP_TEXT_STR8, app->description); if (!desc) goto fail; } f_list = sdp_list_append(NULL, mdepid); if (!f_list) goto fail; if (!sdp_list_append(f_list, dtype)) goto fail; if (!sdp_list_append(f_list, role)) goto fail; if (desc) if (!sdp_list_append(f_list, desc)) goto fail; return f_list; fail: if (f_list) sdp_list_free(f_list, NULL); if (mdepid) sdp_data_free(mdepid); if (dtype) sdp_data_free(dtype); if (role) sdp_data_free(role); if (desc) sdp_data_free(desc); return NULL; }
/* * The service database state is an attribute of the service record * of the SDP server itself. This attribute is guaranteed to * change if any of the contents of the service repository * changes. This function updates the timestamp of value of * the svcDBState attribute * Set the SDP server DB. Simply a timestamp which is the marker * when the DB was modified. */ static void update_db_timestamp(void) { if (fixed_dbts) { sdp_data_t *d = sdp_data_alloc(SDP_UINT32, &fixed_dbts); sdp_attr_replace(server, SDP_ATTR_SVCDB_STATE, d); } else { uint32_t dbts = sdp_get_time(); sdp_data_t *d = sdp_data_alloc(SDP_UINT32, &dbts); sdp_attr_replace(server, SDP_ATTR_SVCDB_STATE, d); } }
static sdp_record_t *create_rfcomm_record(uint8_t chan, uuid_t *uuid, const char *svc_name, bool has_obex) { sdp_list_t *svclass_id; sdp_list_t *seq, *proto_seq, *pbg_seq; sdp_list_t *proto[3]; uuid_t l2cap_uuid, rfcomm_uuid, obex_uuid, pbg_uuid; sdp_data_t *channel; sdp_record_t *record; record = sdp_record_alloc(); if (!record) return NULL; record->handle = sdp_next_handle(); svclass_id = sdp_list_append(NULL, uuid); sdp_set_service_classes(record, svclass_id); sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); proto[0] = sdp_list_append(NULL, &l2cap_uuid); seq = sdp_list_append(NULL, proto[0]); sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID); proto[1] = sdp_list_append(NULL, &rfcomm_uuid); channel = sdp_data_alloc(SDP_UINT8, &chan); proto[1] = sdp_list_append(proto[1], channel); seq = sdp_list_append(seq, proto[1]); if (has_obex) { sdp_uuid16_create(&obex_uuid, OBEX_UUID); proto[2] = sdp_list_append(NULL, &obex_uuid); seq = sdp_list_append(seq, proto[2]); } proto_seq = sdp_list_append(NULL, seq); sdp_set_access_protos(record, proto_seq); sdp_uuid16_create(&pbg_uuid, PUBLIC_BROWSE_GROUP); pbg_seq = sdp_list_append(NULL, &pbg_uuid); sdp_set_browse_groups(record, pbg_seq); if (svc_name) sdp_set_info_attr(record, svc_name, NULL, NULL); sdp_data_free(channel); sdp_list_free(proto[0], NULL); sdp_list_free(proto[1], NULL); if (has_obex) sdp_list_free(proto[2], NULL); sdp_list_free(seq, NULL); sdp_list_free(proto_seq, NULL); sdp_list_free(pbg_seq, NULL); sdp_list_free(svclass_id, NULL); return record; }
void register_device_id(const uint16_t vendor, const uint16_t product, const uint16_t version) { const uint16_t spec = 0x0102, source = 0x0002; const uint8_t primary = 1; sdp_list_t *class_list, *group_list, *profile_list; uuid_t class_uuid, group_uuid; sdp_data_t *sdp_data, *primary_data, *source_data; sdp_data_t *spec_data, *vendor_data, *product_data, *version_data; sdp_profile_desc_t profile; sdp_record_t *record = sdp_record_alloc(); info("Adding device id record for %04x:%04x", vendor, product); btd_manager_set_did(vendor, product, version); record->handle = sdp_next_handle(); sdp_record_add(BDADDR_ANY, record); sdp_data = sdp_data_alloc(SDP_UINT32, &record->handle); sdp_attr_add(record, SDP_ATTR_RECORD_HANDLE, sdp_data); sdp_uuid16_create(&class_uuid, PNP_INFO_SVCLASS_ID); class_list = sdp_list_append(0, &class_uuid); sdp_set_service_classes(record, class_list); sdp_list_free(class_list, NULL); sdp_uuid16_create(&group_uuid, PUBLIC_BROWSE_GROUP); group_list = sdp_list_append(NULL, &group_uuid); sdp_set_browse_groups(record, group_list); sdp_list_free(group_list, NULL); sdp_uuid16_create(&profile.uuid, PNP_INFO_PROFILE_ID); profile.version = spec; profile_list = sdp_list_append(NULL, &profile); sdp_set_profile_descs(record, profile_list); sdp_list_free(profile_list, NULL); spec_data = sdp_data_alloc(SDP_UINT16, &spec); sdp_attr_add(record, 0x0200, spec_data); vendor_data = sdp_data_alloc(SDP_UINT16, &vendor); sdp_attr_add(record, 0x0201, vendor_data); product_data = sdp_data_alloc(SDP_UINT16, &product); sdp_attr_add(record, 0x0202, product_data); version_data = sdp_data_alloc(SDP_UINT16, &version); sdp_attr_add(record, 0x0203, version_data); primary_data = sdp_data_alloc(SDP_BOOL, &primary); sdp_attr_add(record, 0x0204, primary_data); source_data = sdp_data_alloc(SDP_UINT16, &source); sdp_attr_add(record, 0x0205, source_data); update_db_timestamp(); }
static sdp_record_t *create_sap_record(uint8_t channel) { sdp_list_t *apseq, *aproto, *profiles, *proto[2], *root, *svclass_id; uuid_t sap_uuid, gt_uuid, root_uuid, l2cap, rfcomm; sdp_profile_desc_t profile; sdp_record_t *record; sdp_data_t *ch; record = sdp_record_alloc(); if (!record) return NULL; sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); root = sdp_list_append(NULL, &root_uuid); sdp_set_browse_groups(record, root); sdp_list_free(root, NULL); sdp_uuid16_create(&sap_uuid, SAP_SVCLASS_ID); svclass_id = sdp_list_append(NULL, &sap_uuid); sdp_uuid16_create(>_uuid, GENERIC_TELEPHONY_SVCLASS_ID); svclass_id = sdp_list_append(svclass_id, >_uuid); sdp_set_service_classes(record, svclass_id); sdp_list_free(svclass_id, NULL); sdp_uuid16_create(&profile.uuid, SAP_PROFILE_ID); profile.version = SAP_VERSION; profiles = sdp_list_append(NULL, &profile); sdp_set_profile_descs(record, profiles); sdp_list_free(profiles, NULL); sdp_uuid16_create(&l2cap, L2CAP_UUID); proto[0] = sdp_list_append(NULL, &l2cap); apseq = sdp_list_append(NULL, proto[0]); sdp_uuid16_create(&rfcomm, RFCOMM_UUID); proto[1] = sdp_list_append(NULL, &rfcomm); ch = sdp_data_alloc(SDP_UINT8, &channel); proto[1] = sdp_list_append(proto[1], ch); apseq = sdp_list_append(apseq, proto[1]); aproto = sdp_list_append(NULL, apseq); sdp_set_access_protos(record, aproto); sdp_set_info_attr(record, "SIM Access Server", NULL, NULL); sdp_data_free(ch); sdp_list_free(proto[0], NULL); sdp_list_free(proto[1], NULL); sdp_list_free(apseq, NULL); sdp_list_free(aproto, NULL); return record; }
static sdp_record_t *hfp_hs_record(uint8_t ch) { sdp_list_t *svclass_id, *pfseq, *apseq, *root; uuid_t root_uuid, svclass_uuid, ga_svclass_uuid; uuid_t l2cap_uuid, rfcomm_uuid; sdp_profile_desc_t profile; sdp_record_t *record; sdp_list_t *aproto, *proto[2]; sdp_data_t *channel; record = sdp_record_alloc(); if (!record) return NULL; sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); root = sdp_list_append(0, &root_uuid); sdp_set_browse_groups(record, root); sdp_uuid16_create(&svclass_uuid, HANDSFREE_SVCLASS_ID); svclass_id = sdp_list_append(0, &svclass_uuid); sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID); svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid); sdp_set_service_classes(record, svclass_id); sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID); profile.version = 0x0105; pfseq = sdp_list_append(0, &profile); sdp_set_profile_descs(record, pfseq); sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); proto[0] = sdp_list_append(0, &l2cap_uuid); apseq = sdp_list_append(0, proto[0]); sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID); proto[1] = sdp_list_append(0, &rfcomm_uuid); channel = sdp_data_alloc(SDP_UINT8, &ch); proto[1] = sdp_list_append(proto[1], channel); apseq = sdp_list_append(apseq, proto[1]); aproto = sdp_list_append(0, apseq); sdp_set_access_protos(record, aproto); sdp_set_info_attr(record, "Hands-Free", 0, 0); sdp_data_free(channel); sdp_list_free(proto[0], 0); sdp_list_free(proto[1], 0); sdp_list_free(apseq, 0); sdp_list_free(pfseq, 0); sdp_list_free(aproto, 0); sdp_list_free(root, 0); sdp_list_free(svclass_id, 0); return record; }
static sdp_record_t *proxy_record_new(const char *uuid128, uint8_t channel) { sdp_list_t *apseq, *aproto, *profiles, *proto[2], *root, *svclass_id; uuid_t uuid, root_uuid, l2cap, rfcomm; sdp_profile_desc_t profile; sdp_record_t *record; sdp_data_t *ch; record = sdp_record_alloc(); if (!record) return NULL; sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); root = sdp_list_append(NULL, &root_uuid); sdp_set_browse_groups(record, root); sdp_list_free(root, NULL); bt_string2uuid(&uuid, uuid128); svclass_id = sdp_list_append(NULL, &uuid); sdp_set_service_classes(record, svclass_id); sdp_list_free(svclass_id, NULL); sdp_uuid16_create(&profile.uuid, SERIAL_PORT_PROFILE_ID); profile.version = 0x0100; profiles = sdp_list_append(NULL, &profile); sdp_set_profile_descs(record, profiles); sdp_list_free(profiles, NULL); sdp_uuid16_create(&l2cap, L2CAP_UUID); proto[0] = sdp_list_append(NULL, &l2cap); apseq = sdp_list_append(NULL, proto[0]); sdp_uuid16_create(&rfcomm, RFCOMM_UUID); proto[1] = sdp_list_append(NULL, &rfcomm); ch = sdp_data_alloc(SDP_UINT8, &channel); proto[1] = sdp_list_append(proto[1], ch); apseq = sdp_list_append(apseq, proto[1]); aproto = sdp_list_append(NULL, apseq); sdp_set_access_protos(record, aproto); add_lang_attr(record); sdp_set_info_attr(record, "Port Proxy Entity", NULL, "Port Proxy Entity"); sdp_data_free(ch); sdp_list_free(proto[0], NULL); sdp_list_free(proto[1], NULL); sdp_list_free(apseq, NULL); sdp_list_free(aproto, NULL); return record; }
static sdp_record_t *dun_record(uint8_t ch) { sdp_list_t *svclass_id, *pfseq, *apseq, *root, *aproto; uuid_t root_uuid, dun, gn, l2cap, rfcomm; sdp_profile_desc_t profile; sdp_list_t *proto[2]; sdp_record_t *record; sdp_data_t *channel; record = sdp_record_alloc(); if (!record) return NULL; sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); root = sdp_list_append(NULL, &root_uuid); sdp_set_browse_groups(record, root); sdp_uuid16_create(&dun, DIALUP_NET_SVCLASS_ID); svclass_id = sdp_list_append(NULL, &dun); sdp_uuid16_create(&gn, GENERIC_NETWORKING_SVCLASS_ID); svclass_id = sdp_list_append(svclass_id, &gn); sdp_set_service_classes(record, svclass_id); sdp_uuid16_create(&profile.uuid, DIALUP_NET_PROFILE_ID); profile.version = 0x0100; pfseq = sdp_list_append(NULL, &profile); sdp_set_profile_descs(record, pfseq); sdp_uuid16_create(&l2cap, L2CAP_UUID); proto[0] = sdp_list_append(NULL, &l2cap); apseq = sdp_list_append(NULL, proto[0]); sdp_uuid16_create(&rfcomm, RFCOMM_UUID); proto[1] = sdp_list_append(NULL, &rfcomm); channel = sdp_data_alloc(SDP_UINT8, &ch); proto[1] = sdp_list_append(proto[1], channel); apseq = sdp_list_append(apseq, proto[1]); aproto = sdp_list_append(0, apseq); sdp_set_access_protos(record, aproto); sdp_set_info_attr(record, "Dial-Up Networking", 0, 0); sdp_data_free(channel); sdp_list_free(root, NULL); sdp_list_free(svclass_id, NULL); sdp_list_free(proto[0], NULL); sdp_list_free(proto[1], NULL); sdp_list_free(pfseq, NULL); sdp_list_free(apseq, NULL); sdp_list_free(aproto, NULL); return record; }
/* * The SDP server must present its own service record to * the service repository. This can be accessed by service * discovery clients. This method constructs a service record * and stores it in the repository */ void register_server_service(void) { sdp_list_t *classIDList; uuid_t classID; void **versions, **versionDTDs; uint8_t dtd; sdp_data_t *pData; int i; server = sdp_record_alloc(); server->pattern = NULL; /* Force the record to be SDP_SERVER_RECORD_HANDLE */ server->handle = SDP_SERVER_RECORD_HANDLE; sdp_record_add(BDADDR_ANY, server); sdp_attr_add(server, SDP_ATTR_RECORD_HANDLE, sdp_data_alloc(SDP_UINT32, &server->handle)); sdp_uuid16_create(&classID, SDP_SERVER_SVCLASS_ID); classIDList = sdp_list_append(0, &classID); sdp_set_service_classes(server, classIDList); sdp_list_free(classIDList, 0); /* * Set the version numbers supported, these are passed as arguments * to the server on command line. Now defaults to 1.0 * Build the version number sequence first */ versions = malloc(sdpServerVnumEntries * sizeof(void *)); versionDTDs = malloc(sdpServerVnumEntries * sizeof(void *)); dtd = SDP_UINT16; for (i = 0; i < sdpServerVnumEntries; i++) { uint16_t *version = malloc(sizeof(uint16_t)); *version = sdpVnumArray[i].major; *version = (*version << 8); *version |= sdpVnumArray[i].minor; versions[i] = version; versionDTDs[i] = &dtd; } pData = sdp_seq_alloc(versionDTDs, versions, sdpServerVnumEntries); for (i = 0; i < sdpServerVnumEntries; i++) free(versions[i]); free(versions); free(versionDTDs); sdp_attr_add(server, SDP_ATTR_VERSION_NUM_LIST, pData); update_db_timestamp(); }
static gboolean register_data_exchange_spec(sdp_record_t *record) { sdp_data_t *spec; uint8_t data_spec = DATA_EXCHANGE_SPEC_11073; /* As by now 11073 is the only supported we set it by default */ spec = sdp_data_alloc(SDP_UINT8, &data_spec); if (spec == NULL) return FALSE; if (sdp_attr_add(record, SDP_ATTR_DATA_EXCHANGE_SPEC, spec) < 0) { sdp_data_free(spec); return FALSE; } return TRUE; }
static gboolean register_mcap_features(sdp_record_t *sdp_record) { sdp_data_t *mcap_proc; uint8_t mcap_sup_proc = MCAP_SUP_PROC; mcap_proc = sdp_data_alloc(SDP_UINT8, &mcap_sup_proc); if (mcap_proc == NULL) return FALSE; if (sdp_attr_add(sdp_record, SDP_ATTR_MCAP_SUPPORTED_PROCEDURES, mcap_proc) < 0) { sdp_data_free(mcap_proc); return FALSE; } return TRUE; }
static int register_data_exchange_spec(sdp_record_t *rec) { sdp_data_t *spec; uint8_t data_spec = DATA_EXCHANGE_SPEC_11073; /* As of now only 11073 is supported, so we set it as default */ DBG(""); spec = sdp_data_alloc(SDP_UINT8, &data_spec); if (!spec) return -1; if (sdp_attr_add(rec, SDP_ATTR_DATA_EXCHANGE_SPEC, spec) < 0) { sdp_data_free(spec); return -1; } return 0; }
static int register_mcap_features(sdp_record_t *rec) { sdp_data_t *mcap_proc; uint8_t mcap_sup_proc = MCAP_SUP_PROC; DBG(""); mcap_proc = sdp_data_alloc(SDP_UINT8, &mcap_sup_proc); if (!mcap_proc) return -1; if (sdp_attr_add(rec, SDP_ATTR_MCAP_SUPPORTED_PROCEDURES, mcap_proc) < 0) { sdp_data_free(mcap_proc); return -1; } 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; }
void register_public_browse_group(void) { sdp_list_t *browselist; uuid_t bgscid, pbgid; sdp_data_t *sdpdata; sdp_record_t *browse = sdp_record_alloc(); browse->handle = SDP_SERVER_RECORD_HANDLE + 1; sdp_record_add(BDADDR_ANY, browse); sdpdata = sdp_data_alloc(SDP_UINT32, &browse->handle); sdp_attr_add(browse, SDP_ATTR_RECORD_HANDLE, sdpdata); sdp_uuid16_create(&bgscid, BROWSE_GRP_DESC_SVCLASS_ID); browselist = sdp_list_append(0, &bgscid); sdp_set_service_classes(browse, browselist); sdp_list_free(browselist, 0); sdp_uuid16_create(&pbgid, PUBLIC_BROWSE_GROUP); sdp_attr_add_new(browse, SDP_ATTR_GROUP_ID, SDP_UUID16, &pbgid.value.uuid16); }
static sdp_record_t *server_record_new(const char *name, uint16_t id) { sdp_list_t *svclass, *pfseq, *apseq, *root, *aproto; uuid_t root_uuid, pan, l2cap, bnep; sdp_profile_desc_t profile[1]; sdp_list_t *proto[2]; sdp_data_t *v, *p; uint16_t psm = BNEP_PSM, version = 0x0100; uint16_t security_desc = (security ? 0x0001 : 0x0000); uint16_t net_access_type = 0xfffe; uint32_t max_net_access_rate = 0; const char *desc = "Network service"; sdp_record_t *record; record = sdp_record_alloc(); if (!record) return NULL; record->attrlist = NULL; record->pattern = NULL; switch (id) { case BNEP_SVC_NAP: sdp_uuid16_create(&pan, NAP_SVCLASS_ID); svclass = sdp_list_append(NULL, &pan); sdp_set_service_classes(record, svclass); sdp_uuid16_create(&profile[0].uuid, NAP_PROFILE_ID); profile[0].version = 0x0100; pfseq = sdp_list_append(NULL, &profile[0]); sdp_set_profile_descs(record, pfseq); sdp_set_info_attr(record, name, NULL, desc); sdp_attr_add_new(record, SDP_ATTR_NET_ACCESS_TYPE, SDP_UINT16, &net_access_type); sdp_attr_add_new(record, SDP_ATTR_MAX_NET_ACCESSRATE, SDP_UINT32, &max_net_access_rate); break; case BNEP_SVC_GN: sdp_uuid16_create(&pan, GN_SVCLASS_ID); svclass = sdp_list_append(NULL, &pan); sdp_set_service_classes(record, svclass); sdp_uuid16_create(&profile[0].uuid, GN_PROFILE_ID); profile[0].version = 0x0100; pfseq = sdp_list_append(NULL, &profile[0]); sdp_set_profile_descs(record, pfseq); sdp_set_info_attr(record, name, NULL, desc); break; case BNEP_SVC_PANU: sdp_uuid16_create(&pan, PANU_SVCLASS_ID); svclass = sdp_list_append(NULL, &pan); sdp_set_service_classes(record, svclass); sdp_uuid16_create(&profile[0].uuid, PANU_PROFILE_ID); profile[0].version = 0x0100; pfseq = sdp_list_append(NULL, &profile[0]); sdp_set_profile_descs(record, pfseq); sdp_set_info_attr(record, name, NULL, desc); break; default: sdp_record_free(record); return NULL; } sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); root = sdp_list_append(NULL, &root_uuid); sdp_set_browse_groups(record, root); sdp_uuid16_create(&l2cap, L2CAP_UUID); proto[0] = sdp_list_append(NULL, &l2cap); p = sdp_data_alloc(SDP_UINT16, &psm); proto[0] = sdp_list_append(proto[0], p); apseq = sdp_list_append(NULL, proto[0]); sdp_uuid16_create(&bnep, BNEP_UUID); proto[1] = sdp_list_append(NULL, &bnep); v = sdp_data_alloc(SDP_UINT16, &version); proto[1] = sdp_list_append(proto[1], v); /* Supported protocols */ { uint16_t ptype[] = { 0x0800, /* IPv4 */ 0x0806, /* ARP */ }; sdp_data_t *head, *pseq; int p; for (p = 0, head = NULL; p < 2; p++) { sdp_data_t *data = sdp_data_alloc(SDP_UINT16, &ptype[p]); if (head) sdp_seq_append(head, data); else head = data; } pseq = sdp_data_alloc(SDP_SEQ16, head); proto[1] = sdp_list_append(proto[1], pseq); } apseq = sdp_list_append(apseq, proto[1]); aproto = sdp_list_append(NULL, apseq); sdp_set_access_protos(record, aproto); add_lang_attr(record); sdp_attr_add_new(record, SDP_ATTR_SECURITY_DESC, SDP_UINT16, &security_desc); sdp_data_free(p); sdp_data_free(v); sdp_list_free(apseq, NULL); sdp_list_free(root, NULL); sdp_list_free(aproto, NULL); sdp_list_free(proto[0], NULL); sdp_list_free(proto[1], NULL); sdp_list_free(svclass, NULL); sdp_list_free(pfseq, NULL); return record; }
static gboolean register_service_additional_protocols( struct hdp_adapter *adapter, sdp_record_t *sdp_record) { gboolean ret = TRUE; uuid_t l2cap_uuid, mcap_d_uuid; sdp_list_t *l2cap_list, *proto_list = NULL, *mcap_list = NULL; sdp_list_t *access_proto_list = NULL; sdp_data_t *psm = NULL; /* set l2cap information */ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); l2cap_list = sdp_list_append(NULL, &l2cap_uuid); if (l2cap_list == NULL) { ret = FALSE; goto end; } psm = sdp_data_alloc(SDP_UINT16, &adapter->dcpsm); if (psm == NULL) { ret = FALSE; goto end; } if (sdp_list_append(l2cap_list, psm) == NULL) { ret = FALSE; goto end; } proto_list = sdp_list_append(NULL, l2cap_list); if (proto_list == NULL) { ret = FALSE; goto end; } /* set mcap information */ sdp_uuid16_create(&mcap_d_uuid, MCAP_DATA_UUID); mcap_list = sdp_list_append(NULL, &mcap_d_uuid); if (mcap_list == NULL) { ret = FALSE; goto end; } if (sdp_list_append(proto_list, mcap_list) == NULL) { ret = FALSE; goto end; } /* attach protocol information to service record */ access_proto_list = sdp_list_append(NULL, proto_list); if (access_proto_list == NULL) { ret = FALSE; goto end; } sdp_set_add_access_protos(sdp_record, access_proto_list); end: if (l2cap_list != NULL) sdp_list_free(l2cap_list, NULL); if (mcap_list != NULL) sdp_list_free(mcap_list, NULL); if (proto_list != NULL) sdp_list_free(proto_list, NULL); if (access_proto_list != NULL) sdp_list_free(access_proto_list, NULL); if (psm != NULL) sdp_data_free(psm); return ret; }
sdp_session_t *register_service(){ //4e:65:78:75:73:2d:43:6f:6d:70:75:74:69:6e:67 ~ Nexus-Computing :)4e65 7875 732d 436f 6d70 7574 696e 6700 //uint32_t service_uuid_int[] = {0x4e65,0x7875,0x732d,0x436f,0x6d70,0x7574,0x696e,0x6700}; uint8_t service_uuid_int[] = {0x07,0x29,0x3d,0xb4,0xa3, 0x23, 0x4e, 0x07,0x8b, 0x8b,0x25,0x0b,0x34,0x0e, 0x42, 0xa4}; uint8_t rfcomm_channel = SVC_CHANNEL; uuid_t root_uuid, l2cap_uuid, rfcomm_uuid, svc_uuid; sdp_list_t *l2cap_list = 0, *rfcomm_list = 0, *root_list = 0, *proto_list = 0, *access_proto_list = 0, *class_id_list; sdp_data_t *channel = 0, *psm = 0; sdp_record_t *record = sdp_record_alloc(); // set the general service ID sdp_uuid128_create( &svc_uuid, &service_uuid_int ); sdp_set_service_id( record, svc_uuid ); // make the service record publicly browsable sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); root_list = sdp_list_append(0, &root_uuid); sdp_set_browse_groups( record, root_list ); // set l2cap information sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); l2cap_list = sdp_list_append( 0, &l2cap_uuid ); proto_list = sdp_list_append( 0, l2cap_list ); // set rfcomm information sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID); channel = sdp_data_alloc(SDP_UINT8, &rfcomm_channel); rfcomm_list = sdp_list_append( 0, &rfcomm_uuid ); sdp_list_append( rfcomm_list, channel ); sdp_list_append( proto_list, rfcomm_list ); // attach protocol information to service record access_proto_list = sdp_list_append( 0, proto_list ); sdp_set_access_protos( record, access_proto_list ); //service classes IMPORTANT FOR ANDROID! class_id_list = sdp_list_append( 0, &svc_uuid); sdp_set_service_classes( record, class_id_list ); // set the name, provider, and description sdp_set_info_attr(record, SVC_NAME, SVC_PROV, SVC_DESC); int err = 0; sdp_session_t *session = 0; // connect to the local SDP server, register the service record, and // disconnect session = sdp_connect( BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY ); err = sdp_record_register(session, record, 0); if(err != 0) perror("Error registring record"); // cleanup sdp_data_free( channel ); sdp_list_free( l2cap_list, 0 ); sdp_list_free( rfcomm_list, 0 ); sdp_list_free( root_list, 0 ); sdp_list_free( access_proto_list, 0 ); return session; }
static int RegisterSdp(uint8_t port) { int ret = 1; // {6A841273-4A97-4eed-A299-C23D571A54E7} // {00001101-0000-1000-8000-00805F9B34FB} uint8_t svc_uuid_int[] = {0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb}; uuid_t root_uuid, l2cap_uuid, rfcomm_uuid, svc_uuid; sdp_list_t *l2cap_list = 0, *rfcomm_list = 0, *root_list = 0, *proto_list = 0, *access_proto_list = 0; sdp_data_t* channel = 0; sdpRecord = sdp_record_alloc(); // set the general service ID sdp_uuid128_create(&svc_uuid, &svc_uuid_int); sdp_set_service_id(sdpRecord, svc_uuid); // make the service record publicly browsable sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); root_list = sdp_list_append(0, &root_uuid); sdp_set_browse_groups(sdpRecord, root_list); // set l2cap information sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); l2cap_list = sdp_list_append(0, &l2cap_uuid); proto_list = sdp_list_append(0, l2cap_list); // set rfcomm information sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID); channel = sdp_data_alloc(SDP_UINT8, &port); rfcomm_list = sdp_list_append(0, &rfcomm_uuid); sdp_list_append(rfcomm_list, channel); sdp_list_append(proto_list, rfcomm_list); // attach protocol information to service record access_proto_list = sdp_list_append(0, proto_list); sdp_set_access_protos(sdpRecord, access_proto_list); // set the name, provider, and description sdp_set_info_attr(sdpRecord, "DroidCam", "", "Android Webcam"); // connect to the local SDP server, register the service record sdpSession = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY); if(sdp_record_register(sdpSession, sdpRecord, 0)) { MSG_ERROR("Could not register Bluetooth service"); ret = 0; } sdp_data_free(channel); sdp_list_free(l2cap_list, 0); sdp_list_free(rfcomm_list, 0); sdp_list_free(root_list, 0); sdp_list_free(access_proto_list, 0); return ret; }
static gboolean register_service_protocols(struct hdp_adapter *adapter, sdp_record_t *sdp_record) { gboolean ret; uuid_t l2cap_uuid, mcap_c_uuid; sdp_list_t *l2cap_list, *proto_list = NULL, *mcap_list = NULL; sdp_list_t *access_proto_list = NULL; sdp_data_t *psm = NULL, *mcap_ver = NULL; uint16_t version = MCAP_VERSION; /* set l2cap information */ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); l2cap_list = sdp_list_append(NULL, &l2cap_uuid); if (l2cap_list == NULL) { ret = FALSE; goto end; } psm = sdp_data_alloc(SDP_UINT16, &adapter->ccpsm); if (psm == NULL) { ret = FALSE; goto end; } if (sdp_list_append(l2cap_list, psm) == NULL) { ret = FALSE; goto end; } proto_list = sdp_list_append(NULL, l2cap_list); if (proto_list == NULL) { ret = FALSE; goto end; } /* set mcap information */ sdp_uuid16_create(&mcap_c_uuid, MCAP_CTRL_UUID); mcap_list = sdp_list_append(NULL, &mcap_c_uuid); if (mcap_list == NULL) { ret = FALSE; goto end; } mcap_ver = sdp_data_alloc(SDP_UINT16, &version); if (mcap_ver == NULL) { ret = FALSE; goto end; } if (sdp_list_append(mcap_list, mcap_ver) == NULL) { ret = FALSE; goto end; } if (sdp_list_append(proto_list, mcap_list) == NULL) { ret = FALSE; goto end; } /* attach protocol information to service record */ access_proto_list = sdp_list_append(NULL, proto_list); if (access_proto_list == NULL) { ret = FALSE; goto end; } if (sdp_set_access_protos(sdp_record, access_proto_list) < 0) { ret = FALSE; goto end; } ret = TRUE; end: if (l2cap_list != NULL) sdp_list_free(l2cap_list, NULL); if (mcap_list != NULL) sdp_list_free(mcap_list, NULL); if (proto_list != NULL) sdp_list_free(proto_list, NULL); if (access_proto_list != NULL) sdp_list_free(access_proto_list, NULL); if (psm != NULL) sdp_data_free(psm); if (mcap_ver != NULL) sdp_data_free(mcap_ver); return ret; }
sdp_session_t *register_service() { uint32_t service_uuid_int[] = { 0, 0, 0, 0xABCD }; uint8_t rfcomm_channel = 11; const char *service_name = "Edison Test"; const char *service_dsc = "Edison Experimental"; const char *service_prov = "glfernando"; sdp_session_t *session = 0; bdaddr_t bdaddr_local = {{0, 0, 0, 0xff, 0xff, 0xff}}; uuid_t root_uuid, l2cap_uuid, rfcomm_uuid, svc_uuid; sdp_list_t *l2cap_list = 0, *rfcomm_list = 0, *root_list = 0, *proto_list = 0, *access_proto_list = 0; sdp_data_t *channel = 0, *psm = 0; sdp_record_t *record = sdp_record_alloc(); // set the general service ID sdp_uuid128_create( &svc_uuid, &service_uuid_int ); sdp_set_service_id( record, svc_uuid ); // make the service record publicly browsable sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); root_list = sdp_list_append(0, &root_uuid); sdp_set_browse_groups( record, root_list ); // set l2cap information sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); l2cap_list = sdp_list_append( 0, &l2cap_uuid ); proto_list = sdp_list_append( 0, l2cap_list ); // set rfcomm information sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID); channel = sdp_data_alloc(SDP_UINT8, &rfcomm_channel); rfcomm_list = sdp_list_append( 0, &rfcomm_uuid ); sdp_list_append( rfcomm_list, channel ); sdp_list_append( proto_list, rfcomm_list ); // attach protocol information to service record access_proto_list = sdp_list_append( 0, proto_list ); sdp_set_access_protos( record, access_proto_list ); // set the name, provider, and description sdp_set_info_attr(record, service_name, service_prov, service_dsc); // connect to the local SDP server, register the service record, and disconnect session = sdp_connect( BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY); if (!session) { printf("session NULL , err %s\n", strerror(errno)); } sdp_record_register(session, record, 0); // cleanup sdp_data_free( channel ); sdp_list_free( l2cap_list, 0 ); sdp_list_free( rfcomm_list, 0 ); sdp_list_free( root_list, 0 ); sdp_list_free( access_proto_list, 0 ); return session; }
static sdp_record_t *avrcp_record(void) { sdp_list_t *svclass_id, *pfseq, *apseq, *root; uuid_t root_uuid, l2cap, avctp, avrtg; sdp_profile_desc_t profile[1]; sdp_list_t *aproto_control, *proto_control[2]; sdp_record_t *record; sdp_data_t *psm, *version, *features; uint16_t lp = L2CAP_PSM_AVCTP; uint16_t avrcp_ver = 0x0105, avctp_ver = 0x0104; uint16_t feat = (AVRCP_FEATURE_CATEGORY_1 | AVRCP_FEATURE_CATEGORY_2 | AVRCP_FEATURE_CATEGORY_3 | AVRCP_FEATURE_CATEGORY_4); record = sdp_record_alloc(); if (!record) return NULL; sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); root = sdp_list_append(NULL, &root_uuid); sdp_set_browse_groups(record, root); /* Service Class ID List */ sdp_uuid16_create(&avrtg, AV_REMOTE_TARGET_SVCLASS_ID); svclass_id = sdp_list_append(NULL, &avrtg); sdp_set_service_classes(record, svclass_id); /* Protocol Descriptor List */ sdp_uuid16_create(&l2cap, L2CAP_UUID); proto_control[0] = sdp_list_append(NULL, &l2cap); psm = sdp_data_alloc(SDP_UINT16, &lp); proto_control[0] = sdp_list_append(proto_control[0], psm); apseq = sdp_list_append(NULL, proto_control[0]); sdp_uuid16_create(&avctp, AVCTP_UUID); proto_control[1] = sdp_list_append(NULL, &avctp); version = sdp_data_alloc(SDP_UINT16, &avctp_ver); proto_control[1] = sdp_list_append(proto_control[1], version); apseq = sdp_list_append(apseq, proto_control[1]); aproto_control = sdp_list_append(NULL, apseq); sdp_set_access_protos(record, aproto_control); /* Bluetooth Profile Descriptor List */ sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID); profile[0].version = avrcp_ver; pfseq = sdp_list_append(NULL, &profile[0]); sdp_set_profile_descs(record, pfseq); features = sdp_data_alloc(SDP_UINT16, &feat); sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features); sdp_set_info_attr(record, "AVRCP TG", NULL, NULL); sdp_data_free(psm); sdp_data_free(version); sdp_list_free(proto_control[0], NULL); sdp_list_free(proto_control[1], NULL); sdp_list_free(apseq, NULL); sdp_list_free(aproto_control, NULL); sdp_list_free(pfseq, NULL); sdp_list_free(root, NULL); sdp_list_free(svclass_id, NULL); return record; }
/* * 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; }
sdp_session_t *register_service(int chnel, int l2_chnel) { uint32_t service_uuid_int[] = { 0, 0, 0, 0xABCD }; uint8_t rfcomm_channel = chnel; uint16_t l2cap_channel = l2_chnel; const char *service_name = "Roto-Rooter Data Router"; const char *service_dsc = "An experimental plumbing router"; const char *service_prov = "Roto-Rooter"; uuid_t root_uuid, l2cap_uuid, rfcomm_uuid, svc_uuid; sdp_list_t *l2cap_list = 0, *rfcomm_list = 0, *root_list = 0, *proto_list = 0, *access_proto_list = 0, *class_id_list = 0; sdp_data_t *channel = 0, *psm = 0, *l2cap_port = 0; sdp_record_t *record = sdp_record_alloc(); // set the general service ID sdp_uuid128_create( &svc_uuid, &service_uuid_int ); class_id_list = sdp_list_append(0, &svc_uuid); //sdp_set_service_id( record, svc_uuid ); sdp_set_service_classes( record, class_id_list); // make the service record publicly browsable sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); root_list = sdp_list_append(0, &root_uuid); sdp_set_browse_groups( record, root_list ); // set l2cap information sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); l2cap_list = sdp_list_append( 0, &l2cap_uuid ); l2cap_port = sdp_data_alloc(SDP_UINT16, &l2cap_channel); sdp_list_append( l2cap_list, l2cap_port); proto_list = sdp_list_append( 0, l2cap_list ); // set rfcomm information sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID); channel = sdp_data_alloc(SDP_UINT8, &rfcomm_channel); rfcomm_list = sdp_list_append( 0, &rfcomm_uuid ); sdp_list_append( rfcomm_list, channel ); sdp_list_append( proto_list, rfcomm_list ); // attach protocol information to service record access_proto_list = sdp_list_append( 0, proto_list ); sdp_set_access_protos( record, access_proto_list ); // set the name, provider, and description sdp_set_info_attr(record, service_name, service_prov, service_dsc); int err = 0; sdp_session_t *session = 0; // connect to the local SDP server, register the service record, and // disconnect session = sdp_connect( BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY ); err = sdp_record_register(session, record, 0); // cleanup sdp_data_free( channel ); sdp_list_free( l2cap_list, 0 ); sdp_list_free( rfcomm_list, 0 ); sdp_list_free( root_list, 0 ); sdp_list_free( access_proto_list, 0 ); return session; }
static void element_start(GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer user_data, GError **err) { struct context_data *ctx_data = user_data; if (!strcmp(element_name, "record")) return; if (!strcmp(element_name, "attribute")) { int i; for (i = 0; attribute_names[i]; i++) { if (!strcmp(attribute_names[i], "id")) { ctx_data->attr_id = strtol(attribute_values[i], 0, 0); break; } } DBG("New attribute 0x%04x", ctx_data->attr_id); return; } if (ctx_data->stack_head) { struct sdp_xml_data *newelem = sdp_xml_data_alloc(); newelem->next = ctx_data->stack_head; ctx_data->stack_head = newelem; } else { ctx_data->stack_head = sdp_xml_data_alloc(); ctx_data->stack_head->next = NULL; } if (!strcmp(element_name, "sequence")) ctx_data->stack_head->data = sdp_data_alloc(SDP_SEQ8, NULL); else if (!strcmp(element_name, "alternate")) ctx_data->stack_head->data = sdp_data_alloc(SDP_ALT8, NULL); else { int i; /* Parse value, name, encoding */ for (i = 0; attribute_names[i]; i++) { if (!strcmp(attribute_names[i], "value")) { int curlen = strlen(ctx_data->stack_head->text); int attrlen = strlen(attribute_values[i]); /* Ensure we're big enough */ while ((curlen + 1 + attrlen) > ctx_data->stack_head->size) { sdp_xml_data_expand(ctx_data->stack_head); } memcpy(ctx_data->stack_head->text + curlen, attribute_values[i], attrlen); ctx_data->stack_head->text[curlen + attrlen] = '\0'; } if (!strcmp(attribute_names[i], "encoding")) { if (!strcmp(attribute_values[i], "hex")) ctx_data->stack_head->type = 1; } if (!strcmp(attribute_names[i], "name")) { ctx_data->stack_head->name = strdup(attribute_values[i]); } } ctx_data->stack_head->data = sdp_xml_parse_datatype(element_name, ctx_data->stack_head, ctx_data->record); if (ctx_data->stack_head->data == NULL) error("Can't parse element %s", element_name); } }
/* Allows this service to be discovered when running sdptool. For example, you can find this service * after starting it by running * * $ sdptool browse local * * (Adapted from http://www.btessentials.com/examples/bluez/sdp-register.c) * */ sdp_session_t *register_service(uint8_t rfcomm_channel) { /* A 128-bit number used to identify this service. The words are ordered from most to least * significant, but within each word, the octets are ordered from least to most significant. * For example, the UUID represneted by this array is 00001101-0000-1000-8000-00805F9B34FB. (The * hyphenation is a convention specified by the Service Discovery Protocol of the Bluetooth Core * Specification, but is not particularly important for this program.) * * This UUID is the Bluetooth Base UUID and is commonly used for simple Bluetooth applications. * Regardless of the UUID used, it must match the one that the Armatus Android app is searching * for. */ uint32_t svc_uuid_int[] = { 0x01110000, 0x00100000, 0x80000080, 0xFB349B5F }; const char *service_name = "Armatus Bluetooth server"; const char *svc_dsc = "A HERMIT server that interfaces with the Armatus Android app"; const char *service_prov = "Armatus"; uuid_t root_uuid, l2cap_uuid, rfcomm_uuid, svc_uuid, svc_class_uuid; sdp_list_t *l2cap_list = 0, *rfcomm_list = 0, *root_list = 0, *proto_list = 0, *access_proto_list = 0, *svc_class_list = 0, *profile_list = 0; sdp_data_t *channel = 0; sdp_profile_desc_t profile; sdp_record_t record = { 0 }; sdp_session_t *session = 0; // set the general service ID sdp_uuid128_create(&svc_uuid, &svc_uuid_int); sdp_set_service_id(&record, svc_uuid); char str[256] = ""; sdp_uuid2strn(&svc_uuid, str, 256); printf("Registering UUID %s\n", str); // set the service class sdp_uuid16_create(&svc_class_uuid, SERIAL_PORT_SVCLASS_ID); svc_class_list = sdp_list_append(0, &svc_class_uuid); sdp_set_service_classes(&record, svc_class_list); // set the Bluetooth profile information sdp_uuid16_create(&profile.uuid, SERIAL_PORT_PROFILE_ID); profile.version = 0x0100; profile_list = sdp_list_append(0, &profile); sdp_set_profile_descs(&record, profile_list); // make the service record publicly browsable sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); root_list = sdp_list_append(0, &root_uuid); sdp_set_browse_groups(&record, root_list); // set l2cap information sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); l2cap_list = sdp_list_append(0, &l2cap_uuid); proto_list = sdp_list_append(0, l2cap_list); // register the RFCOMM channel for RFCOMM sockets sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID); channel = sdp_data_alloc(SDP_UINT8, &rfcomm_channel); rfcomm_list = sdp_list_append(0, &rfcomm_uuid); sdp_list_append(rfcomm_list, channel); sdp_list_append(proto_list, rfcomm_list); access_proto_list = sdp_list_append(0, proto_list); sdp_set_access_protos(&record, access_proto_list); // set the name, provider, and description sdp_set_info_attr(&record, service_name, service_prov, svc_dsc); // connect to the local SDP server, register the service record, // and disconnect session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY); sdp_record_register(session, &record, 0); // cleanup sdp_data_free(channel); sdp_list_free(l2cap_list, 0); sdp_list_free(rfcomm_list, 0); sdp_list_free(root_list, 0); sdp_list_free(access_proto_list, 0); sdp_list_free(svc_class_list, 0); sdp_list_free(profile_list, 0); return session; }
/* * dosdpregistration - Care for the proper SDP record sent to the "sdpd" * so that other BT devices can discover the HID service * Parameters: none; Return value: 0 = OK, >0 = failure */ int dosdpregistration ( void ) { sdp_record_t record; sdp_session_t *session; sdp_list_t *svclass_id, *pfseq, *apseq, *root; uuid_t root_uuid, hidkb_uuid, l2cap_uuid, hidp_uuid; sdp_profile_desc_t profile[1]; sdp_list_t *aproto, *proto[3]; sdp_data_t *psm, *lang_lst, *lang_lst2, *hid_spec_lst, *hid_spec_lst2; void *dtds[2], *values[2], *dtds2[2], *values2[2]; int i, leng[2]; uint8_t dtd=SDP_UINT16, dtd2=SDP_UINT8, dtd_data=SDP_TEXT_STR8, hid_spec_type=0x22; uint16_t hid_attr_lang[]={0x409, 0x100}, ctrl=PSMHIDCTL, intr=PSMHIDINT, hid_attr[]={0x100, 0x111, 0x40, 0x00, 0x01, 0x01}, // Assigned to SDP 0x200...0x205 - see HID SPEC for // details. Those values seem to work fine... // "it\'s a kind of magic" numbers. hid_attr2[]={0x100, 0x0}; // Connect to SDP server on localhost, to publish service information session = sdp_connect ( BDADDR_ANY, BDADDR_LOCAL, 0 ); if ( ! session ) { fprintf ( stderr, "Failed to connect to SDP server: %s\n", strerror ( errno ) ); return 1; } memset(&record, 0, sizeof(sdp_record_t)); record.handle = 0xffffffff; // With 0xffffffff, we get assigned the first free record >= 0x10000 // Make HID service visible (add to PUBLIC BROWSE GROUP) sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); root = sdp_list_append(0, &root_uuid); sdp_set_browse_groups(&record, root); // Language Information to be added add_lang_attr(&record); // The descriptor for the keyboard sdp_uuid16_create(&hidkb_uuid, HID_SVCLASS_ID); svclass_id = sdp_list_append(0, &hidkb_uuid); sdp_set_service_classes(&record, svclass_id); // And information about the HID profile used sdp_uuid16_create(&profile[0].uuid, HIDP_UUID /*HID_PROFILE_ID*/); profile[0].version = 0x0100; pfseq = sdp_list_append(0, profile); sdp_set_profile_descs(&record, pfseq); // We are using L2CAP, so add an info about that sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); proto[1] = sdp_list_append(0, &l2cap_uuid); psm = sdp_data_alloc(SDP_UINT16, &ctrl); proto[1] = sdp_list_append(proto[1], psm); apseq = sdp_list_append(0, proto[1]); // And about our purpose, the HID protocol data transfer sdp_uuid16_create(&hidp_uuid, HIDP_UUID); proto[2] = sdp_list_append(0, &hidp_uuid); apseq = sdp_list_append(apseq, proto[2]); aproto = sdp_list_append(0, apseq); sdp_set_access_protos(&record, aproto); proto[1] = sdp_list_append(0, &l2cap_uuid); psm = sdp_data_alloc(SDP_UINT16, &intr); proto[1] = sdp_list_append(proto[1], psm); apseq = sdp_list_append(0, proto[1]); sdp_uuid16_create(&hidp_uuid, HIDP_UUID); proto[2] = sdp_list_append(0, &hidp_uuid); apseq = sdp_list_append(apseq, proto[2]); aproto = sdp_list_append(0, apseq); sdp_set_add_access_protos(&record, aproto); // Set service name, description sdp_set_info_attr(&record, HIDINFO_NAME, HIDINFO_PROV, HIDINFO_DESC); // Add a few HID-specifid pieces of information // See the HID spec for details what those codes 0x200+something // are good for... we send a fixed set of info that seems to work sdp_attr_add_new(&record, SDP_ATTR_HID_DEVICE_RELEASE_NUMBER, SDP_UINT16, &hid_attr[0]); /* Opt */ sdp_attr_add_new(&record, SDP_ATTR_HID_PARSER_VERSION, SDP_UINT16, &hid_attr[1]); /* Mand */ sdp_attr_add_new(&record, SDP_ATTR_HID_DEVICE_SUBCLASS, SDP_UINT8, &hid_attr[2]); /* Mand */ sdp_attr_add_new(&record, SDP_ATTR_HID_COUNTRY_CODE, SDP_UINT8, &hid_attr[3]); /* Mand */ sdp_attr_add_new(&record, SDP_ATTR_HID_VIRTUAL_CABLE, SDP_BOOL, &hid_attr[4]); /* Mand */ sdp_attr_add_new(&record, SDP_ATTR_HID_RECONNECT_INITIATE, SDP_BOOL, &hid_attr[5]); /* Mand */ // Add the HID descriptor (describing the virtual device) as code // SDP_ATTR_HID_DESCRIPTOR_LIST (0x206 IIRC) dtds[0] = &dtd2; values[0] = &hid_spec_type; dtd_data= SDPRECORD_BYTES <= 255 ? SDP_TEXT_STR8 : SDP_TEXT_STR16 ; dtds[1] = &dtd_data; values[1] = (uint8_t *) SDPRECORD; leng[0] = 0; leng[1] = SDPRECORD_BYTES; hid_spec_lst = sdp_seq_alloc_with_length(dtds, values, leng, 2); hid_spec_lst2 = sdp_data_alloc(SDP_SEQ8, hid_spec_lst); sdp_attr_add(&record, SDP_ATTR_HID_DESCRIPTOR_LIST, hid_spec_lst2); // and continue adding further data bytes for 0x206+x values for (i = 0; i < sizeof(hid_attr_lang) / 2; i++) { dtds2[i] = &dtd; values2[i] = &hid_attr_lang[i]; } lang_lst = sdp_seq_alloc(dtds2, values2, sizeof(hid_attr_lang) / 2); lang_lst2 = sdp_data_alloc(SDP_SEQ8, lang_lst); sdp_attr_add(&record, SDP_ATTR_HID_LANG_ID_BASE_LIST, lang_lst2); sdp_attr_add_new ( &record, SDP_ATTR_HID_PROFILE_VERSION, SDP_UINT16, &hid_attr2[0] ); sdp_attr_add_new ( &record, SDP_ATTR_HID_BOOT_DEVICE, SDP_UINT16, &hid_attr2[1] ); // Submit our IDEA of a SDP record to the "sdpd" if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) { fprintf ( stderr, "Service Record registration failed\n" ); return -1; } // Store the service handle retrieved from there for reference (i.e., // deleting the service info when this program terminates) sdphandle = record.handle; fprintf ( stdout, "HID keyboard/mouse service registered\n" ); return 0; }