Пример #1
0
/*
 * sco_connect(pcb, sockaddr)
 *
 *	Initiate a SCO connection to the destination address.
 */
int
sco_connect(struct sco_pcb *pcb, struct sockaddr_bt *dest)
{
	hci_add_sco_con_cp cp;
	struct hci_unit *unit;
	struct hci_link *acl, *sco;
	int err;

	if (pcb->sp_flags & SP_LISTENING)
		return EINVAL;

	bdaddr_copy(&pcb->sp_raddr, &dest->bt_bdaddr);

	if (bdaddr_any(&pcb->sp_raddr))
		return EDESTADDRREQ;

	if (bdaddr_any(&pcb->sp_laddr)) {
		err = hci_route_lookup(&pcb->sp_laddr, &pcb->sp_raddr);
		if (err)
			return err;
	}

	unit = hci_unit_lookup(&pcb->sp_laddr);
	if (unit == NULL)
		return ENETDOWN;

	/*
	 * We must have an already open ACL connection before we open the SCO
	 * connection, and since SCO connections dont happen on their own we
	 * will not open one, the application wanting this should have opened
	 * it previously.
	 */
	acl = hci_link_lookup_bdaddr(unit, &pcb->sp_raddr, HCI_LINK_ACL);
	if (acl == NULL || acl->hl_state != HCI_LINK_OPEN)
		return EHOSTUNREACH;

	sco = hci_link_alloc(unit);
	if (sco == NULL)
		return ENOMEM;

	sco->hl_type = HCI_LINK_SCO;
	bdaddr_copy(&sco->hl_bdaddr, &pcb->sp_raddr);

	sco->hl_link = hci_acl_open(unit, &pcb->sp_raddr);
	KKASSERT(sco->hl_link == acl);

	cp.con_handle = htole16(acl->hl_handle);
	cp.pkt_type = htole16(0x00e0);		/* HV1, HV2, HV3 */
	err = hci_send_cmd(unit, HCI_CMD_ADD_SCO_CON, &cp, sizeof(cp));
	if (err) {
		hci_link_free(sco, err);
		return err;
	}

	sco->hl_sco = pcb;
	pcb->sp_link = sco;

	pcb->sp_mtu = unit->hci_max_sco_size;
	return 0;
}
Пример #2
0
/*
 * sco_disconnect(pcb, linger)
 *
 *	Initiate disconnection of connected SCO pcb
 */
int
sco_disconnect(struct sco_pcb *pcb, int linger)
{
	hci_discon_cp cp;
	struct hci_link *sco;
	int err;

	sco = pcb->sp_link;
	if (sco == NULL)
		return EINVAL;

	cp.con_handle = htole16(sco->hl_handle);
	cp.reason = 0x13;	/* "Remote User Terminated Connection" */

	err = hci_send_cmd(sco->hl_unit, HCI_CMD_DISCONNECT, &cp, sizeof(cp));
	if (err || linger == 0) {
		sco->hl_sco = NULL;
		pcb->sp_link = NULL;
		hci_link_free(sco, err);
	}

	return err;
}