|
|
rfcommd.c - rfcommd - RFCOMM daemon to run filters on clients. |
|
|
 |
git clone git://bitreich.org/rfcommd/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/rfcommd/ (git://bitreich.org) |
|
|
 |
Log |
|
|
 |
Files |
|
|
 |
Refs |
|
|
 |
Tags |
|
|
 |
README |
|
|
 |
LICENSE |
|
|
|
--- |
|
|
|
rfcommd.c (12906B) |
|
|
|
--- |
|
|
|
1 /* |
|
|
|
2 * See LICENSE for copyright details. |
|
|
|
3 * |
|
|
|
4 * Logic copied from rfcomm.c in bluez. |
|
|
|
5 * SDP code from pybluez. |
|
|
|
6 * |
|
|
|
7 * Copy me if you can. |
|
|
|
8 * by 20h |
|
|
|
9 */ |
|
|
|
10 |
|
|
|
11 #include <stdio.h> |
|
|
|
12 #include <errno.h> |
|
|
|
13 #include <fcntl.h> |
|
|
|
14 #include <unistd.h> |
|
|
|
15 #include <stdlib.h> |
|
|
|
16 #include <string.h> |
|
|
|
17 #include <getopt.h> |
|
|
|
18 #include <signal.h> |
|
|
|
19 #include <libgen.h> |
|
|
|
20 #include <termios.h> |
|
|
|
21 #include <stdint.h> |
|
|
|
22 #include <poll.h> |
|
|
|
23 #include <stdarg.h> |
|
|
|
24 #include <sys/poll.h> |
|
|
|
25 #include <sys/param.h> |
|
|
|
26 #include <sys/ioctl.h> |
|
|
|
27 #include <sys/socket.h> |
|
|
|
28 #include <sys/wait.h> |
|
|
|
29 |
|
|
|
30 #include <bluetooth/bluetooth.h> |
|
|
|
31 #include <bluetooth/hci.h> |
|
|
|
32 #include <bluetooth/hci_lib.h> |
|
|
|
33 #include <bluetooth/rfcomm.h> |
|
|
|
34 #include <bluetooth/sdp.h> |
|
|
|
35 #include <bluetooth/sdp_lib.h> |
|
|
|
36 |
|
|
|
37 #include "arg.h" |
|
|
|
38 |
|
|
|
39 volatile sig_atomic_t __io_canceled = 0; |
|
|
|
40 |
|
|
|
41 int dodebug = 0; |
|
|
|
42 |
|
|
|
43 void |
|
|
|
44 debug(char *fmt, ...) |
|
|
|
45 { |
|
|
|
46 va_list fmtargs; |
|
|
|
47 |
|
|
|
48 if (!dodebug) |
|
|
|
49 return; |
|
|
|
50 |
|
|
|
51 va_start(fmtargs, fmt); |
|
|
|
52 vfprintf(stderr, fmt, fmtargs); |
|
|
|
53 va_end(fmtargs); |
|
|
|
54 } |
|
|
|
55 |
|
|
|
56 void |
|
|
|
57 sig_hup(int sig) |
|
|
|
58 { |
|
|
|
59 return; |
|
|
|
60 } |
|
|
|
61 |
|
|
|
62 void |
|
|
|
63 sig_term(int sig) |
|
|
|
64 { |
|
|
|
65 __io_canceled = 1; |
|
|
|
66 } |
|
|
|
67 |
|
|
|
68 void |
|
|
|
69 setup_signals(void) |
|
|
|
70 { |
|
|
|
71 struct sigaction sa; |
|
|
|
72 |
|
|
|
73 memset(&sa, 0, sizeof(sa)); |
|
|
|
74 sa.sa_flags = SA_NOCLDSTOP; |
|
|
|
75 sa.sa_handler = SIG_IGN; |
|
|
|
76 sigaction(SIGCHLD, &sa, NULL); |
|
|
|
77 sigaction(SIGPIPE, &sa, NULL); |
|
|
|
78 |
|
|
|
79 sa.sa_handler = sig_term; |
|
|
|
80 sigaction(SIGTERM, &sa, NULL); |
|
|
|
81 sigaction(SIGINT, &sa, NULL); |
|
|
|
82 |
|
|
|
83 sa.sa_handler = sig_hup; |
|
|
|
84 sigaction(SIGHUP, &sa, NULL); |
|
|
|
85 } |
|
|
|
86 |
|
|
|
87 int |
|
|
|
88 _adv_available(struct hci_dev_info *di) |
|
|
|
89 { |
|
|
|
90 uint32_t *flags = &di->flags; |
|
|
|
91 int dd; |
|
|
|
92 |
|
|
|
93 if (hci_test_bit(HCI_RAW, &flags) && !bacmp(&di->bdaddr, BDADDR_ANY)) { |
|
|
|
94 dd = hci_open_dev(di->dev_id); |
|
|
|
95 |
|
|
|
96 if (dd < 0) |
|
|
|
97 return -1; |
|
|
|
98 hci_read_bd_addr(dd, &di->bdaddr, 1000); |
|
|
|
99 hci_close_dev(dd); |
|
|
|
100 } |
|
|
|
101 |
|
|
|
102 return (hci_test_bit(HCI_UP, flags) && |
|
|
|
103 hci_test_bit(HCI_RUNNING, flags) && |
|
|
|
104 hci_test_bit(HCI_PSCAN, flags) && |
|
|
|
105 hci_test_bit(HCI_ISCAN, flags)) != 0 ? 0 : -1; |
|
|
|
106 } |
|
|
|
107 |
|
|
|
108 int |
|
|
|
109 _any_adv_available(void) |
|
|
|
110 { |
|
|
|
111 struct hci_dev_list_req *dl = NULL; |
|
|
|
112 struct hci_dev_req *dr = NULL; |
|
|
|
113 struct hci_dev_info di = {0, }; |
|
|
|
114 int result = -1; |
|
|
|
115 int ctl = -1; |
|
|
|
116 int i; |
|
|
|
117 |
|
|
|
118 if ((ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0) |
|
|
|
119 return -1; |
|
|
|
120 |
|
|
|
121 if (!(dl = malloc(HCI_MAX_DEV * sizeof(struct hci_dev_req) + |
|
|
|
122 sizeof(uint16_t)))) { |
|
|
|
123 goto CLEAN_UP_RETURN; |
|
|
|
124 } |
|
|
|
125 dl->dev_num = HCI_MAX_DEV; |
|
|
|
126 dr = dl->dev_req; |
|
|
|
127 |
|
|
|
128 if (ioctl(ctl, HCIGETDEVLIST, (void *)dl) < 0) |
|
|
|
129 goto CLEAN_UP_RETURN; |
|
|
|
130 |
|
|
|
131 for (i = 0; i < dl->dev_num; i++) { |
|
|
|
132 di.dev_id = (dr+i)->dev_id; |
|
|
|
133 if (ioctl(ctl, HCIGETDEVINFO, (void *)&di) < 0) |
|
|
|
134 continue; |
|
|
|
135 |
|
|
|
136 if (_adv_available(&di) == 0) { |
|
|
|
137 result = 0; |
|
|
|
138 goto CLEAN_UP_RETURN; |
|
|
|
139 } |
|
|
|
140 } |
|
|
|
141 |
|
|
|
142 CLEAN_UP_RETURN: |
|
|
|
143 close(ctl); |
|
|
|
144 free(dl); |
|
|
|
145 |
|
|
|
146 return result; |
|
|
|
147 } |
|
|
|
148 |
|
|
|
149 int |
|
|
|
150 adv_available(int sock) |
|
|
|
151 { |
|
|
|
152 bdaddr_t ba = {{0, }}; |
|
|
|
153 struct sockaddr addr = {0, }; |
|
|
|
154 int dev_id = -1; |
|
|
|
155 socklen_t alen = sizeof(addr); |
|
|
|
156 struct sockaddr_rc const *addr_rc = (struct sockaddr_rc const *)&addr; |
|
|
|
157 struct hci_dev_info di; |
|
|
|
158 |
|
|
|
159 if (getsockname(sock, &addr, &alen) < 0) |
|
|
|
160 return -1; |
|
|
|
161 |
|
|
|
162 ba = addr_rc->rc_bdaddr; |
|
|
|
163 |
|
|
|
164 if (bacmp(&ba, BDADDR_ANY) == 0) { |
|
|
|
165 dev_id = -1; |
|
|
|
166 } else { |
|
|
|
167 dev_id = hci_get_route(&ba); |
|
|
|
168 } |
|
|
|
169 |
|
|
|
170 if (dev_id == -1) { |
|
|
|
171 return _any_adv_available(); |
|
|
|
172 } else { |
|
|
|
173 if (hci_devinfo(dev_id, &di)) |
|
|
|
174 return -1; |
|
|
|
175 return _adv_available(&di); |
|
|
|
176 } |
|
|
|
177 } |
|
|
|
178 |
|
|
|
179 int |
|
|
|
180 str2uuid(char *uuidstr, uuid_t *uuid) |
|
|
|
181 { |
|
|
|
182 uint32_t uuid_int[4]; |
|
|
|
183 int i; |
|
|
|
184 char *endptr, buf[9] = { 0 }; |
|
|
|
185 |
|
|
|
186 if (strlen(uuidstr) == 36) { |
|
|
|
187 if (uuidstr[8] != '-' && uuidstr[13] != '-' && |
|
|
|
188 uuidstr[18] != '-' && uuidstr[23] != '-') { |
|
|
|
189 return 1; |
|
|
|
190 } |
|
|
|
191 |
|
|
|
192 strncpy(buf, uuidstr, 8); |
|
|
|
193 uuid_int[0] = htonl(strtoul(buf, &endptr, 16)); |
|
|
|
194 if (endptr != buf+8) |
|
|
|
195 return 1; |
|
|
|
196 |
|
|
|
197 strncpy(buf, uuidstr+9, 4); |
|
|
|
198 strncpy(buf+4, uuidstr+14, 4); |
|
|
|
199 uuid_int[1] = htonl(strtoul(buf, &endptr, 16)); |
|
|
|
200 if (endptr != buf+8) |
|
|
|
201 return 1; |
|
|
|
202 |
|
|
|
203 strncpy(buf, uuidstr+19, 4); |
|
|
|
204 strncpy(buf+4, uuidstr+24, 4); |
|
|
|
205 uuid_int[2] = htonl(strtoul(buf, &endptr, 16)); |
|
|
|
206 if (endptr != buf+8) |
|
|
|
207 return 1; |
|
|
|
208 |
|
|
|
209 strncpy(buf, uuidstr+28, 4); |
|
|
|
210 uuid_int[3] = htonl(strtoul(buf, &endptr, 16)); |
|
|
|
211 if (endptr != buf+8) |
|
|
|
212 return 1; |
|
|
|
213 |
|
|
|
214 if (uuid != NULL) |
|
|
|
215 sdp_uuid128_create(uuid, uuid_int); |
|
|
|
216 } else if (strlen(uuidstr) == 8) { |
|
|
|
217 uuid_int[0] = strtoul(uuidstr, &endptr, 16); |
|
|
|
218 if (endptr != uuidstr+8) |
|
|
|
219 return 1; |
|
|
|
220 if (uuid != NULL) |
|
|
|
221 sdp_uuid32_create(uuid, uuid_int[0]); |
|
|
|
222 } else if (strlen(uuidstr) == 4) { |
|
|
|
223 i = strtol(uuidstr, &endptr, 16); |
|
|
|
224 if (endptr != uuidstr+4) |
|
|
|
225 return 1; |
|
|
|
226 if (uuid != NULL) |
|
|
|
227 sdp_uuid16_create(uuid, i); |
|
|
|
228 } else { |
|
|
|
229 return 1; |
|
|
|
230 } |
|
|
|
231 |
|
|
|
232 return 0; |
|
|
|
233 } |
|
|
|
234 |
|
|
|
235 int |
|
|
|
236 sdp_advertise_service(int sock, char *svcname, |
|
|
|
237 char *svcid, int svc_class, int profiles, |
|
|
|
238 char *svcprovider, char *svcdescription) |
|
|
|
239 { |
|
|
|
240 char addrbuf[256]; |
|
|
|
241 int res, err = 0; |
|
|
|
242 struct sockaddr *sockaddr; |
|
|
|
243 uuid_t root_uuid, l2cap_uuid, rfcomm_uuid, svc_class_uuid, |
|
|
|
244 svc_uuid; |
|
|
|
245 sdp_profile_desc_t *profile_desc; |
|
|
|
246 sdp_list_t *l2cap_list = NULL, *rfcomm_list = NULL, *root_list = NULL, |
|
|
|
247 *proto_list = NULL, *profile_list = NULL, |
|
|
|
248 *svc_class_list = NULL, *access_proto_list = NULL; |
|
|
|
249 sdp_data_t *channel = 0; |
|
|
|
250 sdp_record_t record; |
|
|
|
251 sdp_session_t *session = 0; |
|
|
|
252 uint8_t rfcomm_channel; |
|
|
|
253 socklen_t addrlen = sizeof(struct sockaddr_rc); |
|
|
|
254 |
|
|
|
255 str2uuid(svcid, &svc_uuid); |
|
|
|
256 sdp_uuid16_create(&svc_class_uuid, svc_class); |
|
|
|
257 |
|
|
|
258 memset(addrbuf, 0, sizeof(addrbuf)); |
|
|
|
259 |
|
|
|
260 if (adv_available(sock) < 0) |
|
|
|
261 return -1; |
|
|
|
262 |
|
|
|
263 res = getsockname(sock, (struct sockaddr *)addrbuf, &addrlen); |
|
|
|
264 if (res < 0) |
|
|
|
265 return -1; |
|
|
|
266 sockaddr = (struct sockaddr *)addrbuf; |
|
|
|
267 |
|
|
|
268 memset(&record, 0, sizeof(record)); |
|
|
|
269 memset(&record.handle, 0xff, sizeof(record.handle)); |
|
|
|
270 |
|
|
|
271 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); |
|
|
|
272 root_list = sdp_list_append(0, &root_uuid); |
|
|
|
273 sdp_set_browse_groups(&record, root_list); |
|
|
|
274 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); |
|
|
|
275 l2cap_list = sdp_list_append(0, &l2cap_uuid); |
|
|
|
276 proto_list = sdp_list_append(0, l2cap_list); |
|
|
|
277 rfcomm_channel = ((struct sockaddr_rc *)sockaddr)->rc_channel; |
|
|
|
278 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID); |
|
|
|
279 channel = sdp_data_alloc(SDP_UINT8, &rfcomm_channel); |
|
|
|
280 rfcomm_list = sdp_list_append(0, &rfcomm_uuid); |
|
|
|
281 sdp_list_append(rfcomm_list, channel); |
|
|
|
282 sdp_list_append(proto_list, rfcomm_list); |
|
|
|
283 access_proto_list = sdp_list_append(0, proto_list); |
|
|
|
284 sdp_set_access_protos(&record, access_proto_list); |
|
|
|
285 svc_class_list = sdp_list_append(svc_class_list, &svc_class_uuid); |
|
|
|
286 sdp_set_service_classes(&record, svc_class_list); |
|
|
|
287 |
|
|
|
288 profile_desc = (sdp_profile_desc_t *)malloc(sizeof(sdp_profile_desc_t)); |
|
|
|
289 if (profile_desc == NULL) |
|
|
|
290 return -1; |
|
|
|
291 sdp_uuid16_create(&profile_desc->uuid, profiles); |
|
|
|
292 profile_list = sdp_list_append(profile_list, profile_desc); |
|
|
|
293 sdp_set_profile_descs(&record, profile_list); |
|
|
|
294 |
|
|
|
295 sdp_set_info_attr(&record, svcname, svcprovider, svcdescription); |
|
|
|
296 sdp_set_service_id(&record, svc_uuid); |
|
|
|
297 |
|
|
|
298 session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, 0); |
|
|
|
299 if (!session) |
|
|
|
300 return -1; |
|
|
|
301 err = sdp_record_register(session, &record, 0); |
|
|
|
302 |
|
|
|
303 if (channel) |
|
|
|
304 sdp_data_free(channel); |
|
|
|
305 sdp_list_free(l2cap_list, 0); |
|
|
|
306 sdp_list_free(rfcomm_list, 0); |
|
|
|
307 sdp_list_free(root_list, 0); |
|
|
|
308 sdp_list_free(access_proto_list, 0); |
|
|
|
309 sdp_list_free(svc_class_list, 0); |
|
|
|
310 sdp_list_free(profile_list, free); |
|
|
|
311 |
|
|
|
312 if (err) |
|
|
|
313 return -1; |
|
|
|
314 |
|
|
|
315 return 0; |
|
|
|
316 } |
|
|
|
317 |
|
|
|
318 void |
|
|
|
319 usage(char *argv0) |
|
|
|
320 { |
|
|
|
321 fprintf(stderr, "%s [-dhrAESM] [-i hciX|bdaddr] [-L linger] [-c channel] [-f filter cmd] [cmd]\n", |
|
|
|
322 basename(argv0)); |
|
|
|
323 exit(1); |
|
|
|
324 } |
|
|
|
325 |
|
|
|
326 int |
|
|
|
327 main(int argc, char *argv[]) |
|
|
|
328 { |
|
|
|
329 int rfcomm_raw_tty = 0, auth = 0, encryption = 0, |
|
|
|
330 secure = 0, master = 0, linger = 0, sk, nsk, fd, lm , try = 30, |
|
|
|
331 ctl, rc_channel = 1, filteri, dev; |
|
|
|
332 char *argv0, *optarg, dst[18], devname[MAXPATHLEN], *replace, |
|
|
|
333 *cmd, *oldcmd, *defaultcmd = NULL, *runcmd; |
|
|
|
334 struct sockaddr_rc laddr, raddr; |
|
|
|
335 struct rfcomm_dev_req req; |
|
|
|
336 struct termios ti; |
|
|
|
337 socklen_t alen; |
|
|
|
338 bdaddr_t bdaddr; |
|
|
|
339 struct linger l; |
|
|
|
340 |
|
|
|
341 char **cmds = NULL; |
|
|
|
342 char **filteraddrs = NULL; |
|
|
|
343 bdaddr_t **filterbds = NULL; |
|
|
|
344 int filtern = 0; |
|
|
|
345 |
|
|
|
346 bacpy(&bdaddr, BDADDR_ANY); |
|
|
|
347 |
|
|
|
348 ARGBEGIN(argv0) { |
|
|
|
349 case 'c': |
|
|
|
350 rc_channel = atoi(EARGF(usage(argv0))); |
|
|
|
351 break; |
|
|
|
352 case 'd': |
|
|
|
353 dodebug = 1; |
|
|
|
354 break; |
|
|
|
355 case 'i': |
|
|
|
356 optarg = EARGF(usage(argv0)); |
|
|
|
357 if (strncmp(optarg, "hci", 3) == 0) { |
|
|
|
358 hci_devba(atoi(optarg + 3), &bdaddr); |
|
|
|
359 } else { |
|
|
|
360 str2ba(optarg, &bdaddr); |
|
|
|
361 } |
|
|
|
362 break; |
|
|
|
363 case 'f': |
|
|
|
364 ++filtern; |
|
|
|
365 filteraddrs = realloc(filteraddrs, |
|
|
|
366 filtern * sizeof(*filteraddrs)); |
|
|
|
367 if (filteraddrs == NULL) |
|
|
|
368 exit(1); |
|
|
|
369 |
|
|
|
370 cmds = realloc(cmds, filtern * sizeof(*cmds)); |
|
|
|
371 if (cmds == NULL) |
|
|
|
372 exit(1); |
|
|
|
373 |
|
|
|
374 filterbds = realloc(filterbds, filtern * sizeof(*filterbds)); |
|
|
|
375 if (filterbds == NULL) |
|
|
|
376 exit(1); |
|
|
|
377 |
|
|
|
378 filteraddrs[filtern-1] = EARGF(usage(argv0)); |
|
|
|
379 argv++, argc--; |
|
|
|
380 if (argc <= 0) |
|
|
|
381 usage(argv0); |
|
|
|
382 cmds[filtern-1] = argv[0]; |
|
|
|
383 |
|
|
|
384 filterbds[filtern-1] = malloc(sizeof(*filterbds)); |
|
|
|
385 if (filterbds[filtern-1] == NULL) |
|
|
|
386 exit(1); |
|
|
|
387 str2ba(filteraddrs[filtern-1], filterbds[filtern-1]); |
|
|
|
388 break; |
|
|
|
389 case 'r': |
|
|
|
390 rfcomm_raw_tty = 1; |
|
|
|
391 break; |
|
|
|
392 case 'A': |
|
|
|
393 auth = 1; |
|
|
|
394 break; |
|
|
|
395 case 'E': |
|
|
|
396 encryption = 1; |
|
|
|
397 break; |
|
|
|
398 case 'S': |
|
|
|
399 secure = 1; |
|
|
|
400 break; |
|
|
|
401 case 'M': |
|
|
|
402 master = 1; |
|
|
|
403 break; |
|
|
|
404 case 'L': |
|
|
|
405 linger = atoi(EARGF(usage(argv0))); |
|
|
|
406 break; |
|
|
|
407 case 'h': |
|
|
|
408 default: |
|
|
|
409 usage(argv0); |
|
|
|
410 } ARGEND; |
|
|
|
411 |
|
|
|
412 if (argc > 0) |
|
|
|
413 defaultcmd = argv[0]; |
|
|
|
414 if (defaultcmd == NULL && filtern < 0) |
|
|
|
415 usage(argv[0]); |
|
|
|
416 |
|
|
|
417 for (filteri = 0; filteri < filtern; filteri++) { |
|
|
|
418 ba2str(filterbds[filteri], dst); |
|
|
|
419 debug("filter: %s (%s) -> %s\n", |
|
|
|
420 filteraddrs[filteri], dst, cmds[filteri]); |
|
|
|
421 } |
|
|
|
422 debug("defaultcmd: %s\n", defaultcmd); |
|
|
|
423 |
|
|
|
424 setup_signals(); |
|
|
|
425 |
|
|
|
426 ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_RFCOMM); |
|
|
|
427 if (ctl < 0) { |
|
|
|
428 perror("Can't open RFCOMM control socket"); |
|
|
|
429 return 1; |
|
|
|
430 } |
|
|
|
431 |
|
|
|
432 laddr.rc_family = AF_BLUETOOTH; |
|
|
|
433 bacpy(&laddr.rc_bdaddr, &bdaddr); |
|
|
|
434 laddr.rc_channel = rc_channel; |
|
|
|
435 |
|
|
|
436 sk = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); |
|
|
|
437 if (sk < 0) { |
|
|
|
438 perror("Can't create RFCOMM socket"); |
|
|
|
439 return 1; |
|
|
|
440 } |
|
|
|
441 |
|
|
|
442 lm = 0; |
|
|
|
443 if (master) |
|
|
|
444 lm |= RFCOMM_LM_MASTER; |
|
|
|
445 if (auth) |
|
|
|
446 lm |= RFCOMM_LM_AUTH; |
|
|
|
447 if (encryption) |
|
|
|
448 lm |= RFCOMM_LM_ENCRYPT; |
|
|
|
449 if (secure) |
|
|
|
450 lm |= RFCOMM_LM_SECURE; |
|
|
|
451 |
|
|
|
452 if (lm && setsockopt(sk, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm)) < 0) { |
|
|
|
453 perror("Can't set RFCOMM link mode"); |
|
|
|
454 close(sk); |
|
|
|
455 return 1; |
|
|
|
456 } |
|
|
|
457 |
|
|
|
458 if (bind(sk, (struct sockaddr *)&laddr, sizeof(laddr)) < 0) { |
|
|
|
459 perror("Can't bind RFCOMM socket"); |
|
|
|
460 close(sk); |
|
|
|
461 return 1; |
|
|
|
462 } |
|
|
|
463 |
|
|
|
464 debug("Waiting for connection on channel %d\n", laddr.rc_channel); |
|
|
|
465 |
|
|
|
466 listen(sk, 10); |
|
|
|
467 |
|
|
|
468 sdp_advertise_service(sk, |
|
|
|
469 "SPP Printer", |
|
|
|
470 "00001101-0000-1000-8000-00805F9B34FB", |
|
|
|
471 SERIAL_PORT_SVCLASS_ID, |
|
|
|
472 SERIAL_PORT_PROFILE_ID, |
|
|
|
473 "SPP Printer Emulation", |
|
|
|
474 "rfcommd"); |
|
|
|
475 |
|
|
|
476 while (!__io_canceled) { |
|
|
|
477 alen = sizeof(raddr); |
|
|
|
478 nsk = accept(sk, (struct sockaddr *)&raddr, &alen); |
|
|
|
479 |
|
|
|
480 if (fork() != 0) |
|
|
|
481 continue; |
|
|
|
482 |
|
|
|
483 ba2str(&raddr.rc_bdaddr, dst); |
|
|
|
484 debug("Accept from %s\n", dst); |
|
|
|
485 |
|
|
|
486 for (filteri = 0; filteri < filtern; filteri++) { |
|
|
|
487 if (!bacmp(filterbds[filteri], &raddr.rc_bdaddr)) { |
|
|
|
488 runcmd = cmds[filteri]; |
|
|
|
489 debug("filter found: %s -> %s\n", |
|
|
|
490 filteraddrs[filteri], |
|
|
|
491 runcmd); |
|
|
|
492 break; |
|
|
|
493 } |
|
|
|
494 } |
|
|
|
495 if (filteri >= filtern) { |
|
|
|
496 if (defaultcmd != NULL) { |
|
|
|
497 debug("running defaultcmd = %s\n", |
|
|
|
498 defaultcmd); |
|
|
|
499 runcmd = defaultcmd; |
|
|
|
500 } else { |
|
|
|
501 close(nsk); |
|
|
|
502 continue; |
|
|
|
503 } |
|
|
|
504 } |
|
|
|
505 |
|
|
|
506 alen = sizeof(laddr); |
|
|
|
507 if (getsockname(nsk, (struct sockaddr *)&laddr, &alen) < 0) { |
|
|
|
508 perror("Can't get RFCOMM socket name"); |
|
|
|
509 close(nsk); |
|
|
|
510 continue; |
|
|
|
511 } |
|
|
|
512 |
|
|
|
513 if (linger) { |
|
|
|
514 l.l_onoff = 1; |
|
|
|
515 l.l_linger = linger; |
|
|
|
516 |
|
|
|
517 if (setsockopt(nsk, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0) { |
|
|
|
518 perror("Can't set linger option"); |
|
|
|
519 close(nsk); |
|
|
|
520 continue; |
|
|
|
521 } |
|
|
|
522 } |
|
|
|
523 |
|
|
|
524 memset(&req, 0, sizeof(req)); |
|
|
|
525 req.dev_id = -1; |
|
|
|
526 req.flags = (1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP); |
|
|
|
527 |
|
|
|
528 bacpy(&req.src, &laddr.rc_bdaddr); |
|
|
|
529 bacpy(&req.dst, &raddr.rc_bdaddr); |
|
|
|
530 req.channel = raddr.rc_channel; |
|
|
|
531 |
|
|
|
532 dev = ioctl(nsk, RFCOMMCREATEDEV, &req); |
|
|
|
533 if (dev < 0) { |
|
|
|
534 perror("Can't create RFCOMM TTY"); |
|
|
|
535 close(sk); |
|
|
|
536 continue; |
|
|
|
537 } |
|
|
|
538 |
|
|
|
539 snprintf(devname, MAXPATHLEN - 1, "/dev/rfcomm%d", dev); |
|
|
|
540 while ((fd = open(devname, O_RDONLY | O_NOCTTY)) < 0) { |
|
|
|
541 if (errno == EACCES) { |
|
|
|
542 perror("Can't open RFCOMM device"); |
|
|
|
543 goto release; |
|
|
|
544 } |
|
|
|
545 |
|
|
|
546 snprintf(devname, MAXPATHLEN - 1, "/dev/bluetooth/rfcomm/%d", dev); |
|
|
|
547 if ((fd = open(devname, O_RDONLY | O_NOCTTY)) < 0) { |
|
|
|
548 if (try--) { |
|
|
|
549 snprintf(devname, MAXPATHLEN - 1, "/dev/rfcomm%d", dev); |
|
|
|
550 usleep(100 * 1000); |
|
|
|
551 continue; |
|
|
|
552 } |
|
|
|
553 perror("Can't open RFCOMM device"); |
|
|
|
554 goto release; |
|
|
|
555 } |
|
|
|
556 } |
|
|
|
557 |
|
|
|
558 if (rfcomm_raw_tty) { |
|
|
|
559 tcflush(fd, TCIOFLUSH); |
|
|
|
560 |
|
|
|
561 cfmakeraw(&ti); |
|
|
|
562 tcsetattr(fd, TCSANOW, &ti); |
|
|
|
563 } |
|
|
|
564 |
|
|
|
565 ba2str(&req.dst, dst); |
|
|
|
566 debug("Connection from %s to %s\n", dst, devname); |
|
|
|
567 |
|
|
|
568 /* Replace all occurences of '{}' with the rfcomm device path. */ |
|
|
|
569 asprintf(&oldcmd, "%s", runcmd); |
|
|
|
570 while ((replace = strstr(oldcmd, "{}"))) { |
|
|
|
571 replace[0] = '%'; |
|
|
|
572 replace[1] = 's'; |
|
|
|
573 asprintf(&cmd, oldcmd, devname); |
|
|
|
574 free(oldcmd); |
|
|
|
575 oldcmd = cmd; |
|
|
|
576 } |
|
|
|
577 |
|
|
|
578 debug("Executing %s\n", cmd); |
|
|
|
579 |
|
|
|
580 system(cmd); |
|
|
|
581 free(cmd); |
|
|
|
582 |
|
|
|
583 close(fd); |
|
|
|
584 close(nsk); |
|
|
|
585 release: |
|
|
|
586 memset(&req, 0, sizeof(req)); |
|
|
|
587 req.dev_id = dev; |
|
|
|
588 req.flags = (1 << RFCOMM_HANGUP_NOW); |
|
|
|
589 ioctl(ctl, RFCOMMRELEASEDEV, &req); |
|
|
|
590 } |
|
|
|
591 |
|
|
|
592 close(sk); |
|
|
|
593 |
|
|
|
594 return 0; |
|
|
|
595 } |
|
|
|
596 |
|