void epox_presenter(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel) { unsigned char buf[16]; struct sigaction sa; struct pollfd p; char addr[18]; int i, fd, sk, len; sk = rfcomm_connect(src, dst, channel); if (sk < 0) return; fd = uinput_create("Bluetooth Presenter", 0, 1); if (fd < 0) { close(sk); return; } ba2str(dst, addr); printf("Connected to %s on channel %d\n", addr, channel); printf("Press CTRL-C for hangup\n"); memset(&sa, 0, sizeof(sa)); sa.sa_flags = SA_NOCLDSTOP; sa.sa_handler = SIG_IGN; sigaction(SIGCHLD, &sa, NULL); sigaction(SIGPIPE, &sa, NULL); sa.sa_handler = sig_term; sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); sa.sa_handler = sig_hup; sigaction(SIGHUP, &sa, NULL); p.fd = sk; p.events = POLLIN | POLLERR | POLLHUP; while (!__io_canceled) { p.revents = 0; if (poll(&p, 1, 100) < 1) continue; len = read(sk, buf, sizeof(buf)); if (len < 0) break; for (i = 0; i < len; i++) epox_decode(fd, buf[i]); } printf("Disconnected\n"); ioctl(fd, UI_DEV_DESTROY); close(fd); close(sk); }
int main(int argc, char *argv[]) { GOptionContext *context; context = g_option_context_new(NULL); g_option_context_add_main_entries(context, options, NULL); if (!g_option_context_parse(context, &argc, &argv, NULL)) exit(EXIT_FAILURE); g_option_context_free(context); printf("accept=%d reject=%d discon=%d defer=%d sec=%d update_sec=%d" " prio=%d voice=0x%04x\n", opt_accept, opt_reject, opt_disconn, opt_defer, opt_sec, opt_update_sec, opt_priority, opt_voice); if (opt_psm || opt_cid) { if (argc > 1) l2cap_connect(opt_dev, argv[1], opt_addr_type, opt_psm, opt_cid, opt_disconn, opt_sec, opt_priority); else l2cap_listen(opt_dev, opt_addr_type, opt_psm, opt_cid, opt_defer, opt_reject, opt_disconn, opt_accept, opt_sec, opt_master); } if (opt_channel != -1) { if (argc > 1) rfcomm_connect(opt_dev, argv[1], opt_channel, opt_disconn, opt_sec); else rfcomm_listen(opt_dev, opt_channel, opt_defer, opt_reject, opt_disconn, opt_accept, opt_sec, opt_master); } if (opt_sco) { if (argc > 1) sco_connect(opt_dev, argv[1], opt_disconn, opt_voice); else sco_listen(opt_dev, opt_defer, opt_reject, opt_disconn, opt_accept, opt_voice); } signal(SIGTERM, sig_term); signal(SIGINT, sig_term); main_loop = g_main_loop_new(NULL, FALSE); g_main_loop_run(main_loop); g_main_loop_unref(main_loop); printf("Exiting\n"); exit(EXIT_SUCCESS); }
bool rfcomm_repeated_connect() { static const int max_iterations = 128; for (int i = 0; i < max_iterations; ++i) { TASSERT(rfcomm_connect(), "Connection failed on attempt %d/%d", i, max_iterations); } return true; }
/* * l2cap_connected(): * * Called by L2CAP when a connection response was received. * Sends a L2CAP configuration request. * Initializes a search for other devices if the connection attempt failed. */ err_t l2cap_connected(void *arg, struct l2cap_pcb *l2cappcb, u16_t result, u16_t status) { struct sdp_pcb *sdppcb; struct rfcomm_pcb *rfcommpcb; u8_t ssp[] = {0x35, 0x03, 0x19, 0x11, 0x02}; /* Service search pattern with LAP UUID is default */ err_t ret; u8_t attrids[] = {0x35, 0x03, 0x09, 0x00, 0x04}; /* Attribute IDs to search for in data element sequence form */ if(result == L2CAP_CONN_SUCCESS) { LWIP_DEBUGF(BT_SPP_DEBUG, ("l2cap_connected: L2CAP connected pcb->state = %d\n", l2cappcb->state)); /* Tell L2CAP that we wish to be informed of a disconnection request */ l2cap_disconnect_ind(l2cappcb, l2cap_disconnected_ind); switch(l2cap_psm(l2cappcb)) { case SDP_PSM: LWIP_DEBUGF(BT_SPP_DEBUG, ("l2cap_connected: SDP L2CAP configured. Result = %d\n", result)); if((sdppcb = sdp_new(l2cappcb)) == NULL) { LWIP_DEBUGF(BT_SPP_DEBUG, ("l2cap_connected: Failed to create a SDP PCB\n")); return ERR_MEM; } l2cap_recv(l2cappcb, sdp_recv); ret = sdp_service_search_attrib_req(sdppcb, 0xFFFF, ssp, sizeof(ssp), attrids, sizeof(attrids), sdp_attributes_recv); return ret; case RFCOMM_PSM: LWIP_DEBUGF(BT_SPP_DEBUG, ("l2cap_connected: RFCOMM L2CAP configured. Result = %d CN = %d\n", result, bt_spp_state.cn)); l2cap_recv(l2cappcb, rfcomm_input); if((rfcommpcb = rfcomm_new(l2cappcb)) == NULL) { LWIP_DEBUGF(BT_SPP_DEBUG, ("l2cap_connected: Failed to create a RFCOMM PCB\n")); return ERR_MEM; } hci_link_key_not(link_key_not); /* Set function to be called if a new link key is created */ return rfcomm_connect(rfcommpcb, bt_spp_state.cn, rfcomm_connected); /* Connect with DLCI 0 */ default: return ERR_VAL; } } else { LWIP_DEBUGF(BT_SPP_DEBUG, ("l2cap_connected: L2CAP not connected. Redo inquiry\n")); l2cap_close(l2cappcb); bt_spp_start(); } return ERR_OK; }
static GIOChannel *bluetooth_connect(GObexTransportType transport) { GIOChannel *io; GError *err = NULL; if (option_dest == NULL || option_channel < 0) return NULL; if (option_channel > 31) io = l2cap_connect(transport, &err); else io = rfcomm_connect(transport, &err); if (io != NULL) return io; g_printerr("%s\n", err->message); g_error_free(err); return NULL; }
static int session_connect(struct obc_session *session, struct callback_data *callback) { int err; if (session->obex) { g_idle_add(connection_complete, callback); err = 0; } else if (session->channel > 0) { session->io = rfcomm_connect(&session->src, &session->dst, session->channel, rfcomm_callback, callback); err = (session->io == NULL) ? -EINVAL : 0; } else { callback->sdp = service_connect(&session->src, &session->dst, service_callback, callback); err = (callback->sdp == NULL) ? -ENOMEM : 0; } return err; }
int main(int argc, char *argv[]) { int dev; int card; struct sigaction sa; #ifdef TEST int rlen; #endif int bt_dev = 0; struct pollfd pfds[16]; int err; char hwdep_name[16]; struct s_headset *akt_headset; atexit(cleanup); /* detect the audio device */ if (find_hwdep_device(&card, &dev)) { perror("Can't find device. Bail"); return 1; } printf("Device is %d:%d\n", card, dev); sprintf(hwdep_name, "hw:%i,%i", card, dev); if (check_bt_voice(bt_dev) < 0) return -1; /* find bdaddr */ switch (argc) { case 2: akt_headset = headset_new(); hci_devba(bt_dev, &akt_headset->local); str2ba(argv[1], &akt_headset->bdaddr); akt_headset->channel = detect_channel(&akt_headset->bdaddr); /* open hwdep on audio device */ if ((err = snd_hwdep_open(&akt_headset->handle, hwdep_name, O_RDWR)) < 0) { fprintf(stderr, "btsco open (%i-%i): %s\n", card, dev, snd_strerror(err)); return -1; } break; case 3: akt_headset = headset_new(); hci_devba(bt_dev, &akt_headset->local); str2ba(argv[1], &akt_headset->bdaddr); akt_headset->channel = atoi(argv[2]); /* open hwdep on audio device */ if ((err = snd_hwdep_open(&akt_headset->handle, hwdep_name, O_RDWR)) < 0) { fprintf(stderr, "btsco open (%i-%i): %s\n", card, dev, snd_strerror(err)); return -1; } break; default: usage(); exit(-1); } /* setup sigterm handler. we must make sure to do a clean disconnect */ memset(&sa, 0, sizeof(sa)); sa.sa_flags = SA_NOCLDSTOP; sa.sa_handler = sig_term; sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); sa.sa_handler = SIG_IGN; sigaction(SIGCHLD, &sa, NULL); sigaction(SIGPIPE, &sa, NULL); /* we are not yet connected */ while (!terminate) { unsigned short revents; int nfds; nfds = 0; /* set up data polling description */ for (akt_headset = first; akt_headset != NULL; akt_headset = akt_headset->next) { if (akt_headset->rfcomm_fd == -1) { /* connect rfcomm control channel */ if ((akt_headset->rfcomm_fd = rfcomm_connect( &akt_headset->local, &akt_headset->bdaddr, akt_headset->channel)) < 0) fprintf(stderr, "Can't connect RFCOMM channel"); else fprintf(stderr, "RFCOMM channel %i connected\n", akt_headset->channel); } if (akt_headset->rfcomm_fd != -1) { pfds[nfds].fd = akt_headset->rfcomm_fd; pfds[nfds++].events = POLLIN; } if (akt_headset->handle != NULL) { /* polling data from hwdep interface */ nfds += snd_hwdep_poll_descriptors(akt_headset->handle, &pfds[nfds], 1); } } /*printf("outer loop\n"); */ if (nfds == 0) { sleep(3); continue; } if (poll(pfds, nfds, 1000) <= 0) continue; for (akt_headset = first; akt_headset != NULL; akt_headset = akt_headset->next) { int j; for (j = 0; j < nfds; j++) { if (pfds[j].fd == akt_headset->rfcomm_fd) { if (pfds[j].revents & POLLIN) headset_from_bt(akt_headset); continue; } #ifdef TEST if (pfds[j].fd == akt_headset->sco_fd) { /* Just for testing; handled by kernel driver */ fd_set rfds; if (0 && FD_ISSET(akt_headset->sco_fd, &rfds)) { int i; unsigned char buf[2048]; memset(buf, 0, sizeof(buf)); rlen = read(akt_headset->sco_fd, buf, sizeof(buf)); write(akt_headset->sco_fd, buf, rlen); i++; if (i % 15 == 0) printf("rlen: %d\n", rlen); } continue; } #endif /* Volume polling (sound card) */ if (!snd_hwdep_poll_descriptors_revents (akt_headset->handle, &pfds[j], 1, &revents) && revents & POLLIN) headset_volume_fromcard (akt_headset); } } } return 0; }
int main(int argc, char *argv[]) { struct sigaction sa; fd_set rfds; struct timeval timeout; unsigned char buf[2048], *p; int maxfd, sel, rlen, wlen; bdaddr_t local; bdaddr_t bdaddr; uint8_t channel; char *filename; mode_t filemode; int err, mode = 0; int dd, rd, sd, fd; uint16_t sco_handle, sco_mtu, vs; switch (argc) { case 4: str2ba(argv[3], &bdaddr); channel = 6; break; case 5: str2ba(argv[3], &bdaddr); channel = atoi(argv[4]); break; default: usage(); exit(-1); } if (strncmp(argv[1], "play", 4) == 0) { mode = PLAY; filemode = O_RDONLY; } else if (strncmp(argv[1], "rec", 3) == 0) { mode = RECORD; filemode = O_WRONLY | O_CREAT | O_TRUNC; } else { usage(); exit(-1); } filename = argv[2]; hci_devba(0, &local); dd = hci_open_dev(0); hci_read_voice_setting(dd, &vs, 1000); vs = htobs(vs); fprintf(stderr, "Voice setting: 0x%04x\n", vs); close(dd); if (vs != 0x0060) { fprintf(stderr, "The voice setting must be 0x0060\n"); return -1; } if (strcmp(filename, "-") == 0) { switch (mode) { case PLAY: fd = 0; break; case RECORD: fd = 1; break; default: return -1; } } else { if ((fd = open(filename, filemode)) < 0) { perror("Can't open input/output file"); return -1; } } memset(&sa, 0, sizeof(sa)); sa.sa_flags = SA_NOCLDSTOP; sa.sa_handler = sig_term; sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); sa.sa_handler = SIG_IGN; sigaction(SIGCHLD, &sa, NULL); sigaction(SIGPIPE, &sa, NULL); if ((rd = rfcomm_connect(&local, &bdaddr, channel)) < 0) { perror("Can't connect RFCOMM channel"); return -1; } fprintf(stderr, "RFCOMM channel connected\n"); if ((sd = sco_connect(&local, &bdaddr, &sco_handle, &sco_mtu)) < 0) { perror("Can't connect SCO audio channel"); close(rd); return -1; } fprintf(stderr, "SCO audio channel connected (handle %d, mtu %d)\n", sco_handle, sco_mtu); if (mode == RECORD) err = write(rd, "RING\r\n", 6); maxfd = (rd > sd) ? rd : sd; while (!terminate) { FD_ZERO(&rfds); FD_SET(rd, &rfds); FD_SET(sd, &rfds); timeout.tv_sec = 0; timeout.tv_usec = 10000; if ((sel = select(maxfd + 1, &rfds, NULL, NULL, &timeout)) > 0) { if (FD_ISSET(rd, &rfds)) { memset(buf, 0, sizeof(buf)); rlen = read(rd, buf, sizeof(buf)); if (rlen > 0) { fprintf(stderr, "%s\n", buf); wlen = write(rd, "OK\r\n", 4); } } if (FD_ISSET(sd, &rfds)) { memset(buf, 0, sizeof(buf)); rlen = read(sd, buf, sizeof(buf)); if (rlen > 0) switch (mode) { case PLAY: rlen = read(fd, buf, rlen); wlen = 0; p = buf; while (rlen > sco_mtu) { wlen += write(sd, p, sco_mtu); rlen -= sco_mtu; p += sco_mtu; } wlen += write(sd, p, rlen); break; case RECORD: wlen = write(fd, buf, rlen); break; default: break; } } } } close(sd); sleep(5); close(rd); close(fd); return 0; }
/* * User Request. * up is socket * m is either * optional mbuf chain containing message * ioctl command (PRU_CONTROL) * nam is either * optional mbuf chain containing an address * ioctl data (PRU_CONTROL) * optionally protocol number (PRU_ATTACH) * message flags (PRU_RCVD) * ctl is either * optional mbuf chain containing socket options * optional interface pointer (PRU_CONTROL, PRU_PURGEIF) * l is pointer to process requesting action (if any) * * we are responsible for disposing of m and ctl if * they are mbuf chains */ int rfcomm_usrreq(struct socket *up, int req, struct mbuf *m, struct mbuf *nam, struct mbuf *ctl, struct lwp *l) { struct rfcomm_dlc *pcb = up->so_pcb; struct sockaddr_bt *sa; struct mbuf *m0; int err = 0; DPRINTFN(2, "%s\n", prurequests[req]); switch (req) { case PRU_CONTROL: return EPASSTHROUGH; case PRU_PURGEIF: return EOPNOTSUPP; case PRU_ATTACH: if (up->so_lock == NULL) { mutex_obj_hold(bt_lock); up->so_lock = bt_lock; solock(up); } KASSERT(solocked(up)); if (pcb != NULL) return EINVAL; /* * Since we have nothing to add, we attach the DLC * structure directly to our PCB pointer. */ err = soreserve(up, rfcomm_sendspace, rfcomm_recvspace); if (err) return err; err = rfcomm_attach((struct rfcomm_dlc **)&up->so_pcb, &rfcomm_proto, up); if (err) return err; err = rfcomm_rcvd(up->so_pcb, sbspace(&up->so_rcv)); if (err) { rfcomm_detach((struct rfcomm_dlc **)&up->so_pcb); return err; } return 0; } if (pcb == NULL) { err = EINVAL; goto release; } switch(req) { case PRU_DISCONNECT: soisdisconnecting(up); return rfcomm_disconnect(pcb, up->so_linger); case PRU_ABORT: rfcomm_disconnect(pcb, 0); soisdisconnected(up); /* fall through to */ case PRU_DETACH: return rfcomm_detach((struct rfcomm_dlc **)&up->so_pcb); case PRU_BIND: KASSERT(nam != NULL); sa = mtod(nam, struct sockaddr_bt *); if (sa->bt_len != sizeof(struct sockaddr_bt)) return EINVAL; if (sa->bt_family != AF_BLUETOOTH) return EAFNOSUPPORT; return rfcomm_bind(pcb, sa); case PRU_CONNECT: KASSERT(nam != NULL); sa = mtod(nam, struct sockaddr_bt *); if (sa->bt_len != sizeof(struct sockaddr_bt)) return EINVAL; if (sa->bt_family != AF_BLUETOOTH) return EAFNOSUPPORT; soisconnecting(up); return rfcomm_connect(pcb, sa); case PRU_PEERADDR: KASSERT(nam != NULL); sa = mtod(nam, struct sockaddr_bt *); nam->m_len = sizeof(struct sockaddr_bt); return rfcomm_peeraddr(pcb, sa); case PRU_SOCKADDR: KASSERT(nam != NULL); sa = mtod(nam, struct sockaddr_bt *); nam->m_len = sizeof(struct sockaddr_bt); return rfcomm_sockaddr(pcb, sa); case PRU_SHUTDOWN: socantsendmore(up); break; case PRU_SEND: KASSERT(m != NULL); if (ctl) /* no use for that */ m_freem(ctl); m0 = m_copypacket(m, M_DONTWAIT); if (m0 == NULL) return ENOMEM; sbappendstream(&up->so_snd, m); return rfcomm_send(pcb, m0); case PRU_SENSE: return 0; /* (no release) */ case PRU_RCVD: return rfcomm_rcvd(pcb, sbspace(&up->so_rcv)); case PRU_RCVOOB: return EOPNOTSUPP; /* (no release) */ case PRU_LISTEN: return rfcomm_listen(pcb); case PRU_ACCEPT: KASSERT(nam != NULL); sa = mtod(nam, struct sockaddr_bt *); nam->m_len = sizeof(struct sockaddr_bt); return rfcomm_peeraddr(pcb, sa); case PRU_CONNECT2: case PRU_SENDOOB: case PRU_FASTTIMO: case PRU_SLOWTIMO: case PRU_PROTORCV: case PRU_PROTOSEND: err = EOPNOTSUPP; break; default: UNKNOWN(req); err = EOPNOTSUPP; break; } release: if (m) m_freem(m); if (ctl) m_freem(ctl); return err; }
struct session_data *session_create(const char *source, const char *destination, const char *target, uint8_t channel, session_callback_t function, void *user_data) { struct session_data *session; struct callback_data *callback; int err; if (destination == NULL) return NULL; session = g_try_malloc0(sizeof(*session)); if (session == NULL) return NULL; session->refcount = 1; session->channel = channel; session->conn = dbus_bus_get(DBUS_BUS_SESSION, NULL); if (session->conn == NULL) { session_free(session); return NULL; } if (source == NULL) bacpy(&session->src, BDADDR_ANY); else str2ba(source, &session->src); str2ba(destination, &session->dst); if (!g_ascii_strncasecmp(target, "OPP", 3)) { sdp_uuid16_create(&session->uuid, OBEX_OBJPUSH_SVCLASS_ID); } else if (!g_ascii_strncasecmp(target, "FTP", 3)) { sdp_uuid16_create(&session->uuid, OBEX_FILETRANS_SVCLASS_ID); session->target = OBEX_FTP_UUID; session->target_len = OBEX_FTP_UUID_LEN; } else if (!g_ascii_strncasecmp(target, "PBAP", 4)) { sdp_uuid16_create(&session->uuid, PBAP_PSE_SVCLASS_ID); session->target = OBEX_PBAP_UUID; session->target_len = OBEX_PBAP_UUID_LEN; } else if (!g_ascii_strncasecmp(target, "SYNC", 4)) { sdp_uuid16_create(&session->uuid, IRMC_SYNC_SVCLASS_ID); session->target = OBEX_SYNC_UUID; session->target_len = OBEX_SYNC_UUID_LEN; } else if (!g_ascii_strncasecmp(target, "PCSUITE", 7)) { sdp_uuid128_create(&session->uuid, pcsuite_uuid); } else { return NULL; } callback = g_try_malloc0(sizeof(*callback)); if (callback == NULL) { session_free(session); return NULL; } callback->session = session_ref(session); callback->func = function; callback->data = user_data; if (session->channel > 0) { session->io = rfcomm_connect(&session->src, &session->dst, session->channel, rfcomm_callback, callback); err = (session->io == NULL) ? -EINVAL : 0; } else { callback->sdp = service_connect(&session->src, &session->dst, service_callback, callback); err = (callback->sdp == NULL) ? -ENOMEM : 0; } if (err < 0) { session_free(session); g_free(callback); return NULL; } return session; }
static void search_callback(uint8_t type, uint16_t status, uint8_t *rsp, size_t size, void *user_data) { struct callback_data *callback = user_data; unsigned int scanned, bytesleft = size; int seqlen = 0; uint8_t dataType, channel = 0; GError *gerr = NULL; if (status || type != SDP_SVC_SEARCH_ATTR_RSP) goto failed; scanned = sdp_extract_seqtype(rsp, bytesleft, &dataType, &seqlen); if (!scanned || !seqlen) goto failed; rsp += scanned; bytesleft -= scanned; do { sdp_record_t *rec; sdp_list_t *protos; int recsize, ch = -1; recsize = 0; rec = sdp_extract_pdu(rsp, bytesleft, &recsize); if (!rec) break; if (!recsize) { sdp_record_free(rec); break; } if (!sdp_get_access_protos(rec, &protos)) { ch = sdp_get_proto_port(protos, RFCOMM_UUID); sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL); sdp_list_free(protos, NULL); protos = NULL; } sdp_record_free(rec); if (ch > 0) { channel = ch; break; } scanned += recsize; rsp += recsize; bytesleft -= recsize; } while (scanned < size && bytesleft > 0); if (channel == 0) goto failed; callback->session->channel = channel; callback->session->io = rfcomm_connect(&callback->session->src, &callback->session->dst, channel, rfcomm_callback, callback); if (callback->session->io != NULL) { sdp_close(callback->sdp); return; } failed: sdp_close(callback->sdp); g_set_error(&gerr, OBEX_IO_ERROR, -EIO, "Unable to find service record"); callback->func(callback->session, gerr, callback->data); g_clear_error(&gerr); session_unref(callback->session); g_free(callback); }
int celluon_keyboard(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel) { unsigned char buf[16]; struct sigaction sa; struct pollfd p; sigset_t sigs; char addr[18]; int i, fd, sk, len; struct celluon_state s; sk = rfcomm_connect(src, dst, channel); if (sk < 0) return -1; fd = uinput_create("Celluon Keyboard", 1, 0); if (fd < 0) { close(sk); return -1; } ba2str(dst, addr); printf("Connected to %s on channel %d\n", addr, channel); printf("Press CTRL-C for hangup\n"); memset(&sa, 0, sizeof(sa)); sa.sa_flags = SA_NOCLDSTOP; sa.sa_handler = SIG_IGN; sigaction(SIGCHLD, &sa, NULL); sigaction(SIGPIPE, &sa, NULL); sa.sa_handler = sig_term; sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); sa.sa_handler = sig_hup; sigaction(SIGHUP, &sa, NULL); sigfillset(&sigs); sigdelset(&sigs, SIGCHLD); sigdelset(&sigs, SIGPIPE); sigdelset(&sigs, SIGTERM); sigdelset(&sigs, SIGINT); sigdelset(&sigs, SIGHUP); p.fd = sk; p.events = POLLIN | POLLERR | POLLHUP; memset(&s, 0, sizeof(s)); while (!__io_canceled) { p.revents = 0; if (ppoll(&p, 1, NULL, &sigs) < 1) continue; len = read(sk, buf, sizeof(buf)); if (len < 0) break; for (i = 0; i < len; i++) celluon_decode(fd, &s, buf[i]); } printf("Disconnected\n"); ioctl(fd, UI_DEV_DESTROY); close(fd); close(sk); return 0; }
int main(int argc, char *argv[]) { struct sigaction sa; fd_set rfds; struct timeval timeout; unsigned char buf[2048], *p; unsigned char cmp[2048]; int maxfd, sel, wlen, rlen; int cnt=0; bdaddr_t local; bdaddr_t bdaddr; uint8_t channel; uint8_t hcidevno; char *infilename; char *outfilename; mode_t infilemode; mode_t outfilemode; int scostarted=0; int mode = 0; int dd, rd, sd, fdi, fdo; uint16_t sco_handle, sco_mtu, vs; switch (argc) { case 5: str2ba(argv[4], &bdaddr); channel = 1; hcidevno = 0; break; case 6: str2ba(argv[4], &bdaddr); channel = atoi(argv[5]); hcidevno = atoi(argv[1]); break; default: usage(); exit(-1); } infilemode = O_RDONLY; outfilemode = O_WRONLY | O_CREAT | O_TRUNC; infilename = argv[2]; outfilename = argv[3]; hci_devba(0, &local); dd = hci_open_dev(hcidevno); hci_read_voice_setting(dd, &vs, 1000); vs = htobs(vs); printf("Voice setting: 0x%04x\n", vs); close(dd); if (vs != 0x0060) { perror("The voice setting must be 0x0060!\n"); return -1; } // Hack by KF to enable realtime audio eavesdropping. Use stdout and pipe to sox. (see usage) if(strcmp(outfilename,"-") == 0) { printf("Using stdout!"); fdo = 1; } else { if ((fdo = open(outfilename, outfilemode)) < 0) { perror("Can't open output file!"); return -1; } } if ((fdi = open(infilename, infilemode)) < 0) { perror("Can't open input file!"); return -1; } memset(&sa, 0, sizeof(sa)); sa.sa_flags = SA_NOCLDSTOP; sa.sa_handler = sig_term; sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); sa.sa_handler = SIG_IGN; sigaction(SIGCHLD, &sa, NULL); sigaction(SIGPIPE, &sa, NULL); if ((rd = rfcomm_connect(&local, &bdaddr, channel)) < 0) { perror("Can't connect RFCOMM channel!"); return -1; } printf("RFCOMM channel connected\n"); // It is important that the RING message is sent before the SCO connection is established. // This way, the audio sent is interpreted as in-band ringtone and is displayed in most cases // immediately. // send 'RING' message in order to initiate fake phone call wlen = write(rd, "RING\r\n", 6); usleep(1000); if ((sd = sco_connect(&local, &bdaddr, &sco_handle, &sco_mtu)) < 0) { perror("Can't connect SCO audio channel!"); close(rd); return -1; } printf("SCO audio channel connected (handle %d, mtu %d)\n", sco_handle, sco_mtu); // wait for connection to be fully established // usleep(200); // turn up the speaker volume and the microphone gain to the highest level wlen = write(rd, "AT+VGS=15\r\n", 11); wlen = write(rd, "AT+VGM=15\r\n", 11); // send 'RING' message in order to initiate fake phone call wlen = write(rd, "RING\r\n", 6); maxfd = (rd > sd) ? rd : sd; while (!terminate) { FD_ZERO(&rfds); FD_SET(rd, &rfds); FD_SET(sd, &rfds); timeout.tv_sec = 2; timeout.tv_usec = 0; if ((sel = select(maxfd + 1, &rfds, NULL, NULL, &timeout)) > 0) { if ((FD_ISSET(rd, &rfds))&&(scostarted!=0)) { memset(buf, 0, sizeof(buf)); rlen = read(rd, buf, sizeof(buf)); //buf[rlen++] = '\0'; if (rlen > 0) { fprintf(stderr, "got: %s\n",buf); if (strncmp(buf, "AT+BRSF=",8)==0) { wlen=write(rd,"+BRSF: 63\r\n",11); fprintf(stderr, "ansewered: +BRSF: 63\n"); } else if (strncmp(buf, "AT+CIND?",8)==0) { wlen=write(rd,"+CIND: 0,1,0,0\r\n",16); fprintf(stderr, "ansewered: +CIND: 1\n"); } else if (strncmp(buf, "AT+CIND=?",9)==0) { wlen=write(rd,"+CIND: (\"call\",(0,1)),(\"service\",(0,1)),(\"call_setup\",(0-3)),(\"callsetup\",(0-3))\r\n",82); fprintf(stderr, "ansewered: +CIND: (\"call\",(0,1)),(\"service\",(0,1)),(\"call_setup\",(0-3)),(\"callsetup\",(0-3))\n"); } else { // answer to anything else with an 'OK' wlen = write(rd, "OK\r\n", 4); fprintf(stderr, "ansewered: OK\n"); } } else { // check return value of read call if (rlen==-1) { // terminate loop wlen = write(rd, "AT+VGM=15\r\n", 11); terminate=1; } } } if (FD_ISSET(sd, &rfds)) { scostarted=1; memset(buf, 0, sizeof(buf)); rlen = read(sd, buf, sizeof(buf)); if (rlen > 0) { wlen = write(fdo, buf, rlen); rlen = read(fdi, buf, rlen); wlen = 0; if (rlen > 0) p = buf; while (rlen > sco_mtu) { wlen += write(sd, p, sco_mtu); rlen -= sco_mtu; p += sco_mtu; } wlen += write(sd, p, rlen); } } if (cnt++>800) { // keep tuning up the volume for speaker and microphone wlen = write(rd, "RING\r\n", 6); wlen = write(rd, "AT+VGS=15\r\n", 11); wlen = write(rd, "AT+VGM=15\r\n", 11); cnt=0; printf(".\n"); } } } // close sockets close(sd); close(rd); // close files close(fdi); close(fdo); return 0; }