Commit bb411b4d authored by John W. Linville's avatar John W. Linville
parents 44c866a0 26954c7f
......@@ -188,7 +188,7 @@ config BT_MRVL
The core driver to support Marvell Bluetooth devices.
This driver is required if you want to support
Marvell Bluetooth devices, such as 8688.
Marvell Bluetooth devices, such as 8688/8787.
Say Y here to compile Marvell Bluetooth driver
into the kernel or say M to compile it as module.
......@@ -201,7 +201,7 @@ config BT_MRVL_SDIO
The driver for Marvell Bluetooth chipsets with SDIO interface.
This driver is required if you want to use Marvell Bluetooth
devices with SDIO interface. Currently only SD8688 chipset is
devices with SDIO interface. Currently SD8688/SD8787 chipsets are
supported.
Say Y here to compile support for Marvell BT-over-SDIO driver
......
......@@ -138,9 +138,6 @@ static int ath3k_load_firmware(struct usb_device *udev,
count -= size;
}
kfree(send_buf);
return 0;
error:
kfree(send_buf);
return err;
......
......@@ -49,15 +49,59 @@
static u8 user_rmmod;
static u8 sdio_ireg;
static const struct btmrvl_sdio_card_reg btmrvl_reg_8688 = {
.cfg = 0x03,
.host_int_mask = 0x04,
.host_intstatus = 0x05,
.card_status = 0x20,
.sq_read_base_addr_a0 = 0x10,
.sq_read_base_addr_a1 = 0x11,
.card_fw_status0 = 0x40,
.card_fw_status1 = 0x41,
.card_rx_len = 0x42,
.card_rx_unit = 0x43,
.io_port_0 = 0x00,
.io_port_1 = 0x01,
.io_port_2 = 0x02,
};
static const struct btmrvl_sdio_card_reg btmrvl_reg_8787 = {
.cfg = 0x00,
.host_int_mask = 0x02,
.host_intstatus = 0x03,
.card_status = 0x30,
.sq_read_base_addr_a0 = 0x40,
.sq_read_base_addr_a1 = 0x41,
.card_revision = 0x5c,
.card_fw_status0 = 0x60,
.card_fw_status1 = 0x61,
.card_rx_len = 0x62,
.card_rx_unit = 0x63,
.io_port_0 = 0x78,
.io_port_1 = 0x79,
.io_port_2 = 0x7a,
};
static const struct btmrvl_sdio_device btmrvl_sdio_sd6888 = {
.helper = "sd8688_helper.bin",
.firmware = "sd8688.bin",
.reg = &btmrvl_reg_8688,
.sd_blksz_fw_dl = 64,
};
static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = {
.helper = NULL,
.firmware = "mrvl/sd8787_uapsta.bin",
.reg = &btmrvl_reg_8787,
.sd_blksz_fw_dl = 256,
};
static const struct sdio_device_id btmrvl_sdio_ids[] = {
/* Marvell SD8688 Bluetooth device */
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9105),
.driver_data = (unsigned long) &btmrvl_sdio_sd6888 },
/* Marvell SD8787 Bluetooth device */
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911A),
.driver_data = (unsigned long) &btmrvl_sdio_sd8787 },
{ } /* Terminating entry */
};
......@@ -69,7 +113,7 @@ static int btmrvl_sdio_get_rx_unit(struct btmrvl_sdio_card *card)
u8 reg;
int ret;
reg = sdio_readb(card->func, CARD_RX_UNIT_REG, &ret);
reg = sdio_readb(card->func, card->reg->card_rx_unit, &ret);
if (!ret)
card->rx_unit = reg;
......@@ -83,11 +127,11 @@ static int btmrvl_sdio_read_fw_status(struct btmrvl_sdio_card *card, u16 *dat)
*dat = 0;
fws0 = sdio_readb(card->func, CARD_FW_STATUS0_REG, &ret);
fws0 = sdio_readb(card->func, card->reg->card_fw_status0, &ret);
if (ret)
return -EIO;
fws1 = sdio_readb(card->func, CARD_FW_STATUS1_REG, &ret);
fws1 = sdio_readb(card->func, card->reg->card_fw_status1, &ret);
if (ret)
return -EIO;
......@@ -101,7 +145,7 @@ static int btmrvl_sdio_read_rx_len(struct btmrvl_sdio_card *card, u16 *dat)
u8 reg;
int ret;
reg = sdio_readb(card->func, CARD_RX_LEN_REG, &ret);
reg = sdio_readb(card->func, card->reg->card_rx_len, &ret);
if (!ret)
*dat = (u16) reg << card->rx_unit;
......@@ -113,7 +157,7 @@ static int btmrvl_sdio_enable_host_int_mask(struct btmrvl_sdio_card *card,
{
int ret;
sdio_writeb(card->func, mask, HOST_INT_MASK_REG, &ret);
sdio_writeb(card->func, mask, card->reg->host_int_mask, &ret);
if (ret) {
BT_ERR("Unable to enable the host interrupt!");
ret = -EIO;
......@@ -128,13 +172,13 @@ static int btmrvl_sdio_disable_host_int_mask(struct btmrvl_sdio_card *card,
u8 host_int_mask;
int ret;
host_int_mask = sdio_readb(card->func, HOST_INT_MASK_REG, &ret);
host_int_mask = sdio_readb(card->func, card->reg->host_int_mask, &ret);
if (ret)
return -EIO;
host_int_mask &= ~mask;
sdio_writeb(card->func, host_int_mask, HOST_INT_MASK_REG, &ret);
sdio_writeb(card->func, host_int_mask, card->reg->host_int_mask, &ret);
if (ret < 0) {
BT_ERR("Unable to disable the host interrupt!");
return -EIO;
......@@ -150,7 +194,7 @@ static int btmrvl_sdio_poll_card_status(struct btmrvl_sdio_card *card, u8 bits)
int ret;
for (tries = 0; tries < MAX_POLL_TRIES * 1000; tries++) {
status = sdio_readb(card->func, CARD_STATUS_REG, &ret);
status = sdio_readb(card->func, card->reg->card_status, &ret);
if (ret)
goto failed;
if ((status & bits) == bits)
......@@ -299,7 +343,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)
u8 base0, base1;
void *tmpfwbuf = NULL;
u8 *fwbuf;
u16 len;
u16 len, blksz_dl = card->sd_blksz_fw_dl;
int txlen = 0, tx_blocks = 0, count = 0;
ret = request_firmware(&fw_firmware, card->firmware,
......@@ -345,7 +389,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)
for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
base0 = sdio_readb(card->func,
SQ_READ_BASE_ADDRESS_A0_REG, &ret);
card->reg->sq_read_base_addr_a0, &ret);
if (ret) {
BT_ERR("BASE0 register read failed:"
" base0 = 0x%04X(%d)."
......@@ -355,7 +399,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)
goto done;
}
base1 = sdio_readb(card->func,
SQ_READ_BASE_ADDRESS_A1_REG, &ret);
card->reg->sq_read_base_addr_a1, &ret);
if (ret) {
BT_ERR("BASE1 register read failed:"
" base1 = 0x%04X(%d)."
......@@ -403,20 +447,19 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)
if (firmwarelen - offset < txlen)
txlen = firmwarelen - offset;
tx_blocks =
(txlen + SDIO_BLOCK_SIZE - 1) / SDIO_BLOCK_SIZE;
tx_blocks = (txlen + blksz_dl - 1) / blksz_dl;
memcpy(fwbuf, &firmware[offset], txlen);
}
ret = sdio_writesb(card->func, card->ioport, fwbuf,
tx_blocks * SDIO_BLOCK_SIZE);
tx_blocks * blksz_dl);
if (ret < 0) {
BT_ERR("FW download, writesb(%d) failed @%d",
count, offset);
sdio_writeb(card->func, HOST_CMD53_FIN, CONFIG_REG,
&ret);
sdio_writeb(card->func, HOST_CMD53_FIN,
card->reg->cfg, &ret);
if (ret)
BT_ERR("writeb failed (CFG)");
}
......@@ -597,7 +640,7 @@ static void btmrvl_sdio_interrupt(struct sdio_func *func)
priv = card->priv;
ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret);
ireg = sdio_readb(card->func, card->reg->host_intstatus, &ret);
if (ret) {
BT_ERR("sdio_readb: read int status register failed");
return;
......@@ -613,7 +656,7 @@ static void btmrvl_sdio_interrupt(struct sdio_func *func)
sdio_writeb(card->func, ~(ireg) & (DN_LD_HOST_INT_STATUS |
UP_LD_HOST_INT_STATUS),
HOST_INTSTATUS_REG, &ret);
card->reg->host_intstatus, &ret);
if (ret) {
BT_ERR("sdio_writeb: clear int status register failed");
return;
......@@ -664,7 +707,7 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card)
goto release_irq;
}
reg = sdio_readb(func, IO_PORT_0_REG, &ret);
reg = sdio_readb(func, card->reg->io_port_0, &ret);
if (ret < 0) {
ret = -EIO;
goto release_irq;
......@@ -672,7 +715,7 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card)
card->ioport = reg;
reg = sdio_readb(func, IO_PORT_1_REG, &ret);
reg = sdio_readb(func, card->reg->io_port_1, &ret);
if (ret < 0) {
ret = -EIO;
goto release_irq;
......@@ -680,7 +723,7 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card)
card->ioport |= (reg << 8);
reg = sdio_readb(func, IO_PORT_2_REG, &ret);
reg = sdio_readb(func, card->reg->io_port_2, &ret);
if (ret < 0) {
ret = -EIO;
goto release_irq;
......@@ -815,6 +858,8 @@ static int btmrvl_sdio_host_to_card(struct btmrvl_private *priv,
static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card)
{
int ret = 0;
u8 fws0;
int pollnum = MAX_POLL_TRIES;
if (!card || !card->func) {
BT_ERR("card or function is NULL!");
......@@ -827,20 +872,36 @@ static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card)
goto done;
}
ret = btmrvl_sdio_download_helper(card);
/* Check if other function driver is downloading the firmware */
fws0 = sdio_readb(card->func, card->reg->card_fw_status0, &ret);
if (ret) {
BT_ERR("Failed to download helper!");
BT_ERR("Failed to read FW downloading status!");
ret = -EIO;
goto done;
}
if (fws0) {
BT_DBG("BT not the winner (%#x). Skip FW downloading", fws0);
/* Give other function more time to download the firmware */
pollnum *= 10;
} else {
if (card->helper) {
ret = btmrvl_sdio_download_helper(card);
if (ret) {
BT_ERR("Failed to download helper!");
ret = -EIO;
goto done;
}
}
if (btmrvl_sdio_download_fw_w_helper(card)) {
BT_ERR("Failed to download firmware!");
ret = -EIO;
goto done;
if (btmrvl_sdio_download_fw_w_helper(card)) {
BT_ERR("Failed to download firmware!");
ret = -EIO;
goto done;
}
}
if (btmrvl_sdio_verify_fw_download(card, MAX_POLL_TRIES)) {
if (btmrvl_sdio_verify_fw_download(card, pollnum)) {
BT_ERR("FW failed to be active in time!");
ret = -ETIMEDOUT;
goto done;
......@@ -864,7 +925,7 @@ static int btmrvl_sdio_wakeup_fw(struct btmrvl_private *priv)
sdio_claim_host(card->func);
sdio_writeb(card->func, HOST_POWER_UP, CONFIG_REG, &ret);
sdio_writeb(card->func, HOST_POWER_UP, card->reg->cfg, &ret);
sdio_release_host(card->func);
......@@ -893,8 +954,10 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
if (id->driver_data) {
struct btmrvl_sdio_device *data = (void *) id->driver_data;
card->helper = data->helper;
card->helper = data->helper;
card->firmware = data->firmware;
card->reg = data->reg;
card->sd_blksz_fw_dl = data->sd_blksz_fw_dl;
}
if (btmrvl_sdio_register_dev(card) < 0) {
......@@ -1011,3 +1074,4 @@ MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL v2");
MODULE_FIRMWARE("sd8688_helper.bin");
MODULE_FIRMWARE("sd8688.bin");
MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");
......@@ -47,44 +47,46 @@
/* Max retry number of CMD53 write */
#define MAX_WRITE_IOMEM_RETRY 2
/* Host Control Registers */
#define IO_PORT_0_REG 0x00
#define IO_PORT_1_REG 0x01
#define IO_PORT_2_REG 0x02
#define CONFIG_REG 0x03
#define HOST_POWER_UP BIT(1)
#define HOST_CMD53_FIN BIT(2)
#define HOST_INT_MASK_REG 0x04
#define HIM_DISABLE 0xff
#define HIM_ENABLE (BIT(0) | BIT(1))
#define HOST_INTSTATUS_REG 0x05
#define UP_LD_HOST_INT_STATUS BIT(0)
#define DN_LD_HOST_INT_STATUS BIT(1)
/* Card Control Registers */
#define SQ_READ_BASE_ADDRESS_A0_REG 0x10
#define SQ_READ_BASE_ADDRESS_A1_REG 0x11
#define CARD_STATUS_REG 0x20
#define DN_LD_CARD_RDY BIT(0)
#define CARD_IO_READY BIT(3)
#define CARD_FW_STATUS0_REG 0x40
#define CARD_FW_STATUS1_REG 0x41
#define FIRMWARE_READY 0xfedc
#define CARD_RX_LEN_REG 0x42
#define CARD_RX_UNIT_REG 0x43
/* register bitmasks */
#define HOST_POWER_UP BIT(1)
#define HOST_CMD53_FIN BIT(2)
#define HIM_DISABLE 0xff
#define HIM_ENABLE (BIT(0) | BIT(1))
#define UP_LD_HOST_INT_STATUS BIT(0)
#define DN_LD_HOST_INT_STATUS BIT(1)
#define DN_LD_CARD_RDY BIT(0)
#define CARD_IO_READY BIT(3)
#define FIRMWARE_READY 0xfedc
struct btmrvl_sdio_card_reg {
u8 cfg;
u8 host_int_mask;
u8 host_intstatus;
u8 card_status;
u8 sq_read_base_addr_a0;
u8 sq_read_base_addr_a1;
u8 card_revision;
u8 card_fw_status0;
u8 card_fw_status1;
u8 card_rx_len;
u8 card_rx_unit;
u8 io_port_0;
u8 io_port_1;
u8 io_port_2;
};
struct btmrvl_sdio_card {
struct sdio_func *func;
u32 ioport;
const char *helper;
const char *firmware;
const struct btmrvl_sdio_card_reg *reg;
u16 sd_blksz_fw_dl;
u8 rx_unit;
struct btmrvl_private *priv;
};
......@@ -92,6 +94,8 @@ struct btmrvl_sdio_card {
struct btmrvl_sdio_device {
const char *helper;
const char *firmware;
const struct btmrvl_sdio_card_reg *reg;
u16 sd_blksz_fw_dl;
};
......
......@@ -201,8 +201,13 @@ static struct sk_buff *ath_dequeue(struct hci_uart *hu)
/* Recv data */
static int ath_recv(struct hci_uart *hu, void *data, int count)
{
if (hci_recv_stream_fragment(hu->hdev, data, count) < 0)
int ret;
ret = hci_recv_stream_fragment(hu->hdev, data, count);
if (ret < 0) {
BT_ERR("Frame Reassembly Failed");
return ret;
}
return count;
}
......
......@@ -151,8 +151,13 @@ static inline int h4_check_data_len(struct h4_struct *h4, int len)
/* Recv data */
static int h4_recv(struct hci_uart *hu, void *data, int count)
{
if (hci_recv_stream_fragment(hu->hdev, data, count) < 0)
int ret;
ret = hci_recv_stream_fragment(hu->hdev, data, count);
if (ret < 0) {
BT_ERR("Frame Reassembly Failed");
return ret;
}
return count;
}
......
......@@ -359,6 +359,7 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty)
*/
static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count)
{
int ret;
struct hci_uart *hu = (void *)tty->disc_data;
if (!hu || tty != hu->tty)
......@@ -368,8 +369,9 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *f
return;
spin_lock(&hu->rx_lock);
hu->proto->recv(hu, (void *) data, count);
hu->hdev->stat.byte_rx += count;
ret = hu->proto->recv(hu, (void *) data, count);
if (ret > 0)
hu->hdev->stat.byte_rx += count;
spin_unlock(&hu->rx_lock);
tty_unthrottle(tty);
......
......@@ -276,10 +276,52 @@ struct l2cap_conn_param_update_rsp {
#define L2CAP_CONN_PARAM_ACCEPTED 0x0000
#define L2CAP_CONN_PARAM_REJECTED 0x0001
/* ----- L2CAP connections ----- */
struct l2cap_chan_list {
struct sock *head;
rwlock_t lock;
/* ----- L2CAP channels and connections ----- */
struct srej_list {
__u8 tx_seq;
struct list_head list;
};
struct l2cap_chan {
struct sock *sk;
__u8 ident;
__u8 conf_req[64];
__u8 conf_len;
__u8 num_conf_req;
__u8 num_conf_rsp;
__u16 conn_state;
__u8 next_tx_seq;
__u8 expected_ack_seq;
__u8 expected_tx_seq;
__u8 buffer_seq;
__u8 buffer_seq_srej;
__u8 srej_save_reqseq;
__u8 frames_sent;
__u8 unacked_frames;
__u8 retry_count;
__u8 num_acked;
__u16 sdu_len;
__u16 partial_sdu_len;
struct sk_buff *sdu;
__u8 remote_tx_win;
__u8 remote_max_tx;
__u16 remote_mps;
struct timer_list retrans_timer;
struct timer_list monitor_timer;
struct timer_list ack_timer;
struct sk_buff *tx_send_head;
struct sk_buff_head tx_q;
struct sk_buff_head srej_q;
struct sk_buff_head busy_q;
struct work_struct busy_work;
struct list_head srej_l;
struct list_head list;
};
struct l2cap_conn {
......@@ -305,29 +347,16 @@ struct l2cap_conn {
__u8 disc_reason;
struct l2cap_chan_list chan_list;
};
struct sock_del_list {
struct sock *sk;
struct list_head list;
struct list_head chan_l;
rwlock_t chan_lock;
};
#define L2CAP_INFO_CL_MTU_REQ_SENT 0x01
#define L2CAP_INFO_FEAT_MASK_REQ_SENT 0x04
#define L2CAP_INFO_FEAT_MASK_REQ_DONE 0x08
/* ----- L2CAP channel and socket info ----- */
/* ----- L2CAP socket info ----- */
#define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
#define TX_QUEUE(sk) (&l2cap_pi(sk)->tx_queue)
#define SREJ_QUEUE(sk) (&l2cap_pi(sk)->srej_queue)
#define BUSY_QUEUE(sk) (&l2cap_pi(sk)->busy_queue)
#define SREJ_LIST(sk) (&l2cap_pi(sk)->srej_l.list)
struct srej_list {
__u8 tx_seq;
struct list_head list;
};
struct l2cap_pinfo {
struct bt_sock bt;
......@@ -339,8 +368,6 @@ struct l2cap_pinfo {
__u16 omtu;
__u16 flush_to;
__u8 mode;
__u8 num_conf_req;
__u8 num_conf_rsp;
__u8 fcs;
__u8 sec_level;
......@@ -348,49 +375,18 @@ struct l2cap_pinfo {
__u8 force_reliable;
__u8 flushable;
__u8 conf_req[64];
__u8 conf_len;
__u8 conf_state;
__u16 conn_state;
__u8 next_tx_seq;
__u8 expected_ack_seq;
__u8 expected_tx_seq;
__u8 buffer_seq;
__u8 buffer_seq_srej;
__u8 srej_save_reqseq;
__u8 frames_sent;
__u8 unacked_frames;
__u8 retry_count;
__u8 num_acked;
__u16 sdu_len;
__u16 partial_sdu_len;
struct sk_buff *sdu;
__u8 ident;
__u8 tx_win;
__u8 max_tx;
__u8 remote_tx_win;
__u8 remote_max_tx;
__u16 retrans_timeout;
__u16 monitor_timeout;
__u16 remote_mps;
__u16 mps;
__le16 sport;
struct timer_list retrans_timer;
struct timer_list monitor_timer;
struct timer_list ack_timer;
struct sk_buff_head tx_queue;
struct sk_buff_head srej_queue;
struct sk_buff_head busy_queue;
struct work_struct busy_work;
struct srej_list srej_l;
struct l2cap_conn *conn;
struct sock *next_c;
struct sock *prev_c;
struct l2cap_chan *chan;
};
#define L2CAP_CONF_REQ_SENT 0x01
......@@ -417,24 +413,23 @@ struct l2cap_pinfo {
#define L2CAP_CONN_RNR_SENT 0x0200
#define L2CAP_CONN_SAR_RETRY 0x0400
#define __mod_retrans_timer() mod_timer(&l2cap_pi(sk)->retrans_timer, \
#define __mod_retrans_timer() mod_timer(&chan->retrans_timer, \
jiffies + msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO));
#define __mod_monitor_timer() mod_timer(&l2cap_pi(sk)->monitor_timer, \
#define __mod_monitor_timer() mod_timer(&chan->monitor_timer, \
jiffies + msecs_to_jiffies(L2CAP_DEFAULT_MONITOR_TO));
#define __mod_ack_timer() mod_timer(&l2cap_pi(sk)->ack_timer, \
#define __mod_ack_timer() mod_timer(&chan->ack_timer, \
jiffies + msecs_to_jiffies(L2CAP_DEFAULT_ACK_TO));
static inline int l2cap_tx_window_full(struct sock *sk)
static inline int l2cap_tx_window_full(struct l2cap_chan *ch)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
int sub;
sub = (pi->next_tx_seq - pi->expected_ack_seq) % 64;
sub = (ch->next_tx_seq - ch->expected_ack_seq) % 64;
if (sub < 0)
sub += 64;
return sub == pi->remote_tx_win;
return sub == ch->remote_tx_win;
}
#define __get_txseq(ctrl) (((ctrl) & L2CAP_CTRL_TXSEQ) >> 1)
......@@ -450,18 +445,17 @@ extern struct bt_sock_list l2cap_sk_list;
int l2cap_init_sockets(void);
void l2cap_cleanup_sockets(void);
u8 l2cap_get_ident(struct l2cap_conn *conn);
void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data);
int l2cap_build_conf_req(struct sock *sk, void *data);
void __l2cap_connect_rsp_defer(struct sock *sk);
int __l2cap_wait_ack(struct sock *sk);
struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, size_t len);
struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size_t len);
struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control, u16 sdulen);
int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, size_t len);
int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len);
void l2cap_do_send(struct sock *sk, struct sk_buff *skb);
void l2cap_streaming_send(struct sock *sk);
int l2cap_ertm_send(struct sock *sk);
void l2cap_streaming_send(struct l2cap_chan *chan);
int l2cap_ertm_send(struct l2cap_chan *chan);
void l2cap_sock_set_timer(struct sock *sk, long timeout);
void l2cap_sock_clear_timer(struct sock *sk);
......@@ -470,8 +464,8 @@ void l2cap_sock_kill(struct sock *sk);
void l2cap_sock_init(struct sock *sk, struct sock *parent);
struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
int proto, gfp_t prio);
void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err);
void l2cap_chan_del(struct sock *sk, int err);
void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err);
void l2cap_chan_del(struct l2cap_chan *chan, int err);
int l2cap_do_connect(struct sock *sk);
#endif /* __L2CAP_H */
......@@ -2497,6 +2497,9 @@ static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
hci_dev_lock(hdev);
if (!test_bit(HCI_MGMT, &hdev->flags))
goto unlock;
data = hci_find_remote_oob_data(hdev, &ev->bdaddr);
if (data) {
struct hci_cp_remote_oob_data_reply cp;
......@@ -2515,6 +2518,7 @@ static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
&cp);
}
unlock:
hci_dev_unlock(hdev);
}
......
......@@ -70,108 +70,101 @@ static void l2cap_busy_work(struct work_struct *work);
static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
u8 code, u8 ident, u16 dlen, void *data);
static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
/* ---- L2CAP channels ---- */
static struct sock *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid)
static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
{
struct sock *s;
for (s = l->head; s; s = l2cap_pi(s)->next_c) {
struct l2cap_chan *c;
list_for_each_entry(c, &conn->chan_l, list) {
struct sock *s = c->sk;
if (l2cap_pi(s)->dcid == cid)
break;
return c;
}
return s;
return NULL;
}
static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid)
static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
{
struct sock *s;
for (s = l->head; s; s = l2cap_pi(s)->next_c) {
struct l2cap_chan *c;
list_for_each_entry(c, &conn->chan_l, list) {
struct sock *s = c->sk;
if (l2cap_pi(s)->scid == cid)
break;
return c;
}
return s;
return NULL;
}
/* Find channel with given SCID.
* Returns locked socket */
static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid)
static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
{
struct sock *s;
read_lock(&l->lock);
s = __l2cap_get_chan_by_scid(l, cid);
if (s)
bh_lock_sock(s);
read_unlock(&l->lock);
return s;
struct l2cap_chan *c;
read_lock(&conn->chan_lock);
c = __l2cap_get_chan_by_scid(conn, cid);
if (c)
bh_lock_sock(c->sk);
read_unlock(&conn->chan_lock);
return c;
}
static struct sock *__l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident)
static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
{
struct sock *s;
for (s = l->head; s; s = l2cap_pi(s)->next_c) {
if (l2cap_pi(s)->ident == ident)
break;
struct l2cap_chan *c;
list_for_each_entry(c, &conn->chan_l, list) {
if (c->ident == ident)
return c;
}
return s;
return NULL;
}
static inline struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident)
static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
{
struct sock *s;
read_lock(&l->lock);
s = __l2cap_get_chan_by_ident(l, ident);
if (s)
bh_lock_sock(s);
read_unlock(&l->lock);
return s;
struct l2cap_chan *c;
read_lock(&conn->chan_lock);
c = __l2cap_get_chan_by_ident(conn, ident);
if (c)
bh_lock_sock(c->sk);
read_unlock(&conn->chan_lock);
return c;
}
static u16 l2cap_alloc_cid(struct l2cap_chan_list *l)
static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
{
u16 cid = L2CAP_CID_DYN_START;
for (; cid < L2CAP_CID_DYN_END; cid++) {
if (!__l2cap_get_chan_by_scid(l, cid))
if (!__l2cap_get_chan_by_scid(conn, cid))
return cid;
}
return 0;
}
static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk)
static struct l2cap_chan *l2cap_chan_alloc(struct sock *sk)
{
sock_hold(sk);
if (l->head)
l2cap_pi(l->head)->prev_c = sk;
struct l2cap_chan *chan;
l2cap_pi(sk)->next_c = l->head;
l2cap_pi(sk)->prev_c = NULL;
l->head = sk;
}
static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk)
{
struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c;
write_lock_bh(&l->lock);
if (sk == l->head)
l->head = next;
chan = kzalloc(sizeof(*chan), GFP_ATOMIC);
if (!chan)
return NULL;
if (next)
l2cap_pi(next)->prev_c = prev;
if (prev)
l2cap_pi(prev)->next_c = next;
write_unlock_bh(&l->lock);
chan->sk = sk;
__sock_put(sk);
return chan;
}
static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk)
static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
{
struct l2cap_chan_list *l = &conn->chan_list;
struct sock *sk = chan->sk;
BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid);
......@@ -188,7 +181,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk)
l2cap_pi(sk)->dcid = L2CAP_CID_LE_DATA;
} else {
/* Alloc CID for connection-oriented socket */
l2cap_pi(sk)->scid = l2cap_alloc_cid(l);
l2cap_pi(sk)->scid = l2cap_alloc_cid(conn);
l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
}
} else if (sk->sk_type == SOCK_DGRAM) {
......@@ -203,23 +196,30 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk)
l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
}
__l2cap_chan_link(l, sk);
sock_hold(sk);
list_add(&chan->list, &conn->chan_l);
}
/* Delete channel.
* Must be called on the locked socket. */
void l2cap_chan_del(struct sock *sk, int err)
void l2cap_chan_del(struct l2cap_chan *chan, int err)
{
struct sock *sk = chan->sk;
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
struct sock *parent = bt_sk(sk)->parent;
l2cap_sock_clear_timer(sk);
BT_DBG("sk %p, conn %p, err %d", sk, conn, err);
BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
if (conn) {
/* Unlink from channel list */
l2cap_chan_unlink(&conn->chan_list, sk);
/* Delete from channel list */
write_lock_bh(&conn->chan_lock);
list_del(&chan->list);
write_unlock_bh(&conn->chan_lock);
__sock_put(sk);
l2cap_pi(sk)->conn = NULL;
hci_conn_put(conn->hcon);
}
......@@ -236,23 +236,30 @@ void l2cap_chan_del(struct sock *sk, int err)
} else
sk->sk_state_change(sk);
skb_queue_purge(TX_QUEUE(sk));
if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE &&
l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE))
goto free;
skb_queue_purge(&chan->tx_q);
if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) {
struct srej_list *l, *tmp;
del_timer(&l2cap_pi(sk)->retrans_timer);
del_timer(&l2cap_pi(sk)->monitor_timer);
del_timer(&l2cap_pi(sk)->ack_timer);
del_timer(&chan->retrans_timer);
del_timer(&chan->monitor_timer);
del_timer(&chan->ack_timer);
skb_queue_purge(SREJ_QUEUE(sk));
skb_queue_purge(BUSY_QUEUE(sk));
skb_queue_purge(&chan->srej_q);
skb_queue_purge(&chan->busy_q);
list_for_each_entry_safe(l, tmp, SREJ_LIST(sk), list) {
list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
list_del(&l->list);
kfree(l);
}
}
free:
kfree(chan);
}
static inline u8 l2cap_get_auth_type(struct sock *sk)
......@@ -338,10 +345,11 @@ void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *d
hci_send_acl(conn->hcon, skb, flags);
}
static inline void l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control)
static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
{
struct sk_buff *skb;
struct l2cap_hdr *lh;
struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
struct l2cap_conn *conn = pi->conn;
struct sock *sk = (struct sock *)pi;
int count, hlen = L2CAP_HDR_SIZE + 2;
......@@ -353,19 +361,19 @@ static inline void l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control)
if (pi->fcs == L2CAP_FCS_CRC16)
hlen += 2;
BT_DBG("pi %p, control 0x%2.2x", pi, control);
BT_DBG("chan %p, control 0x%2.2x", chan, control);
count = min_t(unsigned int, conn->mtu, hlen);
control |= L2CAP_CTRL_FRAME_TYPE;
if (pi->conn_state & L2CAP_CONN_SEND_FBIT) {
if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
control |= L2CAP_CTRL_FINAL;
pi->conn_state &= ~L2CAP_CONN_SEND_FBIT;
chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
}
if (pi->conn_state & L2CAP_CONN_SEND_PBIT) {
if (chan->conn_state & L2CAP_CONN_SEND_PBIT) {
control |= L2CAP_CTRL_POLL;
pi->conn_state &= ~L2CAP_CONN_SEND_PBIT;
chan->conn_state &= ~L2CAP_CONN_SEND_PBIT;
}
skb = bt_skb_alloc(count, GFP_ATOMIC);
......@@ -390,17 +398,17 @@ static inline void l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control)
hci_send_acl(pi->conn->hcon, skb, flags);
}
static inline void l2cap_send_rr_or_rnr(struct l2cap_pinfo *pi, u16 control)
static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control)
{
if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
control |= L2CAP_SUPER_RCV_NOT_READY;
pi->conn_state |= L2CAP_CONN_RNR_SENT;
chan->conn_state |= L2CAP_CONN_RNR_SENT;
} else
control |= L2CAP_SUPER_RCV_READY;
control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
l2cap_send_sframe(pi, control);
l2cap_send_sframe(chan, control);
}
static inline int __l2cap_no_conn_pending(struct sock *sk)
......@@ -408,8 +416,9 @@ static inline int __l2cap_no_conn_pending(struct sock *sk)
return !(l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND);
}
static void l2cap_do_start(struct sock *sk)
static void l2cap_do_start(struct l2cap_chan *chan)
{
struct sock *sk = chan->sk;
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
......@@ -421,11 +430,11 @@ static void l2cap_do_start(struct sock *sk)
req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
req.psm = l2cap_pi(sk)->psm;
l2cap_pi(sk)->ident = l2cap_get_ident(conn);
chan->ident = l2cap_get_ident(conn);
l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND;
l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
L2CAP_CONN_REQ, sizeof(req), &req);
l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
sizeof(req), &req);
}
} else {
struct l2cap_info_req req;
......@@ -458,19 +467,20 @@ static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
}
}
void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err)
void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
{
struct sock *sk;
struct l2cap_disconn_req req;
if (!conn)
return;
skb_queue_purge(TX_QUEUE(sk));
sk = chan->sk;
if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) {
del_timer(&l2cap_pi(sk)->retrans_timer);
del_timer(&l2cap_pi(sk)->monitor_timer);
del_timer(&l2cap_pi(sk)->ack_timer);
del_timer(&chan->retrans_timer);
del_timer(&chan->monitor_timer);
del_timer(&chan->ack_timer);
}
req.dcid = cpu_to_le16(l2cap_pi(sk)->dcid);
......@@ -485,17 +495,15 @@ void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err)
/* ---- L2CAP connections ---- */
static void l2cap_conn_start(struct l2cap_conn *conn)
{
struct l2cap_chan_list *l = &conn->chan_list;
struct sock_del_list del, *tmp1, *tmp2;
struct sock *sk;
struct l2cap_chan *chan, *tmp;
BT_DBG("conn %p", conn);
INIT_LIST_HEAD(&del.list);
read_lock(&conn->chan_lock);
read_lock(&l->lock);
list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
struct sock *sk = chan->sk;
for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
bh_lock_sock(sk);
if (sk->sk_type != SOCK_SEQPACKET &&
......@@ -517,10 +525,11 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
conn->feat_mask)
&& l2cap_pi(sk)->conf_state &
L2CAP_CONF_STATE2_DEVICE) {
tmp1 = kzalloc(sizeof(struct sock_del_list),
GFP_ATOMIC);
tmp1->sk = sk;
list_add_tail(&tmp1->list, &del.list);
/* __l2cap_sock_close() calls list_del(chan)
* so release the lock */
read_unlock_bh(&conn->chan_lock);
__l2cap_sock_close(sk, ECONNRESET);
read_lock_bh(&conn->chan_lock);
bh_unlock_sock(sk);
continue;
}
......@@ -528,11 +537,11 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
req.psm = l2cap_pi(sk)->psm;
l2cap_pi(sk)->ident = l2cap_get_ident(conn);
chan->ident = l2cap_get_ident(conn);
l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND;
l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
L2CAP_CONN_REQ, sizeof(req), &req);
l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
sizeof(req), &req);
} else if (sk->sk_state == BT_CONNECT2) {
struct l2cap_conn_rsp rsp;
......@@ -557,8 +566,8 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
}
l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
L2CAP_CONN_RSP, sizeof(rsp), &rsp);
l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
sizeof(rsp), &rsp);
if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT ||
rsp.result != L2CAP_CR_SUCCESS) {
......@@ -568,22 +577,14 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
l2cap_build_conf_req(sk, buf), buf);
l2cap_pi(sk)->num_conf_req++;
l2cap_build_conf_req(chan, buf), buf);
chan->num_conf_req++;
}
bh_unlock_sock(sk);
}
read_unlock(&l->lock);
list_for_each_entry_safe(tmp1, tmp2, &del.list, list) {
bh_lock_sock(tmp1->sk);
__l2cap_sock_close(tmp1->sk, ECONNRESET);
bh_unlock_sock(tmp1->sk);
list_del(&tmp1->list);
kfree(tmp1);
}
read_unlock(&conn->chan_lock);
}
/* Find socket with cid and source bdaddr.
......@@ -591,7 +592,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
*/
static struct sock *l2cap_get_sock_by_scid(int state, __le16 cid, bdaddr_t *src)
{
struct sock *s, *sk = NULL, *sk1 = NULL;
struct sock *sk = NULL, *sk1 = NULL;
struct hlist_node *node;
read_lock(&l2cap_sk_list.lock);
......@@ -610,18 +611,16 @@ static struct sock *l2cap_get_sock_by_scid(int state, __le16 cid, bdaddr_t *src)
sk1 = sk;
}
}
s = node ? sk : sk1;
if (s)
bh_lock_sock(s);
read_unlock(&l2cap_sk_list.lock);
return s;
return node ? sk : sk1;
}
static void l2cap_le_conn_ready(struct l2cap_conn *conn)
{
struct l2cap_chan_list *list = &conn->chan_list;
struct sock *parent, *uninitialized_var(sk);
struct sock *parent, *sk;
struct l2cap_chan *chan;
BT_DBG("");
......@@ -631,6 +630,8 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
if (!parent)
return;
bh_lock_sock(parent);
/* Check for backlog size */
if (sk_acceptq_is_full(parent)) {
BT_DBG("backlog full %d", parent->sk_ack_backlog);
......@@ -641,24 +642,33 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
if (!sk)
goto clean;
write_lock_bh(&list->lock);
chan = l2cap_chan_alloc(sk);
if (!chan) {
l2cap_sock_kill(sk);
goto clean;
}
write_lock_bh(&conn->chan_lock);
hci_conn_hold(conn->hcon);
l2cap_sock_init(sk, parent);
bacpy(&bt_sk(sk)->src, conn->src);
bacpy(&bt_sk(sk)->dst, conn->dst);
bt_accept_enqueue(parent, sk);
__l2cap_chan_add(conn, sk);
__l2cap_chan_add(conn, chan);
l2cap_pi(sk)->chan = chan;
l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
sk->sk_state = BT_CONNECTED;
parent->sk_data_ready(parent, 0);
write_unlock_bh(&list->lock);
write_unlock_bh(&conn->chan_lock);
clean:
bh_unlock_sock(parent);
......@@ -666,17 +676,18 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
static void l2cap_conn_ready(struct l2cap_conn *conn)
{
struct l2cap_chan_list *l = &conn->chan_list;
struct sock *sk;
struct l2cap_chan *chan;
BT_DBG("conn %p", conn);
if (!conn->hcon->out && conn->hcon->type == LE_LINK)
l2cap_le_conn_ready(conn);
read_lock(&l->lock);
read_lock(&conn->chan_lock);
list_for_each_entry(chan, &conn->chan_l, list) {
struct sock *sk = chan->sk;
for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
bh_lock_sock(sk);
if (conn->hcon->type == LE_LINK) {
......@@ -691,30 +702,31 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
sk->sk_state = BT_CONNECTED;
sk->sk_state_change(sk);
} else if (sk->sk_state == BT_CONNECT)
l2cap_do_start(sk);
l2cap_do_start(chan);
bh_unlock_sock(sk);
}
read_unlock(&l->lock);
read_unlock(&conn->chan_lock);
}
/* Notify sockets that we cannot guaranty reliability anymore */
static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
{
struct l2cap_chan_list *l = &conn->chan_list;
struct sock *sk;
struct l2cap_chan *chan;
BT_DBG("conn %p", conn);
read_lock(&l->lock);
read_lock(&conn->chan_lock);
list_for_each_entry(chan, &conn->chan_l, list) {
struct sock *sk = chan->sk;
for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
if (l2cap_pi(sk)->force_reliable)
sk->sk_err = err;
}
read_unlock(&l->lock);
read_unlock(&conn->chan_lock);
}
static void l2cap_info_timeout(unsigned long arg)
......@@ -754,7 +766,9 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
conn->feat_mask = 0;
spin_lock_init(&conn->lock);
rwlock_init(&conn->chan_list.lock);
rwlock_init(&conn->chan_lock);
INIT_LIST_HEAD(&conn->chan_l);
if (hcon->type != LE_LINK)
setup_timer(&conn->info_timer, l2cap_info_timeout,
......@@ -768,6 +782,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
static void l2cap_conn_del(struct hci_conn *hcon, int err)
{
struct l2cap_conn *conn = hcon->l2cap_data;
struct l2cap_chan *chan, *l;
struct sock *sk;
if (!conn)
......@@ -778,9 +793,10 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
kfree_skb(conn->rx_skb);
/* Kill channels */
while ((sk = conn->chan_list.head)) {
list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
sk = chan->sk;
bh_lock_sock(sk);
l2cap_chan_del(sk, err);
l2cap_chan_del(chan, err);
bh_unlock_sock(sk);
l2cap_sock_kill(sk);
}
......@@ -792,12 +808,11 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
kfree(conn);
}
static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk)
static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
{
struct l2cap_chan_list *l = &conn->chan_list;
write_lock_bh(&l->lock);
__l2cap_chan_add(conn, sk);
write_unlock_bh(&l->lock);
write_lock_bh(&conn->chan_lock);
__l2cap_chan_add(conn, chan);
write_unlock_bh(&conn->chan_lock);
}
/* ---- Socket interface ---- */
......@@ -837,6 +852,7 @@ int l2cap_do_connect(struct sock *sk)
bdaddr_t *src = &bt_sk(sk)->src;
bdaddr_t *dst = &bt_sk(sk)->dst;
struct l2cap_conn *conn;
struct l2cap_chan *chan;
struct hci_conn *hcon;
struct hci_dev *hdev;
__u8 auth_type;
......@@ -872,10 +888,19 @@ int l2cap_do_connect(struct sock *sk)
goto done;
}
chan = l2cap_chan_alloc(sk);
if (!chan) {
hci_conn_put(hcon);
err = -ENOMEM;
goto done;
}
/* Update source addr of the socket */
bacpy(src, conn->src);
l2cap_chan_add(conn, sk);
l2cap_chan_add(conn, chan);
l2cap_pi(sk)->chan = chan;
sk->sk_state = BT_CONNECT;
l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
......@@ -887,7 +912,7 @@ int l2cap_do_connect(struct sock *sk)
if (l2cap_check_security(sk))
sk->sk_state = BT_CONNECTED;
} else
l2cap_do_start(sk);
l2cap_do_start(chan);
}
err = 0;
......@@ -905,7 +930,7 @@ int __l2cap_wait_ack(struct sock *sk)
int timeo = HZ/5;
add_wait_queue(sk_sleep(sk), &wait);
while ((l2cap_pi(sk)->unacked_frames > 0 && l2cap_pi(sk)->conn)) {
while ((l2cap_pi(sk)->chan->unacked_frames > 0 && l2cap_pi(sk)->conn)) {
set_current_state(TASK_INTERRUPTIBLE);
if (!timeo)
......@@ -931,57 +956,59 @@ int __l2cap_wait_ack(struct sock *sk)
static void l2cap_monitor_timeout(unsigned long arg)
{
struct sock *sk = (void *) arg;
struct l2cap_chan *chan = (void *) arg;
struct sock *sk = chan->sk;
BT_DBG("sk %p", sk);
BT_DBG("chan %p", chan);
bh_lock_sock(sk);
if (l2cap_pi(sk)->retry_count >= l2cap_pi(sk)->remote_max_tx) {
l2cap_send_disconn_req(l2cap_pi(sk)->conn, sk, ECONNABORTED);
if (chan->retry_count >= chan->remote_max_tx) {
l2cap_send_disconn_req(l2cap_pi(sk)->conn, chan, ECONNABORTED);
bh_unlock_sock(sk);
return;
}
l2cap_pi(sk)->retry_count++;
chan->retry_count++;
__mod_monitor_timer();
l2cap_send_rr_or_rnr(l2cap_pi(sk), L2CAP_CTRL_POLL);
l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
bh_unlock_sock(sk);
}
static void l2cap_retrans_timeout(unsigned long arg)
{
struct sock *sk = (void *) arg;
struct l2cap_chan *chan = (void *) arg;
struct sock *sk = chan->sk;
BT_DBG("sk %p", sk);
BT_DBG("chan %p", chan);
bh_lock_sock(sk);
l2cap_pi(sk)->retry_count = 1;
chan->retry_count = 1;
__mod_monitor_timer();
l2cap_pi(sk)->conn_state |= L2CAP_CONN_WAIT_F;
chan->conn_state |= L2CAP_CONN_WAIT_F;
l2cap_send_rr_or_rnr(l2cap_pi(sk), L2CAP_CTRL_POLL);
l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
bh_unlock_sock(sk);
}
static void l2cap_drop_acked_frames(struct sock *sk)
static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
{
struct sk_buff *skb;
while ((skb = skb_peek(TX_QUEUE(sk))) &&
l2cap_pi(sk)->unacked_frames) {
if (bt_cb(skb)->tx_seq == l2cap_pi(sk)->expected_ack_seq)
while ((skb = skb_peek(&chan->tx_q)) &&
chan->unacked_frames) {
if (bt_cb(skb)->tx_seq == chan->expected_ack_seq)
break;
skb = skb_dequeue(TX_QUEUE(sk));
skb = skb_dequeue(&chan->tx_q);
kfree_skb(skb);
l2cap_pi(sk)->unacked_frames--;
chan->unacked_frames--;
}
if (!l2cap_pi(sk)->unacked_frames)
del_timer(&l2cap_pi(sk)->retrans_timer);
if (!chan->unacked_frames)
del_timer(&chan->retrans_timer);
}
void l2cap_do_send(struct sock *sk, struct sk_buff *skb)
......@@ -1000,15 +1027,16 @@ void l2cap_do_send(struct sock *sk, struct sk_buff *skb)
hci_send_acl(hcon, skb, flags);
}
void l2cap_streaming_send(struct sock *sk)
void l2cap_streaming_send(struct l2cap_chan *chan)
{
struct sock *sk = chan->sk;
struct sk_buff *skb;
struct l2cap_pinfo *pi = l2cap_pi(sk);
u16 control, fcs;
while ((skb = skb_dequeue(TX_QUEUE(sk)))) {
while ((skb = skb_dequeue(&chan->tx_q))) {
control = get_unaligned_le16(skb->data + L2CAP_HDR_SIZE);
control |= pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT;
control |= chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT;
put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE);
if (pi->fcs == L2CAP_FCS_CRC16) {
......@@ -1018,17 +1046,18 @@ void l2cap_streaming_send(struct sock *sk)
l2cap_do_send(sk, skb);
pi->next_tx_seq = (pi->next_tx_seq + 1) % 64;
chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
}
}
static void l2cap_retransmit_one_frame(struct sock *sk, u8 tx_seq)
static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
{
struct sock *sk = chan->sk;
struct l2cap_pinfo *pi = l2cap_pi(sk);
struct sk_buff *skb, *tx_skb;
u16 control, fcs;
skb = skb_peek(TX_QUEUE(sk));
skb = skb_peek(&chan->tx_q);
if (!skb)
return;
......@@ -1036,14 +1065,14 @@ static void l2cap_retransmit_one_frame(struct sock *sk, u8 tx_seq)
if (bt_cb(skb)->tx_seq == tx_seq)
break;
if (skb_queue_is_last(TX_QUEUE(sk), skb))
if (skb_queue_is_last(&chan->tx_q, skb))
return;
} while ((skb = skb_queue_next(TX_QUEUE(sk), skb)));
} while ((skb = skb_queue_next(&chan->tx_q, skb)));
if (pi->remote_max_tx &&
bt_cb(skb)->retries == pi->remote_max_tx) {
l2cap_send_disconn_req(pi->conn, sk, ECONNABORTED);
if (chan->remote_max_tx &&
bt_cb(skb)->retries == chan->remote_max_tx) {
l2cap_send_disconn_req(pi->conn, chan, ECONNABORTED);
return;
}
......@@ -1051,12 +1080,12 @@ static void l2cap_retransmit_one_frame(struct sock *sk, u8 tx_seq)
bt_cb(skb)->retries++;
control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
if (pi->conn_state & L2CAP_CONN_SEND_FBIT) {
if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
control |= L2CAP_CTRL_FINAL;
pi->conn_state &= ~L2CAP_CONN_SEND_FBIT;
chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
}
control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
| (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
......@@ -1069,9 +1098,10 @@ static void l2cap_retransmit_one_frame(struct sock *sk, u8 tx_seq)
l2cap_do_send(sk, tx_skb);
}
int l2cap_ertm_send(struct sock *sk)
int l2cap_ertm_send(struct l2cap_chan *chan)
{
struct sk_buff *skb, *tx_skb;
struct sock *sk = chan->sk;
struct l2cap_pinfo *pi = l2cap_pi(sk);
u16 control, fcs;
int nsent = 0;
......@@ -1079,11 +1109,11 @@ int l2cap_ertm_send(struct sock *sk)
if (sk->sk_state != BT_CONNECTED)
return -ENOTCONN;
while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(sk))) {
while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
if (pi->remote_max_tx &&
bt_cb(skb)->retries == pi->remote_max_tx) {
l2cap_send_disconn_req(pi->conn, sk, ECONNABORTED);
if (chan->remote_max_tx &&
bt_cb(skb)->retries == chan->remote_max_tx) {
l2cap_send_disconn_req(pi->conn, chan, ECONNABORTED);
break;
}
......@@ -1094,12 +1124,12 @@ int l2cap_ertm_send(struct sock *sk)
control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
control &= L2CAP_CTRL_SAR;
if (pi->conn_state & L2CAP_CONN_SEND_FBIT) {
if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
control |= L2CAP_CTRL_FINAL;
pi->conn_state &= ~L2CAP_CONN_SEND_FBIT;
chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
}
control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
| (pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
| (chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
......@@ -1112,18 +1142,18 @@ int l2cap_ertm_send(struct sock *sk)
__mod_retrans_timer();
bt_cb(skb)->tx_seq = pi->next_tx_seq;
pi->next_tx_seq = (pi->next_tx_seq + 1) % 64;
bt_cb(skb)->tx_seq = chan->next_tx_seq;
chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
if (bt_cb(skb)->retries == 1)
pi->unacked_frames++;
chan->unacked_frames++;
pi->frames_sent++;
chan->frames_sent++;
if (skb_queue_is_last(TX_QUEUE(sk), skb))
sk->sk_send_head = NULL;
if (skb_queue_is_last(&chan->tx_q, skb))
chan->tx_send_head = NULL;
else
sk->sk_send_head = skb_queue_next(TX_QUEUE(sk), skb);
chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
nsent++;
}
......@@ -1131,41 +1161,39 @@ int l2cap_ertm_send(struct sock *sk)
return nsent;
}
static int l2cap_retransmit_frames(struct sock *sk)
static int l2cap_retransmit_frames(struct l2cap_chan *chan)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
int ret;
if (!skb_queue_empty(TX_QUEUE(sk)))
sk->sk_send_head = TX_QUEUE(sk)->next;
if (!skb_queue_empty(&chan->tx_q))
chan->tx_send_head = chan->tx_q.next;
pi->next_tx_seq = pi->expected_ack_seq;
ret = l2cap_ertm_send(sk);
chan->next_tx_seq = chan->expected_ack_seq;
ret = l2cap_ertm_send(chan);
return ret;
}
static void l2cap_send_ack(struct l2cap_pinfo *pi)
static void l2cap_send_ack(struct l2cap_chan *chan)
{
struct sock *sk = (struct sock *)pi;
u16 control = 0;
control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
control |= L2CAP_SUPER_RCV_NOT_READY;
pi->conn_state |= L2CAP_CONN_RNR_SENT;
l2cap_send_sframe(pi, control);
chan->conn_state |= L2CAP_CONN_RNR_SENT;
l2cap_send_sframe(chan, control);
return;
}
if (l2cap_ertm_send(sk) > 0)
if (l2cap_ertm_send(chan) > 0)
return;
control |= L2CAP_SUPER_RCV_READY;
l2cap_send_sframe(pi, control);
l2cap_send_sframe(chan, control);
}
static void l2cap_send_srejtail(struct sock *sk)
static void l2cap_send_srejtail(struct l2cap_chan *chan)
{
struct srej_list *tail;
u16 control;
......@@ -1173,10 +1201,10 @@ static void l2cap_send_srejtail(struct sock *sk)
control = L2CAP_SUPER_SELECT_REJECT;
control |= L2CAP_CTRL_FINAL;
tail = list_entry(SREJ_LIST(sk)->prev, struct srej_list, list);
tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
control |= tail->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
l2cap_send_sframe(l2cap_pi(sk), control);
l2cap_send_sframe(chan, control);
}
static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, int len, int count, struct sk_buff *skb)
......@@ -1313,9 +1341,9 @@ struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, siz
return skb;
}
int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, size_t len)
int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
struct sock *sk = chan->sk;
struct sk_buff *skb;
struct sk_buff_head sar_queue;
u16 control;
......@@ -1323,20 +1351,20 @@ int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, size_t len)
skb_queue_head_init(&sar_queue);
control = L2CAP_SDU_START;
skb = l2cap_create_iframe_pdu(sk, msg, pi->remote_mps, control, len);
skb = l2cap_create_iframe_pdu(sk, msg, chan->remote_mps, control, len);
if (IS_ERR(skb))
return PTR_ERR(skb);
__skb_queue_tail(&sar_queue, skb);
len -= pi->remote_mps;
size += pi->remote_mps;
len -= chan->remote_mps;
size += chan->remote_mps;
while (len > 0) {
size_t buflen;
if (len > pi->remote_mps) {
if (len > chan->remote_mps) {
control = L2CAP_SDU_CONTINUE;
buflen = pi->remote_mps;
buflen = chan->remote_mps;
} else {
control = L2CAP_SDU_END;
buflen = len;
......@@ -1352,9 +1380,9 @@ int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, size_t len)
len -= buflen;
size += buflen;
}
skb_queue_splice_tail(&sar_queue, TX_QUEUE(sk));
if (sk->sk_send_head == NULL)
sk->sk_send_head = sar_queue.next;
skb_queue_splice_tail(&sar_queue, &chan->tx_q);
if (chan->tx_send_head == NULL)
chan->tx_send_head = sar_queue.next;
return size;
}
......@@ -1385,14 +1413,14 @@ static void l2cap_chan_ready(struct sock *sk)
/* Copy frame to all raw sockets on that connection */
static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct l2cap_chan_list *l = &conn->chan_list;
struct sk_buff *nskb;
struct sock *sk;
struct l2cap_chan *chan;
BT_DBG("conn %p", conn);
read_lock(&l->lock);
for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
read_lock(&conn->chan_lock);
list_for_each_entry(chan, &conn->chan_l, list) {
struct sock *sk = chan->sk;
if (sk->sk_type != SOCK_RAW)
continue;
......@@ -1406,7 +1434,7 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
if (sock_queue_rcv_skb(sk, nskb))
kfree_skb(nskb);
}
read_unlock(&l->lock);
read_unlock(&conn->chan_lock);
}
/* ---- L2CAP signalling commands ---- */
......@@ -1538,32 +1566,35 @@ static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
static void l2cap_ack_timeout(unsigned long arg)
{
struct sock *sk = (void *) arg;
struct l2cap_chan *chan = (void *) arg;
bh_lock_sock(sk);
l2cap_send_ack(l2cap_pi(sk));
bh_unlock_sock(sk);
bh_lock_sock(chan->sk);
l2cap_send_ack(chan);
bh_unlock_sock(chan->sk);
}
static inline void l2cap_ertm_init(struct sock *sk)
static inline void l2cap_ertm_init(struct l2cap_chan *chan)
{
l2cap_pi(sk)->expected_ack_seq = 0;
l2cap_pi(sk)->unacked_frames = 0;
l2cap_pi(sk)->buffer_seq = 0;
l2cap_pi(sk)->num_acked = 0;
l2cap_pi(sk)->frames_sent = 0;
struct sock *sk = chan->sk;
chan->expected_ack_seq = 0;
chan->unacked_frames = 0;
chan->buffer_seq = 0;
chan->num_acked = 0;
chan->frames_sent = 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);
setup_timer(&l2cap_pi(sk)->ack_timer,
l2cap_ack_timeout, (unsigned long) sk);
setup_timer(&chan->retrans_timer, l2cap_retrans_timeout,
(unsigned long) chan);
setup_timer(&chan->monitor_timer, l2cap_monitor_timeout,
(unsigned long) chan);
setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan);
__skb_queue_head_init(SREJ_QUEUE(sk));
__skb_queue_head_init(BUSY_QUEUE(sk));
skb_queue_head_init(&chan->srej_q);
skb_queue_head_init(&chan->busy_q);
INIT_WORK(&l2cap_pi(sk)->busy_work, l2cap_busy_work);
INIT_LIST_HEAD(&chan->srej_l);
INIT_WORK(&chan->busy_work, l2cap_busy_work);
sk->sk_backlog_rcv = l2cap_ertm_data_rcv;
}
......@@ -1581,16 +1612,16 @@ static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
}
}
int l2cap_build_conf_req(struct sock *sk, void *data)
static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
struct l2cap_conf_req *req = data;
struct l2cap_conf_rfc rfc = { .mode = pi->mode };
void *ptr = req->data;
BT_DBG("sk %p", sk);
BT_DBG("chan %p", chan);
if (pi->num_conf_req || pi->num_conf_rsp)
if (chan->num_conf_req || chan->num_conf_rsp)
goto done;
switch (pi->mode) {
......@@ -1679,20 +1710,20 @@ int l2cap_build_conf_req(struct sock *sk, void *data)
return ptr - data;
}
static int l2cap_parse_conf_req(struct sock *sk, void *data)
static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
struct l2cap_conf_rsp *rsp = data;
void *ptr = rsp->data;
void *req = pi->conf_req;
int len = pi->conf_len;
void *req = chan->conf_req;
int len = chan->conf_len;
int type, hint, olen;
unsigned long val;
struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
u16 mtu = L2CAP_DEFAULT_MTU;
u16 result = L2CAP_CONF_SUCCESS;
BT_DBG("sk %p", sk);
BT_DBG("chan %p", chan);
while (len >= L2CAP_CONF_OPT_SIZE) {
len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
......@@ -1733,7 +1764,7 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
}
}
if (pi->num_conf_rsp || pi->num_conf_req > 1)
if (chan->num_conf_rsp || chan->num_conf_req > 1)
goto done;
switch (pi->mode) {
......@@ -1756,7 +1787,7 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
result = L2CAP_CONF_UNACCEPT;
rfc.mode = pi->mode;
if (pi->num_conf_rsp == 1)
if (chan->num_conf_rsp == 1)
return -ECONNREFUSED;
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
......@@ -1783,13 +1814,13 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
break;
case L2CAP_MODE_ERTM:
pi->remote_tx_win = rfc.txwin_size;
pi->remote_max_tx = rfc.max_transmit;
chan->remote_tx_win = rfc.txwin_size;
chan->remote_max_tx = rfc.max_transmit;
if (le16_to_cpu(rfc.max_pdu_size) > pi->conn->mtu - 10)
rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10);
pi->remote_mps = le16_to_cpu(rfc.max_pdu_size);
chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
rfc.retrans_timeout =
le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
......@@ -1807,7 +1838,7 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
if (le16_to_cpu(rfc.max_pdu_size) > pi->conn->mtu - 10)
rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10);
pi->remote_mps = le16_to_cpu(rfc.max_pdu_size);
chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
pi->conf_state |= L2CAP_CONF_MODE_DONE;
......@@ -1916,6 +1947,31 @@ static int l2cap_build_conf_rsp(struct sock *sk, void *data, u16 result, u16 fla
return ptr - data;
}
void __l2cap_connect_rsp_defer(struct sock *sk)
{
struct l2cap_conn_rsp rsp;
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
u8 buf[128];
sk->sk_state = BT_CONFIG;
rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
l2cap_send_cmd(conn, chan->ident,
L2CAP_CONN_RSP, sizeof(rsp), &rsp);
if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)
return;
l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
l2cap_build_conf_req(chan, buf), buf);
chan->num_conf_req++;
}
static void l2cap_conf_rfc_get(struct sock *sk, void *rsp, int len)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
......@@ -1973,9 +2029,9 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hd
static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
{
struct l2cap_chan_list *list = &conn->chan_list;
struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
struct l2cap_conn_rsp rsp;
struct l2cap_chan *chan = NULL;
struct sock *parent, *sk = NULL;
int result, status = L2CAP_CS_NO_INFO;
......@@ -2013,11 +2069,17 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
if (!sk)
goto response;
write_lock_bh(&list->lock);
chan = l2cap_chan_alloc(sk);
if (!chan) {
l2cap_sock_kill(sk);
goto response;
}
write_lock_bh(&conn->chan_lock);
/* Check if we already have channel with that dcid */
if (__l2cap_get_chan_by_dcid(list, scid)) {
write_unlock_bh(&list->lock);
if (__l2cap_get_chan_by_dcid(conn, scid)) {
write_unlock_bh(&conn->chan_lock);
sock_set_flag(sk, SOCK_ZAPPED);
l2cap_sock_kill(sk);
goto response;
......@@ -2033,12 +2095,15 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
bt_accept_enqueue(parent, sk);
__l2cap_chan_add(conn, sk);
__l2cap_chan_add(conn, chan);
l2cap_pi(sk)->chan = chan;
dcid = l2cap_pi(sk)->scid;
l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
l2cap_pi(sk)->ident = cmd->ident;
chan->ident = cmd->ident;
if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
if (l2cap_check_security(sk)) {
......@@ -2063,7 +2128,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
status = L2CAP_CS_NO_INFO;
}
write_unlock_bh(&list->lock);
write_unlock_bh(&conn->chan_lock);
response:
bh_unlock_sock(parent);
......@@ -2089,13 +2154,13 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
L2CAP_INFO_REQ, sizeof(info), &info);
}
if (sk && !(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) &&
if (chan && !(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) &&
result == L2CAP_CR_SUCCESS) {
u8 buf[128];
l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
l2cap_build_conf_req(sk, buf), buf);
l2cap_pi(sk)->num_conf_req++;
l2cap_build_conf_req(chan, buf), buf);
chan->num_conf_req++;
}
return 0;
......@@ -2105,6 +2170,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
{
struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
u16 scid, dcid, result, status;
struct l2cap_chan *chan;
struct sock *sk;
u8 req[128];
......@@ -2116,19 +2182,21 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
if (scid) {
sk = l2cap_get_chan_by_scid(&conn->chan_list, scid);
if (!sk)
chan = l2cap_get_chan_by_scid(conn, scid);
if (!chan)
return -EFAULT;
} else {
sk = l2cap_get_chan_by_ident(&conn->chan_list, cmd->ident);
if (!sk)
chan = l2cap_get_chan_by_ident(conn, cmd->ident);
if (!chan)
return -EFAULT;
}
sk = chan->sk;
switch (result) {
case L2CAP_CR_SUCCESS:
sk->sk_state = BT_CONFIG;
l2cap_pi(sk)->ident = 0;
chan->ident = 0;
l2cap_pi(sk)->dcid = dcid;
l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_CONNECT_PEND;
......@@ -2138,8 +2206,8 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
l2cap_build_conf_req(sk, req), req);
l2cap_pi(sk)->num_conf_req++;
l2cap_build_conf_req(chan, req), req);
chan->num_conf_req++;
break;
case L2CAP_CR_PEND:
......@@ -2155,7 +2223,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
break;
}
l2cap_chan_del(sk, ECONNREFUSED);
l2cap_chan_del(chan, ECONNREFUSED);
break;
}
......@@ -2179,6 +2247,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
u16 dcid, flags;
u8 rsp[64];
struct l2cap_chan *chan;
struct sock *sk;
int len;
......@@ -2187,10 +2256,12 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid);
if (!sk)
chan = l2cap_get_chan_by_scid(conn, dcid);
if (!chan)
return -ENOENT;
sk = chan->sk;
if (sk->sk_state != BT_CONFIG) {
struct l2cap_cmd_rej rej;
......@@ -2202,7 +2273,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
/* Reject if config buffer is too small. */
len = cmd_len - sizeof(*req);
if (l2cap_pi(sk)->conf_len + len > sizeof(l2cap_pi(sk)->conf_req)) {
if (chan->conf_len + len > sizeof(chan->conf_req)) {
l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
l2cap_build_conf_rsp(sk, rsp,
L2CAP_CONF_REJECT, flags), rsp);
......@@ -2210,8 +2281,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
}
/* Store config. */
memcpy(l2cap_pi(sk)->conf_req + l2cap_pi(sk)->conf_len, req->data, len);
l2cap_pi(sk)->conf_len += len;
memcpy(chan->conf_req + chan->conf_len, req->data, len);
chan->conf_len += len;
if (flags & 0x0001) {
/* Incomplete config. Send empty response. */
......@@ -2222,17 +2293,17 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
}
/* Complete config. */
len = l2cap_parse_conf_req(sk, rsp);
len = l2cap_parse_conf_req(chan, rsp);
if (len < 0) {
l2cap_send_disconn_req(conn, sk, ECONNRESET);
l2cap_send_disconn_req(conn, chan, ECONNRESET);
goto unlock;
}
l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
l2cap_pi(sk)->num_conf_rsp++;
chan->num_conf_rsp++;
/* Reset config buffer. */
l2cap_pi(sk)->conf_len = 0;
chan->conf_len = 0;
if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE))
goto unlock;
......@@ -2242,11 +2313,11 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
sk->sk_state = BT_CONNECTED;
l2cap_pi(sk)->next_tx_seq = 0;
l2cap_pi(sk)->expected_tx_seq = 0;
__skb_queue_head_init(TX_QUEUE(sk));
chan->next_tx_seq = 0;
chan->expected_tx_seq = 0;
skb_queue_head_init(&chan->tx_q);
if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM)
l2cap_ertm_init(sk);
l2cap_ertm_init(chan);
l2cap_chan_ready(sk);
goto unlock;
......@@ -2256,8 +2327,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
u8 buf[64];
l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
l2cap_build_conf_req(sk, buf), buf);
l2cap_pi(sk)->num_conf_req++;
l2cap_build_conf_req(chan, buf), buf);
chan->num_conf_req++;
}
unlock:
......@@ -2269,6 +2340,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
{
struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
u16 scid, flags, result;
struct l2cap_chan *chan;
struct sock *sk;
int len = cmd->len - sizeof(*rsp);
......@@ -2279,21 +2351,23 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x",
scid, flags, result);
sk = l2cap_get_chan_by_scid(&conn->chan_list, scid);
if (!sk)
chan = l2cap_get_chan_by_scid(conn, scid);
if (!chan)
return 0;
sk = chan->sk;
switch (result) {
case L2CAP_CONF_SUCCESS:
l2cap_conf_rfc_get(sk, rsp->data, len);
break;
case L2CAP_CONF_UNACCEPT:
if (l2cap_pi(sk)->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
char req[64];
if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
l2cap_send_disconn_req(conn, sk, ECONNRESET);
l2cap_send_disconn_req(conn, chan, ECONNRESET);
goto done;
}
......@@ -2302,13 +2376,13 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
len = l2cap_parse_conf_rsp(sk, rsp->data,
len, req, &result);
if (len < 0) {
l2cap_send_disconn_req(conn, sk, ECONNRESET);
l2cap_send_disconn_req(conn, chan, ECONNRESET);
goto done;
}
l2cap_send_cmd(conn, l2cap_get_ident(conn),
L2CAP_CONF_REQ, len, req);
l2cap_pi(sk)->num_conf_req++;
chan->num_conf_req++;
if (result != L2CAP_CONF_SUCCESS)
goto done;
break;
......@@ -2317,7 +2391,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
default:
sk->sk_err = ECONNRESET;
l2cap_sock_set_timer(sk, HZ * 5);
l2cap_send_disconn_req(conn, sk, ECONNRESET);
l2cap_send_disconn_req(conn, chan, ECONNRESET);
goto done;
}
......@@ -2330,11 +2404,11 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
set_default_fcs(l2cap_pi(sk));
sk->sk_state = BT_CONNECTED;
l2cap_pi(sk)->next_tx_seq = 0;
l2cap_pi(sk)->expected_tx_seq = 0;
__skb_queue_head_init(TX_QUEUE(sk));
chan->next_tx_seq = 0;
chan->expected_tx_seq = 0;
skb_queue_head_init(&chan->tx_q);
if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM)
l2cap_ertm_init(sk);
l2cap_ertm_init(chan);
l2cap_chan_ready(sk);
}
......@@ -2349,6 +2423,7 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
struct l2cap_disconn_rsp rsp;
u16 dcid, scid;
struct l2cap_chan *chan;
struct sock *sk;
scid = __le16_to_cpu(req->scid);
......@@ -2356,10 +2431,12 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid);
if (!sk)
chan = l2cap_get_chan_by_scid(conn, dcid);
if (!chan)
return 0;
sk = chan->sk;
rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
......@@ -2375,7 +2452,7 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
return 0;
}
l2cap_chan_del(sk, ECONNRESET);
l2cap_chan_del(chan, ECONNRESET);
bh_unlock_sock(sk);
l2cap_sock_kill(sk);
......@@ -2386,6 +2463,7 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
{
struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
u16 dcid, scid;
struct l2cap_chan *chan;
struct sock *sk;
scid = __le16_to_cpu(rsp->scid);
......@@ -2393,10 +2471,12 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
sk = l2cap_get_chan_by_scid(&conn->chan_list, scid);
if (!sk)
chan = l2cap_get_chan_by_scid(conn, scid);
if (!chan)
return 0;
sk = chan->sk;
/* don't delete l2cap channel if sk is owned by user */
if (sock_owned_by_user(sk)) {
sk->sk_state = BT_DISCONN;
......@@ -2406,7 +2486,7 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
return 0;
}
l2cap_chan_del(sk, 0);
l2cap_chan_del(chan, 0);
bh_unlock_sock(sk);
l2cap_sock_kill(sk);
......@@ -2709,49 +2789,47 @@ static int l2cap_check_fcs(struct l2cap_pinfo *pi, struct sk_buff *skb)
return 0;
}
static inline void l2cap_send_i_or_rr_or_rnr(struct sock *sk)
static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
u16 control = 0;
pi->frames_sent = 0;
chan->frames_sent = 0;
control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
control |= L2CAP_SUPER_RCV_NOT_READY;
l2cap_send_sframe(pi, control);
pi->conn_state |= L2CAP_CONN_RNR_SENT;
l2cap_send_sframe(chan, control);
chan->conn_state |= L2CAP_CONN_RNR_SENT;
}
if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY)
l2cap_retransmit_frames(sk);
if (chan->conn_state & L2CAP_CONN_REMOTE_BUSY)
l2cap_retransmit_frames(chan);
l2cap_ertm_send(sk);
l2cap_ertm_send(chan);
if (!(pi->conn_state & L2CAP_CONN_LOCAL_BUSY) &&
pi->frames_sent == 0) {
if (!(chan->conn_state & L2CAP_CONN_LOCAL_BUSY) &&
chan->frames_sent == 0) {
control |= L2CAP_SUPER_RCV_READY;
l2cap_send_sframe(pi, control);
l2cap_send_sframe(chan, control);
}
}
static int l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_seq, u8 sar)
static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u8 tx_seq, u8 sar)
{
struct sk_buff *next_skb;
struct l2cap_pinfo *pi = l2cap_pi(sk);
int tx_seq_offset, next_tx_seq_offset;
bt_cb(skb)->tx_seq = tx_seq;
bt_cb(skb)->sar = sar;
next_skb = skb_peek(SREJ_QUEUE(sk));
next_skb = skb_peek(&chan->srej_q);
if (!next_skb) {
__skb_queue_tail(SREJ_QUEUE(sk), skb);
__skb_queue_tail(&chan->srej_q, skb);
return 0;
}
tx_seq_offset = (tx_seq - pi->buffer_seq) % 64;
tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
if (tx_seq_offset < 0)
tx_seq_offset += 64;
......@@ -2760,53 +2838,53 @@ static int l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_s
return -EINVAL;
next_tx_seq_offset = (bt_cb(next_skb)->tx_seq -
pi->buffer_seq) % 64;
chan->buffer_seq) % 64;
if (next_tx_seq_offset < 0)
next_tx_seq_offset += 64;
if (next_tx_seq_offset > tx_seq_offset) {
__skb_queue_before(SREJ_QUEUE(sk), next_skb, skb);
__skb_queue_before(&chan->srej_q, next_skb, skb);
return 0;
}
if (skb_queue_is_last(SREJ_QUEUE(sk), next_skb))
if (skb_queue_is_last(&chan->srej_q, next_skb))
break;
} while ((next_skb = skb_queue_next(SREJ_QUEUE(sk), next_skb)));
} while ((next_skb = skb_queue_next(&chan->srej_q, next_skb)));
__skb_queue_tail(SREJ_QUEUE(sk), skb);
__skb_queue_tail(&chan->srej_q, skb);
return 0;
}
static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control)
static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
struct sk_buff *_skb;
int err;
switch (control & L2CAP_CTRL_SAR) {
case L2CAP_SDU_UNSEGMENTED:
if (pi->conn_state & L2CAP_CONN_SAR_SDU)
if (chan->conn_state & L2CAP_CONN_SAR_SDU)
goto drop;
err = sock_queue_rcv_skb(sk, skb);
err = sock_queue_rcv_skb(chan->sk, skb);
if (!err)
return err;
break;
case L2CAP_SDU_START:
if (pi->conn_state & L2CAP_CONN_SAR_SDU)
if (chan->conn_state & L2CAP_CONN_SAR_SDU)
goto drop;
pi->sdu_len = get_unaligned_le16(skb->data);
chan->sdu_len = get_unaligned_le16(skb->data);
if (pi->sdu_len > pi->imtu)
if (chan->sdu_len > pi->imtu)
goto disconnect;
pi->sdu = bt_skb_alloc(pi->sdu_len, GFP_ATOMIC);
if (!pi->sdu)
chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC);
if (!chan->sdu)
return -ENOMEM;
/* pull sdu_len bytes only after alloc, because of Local Busy
......@@ -2814,63 +2892,63 @@ static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 c
* only once, i.e., when alloc does not fail */
skb_pull(skb, 2);
memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
pi->conn_state |= L2CAP_CONN_SAR_SDU;
pi->partial_sdu_len = skb->len;
chan->conn_state |= L2CAP_CONN_SAR_SDU;
chan->partial_sdu_len = skb->len;
break;
case L2CAP_SDU_CONTINUE:
if (!(pi->conn_state & L2CAP_CONN_SAR_SDU))
if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
goto disconnect;
if (!pi->sdu)
if (!chan->sdu)
goto disconnect;
pi->partial_sdu_len += skb->len;
if (pi->partial_sdu_len > pi->sdu_len)
chan->partial_sdu_len += skb->len;
if (chan->partial_sdu_len > chan->sdu_len)
goto drop;
memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
break;
case L2CAP_SDU_END:
if (!(pi->conn_state & L2CAP_CONN_SAR_SDU))
if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
goto disconnect;
if (!pi->sdu)
if (!chan->sdu)
goto disconnect;
if (!(pi->conn_state & L2CAP_CONN_SAR_RETRY)) {
pi->partial_sdu_len += skb->len;
if (!(chan->conn_state & L2CAP_CONN_SAR_RETRY)) {
chan->partial_sdu_len += skb->len;
if (pi->partial_sdu_len > pi->imtu)
if (chan->partial_sdu_len > pi->imtu)
goto drop;
if (pi->partial_sdu_len != pi->sdu_len)
if (chan->partial_sdu_len != chan->sdu_len)
goto drop;
memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
}
_skb = skb_clone(pi->sdu, GFP_ATOMIC);
_skb = skb_clone(chan->sdu, GFP_ATOMIC);
if (!_skb) {
pi->conn_state |= L2CAP_CONN_SAR_RETRY;
chan->conn_state |= L2CAP_CONN_SAR_RETRY;
return -ENOMEM;
}
err = sock_queue_rcv_skb(sk, _skb);
err = sock_queue_rcv_skb(chan->sk, _skb);
if (err < 0) {
kfree_skb(_skb);
pi->conn_state |= L2CAP_CONN_SAR_RETRY;
chan->conn_state |= L2CAP_CONN_SAR_RETRY;
return err;
}
pi->conn_state &= ~L2CAP_CONN_SAR_RETRY;
pi->conn_state &= ~L2CAP_CONN_SAR_SDU;
chan->conn_state &= ~L2CAP_CONN_SAR_RETRY;
chan->conn_state &= ~L2CAP_CONN_SAR_SDU;
kfree_skb(pi->sdu);
kfree_skb(chan->sdu);
break;
}
......@@ -2878,51 +2956,50 @@ static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 c
return 0;
drop:
kfree_skb(pi->sdu);
pi->sdu = NULL;
kfree_skb(chan->sdu);
chan->sdu = NULL;
disconnect:
l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
l2cap_send_disconn_req(pi->conn, chan, ECONNRESET);
kfree_skb(skb);
return 0;
}
static int l2cap_try_push_rx_skb(struct sock *sk)
static int l2cap_try_push_rx_skb(struct l2cap_chan *chan)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
struct sk_buff *skb;
u16 control;
int err;
while ((skb = skb_dequeue(BUSY_QUEUE(sk)))) {
while ((skb = skb_dequeue(&chan->busy_q))) {
control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
err = l2cap_ertm_reassembly_sdu(sk, skb, control);
err = l2cap_ertm_reassembly_sdu(chan, skb, control);
if (err < 0) {
skb_queue_head(BUSY_QUEUE(sk), skb);
skb_queue_head(&chan->busy_q, skb);
return -EBUSY;
}
pi->buffer_seq = (pi->buffer_seq + 1) % 64;
chan->buffer_seq = (chan->buffer_seq + 1) % 64;
}
if (!(pi->conn_state & L2CAP_CONN_RNR_SENT))
if (!(chan->conn_state & L2CAP_CONN_RNR_SENT))
goto done;
control = pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL;
l2cap_send_sframe(pi, control);
l2cap_pi(sk)->retry_count = 1;
l2cap_send_sframe(chan, control);
chan->retry_count = 1;
del_timer(&pi->retrans_timer);
del_timer(&chan->retrans_timer);
__mod_monitor_timer();
l2cap_pi(sk)->conn_state |= L2CAP_CONN_WAIT_F;
chan->conn_state |= L2CAP_CONN_WAIT_F;
done:
pi->conn_state &= ~L2CAP_CONN_LOCAL_BUSY;
pi->conn_state &= ~L2CAP_CONN_RNR_SENT;
chan->conn_state &= ~L2CAP_CONN_LOCAL_BUSY;
chan->conn_state &= ~L2CAP_CONN_RNR_SENT;
BT_DBG("sk %p, Exit local busy", sk);
BT_DBG("chan %p, Exit local busy", chan);
return 0;
}
......@@ -2930,21 +3007,21 @@ static int l2cap_try_push_rx_skb(struct sock *sk)
static void l2cap_busy_work(struct work_struct *work)
{
DECLARE_WAITQUEUE(wait, current);
struct l2cap_pinfo *pi =
container_of(work, struct l2cap_pinfo, busy_work);
struct sock *sk = (struct sock *)pi;
struct l2cap_chan *chan =
container_of(work, struct l2cap_chan, busy_work);
struct sock *sk = chan->sk;
int n_tries = 0, timeo = HZ/5, err;
struct sk_buff *skb;
lock_sock(sk);
add_wait_queue(sk_sleep(sk), &wait);
while ((skb = skb_peek(BUSY_QUEUE(sk)))) {
while ((skb = skb_peek(&chan->busy_q))) {
set_current_state(TASK_INTERRUPTIBLE);
if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) {
err = -EBUSY;
l2cap_send_disconn_req(pi->conn, sk, EBUSY);
l2cap_send_disconn_req(l2cap_pi(sk)->conn, chan, EBUSY);
break;
}
......@@ -2964,7 +3041,7 @@ static void l2cap_busy_work(struct work_struct *work)
if (err)
break;
if (l2cap_try_push_rx_skb(sk) == 0)
if (l2cap_try_push_rx_skb(chan) == 0)
break;
}
......@@ -2974,48 +3051,47 @@ static void l2cap_busy_work(struct work_struct *work)
release_sock(sk);
}
static int l2cap_push_rx_skb(struct sock *sk, struct sk_buff *skb, u16 control)
static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
int sctrl, err;
if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
__skb_queue_tail(BUSY_QUEUE(sk), skb);
return l2cap_try_push_rx_skb(sk);
__skb_queue_tail(&chan->busy_q, skb);
return l2cap_try_push_rx_skb(chan);
}
err = l2cap_ertm_reassembly_sdu(sk, skb, control);
err = l2cap_ertm_reassembly_sdu(chan, skb, control);
if (err >= 0) {
pi->buffer_seq = (pi->buffer_seq + 1) % 64;
chan->buffer_seq = (chan->buffer_seq + 1) % 64;
return err;
}
/* Busy Condition */
BT_DBG("sk %p, Enter local busy", sk);
BT_DBG("chan %p, Enter local busy", chan);
pi->conn_state |= L2CAP_CONN_LOCAL_BUSY;
chan->conn_state |= L2CAP_CONN_LOCAL_BUSY;
bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
__skb_queue_tail(BUSY_QUEUE(sk), skb);
__skb_queue_tail(&chan->busy_q, skb);
sctrl = pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
sctrl = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
sctrl |= L2CAP_SUPER_RCV_NOT_READY;
l2cap_send_sframe(pi, sctrl);
l2cap_send_sframe(chan, sctrl);
pi->conn_state |= L2CAP_CONN_RNR_SENT;
chan->conn_state |= L2CAP_CONN_RNR_SENT;
del_timer(&pi->ack_timer);
del_timer(&chan->ack_timer);
queue_work(_busy_wq, &pi->busy_work);
queue_work(_busy_wq, &chan->busy_work);
return err;
}
static int l2cap_streaming_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control)
static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
struct sk_buff *_skb;
int err = -EINVAL;
......@@ -3026,80 +3102,80 @@ static int l2cap_streaming_reassembly_sdu(struct sock *sk, struct sk_buff *skb,
switch (control & L2CAP_CTRL_SAR) {
case L2CAP_SDU_UNSEGMENTED:
if (pi->conn_state & L2CAP_CONN_SAR_SDU) {
kfree_skb(pi->sdu);
if (chan->conn_state & L2CAP_CONN_SAR_SDU) {
kfree_skb(chan->sdu);
break;
}
err = sock_queue_rcv_skb(sk, skb);
err = sock_queue_rcv_skb(chan->sk, skb);
if (!err)
return 0;
break;
case L2CAP_SDU_START:
if (pi->conn_state & L2CAP_CONN_SAR_SDU) {
kfree_skb(pi->sdu);
if (chan->conn_state & L2CAP_CONN_SAR_SDU) {
kfree_skb(chan->sdu);
break;
}
pi->sdu_len = get_unaligned_le16(skb->data);
chan->sdu_len = get_unaligned_le16(skb->data);
skb_pull(skb, 2);
if (pi->sdu_len > pi->imtu) {
if (chan->sdu_len > pi->imtu) {
err = -EMSGSIZE;
break;
}
pi->sdu = bt_skb_alloc(pi->sdu_len, GFP_ATOMIC);
if (!pi->sdu) {
chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC);
if (!chan->sdu) {
err = -ENOMEM;
break;
}
memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
pi->conn_state |= L2CAP_CONN_SAR_SDU;
pi->partial_sdu_len = skb->len;
chan->conn_state |= L2CAP_CONN_SAR_SDU;
chan->partial_sdu_len = skb->len;
err = 0;
break;
case L2CAP_SDU_CONTINUE:
if (!(pi->conn_state & L2CAP_CONN_SAR_SDU))
if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
break;
memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
pi->partial_sdu_len += skb->len;
if (pi->partial_sdu_len > pi->sdu_len)
kfree_skb(pi->sdu);
chan->partial_sdu_len += skb->len;
if (chan->partial_sdu_len > chan->sdu_len)
kfree_skb(chan->sdu);
else
err = 0;
break;
case L2CAP_SDU_END:
if (!(pi->conn_state & L2CAP_CONN_SAR_SDU))
if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
break;
memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
pi->conn_state &= ~L2CAP_CONN_SAR_SDU;
pi->partial_sdu_len += skb->len;
chan->conn_state &= ~L2CAP_CONN_SAR_SDU;
chan->partial_sdu_len += skb->len;
if (pi->partial_sdu_len > pi->imtu)
if (chan->partial_sdu_len > pi->imtu)
goto drop;
if (pi->partial_sdu_len == pi->sdu_len) {
_skb = skb_clone(pi->sdu, GFP_ATOMIC);
err = sock_queue_rcv_skb(sk, _skb);
if (chan->partial_sdu_len == chan->sdu_len) {
_skb = skb_clone(chan->sdu, GFP_ATOMIC);
err = sock_queue_rcv_skb(chan->sk, _skb);
if (err < 0)
kfree_skb(_skb);
}
err = 0;
drop:
kfree_skb(pi->sdu);
kfree_skb(chan->sdu);
break;
}
......@@ -3107,31 +3183,30 @@ static int l2cap_streaming_reassembly_sdu(struct sock *sk, struct sk_buff *skb,
return err;
}
static void l2cap_check_srej_gap(struct sock *sk, u8 tx_seq)
static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
{
struct sk_buff *skb;
u16 control;
while ((skb = skb_peek(SREJ_QUEUE(sk)))) {
while ((skb = skb_peek(&chan->srej_q))) {
if (bt_cb(skb)->tx_seq != tx_seq)
break;
skb = skb_dequeue(SREJ_QUEUE(sk));
skb = skb_dequeue(&chan->srej_q);
control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
l2cap_ertm_reassembly_sdu(sk, skb, control);
l2cap_pi(sk)->buffer_seq_srej =
(l2cap_pi(sk)->buffer_seq_srej + 1) % 64;
l2cap_ertm_reassembly_sdu(chan, skb, control);
chan->buffer_seq_srej =
(chan->buffer_seq_srej + 1) % 64;
tx_seq = (tx_seq + 1) % 64;
}
}
static void l2cap_resend_srejframe(struct sock *sk, u8 tx_seq)
static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
struct srej_list *l, *tmp;
u16 control;
list_for_each_entry_safe(l, tmp, SREJ_LIST(sk), list) {
list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
if (l->tx_seq == tx_seq) {
list_del(&l->list);
kfree(l);
......@@ -3139,34 +3214,33 @@ static void l2cap_resend_srejframe(struct sock *sk, u8 tx_seq)
}
control = L2CAP_SUPER_SELECT_REJECT;
control |= l->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
l2cap_send_sframe(pi, control);
l2cap_send_sframe(chan, control);
list_del(&l->list);
list_add_tail(&l->list, SREJ_LIST(sk));
list_add_tail(&l->list, &chan->srej_l);
}
}
static void l2cap_send_srejframe(struct sock *sk, u8 tx_seq)
static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
struct srej_list *new;
u16 control;
while (tx_seq != pi->expected_tx_seq) {
while (tx_seq != chan->expected_tx_seq) {
control = L2CAP_SUPER_SELECT_REJECT;
control |= pi->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
l2cap_send_sframe(pi, control);
control |= chan->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
l2cap_send_sframe(chan, control);
new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
new->tx_seq = pi->expected_tx_seq;
pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64;
list_add_tail(&new->list, SREJ_LIST(sk));
new->tx_seq = chan->expected_tx_seq;
chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
list_add_tail(&new->list, &chan->srej_l);
}
pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64;
chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
}
static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, struct sk_buff *skb)
static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
u8 tx_seq = __get_txseq(rx_control);
u8 req_seq = __get_reqseq(rx_control);
u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT;
......@@ -3174,72 +3248,72 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str
int num_to_ack = (pi->tx_win/6) + 1;
int err = 0;
BT_DBG("sk %p len %d tx_seq %d rx_control 0x%4.4x", sk, skb->len, tx_seq,
rx_control);
BT_DBG("chan %p len %d tx_seq %d rx_control 0x%4.4x", chan, skb->len,
tx_seq, rx_control);
if (L2CAP_CTRL_FINAL & rx_control &&
l2cap_pi(sk)->conn_state & L2CAP_CONN_WAIT_F) {
del_timer(&pi->monitor_timer);
if (pi->unacked_frames > 0)
chan->conn_state & L2CAP_CONN_WAIT_F) {
del_timer(&chan->monitor_timer);
if (chan->unacked_frames > 0)
__mod_retrans_timer();
pi->conn_state &= ~L2CAP_CONN_WAIT_F;
chan->conn_state &= ~L2CAP_CONN_WAIT_F;
}
pi->expected_ack_seq = req_seq;
l2cap_drop_acked_frames(sk);
chan->expected_ack_seq = req_seq;
l2cap_drop_acked_frames(chan);
if (tx_seq == pi->expected_tx_seq)
if (tx_seq == chan->expected_tx_seq)
goto expected;
tx_seq_offset = (tx_seq - pi->buffer_seq) % 64;
tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
if (tx_seq_offset < 0)
tx_seq_offset += 64;
/* invalid tx_seq */
if (tx_seq_offset >= pi->tx_win) {
l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
l2cap_send_disconn_req(pi->conn, chan, ECONNRESET);
goto drop;
}
if (pi->conn_state == L2CAP_CONN_LOCAL_BUSY)
if (chan->conn_state == L2CAP_CONN_LOCAL_BUSY)
goto drop;
if (pi->conn_state & L2CAP_CONN_SREJ_SENT) {
if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
struct srej_list *first;
first = list_first_entry(SREJ_LIST(sk),
first = list_first_entry(&chan->srej_l,
struct srej_list, list);
if (tx_seq == first->tx_seq) {
l2cap_add_to_srej_queue(sk, skb, tx_seq, sar);
l2cap_check_srej_gap(sk, tx_seq);
l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
l2cap_check_srej_gap(chan, tx_seq);
list_del(&first->list);
kfree(first);
if (list_empty(SREJ_LIST(sk))) {
pi->buffer_seq = pi->buffer_seq_srej;
pi->conn_state &= ~L2CAP_CONN_SREJ_SENT;
l2cap_send_ack(pi);
BT_DBG("sk %p, Exit SREJ_SENT", sk);
if (list_empty(&chan->srej_l)) {
chan->buffer_seq = chan->buffer_seq_srej;
chan->conn_state &= ~L2CAP_CONN_SREJ_SENT;
l2cap_send_ack(chan);
BT_DBG("chan %p, Exit SREJ_SENT", chan);
}
} else {
struct srej_list *l;
/* duplicated tx_seq */
if (l2cap_add_to_srej_queue(sk, skb, tx_seq, sar) < 0)
if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
goto drop;
list_for_each_entry(l, SREJ_LIST(sk), list) {
list_for_each_entry(l, &chan->srej_l, list) {
if (l->tx_seq == tx_seq) {
l2cap_resend_srejframe(sk, tx_seq);
l2cap_resend_srejframe(chan, tx_seq);
return 0;
}
}
l2cap_send_srejframe(sk, tx_seq);
l2cap_send_srejframe(chan, tx_seq);
}
} else {
expected_tx_seq_offset =
(pi->expected_tx_seq - pi->buffer_seq) % 64;
(chan->expected_tx_seq - chan->buffer_seq) % 64;
if (expected_tx_seq_offset < 0)
expected_tx_seq_offset += 64;
......@@ -3247,51 +3321,51 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str
if (tx_seq_offset < expected_tx_seq_offset)
goto drop;
pi->conn_state |= L2CAP_CONN_SREJ_SENT;
chan->conn_state |= L2CAP_CONN_SREJ_SENT;
BT_DBG("sk %p, Enter SREJ", sk);
BT_DBG("chan %p, Enter SREJ", chan);
INIT_LIST_HEAD(SREJ_LIST(sk));
pi->buffer_seq_srej = pi->buffer_seq;
INIT_LIST_HEAD(&chan->srej_l);
chan->buffer_seq_srej = chan->buffer_seq;
__skb_queue_head_init(SREJ_QUEUE(sk));
__skb_queue_head_init(BUSY_QUEUE(sk));
l2cap_add_to_srej_queue(sk, skb, tx_seq, sar);
__skb_queue_head_init(&chan->srej_q);
__skb_queue_head_init(&chan->busy_q);
l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
pi->conn_state |= L2CAP_CONN_SEND_PBIT;
chan->conn_state |= L2CAP_CONN_SEND_PBIT;
l2cap_send_srejframe(sk, tx_seq);
l2cap_send_srejframe(chan, tx_seq);
del_timer(&pi->ack_timer);
del_timer(&chan->ack_timer);
}
return 0;
expected:
pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64;
chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
if (pi->conn_state & L2CAP_CONN_SREJ_SENT) {
if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
bt_cb(skb)->tx_seq = tx_seq;
bt_cb(skb)->sar = sar;
__skb_queue_tail(SREJ_QUEUE(sk), skb);
__skb_queue_tail(&chan->srej_q, skb);
return 0;
}
err = l2cap_push_rx_skb(sk, skb, rx_control);
err = l2cap_push_rx_skb(chan, skb, rx_control);
if (err < 0)
return 0;
if (rx_control & L2CAP_CTRL_FINAL) {
if (pi->conn_state & L2CAP_CONN_REJ_ACT)
pi->conn_state &= ~L2CAP_CONN_REJ_ACT;
if (chan->conn_state & L2CAP_CONN_REJ_ACT)
chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
else
l2cap_retransmit_frames(sk);
l2cap_retransmit_frames(chan);
}
__mod_ack_timer();
pi->num_acked = (pi->num_acked + 1) % num_to_ack;
if (pi->num_acked == num_to_ack - 1)
l2cap_send_ack(pi);
chan->num_acked = (chan->num_acked + 1) % num_to_ack;
if (chan->num_acked == num_to_ack - 1)
l2cap_send_ack(chan);
return 0;
......@@ -3300,165 +3374,160 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str
return 0;
}
static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control)
static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_control)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, __get_reqseq(rx_control),
BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, __get_reqseq(rx_control),
rx_control);
pi->expected_ack_seq = __get_reqseq(rx_control);
l2cap_drop_acked_frames(sk);
chan->expected_ack_seq = __get_reqseq(rx_control);
l2cap_drop_acked_frames(chan);
if (rx_control & L2CAP_CTRL_POLL) {
pi->conn_state |= L2CAP_CONN_SEND_FBIT;
if (pi->conn_state & L2CAP_CONN_SREJ_SENT) {
if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
(pi->unacked_frames > 0))
chan->conn_state |= L2CAP_CONN_SEND_FBIT;
if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
(chan->unacked_frames > 0))
__mod_retrans_timer();
pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
l2cap_send_srejtail(sk);
chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
l2cap_send_srejtail(chan);
} else {
l2cap_send_i_or_rr_or_rnr(sk);
l2cap_send_i_or_rr_or_rnr(chan);
}
} else if (rx_control & L2CAP_CTRL_FINAL) {
pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
if (pi->conn_state & L2CAP_CONN_REJ_ACT)
pi->conn_state &= ~L2CAP_CONN_REJ_ACT;
if (chan->conn_state & L2CAP_CONN_REJ_ACT)
chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
else
l2cap_retransmit_frames(sk);
l2cap_retransmit_frames(chan);
} else {
if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
(pi->unacked_frames > 0))
if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
(chan->unacked_frames > 0))
__mod_retrans_timer();
pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
if (pi->conn_state & L2CAP_CONN_SREJ_SENT)
l2cap_send_ack(pi);
chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
if (chan->conn_state & L2CAP_CONN_SREJ_SENT)
l2cap_send_ack(chan);
else
l2cap_ertm_send(sk);
l2cap_ertm_send(chan);
}
}
static inline void l2cap_data_channel_rejframe(struct sock *sk, u16 rx_control)
static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_control)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
u8 tx_seq = __get_reqseq(rx_control);
BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, tx_seq, rx_control);
BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
pi->expected_ack_seq = tx_seq;
l2cap_drop_acked_frames(sk);
chan->expected_ack_seq = tx_seq;
l2cap_drop_acked_frames(chan);
if (rx_control & L2CAP_CTRL_FINAL) {
if (pi->conn_state & L2CAP_CONN_REJ_ACT)
pi->conn_state &= ~L2CAP_CONN_REJ_ACT;
if (chan->conn_state & L2CAP_CONN_REJ_ACT)
chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
else
l2cap_retransmit_frames(sk);
l2cap_retransmit_frames(chan);
} else {
l2cap_retransmit_frames(sk);
l2cap_retransmit_frames(chan);
if (pi->conn_state & L2CAP_CONN_WAIT_F)
pi->conn_state |= L2CAP_CONN_REJ_ACT;
if (chan->conn_state & L2CAP_CONN_WAIT_F)
chan->conn_state |= L2CAP_CONN_REJ_ACT;
}
}
static inline void l2cap_data_channel_srejframe(struct sock *sk, u16 rx_control)
static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_control)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
u8 tx_seq = __get_reqseq(rx_control);
BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, tx_seq, rx_control);
BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
if (rx_control & L2CAP_CTRL_POLL) {
pi->expected_ack_seq = tx_seq;
l2cap_drop_acked_frames(sk);
chan->expected_ack_seq = tx_seq;
l2cap_drop_acked_frames(chan);
pi->conn_state |= L2CAP_CONN_SEND_FBIT;
l2cap_retransmit_one_frame(sk, tx_seq);
chan->conn_state |= L2CAP_CONN_SEND_FBIT;
l2cap_retransmit_one_frame(chan, tx_seq);
l2cap_ertm_send(sk);
l2cap_ertm_send(chan);
if (pi->conn_state & L2CAP_CONN_WAIT_F) {
pi->srej_save_reqseq = tx_seq;
pi->conn_state |= L2CAP_CONN_SREJ_ACT;
if (chan->conn_state & L2CAP_CONN_WAIT_F) {
chan->srej_save_reqseq = tx_seq;
chan->conn_state |= L2CAP_CONN_SREJ_ACT;
}
} else if (rx_control & L2CAP_CTRL_FINAL) {
if ((pi->conn_state & L2CAP_CONN_SREJ_ACT) &&
pi->srej_save_reqseq == tx_seq)
pi->conn_state &= ~L2CAP_CONN_SREJ_ACT;
if ((chan->conn_state & L2CAP_CONN_SREJ_ACT) &&
chan->srej_save_reqseq == tx_seq)
chan->conn_state &= ~L2CAP_CONN_SREJ_ACT;
else
l2cap_retransmit_one_frame(sk, tx_seq);
l2cap_retransmit_one_frame(chan, tx_seq);
} else {
l2cap_retransmit_one_frame(sk, tx_seq);
if (pi->conn_state & L2CAP_CONN_WAIT_F) {
pi->srej_save_reqseq = tx_seq;
pi->conn_state |= L2CAP_CONN_SREJ_ACT;
l2cap_retransmit_one_frame(chan, tx_seq);
if (chan->conn_state & L2CAP_CONN_WAIT_F) {
chan->srej_save_reqseq = tx_seq;
chan->conn_state |= L2CAP_CONN_SREJ_ACT;
}
}
}
static inline void l2cap_data_channel_rnrframe(struct sock *sk, u16 rx_control)
static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_control)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
u8 tx_seq = __get_reqseq(rx_control);
BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, tx_seq, rx_control);
BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
pi->conn_state |= L2CAP_CONN_REMOTE_BUSY;
pi->expected_ack_seq = tx_seq;
l2cap_drop_acked_frames(sk);
chan->conn_state |= L2CAP_CONN_REMOTE_BUSY;
chan->expected_ack_seq = tx_seq;
l2cap_drop_acked_frames(chan);
if (rx_control & L2CAP_CTRL_POLL)
pi->conn_state |= L2CAP_CONN_SEND_FBIT;
chan->conn_state |= L2CAP_CONN_SEND_FBIT;
if (!(pi->conn_state & L2CAP_CONN_SREJ_SENT)) {
del_timer(&pi->retrans_timer);
if (!(chan->conn_state & L2CAP_CONN_SREJ_SENT)) {
del_timer(&chan->retrans_timer);
if (rx_control & L2CAP_CTRL_POLL)
l2cap_send_rr_or_rnr(pi, L2CAP_CTRL_FINAL);
l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
return;
}
if (rx_control & L2CAP_CTRL_POLL)
l2cap_send_srejtail(sk);
l2cap_send_srejtail(chan);
else
l2cap_send_sframe(pi, L2CAP_SUPER_RCV_READY);
l2cap_send_sframe(chan, L2CAP_SUPER_RCV_READY);
}
static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, struct sk_buff *skb)
static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb)
{
BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len);
BT_DBG("chan %p rx_control 0x%4.4x len %d", chan, rx_control, skb->len);
if (L2CAP_CTRL_FINAL & rx_control &&
l2cap_pi(sk)->conn_state & L2CAP_CONN_WAIT_F) {
del_timer(&l2cap_pi(sk)->monitor_timer);
if (l2cap_pi(sk)->unacked_frames > 0)
chan->conn_state & L2CAP_CONN_WAIT_F) {
del_timer(&chan->monitor_timer);
if (chan->unacked_frames > 0)
__mod_retrans_timer();
l2cap_pi(sk)->conn_state &= ~L2CAP_CONN_WAIT_F;
chan->conn_state &= ~L2CAP_CONN_WAIT_F;
}
switch (rx_control & L2CAP_CTRL_SUPERVISE) {
case L2CAP_SUPER_RCV_READY:
l2cap_data_channel_rrframe(sk, rx_control);
l2cap_data_channel_rrframe(chan, rx_control);
break;
case L2CAP_SUPER_REJECT:
l2cap_data_channel_rejframe(sk, rx_control);
l2cap_data_channel_rejframe(chan, rx_control);
break;
case L2CAP_SUPER_SELECT_REJECT:
l2cap_data_channel_srejframe(sk, rx_control);
l2cap_data_channel_srejframe(chan, rx_control);
break;
case L2CAP_SUPER_RCV_NOT_READY:
l2cap_data_channel_rnrframe(sk, rx_control);
l2cap_data_channel_rnrframe(chan, rx_control);
break;
}
......@@ -3468,6 +3537,7 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str
static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
{
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
struct l2cap_pinfo *pi = l2cap_pi(sk);
u16 control;
u8 req_seq;
......@@ -3492,41 +3562,41 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
len -= 2;
if (len > pi->mps) {
l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
l2cap_send_disconn_req(pi->conn, chan, ECONNRESET);
goto drop;
}
req_seq = __get_reqseq(control);
req_seq_offset = (req_seq - pi->expected_ack_seq) % 64;
req_seq_offset = (req_seq - chan->expected_ack_seq) % 64;
if (req_seq_offset < 0)
req_seq_offset += 64;
next_tx_seq_offset =
(pi->next_tx_seq - pi->expected_ack_seq) % 64;
(chan->next_tx_seq - chan->expected_ack_seq) % 64;
if (next_tx_seq_offset < 0)
next_tx_seq_offset += 64;
/* check for invalid req-seq */
if (req_seq_offset > next_tx_seq_offset) {
l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
l2cap_send_disconn_req(pi->conn, chan, ECONNRESET);
goto drop;
}
if (__is_iframe(control)) {
if (len < 0) {
l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
l2cap_send_disconn_req(pi->conn, chan, ECONNRESET);
goto drop;
}
l2cap_data_channel_iframe(sk, control, skb);
l2cap_data_channel_iframe(chan, control, skb);
} else {
if (len != 0) {
BT_ERR("%d", len);
l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
l2cap_send_disconn_req(pi->conn, chan, ECONNRESET);
goto drop;
}
l2cap_data_channel_sframe(sk, control, skb);
l2cap_data_channel_sframe(chan, control, skb);
}
return 0;
......@@ -3538,21 +3608,23 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
{
struct l2cap_chan *chan;
struct sock *sk;
struct l2cap_pinfo *pi;
u16 control;
u8 tx_seq;
int len;
sk = l2cap_get_chan_by_scid(&conn->chan_list, cid);
if (!sk) {
chan = l2cap_get_chan_by_scid(conn, cid);
if (!chan) {
BT_DBG("unknown cid 0x%4.4x", cid);
goto drop;
}
sk = chan->sk;
pi = l2cap_pi(sk);
BT_DBG("sk %p, len %d", sk, skb->len);
BT_DBG("chan %p, len %d", chan, skb->len);
if (sk->sk_state != BT_CONNECTED)
goto drop;
......@@ -3600,17 +3672,17 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
tx_seq = __get_txseq(control);
if (pi->expected_tx_seq == tx_seq)
pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64;
if (chan->expected_tx_seq == tx_seq)
chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
else
pi->expected_tx_seq = (tx_seq + 1) % 64;
chan->expected_tx_seq = (tx_seq + 1) % 64;
l2cap_streaming_reassembly_sdu(sk, skb, control);
l2cap_streaming_reassembly_sdu(chan, skb, control);
goto done;
default:
BT_DBG("sk %p: bad mode 0x%2.2x", sk, pi->mode);
BT_DBG("chan %p: bad mode 0x%2.2x", chan, pi->mode);
break;
}
......@@ -3654,6 +3726,36 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str
return 0;
}
static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
{
struct sock *sk;
sk = l2cap_get_sock_by_scid(0, cid, conn->src);
if (!sk)
goto drop;
bh_lock_sock(sk);
BT_DBG("sk %p, len %d", sk, skb->len);
if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED)
goto drop;
if (l2cap_pi(sk)->imtu < skb->len)
goto drop;
if (!sock_queue_rcv_skb(sk, skb))
goto done;
drop:
kfree_skb(skb);
done:
if (sk)
bh_unlock_sock(sk);
return 0;
}
static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct l2cap_hdr *lh = (void *) skb->data;
......@@ -3683,6 +3785,10 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
l2cap_conless_channel(conn, psm, skb);
break;
case L2CAP_CID_LE_DATA:
l2cap_att_channel(conn, cid, skb);
break;
default:
l2cap_data_channel(conn, cid, skb);
break;
......@@ -3786,20 +3892,19 @@ static inline void l2cap_check_encryption(struct sock *sk, u8 encrypt)
static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
{
struct l2cap_chan_list *l;
struct l2cap_conn *conn = hcon->l2cap_data;
struct sock *sk;
struct l2cap_chan *chan;
if (!conn)
return 0;
l = &conn->chan_list;
BT_DBG("conn %p", conn);
read_lock(&l->lock);
read_lock(&conn->chan_lock);
list_for_each_entry(chan, &conn->chan_l, list) {
struct sock *sk = chan->sk;
for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
bh_lock_sock(sk);
if (l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND) {
......@@ -3820,10 +3925,10 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
req.psm = l2cap_pi(sk)->psm;
l2cap_pi(sk)->ident = l2cap_get_ident(conn);
chan->ident = l2cap_get_ident(conn);
l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND;
l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
l2cap_send_cmd(conn, chan->ident,
L2CAP_CONN_REQ, sizeof(req), &req);
} else {
l2cap_sock_clear_timer(sk);
......@@ -3846,14 +3951,14 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
rsp.result = cpu_to_le16(result);
rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
L2CAP_CONN_RSP, sizeof(rsp), &rsp);
l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
sizeof(rsp), &rsp);
}
bh_unlock_sock(sk);
}
read_unlock(&l->lock);
read_unlock(&conn->chan_lock);
return 0;
}
......@@ -3872,7 +3977,7 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
if (!(flags & ACL_CONT)) {
struct l2cap_hdr *hdr;
struct sock *sk;
struct l2cap_chan *chan;
u16 cid;
int len;
......@@ -3910,18 +4015,21 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
goto drop;
}
sk = l2cap_get_chan_by_scid(&conn->chan_list, cid);
chan = l2cap_get_chan_by_scid(conn, 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 (chan && chan->sk) {
struct sock *sk = chan->sk;
if (sk)
if (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;
}
bh_unlock_sock(sk);
}
/* Allocate skb for the complete frame (with header) */
conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
......
......@@ -269,7 +269,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
goto done;
}
if (!l2cap_pi(sk)->psm && !l2cap_pi(sk)->dcid) {
if (!l2cap_pi(sk)->psm && !l2cap_pi(sk)->scid) {
bdaddr_t *src = &bt_sk(sk)->src;
u16 psm;
......@@ -757,35 +757,37 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
case L2CAP_MODE_ERTM:
case L2CAP_MODE_STREAMING:
/* Entire SDU fits into one PDU */
if (len <= pi->remote_mps) {
if (len <= pi->chan->remote_mps) {
control = L2CAP_SDU_UNSEGMENTED;
skb = l2cap_create_iframe_pdu(sk, msg, len, control, 0);
if (IS_ERR(skb)) {
err = PTR_ERR(skb);
goto done;
}
__skb_queue_tail(TX_QUEUE(sk), skb);
__skb_queue_tail(&pi->chan->tx_q, skb);
if (sk->sk_send_head == NULL)
sk->sk_send_head = skb;
if (pi->chan->tx_send_head == NULL)
pi->chan->tx_send_head = skb;
} else {
/* Segment SDU into multiples PDUs */
err = l2cap_sar_segment_sdu(sk, msg, len);
err = l2cap_sar_segment_sdu(pi->chan, msg, len);
if (err < 0)
goto done;
}
if (pi->mode == L2CAP_MODE_STREAMING) {
l2cap_streaming_send(sk);
} else {
if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
(pi->conn_state & L2CAP_CONN_WAIT_F)) {
err = len;
break;
}
err = l2cap_ertm_send(sk);
l2cap_streaming_send(pi->chan);
err = len;
break;
}
if ((pi->chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
(pi->chan->conn_state & L2CAP_CONN_WAIT_F)) {
err = len;
break;
}
err = l2cap_ertm_send(pi->chan);
if (err >= 0)
err = len;
......@@ -808,29 +810,7 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms
lock_sock(sk);
if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) {
struct l2cap_conn_rsp rsp;
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
u8 buf[128];
sk->sk_state = BT_CONFIG;
rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
l2cap_send_cmd(l2cap_pi(sk)->conn, l2cap_pi(sk)->ident,
L2CAP_CONN_RSP, sizeof(rsp), &rsp);
if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) {
release_sock(sk);
return 0;
}
l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
l2cap_build_conf_req(sk, buf), buf);
l2cap_pi(sk)->num_conf_req++;
__l2cap_connect_rsp_defer(sk);
release_sock(sk);
return 0;
}
......@@ -886,6 +866,7 @@ static void l2cap_sock_cleanup_listen(struct sock *parent)
void __l2cap_sock_close(struct sock *sk, int reason)
{
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket);
......@@ -900,9 +881,9 @@ void __l2cap_sock_close(struct sock *sk, int reason)
sk->sk_type == SOCK_STREAM) &&
conn->hcon->type == ACL_LINK) {
l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
l2cap_send_disconn_req(conn, sk, reason);
l2cap_send_disconn_req(conn, chan, reason);
} else
l2cap_chan_del(sk, reason);
l2cap_chan_del(chan, reason);
break;
case BT_CONNECT2:
......@@ -921,16 +902,16 @@ void __l2cap_sock_close(struct sock *sk, int reason)
rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
rsp.result = cpu_to_le16(result);
rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
L2CAP_CONN_RSP, sizeof(rsp), &rsp);
l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
sizeof(rsp), &rsp);
}
l2cap_chan_del(sk, reason);
l2cap_chan_del(chan, reason);
break;
case BT_CONNECT:
case BT_DISCONN:
l2cap_chan_del(sk, reason);
l2cap_chan_del(chan, reason);
break;
default:
......@@ -1035,12 +1016,7 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent)
}
/* Default config options */
pi->conf_len = 0;
pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
skb_queue_head_init(TX_QUEUE(sk));
skb_queue_head_init(SREJ_QUEUE(sk));
skb_queue_head_init(BUSY_QUEUE(sk));
INIT_LIST_HEAD(SREJ_LIST(sk));
}
static struct proto l2cap_proto = {
......
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