示例#1
0
/* Delete channel. 
 * Must be called on the locked socket. */
static void l2cap_chan_del(struct sock *sk, int err)
{
	struct l2cap_conn *conn = l2cap_pi(sk)->conn;
	struct sock *parent = bluez_pi(sk)->parent;

	l2cap_sock_clear_timer(sk);

	BT_DBG("sk %p, conn %p, err %d", sk, conn, err);

	if (conn) { 
		/* Unlink from channel list */
		l2cap_chan_unlink(&conn->chan_list, sk);
		l2cap_pi(sk)->conn = NULL;
		hci_conn_put(conn->hcon);
	}

	sk->state  = BT_CLOSED;
	sk->zapped = 1;

	if (err)
		sk->err = err;

	if (parent)
		parent->data_ready(parent, 0);
	else
		sk->state_change(sk);
}
示例#2
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;
}
示例#3
0
static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
{
	struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
	struct sock *sk = sock->sk;
	int err = 0;

	BT_DBG("sk %p, %s %d", sk, batostr(&la->l2_bdaddr), la->l2_psm);

	if (!addr || addr->sa_family != AF_BLUETOOTH)
		return -EINVAL;

	lock_sock(sk);

	if (sk->state != BT_OPEN) {
		err = -EBADFD;
		goto done;
	}

	write_lock_bh(&l2cap_sk_list.lock);
	if (la->l2_psm && __l2cap_get_sock_by_addr(la->l2_psm, &la->l2_bdaddr)) {
		err = -EADDRINUSE;
	} else {
		/* Save source address */
		bacpy(&bluez_pi(sk)->src, &la->l2_bdaddr);
		l2cap_pi(sk)->psm = la->l2_psm;
		sk->sport = la->l2_psm;
		sk->state = BT_BOUND;
	}
	write_unlock_bh(&l2cap_sk_list.lock);

done:
	release_sock(sk);
	return err;
}
示例#4
0
int sco_connect(struct sock *sk)
{
	bdaddr_t *src = &bluez_pi(sk)->src;
	bdaddr_t *dst = &bluez_pi(sk)->dst;
	struct sco_conn *conn;
	struct hci_conn *hcon;
	struct hci_dev  *hdev;
	int err = 0;

	BT_DBG("%s -> %s", batostr(src), batostr(dst));

	if (!(hdev = hci_get_route(dst, src)))
		return -EHOSTUNREACH;

	hci_dev_lock_bh(hdev);

	err = -ENOMEM;

	hcon = hci_connect(hdev, SCO_LINK, dst);
	if (!hcon)
		goto done;

	conn = sco_conn_add(hcon, 0);
	if (!conn) {
		hci_conn_put(hcon);
		goto done;
	}

	/* Update source addr of the socket */
	bacpy(src, conn->src);

	err = sco_chan_add(conn, sk, NULL);
	if (err)
		goto done;

	if (hcon->state == BT_CONNECTED) {
		sco_sock_clear_timer(sk);
		sk->state = BT_CONNECTED;
	} else {
		sk->state = BT_CONNECT;
		sco_sock_set_timer(sk, sk->sndtimeo);
	}
done:
	hci_dev_unlock_bh(hdev);
	hci_dev_put(hdev);
	return err;
}
示例#5
0
static void sco_conn_ready(struct sco_conn *conn)
{
	struct sock *parent, *sk;

	BT_DBG("conn %p", conn);

	sco_conn_lock(conn);

	if ((sk = conn->sk)) {
		sco_sock_clear_timer(sk);
		bh_lock_sock(sk);
		sk->state = BT_CONNECTED;
		sk->state_change(sk);
		bh_unlock_sock(sk);
	} else {
		parent = sco_get_sock_listen(conn->src);
		if (!parent)
			goto done;

		bh_lock_sock(parent);

		sk = sco_sock_alloc(NULL, BTPROTO_SCO, GFP_ATOMIC);
		if (!sk) {
			bh_unlock_sock(parent);
                	goto done;
		}

		sco_sock_init(sk, parent);

		bacpy(&bluez_pi(sk)->src, conn->src);
		bacpy(&bluez_pi(sk)->dst, conn->dst);

		hci_conn_hold(conn->hcon);
        	__sco_chan_add(conn, sk, parent);

        	sk->state = BT_CONNECTED;

		/* Wake up parent */
		parent->data_ready(parent, 1);
	
        	bh_unlock_sock(parent);
	}

done:
	sco_conn_unlock(conn);
}
示例#6
0
static int sco_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
{
	struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
	struct sock *sk = sock->sk;

	BT_DBG("sock %p, sk %p", sock, sk);

	addr->sa_family = AF_BLUETOOTH;
	*len = sizeof(struct sockaddr_sco);

	if (peer)
		bacpy(&sa->sco_bdaddr, &bluez_pi(sk)->dst);
	else
		bacpy(&sa->sco_bdaddr, &bluez_pi(sk)->src);

	return 0;
}
示例#7
0
static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
{
	struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
	struct sock *sk = sock->sk;

	BT_DBG("sock %p, sk %p", sock, sk);

	addr->sa_family = AF_BLUETOOTH;
	*len = sizeof(struct sockaddr_l2);

	if (peer)
		bacpy(&la->l2_bdaddr, &bluez_pi(sk)->dst);
	else
		bacpy(&la->l2_bdaddr, &bluez_pi(sk)->src);

	la->l2_psm = l2cap_pi(sk)->psm;
	return 0;
}
示例#8
0
/* -------- Socket interface ---------- */
static struct sock *__l2cap_get_sock_by_addr(__u16 psm, bdaddr_t *src)
{
	struct sock *sk;
	for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
		if (sk->sport == psm && !bacmp(&bluez_pi(sk)->src, src))
			break;
	}
	return sk;
}
示例#9
0
static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
{
	struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
	struct sock *sk = sock->sk;
	int err = 0;

	lock_sock(sk);

	BT_DBG("sk %p", sk);

	if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_l2)) {
		err = -EINVAL;
		goto done;
	}

	if (sk->type == SOCK_SEQPACKET && !la->l2_psm) {
		err = -EINVAL;
		goto done;
	}

	switch(sk->state) {
	case BT_CONNECT:
	case BT_CONNECT2:
	case BT_CONFIG:
		/* Already connecting */
		goto wait;

	case BT_CONNECTED:
		/* Already connected */
		goto done;

	case BT_OPEN:
	case BT_BOUND:
		/* Can connect */
		break;

	default:
		err = -EBADFD;
		goto done;
	}

	/* Set destination address and psm */
	bacpy(&bluez_pi(sk)->dst, &la->l2_bdaddr);
	l2cap_pi(sk)->psm = la->l2_psm;

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

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

done:
	release_sock(sk);
	return err;
}
示例#10
0
/* Find socket with psm and source bdaddr.
 * Returns closest match.
 */
static struct sock *__l2cap_get_sock_by_psm(int state, __u16 psm, bdaddr_t *src)
{
	struct sock *sk, *sk1 = NULL;

	for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
		if (state && sk->state != state)
			continue;

		if (l2cap_pi(sk)->psm == psm) {
			/* Exact match. */
			if (!bacmp(&bluez_pi(sk)->src, src))
				break;

			/* Closest match */
			if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY))
				sk1 = sk;
		}
	}
	return sk ? sk : sk1;
}
示例#11
0
/* -------- Socket interface ---------- */
static struct sock *__sco_get_sock_by_addr(bdaddr_t *ba)
{
	struct sock *sk;

	for (sk = sco_sk_list.head; sk; sk = sk->next) {
		if (!bacmp(&bluez_pi(sk)->src, ba))
			break;
	}

	return sk;
}
示例#12
0
/* ----- Proc fs support ------ */
static int l2cap_sock_dump(char *buf, struct bluez_sock_list *list)
{
	struct l2cap_pinfo *pi;
	struct sock *sk;
	char *ptr = buf;

	read_lock_bh(&list->lock);

	for (sk = list->head; sk; sk = sk->next) {
		pi = l2cap_pi(sk);
		ptr += sprintf(ptr, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d 0x%x\n",
				batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst), 
				sk->state, pi->psm, pi->scid, pi->dcid, pi->imtu, pi->omtu,
				pi->link_mode);
	}

	read_unlock_bh(&list->lock);

	ptr += sprintf(ptr, "\n");
	return ptr - buf;
}
示例#13
0
/* ----- Proc fs support ------ */
static int sco_sock_dump(char *buf, struct bluez_sock_list *list)
{
	struct sco_pinfo *pi;
	struct sock *sk;
	char *ptr = buf;

	write_lock_bh(&list->lock);

	for (sk = list->head; sk; sk = sk->next) {
		pi = sco_pi(sk);
		ptr += sprintf(ptr, "%s %s %d\n",
				batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst),
				sk->state); 
	}

	write_unlock_bh(&list->lock);

	ptr += sprintf(ptr, "\n");

	return ptr - buf;
}
示例#14
0
/* Find socket listening on source bdaddr.
 * Returns closest match.
 */
static struct sock *sco_get_sock_listen(bdaddr_t *src)
{
	struct sock *sk, *sk1 = NULL;

	read_lock(&sco_sk_list.lock);

	for (sk = sco_sk_list.head; sk; sk = sk->next) {
		if (sk->state != BT_LISTEN)
			continue;

		/* Exact match. */
		if (!bacmp(&bluez_pi(sk)->src, src))
			break;

		/* Closest match */
		if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY))
			sk1 = sk;
	}

	read_unlock(&sco_sk_list.lock);

	return sk ? sk : sk1;
}
示例#15
0
static void l2cap_chan_ready(struct sock *sk)
{
	struct sock *parent = bluez_pi(sk)->parent;

	BT_DBG("sk %p, parent %p", sk, parent);

	l2cap_pi(sk)->conf_state = 0;
	l2cap_sock_clear_timer(sk);

	if (!parent) {
		/* Outgoing channel.
		 * Wake up socket sleeping on connect.
		 */
		sk->state = BT_CONNECTED;
		sk->state_change(sk);
	} else {
		/* Incomming channel.
		 * Wake up socket sleeping on accept.
		 */
		parent->data_ready(parent, 0);
	}
}
示例#16
0
static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
{
	struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
	struct sock *sk = sock->sk;
	bdaddr_t *src = &sa->sco_bdaddr;
	int err = 0;

	BT_DBG("sk %p %s", sk, batostr(&sa->sco_bdaddr));

	if (!addr || addr->sa_family != AF_BLUETOOTH)
		return -EINVAL;

	lock_sock(sk);

	if (sk->state != BT_OPEN) {
		err = -EBADFD;
		goto done;
	}

	write_lock_bh(&sco_sk_list.lock);

	if (bacmp(src, BDADDR_ANY) && __sco_get_sock_by_addr(src)) {
		err = -EADDRINUSE;
	} else {
	/* Save source address */
	bacpy(&bluez_pi(sk)->src, &sa->sco_bdaddr);
	sk->state = BT_BOUND;
	}

	write_unlock_bh(&sco_sk_list.lock);

done:
	release_sock(sk);

	return err;
}
示例#17
0
static inline int l2cap_connect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
{
	struct l2cap_chan_list *list = &conn->chan_list;
	l2cap_conn_req *req = (l2cap_conn_req *) data;
	l2cap_conn_rsp rsp;
	struct sock *sk, *parent;
	int result = 0, status = 0;

	__u16 dcid = 0, scid = __le16_to_cpu(req->scid);
	__u16 psm  = req->psm;

	BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);

	/* Check if we have socket listening on psm */
	parent = l2cap_get_sock_by_psm(BT_LISTEN, psm, conn->src);
	if (!parent) {
		result = L2CAP_CR_BAD_PSM;
		goto sendresp;
	}

	result = L2CAP_CR_NO_MEM;

	/* Check for backlog size */
	if (parent->ack_backlog > parent->max_ack_backlog) {
		BT_DBG("backlog full %d", parent->ack_backlog); 
		goto response;
	}

	sk = l2cap_sock_alloc(NULL, BTPROTO_L2CAP, GFP_ATOMIC);
	if (!sk)
		goto response;

	write_lock(&list->lock);

	/* Check if we already have channel with that dcid */
	if (__l2cap_get_chan_by_dcid(list, scid)) {
		write_unlock(&list->lock);
		sk->zapped = 1;
		l2cap_sock_kill(sk);
		goto response;
	}

	hci_conn_hold(conn->hcon);

	l2cap_sock_init(sk, parent);
	bacpy(&bluez_pi(sk)->src, conn->src);
	bacpy(&bluez_pi(sk)->dst, conn->dst);
	l2cap_pi(sk)->psm  = psm;
	l2cap_pi(sk)->dcid = scid;

	__l2cap_chan_add(conn, sk, parent);
	dcid = l2cap_pi(sk)->scid;

	l2cap_sock_set_timer(sk, sk->sndtimeo);

	/* Service level security */
	result = L2CAP_CR_PEND;
	status = L2CAP_CS_AUTHEN_PEND;
	sk->state = BT_CONNECT2;
	l2cap_pi(sk)->ident = cmd->ident;
	
	if (l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) {
		if (!hci_conn_encrypt(conn->hcon))
			goto done;
	} else if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH) {
		if (!hci_conn_auth(conn->hcon))
			goto done;
	}

	sk->state = BT_CONFIG;
	result = status = 0;

done:
	write_unlock(&list->lock);

response:
	bh_unlock_sock(parent);

sendresp:
	rsp.scid   = __cpu_to_le16(scid);
	rsp.dcid   = __cpu_to_le16(dcid);
	rsp.result = __cpu_to_le16(result);
	rsp.status = __cpu_to_le16(status);
	l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, L2CAP_CONN_RSP_SIZE, &rsp);
	return 0;
}