Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth-next-2.6 into for-davem
This commit is contained in:
commit
1a63c353c8
|
@ -1358,16 +1358,19 @@ F: drivers/mtd/devices/block2mtd.c
|
||||||
|
|
||||||
BLUETOOTH DRIVERS
|
BLUETOOTH DRIVERS
|
||||||
M: Marcel Holtmann <marcel@holtmann.org>
|
M: Marcel Holtmann <marcel@holtmann.org>
|
||||||
|
M: Gustavo F. Padovan <padovan@profusion.mobi>
|
||||||
L: linux-bluetooth@vger.kernel.org
|
L: linux-bluetooth@vger.kernel.org
|
||||||
W: http://www.bluez.org/
|
W: http://www.bluez.org/
|
||||||
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth-2.6.git
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/bluetooth/
|
F: drivers/bluetooth/
|
||||||
|
|
||||||
BLUETOOTH SUBSYSTEM
|
BLUETOOTH SUBSYSTEM
|
||||||
M: Marcel Holtmann <marcel@holtmann.org>
|
M: Marcel Holtmann <marcel@holtmann.org>
|
||||||
|
M: Gustavo F. Padovan <padovan@profusion.mobi>
|
||||||
L: linux-bluetooth@vger.kernel.org
|
L: linux-bluetooth@vger.kernel.org
|
||||||
W: http://www.bluez.org/
|
W: http://www.bluez.org/
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/holtmann/bluetooth-2.6.git
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth-2.6.git
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: net/bluetooth/
|
F: net/bluetooth/
|
||||||
F: include/net/bluetooth/
|
F: include/net/bluetooth/
|
||||||
|
|
|
@ -117,8 +117,8 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb)
|
||||||
(event->data[2] == MODULE_ALREADY_UP)) ?
|
(event->data[2] == MODULE_ALREADY_UP)) ?
|
||||||
"Bring-up succeed" : "Bring-up failed");
|
"Bring-up succeed" : "Bring-up failed");
|
||||||
|
|
||||||
if (event->length > 3)
|
if (event->length > 3 && event->data[3])
|
||||||
priv->btmrvl_dev.dev_type = event->data[3];
|
priv->btmrvl_dev.dev_type = HCI_AMP;
|
||||||
else
|
else
|
||||||
priv->btmrvl_dev.dev_type = HCI_BREDR;
|
priv->btmrvl_dev.dev_type = HCI_BREDR;
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,9 @@ static const struct sdio_device_id btsdio_table[] = {
|
||||||
/* Generic Bluetooth Type-B SDIO device */
|
/* Generic Bluetooth Type-B SDIO device */
|
||||||
{ SDIO_DEVICE_CLASS(SDIO_CLASS_BT_B) },
|
{ SDIO_DEVICE_CLASS(SDIO_CLASS_BT_B) },
|
||||||
|
|
||||||
|
/* Generic Bluetooth AMP controller */
|
||||||
|
{ SDIO_DEVICE_CLASS(SDIO_CLASS_BT_AMP) },
|
||||||
|
|
||||||
{ } /* Terminating entry */
|
{ } /* Terminating entry */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -329,6 +332,11 @@ static int btsdio_probe(struct sdio_func *func,
|
||||||
hdev->bus = HCI_SDIO;
|
hdev->bus = HCI_SDIO;
|
||||||
hdev->driver_data = data;
|
hdev->driver_data = data;
|
||||||
|
|
||||||
|
if (id->class == SDIO_CLASS_BT_AMP)
|
||||||
|
hdev->dev_type = HCI_AMP;
|
||||||
|
else
|
||||||
|
hdev->dev_type = HCI_BREDR;
|
||||||
|
|
||||||
data->hdev = hdev;
|
data->hdev = hdev;
|
||||||
|
|
||||||
SET_HCIDEV_DEV(hdev, &func->dev);
|
SET_HCIDEV_DEV(hdev, &func->dev);
|
||||||
|
|
|
@ -59,9 +59,15 @@ static struct usb_device_id btusb_table[] = {
|
||||||
/* Generic Bluetooth USB device */
|
/* Generic Bluetooth USB device */
|
||||||
{ USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
|
{ USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
|
||||||
|
|
||||||
|
/* Apple MacBookPro 7,1 */
|
||||||
|
{ USB_DEVICE(0x05ac, 0x8213) },
|
||||||
|
|
||||||
/* Apple iMac11,1 */
|
/* Apple iMac11,1 */
|
||||||
{ USB_DEVICE(0x05ac, 0x8215) },
|
{ USB_DEVICE(0x05ac, 0x8215) },
|
||||||
|
|
||||||
|
/* Apple MacBookPro6,2 */
|
||||||
|
{ USB_DEVICE(0x05ac, 0x8218) },
|
||||||
|
|
||||||
/* AVM BlueFRITZ! USB v2.0 */
|
/* AVM BlueFRITZ! USB v2.0 */
|
||||||
{ USB_DEVICE(0x057c, 0x3800) },
|
{ USB_DEVICE(0x057c, 0x3800) },
|
||||||
|
|
||||||
|
|
|
@ -101,7 +101,7 @@ static inline void hci_uart_tx_complete(struct hci_uart *hu, int pkt_type)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HCI_SCODATA_PKT:
|
case HCI_SCODATA_PKT:
|
||||||
hdev->stat.cmd_tx++;
|
hdev->stat.sco_tx++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#define SDIO_CLASS_PHS 0x06 /* PHS standard interface */
|
#define SDIO_CLASS_PHS 0x06 /* PHS standard interface */
|
||||||
#define SDIO_CLASS_WLAN 0x07 /* WLAN interface */
|
#define SDIO_CLASS_WLAN 0x07 /* WLAN interface */
|
||||||
#define SDIO_CLASS_ATA 0x08 /* Embedded SDIO-ATA std interface */
|
#define SDIO_CLASS_ATA 0x08 /* Embedded SDIO-ATA std interface */
|
||||||
|
#define SDIO_CLASS_BT_AMP 0x09 /* Type-A Bluetooth AMP interface */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Vendors and devices. Sort key: vendor first, device next.
|
* Vendors and devices. Sort key: vendor first, device next.
|
||||||
|
|
|
@ -126,6 +126,8 @@ int bt_sock_unregister(int proto);
|
||||||
void bt_sock_link(struct bt_sock_list *l, struct sock *s);
|
void bt_sock_link(struct bt_sock_list *l, struct sock *s);
|
||||||
void bt_sock_unlink(struct bt_sock_list *l, struct sock *s);
|
void bt_sock_unlink(struct bt_sock_list *l, struct sock *s);
|
||||||
int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags);
|
int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags);
|
||||||
|
int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||||||
|
struct msghdr *msg, size_t len, int flags);
|
||||||
uint bt_sock_poll(struct file * file, struct socket *sock, poll_table *wait);
|
uint bt_sock_poll(struct file * file, struct socket *sock, poll_table *wait);
|
||||||
int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
|
int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
|
||||||
int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo);
|
int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo);
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
|
|
||||||
/* HCI controller types */
|
/* HCI controller types */
|
||||||
#define HCI_BREDR 0x00
|
#define HCI_BREDR 0x00
|
||||||
#define HCI_80211 0x01
|
#define HCI_AMP 0x01
|
||||||
|
|
||||||
/* HCI device quirks */
|
/* HCI device quirks */
|
||||||
enum {
|
enum {
|
||||||
|
|
|
@ -213,11 +213,6 @@ struct rfcomm_dlc {
|
||||||
#define RFCOMM_DEFER_SETUP 8
|
#define RFCOMM_DEFER_SETUP 8
|
||||||
|
|
||||||
/* Scheduling flags and events */
|
/* Scheduling flags and events */
|
||||||
#define RFCOMM_SCHED_STATE 0
|
|
||||||
#define RFCOMM_SCHED_RX 1
|
|
||||||
#define RFCOMM_SCHED_TX 2
|
|
||||||
#define RFCOMM_SCHED_TIMEO 3
|
|
||||||
#define RFCOMM_SCHED_AUTH 4
|
|
||||||
#define RFCOMM_SCHED_WAKEUP 31
|
#define RFCOMM_SCHED_WAKEUP 31
|
||||||
|
|
||||||
/* MSC exchange flags */
|
/* MSC exchange flags */
|
||||||
|
|
|
@ -265,6 +265,115 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(bt_sock_recvmsg);
|
EXPORT_SYMBOL(bt_sock_recvmsg);
|
||||||
|
|
||||||
|
static long bt_sock_data_wait(struct sock *sk, long timeo)
|
||||||
|
{
|
||||||
|
DECLARE_WAITQUEUE(wait, current);
|
||||||
|
|
||||||
|
add_wait_queue(sk_sleep(sk), &wait);
|
||||||
|
for (;;) {
|
||||||
|
set_current_state(TASK_INTERRUPTIBLE);
|
||||||
|
|
||||||
|
if (!skb_queue_empty(&sk->sk_receive_queue))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (sk->sk_err || (sk->sk_shutdown & RCV_SHUTDOWN))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (signal_pending(current) || !timeo)
|
||||||
|
break;
|
||||||
|
|
||||||
|
set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
|
||||||
|
release_sock(sk);
|
||||||
|
timeo = schedule_timeout(timeo);
|
||||||
|
lock_sock(sk);
|
||||||
|
clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
__set_current_state(TASK_RUNNING);
|
||||||
|
remove_wait_queue(sk_sleep(sk), &wait);
|
||||||
|
return timeo;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||||||
|
struct msghdr *msg, size_t size, int flags)
|
||||||
|
{
|
||||||
|
struct sock *sk = sock->sk;
|
||||||
|
int err = 0;
|
||||||
|
size_t target, copied = 0;
|
||||||
|
long timeo;
|
||||||
|
|
||||||
|
if (flags & MSG_OOB)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
msg->msg_namelen = 0;
|
||||||
|
|
||||||
|
BT_DBG("sk %p size %zu", sk, size);
|
||||||
|
|
||||||
|
lock_sock(sk);
|
||||||
|
|
||||||
|
target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);
|
||||||
|
timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
|
||||||
|
|
||||||
|
do {
|
||||||
|
struct sk_buff *skb;
|
||||||
|
int chunk;
|
||||||
|
|
||||||
|
skb = skb_dequeue(&sk->sk_receive_queue);
|
||||||
|
if (!skb) {
|
||||||
|
if (copied >= target)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if ((err = sock_error(sk)) != 0)
|
||||||
|
break;
|
||||||
|
if (sk->sk_shutdown & RCV_SHUTDOWN)
|
||||||
|
break;
|
||||||
|
|
||||||
|
err = -EAGAIN;
|
||||||
|
if (!timeo)
|
||||||
|
break;
|
||||||
|
|
||||||
|
timeo = bt_sock_data_wait(sk, timeo);
|
||||||
|
|
||||||
|
if (signal_pending(current)) {
|
||||||
|
err = sock_intr_errno(timeo);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk = min_t(unsigned int, skb->len, size);
|
||||||
|
if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) {
|
||||||
|
skb_queue_head(&sk->sk_receive_queue, skb);
|
||||||
|
if (!copied)
|
||||||
|
copied = -EFAULT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
copied += chunk;
|
||||||
|
size -= chunk;
|
||||||
|
|
||||||
|
sock_recv_ts_and_drops(msg, sk, skb);
|
||||||
|
|
||||||
|
if (!(flags & MSG_PEEK)) {
|
||||||
|
skb_pull(skb, chunk);
|
||||||
|
if (skb->len) {
|
||||||
|
skb_queue_head(&sk->sk_receive_queue, skb);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
kfree_skb(skb);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* put message back and return */
|
||||||
|
skb_queue_head(&sk->sk_receive_queue, skb);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (size);
|
||||||
|
|
||||||
|
out:
|
||||||
|
release_sock(sk);
|
||||||
|
return copied ? : err;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(bt_sock_stream_recvmsg);
|
||||||
|
|
||||||
static inline unsigned int bt_accept_poll(struct sock *parent)
|
static inline unsigned int bt_accept_poll(struct sock *parent)
|
||||||
{
|
{
|
||||||
struct list_head *p, *n;
|
struct list_head *p, *n;
|
||||||
|
|
|
@ -321,14 +321,10 @@ static int cmtp_session(void *arg)
|
||||||
int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
|
int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
|
||||||
{
|
{
|
||||||
struct cmtp_session *session, *s;
|
struct cmtp_session *session, *s;
|
||||||
bdaddr_t src, dst;
|
|
||||||
int i, err;
|
int i, err;
|
||||||
|
|
||||||
BT_DBG("");
|
BT_DBG("");
|
||||||
|
|
||||||
baswap(&src, &bt_sk(sock->sk)->src);
|
|
||||||
baswap(&dst, &bt_sk(sock->sk)->dst);
|
|
||||||
|
|
||||||
session = kzalloc(sizeof(struct cmtp_session), GFP_KERNEL);
|
session = kzalloc(sizeof(struct cmtp_session), GFP_KERNEL);
|
||||||
if (!session)
|
if (!session)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -347,7 +343,7 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
|
||||||
|
|
||||||
BT_DBG("mtu %d", session->mtu);
|
BT_DBG("mtu %d", session->mtu);
|
||||||
|
|
||||||
sprintf(session->name, "%s", batostr(&dst));
|
sprintf(session->name, "%s", batostr(&bt_sk(sock->sk)->dst));
|
||||||
|
|
||||||
session->sock = sock;
|
session->sock = sock;
|
||||||
session->state = BT_CONFIG;
|
session->state = BT_CONFIG;
|
||||||
|
|
|
@ -562,7 +562,6 @@ static int hci_dev_do_close(struct hci_dev *hdev)
|
||||||
hci_dev_lock_bh(hdev);
|
hci_dev_lock_bh(hdev);
|
||||||
inquiry_cache_flush(hdev);
|
inquiry_cache_flush(hdev);
|
||||||
hci_conn_hash_flush(hdev);
|
hci_conn_hash_flush(hdev);
|
||||||
hci_blacklist_clear(hdev);
|
|
||||||
hci_dev_unlock_bh(hdev);
|
hci_dev_unlock_bh(hdev);
|
||||||
|
|
||||||
hci_notify(hdev, HCI_DEV_DOWN);
|
hci_notify(hdev, HCI_DEV_DOWN);
|
||||||
|
|
|
@ -37,9 +37,7 @@ static ssize_t show_link_type(struct device *dev, struct device_attribute *attr,
|
||||||
static ssize_t show_link_address(struct device *dev, struct device_attribute *attr, char *buf)
|
static ssize_t show_link_address(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
struct hci_conn *conn = dev_get_drvdata(dev);
|
struct hci_conn *conn = dev_get_drvdata(dev);
|
||||||
bdaddr_t bdaddr;
|
return sprintf(buf, "%s\n", batostr(&conn->dst));
|
||||||
baswap(&bdaddr, &conn->dst);
|
|
||||||
return sprintf(buf, "%s\n", batostr(&bdaddr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t show_link_features(struct device *dev, struct device_attribute *attr, char *buf)
|
static ssize_t show_link_features(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
|
@ -196,8 +194,8 @@ static inline char *host_typetostr(int type)
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case HCI_BREDR:
|
case HCI_BREDR:
|
||||||
return "BR/EDR";
|
return "BR/EDR";
|
||||||
case HCI_80211:
|
case HCI_AMP:
|
||||||
return "802.11";
|
return "AMP";
|
||||||
default:
|
default:
|
||||||
return "UNKNOWN";
|
return "UNKNOWN";
|
||||||
}
|
}
|
||||||
|
@ -238,9 +236,7 @@ static ssize_t show_class(struct device *dev, struct device_attribute *attr, cha
|
||||||
static ssize_t show_address(struct device *dev, struct device_attribute *attr, char *buf)
|
static ssize_t show_address(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
struct hci_dev *hdev = dev_get_drvdata(dev);
|
struct hci_dev *hdev = dev_get_drvdata(dev);
|
||||||
bdaddr_t bdaddr;
|
return sprintf(buf, "%s\n", batostr(&hdev->bdaddr));
|
||||||
baswap(&bdaddr, &hdev->bdaddr);
|
|
||||||
return sprintf(buf, "%s\n", batostr(&bdaddr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t show_features(struct device *dev, struct device_attribute *attr, char *buf)
|
static ssize_t show_features(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
|
@ -408,10 +404,8 @@ static int inquiry_cache_show(struct seq_file *f, void *p)
|
||||||
|
|
||||||
for (e = cache->list; e; e = e->next) {
|
for (e = cache->list; e; e = e->next) {
|
||||||
struct inquiry_data *data = &e->data;
|
struct inquiry_data *data = &e->data;
|
||||||
bdaddr_t bdaddr;
|
|
||||||
baswap(&bdaddr, &data->bdaddr);
|
|
||||||
seq_printf(f, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n",
|
seq_printf(f, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n",
|
||||||
batostr(&bdaddr),
|
batostr(&data->bdaddr),
|
||||||
data->pscan_rep_mode, data->pscan_period_mode,
|
data->pscan_rep_mode, data->pscan_period_mode,
|
||||||
data->pscan_mode, data->dev_class[2],
|
data->pscan_mode, data->dev_class[2],
|
||||||
data->dev_class[1], data->dev_class[0],
|
data->dev_class[1], data->dev_class[0],
|
||||||
|
@ -445,13 +439,10 @@ static int blacklist_show(struct seq_file *f, void *p)
|
||||||
|
|
||||||
list_for_each(l, &hdev->blacklist) {
|
list_for_each(l, &hdev->blacklist) {
|
||||||
struct bdaddr_list *b;
|
struct bdaddr_list *b;
|
||||||
bdaddr_t bdaddr;
|
|
||||||
|
|
||||||
b = list_entry(l, struct bdaddr_list, list);
|
b = list_entry(l, struct bdaddr_list, list);
|
||||||
|
|
||||||
baswap(&bdaddr, &b->bdaddr);
|
seq_printf(f, "%s\n", batostr(&b->bdaddr));
|
||||||
|
|
||||||
seq_printf(f, "%s\n", batostr(&bdaddr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hci_dev_unlock_bh(hdev);
|
hci_dev_unlock_bh(hdev);
|
||||||
|
|
|
@ -758,7 +758,6 @@ static int hidp_setup_hid(struct hidp_session *session,
|
||||||
struct hidp_connadd_req *req)
|
struct hidp_connadd_req *req)
|
||||||
{
|
{
|
||||||
struct hid_device *hid;
|
struct hid_device *hid;
|
||||||
bdaddr_t src, dst;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
session->rd_data = kzalloc(req->rd_size, GFP_KERNEL);
|
session->rd_data = kzalloc(req->rd_size, GFP_KERNEL);
|
||||||
|
@ -781,9 +780,6 @@ static int hidp_setup_hid(struct hidp_session *session,
|
||||||
|
|
||||||
hid->driver_data = session;
|
hid->driver_data = session;
|
||||||
|
|
||||||
baswap(&src, &bt_sk(session->ctrl_sock->sk)->src);
|
|
||||||
baswap(&dst, &bt_sk(session->ctrl_sock->sk)->dst);
|
|
||||||
|
|
||||||
hid->bus = BUS_BLUETOOTH;
|
hid->bus = BUS_BLUETOOTH;
|
||||||
hid->vendor = req->vendor;
|
hid->vendor = req->vendor;
|
||||||
hid->product = req->product;
|
hid->product = req->product;
|
||||||
|
@ -791,8 +787,8 @@ static int hidp_setup_hid(struct hidp_session *session,
|
||||||
hid->country = req->country;
|
hid->country = req->country;
|
||||||
|
|
||||||
strncpy(hid->name, req->name, 128);
|
strncpy(hid->name, req->name, 128);
|
||||||
strncpy(hid->phys, batostr(&src), 64);
|
strncpy(hid->phys, batostr(&bt_sk(session->ctrl_sock->sk)->src), 64);
|
||||||
strncpy(hid->uniq, batostr(&dst), 64);
|
strncpy(hid->uniq, batostr(&bt_sk(session->ctrl_sock->sk)->dst), 64);
|
||||||
|
|
||||||
hid->dev.parent = hidp_get_device(session);
|
hid->dev.parent = hidp_get_device(session);
|
||||||
hid->ll_driver = &hidp_hid_driver;
|
hid->ll_driver = &hidp_hid_driver;
|
||||||
|
|
|
@ -1008,10 +1008,20 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (la.l2_psm && __le16_to_cpu(la.l2_psm) < 0x1001 &&
|
if (la.l2_psm) {
|
||||||
!capable(CAP_NET_BIND_SERVICE)) {
|
__u16 psm = __le16_to_cpu(la.l2_psm);
|
||||||
err = -EACCES;
|
|
||||||
goto done;
|
/* PSM must be odd and lsb of upper byte must be 0 */
|
||||||
|
if ((psm & 0x0101) != 0x0001) {
|
||||||
|
err = -EINVAL;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restrict usage of well-known PSMs */
|
||||||
|
if (psm < 0x1001 && !capable(CAP_NET_BIND_SERVICE)) {
|
||||||
|
err = -EACCES;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
write_lock_bh(&l2cap_sk_list.lock);
|
write_lock_bh(&l2cap_sk_list.lock);
|
||||||
|
@ -1190,6 +1200,13 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* PSM must be odd and lsb of upper byte must be 0 */
|
||||||
|
if ((__le16_to_cpu(la.l2_psm) & 0x0101) != 0x0001 &&
|
||||||
|
sk->sk_type != SOCK_RAW) {
|
||||||
|
err = -EINVAL;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
/* Set destination address and psm */
|
/* Set destination address and psm */
|
||||||
bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr);
|
bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr);
|
||||||
l2cap_pi(sk)->psm = la.l2_psm;
|
l2cap_pi(sk)->psm = la.l2_psm;
|
||||||
|
@ -1635,7 +1652,7 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in
|
||||||
|
|
||||||
*frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
|
*frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
|
||||||
if (!*frag)
|
if (!*frag)
|
||||||
return -EFAULT;
|
return err;
|
||||||
if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
|
if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
|
@ -1661,7 +1678,7 @@ static struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr
|
||||||
skb = bt_skb_send_alloc(sk, count + hlen,
|
skb = bt_skb_send_alloc(sk, count + hlen,
|
||||||
msg->msg_flags & MSG_DONTWAIT, &err);
|
msg->msg_flags & MSG_DONTWAIT, &err);
|
||||||
if (!skb)
|
if (!skb)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(err);
|
||||||
|
|
||||||
/* Create L2CAP header */
|
/* Create L2CAP header */
|
||||||
lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
|
lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
|
||||||
|
@ -1690,7 +1707,7 @@ static struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *ms
|
||||||
skb = bt_skb_send_alloc(sk, count + hlen,
|
skb = bt_skb_send_alloc(sk, count + hlen,
|
||||||
msg->msg_flags & MSG_DONTWAIT, &err);
|
msg->msg_flags & MSG_DONTWAIT, &err);
|
||||||
if (!skb)
|
if (!skb)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(err);
|
||||||
|
|
||||||
/* Create L2CAP header */
|
/* Create L2CAP header */
|
||||||
lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
|
lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
|
||||||
|
@ -1727,7 +1744,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *m
|
||||||
skb = bt_skb_send_alloc(sk, count + hlen,
|
skb = bt_skb_send_alloc(sk, count + hlen,
|
||||||
msg->msg_flags & MSG_DONTWAIT, &err);
|
msg->msg_flags & MSG_DONTWAIT, &err);
|
||||||
if (!skb)
|
if (!skb)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(err);
|
||||||
|
|
||||||
/* Create L2CAP header */
|
/* Create L2CAP header */
|
||||||
lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
|
lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
|
||||||
|
@ -1934,6 +1951,9 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms
|
||||||
|
|
||||||
release_sock(sk);
|
release_sock(sk);
|
||||||
|
|
||||||
|
if (sock->type == SOCK_STREAM)
|
||||||
|
return bt_sock_stream_recvmsg(iocb, sock, msg, len, flags);
|
||||||
|
|
||||||
return bt_sock_recvmsg(iocb, sock, msg, len, flags);
|
return bt_sock_recvmsg(iocb, sock, msg, len, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3151,6 +3171,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
|
||||||
|
|
||||||
if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) {
|
if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) {
|
||||||
u8 buf[64];
|
u8 buf[64];
|
||||||
|
l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
|
||||||
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
|
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
|
||||||
l2cap_build_conf_req(sk, buf), buf);
|
l2cap_build_conf_req(sk, buf), buf);
|
||||||
l2cap_pi(sk)->num_conf_req++;
|
l2cap_pi(sk)->num_conf_req++;
|
||||||
|
@ -4643,6 +4664,8 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
|
||||||
|
|
||||||
if (flags & ACL_START) {
|
if (flags & ACL_START) {
|
||||||
struct l2cap_hdr *hdr;
|
struct l2cap_hdr *hdr;
|
||||||
|
struct sock *sk;
|
||||||
|
u16 cid;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
if (conn->rx_len) {
|
if (conn->rx_len) {
|
||||||
|
@ -4653,7 +4676,8 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
|
||||||
l2cap_conn_unreliable(conn, ECOMM);
|
l2cap_conn_unreliable(conn, ECOMM);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skb->len < 2) {
|
/* Start fragment always begin with Basic L2CAP header */
|
||||||
|
if (skb->len < L2CAP_HDR_SIZE) {
|
||||||
BT_ERR("Frame is too short (len %d)", skb->len);
|
BT_ERR("Frame is too short (len %d)", skb->len);
|
||||||
l2cap_conn_unreliable(conn, ECOMM);
|
l2cap_conn_unreliable(conn, ECOMM);
|
||||||
goto drop;
|
goto drop;
|
||||||
|
@ -4661,6 +4685,7 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
|
||||||
|
|
||||||
hdr = (struct l2cap_hdr *) skb->data;
|
hdr = (struct l2cap_hdr *) skb->data;
|
||||||
len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
|
len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
|
||||||
|
cid = __le16_to_cpu(hdr->cid);
|
||||||
|
|
||||||
if (len == skb->len) {
|
if (len == skb->len) {
|
||||||
/* Complete frame received */
|
/* Complete frame received */
|
||||||
|
@ -4677,6 +4702,19 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
|
||||||
goto drop;
|
goto drop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sk = l2cap_get_chan_by_scid(&conn->chan_list, cid);
|
||||||
|
|
||||||
|
if (sk && l2cap_pi(sk)->imtu < len - L2CAP_HDR_SIZE) {
|
||||||
|
BT_ERR("Frame exceeding recv MTU (len %d, MTU %d)",
|
||||||
|
len, l2cap_pi(sk)->imtu);
|
||||||
|
bh_unlock_sock(sk);
|
||||||
|
l2cap_conn_unreliable(conn, ECOMM);
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sk)
|
||||||
|
bh_unlock_sock(sk);
|
||||||
|
|
||||||
/* Allocate skb for the complete frame (with header) */
|
/* Allocate skb for the complete frame (with header) */
|
||||||
conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
|
conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
|
||||||
if (!conn->rx_skb)
|
if (!conn->rx_skb)
|
||||||
|
|
|
@ -51,8 +51,8 @@ char *batostr(bdaddr_t *ba)
|
||||||
|
|
||||||
i ^= 1;
|
i ^= 1;
|
||||||
sprintf(str[i], "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
|
sprintf(str[i], "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
|
||||||
ba->b[0], ba->b[1], ba->b[2],
|
ba->b[5], ba->b[4], ba->b[3],
|
||||||
ba->b[3], ba->b[4], ba->b[5]);
|
ba->b[2], ba->b[1], ba->b[0]);
|
||||||
|
|
||||||
return str[i];
|
return str[i];
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,11 +113,10 @@ static void rfcomm_session_del(struct rfcomm_session *s);
|
||||||
#define __get_rpn_stop_bits(line) (((line) >> 2) & 0x1)
|
#define __get_rpn_stop_bits(line) (((line) >> 2) & 0x1)
|
||||||
#define __get_rpn_parity(line) (((line) >> 3) & 0x7)
|
#define __get_rpn_parity(line) (((line) >> 3) & 0x7)
|
||||||
|
|
||||||
static inline void rfcomm_schedule(uint event)
|
static inline void rfcomm_schedule(void)
|
||||||
{
|
{
|
||||||
if (!rfcomm_thread)
|
if (!rfcomm_thread)
|
||||||
return;
|
return;
|
||||||
//set_bit(event, &rfcomm_event);
|
|
||||||
set_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
|
set_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
|
||||||
wake_up_process(rfcomm_thread);
|
wake_up_process(rfcomm_thread);
|
||||||
}
|
}
|
||||||
|
@ -203,13 +202,13 @@ static inline int __check_fcs(u8 *data, int type, u8 fcs)
|
||||||
static void rfcomm_l2state_change(struct sock *sk)
|
static void rfcomm_l2state_change(struct sock *sk)
|
||||||
{
|
{
|
||||||
BT_DBG("%p state %d", sk, sk->sk_state);
|
BT_DBG("%p state %d", sk, sk->sk_state);
|
||||||
rfcomm_schedule(RFCOMM_SCHED_STATE);
|
rfcomm_schedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rfcomm_l2data_ready(struct sock *sk, int bytes)
|
static void rfcomm_l2data_ready(struct sock *sk, int bytes)
|
||||||
{
|
{
|
||||||
BT_DBG("%p bytes %d", sk, bytes);
|
BT_DBG("%p bytes %d", sk, bytes);
|
||||||
rfcomm_schedule(RFCOMM_SCHED_RX);
|
rfcomm_schedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rfcomm_l2sock_create(struct socket **sock)
|
static int rfcomm_l2sock_create(struct socket **sock)
|
||||||
|
@ -255,7 +254,7 @@ static void rfcomm_session_timeout(unsigned long arg)
|
||||||
BT_DBG("session %p state %ld", s, s->state);
|
BT_DBG("session %p state %ld", s, s->state);
|
||||||
|
|
||||||
set_bit(RFCOMM_TIMED_OUT, &s->flags);
|
set_bit(RFCOMM_TIMED_OUT, &s->flags);
|
||||||
rfcomm_schedule(RFCOMM_SCHED_TIMEO);
|
rfcomm_schedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rfcomm_session_set_timer(struct rfcomm_session *s, long timeout)
|
static void rfcomm_session_set_timer(struct rfcomm_session *s, long timeout)
|
||||||
|
@ -283,7 +282,7 @@ static void rfcomm_dlc_timeout(unsigned long arg)
|
||||||
|
|
||||||
set_bit(RFCOMM_TIMED_OUT, &d->flags);
|
set_bit(RFCOMM_TIMED_OUT, &d->flags);
|
||||||
rfcomm_dlc_put(d);
|
rfcomm_dlc_put(d);
|
||||||
rfcomm_schedule(RFCOMM_SCHED_TIMEO);
|
rfcomm_schedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rfcomm_dlc_set_timer(struct rfcomm_dlc *d, long timeout)
|
static void rfcomm_dlc_set_timer(struct rfcomm_dlc *d, long timeout)
|
||||||
|
@ -465,7 +464,7 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
|
||||||
case BT_CONFIG:
|
case BT_CONFIG:
|
||||||
if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
|
if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
|
||||||
set_bit(RFCOMM_AUTH_REJECT, &d->flags);
|
set_bit(RFCOMM_AUTH_REJECT, &d->flags);
|
||||||
rfcomm_schedule(RFCOMM_SCHED_AUTH);
|
rfcomm_schedule();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* Fall through */
|
/* Fall through */
|
||||||
|
@ -485,7 +484,7 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
|
||||||
case BT_CONNECT2:
|
case BT_CONNECT2:
|
||||||
if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
|
if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
|
||||||
set_bit(RFCOMM_AUTH_REJECT, &d->flags);
|
set_bit(RFCOMM_AUTH_REJECT, &d->flags);
|
||||||
rfcomm_schedule(RFCOMM_SCHED_AUTH);
|
rfcomm_schedule();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* Fall through */
|
/* Fall through */
|
||||||
|
@ -533,7 +532,7 @@ int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb)
|
||||||
skb_queue_tail(&d->tx_queue, skb);
|
skb_queue_tail(&d->tx_queue, skb);
|
||||||
|
|
||||||
if (!test_bit(RFCOMM_TX_THROTTLED, &d->flags))
|
if (!test_bit(RFCOMM_TX_THROTTLED, &d->flags))
|
||||||
rfcomm_schedule(RFCOMM_SCHED_TX);
|
rfcomm_schedule();
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -545,7 +544,7 @@ void __rfcomm_dlc_throttle(struct rfcomm_dlc *d)
|
||||||
d->v24_sig |= RFCOMM_V24_FC;
|
d->v24_sig |= RFCOMM_V24_FC;
|
||||||
set_bit(RFCOMM_MSC_PENDING, &d->flags);
|
set_bit(RFCOMM_MSC_PENDING, &d->flags);
|
||||||
}
|
}
|
||||||
rfcomm_schedule(RFCOMM_SCHED_TX);
|
rfcomm_schedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
void __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
|
void __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
|
||||||
|
@ -556,7 +555,7 @@ void __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
|
||||||
d->v24_sig &= ~RFCOMM_V24_FC;
|
d->v24_sig &= ~RFCOMM_V24_FC;
|
||||||
set_bit(RFCOMM_MSC_PENDING, &d->flags);
|
set_bit(RFCOMM_MSC_PENDING, &d->flags);
|
||||||
}
|
}
|
||||||
rfcomm_schedule(RFCOMM_SCHED_TX);
|
rfcomm_schedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -577,7 +576,7 @@ int rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig)
|
||||||
d->v24_sig = v24_sig;
|
d->v24_sig = v24_sig;
|
||||||
|
|
||||||
if (!test_and_set_bit(RFCOMM_MSC_PENDING, &d->flags))
|
if (!test_and_set_bit(RFCOMM_MSC_PENDING, &d->flags))
|
||||||
rfcomm_schedule(RFCOMM_SCHED_TX);
|
rfcomm_schedule();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -816,7 +815,7 @@ static int rfcomm_queue_disc(struct rfcomm_dlc *d)
|
||||||
cmd->fcs = __fcs2((u8 *) cmd);
|
cmd->fcs = __fcs2((u8 *) cmd);
|
||||||
|
|
||||||
skb_queue_tail(&d->tx_queue, skb);
|
skb_queue_tail(&d->tx_queue, skb);
|
||||||
rfcomm_schedule(RFCOMM_SCHED_TX);
|
rfcomm_schedule();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1415,8 +1414,8 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (len == 1) {
|
if (len == 1) {
|
||||||
/* This is a request, return default settings */
|
/* This is a request, return default (according to ETSI TS 07.10) settings */
|
||||||
bit_rate = RFCOMM_RPN_BR_115200;
|
bit_rate = RFCOMM_RPN_BR_9600;
|
||||||
data_bits = RFCOMM_RPN_DATA_8;
|
data_bits = RFCOMM_RPN_DATA_8;
|
||||||
stop_bits = RFCOMM_RPN_STOP_1;
|
stop_bits = RFCOMM_RPN_STOP_1;
|
||||||
parity = RFCOMM_RPN_PARITY_NONE;
|
parity = RFCOMM_RPN_PARITY_NONE;
|
||||||
|
@ -1431,9 +1430,9 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_
|
||||||
|
|
||||||
if (rpn->param_mask & cpu_to_le16(RFCOMM_RPN_PM_BITRATE)) {
|
if (rpn->param_mask & cpu_to_le16(RFCOMM_RPN_PM_BITRATE)) {
|
||||||
bit_rate = rpn->bit_rate;
|
bit_rate = rpn->bit_rate;
|
||||||
if (bit_rate != RFCOMM_RPN_BR_115200) {
|
if (bit_rate > RFCOMM_RPN_BR_230400) {
|
||||||
BT_DBG("RPN bit rate mismatch 0x%x", bit_rate);
|
BT_DBG("RPN bit rate mismatch 0x%x", bit_rate);
|
||||||
bit_rate = RFCOMM_RPN_BR_115200;
|
bit_rate = RFCOMM_RPN_BR_9600;
|
||||||
rpn_mask ^= RFCOMM_RPN_PM_BITRATE;
|
rpn_mask ^= RFCOMM_RPN_PM_BITRATE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1698,7 +1697,7 @@ static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
BT_ERR("Unknown packet type 0x%02x\n", type);
|
BT_ERR("Unknown packet type 0x%02x", type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
|
@ -1884,7 +1883,7 @@ static inline void rfcomm_accept_connection(struct rfcomm_session *s)
|
||||||
* L2CAP MTU minus UIH header and FCS. */
|
* L2CAP MTU minus UIH header and FCS. */
|
||||||
s->mtu = min(l2cap_pi(nsock->sk)->omtu, l2cap_pi(nsock->sk)->imtu) - 5;
|
s->mtu = min(l2cap_pi(nsock->sk)->omtu, l2cap_pi(nsock->sk)->imtu) - 5;
|
||||||
|
|
||||||
rfcomm_schedule(RFCOMM_SCHED_RX);
|
rfcomm_schedule();
|
||||||
} else
|
} else
|
||||||
sock_release(nsock);
|
sock_release(nsock);
|
||||||
}
|
}
|
||||||
|
@ -2093,7 +2092,7 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
|
||||||
|
|
||||||
rfcomm_session_put(s);
|
rfcomm_session_put(s);
|
||||||
|
|
||||||
rfcomm_schedule(RFCOMM_SCHED_AUTH);
|
rfcomm_schedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct hci_cb rfcomm_cb = {
|
static struct hci_cb rfcomm_cb = {
|
||||||
|
|
|
@ -621,121 +621,29 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
|
||||||
return sent;
|
return sent;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long rfcomm_sock_data_wait(struct sock *sk, long timeo)
|
|
||||||
{
|
|
||||||
DECLARE_WAITQUEUE(wait, current);
|
|
||||||
|
|
||||||
add_wait_queue(sk_sleep(sk), &wait);
|
|
||||||
for (;;) {
|
|
||||||
set_current_state(TASK_INTERRUPTIBLE);
|
|
||||||
|
|
||||||
if (!skb_queue_empty(&sk->sk_receive_queue) ||
|
|
||||||
sk->sk_err ||
|
|
||||||
(sk->sk_shutdown & RCV_SHUTDOWN) ||
|
|
||||||
signal_pending(current) ||
|
|
||||||
!timeo)
|
|
||||||
break;
|
|
||||||
|
|
||||||
set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
|
|
||||||
release_sock(sk);
|
|
||||||
timeo = schedule_timeout(timeo);
|
|
||||||
lock_sock(sk);
|
|
||||||
clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
__set_current_state(TASK_RUNNING);
|
|
||||||
remove_wait_queue(sk_sleep(sk), &wait);
|
|
||||||
return timeo;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
|
static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||||||
struct msghdr *msg, size_t size, int flags)
|
struct msghdr *msg, size_t size, int flags)
|
||||||
{
|
{
|
||||||
struct sock *sk = sock->sk;
|
struct sock *sk = sock->sk;
|
||||||
struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
|
struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
|
||||||
int err = 0;
|
int len;
|
||||||
size_t target, copied = 0;
|
|
||||||
long timeo;
|
|
||||||
|
|
||||||
if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
|
if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
|
||||||
rfcomm_dlc_accept(d);
|
rfcomm_dlc_accept(d);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & MSG_OOB)
|
len = bt_sock_stream_recvmsg(iocb, sock, msg, size, flags);
|
||||||
return -EOPNOTSUPP;
|
|
||||||
|
|
||||||
msg->msg_namelen = 0;
|
|
||||||
|
|
||||||
BT_DBG("sk %p size %zu", sk, size);
|
|
||||||
|
|
||||||
lock_sock(sk);
|
lock_sock(sk);
|
||||||
|
if (!(flags & MSG_PEEK) && len > 0)
|
||||||
|
atomic_sub(len, &sk->sk_rmem_alloc);
|
||||||
|
|
||||||
target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);
|
|
||||||
timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
|
|
||||||
|
|
||||||
do {
|
|
||||||
struct sk_buff *skb;
|
|
||||||
int chunk;
|
|
||||||
|
|
||||||
skb = skb_dequeue(&sk->sk_receive_queue);
|
|
||||||
if (!skb) {
|
|
||||||
if (copied >= target)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if ((err = sock_error(sk)) != 0)
|
|
||||||
break;
|
|
||||||
if (sk->sk_shutdown & RCV_SHUTDOWN)
|
|
||||||
break;
|
|
||||||
|
|
||||||
err = -EAGAIN;
|
|
||||||
if (!timeo)
|
|
||||||
break;
|
|
||||||
|
|
||||||
timeo = rfcomm_sock_data_wait(sk, timeo);
|
|
||||||
|
|
||||||
if (signal_pending(current)) {
|
|
||||||
err = sock_intr_errno(timeo);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
chunk = min_t(unsigned int, skb->len, size);
|
|
||||||
if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) {
|
|
||||||
skb_queue_head(&sk->sk_receive_queue, skb);
|
|
||||||
if (!copied)
|
|
||||||
copied = -EFAULT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
copied += chunk;
|
|
||||||
size -= chunk;
|
|
||||||
|
|
||||||
sock_recv_ts_and_drops(msg, sk, skb);
|
|
||||||
|
|
||||||
if (!(flags & MSG_PEEK)) {
|
|
||||||
atomic_sub(chunk, &sk->sk_rmem_alloc);
|
|
||||||
|
|
||||||
skb_pull(skb, chunk);
|
|
||||||
if (skb->len) {
|
|
||||||
skb_queue_head(&sk->sk_receive_queue, skb);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
kfree_skb(skb);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
/* put message back and return */
|
|
||||||
skb_queue_head(&sk->sk_receive_queue, skb);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (size);
|
|
||||||
|
|
||||||
out:
|
|
||||||
if (atomic_read(&sk->sk_rmem_alloc) <= (sk->sk_rcvbuf >> 2))
|
if (atomic_read(&sk->sk_rmem_alloc) <= (sk->sk_rcvbuf >> 2))
|
||||||
rfcomm_dlc_unthrottle(rfcomm_pi(sk)->dlc);
|
rfcomm_dlc_unthrottle(rfcomm_pi(sk)->dlc);
|
||||||
|
|
||||||
release_sock(sk);
|
release_sock(sk);
|
||||||
return copied ? : err;
|
|
||||||
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen)
|
static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen)
|
||||||
|
|
|
@ -183,9 +183,7 @@ static struct device *rfcomm_get_device(struct rfcomm_dev *dev)
|
||||||
static ssize_t show_address(struct device *tty_dev, struct device_attribute *attr, char *buf)
|
static ssize_t show_address(struct device *tty_dev, struct device_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
struct rfcomm_dev *dev = dev_get_drvdata(tty_dev);
|
struct rfcomm_dev *dev = dev_get_drvdata(tty_dev);
|
||||||
bdaddr_t bdaddr;
|
return sprintf(buf, "%s\n", batostr(&dev->dst));
|
||||||
baswap(&bdaddr, &dev->dst);
|
|
||||||
return sprintf(buf, "%s\n", batostr(&bdaddr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t show_channel(struct device *tty_dev, struct device_attribute *attr, char *buf)
|
static ssize_t show_channel(struct device *tty_dev, struct device_attribute *attr, char *buf)
|
||||||
|
|
Loading…
Reference in New Issue