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