4 * Collin R. Mulliner <collin@betaversion.net>
6 * http://www.mulliner.org/bluetooth/
21 #include <sys/ioctl.h>
22 #include <sys/socket.h>
28 #include <netinet/in.h>
30 #include <bluetooth/bluetooth.h>
31 #include <bluetooth/hci.h>
32 #include <bluetooth/hci_lib.h>
33 #include <bluetooth/sdp.h>
34 #include <bluetooth/sdp_lib.h>
35 #include <bluetooth/rfcomm.h>
36 #include <openobex/obex.h>
38 sdp_record_t *sdp_record;
39 sdp_session_t *sdp_session;
42 * 100% taken from bluez-utils (sdptool)
44 static void add_lang_attr(sdp_record_t *r)
46 sdp_lang_attr_t base_lang;
47 sdp_list_t *langs = 0;
49 /* UTF-8 MIBenum (http://www.iana.org/assignments/character-sets) */
50 base_lang.code_ISO639 = (0x65 << 8) | 0x6e;
51 base_lang.encoding = 106;
52 base_lang.base_offset = SDP_PRIMARY_LANG_BASE;
53 langs = sdp_list_append(0, &base_lang);
54 sdp_set_lang_attr(r, langs);
55 sdp_list_free(langs, 0);
59 * 100% taken from bluez-utils (sdptool)
61 static sdp_data_t *access_proto_to_dataseq(sdp_record_t *rec, sdp_list_t *proto)
63 sdp_data_t *seq = NULL;
64 void *dtds[10], *values[10];
65 void **seqDTDs, **seqs;
69 seqlen = sdp_list_len(proto);
70 seqDTDs = (void **)malloc(seqlen * sizeof(void *));
71 seqs = (void **)malloc(seqlen * sizeof(void *));
72 for (i = 0, p = proto; p; p = p->next, i++) {
73 sdp_list_t *elt = (sdp_list_t *)p->data;
76 for (; elt && pslen < sizeof(dtds); elt = elt->next, pslen++) {
77 sdp_data_t *d = (sdp_data_t *)elt->data;
78 dtds[pslen] = &d->dtd;
81 values[pslen] = &((uuid_t *)d)->value.uuid16;
84 values[pslen] = &((uuid_t *)d)->value.uuid32;
87 values[pslen] = &((uuid_t *)d)->value.uuid128;
90 values[pslen] = &d->val.uint8;
93 values[pslen] = &d->val.uint16;
103 s = sdp_seq_alloc(dtds, values, pslen);
105 seqDTDs[i] = &s->dtd;
109 seq = sdp_seq_alloc(seqDTDs, seqs, seqlen);
117 * add keyboard descriptor
119 void sdp_add_keyboard()
121 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
122 uuid_t root_uuid, hidkb_uuid, l2cap_uuid, hidp_uuid;
123 sdp_profile_desc_t profile[1];
124 sdp_list_t *aproto, *proto[3];
125 sdp_data_t *channel, *lang_lst, *lang_lst2, *hid_spec_lst, *hid_spec_lst2;
127 uint8_t dtd = SDP_UINT16;
128 uint8_t dtd2 = SDP_UINT8;
129 uint8_t dtd_data = SDP_TEXT_STR8;
130 sdp_session_t *session;
136 uint8_t hid_spec_type = 0x22;
137 uint16_t hid_attr_lang[] = {0x409,0x100};
138 static const uint8_t ctrl = 0x11;
139 static const uint8_t intr = 0x13;
140 static const uint16_t hid_attr[] = {0x100,0x111,0x40,0x0d,0x01,0x01};
141 static const uint16_t hid_attr2[] = {0x0,0x01,0x100,0x1f40,0x01,0x01};
142 // taken from Apple Wireless Keyboard
143 const uint8_t hid_spec[] = {
144 0x05, 0x01, // usage page
145 0x09, 0x06, // keyboard
146 0xa1, 0x01, // key codes
147 0x85, 0x01, // minimum
149 0x19, 0xe0, // logical min
150 0x29, 0xe7, // logical max
151 0x15, 0x00, // report size
152 0x25, 0x01, // report count
153 0x75, 0x01, // input data variable absolute
154 0x95, 0x08, // report count
155 0x81, 0x02, // report size
198 printf("%s: sdp_session invalid\n", (char*)__func__);
201 session = sdp_session;
203 sdp_record = sdp_record_alloc();
205 perror("add_keyboard sdp_record_alloc: ");
209 memset((void*)sdp_record, 0, sizeof(sdp_record_t));
210 sdp_record->handle = 0xffffffff;
211 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
212 root = sdp_list_append(0, &root_uuid);
213 sdp_set_browse_groups(sdp_record, root);
215 add_lang_attr(sdp_record);
217 sdp_uuid16_create(&hidkb_uuid, HID_SVCLASS_ID);
218 svclass_id = sdp_list_append(0, &hidkb_uuid);
219 sdp_set_service_classes(sdp_record, svclass_id);
221 sdp_uuid16_create(&profile[0].uuid, HID_PROFILE_ID);
222 profile[0].version = 0x0100;
223 pfseq = sdp_list_append(0, profile);
224 sdp_set_profile_descs(sdp_record, pfseq);
227 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
228 proto[1] = sdp_list_append(0, &l2cap_uuid);
229 channel = sdp_data_alloc(SDP_UINT8, &ctrl);
230 proto[1] = sdp_list_append(proto[1], channel);
231 apseq = sdp_list_append(0, proto[1]);
233 sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
234 proto[2] = sdp_list_append(0, &hidp_uuid);
235 apseq = sdp_list_append(apseq, proto[2]);
237 aproto = sdp_list_append(0, apseq);
238 sdp_set_access_protos(sdp_record, aproto);
241 proto[1] = sdp_list_append(0, &l2cap_uuid);
242 channel = sdp_data_alloc(SDP_UINT8, &intr);
243 proto[1] = sdp_list_append(proto[1], channel);
244 apseq = sdp_list_append(0, proto[1]);
246 sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
247 proto[2] = sdp_list_append(0, &hidp_uuid);
248 apseq = sdp_list_append(apseq, proto[2]);
250 aproto = sdp_list_append(0, apseq);
251 sdp_set_add_access_protos(sdp_record, aproto);
253 sdp_set_info_attr(sdp_record, "Collin's Fake Bluetooth Keyboard",
254 "MUlliNER.ORG", "http://www.mulliner.org/bluetooth/");
256 for (i = 0; i < sizeof(hid_attr)/2; i++) {
257 sdp_attr_add_new(sdp_record, SDP_ATTR_HID_DEVICE_RELEASE_NUMBER+i, SDP_UINT16, &hid_attr[i]);
261 values[0] = &hid_spec_type;
263 values[1] = (uint8_t*)hid_spec;
265 leng[1] = sizeof(hid_spec);
266 hid_spec_lst = sdp_seq_alloc_with_length(dtds, values, leng, 2);
267 hid_spec_lst2 = sdp_data_alloc(SDP_SEQ8, hid_spec_lst);
268 sdp_attr_add(sdp_record, SDP_ATTR_HID_DESCRIPTOR_LIST, hid_spec_lst2);
270 for (i = 0; i < sizeof(hid_attr_lang)/2; i++) {
272 values2[i] = &hid_attr_lang[i];
274 lang_lst = sdp_seq_alloc(dtds2, values2, sizeof(hid_attr_lang)/2);
275 lang_lst2 = sdp_data_alloc(SDP_SEQ8, lang_lst);
276 sdp_attr_add(sdp_record, SDP_ATTR_HID_LANG_ID_BASE_LIST, lang_lst2);
278 sdp_attr_add_new(sdp_record, SDP_ATTR_HID_SDP_DISABLE, SDP_UINT16, &hid_attr2[0]);
279 for (i = 0; i < sizeof(hid_attr2)/2-1; i++) {
280 sdp_attr_add_new(sdp_record, SDP_ATTR_HID_REMOTE_WAKEUP+i, SDP_UINT16, &hid_attr2[i+1]);
283 if (sdp_record_register(session, sdp_record, 0) < 0) {
284 printf("%s: HID Device (Keyboard) Service Record registration failed\n", (char*)__func__);
291 if (sdp_record && sdp_record_unregister(sdp_session, sdp_record)) {
292 printf("%s: HID Device (Keyboard) Service Record unregistration failed\n", (char*)__func__);
295 sdp_close(sdp_session);
301 sdp_session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, 0);
304 printf("%s: sdp_session invalid\n", (char*)__func__);