Commit 4a1d861e authored by David S. Miller's avatar David S. Miller

Merge http://linux-mh.bkbits.net/bluetooth-2.6

into nuts.davemloft.net:/disk1/BK/bt-2.6
parents bfb17dbd f26ab3da
...@@ -253,6 +253,17 @@ struct hci_cp_write_dev_class { ...@@ -253,6 +253,17 @@ struct hci_cp_write_dev_class {
__u8 dev_class[3]; __u8 dev_class[3];
} __attribute__ ((packed)); } __attribute__ ((packed));
#define OCF_READ_VOICE_SETTING 0x0025
struct hci_rp_read_voice_setting {
__u8 status;
__u16 voice_setting;
} __attribute__ ((packed));
#define OCF_WRITE_VOICE_SETTING 0x0026
struct hci_cp_write_voice_setting {
__u16 voice_setting;
} __attribute__ ((packed));
#define OCF_HOST_BUFFER_SIZE 0x0033 #define OCF_HOST_BUFFER_SIZE 0x0033
struct hci_cp_host_buffer_size { struct hci_cp_host_buffer_size {
__u16 acl_mtu; __u16 acl_mtu;
......
...@@ -71,11 +71,12 @@ struct hci_dev { ...@@ -71,11 +71,12 @@ struct hci_dev {
__u8 type; __u8 type;
bdaddr_t bdaddr; bdaddr_t bdaddr;
__u8 features[8]; __u8 features[8];
__u16 voice_setting;
__u16 pkt_type; __u16 pkt_type;
__u16 link_policy; __u16 link_policy;
__u16 link_mode; __u16 link_mode;
atomic_t cmd_cnt; atomic_t cmd_cnt;
unsigned int acl_cnt; unsigned int acl_cnt;
unsigned int sco_cnt; unsigned int sco_cnt;
...@@ -88,7 +89,7 @@ struct hci_dev { ...@@ -88,7 +89,7 @@ struct hci_dev {
unsigned long cmd_last_tx; unsigned long cmd_last_tx;
unsigned long acl_last_tx; unsigned long acl_last_tx;
unsigned long sco_last_tx; unsigned long sco_last_tx;
struct tasklet_struct cmd_task; struct tasklet_struct cmd_task;
struct tasklet_struct rx_task; struct tasklet_struct rx_task;
struct tasklet_struct tx_task; struct tasklet_struct tx_task;
...@@ -119,7 +120,7 @@ struct hci_dev { ...@@ -119,7 +120,7 @@ struct hci_dev {
#endif #endif
struct module *owner; struct module *owner;
int (*open)(struct hci_dev *hdev); int (*open)(struct hci_dev *hdev);
int (*close)(struct hci_dev *hdev); int (*close)(struct hci_dev *hdev);
int (*flush)(struct hci_dev *hdev); int (*flush)(struct hci_dev *hdev);
......
...@@ -236,15 +236,31 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock, ...@@ -236,15 +236,31 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
return err ? : copied; return err ? : copied;
} }
static inline unsigned int bt_accept_poll(struct sock *parent)
{
struct list_head *p, *n;
struct sock *sk;
list_for_each_safe(p, n, &bt_sk(parent)->accept_q) {
sk = (struct sock *) list_entry(p, struct bt_sock, accept_q);
if (sk->sk_state == BT_CONNECTED)
return POLLIN | POLLRDNORM;
}
return 0;
}
unsigned int bt_sock_poll(struct file * file, struct socket *sock, poll_table *wait) unsigned int bt_sock_poll(struct file * file, struct socket *sock, poll_table *wait)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
unsigned int mask; unsigned int mask = 0;
BT_DBG("sock %p, sk %p", sock, sk); BT_DBG("sock %p, sk %p", sock, sk);
poll_wait(file, sk->sk_sleep, wait); poll_wait(file, sk->sk_sleep, wait);
mask = 0;
if (sk->sk_state == BT_LISTEN)
return bt_accept_poll(sk);
if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
mask |= POLLERR; mask |= POLLERR;
...@@ -253,16 +269,17 @@ unsigned int bt_sock_poll(struct file * file, struct socket *sock, poll_table *w ...@@ -253,16 +269,17 @@ unsigned int bt_sock_poll(struct file * file, struct socket *sock, poll_table *w
mask |= POLLHUP; mask |= POLLHUP;
if (!skb_queue_empty(&sk->sk_receive_queue) || if (!skb_queue_empty(&sk->sk_receive_queue) ||
!list_empty(&bt_sk(sk)->accept_q) ||
(sk->sk_shutdown & RCV_SHUTDOWN)) (sk->sk_shutdown & RCV_SHUTDOWN))
mask |= POLLIN | POLLRDNORM; mask |= POLLIN | POLLRDNORM;
if (sk->sk_state == BT_CLOSED) if (sk->sk_state == BT_CLOSED)
mask |= POLLHUP; mask |= POLLHUP;
if (sk->sk_state == BT_CONNECT || sk->sk_state == BT_CONNECT2) if (sk->sk_state == BT_CONNECT ||
sk->sk_state == BT_CONNECT2 ||
sk->sk_state == BT_CONFIG)
return mask; return mask;
if (sock_writeable(sk)) if (sock_writeable(sk))
mask |= POLLOUT | POLLWRNORM | POLLWRBAND; mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
else else
......
...@@ -93,8 +93,10 @@ static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long ...@@ -93,8 +93,10 @@ static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long
if (!nsock) if (!nsock)
return err; return err;
if (nsock->sk->sk_state != BT_CONNECTED) if (nsock->sk->sk_state != BT_CONNECTED) {
fput(nsock->file);
return -EBADFD; return -EBADFD;
}
err = bnep_add_connection(&ca, nsock); err = bnep_add_connection(&ca, nsock);
if (!err) { if (!err) {
......
...@@ -87,8 +87,10 @@ static int cmtp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long ...@@ -87,8 +87,10 @@ static int cmtp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long
if (!nsock) if (!nsock)
return err; return err;
if (nsock->sk->sk_state != BT_CONNECTED) if (nsock->sk->sk_state != BT_CONNECTED) {
fput(nsock->file);
return -EBADFD; return -EBADFD;
}
err = cmtp_add_connection(&ca, nsock); err = cmtp_add_connection(&ca, nsock);
if (!err) { if (!err) {
......
...@@ -353,21 +353,24 @@ int hci_get_conn_list(unsigned long arg) ...@@ -353,21 +353,24 @@ int hci_get_conn_list(unsigned long arg)
struct hci_conn_info *ci; struct hci_conn_info *ci;
struct hci_dev *hdev; struct hci_dev *hdev;
struct list_head *p; struct list_head *p;
int n = 0, size; int n = 0, size, err;
if (copy_from_user(&req, (void *) arg, sizeof(req))) if (copy_from_user(&req, (void *) arg, sizeof(req)))
return -EFAULT; return -EFAULT;
if (!(hdev = hci_dev_get(req.dev_id))) if (!req.conn_num || req.conn_num > (PAGE_SIZE * 2) / sizeof(*ci))
return -ENODEV; return -EINVAL;
size = req.conn_num * sizeof(struct hci_conn_info) + sizeof(req);
if (verify_area(VERIFY_WRITE, (void *)arg, size)) size = sizeof(req) + req.conn_num * sizeof(*ci);
return -EFAULT;
if (!(cl = (void *) kmalloc(size, GFP_KERNEL))) if (!(cl = (void *) kmalloc(size, GFP_KERNEL)))
return -ENOMEM; return -ENOMEM;
if (!(hdev = hci_dev_get(req.dev_id))) {
kfree(cl);
return -ENODEV;
}
ci = cl->conn_info; ci = cl->conn_info;
hci_dev_lock_bh(hdev); hci_dev_lock_bh(hdev);
...@@ -381,20 +384,21 @@ int hci_get_conn_list(unsigned long arg) ...@@ -381,20 +384,21 @@ int hci_get_conn_list(unsigned long arg)
(ci + n)->out = c->out; (ci + n)->out = c->out;
(ci + n)->state = c->state; (ci + n)->state = c->state;
(ci + n)->link_mode = c->link_mode; (ci + n)->link_mode = c->link_mode;
n++; if (++n >= req.conn_num)
break;
} }
hci_dev_unlock_bh(hdev); hci_dev_unlock_bh(hdev);
cl->dev_id = hdev->id; cl->dev_id = hdev->id;
cl->conn_num = n; cl->conn_num = n;
size = n * sizeof(struct hci_conn_info) + sizeof(req); size = sizeof(req) + n * sizeof(*ci);
hci_dev_put(hdev); hci_dev_put(hdev);
copy_to_user((void *) arg, cl, size); err = copy_to_user((void *) arg, cl, size);
kfree(cl); kfree(cl);
return 0; return err ? -EFAULT : 0;
} }
int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg) int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg)
...@@ -407,9 +411,6 @@ int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg) ...@@ -407,9 +411,6 @@ int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg)
if (copy_from_user(&req, (void *) arg, sizeof(req))) if (copy_from_user(&req, (void *) arg, sizeof(req)))
return -EFAULT; return -EFAULT;
if (verify_area(VERIFY_WRITE, ptr, sizeof(ci)))
return -EFAULT;
hci_dev_lock_bh(hdev); hci_dev_lock_bh(hdev);
conn = hci_conn_hash_lookup_ba(hdev, req.type, &req.bdaddr); conn = hci_conn_hash_lookup_ba(hdev, req.type, &req.bdaddr);
if (conn) { if (conn) {
...@@ -425,6 +426,5 @@ int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg) ...@@ -425,6 +426,5 @@ int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg)
if (!conn) if (!conn)
return -ENOENT; return -ENOENT;
copy_to_user(ptr, &ci, sizeof(ci)); return copy_to_user(ptr, &ci, sizeof(ci)) ? -EFAULT : 0;
return 0;
} }
...@@ -237,6 +237,9 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt) ...@@ -237,6 +237,9 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
/* Read BD Address */ /* Read BD Address */
hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BD_ADDR, 0, NULL); hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BD_ADDR, 0, NULL);
/* Read Voice Setting */
hci_send_cmd(hdev, OGF_HOST_CTL, OCF_READ_VOICE_SETTING, 0, NULL);
/* Optional initialization */ /* Optional initialization */
/* Clear Event Filters */ /* Clear Event Filters */
...@@ -713,22 +716,20 @@ int hci_get_dev_list(unsigned long arg) ...@@ -713,22 +716,20 @@ int hci_get_dev_list(unsigned long arg)
struct hci_dev_list_req *dl; struct hci_dev_list_req *dl;
struct hci_dev_req *dr; struct hci_dev_req *dr;
struct list_head *p; struct list_head *p;
int n = 0, size; int n = 0, size, err;
__u16 dev_num; __u16 dev_num;
if (get_user(dev_num, (__u16 *) arg)) if (get_user(dev_num, (__u16 *) arg))
return -EFAULT; return -EFAULT;
if (!dev_num) if (!dev_num || dev_num > (PAGE_SIZE * 2) / sizeof(*dr))
return -EINVAL; return -EINVAL;
size = dev_num * sizeof(*dr) + sizeof(*dl);
if (verify_area(VERIFY_WRITE, (void *) arg, size)) size = sizeof(*dl) + dev_num * sizeof(*dr);
return -EFAULT;
if (!(dl = kmalloc(size, GFP_KERNEL))) if (!(dl = kmalloc(size, GFP_KERNEL)))
return -ENOMEM; return -ENOMEM;
dr = dl->dev_req; dr = dl->dev_req;
read_lock_bh(&hci_dev_list_lock); read_lock_bh(&hci_dev_list_lock);
...@@ -743,12 +744,12 @@ int hci_get_dev_list(unsigned long arg) ...@@ -743,12 +744,12 @@ int hci_get_dev_list(unsigned long arg)
read_unlock_bh(&hci_dev_list_lock); read_unlock_bh(&hci_dev_list_lock);
dl->dev_num = n; dl->dev_num = n;
size = n * sizeof(*dr) + sizeof(*dl); size = sizeof(*dl) + n * sizeof(*dr);
copy_to_user((void *) arg, dl, size); err = copy_to_user((void *) arg, dl, size);
kfree(dl); kfree(dl);
return 0; return err ? -EFAULT : 0;
} }
int hci_get_dev_info(unsigned long arg) int hci_get_dev_info(unsigned long arg)
......
...@@ -123,6 +123,8 @@ static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff * ...@@ -123,6 +123,8 @@ static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *
static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
{ {
__u8 status, param; __u8 status, param;
__u16 setting;
struct hci_rp_read_voice_setting *vs;
void *sent; void *sent;
BT_DBG("%s ocf 0x%x", hdev->name, ocf); BT_DBG("%s ocf 0x%x", hdev->name, ocf);
...@@ -198,6 +200,7 @@ static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb ...@@ -198,6 +200,7 @@ static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb
sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE); sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE);
if (!sent) if (!sent)
break; break;
status = *((__u8 *) skb->data); status = *((__u8 *) skb->data);
param = *((__u8 *) sent); param = *((__u8 *) sent);
...@@ -215,6 +218,39 @@ static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb ...@@ -215,6 +218,39 @@ static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb
hci_req_complete(hdev, status); hci_req_complete(hdev, status);
break; break;
case OCF_READ_VOICE_SETTING:
vs = (struct hci_rp_read_voice_setting *) skb->data;
if (vs->status) {
BT_DBG("%s READ_VOICE_SETTING failed %d", hdev->name, vc->status);
break;
}
setting = __le16_to_cpu(vs->voice_setting);
if (hdev->voice_setting != setting ) {
hdev->voice_setting = setting;
BT_DBG("%s: voice setting 0x%04x", hdev->name, setting);
}
break;
case OCF_WRITE_VOICE_SETTING:
sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_VOICE_SETTING);
if (!sent)
break;
status = *((__u8 *) skb->data);
setting = __le16_to_cpu(get_unaligned((__u16 *) sent));
if (!status && hdev->voice_setting != setting) {
hdev->voice_setting = setting;
BT_DBG("%s: voice setting 0x%04x", hdev->name, setting);
}
hci_req_complete(hdev, status);
break;
case OCF_HOST_BUFFER_SIZE: case OCF_HOST_BUFFER_SIZE:
status = *((__u8 *) skb->data); status = *((__u8 *) skb->data);
if (status) { if (status) {
...@@ -282,7 +318,7 @@ static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *s ...@@ -282,7 +318,7 @@ static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *s
hdev->sco_pkts = hdev->sco_cnt = __le16_to_cpu(bs->sco_max_pkt); hdev->sco_pkts = hdev->sco_cnt = __le16_to_cpu(bs->sco_max_pkt);
BT_DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name, BT_DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name,
hdev->acl_mtu, hdev->sco_mtu, hdev->acl_pkts, hdev->sco_pkts); hdev->acl_mtu, hdev->sco_mtu, hdev->acl_pkts, hdev->sco_pkts);
break; break;
case OCF_READ_BD_ADDR: case OCF_READ_BD_ADDR:
......
...@@ -1663,9 +1663,10 @@ static inline void rfcomm_accept_connection(struct rfcomm_session *s) ...@@ -1663,9 +1663,10 @@ static inline void rfcomm_accept_connection(struct rfcomm_session *s)
nsock->sk->sk_state_change = rfcomm_l2state_change; nsock->sk->sk_state_change = rfcomm_l2state_change;
s = rfcomm_session_add(nsock, BT_OPEN); s = rfcomm_session_add(nsock, BT_OPEN);
if (s) if (s) {
rfcomm_session_hold(s); rfcomm_session_hold(s);
else rfcomm_schedule(RFCOMM_SCHED_RX);
} else
sock_release(nsock); sock_release(nsock);
} }
......
...@@ -349,7 +349,7 @@ static int rfcomm_get_dev_list(unsigned long arg) ...@@ -349,7 +349,7 @@ static int rfcomm_get_dev_list(unsigned long arg)
struct rfcomm_dev_list_req *dl; struct rfcomm_dev_list_req *dl;
struct rfcomm_dev_info *di; struct rfcomm_dev_info *di;
struct list_head *p; struct list_head *p;
int n = 0, size; int n = 0, size, err;
u16 dev_num; u16 dev_num;
BT_DBG(""); BT_DBG("");
...@@ -357,14 +357,11 @@ static int rfcomm_get_dev_list(unsigned long arg) ...@@ -357,14 +357,11 @@ static int rfcomm_get_dev_list(unsigned long arg)
if (get_user(dev_num, (u16 *) arg)) if (get_user(dev_num, (u16 *) arg))
return -EFAULT; return -EFAULT;
if (!dev_num) if (!dev_num || dev_num > (PAGE_SIZE * 4) / sizeof(*di))
return -EINVAL; return -EINVAL;
size = sizeof(*dl) + dev_num * sizeof(*di); size = sizeof(*dl) + dev_num * sizeof(*di);
if (verify_area(VERIFY_WRITE, (void *)arg, size))
return -EFAULT;
if (!(dl = kmalloc(size, GFP_KERNEL))) if (!(dl = kmalloc(size, GFP_KERNEL)))
return -ENOMEM; return -ENOMEM;
...@@ -389,9 +386,10 @@ static int rfcomm_get_dev_list(unsigned long arg) ...@@ -389,9 +386,10 @@ static int rfcomm_get_dev_list(unsigned long arg)
dl->dev_num = n; dl->dev_num = n;
size = sizeof(*dl) + n * sizeof(*di); size = sizeof(*dl) + n * sizeof(*di);
copy_to_user((void *) arg, dl, size); err = copy_to_user((void *) arg, dl, size);
kfree(dl); kfree(dl);
return 0;
return err ? -EFAULT : 0;
} }
static int rfcomm_get_dev_info(unsigned long arg) static int rfcomm_get_dev_info(unsigned long arg)
...@@ -563,8 +561,10 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) ...@@ -563,8 +561,10 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
set_bit(RFCOMM_TTY_ATTACHED, &dev->flags); set_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
err = rfcomm_dlc_open(dlc, &dev->src, &dev->dst, dev->channel); err = rfcomm_dlc_open(dlc, &dev->src, &dev->dst, dev->channel);
if (err < 0) if (err < 0) {
rfcomm_dev_put(dev);
return err; return err;
}
/* Wait for DLC to connect */ /* Wait for DLC to connect */
add_wait_queue(&dev->wait, &wait); add_wait_queue(&dev->wait, &wait);
...@@ -589,6 +589,9 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) ...@@ -589,6 +589,9 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
remove_wait_queue(&dev->wait, &wait); remove_wait_queue(&dev->wait, &wait);
if (err < 0)
rfcomm_dev_put(dev);
return err; return err;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment