1 //
2 // anyRemote
3 // a wi-fi or bluetooth remote for your PC.
4 //
5 // Copyright (C) 2006-2016 Mikhail Fedotov <anyremote@mail.ru>
6 //
7 // This program is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 3 of the License, or
10 // (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 //
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <sys/socket.h>
25 #include <errno.h>
26
27
28 #ifdef USE_L2CAP
29
30 #ifdef USE_BLUEZ
31 #include <bluetooth/bluetooth.h>
32 #include <bluetooth/l2cap.h>
33 #include <bluetooth/sdp.h>
34 #include <bluetooth/sdp_lib.h>
35 #endif
36
37 #ifdef USE_BT_FBSD
38 #include <bluetooth.h>
39 #include <sdp.h>
40 #include <err.h>
41 #endif
42
43 #include "common.h"
44 #include "utils.h"
45 #include "peer.h"
46
47 extern char tmp[MAXMAXLEN];
48 extern boolean_t stillRun;
49
50 typedef struct _L2CapConnection_ {
51 int fileDescriptor;
52 int serverFileDescriptor;
53 #ifdef USE_BLUEZ
54 sdp_session_t *session;
55 sdp_record_t *record;
56 #endif
57 #ifdef USE_BT_FBSD
58 void *session = NULL;
59 uint32_t record;
60 #endif
61 } _L2CapConnection;
62
63 //
64 // Support SDP
65 //
66
67 #ifdef USE_BLUEZ
68
sdpRegisterL2cap(ConnectInfo * connInfo)69 void sdpRegisterL2cap(ConnectInfo* connInfo)
70 {
71 _L2CapConnection* cn = (_L2CapConnection*) connInfo->connectionData;
72 if (!cn) return;
73
74 uint8_t svc_uuid_int[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xab, 0xcd };
75 const char *service_name = "anyRemote/l2cap";
76 const char *svc_dsc = "Bluetooth remote control";
77 const char *service_prov = "anyRemote";
78 uint8_t l2cap_port = connInfo->port;
79
80 uuid_t root_uuid, l2cap_uuid, svc_uuid, svc_class_uuid;
81 sdp_list_t *l2cap_list = 0,
82 *root_list = 0,
83 *proto_list = 0,
84 *access_proto_list = 0,
85 *svc_class_list = 0,
86 *profile_list = 0;
87 sdp_data_t *channel = 0;
88 sdp_profile_desc_t profile;
89 cn->record = sdp_record_alloc();
90
91 // set the general service ID
92 sdp_uuid128_create( &svc_uuid, &svc_uuid_int );
93 sdp_set_service_id( cn->record, svc_uuid );
94
95 // set the service class
96 sdp_uuid16_create(&svc_class_uuid, SERIAL_PORT_SVCLASS_ID);
97 svc_class_list = sdp_list_append(0, &svc_class_uuid);
98 sdp_set_service_classes(cn->record, svc_class_list);
99
100 // set the Bluetooth profile information
101 sdp_uuid16_create(&profile.uuid, SERIAL_PORT_PROFILE_ID);
102 profile.version = 0x0100;
103 profile_list = sdp_list_append(0, &profile);
104 sdp_set_profile_descs(cn->record, profile_list);
105
106 // make the service record publicly browsable
107 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
108 root_list = sdp_list_append(0, &root_uuid);
109 sdp_set_browse_groups(cn->record, root_list );
110
111 // set l2cap information
112 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
113 l2cap_list = sdp_list_append( 0, &l2cap_uuid );
114 channel = sdp_data_alloc(SDP_UINT8, &l2cap_port);
115 sdp_list_append(l2cap_list, channel );
116 proto_list = sdp_list_append( 0, l2cap_list );
117
118 access_proto_list = sdp_list_append( 0, proto_list );
119 sdp_set_access_protos(cn->record, access_proto_list );
120
121 // set the name, provider, and description
122 sdp_set_info_attr(cn->record, service_name, service_prov, svc_dsc);
123
124 // connect to the local SDP server, register the service record,
125 // and disconnect
126 cn->session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY);
127 if ( (!(cn->session && cn->record)) || sdp_record_register(cn->session, cn->record, 0) == -1) {
128 logger(L_ERR, "can not register SDP service");
129 }
130
131 // cleanup
132 sdp_data_free( channel );
133 sdp_list_free( l2cap_list, 0 );
134 sdp_list_free( proto_list, 0 );
135 sdp_list_free( root_list, 0 );
136 sdp_list_free( access_proto_list, 0 );
137 sdp_list_free( svc_class_list, 0 );
138 sdp_list_free( profile_list, 0 );
139 }
140 #endif
141
142 #ifdef USE_BT_FBSD
143
sdpRegisterL2cap(ConnectInfo * connInfo)144 void sdpRegisterL2cap(ConnectInfo* connInfo)
145 {
146 errx(1, "Not yet supported");
147 }
148 #endif
149
sdpDeregisterL2cap(_L2CapConnection * cn)150 void sdpDeregisterL2cap(_L2CapConnection* cn)
151 {
152 #ifdef USE_BLUEZ
153 if (cn->session != NULL) {
154 sdp_record_unregister(cn->session, cn->record);
155 cn->session = NULL;
156 }
157 #endif
158 #ifdef USE_BT_FBSD
159 if (cn->session != NULL) {
160 sdp_unregister_service(cn->session, cn->record);
161 sdp_close(cn->session);
162 cn->session = NULL;
163 }
164 #endif
165 }
166
167 //
168 // Support L2CAP sockets
169 //
170
openL2capPort(ConnectInfo * connInfo)171 int openL2capPort(ConnectInfo* connInfo)
172 {
173 #ifdef USE_BLUEZ
174 struct sockaddr_l2 l2_addr;
175 #endif
176 #ifdef USE_BT_FBSD
177
178 #endif
179
180 struct sockaddr* socketaddr = NULL;
181
182 int sz;
183
184 if (connInfo->connectionData && ((_L2CapConnection*) connInfo->connectionData)->serverFileDescriptor > 0) {
185 logger(L_ERR, "L2CAP socket was already opened");
186 return 1;
187 }
188
189 if (connInfo->connectionData) {
190 free(connInfo->connectionData);
191 }
192
193 connInfo->connectionData = (_L2CapConnection*) malloc(sizeof(_L2CapConnection));
194 _L2CapConnection* cn = (_L2CapConnection*) connInfo->connectionData;
195
196 cn->serverFileDescriptor = -1;
197 cn->fileDescriptor = -1;
198 cn->session = NULL;
199 cn->record = NULL;
200
201 if ((cn->serverFileDescriptor = socket(PF_BLUETOOTH, SOCK_SEQPACKET|SOCK_CLOEXEC, BTPROTO_L2CAP)) < 0) {
202 logger(L_ERR, "opening BT/L2CAP socket");
203 printf("ERROR: opening BT/L2CAP socket\n");
204 return -1;
205 }
206
207 #ifdef USE_BLUEZ
208 memset((void *) &l2_addr, 0, sizeof(l2_addr));
209 sz = sizeof(l2_addr);
210
211 // bind socket to the specified port of the first available local bluetooth adapter
212 l2_addr.l2_family = AF_BLUETOOTH;
213 l2_addr.l2_bdaddr = *BDADDR_ANY;
214 l2_addr.l2_psm = htobs(0x1001); //port);
215
216 sdpRegisterL2cap(connInfo);
217 sprintf(tmp, "registered L2CAP on port %i", connInfo->port);
218 logger(L_INF, tmp);
219 socketaddr=(struct sockaddr *)&l2_addr;
220 #endif
221
222 #ifdef USE_BT_FBSD
223
224 #endif
225
226 if (bind(cn->serverFileDescriptor, (struct sockaddr *) socketaddr, sz) < 0) {
227 logger(L_ERR, "on binding");
228 printf("ERROR: on binding %d->%s\n", errno, strerror(errno));
229 return -1;
230 }
231
232 return 1;
233 }
234
l2capOpen(ConnectInfo * connInfo)235 int l2capOpen(ConnectInfo* connInfo)
236 {
237 DEBUG2("[DS]: L2CAP Server mode. Use port %d", connInfo->port);
238 if (openL2capPort(connInfo) < 0) {
239 return EXIT_NOK;
240 }
241 return EXIT_OK;
242 }
243
l2capFD(ConnectInfo * connInfo)244 int l2capFD(ConnectInfo* connInfo)
245 {
246 _L2CapConnection* cn = (_L2CapConnection*) connInfo->connectionData;
247 return (cn ? cn->fileDescriptor : -1);
248 }
249
l2capClose(ConnectInfo * connInfo,int final)250 void l2capClose(ConnectInfo* connInfo, int final)
251 {
252 logger(L_INF, "l2capClose");
253
254 _L2CapConnection* cn = (_L2CapConnection*) connInfo->connectionData;
255 if (!cn) return;
256
257 if (cn->fileDescriptor >= 0) {
258 close(cn->fileDescriptor);
259 cn->fileDescriptor = -1;
260 }
261 if (cn->serverFileDescriptor > 0) {
262 close(cn->serverFileDescriptor);
263 cn->serverFileDescriptor = -1;
264 }
265
266 if (final) {
267 sdpDeregisterL2cap(cn);
268 }
269
270 free(cn);
271 connInfo->connectionData = NULL;
272 connInfo->state = PEER_DISCONNECTED;
273 }
274
l2capReset(ConnectInfo * conn)275 void l2capReset(ConnectInfo* conn)
276 {
277 logger(L_INF, "l2capReset");
278
279 _L2CapConnection* cn = (_L2CapConnection*) connInfo->connectionData;
280 if (cn) {
281 if (cn->fileDescriptor >= 0) {
282 close(cn->fileDescriptor);
283 cn->fileDescriptor = -1;
284 }
285 connInfo->state = PEER_WAIT_ACCEPT;
286 } else {
287 conn->state = PEER_DISCONNECTED; // should not happens
288 }
289 }
290
l2capSetup(ConnectInfo * connInfo)291 int l2capSetup(ConnectInfo* connInfo)
292 {
293 _L2CapConnection* cn = (_L2CapConnection*) connInfo->connectionData;
294 if (!cn) {
295 return -1;
296 }
297 int ret = listen(cn->serverFileDescriptor,0);
298 if (ret >= 0) {
299 conn->state = PEER_WAIT_ACCEPT;
300 }
301 return (ret < 0 ? -1 : 1);
302 }
303
l2capAccept(ConnectInfo * connInfo)304 int l2capAccept(ConnectInfo* connInfo)
305 {
306 logger(L_INF, "[DS]: Server mode/L2CAP: Waiting connection");
307 int cnt;
308 char buf[1024] = { 0 };
309
310 #ifdef USE_BLUEZ
311 struct sockaddr_l2 l2rem_addr;
312 socklen_t opt = sizeof(l2rem_addr);
313 #endif
314
315 #ifdef USE_BT_FBSD
316
317 #endif
318 cnt = 0;
319
320 _L2CapConnection* cn = (_L2CapConnection*) connInfo->connectionData;
321 if (!cn) return -1;
322
323 while (stillRun) {
324
325 cn->fileDescriptor = accept(cn->serverFileDescriptor, (struct sockaddr *)&l2rem_addr, &opt);
326
327 if (cn->fileDescriptor == -1 && errno == EAGAIN) {
328
329 if (cnt >= 60) { // Print to log every minute
330 logger(L_INF, "l2capAccept: waiting for connection");
331 cnt = 0;
332 }
333 fflush(stdout);
334
335 sleep(1);
336 cnt++;
337
338 continue;
339 }
340
341 if (cn->fileDescriptor < 0) {
342 logger(L_ERR, "on accept");
343 printf("ERROR: on accept %d\n", errno);
344 return -1;
345 }
346
347 ba2str(&l2rem_addr.l2_bdaddr, buf);
348
349 if (!isAllowed(buf)) {
350 INFO2("l2capAccept: host %s is not in the list of accepted host, close connection", buf);
351 write(cn->fileDescriptor,CMD_STR_DISCONNECT,strlen(CMD_STR_DISCONNECT));
352
353 close(cn->fileDescriptor);
354 cn->fileDescriptor = -1;
355 connInfo->state = PEER_DISCONNECTED;
356
357 return -1;
358 }
359
360 if (getUsePassword()) {
361 logger(L_DBG,"[DS]: l2capAccept: Do password verification");
362
363 int ret = EXIT_OK;
364
365 int i=0;
366 for ( ; i<3; i++) {
367 ret = verifyPassword(cn->fileDescriptor);
368
369 if (ret == EXIT_OK) { // got it
370 break;
371 }
372 }
373
374 if (ret != EXIT_OK) {
375
376 if (ret == EXIT_NOK) {
377 write(cn->fileDescriptor,CMD_STR_DISCONNECT,strlen(CMD_STR_DISCONNECT));
378 }
379
380 close(cn->fileDescriptor);
381 cn->fileDescriptor = -1;
382 connInfo->state = PEER_DISCONNECTED;
383
384 return -1;
385 }
386 logger(L_DBG,"[DS]: l2capAccept: Password verification OK");
387 }
388
389 sprintf(tmp, "l2capAccept: accepted from %s", buf);
390 logger(L_INF, tmp);
391
392 connInfo->state = PEER_CONNECTED;
393
394 // force to detect cover size. need to do that before (Connect) or syncPeer() handling
395 getCoverSize(connInfo->id, cn->fileDescriptor);
396
397 break;
398 }
399 return 1;
400 }
401
l2capWrite(ConnectInfo * connInfo,dMessage * msg)402 int l2capWrite(ConnectInfo* connInfo, dMessage* msg)
403 {
404 _L2CapConnection* cn = (_L2CapConnection*) connInfo->connectionData;
405 if (!cn) {
406 logger(L_DBG,"[DS]: l2capWrite() no connection data");
407 return EXIT_NOK;
408 }
409 const char* command = msg->value;
410 int count = msg->size;
411
412 logger(L_DBG, "l2capWrite");
413
414 if (!command || count <= 0) {
415 return EXIT_OK;
416 }
417
418 if (strcmp("End();",command) == 0) { // used only for WEB/CMXML
419 return EXIT_OK;
420 }
421
422 // send command
423 memset(tmp, 0, MAXMAXLEN);
424 strcat(tmp, "l2capWrite ");
425
426 int logSz = (count > 256 ? 255 : count);
427
428 // it is possible to get binary data here
429 memcpy(tmp, command, logSz); // Do not dump long commands
430 tmp[logSz] = '\0';
431 logger(L_DBG, tmp);
432
433 sprintf(tmp, "l2capWrite %d bytes", count);
434 logger(L_INF, tmp);
435
436 int n = write(cn->fileDescriptor,command,count);
437 if (n < 0) {
438 logger(L_ERR, "error writing to L2CAP socket");
439 return EXIT_NOK;
440 }
441
442 return EXIT_OK;
443 }
444
445 #endif
446