Commit a7fca0cc authored by David S. Miller's avatar David S. Miller
parents 424eff97 2861453b
...@@ -29,7 +29,6 @@ struct btmrvl_debugfs_data { ...@@ -29,7 +29,6 @@ struct btmrvl_debugfs_data {
struct dentry *root_dir, *config_dir, *status_dir; struct dentry *root_dir, *config_dir, *status_dir;
/* config */ /* config */
struct dentry *drvdbg;
struct dentry *psmode; struct dentry *psmode;
struct dentry *pscmd; struct dentry *pscmd;
struct dentry *hsmode; struct dentry *hsmode;
......
...@@ -131,6 +131,7 @@ void btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb); ...@@ -131,6 +131,7 @@ void btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb);
int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb); int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb);
int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd); int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd);
int btmrvl_enable_ps(struct btmrvl_private *priv);
int btmrvl_prepare_command(struct btmrvl_private *priv); int btmrvl_prepare_command(struct btmrvl_private *priv);
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
......
...@@ -189,6 +189,38 @@ int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd) ...@@ -189,6 +189,38 @@ int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd)
} }
EXPORT_SYMBOL_GPL(btmrvl_send_module_cfg_cmd); EXPORT_SYMBOL_GPL(btmrvl_send_module_cfg_cmd);
int btmrvl_enable_ps(struct btmrvl_private *priv)
{
struct sk_buff *skb;
struct btmrvl_cmd *cmd;
skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC);
if (skb == NULL) {
BT_ERR("No free skb");
return -ENOMEM;
}
cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd));
cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF,
BT_CMD_AUTO_SLEEP_MODE));
cmd->length = 1;
if (priv->btmrvl_dev.psmode)
cmd->data[0] = BT_PS_ENABLE;
else
cmd->data[0] = BT_PS_DISABLE;
bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
skb->dev = (void *) priv->btmrvl_dev.hcidev;
skb_queue_head(&priv->adapter->tx_queue, skb);
BT_DBG("Queue PSMODE Command:%d", cmd->data[0]);
return 0;
}
EXPORT_SYMBOL_GPL(btmrvl_enable_ps);
static int btmrvl_enable_hs(struct btmrvl_private *priv) static int btmrvl_enable_hs(struct btmrvl_private *priv)
{ {
struct sk_buff *skb; struct sk_buff *skb;
...@@ -258,28 +290,7 @@ int btmrvl_prepare_command(struct btmrvl_private *priv) ...@@ -258,28 +290,7 @@ int btmrvl_prepare_command(struct btmrvl_private *priv)
if (priv->btmrvl_dev.pscmd) { if (priv->btmrvl_dev.pscmd) {
priv->btmrvl_dev.pscmd = 0; priv->btmrvl_dev.pscmd = 0;
btmrvl_enable_ps(priv);
skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC);
if (skb == NULL) {
BT_ERR("No free skb");
return -ENOMEM;
}
cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd));
cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_AUTO_SLEEP_MODE));
cmd->length = 1;
if (priv->btmrvl_dev.psmode)
cmd->data[0] = BT_PS_ENABLE;
else
cmd->data[0] = BT_PS_DISABLE;
bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
skb->dev = (void *) priv->btmrvl_dev.hcidev;
skb_queue_head(&priv->adapter->tx_queue, skb);
BT_DBG("Queue PSMODE Command:%d", cmd->data[0]);
} }
if (priv->btmrvl_dev.hscmd) { if (priv->btmrvl_dev.hscmd) {
......
...@@ -930,6 +930,8 @@ static int btmrvl_sdio_probe(struct sdio_func *func, ...@@ -930,6 +930,8 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
priv->hw_wakeup_firmware = btmrvl_sdio_wakeup_fw; priv->hw_wakeup_firmware = btmrvl_sdio_wakeup_fw;
btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ); btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);
priv->btmrvl_dev.psmode = 1;
btmrvl_enable_ps(priv);
return 0; return 0;
...@@ -1001,3 +1003,5 @@ MODULE_AUTHOR("Marvell International Ltd."); ...@@ -1001,3 +1003,5 @@ MODULE_AUTHOR("Marvell International Ltd.");
MODULE_DESCRIPTION("Marvell BT-over-SDIO driver ver " VERSION); MODULE_DESCRIPTION("Marvell BT-over-SDIO driver ver " VERSION);
MODULE_VERSION(VERSION); MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_FIRMWARE("sd8688_helper.bin");
MODULE_FIRMWARE("sd8688.bin");
...@@ -41,8 +41,6 @@ ...@@ -41,8 +41,6 @@
#define VERSION "1.3" #define VERSION "1.3"
static int minor = MISC_DYNAMIC_MINOR;
struct vhci_data { struct vhci_data {
struct hci_dev *hdev; struct hci_dev *hdev;
...@@ -218,12 +216,6 @@ static unsigned int vhci_poll(struct file *file, poll_table *wait) ...@@ -218,12 +216,6 @@ static unsigned int vhci_poll(struct file *file, poll_table *wait)
return POLLOUT | POLLWRNORM; return POLLOUT | POLLWRNORM;
} }
static int vhci_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
return -EINVAL;
}
static int vhci_open(struct inode *inode, struct file *file) static int vhci_open(struct inode *inode, struct file *file)
{ {
struct vhci_data *data; struct vhci_data *data;
...@@ -284,10 +276,10 @@ static int vhci_release(struct inode *inode, struct file *file) ...@@ -284,10 +276,10 @@ static int vhci_release(struct inode *inode, struct file *file)
} }
static const struct file_operations vhci_fops = { static const struct file_operations vhci_fops = {
.owner = THIS_MODULE,
.read = vhci_read, .read = vhci_read,
.write = vhci_write, .write = vhci_write,
.poll = vhci_poll, .poll = vhci_poll,
.ioctl = vhci_ioctl,
.open = vhci_open, .open = vhci_open,
.release = vhci_release, .release = vhci_release,
}; };
...@@ -302,18 +294,12 @@ static int __init vhci_init(void) ...@@ -302,18 +294,12 @@ static int __init vhci_init(void)
{ {
BT_INFO("Virtual HCI driver ver %s", VERSION); BT_INFO("Virtual HCI driver ver %s", VERSION);
if (misc_register(&vhci_miscdev) < 0) { return misc_register(&vhci_miscdev);
BT_ERR("Can't register misc device with minor %d", minor);
return -EIO;
}
return 0;
} }
static void __exit vhci_exit(void) static void __exit vhci_exit(void)
{ {
if (misc_deregister(&vhci_miscdev) < 0) misc_deregister(&vhci_miscdev);
BT_ERR("Can't unregister misc device with minor %d", minor);
} }
module_init(vhci_init); module_init(vhci_init);
......
...@@ -367,22 +367,6 @@ static inline void hci_conn_put(struct hci_conn *conn) ...@@ -367,22 +367,6 @@ static inline void hci_conn_put(struct hci_conn *conn)
} }
} }
/* ----- HCI tasks ----- */
static inline void hci_sched_cmd(struct hci_dev *hdev)
{
tasklet_schedule(&hdev->cmd_task);
}
static inline void hci_sched_rx(struct hci_dev *hdev)
{
tasklet_schedule(&hdev->rx_task);
}
static inline void hci_sched_tx(struct hci_dev *hdev)
{
tasklet_schedule(&hdev->tx_task);
}
/* ----- HCI Devices ----- */ /* ----- HCI Devices ----- */
static inline void __hci_dev_put(struct hci_dev *d) static inline void __hci_dev_put(struct hci_dev *d)
{ {
...@@ -437,28 +421,7 @@ int hci_inquiry(void __user *arg); ...@@ -437,28 +421,7 @@ int hci_inquiry(void __user *arg);
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
/* Receive frame from HCI drivers */ int hci_recv_frame(struct sk_buff *skb);
static inline int hci_recv_frame(struct sk_buff *skb)
{
struct hci_dev *hdev = (struct hci_dev *) skb->dev;
if (!hdev || (!test_bit(HCI_UP, &hdev->flags)
&& !test_bit(HCI_INIT, &hdev->flags))) {
kfree_skb(skb);
return -ENXIO;
}
/* Incomming skb */
bt_cb(skb)->incoming = 1;
/* Time stamp */
__net_timestamp(skb);
/* Queue frame for rx task */
skb_queue_tail(&hdev->rx_q, skb);
hci_sched_rx(hdev);
return 0;
}
int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count); int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count);
int hci_register_sysfs(struct hci_dev *hdev); int hci_register_sysfs(struct hci_dev *hdev);
......
...@@ -324,7 +324,6 @@ struct l2cap_pinfo { ...@@ -324,7 +324,6 @@ struct l2cap_pinfo {
__u8 next_tx_seq; __u8 next_tx_seq;
__u8 expected_ack_seq; __u8 expected_ack_seq;
__u8 req_seq;
__u8 expected_tx_seq; __u8 expected_tx_seq;
__u8 buffer_seq; __u8 buffer_seq;
__u8 buffer_seq_srej; __u8 buffer_seq_srej;
...@@ -375,6 +374,7 @@ struct l2cap_pinfo { ...@@ -375,6 +374,7 @@ struct l2cap_pinfo {
#define L2CAP_CONN_SEND_PBIT 0x10 #define L2CAP_CONN_SEND_PBIT 0x10
#define L2CAP_CONN_REMOTE_BUSY 0x20 #define L2CAP_CONN_REMOTE_BUSY 0x20
#define L2CAP_CONN_LOCAL_BUSY 0x40 #define L2CAP_CONN_LOCAL_BUSY 0x40
#define L2CAP_CONN_REJ_ACT 0x80
#define __mod_retrans_timer() mod_timer(&l2cap_pi(sk)->retrans_timer, \ #define __mod_retrans_timer() mod_timer(&l2cap_pi(sk)->retrans_timer, \
jiffies + msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO)); jiffies + msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO));
......
...@@ -230,7 +230,6 @@ static int bnep_rx_control(struct bnep_session *s, void *data, int len) ...@@ -230,7 +230,6 @@ static int bnep_rx_control(struct bnep_session *s, void *data, int len)
switch (cmd) { switch (cmd) {
case BNEP_CMD_NOT_UNDERSTOOD: case BNEP_CMD_NOT_UNDERSTOOD:
case BNEP_SETUP_CONN_REQ:
case BNEP_SETUP_CONN_RSP: case BNEP_SETUP_CONN_RSP:
case BNEP_FILTER_NET_TYPE_RSP: case BNEP_FILTER_NET_TYPE_RSP:
case BNEP_FILTER_MULTI_ADDR_RSP: case BNEP_FILTER_MULTI_ADDR_RSP:
...@@ -245,6 +244,10 @@ static int bnep_rx_control(struct bnep_session *s, void *data, int len) ...@@ -245,6 +244,10 @@ static int bnep_rx_control(struct bnep_session *s, void *data, int len)
err = bnep_ctrl_set_mcfilter(s, data, len); err = bnep_ctrl_set_mcfilter(s, data, len);
break; break;
case BNEP_SETUP_CONN_REQ:
err = bnep_send_rsp(s, BNEP_SETUP_CONN_RSP, BNEP_CONN_NOT_ALLOWED);
break;
default: { default: {
u8 pkt[3]; u8 pkt[3];
pkt[0] = BNEP_CONTROL; pkt[0] = BNEP_CONTROL;
......
...@@ -193,8 +193,9 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt) ...@@ -193,8 +193,9 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
while ((skb = skb_dequeue(&hdev->driver_init))) { while ((skb = skb_dequeue(&hdev->driver_init))) {
bt_cb(skb)->pkt_type = HCI_COMMAND_PKT; bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
skb->dev = (void *) hdev; skb->dev = (void *) hdev;
skb_queue_tail(&hdev->cmd_q, skb); skb_queue_tail(&hdev->cmd_q, skb);
hci_sched_cmd(hdev); tasklet_schedule(&hdev->cmd_task);
} }
skb_queue_purge(&hdev->driver_init); skb_queue_purge(&hdev->driver_init);
...@@ -987,6 +988,30 @@ int hci_resume_dev(struct hci_dev *hdev) ...@@ -987,6 +988,30 @@ int hci_resume_dev(struct hci_dev *hdev)
} }
EXPORT_SYMBOL(hci_resume_dev); EXPORT_SYMBOL(hci_resume_dev);
/* Receive frame from HCI drivers */
int hci_recv_frame(struct sk_buff *skb)
{
struct hci_dev *hdev = (struct hci_dev *) skb->dev;
if (!hdev || (!test_bit(HCI_UP, &hdev->flags)
&& !test_bit(HCI_INIT, &hdev->flags))) {
kfree_skb(skb);
return -ENXIO;
}
/* Incomming skb */
bt_cb(skb)->incoming = 1;
/* Time stamp */
__net_timestamp(skb);
/* Queue frame for rx task */
skb_queue_tail(&hdev->rx_q, skb);
tasklet_schedule(&hdev->rx_task);
return 0;
}
EXPORT_SYMBOL(hci_recv_frame);
/* Receive packet type fragment */ /* Receive packet type fragment */
#define __reassembly(hdev, type) ((hdev)->reassembly[(type) - 2]) #define __reassembly(hdev, type) ((hdev)->reassembly[(type) - 2])
...@@ -1193,8 +1218,9 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param) ...@@ -1193,8 +1218,9 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param)
bt_cb(skb)->pkt_type = HCI_COMMAND_PKT; bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
skb->dev = (void *) hdev; skb->dev = (void *) hdev;
skb_queue_tail(&hdev->cmd_q, skb); skb_queue_tail(&hdev->cmd_q, skb);
hci_sched_cmd(hdev); tasklet_schedule(&hdev->cmd_task);
return 0; return 0;
} }
...@@ -1271,7 +1297,8 @@ int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags) ...@@ -1271,7 +1297,8 @@ int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
spin_unlock_bh(&conn->data_q.lock); spin_unlock_bh(&conn->data_q.lock);
} }
hci_sched_tx(hdev); tasklet_schedule(&hdev->tx_task);
return 0; return 0;
} }
EXPORT_SYMBOL(hci_send_acl); EXPORT_SYMBOL(hci_send_acl);
...@@ -1298,8 +1325,10 @@ int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb) ...@@ -1298,8 +1325,10 @@ int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb)
skb->dev = (void *) hdev; skb->dev = (void *) hdev;
bt_cb(skb)->pkt_type = HCI_SCODATA_PKT; bt_cb(skb)->pkt_type = HCI_SCODATA_PKT;
skb_queue_tail(&conn->data_q, skb); skb_queue_tail(&conn->data_q, skb);
hci_sched_tx(hdev); tasklet_schedule(&hdev->tx_task);
return 0; return 0;
} }
EXPORT_SYMBOL(hci_send_sco); EXPORT_SYMBOL(hci_send_sco);
...@@ -1612,7 +1641,7 @@ static void hci_cmd_task(unsigned long arg) ...@@ -1612,7 +1641,7 @@ static void hci_cmd_task(unsigned long arg)
hdev->cmd_last_tx = jiffies; hdev->cmd_last_tx = jiffies;
} else { } else {
skb_queue_head(&hdev->cmd_q, skb); skb_queue_head(&hdev->cmd_q, skb);
hci_sched_cmd(hdev); tasklet_schedule(&hdev->cmd_task);
} }
} }
} }
...@@ -1320,7 +1320,7 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk ...@@ -1320,7 +1320,7 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
if (ev->ncmd) { if (ev->ncmd) {
atomic_set(&hdev->cmd_cnt, 1); atomic_set(&hdev->cmd_cnt, 1);
if (!skb_queue_empty(&hdev->cmd_q)) if (!skb_queue_empty(&hdev->cmd_q))
hci_sched_cmd(hdev); tasklet_schedule(&hdev->cmd_task);
} }
} }
...@@ -1386,7 +1386,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -1386,7 +1386,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
if (ev->ncmd) { if (ev->ncmd) {
atomic_set(&hdev->cmd_cnt, 1); atomic_set(&hdev->cmd_cnt, 1);
if (!skb_queue_empty(&hdev->cmd_q)) if (!skb_queue_empty(&hdev->cmd_q))
hci_sched_cmd(hdev); tasklet_schedule(&hdev->cmd_task);
} }
} }
...@@ -1454,7 +1454,7 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s ...@@ -1454,7 +1454,7 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
} }
} }
hci_sched_tx(hdev); tasklet_schedule(&hdev->tx_task);
tasklet_enable(&hdev->tx_task); tasklet_enable(&hdev->tx_task);
} }
......
...@@ -414,6 +414,11 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -414,6 +414,11 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
goto done; goto done;
} }
if (!test_bit(HCI_UP, &hdev->flags)) {
err = -ENETDOWN;
goto done;
}
if (!(skb = bt_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err))) if (!(skb = bt_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err)))
goto done; goto done;
...@@ -440,10 +445,10 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -440,10 +445,10 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
if (test_bit(HCI_RAW, &hdev->flags) || (ogf == 0x3f)) { if (test_bit(HCI_RAW, &hdev->flags) || (ogf == 0x3f)) {
skb_queue_tail(&hdev->raw_q, skb); skb_queue_tail(&hdev->raw_q, skb);
hci_sched_tx(hdev); tasklet_schedule(&hdev->tx_task);
} else { } else {
skb_queue_tail(&hdev->cmd_q, skb); skb_queue_tail(&hdev->cmd_q, skb);
hci_sched_cmd(hdev); tasklet_schedule(&hdev->cmd_task);
} }
} else { } else {
if (!capable(CAP_NET_RAW)) { if (!capable(CAP_NET_RAW)) {
...@@ -452,7 +457,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -452,7 +457,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
} }
skb_queue_tail(&hdev->raw_q, skb); skb_queue_tail(&hdev->raw_q, skb);
hci_sched_tx(hdev); tasklet_schedule(&hdev->tx_task);
} }
err = len; err = len;
......
...@@ -280,6 +280,13 @@ static int hidp_send_report(struct hidp_session *session, struct hid_report *rep ...@@ -280,6 +280,13 @@ static int hidp_send_report(struct hidp_session *session, struct hid_report *rep
return hidp_queue_report(session, buf, rsize); return hidp_queue_report(session, buf, rsize);
} }
static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count)
{
if (hidp_queue_report(hid->driver_data, data, count))
return -ENOMEM;
return count;
}
static void hidp_idle_timeout(unsigned long arg) static void hidp_idle_timeout(unsigned long arg)
{ {
struct hidp_session *session = (struct hidp_session *) arg; struct hidp_session *session = (struct hidp_session *) arg;
...@@ -785,6 +792,8 @@ static int hidp_setup_hid(struct hidp_session *session, ...@@ -785,6 +792,8 @@ static int hidp_setup_hid(struct hidp_session *session,
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;
hid->hid_output_raw_report = hidp_output_raw_report;
err = hid_add_device(hid); err = hid_add_device(hid);
if (err < 0) if (err < 0)
goto failed; goto failed;
......
...@@ -54,6 +54,7 @@ ...@@ -54,6 +54,7 @@
#define VERSION "2.14" #define VERSION "2.14"
static int enable_ertm = 0; static int enable_ertm = 0;
static int max_transmit = L2CAP_DEFAULT_MAX_TX;
static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN; static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
static u8 l2cap_fixed_chan[8] = { 0x02, }; static u8 l2cap_fixed_chan[8] = { 0x02, };
...@@ -373,6 +374,8 @@ static inline int l2cap_send_rr_or_rnr(struct l2cap_pinfo *pi, u16 control) ...@@ -373,6 +374,8 @@ static inline int l2cap_send_rr_or_rnr(struct l2cap_pinfo *pi, u16 control)
else else
control |= L2CAP_SUPER_RCV_READY; control |= L2CAP_SUPER_RCV_READY;
control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
return l2cap_send_sframe(pi, control); return l2cap_send_sframe(pi, control);
} }
...@@ -1333,7 +1336,7 @@ static int l2cap_retransmit_frame(struct sock *sk, u8 tx_seq) ...@@ -1333,7 +1336,7 @@ static int l2cap_retransmit_frame(struct sock *sk, u8 tx_seq)
tx_skb = skb_clone(skb, GFP_ATOMIC); tx_skb = skb_clone(skb, GFP_ATOMIC);
bt_cb(skb)->retries++; bt_cb(skb)->retries++;
control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE); control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
control |= (pi->req_seq << L2CAP_CTRL_REQSEQ_SHIFT) control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
| (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT); | (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
...@@ -1375,7 +1378,7 @@ static int l2cap_ertm_send(struct sock *sk) ...@@ -1375,7 +1378,7 @@ static int l2cap_ertm_send(struct sock *sk)
bt_cb(skb)->retries++; bt_cb(skb)->retries++;
control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE); control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
control |= (pi->req_seq << L2CAP_CTRL_REQSEQ_SHIFT) control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
| (pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT); | (pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
...@@ -2173,6 +2176,21 @@ static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val) ...@@ -2173,6 +2176,21 @@ static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
*ptr += L2CAP_CONF_OPT_SIZE + len; *ptr += L2CAP_CONF_OPT_SIZE + len;
} }
static inline void l2cap_ertm_init(struct sock *sk)
{
l2cap_pi(sk)->expected_ack_seq = 0;
l2cap_pi(sk)->unacked_frames = 0;
l2cap_pi(sk)->buffer_seq = 0;
l2cap_pi(sk)->num_to_ack = 0;
setup_timer(&l2cap_pi(sk)->retrans_timer,
l2cap_retrans_timeout, (unsigned long) sk);
setup_timer(&l2cap_pi(sk)->monitor_timer,
l2cap_monitor_timeout, (unsigned long) sk);
__skb_queue_head_init(SREJ_QUEUE(sk));
}
static int l2cap_mode_supported(__u8 mode, __u32 feat_mask) static int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
{ {
u32 local_feat_mask = l2cap_feat_mask; u32 local_feat_mask = l2cap_feat_mask;
...@@ -2236,7 +2254,7 @@ static int l2cap_build_conf_req(struct sock *sk, void *data) ...@@ -2236,7 +2254,7 @@ static int l2cap_build_conf_req(struct sock *sk, void *data)
case L2CAP_MODE_ERTM: case L2CAP_MODE_ERTM:
rfc.mode = L2CAP_MODE_ERTM; rfc.mode = L2CAP_MODE_ERTM;
rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW; rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW;
rfc.max_transmit = L2CAP_DEFAULT_MAX_TX; rfc.max_transmit = max_transmit;
rfc.retrans_timeout = 0; rfc.retrans_timeout = 0;
rfc.monitor_timeout = 0; rfc.monitor_timeout = 0;
rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE); rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
...@@ -2761,17 +2779,13 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr ...@@ -2761,17 +2779,13 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
l2cap_pi(sk)->fcs = L2CAP_FCS_CRC16; l2cap_pi(sk)->fcs = L2CAP_FCS_CRC16;
sk->sk_state = BT_CONNECTED; sk->sk_state = BT_CONNECTED;
l2cap_pi(sk)->next_tx_seq = 0;
l2cap_pi(sk)->expected_ack_seq = 0;
l2cap_pi(sk)->unacked_frames = 0;
setup_timer(&l2cap_pi(sk)->retrans_timer,
l2cap_retrans_timeout, (unsigned long) sk);
setup_timer(&l2cap_pi(sk)->monitor_timer,
l2cap_monitor_timeout, (unsigned long) sk);
l2cap_pi(sk)->next_tx_seq = 0;
l2cap_pi(sk)->expected_tx_seq = 0;
__skb_queue_head_init(TX_QUEUE(sk)); __skb_queue_head_init(TX_QUEUE(sk));
__skb_queue_head_init(SREJ_QUEUE(sk)); if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM)
l2cap_ertm_init(sk);
l2cap_chan_ready(sk); l2cap_chan_ready(sk);
goto unlock; goto unlock;
} }
...@@ -2850,11 +2864,12 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr ...@@ -2850,11 +2864,12 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
l2cap_pi(sk)->fcs = L2CAP_FCS_CRC16; l2cap_pi(sk)->fcs = L2CAP_FCS_CRC16;
sk->sk_state = BT_CONNECTED; sk->sk_state = BT_CONNECTED;
l2cap_pi(sk)->next_tx_seq = 0;
l2cap_pi(sk)->expected_tx_seq = 0; l2cap_pi(sk)->expected_tx_seq = 0;
l2cap_pi(sk)->buffer_seq = 0;
l2cap_pi(sk)->num_to_ack = 0;
__skb_queue_head_init(TX_QUEUE(sk)); __skb_queue_head_init(TX_QUEUE(sk));
__skb_queue_head_init(SREJ_QUEUE(sk)); if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM)
l2cap_ertm_init(sk);
l2cap_chan_ready(sk); l2cap_chan_ready(sk);
} }
...@@ -2886,9 +2901,12 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd ...@@ -2886,9 +2901,12 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
sk->sk_shutdown = SHUTDOWN_MASK; sk->sk_shutdown = SHUTDOWN_MASK;
skb_queue_purge(TX_QUEUE(sk)); skb_queue_purge(TX_QUEUE(sk));
skb_queue_purge(SREJ_QUEUE(sk));
del_timer(&l2cap_pi(sk)->retrans_timer); if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) {
del_timer(&l2cap_pi(sk)->monitor_timer); skb_queue_purge(SREJ_QUEUE(sk));
del_timer(&l2cap_pi(sk)->retrans_timer);
del_timer(&l2cap_pi(sk)->monitor_timer);
}
l2cap_chan_del(sk, ECONNRESET); l2cap_chan_del(sk, ECONNRESET);
bh_unlock_sock(sk); bh_unlock_sock(sk);
...@@ -2913,9 +2931,12 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd ...@@ -2913,9 +2931,12 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
return 0; return 0;
skb_queue_purge(TX_QUEUE(sk)); skb_queue_purge(TX_QUEUE(sk));
skb_queue_purge(SREJ_QUEUE(sk));
del_timer(&l2cap_pi(sk)->retrans_timer); if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) {
del_timer(&l2cap_pi(sk)->monitor_timer); skb_queue_purge(SREJ_QUEUE(sk));
del_timer(&l2cap_pi(sk)->retrans_timer);
del_timer(&l2cap_pi(sk)->monitor_timer);
}
l2cap_chan_del(sk, 0); l2cap_chan_del(sk, 0);
bh_unlock_sock(sk); bh_unlock_sock(sk);
...@@ -3280,12 +3301,16 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str ...@@ -3280,12 +3301,16 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str
{ {
struct l2cap_pinfo *pi = l2cap_pi(sk); struct l2cap_pinfo *pi = l2cap_pi(sk);
u8 tx_seq = __get_txseq(rx_control); u8 tx_seq = __get_txseq(rx_control);
u8 req_seq = __get_reqseq(rx_control);
u16 tx_control = 0; u16 tx_control = 0;
u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT; u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT;
int err = 0; int err = 0;
BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len); BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len);
pi->expected_ack_seq = req_seq;
l2cap_drop_acked_frames(sk);
if (tx_seq == pi->expected_tx_seq) if (tx_seq == pi->expected_tx_seq)
goto expected; goto expected;
...@@ -3340,6 +3365,16 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str ...@@ -3340,6 +3365,16 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str
return 0; return 0;
} }
if (rx_control & L2CAP_CTRL_FINAL) {
if (pi->conn_state & L2CAP_CONN_REJ_ACT)
pi->conn_state &= ~L2CAP_CONN_REJ_ACT;
else {
sk->sk_send_head = TX_QUEUE(sk)->next;
pi->next_tx_seq = pi->expected_ack_seq;
l2cap_ertm_send(sk);
}
}
pi->buffer_seq = (pi->buffer_seq + 1) % 64; pi->buffer_seq = (pi->buffer_seq + 1) % 64;
err = l2cap_sar_reassembly_sdu(sk, skb, rx_control); err = l2cap_sar_reassembly_sdu(sk, skb, rx_control);
...@@ -3376,6 +3411,14 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str ...@@ -3376,6 +3411,14 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str
pi->expected_ack_seq = tx_seq; pi->expected_ack_seq = tx_seq;
l2cap_drop_acked_frames(sk); l2cap_drop_acked_frames(sk);
if (pi->conn_state & L2CAP_CONN_REJ_ACT)
pi->conn_state &= ~L2CAP_CONN_REJ_ACT;
else {
sk->sk_send_head = TX_QUEUE(sk)->next;
pi->next_tx_seq = pi->expected_ack_seq;
l2cap_ertm_send(sk);
}
if (!(pi->conn_state & L2CAP_CONN_WAIT_F)) if (!(pi->conn_state & L2CAP_CONN_WAIT_F))
break; break;
...@@ -3403,10 +3446,24 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str ...@@ -3403,10 +3446,24 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str
pi->expected_ack_seq = __get_reqseq(rx_control); pi->expected_ack_seq = __get_reqseq(rx_control);
l2cap_drop_acked_frames(sk); l2cap_drop_acked_frames(sk);
sk->sk_send_head = TX_QUEUE(sk)->next; if (rx_control & L2CAP_CTRL_FINAL) {
pi->next_tx_seq = pi->expected_ack_seq; if (pi->conn_state & L2CAP_CONN_REJ_ACT)
pi->conn_state &= ~L2CAP_CONN_REJ_ACT;
else {
sk->sk_send_head = TX_QUEUE(sk)->next;
pi->next_tx_seq = pi->expected_ack_seq;
l2cap_ertm_send(sk);
}
} else {
sk->sk_send_head = TX_QUEUE(sk)->next;
pi->next_tx_seq = pi->expected_ack_seq;
l2cap_ertm_send(sk);
l2cap_ertm_send(sk); if (pi->conn_state & L2CAP_CONN_WAIT_F) {
pi->srej_save_reqseq = tx_seq;
pi->conn_state |= L2CAP_CONN_REJ_ACT;
}
}
break; break;
...@@ -3425,7 +3482,7 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str ...@@ -3425,7 +3482,7 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str
} else if (rx_control & L2CAP_CTRL_FINAL) { } else if (rx_control & L2CAP_CTRL_FINAL) {
if ((pi->conn_state & L2CAP_CONN_SREJ_ACT) && if ((pi->conn_state & L2CAP_CONN_SREJ_ACT) &&
pi->srej_save_reqseq == tx_seq) pi->srej_save_reqseq == tx_seq)
pi->srej_save_reqseq &= ~L2CAP_CONN_SREJ_ACT; pi->conn_state &= ~L2CAP_CONN_SREJ_ACT;
else else
l2cap_retransmit_frame(sk, tx_seq); l2cap_retransmit_frame(sk, tx_seq);
} }
...@@ -4004,6 +4061,9 @@ module_exit(l2cap_exit); ...@@ -4004,6 +4061,9 @@ module_exit(l2cap_exit);
module_param(enable_ertm, bool, 0644); module_param(enable_ertm, bool, 0644);
MODULE_PARM_DESC(enable_ertm, "Enable enhanced retransmission mode"); MODULE_PARM_DESC(enable_ertm, "Enable enhanced retransmission mode");
module_param(max_transmit, uint, 0644);
MODULE_PARM_DESC(max_transmit, "Max transmit value (default = 3)");
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Bluetooth L2CAP ver " VERSION); MODULE_DESCRIPTION("Bluetooth L2CAP ver " VERSION);
MODULE_VERSION(VERSION); MODULE_VERSION(VERSION);
......
...@@ -51,6 +51,7 @@ ...@@ -51,6 +51,7 @@
static int disable_cfc = 0; static int disable_cfc = 0;
static int channel_mtu = -1; static int channel_mtu = -1;
static unsigned int l2cap_mtu = RFCOMM_MAX_L2CAP_MTU; static unsigned int l2cap_mtu = RFCOMM_MAX_L2CAP_MTU;
static int l2cap_ertm = 0;
static struct task_struct *rfcomm_thread; static struct task_struct *rfcomm_thread;
...@@ -702,6 +703,8 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst ...@@ -702,6 +703,8 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst
sk = sock->sk; sk = sock->sk;
lock_sock(sk); lock_sock(sk);
l2cap_pi(sk)->imtu = l2cap_mtu; l2cap_pi(sk)->imtu = l2cap_mtu;
if (l2cap_ertm)
l2cap_pi(sk)->mode = L2CAP_MODE_ERTM;
release_sock(sk); release_sock(sk);
s = rfcomm_session_add(sock, BT_BOUND); s = rfcomm_session_add(sock, BT_BOUND);
...@@ -2185,6 +2188,9 @@ MODULE_PARM_DESC(channel_mtu, "Default MTU for the RFCOMM channel"); ...@@ -2185,6 +2188,9 @@ MODULE_PARM_DESC(channel_mtu, "Default MTU for the RFCOMM channel");
module_param(l2cap_mtu, uint, 0644); module_param(l2cap_mtu, uint, 0644);
MODULE_PARM_DESC(l2cap_mtu, "Default MTU for the L2CAP connection"); MODULE_PARM_DESC(l2cap_mtu, "Default MTU for the L2CAP connection");
module_param(l2cap_ertm, bool, 0644);
MODULE_PARM_DESC(l2cap_ertm, "Use L2CAP ERTM mode for connection");
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Bluetooth RFCOMM ver " VERSION); MODULE_DESCRIPTION("Bluetooth RFCOMM ver " VERSION);
MODULE_VERSION(VERSION); MODULE_VERSION(VERSION);
......
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