static void add_lang_attr(sdp_record_t *r) { sdp_lang_attr_t base_lang; sdp_list_t *langs = 0; /* UTF-8 MIBenum (http://www.iana.org/assignments/character-sets) */ base_lang.code_ISO639 = (0x65 << 8) | 0x6e; base_lang.encoding = 106; base_lang.base_offset = SDP_PRIMARY_LANG_BASE; langs = sdp_list_append(0, &base_lang); sdp_set_lang_attr(r, langs); sdp_list_free(langs, 0); }
int sdpreg_pan(struct btservice *svc) { int status = -1; sdpsvc_t *svcRec; sdpdata_t *attr; slist_t *ptype = NULL; /* ** First create a service record handle */ s_list_append_uint(&ptype, 0x800); s_list_append_uint(&ptype, 0x806); svcRec = sdp_create_pan_svc(svc->profile->svc_class, ptype, 0x0000, 0x0005, 0x100); s_list_free(&ptype); if (svcRec == NULL) return -1; /* add language attribute */ attr = sdp_set_lang_attr(svcRec); if (attr == NULL) { BTERROR("setLanguageBase failed"); sdp_free_svc(svcRec); return -1; } status = sdp_add_lang(attr, 0, 0, 0); if (status) { sdp_free_svc(svcRec); return -1; } /* set informational attibutes */ status = sdp_set_info_attr(svcRec, svc->name, svc->prov, svc->desc); if (status != 0) { sdp_free_svc(svcRec); return -1; } status = sdp_register_service(srvHandle, svcRec); if (status != 0) { BTERROR("sdp_register_service failed"); sdp_free_svc(svcRec); return -1; } svc->svcRec = svcRec; return 0; }
int register_record(int descriptor_is_relative){ // Connect to to local SDP-Servicer on localhost, to publish // the new service record. // Session will be established. sdp_session_t *session; session = sdp_connect ( BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY ); if ( ! session ) { // LOGCAT: __android_log_print(ANDROID_LOG_DEBUG, TAG, "SDP: Connection to SDP failed."); return CODE_SDP_SESSION_FAILED; } // LOGCAT: __android_log_print(ANDROID_LOG_DEBUG, TAG, "SDP: Connection to SDP established."); // Service record, to be included in the registry of the SDP-Server sdp_record_t record; // To create the record, several lists must be put together sdp_list_t *languages, *service_class_id, *profile_sequence, *access_protocol_sequence, *root_list, *access_protocol, *protocol_list[3]; // The uuid_t data type is used to represent the 128-bit UUID that // is used as un universal unique identifier. SEE THE THESIS, SUBSECTION 2.2.2 uuid_t root_uuid, hid_uuid, l2cap_uuid, hidp_uuid; // BluetoothProfileDescriptorList. SEE THE THESIS, SUBSECTION 4.2.6 sdp_profile_desc_t sdp_profile[1]; // LanguageBaseAttributeIDList, SEE THE THESIS, SUBSECTION 4.2.4 sdp_lang_attr_t base_language; // The sdp_data_t structure stores information in a service record sdp_data_t *psm, *hid_descriptor_list, *hid_descriptor_formatted_list, *language_base_list, *language_base_formatted_list; // SDP-specific types: 8- and 16- bit unsigned integers and a 8-bit string uint8_t data_type_uint8 = SDP_UINT8; uint8_t data_type_uint16 = SDP_UINT16; uint8_t data_type_str8 = SDP_TEXT_STR8; int length[2]; // arrays used to form the sdp specific strcuture of sequence attribites: descriptor and language base void *data_types[2] , *descriptor_array[2], *language_base_array[2]; memset(&record, 0, sizeof(sdp_record_t)); // Assigning the Record Handle, SEE THE THESIS, SUBSECTION 4.2.2 record.handle = handle; // Putting together attributes, common to all services. // SEE THE THESIS, SECTION 4.2 // Setting the Browse Group and making // the service record publicly available. // SEE THE THESIS, SUBSECTION 4.2.3 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); root_list = sdp_list_append(0, &root_uuid); sdp_set_browse_groups( &record, root_list ); // The LanguageBaseAttributeIDList // SEE THE THESIS, SUBSECTION 4.2.4 base_language.code_ISO639 = (0x65 << 8) | 0x6e; base_language.base_offset = SDP_PRIMARY_LANG_BASE; base_language.encoding = 106; languages = sdp_list_append(0, &base_language); sdp_set_lang_attr(&record, languages); sdp_list_free(languages, 0); // The ServiceClassIDList // SEE THE THESIS, SUBSECTION 4.2.1 sdp_uuid16_create(&hid_uuid, HID_SVCLASS_ID); service_class_id = sdp_list_append(0, &hid_uuid); sdp_set_service_classes(&record, service_class_id); // The BluetoothProfileDescriptorList // SEE THE THESIS, SUBSECTION 4.2.6 sdp_uuid16_create(&sdp_profile[0].uuid, HID_PROFILE_ID); sdp_profile[0].version = 0x0100; profile_sequence = sdp_list_append(0, sdp_profile); sdp_set_profile_descs(&record, profile_sequence); // The ProtocolDescriptorList // SEE THE THESIS, SUBSECTION 4.2.5 // We set information about: // A) Control Channel -> // B) Interruption Channel // We use the protocol_list to bind information // about L2CAP and HID stack level // A) Control Channel (PSM: 0x11) // 1) Set info on L2CAP sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); protocol_list[1] = sdp_list_append(0, &l2cap_uuid); psm = sdp_data_alloc(SDP_UINT16, &control_channel_psm); protocol_list[1] = sdp_list_append(protocol_list[1], psm); access_protocol_sequence = sdp_list_append(0, protocol_list[1]); // 2) Set info on HID sdp_uuid16_create(&hidp_uuid, HIDP_UUID); protocol_list[2] = sdp_list_append(0, &hidp_uuid); access_protocol_sequence = sdp_list_append(access_protocol_sequence, protocol_list[2]); // bind to DecriptorList access_protocol = sdp_list_append(0, access_protocol_sequence); sdp_set_access_protos(&record, access_protocol); // B) Interruption Channel (PSM: 0x13) // 1) Set info on L2CAP protocol_list[1] = sdp_list_append(0, &l2cap_uuid); psm = sdp_data_alloc(SDP_UINT16, &interruption_channel_psm); protocol_list[1] = sdp_list_append(protocol_list[1], psm); access_protocol_sequence = sdp_list_append(0, protocol_list[1]); // 2) Set info on HID sdp_uuid16_create(&hidp_uuid, HIDP_UUID); protocol_list[2] = sdp_list_append(0, &hidp_uuid); access_protocol_sequence = sdp_list_append(access_protocol_sequence, protocol_list[2]); access_protocol = sdp_list_append(0, access_protocol_sequence); sdp_set_add_access_protos(&record, access_protocol); // Setting the information on device, author and service, // throuth the human-readable attributes // SEE THE THESIS, SUBSECTION 4.2.4 sdp_set_info_attr(&record, SERVICE_NAME, SERVICE_INFO, AUTHOR_INFO); // After putting together the attributes, common to all services, // we bind the attributes that are specific to the HID service. // SEE THE THESIS, SECTION 4.3 // Adding all HID attributes (mandatory or optional) // explained in the THESIS (4.3.1 - 4.3.13) // SEE THE THESIS, SUBSECTION 4.3.1 if(descriptor_is_relative){ sdp_attr_add_new( &record, SDP_ATTR_HID_DEVICE_RELEASE_NUMBER, SDP_UINT16, &attr_release_number_mouse_keyboard); }else{ sdp_attr_add_new( &record, SDP_ATTR_HID_DEVICE_RELEASE_NUMBER, SDP_UINT16, &attr_release_number_pointer_keyboard); } // SEE THE THESIS, SUBSECTION 4.3.2 sdp_attr_add_new( &record, SDP_ATTR_HID_PARSER_VERSION, SDP_UINT16, &attr_parser_version); // SEE THE THESIS, SUBSECTION 4.3.3 sdp_attr_add_new( &record, SDP_ATTR_HID_DEVICE_SUBCLASS, SDP_UINT8, &attr_device_subclass); // SEE THE THESIS, SUBSECTION 4.3.4 sdp_attr_add_new( &record, SDP_ATTR_HID_COUNTRY_CODE, SDP_UINT8, &attr_country_code); // SEE THE THESIS, SUBSECTION 4.3.5 sdp_attr_add_new( &record, SDP_ATTR_HID_VIRTUAL_CABLE, SDP_BOOL, &attr_virtual_cable); // SEE THE THESIS, SUBSECTION 4.3.6 sdp_attr_add_new( &record, SDP_ATTR_HID_RECONNECT_INITIATE, SDP_BOOL, &attr_reconnect_initiate); // SEE THE THESIS, SUBSECTION 4.3.13 // Adding the HIDDescriptorList attribute is more complex, // thus it is data sequence. // // The attribute contains two things: // A) The descriptor type as unsigned integer (In our case it is a report descriptor) // B) The two descriptors as string sequence (keyboard + mouse or keyboard + pointer) data_types[0] = &data_type_uint8; data_types[1] = &data_type_str8; // We check the descriptor_is_realtive value to // find out, if the keyboard + mouse or keyboard + pointer // service description is to be added. if(descriptor_is_relative){ descriptor_array[0] = &hid_descriptor_type; descriptor_array[1] =(uint8_t *) attr_hid_descriptor_relative; length[0] = 0; length[1] = sizeof(attr_hid_descriptor_relative); }else{ descriptor_array[0] = &hid_descriptor_type; descriptor_array[1] =(uint8_t *) attr_hid_descriptor_absolute; length[0] = 0; length[1] = sizeof(attr_hid_descriptor_absolute); } // We bind the array containing the type and the array containing the values // with the sdp_seq_alloc_with_length function hid_descriptor_list = sdp_seq_alloc_with_length( data_types, descriptor_array, length, 2 ); // The newly created array contains all information, so it is used to create // the list from the right SDP-specific type (SDP_SEQ8) hid_descriptor_formatted_list = sdp_data_alloc( SDP_SEQ8, hid_descriptor_list ); // Finally the list is added as un SDP-attribute sdp_attr_add( &record, SDP_ATTR_HID_DESCRIPTOR_LIST, hid_descriptor_formatted_list ); // Done! // The same is also done with the HIDLANGIDBaseList // SEE THE THESIS, SUBSECTION 4.3.12 data_types[0] = &data_type_uint16; data_types[1] = &data_type_uint16; language_base_array[0] = &attr_language_base[0]; language_base_array[1] = &attr_language_base[1]; //sizeof(attr_language_base) is devided by two, since values are 16-bit integers (not 8-bit like with the HIDDecriptorList) language_base_list = sdp_seq_alloc(data_types, language_base_array, sizeof(attr_language_base) / 2); language_base_formatted_list = sdp_data_alloc(SDP_SEQ8, language_base_list); sdp_attr_add(&record, SDP_ATTR_HID_LANG_ID_BASE_LIST, language_base_formatted_list); // Done! // SEE THE THESIS, SUBSECTION 4.3.7 sdp_attr_add_new( &record, SDP_ATTR_HID_SDP_DISABLE, SDP_BOOL, &attr_sdp_disable); // SEE THE THESIS, SUBSECTION 4.3.8 sdp_attr_add_new( &record, SDP_ATTR_HID_BATTERY_POWER, SDP_BOOL, &attr_battery_power); // SEE THE THESIS, SUBSECTION 4.3.9 sdp_attr_add_new( &record, SDP_ATTR_HID_REMOTE_WAKEUP, SDP_BOOL, &attr_remote_wake); // SEE THE THESIS, SUBSECTION 4.3.10 sdp_attr_add_new( &record, SDP_ATTR_HID_PROFILE_VERSION, SDP_UINT16, &attr_profile_version); // sdp_attr_add_new( &record, // SDP_ATTR_HID_SUPERVISION_TIMEOUT, // SDP_UINT16, // &attr_supervision_timeout); // SEE THE THESIS, SUBSECTION 4.3.6 sdp_attr_add_new( &record, SDP_ATTR_HID_NORMALLY_CONNECTABLE, SDP_BOOL, &attr_normally_connectable); // SEE THE THESIS, SUBSECTION 4.3.11 sdp_attr_add_new( &record, SDP_ATTR_HID_BOOT_DEVICE, SDP_BOOL, &attr_boot_device); // At last the record is good to go and could be added to the sdp registry! if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) { // LOGCAT: __android_log_print(ANDROID_LOG_DEBUG, TAG, "SDP: Registration of new record failed."); return CODE_RECORD_REGISTRATION_FAILED; } // LOGCAT: __android_log_print(ANDROID_LOG_DEBUG, TAG, "SDP: Registration of new record successful."); sdp_close(session); return CODE_RECORD_REGISTERED; }