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);
116 * add additional access protos
118 static int sdp_set_add_access_protos(sdp_record_t *rec, const sdp_list_t *ap)
121 sdp_data_t *protos = 0;
122 sdp_data_t *protosg = 0;
124 for (p = ap; p; p = p->next) {
125 sdp_data_t *seq = access_proto_to_dataseq(rec, (sdp_list_t *)p->data);
126 protos = sdp_seq_append(protos, seq);
128 protosg = sdp_data_alloc(SDP_SEQ8, protos);
129 sdp_attr_add(rec, SDP_ATTR_ADD_PROTO_DESC_LIST, protosg);
134 * add keyboard descriptor
136 void sdp_add_keyboard()
138 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
139 uuid_t root_uuid, hidkb_uuid, l2cap_uuid, hidp_uuid;
140 sdp_profile_desc_t profile[1];
141 sdp_list_t *aproto, *proto[3];
142 sdp_data_t *channel, *lang_lst, *lang_lst2, *hid_spec_lst, *hid_spec_lst2;
144 uint8_t dtd = SDP_UINT16;
145 uint8_t dtd2 = SDP_UINT8;
146 uint8_t dtd_data = SDP_TEXT_STR8;
147 sdp_session_t *session;
153 uint8_t hid_spec_type = 0x22;
154 uint16_t hid_attr_lang[] = {0x409,0x100};
155 static const uint8_t ctrl = 0x11;
156 static const uint8_t intr = 0x13;
157 static const uint16_t hid_attr[] = {0x100,0x111,0x40,0x0d,0x01,0x01};
158 static const uint16_t hid_attr2[] = {0x0,0x01,0x100,0x1f40,0x01,0x01};
159 // taken from Apple Wireless Keyboard
160 const uint8_t hid_spec[] = {
161 0x05, 0x01, // usage page
162 0x09, 0x06, // keyboard
163 0xa1, 0x01, // key codes
164 0x85, 0x01, // minimum
166 0x19, 0xe0, // logical min
167 0x29, 0xe7, // logical max
168 0x15, 0x00, // report size
169 0x25, 0x01, // report count
170 0x75, 0x01, // input data variable absolute
171 0x95, 0x08, // report count
172 0x81, 0x02, // report size
215 printf("%s: sdp_session invalid\n", (char*)__func__);
218 session = sdp_session;
220 sdp_record = sdp_record_alloc();
222 perror("add_keyboard sdp_record_alloc: ");
226 memset((void*)sdp_record, 0, sizeof(sdp_record_t));
227 sdp_record->handle = 0xffffffff;
228 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
229 root = sdp_list_append(0, &root_uuid);
230 sdp_set_browse_groups(sdp_record, root);
232 add_lang_attr(sdp_record);
234 sdp_uuid16_create(&hidkb_uuid, HID_SVCLASS_ID);
235 svclass_id = sdp_list_append(0, &hidkb_uuid);
236 sdp_set_service_classes(sdp_record, svclass_id);
238 sdp_uuid16_create(&profile[0].uuid, HID_PROFILE_ID);
239 profile[0].version = 0x0100;
240 pfseq = sdp_list_append(0, profile);
241 sdp_set_profile_descs(sdp_record, pfseq);
244 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
245 proto[1] = sdp_list_append(0, &l2cap_uuid);
246 channel = sdp_data_alloc(SDP_UINT8, &ctrl);
247 proto[1] = sdp_list_append(proto[1], channel);
248 apseq = sdp_list_append(0, proto[1]);
250 sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
251 proto[2] = sdp_list_append(0, &hidp_uuid);
252 apseq = sdp_list_append(apseq, proto[2]);
254 aproto = sdp_list_append(0, apseq);
255 sdp_set_access_protos(sdp_record, aproto);
258 proto[1] = sdp_list_append(0, &l2cap_uuid);
259 channel = sdp_data_alloc(SDP_UINT8, &intr);
260 proto[1] = sdp_list_append(proto[1], channel);
261 apseq = sdp_list_append(0, proto[1]);
263 sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
264 proto[2] = sdp_list_append(0, &hidp_uuid);
265 apseq = sdp_list_append(apseq, proto[2]);
267 aproto = sdp_list_append(0, apseq);
268 sdp_set_add_access_protos(sdp_record, aproto);
270 sdp_set_info_attr(sdp_record, "Collin's Fake Bluetooth Keyboard",
271 "MUlliNER.ORG", "http://www.mulliner.org/bluetooth/");
273 for (i = 0; i < sizeof(hid_attr)/2; i++) {
274 sdp_attr_add_new(sdp_record, SDP_ATTR_HID_DEVICE_RELEASE_NUMBER+i, SDP_UINT16, &hid_attr[i]);
278 values[0] = &hid_spec_type;
280 values[1] = (uint8_t*)hid_spec;
282 leng[1] = sizeof(hid_spec);
283 hid_spec_lst = sdp_seq_alloc_with_length(dtds, values, leng, 2);
284 hid_spec_lst2 = sdp_data_alloc(SDP_SEQ8, hid_spec_lst);
285 sdp_attr_add(sdp_record, SDP_ATTR_HID_DESCRIPTOR_LIST, hid_spec_lst2);
287 for (i = 0; i < sizeof(hid_attr_lang)/2; i++) {
289 values2[i] = &hid_attr_lang[i];
291 lang_lst = sdp_seq_alloc(dtds2, values2, sizeof(hid_attr_lang)/2);
292 lang_lst2 = sdp_data_alloc(SDP_SEQ8, lang_lst);
293 sdp_attr_add(sdp_record, SDP_ATTR_HID_LANG_ID_BASE_LIST, lang_lst2);
295 sdp_attr_add_new(sdp_record, SDP_ATTR_HID_SDP_DISABLE, SDP_UINT16, &hid_attr2[0]);
296 for (i = 0; i < sizeof(hid_attr2)/2-1; i++) {
297 sdp_attr_add_new(sdp_record, SDP_ATTR_HID_REMOTE_WAKEUP+i, SDP_UINT16, &hid_attr2[i+1]);
300 if (sdp_record_register(session, sdp_record, 0) < 0) {
301 printf("%s: HID Device (Keyboard) Service Record registration failed\n", (char*)__func__);
308 if (sdp_record && sdp_record_unregister(sdp_session, sdp_record)) {
309 printf("%s: HID Device (Keyboard) Service Record unregistration failed\n", (char*)__func__);
312 sdp_close(sdp_session);
318 sdp_session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, 0);
321 printf("%s: sdp_session invalid\n", (char*)__func__);