Exemplo n.º 1
0
static int
hostmode(char const *arg, int brief)
{
	struct hostent	*he = NULL;
	bdaddr_t	 ba;
	char		 bastr[32];
	int		 reverse;

	if (bt_aton(arg, &ba) == 1) {
		reverse = 1;
		he = bt_gethostbyaddr((char const *) &ba, sizeof(ba), 
					AF_BLUETOOTH);
	} else {
		reverse = 0;
		he = bt_gethostbyname(arg);
	}

	if (he == NULL) {
		herror(reverse? bt_ntoa(&ba, bastr) : arg);
		return (1);
	}

	if (brief)
		printf("%s", reverse? he->h_name :
				bt_ntoa((bdaddr_t *)(he->h_addr), bastr));
	else
		printf("Host %s has %s %s\n", 
			reverse? bt_ntoa(&ba, bastr) : arg,
			reverse? "name" : "address",
			reverse? he->h_name :
				bt_ntoa((bdaddr_t *)(he->h_addr), bastr));

	return (0);
}
Exemplo n.º 2
0
int
main(int argc, char *argv[])
{
	bdaddr_t	bdaddr;
	int		opt;

	hid_init(NULL);
	memcpy(&bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr));

	while ((opt = getopt(argc, argv, "a:c:H:hv")) != -1) {
		switch (opt) {
		case 'a': /* bdaddr */
			if (!bt_aton(optarg, &bdaddr)) {
				struct hostent  *he = NULL;

				if ((he = bt_gethostbyname(optarg)) == NULL)
					errx(1, "%s: %s", optarg, hstrerror(h_errno));

				memcpy(&bdaddr, he->h_addr, sizeof(bdaddr));
			}
			break;

		case 'c': /* config file */
			config_file = optarg;
			break;

		case 'H': /* HIDs file */
			hids_file = optarg;
			break;

		case 'v': /* verbose */
			verbose++;
			break;

		case 'h':
		default:
			usage();
			/* NOT REACHED */
		}
	}

	argc -= optind;
	argv += optind;

	if (*argv == NULL)
		usage();

	return (do_bthid_command(&bdaddr, argc, argv));
} /* main */
Exemplo n.º 3
0
/* Main */
int
main(int argc, char *argv[])
{
	char const	*control = SDP_LOCAL_PATH;
	int		 n, local;
	bdaddr_t	 bdaddr;

	memset(&bdaddr, 0, sizeof(bdaddr));
	local = 0;

	/* Process command line arguments */
	while ((n = getopt(argc, argv, "a:c:lh")) != -1) {
		switch (n) {
		case 'a': /* bdaddr */
			if (!bt_aton(optarg, &bdaddr)) {
				struct hostent  *he = NULL;

				if ((he = bt_gethostbyname(optarg)) == NULL)
					errx(1, "%s: %s", optarg, hstrerror(h_errno));
 
				memcpy(&bdaddr, he->h_addr, sizeof(bdaddr));
			}
			break;

		case 'c': /* control socket */
			control = optarg;
			break;

		case 'l': /* local sdpd */
			local = 1;
			break;

		case 'h':
		default:
			usage();
			/* NOT REACHED */
		}
	}

	argc -= optind; 
	argv += optind;

	if (*argv == NULL)
		usage();

	return (do_sdp_command(&bdaddr, control, local, argc, argv));
}
Exemplo n.º 4
0
int
main(int argc, char *argv[])
{
	int		n;
	bdaddr_t	bdaddr;

	memset(&bdaddr, 0, sizeof(bdaddr));

	/* Process command line arguments */
	while ((n = getopt(argc, argv, "a:nh")) != -1) {
		switch (n) {
		case 'a':
			if (!bt_aton(optarg, &bdaddr)) {
				struct hostent	*he = NULL;

				if ((he = bt_gethostbyname(optarg)) == NULL)
					errx(1, "%s: %s", optarg, hstrerror(h_errno));

				memcpy(&bdaddr, he->h_addr, sizeof(bdaddr));
			}
			break;

		case 'n':
			numeric_bdaddr = 1;
			break;

		case 'h':
		default:
			usage();
			break;
		}
	}

	argc -= optind;
	argv += optind;

	if (*argv == NULL)
		usage();

	return (do_l2cap_command(&bdaddr, argc, argv));
} /* main */
Exemplo n.º 5
0
static int
bt_open(struct voss_backend *pbe, const char *devname, int samplerate, int bufsize,
    int *pchannels, int *pformat, struct bt_config *cfg,
    int service_class, int isSink)
{
	struct sockaddr_l2cap addr;
	struct l2cap_info info;
	socklen_t mtusize = sizeof(uint16_t);
	int tmpbitpool;
	int l2cap_psm;
	int temp;
	int err;

	memset(&info, 0, sizeof(info));

	if (strstr(devname, "/dev/bluetooth/") != devname) {
		printf("Invalid device name '%s'", devname);
		goto error;
	}
	/* skip prefix */
	devname += sizeof("/dev/bluetooth/") - 1;

	if (!bt_aton(devname, &info.raddr)) {
		struct hostent *he = NULL;

		if ((he = bt_gethostbyname(devname)) == NULL) {
			DPRINTF("Could not get host by name\n");
			goto error;
		}
		bdaddr_copy(&info.raddr, (bdaddr_t *)he->h_addr);
	}
retry:
	switch (samplerate) {
	case 8000:
		cfg->freq = FREQ_UNDEFINED;
		cfg->aacMode1 = 0x80;
		cfg->aacMode2 = 0x0C;
		break;
	case 11025:
		cfg->freq = FREQ_UNDEFINED;
		cfg->aacMode1 = 0x40;
		cfg->aacMode2 = 0x0C;
		break;
	case 12000:
		cfg->freq = FREQ_UNDEFINED;
		cfg->aacMode1 = 0x20;
		cfg->aacMode2 = 0x0C;
		break;
	case 16000:
		cfg->freq = FREQ_16K;
		cfg->aacMode1 = 0x10;
		cfg->aacMode2 = 0x0C;
		break;
	case 22050:
		cfg->freq = FREQ_UNDEFINED;
		cfg->aacMode1 = 0x08;
		cfg->aacMode2 = 0x0C;
		break;
	case 24000:
		cfg->freq = FREQ_UNDEFINED;
		cfg->aacMode1 = 0x04;
		cfg->aacMode2 = 0x0C;
		break;
	case 32000:
		cfg->freq = FREQ_32K;
		cfg->aacMode1 = 0x02;
		cfg->aacMode2 = 0x0C;
		break;
	case 44100:
		cfg->freq = FREQ_44_1K;
		cfg->aacMode1 = 0x01;
		cfg->aacMode2 = 0x0C;
		break;
	case 48000:
		cfg->freq = FREQ_48K;
		cfg->aacMode1 = 0;
		cfg->aacMode2 = 0x8C;
		break;
	case 64000:
		cfg->freq = FREQ_UNDEFINED;
		cfg->aacMode1 = 0;
		cfg->aacMode2 = 0x4C;
		break;
	case 88200:
		cfg->freq = FREQ_UNDEFINED;
		cfg->aacMode1 = 0;
		cfg->aacMode2 = 0x2C;
		break;
	case 96000:
		cfg->freq = FREQ_UNDEFINED;
		cfg->aacMode1 = 0;
		cfg->aacMode2 = 0x1C;
		break;
	default:
		DPRINTF("Invalid samplerate %d", samplerate);
		goto error;
	}
	cfg->bands = BANDS_8;
	cfg->bitpool = 0;

	switch (*pchannels) {
	case 1:
		cfg->aacMode2 &= 0xF8;
		cfg->chmode = MODE_MONO;
		break;
	default:
		cfg->aacMode2 &= 0xF4;
		cfg->chmode = MODE_STEREO;
		break;
	}

	cfg->allocm = ALLOC_LOUDNESS;

	if (cfg->chmode == MODE_MONO || cfg->chmode == MODE_DUAL)
		tmpbitpool = 16;
	else
		tmpbitpool = 32;

	if (cfg->bands == BANDS_8)
		tmpbitpool *= 8;
	else
		tmpbitpool *= 4;

	if (tmpbitpool > DEFAULT_MAXBPOOL)
		tmpbitpool = DEFAULT_MAXBPOOL;

	cfg->bitpool = tmpbitpool;

	if (bt_set_format(pformat)) {
		DPRINTF("Unsupported sample format\n");
		goto error;
	}
	l2cap_psm = bt_query(&info, service_class);
	DPRINTF("PSM=0x%02x\n", l2cap_psm);
	if (l2cap_psm < 0) {
		DPRINTF("PSM not found\n");
		goto error;
	}
	cfg->hc = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BLUETOOTH_PROTO_L2CAP);
	if (cfg->hc < 0) {
		DPRINTF("Could not create BT socket\n");
		goto error;
	}
	memset(&addr, 0, sizeof(addr));
	addr.l2cap_len = sizeof(addr);
	addr.l2cap_family = AF_BLUETOOTH;
	bdaddr_copy(&addr.l2cap_bdaddr, &info.laddr);

	if (bind(cfg->hc, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
		DPRINTF("Could not bind to HC\n");
		goto error;
	}
	bdaddr_copy(&addr.l2cap_bdaddr, &info.raddr);
	addr.l2cap_psm = l2cap_psm;
	if (connect(cfg->hc, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
		DPRINTF("Could not connect to HC: %d\n", errno);
		goto error;
	}
	if (avdtpDiscoverAndConfig(cfg, isSink)) {
		DPRINTF("DISCOVER FAILED\n");
		goto error;
	}
	if (avdtpOpen(cfg->hc, cfg->sep)) {
		DPRINTF("OPEN FAILED\n");
		goto error;
	}
	cfg->fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BLUETOOTH_PROTO_L2CAP);
	if (cfg->fd < 0) {
		DPRINTF("Could not create BT socket\n");
		goto error;
	}
	memset(&addr, 0, sizeof(addr));

	addr.l2cap_len = sizeof(addr);
	addr.l2cap_family = AF_BLUETOOTH;
	bdaddr_copy(&addr.l2cap_bdaddr, &info.laddr);

	if (bind(cfg->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
		DPRINTF("Could not bind\n");
		goto error;
	}
	bdaddr_copy(&addr.l2cap_bdaddr, &info.raddr);
	addr.l2cap_psm = l2cap_psm;
	if (connect(cfg->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
		DPRINTF("Could not connect: %d\n", errno);
		goto error;
	}
	if (isSink) {
		if (getsockopt(cfg->fd, SOL_L2CAP, SO_L2CAP_OMTU, &cfg->mtu, &mtusize) == -1) {
			DPRINTF("Could not get MTU\n");
			goto error;
		}
		temp = cfg->mtu * 2;
		if (setsockopt(cfg->fd, SOL_SOCKET, SO_SNDBUF, &temp, sizeof(temp)) == -1) {
			DPRINTF("Could not set send buffer size\n");
			goto error;
		}
		temp = cfg->mtu;
		if (setsockopt(cfg->fd, SOL_SOCKET, SO_SNDLOWAT, &temp, sizeof(temp)) == -1) {
			DPRINTF("Could not set low water mark\n");
			goto error;
		}
	} else {
		if (getsockopt(cfg->fd, SOL_L2CAP, SO_L2CAP_IMTU, &cfg->mtu, &mtusize) == -1) {
			DPRINTF("Could not get MTU\n");
			goto error;
		}
		temp = cfg->mtu * 16;
		if (setsockopt(cfg->fd, SOL_SOCKET, SO_RCVBUF, &temp, sizeof(temp)) == -1) {
			DPRINTF("Could not set receive buffer size\n");
			goto error;
		}
		temp = 1;
		if (setsockopt(cfg->fd, SOL_SOCKET, SO_RCVLOWAT, &temp, sizeof(temp)) == -1) {
			DPRINTF("Could not set low water mark\n");
			goto error;
		}
	}

	if (avdtpStart(cfg->hc, cfg->sep)) {
		DPRINTF("START FAILED\n");
		goto error;
	}
	switch (cfg->chmode) {
	case MODE_MONO:
		*pchannels = 1;
		break;
	default:
		*pchannels = 2;
		break;
	}
	return (0);

error:
	if (cfg->hc > 0) {
		close(cfg->hc);
		cfg->hc = -1;
	}
	if (cfg->fd > 0) {
		close(cfg->fd);
		cfg->fd = -1;
	}
	return (-1);
}
Exemplo n.º 6
0
/* Send Swith Role to the unit */
static int
hci_switch_role(int s, int argc, char **argv)
{
	int			 n0;
	char			 b[512];
	ng_hci_switch_role_cp	 cp;
	ng_hci_event_pkt_t	*e = (ng_hci_event_pkt_t *) b; 

	/* parse command parameters */
	switch (argc) {
	case 2:
		/* bdaddr */
		if (!bt_aton(argv[0], &cp.bdaddr)) {
			struct hostent	*he = NULL;

			if ((he = bt_gethostbyname(argv[0])) == NULL)
				return (USAGE);

			memcpy(&cp.bdaddr, he->h_addr, sizeof(cp.bdaddr));
		}

		/* role */
		if (sscanf(argv[1], "%d", &n0) != 1)
			return (USAGE);

		cp.role = n0? NG_HCI_ROLE_SLAVE : NG_HCI_ROLE_MASTER;
		break;

	default:
		return (USAGE);
	}

	/* send request and expect status response */
	n0 = sizeof(b);
	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY,
			NG_HCI_OCF_SWITCH_ROLE),
			(char const *) &cp, sizeof(cp), b, &n0) == ERROR)
		return (ERROR);

	if (*b != 0x00)
		return (FAILED);

	/* wait for event */
again:
	n0 = sizeof(b);
	if (hci_recv(s, b, &n0) == ERROR)
		return (ERROR);
	if (n0 < sizeof(*e)) {
		errno = EIO;
		return (ERROR);
	}

	if (e->event == NG_HCI_EVENT_ROLE_CHANGE) {
		ng_hci_role_change_ep	*ep = (ng_hci_role_change_ep *)(e + 1);

		if (ep->status != 0x00) {
			fprintf(stdout, "Status: %s [%#02x]\n", 
				hci_status2str(ep->status), ep->status);
			return (FAILED);
		}

		fprintf(stdout, "BD_ADDR: %s\n", hci_bdaddr2str(&ep->bdaddr));
		fprintf(stdout, "Role: %s [%#x]\n",
			(ep->role == NG_HCI_ROLE_MASTER)? "Master" : "Slave",
			ep->role);
	} else
		goto again;

	return (OK);
} /* hci_switch_role */
Exemplo n.º 7
0
/* Send Remote_Name_Request command to the unit */
static int
hci_remote_name_request(int s, int argc, char **argv)
{
	int				 n0;
	char				 b[512];
	ng_hci_remote_name_req_cp	 cp;
	ng_hci_event_pkt_t		*e = (ng_hci_event_pkt_t *) b; 

	memset(&cp, 0, sizeof(cp));
	cp.page_scan_rep_mode = NG_HCI_SCAN_REP_MODE0;
	cp.page_scan_mode = NG_HCI_MANDATORY_PAGE_SCAN_MODE;

	/* parse command parameters */
	switch (argc) {
	case 4:
		/* clock_offset */
		if (sscanf(argv[3], "%x", &n0) != 1)
			return (USAGE);

		cp.clock_offset = (n0 & 0xffff);
		cp.clock_offset = htole16(cp.clock_offset);

	case 3:
		/* page_scan_mode */
		if (sscanf(argv[2], "%d", &n0) != 1 || n0 < 0x00 || n0 > 0x03)
			return (USAGE);

		cp.page_scan_mode = (n0 & 0xff);

	case 2:
		/* page_scan_rep_mode */
		if (sscanf(argv[1], "%d", &n0) != 1 || n0 < 0x00 || n0 > 0x02)
			return (USAGE);

		cp.page_scan_rep_mode = (n0 & 0xff);

	case 1:
		/* BD_ADDR */
		if (!bt_aton(argv[0], &cp.bdaddr)) {
			struct hostent	*he = NULL;

			if ((he = bt_gethostbyname(argv[0])) == NULL)
				return (USAGE);

			memcpy(&cp.bdaddr, he->h_addr, sizeof(cp.bdaddr));
		}
		break;

	default:
		return (USAGE);
	}

	/* send request and expect status response */
	n0 = sizeof(b);
	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
			NG_HCI_OCF_REMOTE_NAME_REQ),
			(char const *) &cp, sizeof(cp), b, &n0) == ERROR)
		return (ERROR);

	if (*b != 0x00)
		return (FAILED);

	/* wait for event */
again:
	n0 = sizeof(b);
	if (hci_recv(s, b, &n0) == ERROR)
		return (ERROR);
	if (n0 < sizeof(*e)) {
		errno = EIO;
		return (ERROR);
	}

	if (e->event == NG_HCI_EVENT_REMOTE_NAME_REQ_COMPL) {
		ng_hci_remote_name_req_compl_ep	*ep = 
				(ng_hci_remote_name_req_compl_ep *)(e + 1);

		if (ep->status != 0x00) {
			fprintf(stdout, "Status: %s [%#02x]\n", 
				hci_status2str(ep->status), ep->status);
			return (FAILED);
		}

		fprintf(stdout, "BD_ADDR: %s\n", hci_bdaddr2str(&ep->bdaddr));
		fprintf(stdout, "Name: %s\n", ep->name);
	} else 
		goto again;

	return (OK);
} /* hci_remote_name_request */
Exemplo n.º 8
0
int
main(int ac, char *av[])
{
	bthcid_pin_response_t rp;
	struct sockaddr_un un;
	char *pin = NULL;
	int ch, s, len;

	memset(&rp, 0, sizeof(rp));
	len = -1;

	memset(&un, 0, sizeof(un));
	un.sun_len = sizeof(un);
	un.sun_family = AF_LOCAL;
	strlcpy(un.sun_path, BTHCID_SOCKET_NAME, sizeof(un.sun_path));

	while ((ch = getopt(ac, av, "a:d:l:p:rs:")) != -1) {
		switch (ch) {
		case 'a':
			if (!bt_aton(optarg, &rp.raddr)) {
				struct hostent  *he = NULL;

				if ((he = bt_gethostbyname(optarg)) == NULL)
					errx(EXIT_FAILURE, "%s: %s", optarg,
							hstrerror(h_errno));

				bdaddr_copy(&rp.raddr, (bdaddr_t *)he->h_addr);
			}
			break;

		case 'd':
			if (!bt_devaddr(optarg, &rp.laddr))
				err(EXIT_FAILURE, "%s", optarg);

			break;

		case 'l':
			len = atoi(optarg);
			if (len < 1 || len > HCI_PIN_SIZE)
				errx(EXIT_FAILURE, "Invalid PIN length");

			break;

		case 'p':
			pin = optarg;
			break;

		case 'r':
			if (len == -1)
				len = 4;

			break;

		case 's':
			strlcpy(un.sun_path, optarg, sizeof(un.sun_path));
			break;

		default:
			usage();
		}
	}

	if (bdaddr_any(&rp.raddr))
		usage();

	if (pin == NULL) {
		if (len == -1)
			usage();

		srandom(time(NULL));

		pin = (char *)rp.pin;
		while (len-- > 0)
			*pin++ = '0' + (random() % 10);

		printf("PIN: %.*s\n", HCI_PIN_SIZE, rp.pin);
	} else {
		if (len != -1)
			usage();

		strncpy((char *)rp.pin, pin, HCI_PIN_SIZE);
	}

	s = socket(PF_LOCAL, SOCK_STREAM, 0);
	if (s < 0)
		err(EXIT_FAILURE, "socket");

	if (connect(s, (struct sockaddr *)&un, sizeof(un)) < 0)
		err(EXIT_FAILURE, "connect(\"%s\")", un.sun_path);
	
	if (send(s, &rp, sizeof(rp), 0) != sizeof(rp))
		err(EXIT_FAILURE, "send");

	close(s);
	exit(EXIT_SUCCESS);
}
Exemplo n.º 9
0
/* Send Create_Connection command to the unit */
static int
hci_create_connection(int s, int argc, char **argv)
{
	int			 n0;
	char			 b[512];
	ng_hci_create_con_cp	 cp;
	ng_hci_event_pkt_t	*e = (ng_hci_event_pkt_t *) b; 

	/* Set defaults */
	memset(&cp, 0, sizeof(cp));
	cp.pkt_type = htole16(	NG_HCI_PKT_DM1 | NG_HCI_PKT_DH1 |
				NG_HCI_PKT_DM3 | NG_HCI_PKT_DH3 |
				NG_HCI_PKT_DM5);
	cp.page_scan_rep_mode = NG_HCI_SCAN_REP_MODE0;
	cp.page_scan_mode = NG_HCI_MANDATORY_PAGE_SCAN_MODE;
	cp.clock_offset = 0;
	cp.accept_role_switch = 1;

	/* parse command parameters */
	switch (argc) {
	case 6:
		/* accept role switch */
		if (sscanf(argv[5], "%d", &n0) != 1)
			return (USAGE);

		cp.accept_role_switch = n0 ? 1 : 0;

	case 5:
		/* clock offset */
		if (sscanf(argv[4], "%d", &n0) != 1)
			return (USAGE);

		cp.clock_offset = (n0 & 0xffff);
		cp.clock_offset = htole16(cp.clock_offset);

	case 4:
		/* page scan mode */
		if (sscanf(argv[3], "%d", &n0) != 1 || n0 < 0 || n0 > 3)
			return (USAGE);

		cp.page_scan_mode = (n0 & 0xff);

	case 3:
		/* page scan rep mode */
		if (sscanf(argv[2], "%d", &n0) != 1 || n0 < 0 || n0 > 2)
			return (USAGE);

		cp.page_scan_rep_mode = (n0 & 0xff);

	case 2:
		/* packet type */
		if (sscanf(argv[1], "%x", &n0) != 1)
			return (USAGE);

		n0 &= (	NG_HCI_PKT_DM1 | NG_HCI_PKT_DH1 |
			NG_HCI_PKT_DM3 | NG_HCI_PKT_DH3 |
			NG_HCI_PKT_DM5);
		if (n0 == 0)
			return (USAGE);

		cp.pkt_type = (n0 & 0xffff);
		cp.pkt_type = htole16(cp.pkt_type);

	case 1:
		/* BD_ADDR */
		if (!bt_aton(argv[0], &cp.bdaddr)) {
			struct hostent	*he = NULL;

			if ((he = bt_gethostbyname(argv[0])) == NULL)
				return (USAGE);

			memcpy(&cp.bdaddr, he->h_addr, sizeof(cp.bdaddr));
		}
		break;

	default:
		return (USAGE);
	}

	/* send request and expect status response */
	n0 = sizeof(b);
	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
			NG_HCI_OCF_CREATE_CON),
			(char const *) &cp, sizeof(cp), b, &n0) == ERROR)
		return (ERROR);

	if (*b != 0x00)
		return (FAILED);

	/* wait for event */
again:
	n0 = sizeof(b);
	if (hci_recv(s, b, &n0) == ERROR)
		return (ERROR);
	if (n0 < sizeof(*e)) {
		errno = EIO;
		return (ERROR);
	}

	if (e->event == NG_HCI_EVENT_CON_COMPL) {
		ng_hci_con_compl_ep	*ep = (ng_hci_con_compl_ep *)(e + 1);

		if (ep->status != 0x00) {
			fprintf(stdout, "Status: %s [%#02x]\n", 
				hci_status2str(ep->status), ep->status);
			return (FAILED);
		}

		fprintf(stdout, "BD_ADDR: %s\n", hci_bdaddr2str(&ep->bdaddr));
		fprintf(stdout, "Connection handle: %d\n",
			le16toh(ep->con_handle));
		fprintf(stdout, "Encryption mode: %s [%d]\n",
			hci_encrypt2str(ep->encryption_mode, 0),
			ep->encryption_mode);
	} else
		goto again;

	return (OK);
} /* hci_create_connection */
Exemplo n.º 10
0
/* Main */
int
main(int argc, char *argv[])
{
	struct sockaddr_rfcomm   sock_addr;
	char			*label = NULL, *unit = NULL, *ep = NULL;
	bdaddr_t		 addr;
	int			 s, channel, detach, server, service,
				 regdun, regsp;
	pid_t			 pid;

	memcpy(&addr, NG_HCI_BDADDR_ANY, sizeof(addr));
	channel = 0;
	detach = 1;
	server = 0;
	service = 0;
	regdun = 0;
	regsp = 0;

	/* Parse command line arguments */
	while ((s = getopt(argc, argv, "a:cC:dDhl:sSu:")) != -1) {
		switch (s) {
		case 'a': /* BDADDR */
			if (!bt_aton(optarg, &addr)) {
				struct hostent	*he = NULL;

				if ((he = bt_gethostbyname(optarg)) == NULL)
					errx(1, "%s: %s", optarg, hstrerror(h_errno));

				memcpy(&addr, he->h_addr, sizeof(addr));
			}
			break;

		case 'c': /* client */
			server = 0;
			break;

		case 'C': /* RFCOMM channel */
			channel = strtoul(optarg, &ep, 10);
			if (*ep != '\0') {
				channel = 0;
				switch (tolower(optarg[0])) {
				case 'd': /* DialUp Networking */
					service = SDP_SERVICE_CLASS_DIALUP_NETWORKING;
					break;

				case 'l': /* LAN Access Using PPP */
					service = SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP;
					break;
				}
			}
			break;

		case 'd': /* do not detach */
			detach = 0;
			break;

		case 'D': /* Register DUN service as well as LAN service */
			regdun = 1;
			break;

		case 'l': /* PPP label */
			label = optarg;
			break;

		case 's': /* server */
			server = 1;
			break;

		case 'S': /* Register SP service as well as LAN service */
			regsp = 1;
			break;

		case 'u': /* PPP -unit option */
			strtoul(optarg, &ep, 10);
			if (*ep != '\0')
				usage();
				/* NOT REACHED */

			unit = optarg;
			break;

		case 'h':
		default:
			usage();
			/* NOT REACHED */
		}
	}

	/* Check if we got everything we wanted */
	if (label == NULL)
                errx(1, "Must specify PPP label");

	if (!server) {
		if (memcmp(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)) == 0)
                	errx(1, "Must specify server BD_ADDR");

		/* Check channel, if was not set then obtain it via SDP */
		if (channel == 0 && service != 0)
			if (rfcomm_channel_lookup(NULL, &addr, service,
							&channel, &s) != 0)
				errc(1, s, "Could not obtain RFCOMM channel");
	}

        if (channel <= 0 || channel > 30)
                errx(1, "Invalid RFCOMM channel number %d", channel);

	openlog(RFCOMM_PPPD, LOG_PID | LOG_PERROR | LOG_NDELAY, LOG_USER);

	if (detach && daemon(0, 0) < 0) {
		syslog(LOG_ERR, "Could not daemon(0, 0). %s (%d)",
			strerror(errno), errno);
		exit(1);
	}

	s = socket(PF_BLUETOOTH, SOCK_STREAM, BLUETOOTH_PROTO_RFCOMM);
	if (s < 0) {
		syslog(LOG_ERR, "Could not create socket. %s (%d)",
			strerror(errno), errno);
		exit(1);
	}

	if (server) {
		struct sigaction	 sa;
		void			*ss = NULL;
		sdp_lan_profile_t	 lan;

		/* Install signal handler */
		memset(&sa, 0, sizeof(sa));
		sa.sa_handler = sighandler;

		if (sigaction(SIGTERM, &sa, NULL) < 0) {
			syslog(LOG_ERR, "Could not sigaction(SIGTERM). %s (%d)",
				strerror(errno), errno);
			exit(1);
		}

		if (sigaction(SIGHUP, &sa, NULL) < 0) {
			syslog(LOG_ERR, "Could not sigaction(SIGHUP). %s (%d)",
				strerror(errno), errno);
			exit(1);
		}

		if (sigaction(SIGINT, &sa, NULL) < 0) {
			syslog(LOG_ERR, "Could not sigaction(SIGINT). %s (%d)",
				strerror(errno), errno);
			exit(1);
		}

		sa.sa_handler = SIG_IGN;
		sa.sa_flags = SA_NOCLDWAIT;

		if (sigaction(SIGCHLD, &sa, NULL) < 0) {
			syslog(LOG_ERR, "Could not sigaction(SIGCHLD). %s (%d)",
				strerror(errno), errno);
			exit(1);
		}

		/* bind socket and listen for incoming connections */
		sock_addr.rfcomm_len = sizeof(sock_addr);
		sock_addr.rfcomm_family = AF_BLUETOOTH;
		memcpy(&sock_addr.rfcomm_bdaddr, &addr,
			sizeof(sock_addr.rfcomm_bdaddr));
		sock_addr.rfcomm_channel = channel;

		if (bind(s, (struct sockaddr *) &sock_addr,
				sizeof(sock_addr)) < 0) {
			syslog(LOG_ERR, "Could not bind socket. %s (%d)",
				strerror(errno), errno);
			exit(1);
		}

		if (listen(s, 10) < 0) {
			syslog(LOG_ERR, "Could not listen on socket. %s (%d)",
				strerror(errno), errno);
			exit(1);
		}

		ss = sdp_open_local(NULL);
		if (ss == NULL) {
			syslog(LOG_ERR, "Unable to create local SDP session");
			exit(1);
		}

		if (sdp_error(ss) != 0) {
			syslog(LOG_ERR, "Unable to open local SDP session. " \
				"%s (%d)", strerror(sdp_error(ss)),
				sdp_error(ss));
			exit(1);
		}

		memset(&lan, 0, sizeof(lan));
		lan.server_channel = channel;

		if (sdp_register_service(ss,
				SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP,
				&addr, (void *) &lan, sizeof(lan), NULL) != 0) {
			syslog(LOG_ERR, "Unable to register LAN service with " \
				"local SDP daemon. %s (%d)",
				strerror(sdp_error(ss)), sdp_error(ss));
			exit(1);
		}

		/*
		 * Register DUN (Dial-Up Networking) service on the same
		 * RFCOMM channel if requested. There is really no good reason
		 * to not to support this. AT-command exchange can be faked
		 * with chat script in ppp.conf
		 */

		if (regdun) {
			sdp_dun_profile_t	dun;

			memset(&dun, 0, sizeof(dun));
			dun.server_channel = channel;

			if (sdp_register_service(ss,
					SDP_SERVICE_CLASS_DIALUP_NETWORKING,
					&addr, (void *) &dun, sizeof(dun),
					NULL) != 0) {
				syslog(LOG_ERR, "Unable to register DUN " \
					"service with local SDP daemon. " \
					"%s (%d)", strerror(sdp_error(ss)),
					sdp_error(ss));
				exit(1);
			}
		}

		/*
		 * Register SP (Serial Port) service on the same RFCOMM channel
		 * if requested. It appears that some cell phones are using so
		 * called "callback mechanism". In this scenario user is trying
		 * to connect his cell phone to the Internet, and, user's host
		 * computer is acting as the gateway server. It seems that it
		 * is not possible to tell the phone to just connect and start
		 * using the LAN service. Instead the user's host computer must
		 * "jump start" the phone by connecting to the phone's SP
		 * service. What happens next is the phone kills the existing
		 * connection and opens another connection back to the user's
		 * host computer. The phone really wants to use LAN service,
		 * but for whatever reason it looks for SP service on the
		 * user's host computer. This brain damaged behavior was
		 * reported for Nokia 6600 and Sony/Ericsson P900. Both phones
		 * are Symbian-based phones. Perhaps this is a Symbian problem?
		 */

		if (regsp) {
			sdp_sp_profile_t	sp;

			memset(&sp, 0, sizeof(sp));
			sp.server_channel = channel;

			if (sdp_register_service(ss,
					SDP_SERVICE_CLASS_SERIAL_PORT,
					&addr, (void *) &sp, sizeof(sp),
					NULL) != 0) {
				syslog(LOG_ERR, "Unable to register SP " \
					"service with local SDP daemon. " \
					"%s (%d)", strerror(sdp_error(ss)),
					sdp_error(ss));
				exit(1);
			}
		}
		
		for (done = 0; !done; ) {
			socklen_t	len = sizeof(sock_addr);
			int		s1 = accept(s, (struct sockaddr *) &sock_addr, &len);

			if (s1 < 0) {
				syslog(LOG_ERR, "Could not accept connection " \
					"on socket. %s (%d)", strerror(errno),
					errno);
				exit(1);
			}
				
			pid = fork();
			if (pid == (pid_t) -1) {
				syslog(LOG_ERR, "Could not fork(). %s (%d)",
					strerror(errno), errno);
				exit(1);
			}

			if (pid == 0) {
				sdp_close(ss);
				close(s);

				/* Reset signal handler */
				memset(&sa, 0, sizeof(sa));
				sa.sa_handler = SIG_DFL;

				sigaction(SIGTERM, &sa, NULL);
				sigaction(SIGHUP, &sa, NULL);
				sigaction(SIGINT, &sa, NULL);
				sigaction(SIGCHLD, &sa, NULL);

				/* Become daemon */
				daemon(0, 0);

				/*
				 * XXX Make sure user does not shoot himself
				 * in the foot. Do not pass unit option to the
				 * PPP when operating in the server mode.
				 */

				exec_ppp(s1, NULL, label);
			} else
				close(s1);
		}
	} else {
		sock_addr.rfcomm_len = sizeof(sock_addr);
		sock_addr.rfcomm_family = AF_BLUETOOTH;
		memcpy(&sock_addr.rfcomm_bdaddr, NG_HCI_BDADDR_ANY,
			sizeof(sock_addr.rfcomm_bdaddr));
		sock_addr.rfcomm_channel = 0;

		if (bind(s, (struct sockaddr *) &sock_addr,
				sizeof(sock_addr)) < 0) {
			syslog(LOG_ERR, "Could not bind socket. %s (%d)",
				strerror(errno), errno);
			exit(1);
		}

		memcpy(&sock_addr.rfcomm_bdaddr, &addr,
			sizeof(sock_addr.rfcomm_bdaddr));
		sock_addr.rfcomm_channel = channel;

		if (connect(s, (struct sockaddr *) &sock_addr,
				sizeof(sock_addr)) < 0) {
			syslog(LOG_ERR, "Could not connect socket. %s (%d)",
				strerror(errno), errno);
			exit(1);
		}

		exec_ppp(s, unit, label);
	}

	exit(0);
} /* main */
Exemplo n.º 11
0
int
main(int argc, char *argv[])
{
	bdaddr_t		 src, dst;
	struct hostent		*he;
	uint8_t			*echo_data;
	struct sockaddr_l2cap	 sa;
	int32_t			 n, s, count, wait, flood, echo_size, numeric;
	char			*endp, *rname;

	/* Set defaults */
	memcpy(&src, NG_HCI_BDADDR_ANY, sizeof(src));
	memcpy(&dst, NG_HCI_BDADDR_ANY, sizeof(dst));

	echo_data = (uint8_t *) calloc(NG_L2CAP_MAX_ECHO_SIZE, sizeof(uint8_t));
	if (echo_data == NULL) {
		fprintf(stderr, "Failed to allocate echo data buffer");
		exit(1);
	}

	/*
	 * Set default echo size to the NG_L2CAP_MTU_MINIMUM minus
	 * the size of the L2CAP signalling command header.
	 */

	echo_size = NG_L2CAP_MTU_MINIMUM - sizeof(ng_l2cap_cmd_hdr_t);
	count = -1; /* unimited */
	wait = 1;   /* sec */
	flood = 0;
	numeric = 0;

	/* Parse command line arguments */
	while ((n = getopt(argc, argv, "a:c:fi:nS:s:h")) != -1) {
		switch (n) {
		case 'a':
			if (!bt_aton(optarg, &dst)) {
				if ((he = bt_gethostbyname(optarg)) == NULL)
					errx(1, "%s: %s", optarg, hstrerror(h_errno));

				memcpy(&dst, he->h_addr, sizeof(dst));
			}
			break;

		case 'c':
			count = strtol(optarg, &endp, 10);
			if (count <= 0 || *endp != '\0')
				usage();
			break;

		case 'f':
			flood = 1;
			break;

		case 'i':
			wait = strtol(optarg, &endp, 10);
			if (wait <= 0 || *endp != '\0')
				usage();
			break;

		case 'n':
			numeric = 1;
			break;

		case 'S':
			if (!bt_aton(optarg, &src)) {
				if ((he = bt_gethostbyname(optarg)) == NULL)
					errx(1, "%s: %s", optarg, hstrerror(h_errno));

				memcpy(&src, he->h_addr, sizeof(src));
			}
			break;

		case 's':
                        echo_size = strtol(optarg, &endp, 10);
                        if (echo_size < sizeof(int32_t) ||
			    echo_size > NG_L2CAP_MAX_ECHO_SIZE ||
			    *endp != '\0')
				usage();
			break;

		case 'h':
		default:
			usage();
			break;
		}
	}

	if (memcmp(&dst, NG_HCI_BDADDR_ANY, sizeof(dst)) == 0)
		usage();

	he = bt_gethostbyaddr((const char *)&dst, sizeof(dst), AF_BLUETOOTH);
	if (he == NULL || he->h_name == NULL || he->h_name[0] == '\0' || numeric)
		asprintf(&rname, "%s", bt_ntoa(&dst, NULL));
	else
		rname = strdup(he->h_name);

	if (rname == NULL)
		errx(1, "Failed to create remote hostname");

	s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_L2CAP);
	if (s < 0)
		err(2, "Could not create socket");

	memset(&sa, 0, sizeof(sa));
	sa.l2cap_len = sizeof(sa);
	sa.l2cap_family = AF_BLUETOOTH;
	memcpy(&sa.l2cap_bdaddr, &src, sizeof(sa.l2cap_bdaddr));

	if (bind(s, (struct sockaddr *) &sa, sizeof(sa)) < 0)
		err(3,
"Could not bind socket, src bdaddr=%s", bt_ntoa(&sa.l2cap_bdaddr, NULL));

	memset(&sa, 0, sizeof(sa));
	sa.l2cap_len = sizeof(sa);
	sa.l2cap_family = AF_BLUETOOTH;
	memcpy(&sa.l2cap_bdaddr, &dst, sizeof(sa.l2cap_bdaddr));

	if (connect(s, (struct sockaddr *) &sa, sizeof(sa)) < 0)
		err(4,
"Could not connect socket, dst bdaddr=%s", bt_ntoa(&sa.l2cap_bdaddr, NULL));

	/* Fill pattern */
	for (n = 0; n < echo_size; ) {
		int32_t	avail = min(echo_size - n, PATTERN_SIZE);

		memcpy(echo_data + n, pattern, avail);
		n += avail;
	}

	/* Start ping'ing */
	for (n = 0; count == -1 || count > 0; n ++) {
		struct ng_btsocket_l2cap_raw_ping	r;
		struct timeval				a, b;
		int32_t					fail;

		if (gettimeofday(&a, NULL) < 0)
			err(5, "Could not gettimeofday(a)");

		fail = 0;
		*((int32_t *) echo_data) = htonl(n);

		r.result = 0;
		r.echo_size = echo_size;
		r.echo_data = echo_data;
		if (ioctl(s, SIOC_L2CAP_L2CA_PING, &r, sizeof(r)) < 0) {
			r.result = errno;
			fail = 1;
/*
			warn("Could not ping, dst bdaddr=%s",
				bt_ntoa(&r.echo_dst, NULL));
*/
		}

		if (gettimeofday(&b, NULL) < 0)
			err(7, "Could not gettimeofday(b)");

		tv_sub(&b, &a);

		fprintf(stdout,
"%d bytes from %s seq_no=%d time=%.3f ms result=%#x %s\n",
			r.echo_size,
			rname,
			ntohl(*((int32_t *)(r.echo_data))),
			tv2msec(&b), r.result,
			((fail == 0)? "" : strerror(errno)));

		if (!flood) {
			/* Wait */
			a.tv_sec = wait;
			a.tv_usec = 0;
			select(0, NULL, NULL, NULL, &a);
		}

		if (count != -1)
			count --;
	}

	free(rname);
	free(echo_data);
	close(s);

	return (0);
} /* main */
Exemplo n.º 12
0
int32_t
main(int32_t argc, char *argv[])
{
	struct bthid_server	 srv;
	struct sigaction	 sa;
	char const		*pid_file = BTHIDD_PIDFILE;
	char			*ep;
	int32_t			 opt, detach, tval;

	memset(&srv, 0, sizeof(srv));
	memset(&srv.bdaddr, 0, sizeof(srv.bdaddr));
	detach = 1;
	tval = 10; /* sec */

	while ((opt = getopt(argc, argv, "a:c:dH:hp:t:")) != -1) {
		switch (opt) {
		case 'a': /* BDADDR */
			if (!bt_aton(optarg, &srv.bdaddr)) {
				struct hostent  *he;

				if ((he = bt_gethostbyname(optarg)) == NULL)
					errx(1, "%s: %s", optarg, hstrerror(h_errno));

				memcpy(&srv.bdaddr, he->h_addr, sizeof(srv.bdaddr));
			}
			break;
			
		case 'c': /* config file */
			config_file = optarg;
			break;

		case 'd': /* do not detach */
			detach = 0;
			break;

		case 'H': /* hids file */
			hids_file = optarg;
			break;

		case 'p': /* pid file */
			pid_file = optarg;
			break;

		case 't': /* rescan interval */
			tval = strtol(optarg, (char **) &ep, 10);
			if (*ep != '\0' || tval <= 0)
				usage();
			break;

		case 'h':
		default:
			usage();
			/* NOT REACHED */
		}
	}

	openlog(BTHIDD_IDENT, LOG_PID|LOG_PERROR|LOG_NDELAY, LOG_USER);

	/* Become daemon if required */
	if (detach && daemon(0, 0) < 0) {
		syslog(LOG_CRIT, "Could not become daemon. %s (%d)",
			strerror(errno), errno);
		exit(1);
	}

	/* Install signal handler */
	memset(&sa, 0, sizeof(sa));
	sa.sa_handler = sighandler;

	if (sigaction(SIGTERM, &sa, NULL) < 0 ||
	    sigaction(SIGHUP, &sa, NULL) < 0 ||
	    sigaction(SIGINT, &sa, NULL) < 0) {
		syslog(LOG_CRIT, "Could not install signal handlers. %s (%d)",
			strerror(errno), errno);
		exit(1);
	}

	sa.sa_handler = SIG_IGN;
	if (sigaction(SIGPIPE, &sa, NULL) < 0) {
		syslog(LOG_CRIT, "Could not install signal handlers. %s (%d)",
			strerror(errno), errno);
		exit(1);
	}

	sa.sa_handler = SIG_IGN;
	sa.sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT;
	if (sigaction(SIGCHLD, &sa, NULL) < 0) {
		syslog(LOG_CRIT, "Could not install signal handlers. %s (%d)",
			strerror(errno), errno);
		exit(1);
	}

	if (read_config_file() < 0 || read_hids_file() < 0 ||
	    server_init(&srv) < 0 || write_pid_file(pid_file) < 0)
		exit(1);

	for (done = 0; !done; ) {
		if (elapsed(tval))
			client_rescan(&srv);

		if (server_do(&srv) < 0)
			break;
	}

	server_shutdown(&srv);
	remove_pid_file(pid_file);
	clean_config();
	closelog();

	return (0);
}
Exemplo n.º 13
0
/* Main */
int
main(int argc, char *argv[]) 
{
	struct sigaction	 sa;
	struct sockaddr_rfcomm	 ra;
	bdaddr_t		 addr;
	int			 n, background, channel, service,
				 s, amaster, aslave, fd, doserver,
				 dopty;
	fd_set			 rfd;
	char			*tty = NULL, *ep = NULL, buf[SPPD_BUFFER_SIZE];

	memcpy(&addr, NG_HCI_BDADDR_ANY, sizeof(addr));
	background = channel = 0;
	service = SDP_SERVICE_CLASS_SERIAL_PORT;
	doserver = 0;
	dopty = 0;

	/* Parse command line options */
	while ((n = getopt(argc, argv, "a:bc:thS")) != -1) {
		switch (n) { 
		case 'a': /* BDADDR */
			if (!bt_aton(optarg, &addr)) {
				struct hostent	*he = NULL;

				if ((he = bt_gethostbyname(optarg)) == NULL)
					errx(1, "%s: %s", optarg, hstrerror(h_errno));

				memcpy(&addr, he->h_addr, sizeof(addr));
			}
			break;

		case 'c': /* RFCOMM channel */
			channel = strtoul(optarg, &ep, 10);
			if (*ep != '\0') {
				channel = 0;
				switch (tolower(optarg[0])) {
				case 'd': /* DialUp Networking */
					service = SDP_SERVICE_CLASS_DIALUP_NETWORKING;
					break;

				case 'f': /* Fax */
					service = SDP_SERVICE_CLASS_FAX;
					break;

				case 'l': /* LAN */
					service = SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP;
					break;

				case 's': /* Serial Port */
					service = SDP_SERVICE_CLASS_SERIAL_PORT;
					break;

				default:
					errx(1, "Unknown service name: %s",
						optarg);
					/* NOT REACHED */
				}
			}
			break;

		case 'b': /* Run in background */
			background = 1;
			break;

		case 't': /* Open pseudo TTY */
			dopty = 1;
			break;

		case 'S':
			doserver = 1;
			break;

		case 'h':
		default:
			usage();
			/* NOT REACHED */
		}
	}

	/* Check if we have everything we need */
	if (!doserver && memcmp(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)) == 0)
		usage();
		/* NOT REACHED */

	/* Set signal handlers */
	memset(&sa, 0, sizeof(sa));
	sa.sa_handler = sppd_sighandler;

	if (sigaction(SIGTERM, &sa, NULL) < 0)
		err(1, "Could not sigaction(SIGTERM)");
 
	if (sigaction(SIGHUP, &sa, NULL) < 0)
		err(1, "Could not sigaction(SIGHUP)");
 
	if (sigaction(SIGINT, &sa, NULL) < 0)
		err(1, "Could not sigaction(SIGINT)");

	sa.sa_handler = SIG_IGN;
	sa.sa_flags = SA_NOCLDWAIT;

	if (sigaction(SIGCHLD, &sa, NULL) < 0)
		err(1, "Could not sigaction(SIGCHLD)");

	/* Open TTYs */
	if (dopty) {
		if (sppd_ttys_open(&tty, &amaster, &aslave) < 0)
			exit(1);

		fd = amaster;
	} else {
		if (background)
			usage();

		amaster = STDIN_FILENO;
		fd = STDOUT_FILENO;
	}

	/* Open RFCOMM connection */

	if (doserver) {
		struct sockaddr_rfcomm	 ma;
		bdaddr_t		 bt_addr_any;
		sdp_sp_profile_t	 sp;
		void			*ss;
		uint32_t		 sdp_handle;
		int			 acceptsock, aaddrlen;

		acceptsock = socket(PF_BLUETOOTH, SOCK_STREAM,
					BLUETOOTH_PROTO_RFCOMM);
		if (acceptsock < 0)
			err(1, "Could not create socket");

		memcpy(&bt_addr_any, NG_HCI_BDADDR_ANY, sizeof(bt_addr_any));

		memset(&ma, 0, sizeof(ma));
		ma.rfcomm_len = sizeof(ma);
		ma.rfcomm_family = AF_BLUETOOTH;
		memcpy(&ma.rfcomm_bdaddr, &bt_addr_any, sizeof(bt_addr_any));
		ma.rfcomm_channel = channel;

		if (bind(acceptsock, (struct sockaddr *)&ma, sizeof(ma)) < 0)
			err(1, "Could not bind socket on channel %d", channel);
		if (listen(acceptsock, 10) != 0)
			err(1, "Could not listen on socket");

		aaddrlen = sizeof(ma);
		if (getsockname(acceptsock, (struct sockaddr *)&ma, &aaddrlen) < 0)
			err(1, "Could not get socket name");
		channel = ma.rfcomm_channel;

		ss = sdp_open_local(NULL);
		if (ss == NULL)
			errx(1, "Unable to create local SDP session");
		if (sdp_error(ss) != 0)
			errx(1, "Unable to open local SDP session. %s (%d)",
			    strerror(sdp_error(ss)), sdp_error(ss));
		memset(&sp, 0, sizeof(sp));
		sp.server_channel = channel;

		if (sdp_register_service(ss, SDP_SERVICE_CLASS_SERIAL_PORT,
				&bt_addr_any, (void *)&sp, sizeof(sp),
				&sdp_handle) != 0) {
			errx(1, "Unable to register LAN service with "
			    "local SDP daemon. %s (%d)",
			    strerror(sdp_error(ss)), sdp_error(ss));
		}

		s = -1;
		while (s < 0) {
			aaddrlen = sizeof(ra);
			s = accept(acceptsock, (struct sockaddr *)&ra,
			    &aaddrlen);
			if (s < 0)
				err(1, "Unable to accept()");
			if (memcmp(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)) &&
			    memcmp(&addr, &ra.rfcomm_bdaddr, sizeof(addr))) {
				warnx("Connect from wrong client");
				close(s);
				s = -1;
			}
		}
		sdp_unregister_service(ss, sdp_handle);
		sdp_close(ss);
		close(acceptsock);
	} else {
		/* Check channel, if was not set then obtain it via SDP */
		if (channel == 0 && service != 0)
			if (rfcomm_channel_lookup(NULL, &addr,
				    service, &channel, &n) != 0)
				errc(1, n, "Could not obtain RFCOMM channel");
		if (channel <= 0 || channel > 30)
			errx(1, "Invalid RFCOMM channel number %d", channel);

		s = socket(PF_BLUETOOTH, SOCK_STREAM, BLUETOOTH_PROTO_RFCOMM);
		if (s < 0)
			err(1, "Could not create socket");

		memset(&ra, 0, sizeof(ra));
		ra.rfcomm_len = sizeof(ra);
		ra.rfcomm_family = AF_BLUETOOTH;

		if (bind(s, (struct sockaddr *) &ra, sizeof(ra)) < 0)
			err(1, "Could not bind socket");

		memcpy(&ra.rfcomm_bdaddr, &addr, sizeof(ra.rfcomm_bdaddr));
		ra.rfcomm_channel = channel;

		if (connect(s, (struct sockaddr *) &ra, sizeof(ra)) < 0)
			err(1, "Could not connect socket");
	}

	/* Became daemon if required */
	if (background && daemon(0, 0) < 0)
		err(1, "Could not daemon()");

	openlog(SPPD_IDENT, LOG_NDELAY|LOG_PERROR|LOG_PID, LOG_DAEMON);
	syslog(LOG_INFO, "Starting on %s...", (tty != NULL)? tty : "stdin/stdout");

	/* Print used tty on stdout for wrappers to pick up */
	if (!background)
		fprintf(stdout, "%s\n", tty);

	for (done = 0; !done; ) {
		FD_ZERO(&rfd);
		FD_SET(amaster, &rfd);
		FD_SET(s, &rfd);

		n = select(max(amaster, s) + 1, &rfd, NULL, NULL, NULL);
		if (n < 0) {
			if (errno == EINTR)
				continue;

			syslog(LOG_ERR, "Could not select(). %s",
					strerror(errno));
			exit(1);
		}

		if (n == 0)
			continue;

		if (FD_ISSET(amaster, &rfd)) {
			n = sppd_read(amaster, buf, sizeof(buf));
			if (n < 0) {
				syslog(LOG_ERR, "Could not read master pty, " \
					"fd=%d. %s", amaster, strerror(errno));
				exit(1);
			}

			if (n == 0)
				break; /* XXX */

			if (sppd_write(s, buf, n) < 0) {
				syslog(LOG_ERR, "Could not write to socket, " \
					"fd=%d, size=%d. %s",
					s, n, strerror(errno));
				exit(1);
			}
		}

		if (FD_ISSET(s, &rfd)) {
			n = sppd_read(s, buf, sizeof(buf));
			if (n < 0) {
				syslog(LOG_ERR, "Could not read socket, " \
					"fd=%d. %s", s, strerror(errno));
				exit(1);
			}

			if (n == 0)
				break;

			if (sppd_write(fd, buf, n) < 0) {
				syslog(LOG_ERR, "Could not write to master " \
					"pty, fd=%d, size=%d. %s",
					fd, n, strerror(errno));
				exit(1);
			}
		}
	}

	syslog(LOG_INFO, "Completed on %s", (tty != NULL)? tty : "stdin/stdout");
	closelog();

	close(s);

	if (tty != NULL) {
		close(aslave);
		close(amaster);
	}	

	return (0);
}