Exemple #1
0
static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
{
	struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
	struct sock *sk = sock->sk;
	int err = 0;


	BT_DBG("sk %p", sk);

	if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_sco))
		return -EINVAL;

	if (sk->state != BT_OPEN && sk->state != BT_BOUND)
		return -EBADFD;

	if (sk->type != SOCK_SEQPACKET)
		return -EINVAL;

	lock_sock(sk);

	/* Set destination address and psm */
	bacpy(&bluez_pi(sk)->dst, &sa->sco_bdaddr);

	if ((err = sco_connect(sk)))
		goto done;

	err = bluez_sock_wait_state(sk, BT_CONNECTED,
			sock_sndtimeo(sk, flags & O_NONBLOCK));

done:
	release_sock(sk);
	return err;
}
Exemple #2
0
static int headset_button(struct s_headset *headset)
{
	uint16_t sco_handle, sco_mtu;

	if (headset == NULL)
		return 0;
	if (headset->sco_fd != -1) {
		/* close bt_sco audio handle */
		bt_sco_set_fd(headset->handle, -1);
		/* disconnect SCO stream */
		close(headset->sco_fd);
		headset->sco_fd = -1;
		fprintf(stderr, "disconnected SCO channel\n");
		return 1;
	}
	fprintf(stderr, "opened hwdep\n");
	/* connect sco stream */
	if ((headset->sco_fd = sco_connect(&headset->local, &headset->bdaddr, &sco_handle, &sco_mtu)) < 0) {
		perror("Can't connect SCO audio channel");
		return 1;
	}
	fprintf(stderr, "connected SCO channel\n");
	//      write(rd, "RING\r\n", 6);
	fprintf(stderr, "Setting sco fd\n"); 
	bt_sco_set_fd (headset->handle, headset->sco_fd);
	fprintf(stderr, "Done setting sco fd\n"); 
	return 1;
}
Exemple #3
0
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);
}
Exemple #4
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;
}
Exemple #5
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)
 * ctl is optional mbuf chain containing socket options
 * l is pointer to process requesting action (if any)
 *
 * we are responsible for disposing of m and ctl if
 * they are mbuf chains
 */
static int
sco_usrreq(struct socket *up, int req, struct mbuf *m,
    struct mbuf *nam, struct mbuf *ctl, struct lwp *l)
{
	struct sco_pcb *pcb = (struct sco_pcb *)up->so_pcb;
	struct sockaddr_bt *sa;
	struct mbuf *m0;
	int err = 0;

	DPRINTFN(2, "%s\n", prurequests[req]);
	KASSERT(req != PRU_ATTACH);
	KASSERT(req != PRU_DETACH);

	switch(req) {
	case PRU_CONTROL:
		return EOPNOTSUPP;

	case PRU_PURGEIF:
		return EOPNOTSUPP;
	}

	/* anything after here *requires* a pcb */
	if (pcb == NULL) {
		err = EINVAL;
		goto release;
	}

	switch(req) {
	case PRU_DISCONNECT:
		soisdisconnecting(up);
		return sco_disconnect(pcb, up->so_linger);

	case PRU_ABORT:
		sco_disconnect(pcb, 0);
		soisdisconnected(up);
		sco_detach(up);
		return 0;

	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 sco_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 sco_connect(pcb, sa);

	case PRU_PEERADDR:
		KASSERT(nam != NULL);
		sa = mtod(nam, struct sockaddr_bt *);
		nam->m_len = sizeof(struct sockaddr_bt);
		return sco_peeraddr(pcb, sa);

	case PRU_SOCKADDR:
		KASSERT(nam != NULL);
		sa = mtod(nam, struct sockaddr_bt *);
		nam->m_len = sizeof(struct sockaddr_bt);
		return sco_sockaddr(pcb, sa);

	case PRU_SHUTDOWN:
		socantsendmore(up);
		break;

	case PRU_SEND:
		KASSERT(m != NULL);
		if (m->m_pkthdr.len == 0)
			break;

		if (m->m_pkthdr.len > pcb->sp_mtu) {
			err = EMSGSIZE;
			break;
		}

		m0 = m_copypacket(m, M_DONTWAIT);
		if (m0 == NULL) {
			err = ENOMEM;
			break;
		}

		if (ctl) /* no use for that */
			m_freem(ctl);

		sbappendrecord(&up->so_snd, m);
		return sco_send(pcb, m0);

	case PRU_SENSE:
		return 0;		/* (no sense - Doh!) */

	case PRU_RCVD:
	case PRU_RCVOOB:
		return EOPNOTSUPP;	/* (no release) */

	case PRU_LISTEN:
		return sco_listen(pcb);

	case PRU_ACCEPT:
		KASSERT(nam != NULL);
		sa = mtod(nam, struct sockaddr_bt *);
		nam->m_len = sizeof(struct sockaddr_bt);
		return sco_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;
}
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;
}