Ejemplo n.º 1
0
static inline void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
{
	__u32 mask = hci_pi(sk)->cmsg_mask;

	if (mask & HCI_CMSG_DIR)
        	put_cmsg(msg, SOL_HCI, HCI_CMSG_DIR, sizeof(int), &bluez_cb(skb)->incomming);

	if (mask & HCI_CMSG_TSTAMP)
        	put_cmsg(msg, SOL_HCI, HCI_CMSG_TSTAMP, sizeof(skb->stamp), &skb->stamp);
}
Ejemplo n.º 2
0
int hci_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
{
	struct sock *sk = sock->sk;
	int len, opt; 

	if (get_user(len, optlen))
		return -EFAULT;

	switch (optname) {
	case HCI_DATA_DIR:
		if (hci_pi(sk)->cmsg_mask & HCI_CMSG_DIR)
			opt = 1;
		else 
			opt = 0;

		if (put_user(opt, optval))
			return -EFAULT;
		break;

	case HCI_TIME_STAMP:
		if (hci_pi(sk)->cmsg_mask & HCI_CMSG_TSTAMP)
			opt = 1;
		else 
			opt = 0;

		if (put_user(opt, optval))
			return -EFAULT;
		break;

	case HCI_FILTER:
		len = MIN(len, sizeof(struct hci_filter));
		if (copy_to_user(optval, &hci_pi(sk)->filter, len))
			return -EFAULT;
		break;

	default:
		return -ENOPROTOOPT;
		break;
	};

	return 0;
}
Ejemplo n.º 3
0
/* Send frame to RAW socket */
void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct sock * sk;

	DBG("hdev %p len %d", hdev, skb->len);

	read_lock(&hci_sk_list.lock);
	for (sk = hci_sk_list.head; sk; sk = sk->next) {
		struct hci_filter *flt;	
		struct sk_buff *nskb;

		if (sk->state != BT_BOUND || hci_pi(sk)->hdev != hdev)
			continue;

		/* Don't send frame to the socket it came from */
		if (skb->sk == sk)
			continue;

		/* Apply filter */
		flt = &hci_pi(sk)->filter;

		if (!test_bit(skb->pkt_type, &flt->type_mask))
			continue;

		if (skb->pkt_type == HCI_EVENT_PKT) {
			register int evt = (*(__u8 *)skb->data & 63);

			if (!test_bit(evt, &flt->event_mask))
				continue;
		}

		if (!(nskb = skb_clone(skb, GFP_ATOMIC)))
			continue;

		/* Put type byte before the data */
		memcpy(skb_push(nskb, 1), &nskb->pkt_type, 1);

		skb_queue_tail(&sk->receive_queue, nskb);
		sk->data_ready(sk, nskb->len);
	}
	read_unlock(&hci_sk_list.lock);
}
Ejemplo n.º 4
0
static struct sock *hci_sock_lookup(struct hci_dev *hdev)
{
	struct sock *sk;

	read_lock(&hci_sk_list.lock);
	for (sk = hci_sk_list.head; sk; sk = sk->next) {
		if (hci_pi(sk)->hdev == hdev)
			break;
	}
	read_unlock(&hci_sk_list.lock);
	return sk;
}
Ejemplo n.º 5
0
static int hci_sock_getname(struct socket *sock, struct sockaddr *addr, int *addr_len, int peer)
{
	struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr;
	struct sock *sk = sock->sk;

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

	*addr_len = sizeof(*haddr);
	haddr->hci_family = AF_BLUETOOTH;
	haddr->hci_dev    = hci_pi(sk)->hdev->id;

	return 0;
}
Ejemplo n.º 6
0
int hci_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int len)
{
	struct sock *sk = sock->sk;
	struct hci_filter flt;
	int err = 0, opt = 0;

	DBG("sk %p, opt %d", sk, optname);

	lock_sock(sk);

	switch (optname) {
	case HCI_DATA_DIR:
		if (get_user(opt, (int *)optval))
			return -EFAULT;

		if (opt)
			hci_pi(sk)->cmsg_mask |= HCI_CMSG_DIR;
		else
			hci_pi(sk)->cmsg_mask &= ~HCI_CMSG_DIR;
		break;

	case HCI_FILTER:
		len = MIN(len, sizeof(struct hci_filter));
		if (copy_from_user(&flt, optval, len)) {
			err = -EFAULT;
			break;
		}
		memcpy(&hci_pi(sk)->filter, &flt, len);
		break;

	default:
		err = -ENOPROTOOPT;
		break;
	};

	release_sock(sk);
	return err;
}
Ejemplo n.º 7
0
static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len,
                            struct scm_cookie *scm)
{
	struct sock *sk = sock->sk;
	struct hci_dev *hdev = hci_pi(sk)->hdev;
	struct sk_buff *skb;
	int err;

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

	if (msg->msg_flags & MSG_OOB)
		return -EOPNOTSUPP;

	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE))
		return -EINVAL;

	if (!hdev)
		return -EBADFD;

	if (!(skb = bluez_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err)))
		return err;

	if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
		kfree_skb(skb);
		return -EFAULT;
	}

	skb->dev = (void *) hdev;
	skb->pkt_type = *((unsigned char *) skb->data);
	skb_pull(skb, 1);

	/* Send frame to HCI core */
	hci_send_raw(skb);

	return len;
}
Ejemplo n.º 8
0
static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len,
                            struct scm_cookie *scm)
{
	struct sock *sk = sock->sk;
	struct hci_dev *hdev;
	struct sk_buff *skb;
	int err;

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

	if (msg->msg_flags & MSG_OOB)
		return -EOPNOTSUPP;

	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE))
		return -EINVAL;

	if (len < 4)
		return -EINVAL;
	
	lock_sock(sk);

	if (!(hdev = hci_pi(sk)->hdev)) {
		err = -EBADFD;
		goto done;
	}

	if (!(skb = bluez_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err)))
		goto done;

	if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
		err = -EFAULT;
		goto drop;
	}

	skb->pkt_type = *((unsigned char *) skb->data);
	skb_pull(skb, 1);
	skb->dev = (void *) hdev;

	if (skb->pkt_type == HCI_COMMAND_PKT) {
		u16 opcode = __le16_to_cpu(get_unaligned((u16 *)skb->data));
		u16 ogf = cmd_opcode_ogf(opcode);
		u16 ocf = cmd_opcode_ocf(opcode);

		if (((ogf > HCI_SFLT_MAX_OGF) || 
				!hci_test_bit(ocf & HCI_FLT_OCF_BITS, &hci_sec_filter.ocf_mask[ogf])) &&
		    			!capable(CAP_NET_RAW)) {
			err = -EPERM;
			goto drop;
		}

		if (test_bit(HCI_RAW, &hdev->flags) || (ogf == OGF_VENDOR_CMD)) {
			skb_queue_tail(&hdev->raw_q, skb);
			hci_sched_tx(hdev);
		} else {
			skb_queue_tail(&hdev->cmd_q, skb);
			hci_sched_cmd(hdev);
		}
	} else {
		if (!capable(CAP_NET_RAW)) {
			err = -EPERM;
			goto drop;
		}

		skb_queue_tail(&hdev->raw_q, skb);
		hci_sched_tx(hdev);
	}

	err = len;

done:
	release_sock(sk);
	return err;

drop:
	kfree_skb(skb);
	goto done;
}
Ejemplo n.º 9
0
static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
	struct sock *sk = sock->sk;
	struct hci_dev *hdev = hci_pi(sk)->hdev;
	__u32 mode;

	DBG("cmd %x arg %lx", cmd, arg);

	switch (cmd) {
	case HCIGETINFO:
		return hci_dev_info(arg);

	case HCIGETDEVLIST:
		return hci_dev_list(arg);

	case HCIDEVUP:
		if (!capable(CAP_NET_ADMIN))
			return -EACCES;
		return hci_dev_open(arg);

	case HCIDEVDOWN:
		if (!capable(CAP_NET_ADMIN))
			return -EACCES;
		return hci_dev_close(arg);

	case HCIDEVRESET:
		if (!capable(CAP_NET_ADMIN))
			return -EACCES;
		return hci_dev_reset(arg);

	case HCIRESETSTAT:
		if (!capable(CAP_NET_ADMIN))
			return -EACCES;
		return hci_dev_reset_stat(arg);

	case HCISETSCAN:
		if (!capable(CAP_NET_ADMIN))
			return -EACCES;
		return hci_dev_setscan(arg);

	case HCISETAUTH:
		if (!capable(CAP_NET_ADMIN))
			return -EACCES;
		return hci_dev_setauth(arg);

	case HCISETRAW:
		if (!capable(CAP_NET_ADMIN))
			return -EACCES;

		if (!hdev)
			return -EBADFD;

		if (arg)
			mode = HCI_RAW;
		else
			mode = HCI_NORMAL;

		return hci_dev_setmode(hdev, mode);

	case HCISETPTYPE:
		if (!capable(CAP_NET_ADMIN))
			return -EACCES;
		return hci_dev_setptype(arg);

	case HCIINQUIRY:
		return hci_inquiry(arg);

	case HCIGETCONNLIST:
		return hci_conn_list(arg);

	default:
		return -EINVAL;
	};
}
Ejemplo n.º 10
0
int hci_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int len)
{
	struct sock *sk = sock->sk;
	struct hci_filter flt = { opcode: 0 };
	int err = 0, opt = 0;

	BT_DBG("sk %p, opt %d", sk, optname);

	lock_sock(sk);

	switch (optname) {
	case HCI_DATA_DIR:
		if (get_user(opt, (int *)optval)) {
			err = -EFAULT;
			break;
		}

		if (opt)
			hci_pi(sk)->cmsg_mask |= HCI_CMSG_DIR;
		else
			hci_pi(sk)->cmsg_mask &= ~HCI_CMSG_DIR;
		break;

	case HCI_TIME_STAMP:
		if (get_user(opt, (int *)optval)) {
			err = -EFAULT;
			break;
		}

		if (opt)
			hci_pi(sk)->cmsg_mask |= HCI_CMSG_TSTAMP;
		else
			hci_pi(sk)->cmsg_mask &= ~HCI_CMSG_TSTAMP;
		break;

	case HCI_FILTER:
		memcpy(&flt, &hci_pi(sk)->filter, len);

		len = MIN(len, sizeof(struct hci_filter));
		if (copy_from_user(&flt, optval, len)) {
			err = -EFAULT;
			break;
		}

		if (!capable(CAP_NET_RAW)) {
			flt.type_mask     &= hci_sec_filter.type_mask;
			flt.event_mask[0] &= hci_sec_filter.event_mask[0];
			flt.event_mask[1] &= hci_sec_filter.event_mask[1];
		}
		
		memcpy(&hci_pi(sk)->filter, &flt, len);
		break;

	default:
		err = -ENOPROTOOPT;
		break;
	};

	release_sock(sk);
	return err;
}
Ejemplo n.º 11
0
static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len,
                            struct scm_cookie *scm)
{
	struct sock *sk = sock->sk;
	struct hci_dev *hdev;
	struct sk_buff *skb;
	int err;

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

	if (msg->msg_flags & MSG_OOB)
		return -EOPNOTSUPP;

	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE))
		return -EINVAL;

	if (len < 4)
		return -EINVAL;
	
	lock_sock(sk);

	if (!(hdev = hci_pi(sk)->hdev)) {
		err = -EBADFD;
		goto done;
	}

	if (!(skb = bluez_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err)))
		goto done;

	if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
		err = -EFAULT;
		goto drop;
	}

	skb->pkt_type = *((unsigned char *) skb->data);
	skb_pull(skb, 1);

	if (!capable(CAP_NET_RAW)) {
		err = -EPERM;

		if (skb->pkt_type == HCI_COMMAND_PKT) {
			__u16 opcode = __le16_to_cpu(*(__u16 *)skb->data);
			__u16 ogf = cmd_opcode_ogf(opcode) - 1;
			__u16 ocf = cmd_opcode_ocf(opcode) & HCI_FLT_OCF_BITS;

			if (ogf > HCI_SFLT_MAX_OGF ||
					!hci_test_bit(ocf, &hci_sec_filter.ocf_mask[ogf]))
				goto drop;
		} else
			goto drop;
	}
		
	/* Send frame to HCI core */
	skb->dev = (void *) hdev;
	hci_send_raw(skb);
	err = len;

done:
	release_sock(sk);
	return err;

drop:
	kfree_skb(skb);
	goto done;
}