allready defined in sdp_lib.h
[xkbdbthid.git] / xkbd-0.8.15_bthid / src / sdp.c
1 /*
2  *  xkbd-bthid
3  *
4  *  Collin R. Mulliner <collin@betaversion.net>
5  *
6  *  http://www.mulliner.org/bluetooth/
7  *
8  *  License: GPL
9  *
10  */
11
12 #define _GNU_SOURCE
13 #include <assert.h>
14 #include <errno.h>
15 #include <fcntl.h>
16 #include <stdarg.h>
17 #include <stdbool.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <sys/ioctl.h>
22 #include <sys/socket.h>
23 #include <sys/poll.h>
24 #include <termios.h>
25 #include <time.h>
26 #include <unistd.h>
27 #include <dirent.h>
28 #include <netinet/in.h>
29 #include <netdb.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>
37
38 sdp_record_t *sdp_record;
39 sdp_session_t *sdp_session;
40
41 /*
42  *  100% taken from bluez-utils (sdptool)
43  */
44 static void add_lang_attr(sdp_record_t *r)
45 {
46         sdp_lang_attr_t base_lang;
47         sdp_list_t *langs = 0;
48
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);
56 }
57
58 /*
59  *  100% taken from bluez-utils (sdptool)
60  */
61 static sdp_data_t *access_proto_to_dataseq(sdp_record_t *rec, sdp_list_t *proto)
62 {
63         sdp_data_t *seq = NULL;
64         void *dtds[10], *values[10];
65         void **seqDTDs, **seqs;
66         int i, seqlen;
67         sdp_list_t *p;
68
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;
74                 sdp_data_t *s;
75                 int pslen = 0;
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;
79                         switch (d->dtd) {
80                         case SDP_UUID16:
81                                 values[pslen] = &((uuid_t *)d)->value.uuid16;
82                                 break;
83                         case SDP_UUID32:
84                                 values[pslen] = &((uuid_t *)d)->value.uuid32;
85                                 break;
86                         case SDP_UUID128:
87                                 values[pslen] = &((uuid_t *)d)->value.uuid128;
88                                 break;
89                         case SDP_UINT8:
90                                 values[pslen] = &d->val.uint8;
91                                 break;
92                         case SDP_UINT16:
93                                 values[pslen] = &d->val.uint16;
94                                 break;
95                         case SDP_SEQ8:
96                         case SDP_SEQ16:
97                         case SDP_SEQ32:
98                                 values[pslen] = d;
99                                 break;
100                         // FIXME: more
101                         }
102                 }
103                 s = sdp_seq_alloc(dtds, values, pslen);
104                 if (s) {
105                         seqDTDs[i] = &s->dtd;
106                         seqs[i] = s;
107                 }
108         }
109         seq = sdp_seq_alloc(seqDTDs, seqs, seqlen);
110         free(seqDTDs);
111         free(seqs);
112         return seq;
113 }
114
115
116 /*
117  *  add keyboard descriptor
118  */
119 void sdp_add_keyboard()
120 {
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;
126         int i;
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;
131         void *dtds[2];
132         void *values[2];
133         void *dtds2[2];
134         void *values2[2];
135         int leng[2];
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
148                 0x05, 0x07, // max
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
156                 0x75, 0x08, 
157                 0x95, 0x01, 
158                 0x81, 0x01, 
159                 0x75, 0x01, 
160                 0x95, 0x05,
161                 0x05, 0x08,
162                 0x19, 0x01,
163                 0x29, 0x05, 
164                 0x91, 0x02,
165                 0x75, 0x03,
166                 0x95, 0x01,
167                 0x91, 0x01,
168                 0x75, 0x08,
169                 0x95, 0x06,
170                 0x15, 0x00,
171                 0x26, 0xff,
172                 0x00, 0x05,
173                 0x07, 0x19,
174                 0x00, 0x2a,
175                 0xff, 0x00,
176                 0x81, 0x00,
177                 0x75, 0x01,
178                 0x95, 0x01,
179                 0x15, 0x00,
180                 0x25, 0x01,
181                 0x05, 0x0c,
182                 0x09, 0xb8,
183                 0x81, 0x06,
184                 0x09, 0xe2,
185                 0x81, 0x06,
186                 0x09, 0xe9,
187                 0x81, 0x02,
188                 0x09, 0xea,
189                 0x81, 0x02,
190                 0x75, 0x01,
191                 0x95, 0x04,
192                 0x81, 0x01,
193                 0xc0         // end tag
194         };
195
196
197         if (!sdp_session) {
198                 printf("%s: sdp_session invalid\n", (char*)__func__);
199                 exit(-1);
200         }
201         session = sdp_session;
202
203         sdp_record = sdp_record_alloc();
204         if (!sdp_record) {
205                 perror("add_keyboard sdp_record_alloc: ");
206                 exit(-1);
207         }
208
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);
214
215         add_lang_attr(sdp_record);
216         
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);
220
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);
225
226         // PROTO
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]);
232
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]);
236
237         aproto = sdp_list_append(0, apseq);
238         sdp_set_access_protos(sdp_record, aproto);
239
240         // ATTR_ADD_PROTO
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]);
245
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]);
249
250         aproto = sdp_list_append(0, apseq);
251         sdp_set_add_access_protos(sdp_record, aproto);
252         
253         sdp_set_info_attr(sdp_record, "Collin's Fake Bluetooth Keyboard", 
254                 "MUlliNER.ORG", "http://www.mulliner.org/bluetooth/");
255
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]);
258         }
259
260         dtds[0] = &dtd2;
261         values[0] = &hid_spec_type;
262         dtds[1] = &dtd_data;
263         values[1] = (uint8_t*)hid_spec;
264         leng[0] = 0;
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);
269         
270         for (i = 0; i < sizeof(hid_attr_lang)/2; i++) {
271                 dtds2[i] = &dtd;
272                 values2[i] = &hid_attr_lang[i];
273         }
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);
277
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]);
281         }
282         
283         if (sdp_record_register(session, sdp_record, 0) < 0) {
284                 printf("%s: HID Device (Keyboard) Service Record registration failed\n", (char*)__func__);
285                 exit(-1);
286         }
287 }
288
289 void sdp_remove()
290 {
291         if (sdp_record && sdp_record_unregister(sdp_session, sdp_record)) {
292                 printf("%s: HID Device (Keyboard) Service Record unregistration failed\n", (char*)__func__);
293         }
294         
295         sdp_close(sdp_session);
296 }
297
298 void sdp_open()
299 {
300         if (!sdp_session) {
301                 sdp_session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, 0);
302         }
303         if (!sdp_session) {
304                 printf("%s: sdp_session invalid\n", (char*)__func__);
305                 exit(-1);
306         }
307 }
308
309 #ifdef SDP_MAIN
310 int main()
311 {
312         sdp_open();
313         sdp_add_keyboard();
314         sleep(60);      
315         sdp_remove();
316         return(1);
317 }
318 #endif