2007-02-09 17:24:33 +03:00
/*
2005-04-17 02:20:36 +04:00
BlueZ - Bluetooth protocol stack for Linux
Copyright ( C ) 2000 - 2001 Qualcomm Incorporated
2010-07-13 18:57:11 +04:00
Copyright ( C ) 2009 - 2010 Gustavo F . Padovan < gustavo @ padovan . org >
2010-07-16 23:18:39 +04:00
Copyright ( C ) 2010 Google Inc .
2005-04-17 02:20:36 +04:00
Written 2000 , 2001 by Maxim Krasnyansky < maxk @ qualcomm . com >
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation ;
THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS
OR IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS .
IN NO EVENT SHALL THE COPYRIGHT HOLDER ( S ) AND AUTHOR ( S ) BE LIABLE FOR ANY
2007-02-09 17:24:33 +03:00
CLAIM , OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES , OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE , DATA OR PROFITS , WHETHER IN AN
ACTION OF CONTRACT , NEGLIGENCE OR OTHER TORTIOUS ACTION , ARISING OUT OF
2005-04-17 02:20:36 +04:00
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE .
2007-02-09 17:24:33 +03:00
ALL LIABILITY , INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS ,
COPYRIGHTS , TRADEMARKS OR OTHER RIGHTS , RELATING TO USE OF THIS
2005-04-17 02:20:36 +04:00
SOFTWARE IS DISCLAIMED .
*/
2011-02-04 01:50:35 +03:00
/* Bluetooth L2CAP core. */
2005-04-17 02:20:36 +04:00
# include <linux/module.h>
# include <linux/types.h>
2006-01-11 23:17:47 +03:00
# include <linux/capability.h>
2005-04-17 02:20:36 +04:00
# include <linux/errno.h>
# include <linux/kernel.h>
# include <linux/sched.h>
# include <linux/slab.h>
# include <linux/poll.h>
# include <linux/fcntl.h>
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/socket.h>
# include <linux/skbuff.h>
# include <linux/list.h>
2005-11-08 20:57:38 +03:00
# include <linux/device.h>
2010-03-21 07:27:45 +03:00
# include <linux/debugfs.h>
# include <linux/seq_file.h>
2009-04-20 08:31:08 +04:00
# include <linux/uaccess.h>
2009-08-21 05:26:02 +04:00
# include <linux/crc16.h>
2005-04-17 02:20:36 +04:00
# include <net/sock.h>
# include <asm/system.h>
# include <asm/unaligned.h>
# include <net/bluetooth/bluetooth.h>
# include <net/bluetooth/hci_core.h>
# include <net/bluetooth/l2cap.h>
2011-06-08 01:46:31 +04:00
# include <net/bluetooth/smp.h>
2005-04-17 02:20:36 +04:00
2011-02-04 01:50:35 +03:00
int disable_ertm ;
2007-10-20 15:38:51 +04:00
2009-05-03 05:57:55 +04:00
static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN ;
2009-02-09 11:18:02 +03:00
static u8 l2cap_fixed_chan [ 8 ] = { 0x02 , } ;
2005-04-17 02:20:36 +04:00
2011-06-01 10:54:45 +04:00
static LIST_HEAD ( chan_list ) ;
static DEFINE_RWLOCK ( chan_list_lock ) ;
2005-04-17 02:20:36 +04:00
static struct sk_buff * l2cap_build_cmd ( struct l2cap_conn * conn ,
u8 code , u8 ident , u16 dlen , void * data ) ;
2011-04-29 00:55:53 +04:00
static void l2cap_send_cmd ( struct l2cap_conn * conn , u8 ident , u8 code , u16 len ,
void * data ) ;
2011-03-25 20:30:37 +03:00
static int l2cap_build_conf_req ( struct l2cap_chan * chan , void * data ) ;
2011-04-29 00:55:53 +04:00
static void l2cap_send_disconn_req ( struct l2cap_conn * conn ,
struct l2cap_chan * chan , int err ) ;
2005-04-17 02:20:36 +04:00
2010-06-22 01:53:22 +04:00
static int l2cap_ertm_data_rcv ( struct sock * sk , struct sk_buff * skb ) ;
2006-07-03 12:02:46 +04:00
/* ---- L2CAP channels ---- */
2011-05-17 21:34:52 +04:00
static inline void chan_hold ( struct l2cap_chan * c )
{
atomic_inc ( & c - > refcnt ) ;
}
static inline void chan_put ( struct l2cap_chan * c )
{
if ( atomic_dec_and_test ( & c - > refcnt ) )
kfree ( c ) ;
}
2011-03-31 23:17:41 +04:00
static struct l2cap_chan * __l2cap_get_chan_by_dcid ( struct l2cap_conn * conn , u16 cid )
2006-07-03 12:02:46 +04:00
{
2011-03-25 06:22:30 +03:00
struct l2cap_chan * c ;
2011-03-31 23:17:41 +04:00
list_for_each_entry ( c , & conn - > chan_l , list ) {
2011-04-14 02:50:45 +04:00
if ( c - > dcid = = cid )
2011-03-31 23:17:41 +04:00
return c ;
2006-07-03 12:02:46 +04:00
}
2011-03-31 23:17:41 +04:00
return NULL ;
2006-07-03 12:02:46 +04:00
}
2011-03-31 23:17:41 +04:00
static struct l2cap_chan * __l2cap_get_chan_by_scid ( struct l2cap_conn * conn , u16 cid )
2006-07-03 12:02:46 +04:00
{
2011-03-25 06:22:30 +03:00
struct l2cap_chan * c ;
2011-03-31 23:17:41 +04:00
list_for_each_entry ( c , & conn - > chan_l , list ) {
2011-04-14 02:50:45 +04:00
if ( c - > scid = = cid )
2011-03-31 23:17:41 +04:00
return c ;
2006-07-03 12:02:46 +04:00
}
2011-03-31 23:17:41 +04:00
return NULL ;
2006-07-03 12:02:46 +04:00
}
/* Find channel with given SCID.
* Returns locked socket */
2011-03-31 23:17:41 +04:00
static struct l2cap_chan * l2cap_get_chan_by_scid ( struct l2cap_conn * conn , u16 cid )
2006-07-03 12:02:46 +04:00
{
2011-03-25 06:22:30 +03:00
struct l2cap_chan * c ;
2011-03-31 23:17:41 +04:00
read_lock ( & conn - > chan_lock ) ;
c = __l2cap_get_chan_by_scid ( conn , cid ) ;
2011-03-25 06:22:30 +03:00
if ( c )
bh_lock_sock ( c - > sk ) ;
2011-03-31 23:17:41 +04:00
read_unlock ( & conn - > chan_lock ) ;
2011-03-25 06:22:30 +03:00
return c ;
2006-07-03 12:02:46 +04:00
}
2011-03-31 23:17:41 +04:00
static struct l2cap_chan * __l2cap_get_chan_by_ident ( struct l2cap_conn * conn , u8 ident )
2006-07-03 12:02:46 +04:00
{
2011-03-25 06:22:30 +03:00
struct l2cap_chan * c ;
2011-03-31 23:17:41 +04:00
list_for_each_entry ( c , & conn - > chan_l , list ) {
2011-03-25 19:59:37 +03:00
if ( c - > ident = = ident )
2011-03-31 23:17:41 +04:00
return c ;
2006-07-03 12:02:46 +04:00
}
2011-03-31 23:17:41 +04:00
return NULL ;
2006-07-03 12:02:46 +04:00
}
2011-03-31 23:17:41 +04:00
static inline struct l2cap_chan * l2cap_get_chan_by_ident ( struct l2cap_conn * conn , u8 ident )
2006-07-03 12:02:46 +04:00
{
2011-03-25 06:22:30 +03:00
struct l2cap_chan * c ;
2011-03-31 23:17:41 +04:00
read_lock ( & conn - > chan_lock ) ;
c = __l2cap_get_chan_by_ident ( conn , ident ) ;
2011-03-25 06:22:30 +03:00
if ( c )
bh_lock_sock ( c - > sk ) ;
2011-03-31 23:17:41 +04:00
read_unlock ( & conn - > chan_lock ) ;
2011-03-25 06:22:30 +03:00
return c ;
2006-07-03 12:02:46 +04:00
}
2011-04-28 01:26:32 +04:00
static struct l2cap_chan * __l2cap_global_chan_by_addr ( __le16 psm , bdaddr_t * src )
2011-04-19 01:38:43 +04:00
{
2011-04-28 01:26:32 +04:00
struct l2cap_chan * c ;
2011-04-19 01:38:43 +04:00
2011-04-28 01:26:32 +04:00
list_for_each_entry ( c , & chan_list , global_l ) {
if ( c - > sport = = psm & & ! bacmp ( & bt_sk ( c - > sk ) - > src , src ) )
2011-04-19 01:38:43 +04:00
goto found ;
}
2011-04-28 01:26:32 +04:00
c = NULL ;
2011-04-19 01:38:43 +04:00
found :
2011-04-28 01:26:32 +04:00
return c ;
2011-04-19 01:38:43 +04:00
}
int l2cap_add_psm ( struct l2cap_chan * chan , bdaddr_t * src , __le16 psm )
{
2011-04-19 02:36:44 +04:00
int err ;
2011-04-28 01:26:32 +04:00
write_lock_bh ( & chan_list_lock ) ;
2011-04-19 01:38:43 +04:00
2011-04-28 01:26:32 +04:00
if ( psm & & __l2cap_global_chan_by_addr ( psm , src ) ) {
2011-04-19 02:36:44 +04:00
err = - EADDRINUSE ;
goto done ;
2011-04-19 01:38:43 +04:00
}
2011-04-19 02:36:44 +04:00
if ( psm ) {
chan - > psm = psm ;
chan - > sport = psm ;
err = 0 ;
} else {
u16 p ;
err = - EINVAL ;
for ( p = 0x1001 ; p < 0x1100 ; p + = 2 )
2011-04-28 01:26:32 +04:00
if ( ! __l2cap_global_chan_by_addr ( cpu_to_le16 ( p ) , src ) ) {
2011-04-19 02:36:44 +04:00
chan - > psm = cpu_to_le16 ( p ) ;
chan - > sport = cpu_to_le16 ( p ) ;
err = 0 ;
break ;
}
}
2011-04-19 01:38:43 +04:00
2011-04-19 02:36:44 +04:00
done :
2011-04-28 01:26:32 +04:00
write_unlock_bh ( & chan_list_lock ) ;
2011-04-19 02:36:44 +04:00
return err ;
2011-04-19 01:38:43 +04:00
}
int l2cap_add_scid ( struct l2cap_chan * chan , __u16 scid )
{
2011-04-28 01:26:32 +04:00
write_lock_bh ( & chan_list_lock ) ;
2011-04-19 01:38:43 +04:00
chan - > scid = scid ;
2011-04-28 01:26:32 +04:00
write_unlock_bh ( & chan_list_lock ) ;
2011-04-19 01:38:43 +04:00
return 0 ;
}
2011-03-31 23:17:41 +04:00
static u16 l2cap_alloc_cid ( struct l2cap_conn * conn )
2006-07-03 12:02:46 +04:00
{
2009-04-20 08:31:05 +04:00
u16 cid = L2CAP_CID_DYN_START ;
2006-07-03 12:02:46 +04:00
2009-04-20 08:31:05 +04:00
for ( ; cid < L2CAP_CID_DYN_END ; cid + + ) {
2011-03-31 23:17:41 +04:00
if ( ! __l2cap_get_chan_by_scid ( conn , cid ) )
2006-07-03 12:02:46 +04:00
return cid ;
}
return 0 ;
}
2011-05-17 21:59:01 +04:00
static void l2cap_set_timer ( struct l2cap_chan * chan , struct timer_list * timer , long timeout )
2011-05-03 01:25:01 +04:00
{
2011-06-30 01:35:20 +04:00
BT_DBG ( " chan %p state %d timeout %ld " , chan - > sk , chan - > state , timeout ) ;
2011-06-03 07:19:47 +04:00
2011-06-30 01:35:21 +04:00
if ( ! mod_timer ( timer , jiffies + msecs_to_jiffies ( timeout ) ) )
2011-06-30 01:35:20 +04:00
chan_hold ( chan ) ;
2011-05-03 01:25:01 +04:00
}
2011-05-17 21:59:01 +04:00
static void l2cap_clear_timer ( struct l2cap_chan * chan , struct timer_list * timer )
2011-05-03 01:25:01 +04:00
{
2011-06-30 01:35:20 +04:00
BT_DBG ( " chan %p state %d " , chan , chan - > state ) ;
2011-05-03 01:25:01 +04:00
2011-06-30 01:35:20 +04:00
if ( timer_pending ( timer ) & & del_timer ( timer ) )
chan_put ( chan ) ;
2011-05-03 01:25:01 +04:00
}
2011-06-03 07:19:47 +04:00
static void l2cap_state_change ( struct l2cap_chan * chan , int state )
{
chan - > state = state ;
chan - > ops - > state_change ( chan - > data , state ) ;
}
2011-05-03 01:25:01 +04:00
static void l2cap_chan_timeout ( unsigned long arg )
{
struct l2cap_chan * chan = ( struct l2cap_chan * ) arg ;
struct sock * sk = chan - > sk ;
int reason ;
2011-06-03 07:19:47 +04:00
BT_DBG ( " chan %p state %d " , chan , chan - > state ) ;
2011-05-03 01:25:01 +04:00
bh_lock_sock ( sk ) ;
if ( sock_owned_by_user ( sk ) ) {
/* sk is owned by user. Try again later */
2011-05-17 21:59:01 +04:00
__set_chan_timer ( chan , HZ / 5 ) ;
2011-05-03 01:25:01 +04:00
bh_unlock_sock ( sk ) ;
2011-05-17 21:34:52 +04:00
chan_put ( chan ) ;
2011-05-03 01:25:01 +04:00
return ;
}
2011-06-03 07:19:47 +04:00
if ( chan - > state = = BT_CONNECTED | | chan - > state = = BT_CONFIG )
2011-05-03 01:25:01 +04:00
reason = ECONNREFUSED ;
2011-06-03 07:19:47 +04:00
else if ( chan - > state = = BT_CONNECT & &
2011-05-03 01:25:01 +04:00
chan - > sec_level ! = BT_SECURITY_SDP )
reason = ECONNREFUSED ;
else
reason = ETIMEDOUT ;
2011-05-05 02:42:50 +04:00
l2cap_chan_close ( chan , reason ) ;
2011-05-03 01:25:01 +04:00
bh_unlock_sock ( sk ) ;
2011-05-17 01:23:24 +04:00
chan - > ops - > close ( chan - > data ) ;
2011-05-17 21:34:52 +04:00
chan_put ( chan ) ;
2011-05-03 01:25:01 +04:00
}
2011-04-28 01:26:32 +04:00
struct l2cap_chan * l2cap_chan_create ( struct sock * sk )
2011-03-25 06:22:30 +03:00
{
struct l2cap_chan * chan ;
chan = kzalloc ( sizeof ( * chan ) , GFP_ATOMIC ) ;
if ( ! chan )
return NULL ;
chan - > sk = sk ;
2011-04-28 01:26:32 +04:00
write_lock_bh ( & chan_list_lock ) ;
list_add ( & chan - > global_l , & chan_list ) ;
write_unlock_bh ( & chan_list_lock ) ;
2011-05-03 01:25:01 +04:00
setup_timer ( & chan - > chan_timer , l2cap_chan_timeout , ( unsigned long ) chan ) ;
2011-06-03 07:19:47 +04:00
chan - > state = BT_OPEN ;
2011-05-17 21:34:52 +04:00
atomic_set ( & chan - > refcnt , 1 ) ;
2011-03-25 06:22:30 +03:00
return chan ;
}
2011-04-28 01:26:32 +04:00
void l2cap_chan_destroy ( struct l2cap_chan * chan )
2011-04-25 22:10:41 +04:00
{
2011-04-28 01:26:32 +04:00
write_lock_bh ( & chan_list_lock ) ;
list_del ( & chan - > global_l ) ;
write_unlock_bh ( & chan_list_lock ) ;
2011-05-17 21:34:52 +04:00
chan_put ( chan ) ;
2011-04-25 22:10:41 +04:00
}
2011-03-25 06:22:30 +03:00
static void __l2cap_chan_add ( struct l2cap_conn * conn , struct l2cap_chan * chan )
2006-07-03 12:02:46 +04:00
{
2009-04-20 08:31:08 +04:00
BT_DBG ( " conn %p, psm 0x%2.2x, dcid 0x%4.4x " , conn ,
2011-04-14 02:50:45 +04:00
chan - > psm , chan - > dcid ) ;
2006-07-03 12:02:46 +04:00
2009-02-12 16:02:50 +03:00
conn - > disc_reason = 0x13 ;
2011-04-14 03:23:55 +04:00
chan - > conn = conn ;
2006-07-03 12:02:46 +04:00
2011-05-03 00:13:55 +04:00
if ( chan - > chan_type = = L2CAP_CHAN_CONN_ORIENTED ) {
2011-02-11 04:38:50 +03:00
if ( conn - > hcon - > type = = LE_LINK ) {
/* LE connection */
2011-04-14 00:20:49 +04:00
chan - > omtu = L2CAP_LE_DEFAULT_MTU ;
2011-04-14 02:50:45 +04:00
chan - > scid = L2CAP_CID_LE_DATA ;
chan - > dcid = L2CAP_CID_LE_DATA ;
2011-02-11 04:38:50 +03:00
} else {
/* Alloc CID for connection-oriented socket */
2011-04-14 02:50:45 +04:00
chan - > scid = l2cap_alloc_cid ( conn ) ;
2011-04-14 00:20:49 +04:00
chan - > omtu = L2CAP_DEFAULT_MTU ;
2011-02-11 04:38:50 +03:00
}
2011-05-03 00:13:55 +04:00
} else if ( chan - > chan_type = = L2CAP_CHAN_CONN_LESS ) {
2006-07-03 12:02:46 +04:00
/* Connectionless socket */
2011-04-14 02:50:45 +04:00
chan - > scid = L2CAP_CID_CONN_LESS ;
chan - > dcid = L2CAP_CID_CONN_LESS ;
2011-04-14 00:20:49 +04:00
chan - > omtu = L2CAP_DEFAULT_MTU ;
2006-07-03 12:02:46 +04:00
} else {
/* Raw socket can send/recv signalling messages only */
2011-04-14 02:50:45 +04:00
chan - > scid = L2CAP_CID_SIGNALING ;
chan - > dcid = L2CAP_CID_SIGNALING ;
2011-04-14 00:20:49 +04:00
chan - > omtu = L2CAP_DEFAULT_MTU ;
2006-07-03 12:02:46 +04:00
}
2011-05-17 21:34:52 +04:00
chan_hold ( chan ) ;
2011-03-31 23:17:41 +04:00
list_add ( & chan - > list , & conn - > chan_l ) ;
2006-07-03 12:02:46 +04:00
}
2007-02-09 17:24:33 +03:00
/* Delete channel.
2006-07-03 12:02:46 +04:00
* Must be called on the locked socket . */
2011-04-29 00:55:53 +04:00
static void l2cap_chan_del ( struct l2cap_chan * chan , int err )
2006-07-03 12:02:46 +04:00
{
2011-03-25 06:22:30 +03:00
struct sock * sk = chan - > sk ;
2011-04-14 03:23:55 +04:00
struct l2cap_conn * conn = chan - > conn ;
2006-07-03 12:02:46 +04:00
struct sock * parent = bt_sk ( sk ) - > parent ;
2011-05-17 21:59:01 +04:00
__clear_chan_timer ( chan ) ;
2006-07-03 12:02:46 +04:00
2011-04-04 22:59:54 +04:00
BT_DBG ( " chan %p, conn %p, err %d " , chan , conn , err ) ;
2006-07-03 12:02:46 +04:00
2007-02-09 17:24:33 +03:00
if ( conn ) {
2011-03-31 23:17:41 +04:00
/* Delete from channel list */
write_lock_bh ( & conn - > chan_lock ) ;
list_del ( & chan - > list ) ;
write_unlock_bh ( & conn - > chan_lock ) ;
2011-05-17 21:34:52 +04:00
chan_put ( chan ) ;
2011-03-31 23:17:41 +04:00
2011-04-14 03:23:55 +04:00
chan - > conn = NULL ;
2006-07-03 12:02:46 +04:00
hci_conn_put ( conn - > hcon ) ;
}
2011-06-03 07:19:47 +04:00
l2cap_state_change ( chan , BT_CLOSED ) ;
2006-07-03 12:02:46 +04:00
sock_set_flag ( sk , SOCK_ZAPPED ) ;
if ( err )
sk - > sk_err = err ;
if ( parent ) {
bt_accept_unlink ( sk ) ;
parent - > sk_data_ready ( parent , 0 ) ;
} else
sk - > sk_state_change ( sk ) ;
2010-05-14 03:50:12 +04:00
2011-06-11 00:02:12 +04:00
if ( ! ( test_bit ( CONF_OUTPUT_DONE , & chan - > conf_state ) & &
test_bit ( CONF_INPUT_DONE , & chan - > conf_state ) ) )
2011-04-25 22:10:41 +04:00
return ;
2011-04-01 22:13:36 +04:00
2011-04-04 23:16:44 +04:00
skb_queue_purge ( & chan - > tx_q ) ;
2010-05-14 03:50:12 +04:00
2011-04-14 00:20:49 +04:00
if ( chan - > mode = = L2CAP_MODE_ERTM ) {
2010-05-14 03:50:12 +04:00
struct srej_list * l , * tmp ;
2011-05-17 22:13:19 +04:00
__clear_retrans_timer ( chan ) ;
__clear_monitor_timer ( chan ) ;
__clear_ack_timer ( chan ) ;
2010-05-14 03:50:12 +04:00
2011-03-26 02:36:10 +03:00
skb_queue_purge ( & chan - > srej_q ) ;
2010-05-14 03:50:12 +04:00
2011-04-04 22:40:12 +04:00
list_for_each_entry_safe ( l , tmp , & chan - > srej_l , list ) {
2010-05-14 03:50:12 +04:00
list_del ( & l - > list ) ;
kfree ( l ) ;
}
}
2006-07-03 12:02:46 +04:00
}
2011-04-29 00:55:53 +04:00
static void l2cap_chan_cleanup_listen ( struct sock * parent )
{
struct sock * sk ;
BT_DBG ( " parent %p " , parent ) ;
/* Close not yet accepted channels */
2011-05-05 02:42:50 +04:00
while ( ( sk = bt_accept_dequeue ( parent , NULL ) ) ) {
2011-05-17 01:23:24 +04:00
struct l2cap_chan * chan = l2cap_pi ( sk ) - > chan ;
2011-05-17 21:59:01 +04:00
__clear_chan_timer ( chan ) ;
2011-05-05 02:42:50 +04:00
lock_sock ( sk ) ;
2011-05-17 01:23:24 +04:00
l2cap_chan_close ( chan , ECONNRESET ) ;
2011-05-05 02:42:50 +04:00
release_sock ( sk ) ;
2011-05-17 01:23:24 +04:00
chan - > ops - > close ( chan - > data ) ;
2011-05-05 02:42:50 +04:00
}
2011-04-29 00:55:53 +04:00
}
2011-05-05 02:42:50 +04:00
void l2cap_chan_close ( struct l2cap_chan * chan , int reason )
2011-04-29 00:55:53 +04:00
{
struct l2cap_conn * conn = chan - > conn ;
struct sock * sk = chan - > sk ;
2011-06-03 07:19:47 +04:00
BT_DBG ( " chan %p state %d socket %p " , chan , chan - > state , sk - > sk_socket ) ;
2011-04-29 00:55:53 +04:00
2011-06-03 07:19:47 +04:00
switch ( chan - > state ) {
2011-04-29 00:55:53 +04:00
case BT_LISTEN :
l2cap_chan_cleanup_listen ( sk ) ;
2011-06-03 07:19:47 +04:00
l2cap_state_change ( chan , BT_CLOSED ) ;
sock_set_flag ( sk , SOCK_ZAPPED ) ;
2011-04-29 00:55:53 +04:00
break ;
case BT_CONNECTED :
case BT_CONFIG :
2011-05-03 00:13:55 +04:00
if ( chan - > chan_type = = L2CAP_CHAN_CONN_ORIENTED & &
2011-04-29 00:55:53 +04:00
conn - > hcon - > type = = ACL_LINK ) {
2011-05-17 21:59:01 +04:00
__clear_chan_timer ( chan ) ;
__set_chan_timer ( chan , sk - > sk_sndtimeo ) ;
2011-04-29 00:55:53 +04:00
l2cap_send_disconn_req ( conn , chan , reason ) ;
} else
l2cap_chan_del ( chan , reason ) ;
break ;
case BT_CONNECT2 :
2011-05-03 00:13:55 +04:00
if ( chan - > chan_type = = L2CAP_CHAN_CONN_ORIENTED & &
2011-04-29 00:55:53 +04:00
conn - > hcon - > type = = ACL_LINK ) {
struct l2cap_conn_rsp rsp ;
__u16 result ;
if ( bt_sk ( sk ) - > defer_setup )
result = L2CAP_CR_SEC_BLOCK ;
else
result = L2CAP_CR_BAD_PSM ;
2011-06-03 07:19:47 +04:00
l2cap_state_change ( chan , BT_DISCONN ) ;
2011-04-29 00:55:53 +04:00
rsp . scid = cpu_to_le16 ( chan - > dcid ) ;
rsp . dcid = cpu_to_le16 ( chan - > scid ) ;
rsp . result = cpu_to_le16 ( result ) ;
rsp . status = cpu_to_le16 ( L2CAP_CS_NO_INFO ) ;
l2cap_send_cmd ( conn , chan - > ident , L2CAP_CONN_RSP ,
sizeof ( rsp ) , & rsp ) ;
}
l2cap_chan_del ( chan , reason ) ;
break ;
case BT_CONNECT :
case BT_DISCONN :
l2cap_chan_del ( chan , reason ) ;
break ;
default :
sock_set_flag ( sk , SOCK_ZAPPED ) ;
break ;
}
}
2011-04-13 01:31:57 +04:00
static inline u8 l2cap_get_auth_type ( struct l2cap_chan * chan )
2008-07-14 22:13:44 +04:00
{
2011-05-03 00:13:55 +04:00
if ( chan - > chan_type = = L2CAP_CHAN_RAW ) {
2011-04-13 01:31:57 +04:00
switch ( chan - > sec_level ) {
2011-01-19 09:36:50 +03:00
case BT_SECURITY_HIGH :
return HCI_AT_DEDICATED_BONDING_MITM ;
case BT_SECURITY_MEDIUM :
return HCI_AT_DEDICATED_BONDING ;
default :
return HCI_AT_NO_BONDING ;
}
2011-04-14 02:50:45 +04:00
} else if ( chan - > psm = = cpu_to_le16 ( 0x0001 ) ) {
2011-04-13 01:31:57 +04:00
if ( chan - > sec_level = = BT_SECURITY_LOW )
chan - > sec_level = BT_SECURITY_SDP ;
2009-02-09 04:48:38 +03:00
2011-04-13 01:31:57 +04:00
if ( chan - > sec_level = = BT_SECURITY_HIGH )
2011-01-19 09:36:50 +03:00
return HCI_AT_NO_BONDING_MITM ;
2009-02-12 18:19:45 +03:00
else
2011-01-19 09:36:50 +03:00
return HCI_AT_NO_BONDING ;
2009-02-12 18:19:45 +03:00
} else {
2011-04-13 01:31:57 +04:00
switch ( chan - > sec_level ) {
2009-02-12 18:19:45 +03:00
case BT_SECURITY_HIGH :
2011-01-19 09:36:50 +03:00
return HCI_AT_GENERAL_BONDING_MITM ;
2009-02-12 18:19:45 +03:00
case BT_SECURITY_MEDIUM :
2011-01-19 09:36:50 +03:00
return HCI_AT_GENERAL_BONDING ;
2009-02-12 18:19:45 +03:00
default :
2011-01-19 09:36:50 +03:00
return HCI_AT_NO_BONDING ;
2009-02-12 18:19:45 +03:00
}
2009-02-09 04:48:38 +03:00
}
2011-01-19 09:36:50 +03:00
}
/* Service level security */
2011-04-13 01:31:57 +04:00
static inline int l2cap_check_security ( struct l2cap_chan * chan )
2011-01-19 09:36:50 +03:00
{
2011-04-14 03:23:55 +04:00
struct l2cap_conn * conn = chan - > conn ;
2011-01-19 09:36:50 +03:00
__u8 auth_type ;
2011-04-13 01:31:57 +04:00
auth_type = l2cap_get_auth_type ( chan ) ;
2008-07-14 22:13:44 +04:00
2011-04-13 01:31:57 +04:00
return hci_conn_security ( conn - > hcon , chan - > sec_level , auth_type ) ;
2008-07-14 22:13:44 +04:00
}
2011-06-01 10:54:45 +04:00
static u8 l2cap_get_ident ( struct l2cap_conn * conn )
2007-10-20 15:37:56 +04:00
{
u8 id ;
/* Get next available identificator.
* 1 - 128 are used by kernel .
* 129 - 199 are reserved .
* 200 - 254 are used by utilities like l2ping , etc .
*/
spin_lock_bh ( & conn - > lock ) ;
if ( + + conn - > tx_ident > 128 )
conn - > tx_ident = 1 ;
id = conn - > tx_ident ;
spin_unlock_bh ( & conn - > lock ) ;
return id ;
}
2011-04-29 00:55:53 +04:00
static void l2cap_send_cmd ( struct l2cap_conn * conn , u8 ident , u8 code , u16 len , void * data )
2007-10-20 15:37:56 +04:00
{
struct sk_buff * skb = l2cap_build_cmd ( conn , code , ident , len , data ) ;
2011-01-03 12:14:36 +03:00
u8 flags ;
2007-10-20 15:37:56 +04:00
BT_DBG ( " code 0x%2.2x " , code ) ;
if ( ! skb )
2010-05-01 23:15:43 +04:00
return ;
2007-10-20 15:37:56 +04:00
2011-01-03 12:14:36 +03:00
if ( lmp_no_flush_capable ( conn - > hcon - > hdev ) )
flags = ACL_START_NO_FLUSH ;
else
flags = ACL_START ;
2011-05-24 05:06:04 +04:00
bt_cb ( skb ) - > force_active = BT_POWER_FORCE_ACTIVE_ON ;
2011-01-03 12:14:36 +03:00
hci_send_acl ( conn - > hcon , skb , flags ) ;
2007-10-20 15:37:56 +04:00
}
2011-03-26 01:43:39 +03:00
static inline void l2cap_send_sframe ( struct l2cap_chan * chan , u16 control )
2009-08-21 05:25:57 +04:00
{
struct sk_buff * skb ;
struct l2cap_hdr * lh ;
2011-04-14 03:23:55 +04:00
struct l2cap_conn * conn = chan - > conn ;
2009-08-21 05:26:02 +04:00
int count , hlen = L2CAP_HDR_SIZE + 2 ;
2011-01-03 12:14:36 +03:00
u8 flags ;
2009-08-21 05:26:02 +04:00
2011-06-03 07:19:47 +04:00
if ( chan - > state ! = BT_CONNECTED )
2010-05-14 03:50:12 +04:00
return ;
2011-04-13 22:57:03 +04:00
if ( chan - > fcs = = L2CAP_FCS_CRC16 )
2009-08-21 05:26:02 +04:00
hlen + = 2 ;
2009-08-21 05:25:57 +04:00
2011-04-04 22:59:54 +04:00
BT_DBG ( " chan %p, control 0x%2.2x " , chan , control ) ;
2009-08-21 05:25:57 +04:00
2009-08-21 05:26:02 +04:00
count = min_t ( unsigned int , conn - > mtu , hlen ) ;
2009-08-21 05:25:57 +04:00
control | = L2CAP_CTRL_FRAME_TYPE ;
2011-06-11 04:28:49 +04:00
if ( test_and_clear_bit ( CONN_SEND_FBIT , & chan - > conn_state ) )
2010-05-01 23:15:37 +04:00
control | = L2CAP_CTRL_FINAL ;
2011-06-11 04:28:49 +04:00
if ( test_and_clear_bit ( CONN_SEND_PBIT , & chan - > conn_state ) )
2010-05-01 23:15:37 +04:00
control | = L2CAP_CTRL_POLL ;
2009-08-21 05:25:57 +04:00
skb = bt_skb_alloc ( count , GFP_ATOMIC ) ;
if ( ! skb )
2010-05-01 23:15:43 +04:00
return ;
2009-08-21 05:25:57 +04:00
lh = ( struct l2cap_hdr * ) skb_put ( skb , L2CAP_HDR_SIZE ) ;
2009-08-21 05:26:02 +04:00
lh - > len = cpu_to_le16 ( hlen - L2CAP_HDR_SIZE ) ;
2011-04-14 02:50:45 +04:00
lh - > cid = cpu_to_le16 ( chan - > dcid ) ;
2009-08-21 05:25:57 +04:00
put_unaligned_le16 ( control , skb_put ( skb , 2 ) ) ;
2011-04-13 22:57:03 +04:00
if ( chan - > fcs = = L2CAP_FCS_CRC16 ) {
2009-08-21 05:26:02 +04:00
u16 fcs = crc16 ( 0 , ( u8 * ) lh , count - 2 ) ;
put_unaligned_le16 ( fcs , skb_put ( skb , 2 ) ) ;
}
2011-01-03 12:14:36 +03:00
if ( lmp_no_flush_capable ( conn - > hcon - > hdev ) )
flags = ACL_START_NO_FLUSH ;
else
flags = ACL_START ;
2011-05-24 05:06:04 +04:00
bt_cb ( skb ) - > force_active = chan - > force_active ;
2011-04-14 03:23:55 +04:00
hci_send_acl ( chan - > conn - > hcon , skb , flags ) ;
2009-08-21 05:25:57 +04:00
}
2011-03-26 01:43:39 +03:00
static inline void l2cap_send_rr_or_rnr ( struct l2cap_chan * chan , u16 control )
2009-08-26 11:04:03 +04:00
{
2011-06-11 04:28:49 +04:00
if ( test_bit ( CONN_LOCAL_BUSY , & chan - > conn_state ) ) {
2009-08-26 11:04:03 +04:00
control | = L2CAP_SUPER_RCV_NOT_READY ;
2011-06-11 04:28:49 +04:00
set_bit ( CONN_RNR_SENT , & chan - > conn_state ) ;
2010-05-01 23:15:44 +04:00
} else
2009-08-26 11:04:03 +04:00
control | = L2CAP_SUPER_RCV_READY ;
2011-03-26 01:58:34 +03:00
control | = chan - > buffer_seq < < L2CAP_CTRL_REQSEQ_SHIFT ;
2009-10-03 09:34:40 +04:00
2011-03-26 01:43:39 +03:00
l2cap_send_sframe ( chan , control ) ;
2009-08-26 11:04:03 +04:00
}
2011-04-13 01:15:09 +04:00
static inline int __l2cap_no_conn_pending ( struct l2cap_chan * chan )
2010-07-08 13:14:41 +04:00
{
2011-06-11 00:02:12 +04:00
return ! test_bit ( CONF_CONNECT_PEND , & chan - > conf_state ) ;
2010-07-08 13:14:41 +04:00
}
2011-03-25 19:59:37 +03:00
static void l2cap_do_start ( struct l2cap_chan * chan )
2008-07-14 22:13:44 +04:00
{
2011-04-14 03:23:55 +04:00
struct l2cap_conn * conn = chan - > conn ;
2008-07-14 22:13:44 +04:00
if ( conn - > info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT ) {
2009-02-07 01:35:19 +03:00
if ( ! ( conn - > info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE ) )
return ;
2011-04-13 01:31:57 +04:00
if ( l2cap_check_security ( chan ) & &
__l2cap_no_conn_pending ( chan ) ) {
2008-07-14 22:13:54 +04:00
struct l2cap_conn_req req ;
2011-04-14 02:50:45 +04:00
req . scid = cpu_to_le16 ( chan - > scid ) ;
req . psm = chan - > psm ;
2008-07-14 22:13:44 +04:00
2011-03-25 19:59:37 +03:00
chan - > ident = l2cap_get_ident ( conn ) ;
2011-06-11 00:02:12 +04:00
set_bit ( CONF_CONNECT_PEND , & chan - > conf_state ) ;
2008-07-14 22:13:44 +04:00
2011-03-25 19:59:37 +03:00
l2cap_send_cmd ( conn , chan - > ident , L2CAP_CONN_REQ ,
sizeof ( req ) , & req ) ;
2008-07-14 22:13:54 +04:00
}
2008-07-14 22:13:44 +04:00
} else {
struct l2cap_info_req req ;
req . type = cpu_to_le16 ( L2CAP_IT_FEAT_MASK ) ;
conn - > info_state | = L2CAP_INFO_FEAT_MASK_REQ_SENT ;
conn - > info_ident = l2cap_get_ident ( conn ) ;
mod_timer ( & conn - > info_timer , jiffies +
msecs_to_jiffies ( L2CAP_INFO_TIMEOUT ) ) ;
l2cap_send_cmd ( conn , conn - > info_ident ,
L2CAP_INFO_REQ , sizeof ( req ) , & req ) ;
}
}
2010-06-08 03:54:45 +04:00
static inline int l2cap_mode_supported ( __u8 mode , __u32 feat_mask )
{
u32 local_feat_mask = l2cap_feat_mask ;
2010-07-18 23:25:54 +04:00
if ( ! disable_ertm )
2010-06-08 03:54:45 +04:00
local_feat_mask | = L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING ;
switch ( mode ) {
case L2CAP_MODE_ERTM :
return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask ;
case L2CAP_MODE_STREAMING :
return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask ;
default :
return 0x00 ;
}
}
2011-04-29 00:55:53 +04:00
static void l2cap_send_disconn_req ( struct l2cap_conn * conn , struct l2cap_chan * chan , int err )
2009-07-23 17:27:23 +04:00
{
2011-04-01 07:53:45 +04:00
struct sock * sk ;
2009-07-23 17:27:23 +04:00
struct l2cap_disconn_req req ;
2010-05-14 03:50:12 +04:00
if ( ! conn )
return ;
2011-04-01 07:53:45 +04:00
sk = chan - > sk ;
2011-04-14 00:20:49 +04:00
if ( chan - > mode = = L2CAP_MODE_ERTM ) {
2011-05-17 22:13:19 +04:00
__clear_retrans_timer ( chan ) ;
__clear_monitor_timer ( chan ) ;
__clear_ack_timer ( chan ) ;
2010-05-14 03:50:12 +04:00
}
2011-04-14 02:50:45 +04:00
req . dcid = cpu_to_le16 ( chan - > dcid ) ;
req . scid = cpu_to_le16 ( chan - > scid ) ;
2009-07-23 17:27:23 +04:00
l2cap_send_cmd ( conn , l2cap_get_ident ( conn ) ,
L2CAP_DISCONN_REQ , sizeof ( req ) , & req ) ;
2010-05-14 03:50:12 +04:00
2011-06-03 07:19:47 +04:00
l2cap_state_change ( chan , BT_DISCONN ) ;
2010-05-20 23:21:53 +04:00
sk - > sk_err = err ;
2009-07-23 17:27:23 +04:00
}
2005-04-17 02:20:36 +04:00
/* ---- L2CAP connections ---- */
2007-10-20 15:37:56 +04:00
static void l2cap_conn_start ( struct l2cap_conn * conn )
{
2011-04-01 07:35:21 +04:00
struct l2cap_chan * chan , * tmp ;
2007-10-20 15:37:56 +04:00
BT_DBG ( " conn %p " , conn ) ;
2011-03-31 23:17:41 +04:00
read_lock ( & conn - > chan_lock ) ;
2007-10-20 15:37:56 +04:00
2011-04-01 07:35:21 +04:00
list_for_each_entry_safe ( chan , tmp , & conn - > chan_l , list ) {
2011-03-25 06:22:30 +03:00
struct sock * sk = chan - > sk ;
2011-03-31 23:17:41 +04:00
2007-10-20 15:37:56 +04:00
bh_lock_sock ( sk ) ;
2011-05-03 00:13:55 +04:00
if ( chan - > chan_type ! = L2CAP_CHAN_CONN_ORIENTED ) {
2008-07-14 22:13:44 +04:00
bh_unlock_sock ( sk ) ;
continue ;
}
2011-06-03 07:19:47 +04:00
if ( chan - > state = = BT_CONNECT ) {
2010-07-09 23:38:35 +04:00
struct l2cap_conn_req req ;
2008-07-14 22:13:44 +04:00
2011-04-13 01:31:57 +04:00
if ( ! l2cap_check_security ( chan ) | |
2011-04-13 01:15:09 +04:00
! __l2cap_no_conn_pending ( chan ) ) {
2010-07-09 23:38:35 +04:00
bh_unlock_sock ( sk ) ;
continue ;
}
2008-07-14 22:13:44 +04:00
2011-06-11 00:02:12 +04:00
if ( ! l2cap_mode_supported ( chan - > mode , conn - > feat_mask )
& & test_bit ( CONF_STATE2_DEVICE ,
& chan - > conf_state ) ) {
2011-05-05 02:42:50 +04:00
/* l2cap_chan_close() calls list_del(chan)
2011-04-01 07:35:21 +04:00
* so release the lock */
2011-06-17 19:57:25 +04:00
read_unlock ( & conn - > chan_lock ) ;
2011-06-03 07:19:47 +04:00
l2cap_chan_close ( chan , ECONNRESET ) ;
2011-06-17 19:57:25 +04:00
read_lock ( & conn - > chan_lock ) ;
2010-07-09 23:38:35 +04:00
bh_unlock_sock ( sk ) ;
continue ;
2008-07-14 22:13:54 +04:00
}
2010-07-09 23:38:35 +04:00
2011-04-14 02:50:45 +04:00
req . scid = cpu_to_le16 ( chan - > scid ) ;
req . psm = chan - > psm ;
2010-07-09 23:38:35 +04:00
2011-03-25 19:59:37 +03:00
chan - > ident = l2cap_get_ident ( conn ) ;
2011-06-11 00:02:12 +04:00
set_bit ( CONF_CONNECT_PEND , & chan - > conf_state ) ;
2010-07-09 23:38:35 +04:00
2011-03-25 19:59:37 +03:00
l2cap_send_cmd ( conn , chan - > ident , L2CAP_CONN_REQ ,
sizeof ( req ) , & req ) ;
2010-07-09 23:38:35 +04:00
2011-06-03 07:19:47 +04:00
} else if ( chan - > state = = BT_CONNECT2 ) {
2008-07-14 22:13:44 +04:00
struct l2cap_conn_rsp rsp ;
2010-07-09 03:08:18 +04:00
char buf [ 128 ] ;
2011-04-14 02:50:45 +04:00
rsp . scid = cpu_to_le16 ( chan - > dcid ) ;
rsp . dcid = cpu_to_le16 ( chan - > scid ) ;
2008-07-14 22:13:44 +04:00
2011-04-13 01:31:57 +04:00
if ( l2cap_check_security ( chan ) ) {
2009-01-15 23:57:00 +03:00
if ( bt_sk ( sk ) - > defer_setup ) {
struct sock * parent = bt_sk ( sk ) - > parent ;
rsp . result = cpu_to_le16 ( L2CAP_CR_PEND ) ;
rsp . status = cpu_to_le16 ( L2CAP_CS_AUTHOR_PEND ) ;
2011-07-15 22:30:21 +04:00
if ( parent )
parent - > sk_data_ready ( parent , 0 ) ;
2009-01-15 23:57:00 +03:00
} else {
2011-06-03 07:19:47 +04:00
l2cap_state_change ( chan , BT_CONFIG ) ;
2009-01-15 23:57:00 +03:00
rsp . result = cpu_to_le16 ( L2CAP_CR_SUCCESS ) ;
rsp . status = cpu_to_le16 ( L2CAP_CS_NO_INFO ) ;
}
2008-07-14 22:13:44 +04:00
} else {
rsp . result = cpu_to_le16 ( L2CAP_CR_PEND ) ;
rsp . status = cpu_to_le16 ( L2CAP_CS_AUTHEN_PEND ) ;
}
2011-03-25 19:59:37 +03:00
l2cap_send_cmd ( conn , chan - > ident , L2CAP_CONN_RSP ,
sizeof ( rsp ) , & rsp ) ;
2010-07-09 03:08:18 +04:00
2011-06-11 00:02:12 +04:00
if ( test_bit ( CONF_REQ_SENT , & chan - > conf_state ) | |
2010-07-09 03:08:18 +04:00
rsp . result ! = L2CAP_CR_SUCCESS ) {
bh_unlock_sock ( sk ) ;
continue ;
}
2011-06-11 00:02:12 +04:00
set_bit ( CONF_REQ_SENT , & chan - > conf_state ) ;
2010-07-09 03:08:18 +04:00
l2cap_send_cmd ( conn , l2cap_get_ident ( conn ) , L2CAP_CONF_REQ ,
2011-03-25 20:16:54 +03:00
l2cap_build_conf_req ( chan , buf ) , buf ) ;
chan - > num_conf_req + + ;
2007-10-20 15:37:56 +04:00
}
bh_unlock_sock ( sk ) ;
}
2011-03-31 23:17:41 +04:00
read_unlock ( & conn - > chan_lock ) ;
2007-10-20 15:37:56 +04:00
}
2011-02-11 04:38:50 +03:00
/* Find socket with cid and source bdaddr.
* Returns closest match , locked .
*/
2011-04-28 01:26:32 +04:00
static struct l2cap_chan * l2cap_global_chan_by_scid ( int state , __le16 cid , bdaddr_t * src )
2011-02-11 04:38:50 +03:00
{
2011-04-28 01:26:32 +04:00
struct l2cap_chan * c , * c1 = NULL ;
2011-02-11 04:38:50 +03:00
2011-04-28 01:26:32 +04:00
read_lock ( & chan_list_lock ) ;
2011-02-11 04:38:50 +03:00
2011-04-28 01:26:32 +04:00
list_for_each_entry ( c , & chan_list , global_l ) {
struct sock * sk = c - > sk ;
2011-04-14 02:50:45 +04:00
2011-06-03 07:19:47 +04:00
if ( state & & c - > state ! = state )
2011-02-11 04:38:50 +03:00
continue ;
2011-04-28 01:26:32 +04:00
if ( c - > scid = = cid ) {
2011-02-11 04:38:50 +03:00
/* Exact match. */
2011-04-28 01:26:32 +04:00
if ( ! bacmp ( & bt_sk ( sk ) - > src , src ) ) {
read_unlock ( & chan_list_lock ) ;
return c ;
}
2011-02-11 04:38:50 +03:00
/* Closest match */
if ( ! bacmp ( & bt_sk ( sk ) - > src , BDADDR_ANY ) )
2011-04-28 01:26:32 +04:00
c1 = c ;
2011-02-11 04:38:50 +03:00
}
}
2011-04-14 02:01:22 +04:00
2011-04-28 01:26:32 +04:00
read_unlock ( & chan_list_lock ) ;
2011-02-11 04:38:50 +03:00
2011-04-28 01:26:32 +04:00
return c1 ;
2011-02-11 04:38:50 +03:00
}
static void l2cap_le_conn_ready ( struct l2cap_conn * conn )
{
2011-04-04 23:00:55 +04:00
struct sock * parent , * sk ;
2011-04-28 01:26:32 +04:00
struct l2cap_chan * chan , * pchan ;
2011-02-11 04:38:50 +03:00
BT_DBG ( " " ) ;
/* Check if we have socket listening on cid */
2011-04-28 01:26:32 +04:00
pchan = l2cap_global_chan_by_scid ( BT_LISTEN , L2CAP_CID_LE_DATA ,
2011-02-11 04:38:50 +03:00
conn - > src ) ;
2011-04-28 01:26:32 +04:00
if ( ! pchan )
2011-02-11 04:38:50 +03:00
return ;
2011-04-28 01:26:32 +04:00
parent = pchan - > sk ;
2011-04-15 01:34:34 +04:00
bh_lock_sock ( parent ) ;
2011-02-11 04:38:50 +03:00
/* Check for backlog size */
if ( sk_acceptq_is_full ( parent ) ) {
BT_DBG ( " backlog full %d " , parent - > sk_ack_backlog ) ;
goto clean ;
}
2011-05-17 00:24:37 +04:00
chan = pchan - > ops - > new_connection ( pchan - > data ) ;
if ( ! chan )
2011-02-11 04:38:50 +03:00
goto clean ;
2011-05-17 00:24:37 +04:00
sk = chan - > sk ;
2011-04-08 22:40:02 +04:00
2011-03-31 23:17:41 +04:00
write_lock_bh ( & conn - > chan_lock ) ;
2011-02-11 04:38:50 +03:00
hci_conn_hold ( conn - > hcon ) ;
bacpy ( & bt_sk ( sk ) - > src , conn - > src ) ;
bacpy ( & bt_sk ( sk ) - > dst , conn - > dst ) ;
2011-03-25 06:39:48 +03:00
bt_accept_enqueue ( parent , sk ) ;
2011-03-25 06:22:30 +03:00
__l2cap_chan_add ( conn , chan ) ;
2011-05-17 21:59:01 +04:00
__set_chan_timer ( chan , sk - > sk_sndtimeo ) ;
2011-02-11 04:38:50 +03:00
2011-06-03 07:19:47 +04:00
l2cap_state_change ( chan , BT_CONNECTED ) ;
2011-02-11 04:38:50 +03:00
parent - > sk_data_ready ( parent , 0 ) ;
2011-03-31 23:17:41 +04:00
write_unlock_bh ( & conn - > chan_lock ) ;
2011-02-11 04:38:50 +03:00
clean :
bh_unlock_sock ( parent ) ;
}
2011-01-27 03:42:57 +03:00
static void l2cap_chan_ready ( struct sock * sk )
{
struct l2cap_chan * chan = l2cap_pi ( sk ) - > chan ;
struct sock * parent = bt_sk ( sk ) - > parent ;
BT_DBG ( " sk %p, parent %p " , sk , parent ) ;
chan - > conf_state = 0 ;
__clear_chan_timer ( chan ) ;
2011-06-21 01:53:18 +04:00
l2cap_state_change ( chan , BT_CONNECTED ) ;
2011-01-27 03:42:57 +03:00
sk - > sk_state_change ( sk ) ;
if ( parent )
parent - > sk_data_ready ( parent , 0 ) ;
}
2007-10-20 15:37:56 +04:00
static void l2cap_conn_ready ( struct l2cap_conn * conn )
{
2011-03-25 06:22:30 +03:00
struct l2cap_chan * chan ;
2007-10-20 15:37:56 +04:00
2008-07-14 22:13:44 +04:00
BT_DBG ( " conn %p " , conn ) ;
2007-10-20 15:37:56 +04:00
2011-02-11 04:38:50 +03:00
if ( ! conn - > hcon - > out & & conn - > hcon - > type = = LE_LINK )
l2cap_le_conn_ready ( conn ) ;
2011-03-31 23:17:41 +04:00
read_lock ( & conn - > chan_lock ) ;
2007-10-20 15:37:56 +04:00
2011-03-31 23:17:41 +04:00
list_for_each_entry ( chan , & conn - > chan_l , list ) {
2011-03-25 06:22:30 +03:00
struct sock * sk = chan - > sk ;
2011-03-31 23:17:41 +04:00
2008-07-14 22:13:44 +04:00
bh_lock_sock ( sk ) ;
2007-10-20 15:37:56 +04:00
2011-06-18 05:46:26 +04:00
if ( conn - > hcon - > type = = LE_LINK ) {
2011-06-08 01:46:31 +04:00
if ( smp_conn_security ( conn , chan - > sec_level ) )
2011-01-27 03:42:57 +03:00
l2cap_chan_ready ( sk ) ;
2011-02-11 04:38:49 +03:00
2011-06-18 05:46:26 +04:00
} else if ( chan - > chan_type ! = L2CAP_CHAN_CONN_ORIENTED ) {
2011-05-17 21:59:01 +04:00
__clear_chan_timer ( chan ) ;
2011-06-03 07:19:47 +04:00
l2cap_state_change ( chan , BT_CONNECTED ) ;
2008-07-14 22:13:44 +04:00
sk - > sk_state_change ( sk ) ;
2011-06-08 01:46:31 +04:00
2011-06-03 07:19:47 +04:00
} else if ( chan - > state = = BT_CONNECT )
2011-03-25 19:59:37 +03:00
l2cap_do_start ( chan ) ;
2007-10-20 15:37:56 +04:00
2008-07-14 22:13:44 +04:00
bh_unlock_sock ( sk ) ;
2007-10-20 15:37:56 +04:00
}
2008-07-14 22:13:44 +04:00
2011-03-31 23:17:41 +04:00
read_unlock ( & conn - > chan_lock ) ;
2007-10-20 15:37:56 +04:00
}
/* Notify sockets that we cannot guaranty reliability anymore */
static void l2cap_conn_unreliable ( struct l2cap_conn * conn , int err )
{
2011-03-25 06:22:30 +03:00
struct l2cap_chan * chan ;
2007-10-20 15:37:56 +04:00
BT_DBG ( " conn %p " , conn ) ;
2011-03-31 23:17:41 +04:00
read_lock ( & conn - > chan_lock ) ;
2007-10-20 15:37:56 +04:00
2011-03-31 23:17:41 +04:00
list_for_each_entry ( chan , & conn - > chan_l , list ) {
2011-03-25 06:22:30 +03:00
struct sock * sk = chan - > sk ;
2011-03-31 23:17:41 +04:00
2011-04-13 01:31:57 +04:00
if ( chan - > force_reliable )
2007-10-20 15:37:56 +04:00
sk - > sk_err = err ;
}
2011-03-31 23:17:41 +04:00
read_unlock ( & conn - > chan_lock ) ;
2007-10-20 15:37:56 +04:00
}
static void l2cap_info_timeout ( unsigned long arg )
{
struct l2cap_conn * conn = ( void * ) arg ;
2009-02-07 01:35:19 +03:00
conn - > info_state | = L2CAP_INFO_FEAT_MASK_REQ_DONE ;
2009-02-09 11:18:02 +03:00
conn - > info_ident = 0 ;
2009-02-07 01:35:19 +03:00
2007-10-20 15:37:56 +04:00
l2cap_conn_start ( conn ) ;
}
2011-06-14 20:37:41 +04:00
static void l2cap_conn_del ( struct hci_conn * hcon , int err )
{
struct l2cap_conn * conn = hcon - > l2cap_data ;
struct l2cap_chan * chan , * l ;
struct sock * sk ;
if ( ! conn )
return ;
BT_DBG ( " hcon %p conn %p, err %d " , hcon , conn , err ) ;
kfree_skb ( conn - > rx_skb ) ;
/* Kill channels */
list_for_each_entry_safe ( chan , l , & conn - > chan_l , list ) {
sk = chan - > sk ;
bh_lock_sock ( sk ) ;
l2cap_chan_del ( chan , err ) ;
bh_unlock_sock ( sk ) ;
chan - > ops - > close ( chan - > data ) ;
}
if ( conn - > info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT )
del_timer_sync ( & conn - > info_timer ) ;
if ( test_bit ( HCI_CONN_ENCRYPT_PEND , & hcon - > pend ) )
del_timer ( & conn - > security_timer ) ;
hcon - > l2cap_data = NULL ;
kfree ( conn ) ;
}
static void security_timeout ( unsigned long arg )
{
struct l2cap_conn * conn = ( void * ) arg ;
l2cap_conn_del ( conn - > hcon , ETIMEDOUT ) ;
}
2005-04-17 02:20:36 +04:00
static struct l2cap_conn * l2cap_conn_add ( struct hci_conn * hcon , u8 status )
{
2006-07-03 12:02:46 +04:00
struct l2cap_conn * conn = hcon - > l2cap_data ;
2005-04-17 02:20:36 +04:00
2006-07-03 12:02:46 +04:00
if ( conn | | status )
2005-04-17 02:20:36 +04:00
return conn ;
2006-07-03 12:02:46 +04:00
conn = kzalloc ( sizeof ( struct l2cap_conn ) , GFP_ATOMIC ) ;
if ( ! conn )
2005-04-17 02:20:36 +04:00
return NULL ;
hcon - > l2cap_data = conn ;
conn - > hcon = hcon ;
2006-07-03 12:02:46 +04:00
BT_DBG ( " hcon %p conn %p " , hcon , conn ) ;
2011-02-11 04:38:49 +03:00
if ( hcon - > hdev - > le_mtu & & hcon - > type = = LE_LINK )
conn - > mtu = hcon - > hdev - > le_mtu ;
else
conn - > mtu = hcon - > hdev - > acl_mtu ;
2005-04-17 02:20:36 +04:00
conn - > src = & hcon - > hdev - > bdaddr ;
conn - > dst = & hcon - > dst ;
2007-10-20 15:37:56 +04:00
conn - > feat_mask = 0 ;
2005-04-17 02:20:36 +04:00
spin_lock_init ( & conn - > lock ) ;
2011-03-31 23:17:41 +04:00
rwlock_init ( & conn - > chan_lock ) ;
INIT_LIST_HEAD ( & conn - > chan_l ) ;
2005-04-17 02:20:36 +04:00
2011-06-14 20:37:41 +04:00
if ( hcon - > type = = LE_LINK )
setup_timer ( & conn - > security_timer , security_timeout ,
( unsigned long ) conn ) ;
else
2011-02-11 04:38:50 +03:00
setup_timer ( & conn - > info_timer , l2cap_info_timeout ,
2009-10-19 00:28:30 +04:00
( unsigned long ) conn ) ;
2009-02-12 16:02:50 +03:00
conn - > disc_reason = 0x13 ;
2005-04-17 02:20:36 +04:00
return conn ;
}
2011-03-25 06:22:30 +03:00
static inline void l2cap_chan_add ( struct l2cap_conn * conn , struct l2cap_chan * chan )
2005-04-17 02:20:36 +04:00
{
2011-03-31 23:17:41 +04:00
write_lock_bh ( & conn - > chan_lock ) ;
2011-03-25 06:22:30 +03:00
__l2cap_chan_add ( conn , chan ) ;
2011-03-31 23:17:41 +04:00
write_unlock_bh ( & conn - > chan_lock ) ;
2005-04-17 02:20:36 +04:00
}
/* ---- Socket interface ---- */
/* Find socket with psm and source bdaddr.
* Returns closest match .
*/
2011-04-28 01:26:32 +04:00
static struct l2cap_chan * l2cap_global_chan_by_psm ( int state , __le16 psm , bdaddr_t * src )
2005-04-17 02:20:36 +04:00
{
2011-04-28 01:26:32 +04:00
struct l2cap_chan * c , * c1 = NULL ;
2005-04-17 02:20:36 +04:00
2011-04-28 01:26:32 +04:00
read_lock ( & chan_list_lock ) ;
2010-11-01 21:43:53 +03:00
2011-04-28 01:26:32 +04:00
list_for_each_entry ( c , & chan_list , global_l ) {
struct sock * sk = c - > sk ;
2011-04-14 02:50:45 +04:00
2011-06-03 07:19:47 +04:00
if ( state & & c - > state ! = state )
2005-04-17 02:20:36 +04:00
continue ;
2011-04-28 01:26:32 +04:00
if ( c - > psm = = psm ) {
2005-04-17 02:20:36 +04:00
/* Exact match. */
2011-04-28 01:26:32 +04:00
if ( ! bacmp ( & bt_sk ( sk ) - > src , src ) ) {
2011-06-01 10:29:54 +04:00
read_unlock ( & chan_list_lock ) ;
2011-04-28 01:26:32 +04:00
return c ;
}
2005-04-17 02:20:36 +04:00
/* Closest match */
if ( ! bacmp ( & bt_sk ( sk ) - > src , BDADDR_ANY ) )
2011-04-28 01:26:32 +04:00
c1 = c ;
2005-04-17 02:20:36 +04:00
}
}
2011-04-28 01:26:32 +04:00
read_unlock ( & chan_list_lock ) ;
2010-11-01 21:43:53 +03:00
2011-04-28 01:26:32 +04:00
return c1 ;
2005-04-17 02:20:36 +04:00
}
2011-04-13 01:17:14 +04:00
int l2cap_chan_connect ( struct l2cap_chan * chan )
2005-04-17 02:20:36 +04:00
{
2011-04-08 22:40:02 +04:00
struct sock * sk = chan - > sk ;
2005-04-17 02:20:36 +04:00
bdaddr_t * src = & bt_sk ( sk ) - > src ;
bdaddr_t * dst = & bt_sk ( sk ) - > dst ;
struct l2cap_conn * conn ;
struct hci_conn * hcon ;
struct hci_dev * hdev ;
2008-09-09 09:19:20 +04:00
__u8 auth_type ;
2009-04-20 09:09:16 +04:00
int err ;
2005-04-17 02:20:36 +04:00
2009-02-12 07:07:45 +03:00
BT_DBG ( " %s -> %s psm 0x%2.2x " , batostr ( src ) , batostr ( dst ) ,
2011-04-14 02:50:45 +04:00
chan - > psm ) ;
2005-04-17 02:20:36 +04:00
2009-04-20 08:31:08 +04:00
hdev = hci_get_route ( dst , src ) ;
if ( ! hdev )
2005-04-17 02:20:36 +04:00
return - EHOSTUNREACH ;
hci_dev_lock_bh ( hdev ) ;
2011-04-13 01:31:57 +04:00
auth_type = l2cap_get_auth_type ( chan ) ;
2008-09-09 09:19:20 +04:00
2011-04-14 02:50:45 +04:00
if ( chan - > dcid = = L2CAP_CID_LE_DATA )
2011-02-11 04:38:49 +03:00
hcon = hci_connect ( hdev , LE_LINK , dst ,
2011-04-13 01:31:57 +04:00
chan - > sec_level , auth_type ) ;
2011-02-11 04:38:49 +03:00
else
hcon = hci_connect ( hdev , ACL_LINK , dst ,
2011-04-13 01:31:57 +04:00
chan - > sec_level , auth_type ) ;
2011-02-11 04:38:49 +03:00
2011-02-22 22:10:53 +03:00
if ( IS_ERR ( hcon ) ) {
err = PTR_ERR ( hcon ) ;
2005-04-17 02:20:36 +04:00
goto done ;
2011-02-22 22:10:53 +03:00
}
2005-04-17 02:20:36 +04:00
conn = l2cap_conn_add ( hcon , 0 ) ;
if ( ! conn ) {
hci_conn_put ( hcon ) ;
2011-02-22 22:10:53 +03:00
err = - ENOMEM ;
2005-04-17 02:20:36 +04:00
goto done ;
}
/* Update source addr of the socket */
bacpy ( src , conn - > src ) ;
2011-03-25 06:22:30 +03:00
l2cap_chan_add ( conn , chan ) ;
2011-06-03 07:19:47 +04:00
l2cap_state_change ( chan , BT_CONNECT ) ;
2011-05-17 21:59:01 +04:00
__set_chan_timer ( chan , sk - > sk_sndtimeo ) ;
2005-04-17 02:20:36 +04:00
if ( hcon - > state = = BT_CONNECTED ) {
2011-05-03 00:13:55 +04:00
if ( chan - > chan_type ! = L2CAP_CHAN_CONN_ORIENTED ) {
2011-05-17 21:59:01 +04:00
__clear_chan_timer ( chan ) ;
2011-04-13 01:31:57 +04:00
if ( l2cap_check_security ( chan ) )
2011-06-03 07:19:47 +04:00
l2cap_state_change ( chan , BT_CONNECTED ) ;
2008-07-14 22:13:44 +04:00
} else
2011-03-25 19:59:37 +03:00
l2cap_do_start ( chan ) ;
2005-04-17 02:20:36 +04:00
}
2011-02-22 22:10:53 +03:00
err = 0 ;
2005-04-17 02:20:36 +04:00
done :
hci_dev_unlock_bh ( hdev ) ;
hci_dev_put ( hdev ) ;
return err ;
}
2011-02-04 08:08:36 +03:00
int __l2cap_wait_ack ( struct sock * sk )
2010-05-01 23:15:44 +04:00
{
2011-04-14 03:23:55 +04:00
struct l2cap_chan * chan = l2cap_pi ( sk ) - > chan ;
2010-05-01 23:15:44 +04:00
DECLARE_WAITQUEUE ( wait , current ) ;
int err = 0 ;
int timeo = HZ / 5 ;
2010-05-10 13:33:10 +04:00
add_wait_queue ( sk_sleep ( sk ) , & wait ) ;
2011-07-26 02:36:26 +04:00
set_current_state ( TASK_INTERRUPTIBLE ) ;
while ( chan - > unacked_frames > 0 & & chan - > conn ) {
2010-05-01 23:15:44 +04:00
if ( ! timeo )
timeo = HZ / 5 ;
if ( signal_pending ( current ) ) {
err = sock_intr_errno ( timeo ) ;
break ;
}
release_sock ( sk ) ;
timeo = schedule_timeout ( timeo ) ;
lock_sock ( sk ) ;
2011-07-26 02:36:26 +04:00
set_current_state ( TASK_INTERRUPTIBLE ) ;
2010-05-01 23:15:44 +04:00
err = sock_error ( sk ) ;
if ( err )
break ;
}
set_current_state ( TASK_RUNNING ) ;
2010-05-10 13:33:10 +04:00
remove_wait_queue ( sk_sleep ( sk ) , & wait ) ;
2010-05-01 23:15:44 +04:00
return err ;
}
2009-08-21 05:26:00 +04:00
static void l2cap_monitor_timeout ( unsigned long arg )
{
2011-03-26 01:43:39 +03:00
struct l2cap_chan * chan = ( void * ) arg ;
struct sock * sk = chan - > sk ;
2009-08-21 05:26:00 +04:00
2011-03-26 01:43:39 +03:00
BT_DBG ( " chan %p " , chan ) ;
2010-04-19 21:45:38 +04:00
2009-08-24 07:45:19 +04:00
bh_lock_sock ( sk ) ;
2011-03-26 02:15:28 +03:00
if ( chan - > retry_count > = chan - > remote_max_tx ) {
2011-04-14 03:23:55 +04:00
l2cap_send_disconn_req ( chan - > conn , chan , ECONNABORTED ) ;
2009-12-15 12:38:04 +03:00
bh_unlock_sock ( sk ) ;
2009-08-21 05:26:00 +04:00
return ;
}
2011-04-01 07:38:50 +04:00
chan - > retry_count + + ;
2011-05-17 22:13:19 +04:00
__set_monitor_timer ( chan ) ;
2009-08-21 05:26:00 +04:00
2011-03-26 01:43:39 +03:00
l2cap_send_rr_or_rnr ( chan , L2CAP_CTRL_POLL ) ;
2009-08-24 07:45:19 +04:00
bh_unlock_sock ( sk ) ;
2009-08-21 05:26:00 +04:00
}
static void l2cap_retrans_timeout ( unsigned long arg )
{
2011-03-26 01:43:39 +03:00
struct l2cap_chan * chan = ( void * ) arg ;
struct sock * sk = chan - > sk ;
2009-08-21 05:26:00 +04:00
2011-04-04 22:59:54 +04:00
BT_DBG ( " chan %p " , chan ) ;
2010-04-19 21:45:38 +04:00
2009-08-24 07:45:19 +04:00
bh_lock_sock ( sk ) ;
2011-04-01 07:38:50 +04:00
chan - > retry_count = 1 ;
2011-05-17 22:13:19 +04:00
__set_monitor_timer ( chan ) ;
2009-08-21 05:26:00 +04:00
2011-06-11 04:28:49 +04:00
set_bit ( CONN_WAIT_F , & chan - > conn_state ) ;
2009-08-21 05:26:00 +04:00
2011-03-26 01:43:39 +03:00
l2cap_send_rr_or_rnr ( chan , L2CAP_CTRL_POLL ) ;
2009-08-24 07:45:19 +04:00
bh_unlock_sock ( sk ) ;
2009-08-21 05:26:00 +04:00
}
2011-03-26 01:58:34 +03:00
static void l2cap_drop_acked_frames ( struct l2cap_chan * chan )
2005-04-17 02:20:36 +04:00
{
2009-08-21 05:25:57 +04:00
struct sk_buff * skb ;
2005-04-17 02:20:36 +04:00
2011-04-04 23:16:44 +04:00
while ( ( skb = skb_peek ( & chan - > tx_q ) ) & &
2011-04-01 07:38:50 +04:00
chan - > unacked_frames ) {
2011-03-26 01:58:34 +03:00
if ( bt_cb ( skb ) - > tx_seq = = chan - > expected_ack_seq )
2009-08-21 05:25:57 +04:00
break ;
2005-04-17 02:20:36 +04:00
2011-04-04 23:16:44 +04:00
skb = skb_dequeue ( & chan - > tx_q ) ;
2009-08-21 05:25:57 +04:00
kfree_skb ( skb ) ;
2005-04-17 02:20:36 +04:00
2011-04-01 07:38:50 +04:00
chan - > unacked_frames - - ;
2009-08-21 05:25:57 +04:00
}
2005-04-17 02:20:36 +04:00
2011-04-01 07:38:50 +04:00
if ( ! chan - > unacked_frames )
2011-05-17 22:13:19 +04:00
__clear_retrans_timer ( chan ) ;
2009-08-21 05:25:57 +04:00
}
2005-04-17 02:20:36 +04:00
2011-04-13 01:31:57 +04:00
void l2cap_do_send ( struct l2cap_chan * chan , struct sk_buff * skb )
2009-08-21 05:25:57 +04:00
{
2011-04-14 03:23:55 +04:00
struct hci_conn * hcon = chan - > conn - > hcon ;
2011-01-03 12:14:36 +03:00
u16 flags ;
2009-08-21 05:25:57 +04:00
2011-04-13 01:31:57 +04:00
BT_DBG ( " chan %p, skb %p len %d " , chan , skb , skb - > len ) ;
2005-04-17 02:20:36 +04:00
2011-04-13 01:31:57 +04:00
if ( ! chan - > flushable & & lmp_no_flush_capable ( hcon - > hdev ) )
2011-01-03 12:14:36 +03:00
flags = ACL_START_NO_FLUSH ;
else
flags = ACL_START ;
2011-05-24 05:06:04 +04:00
bt_cb ( skb ) - > force_active = chan - > force_active ;
2011-01-03 12:14:36 +03:00
hci_send_acl ( hcon , skb , flags ) ;
2009-08-21 05:25:57 +04:00
}
2011-03-26 01:58:34 +03:00
void l2cap_streaming_send ( struct l2cap_chan * chan )
2009-08-21 05:26:01 +04:00
{
2010-08-31 01:44:44 +04:00
struct sk_buff * skb ;
2009-08-21 05:26:02 +04:00
u16 control , fcs ;
2009-08-21 05:26:01 +04:00
2011-04-04 23:16:44 +04:00
while ( ( skb = skb_dequeue ( & chan - > tx_q ) ) ) {
2010-08-31 01:44:44 +04:00
control = get_unaligned_le16 ( skb - > data + L2CAP_HDR_SIZE ) ;
2011-03-26 01:58:34 +03:00
control | = chan - > next_tx_seq < < L2CAP_CTRL_TXSEQ_SHIFT ;
2010-08-31 01:44:44 +04:00
put_unaligned_le16 ( control , skb - > data + L2CAP_HDR_SIZE ) ;
2009-08-21 05:26:01 +04:00
2011-04-13 22:57:03 +04:00
if ( chan - > fcs = = L2CAP_FCS_CRC16 ) {
2010-08-31 01:44:44 +04:00
fcs = crc16 ( 0 , ( u8 * ) skb - > data , skb - > len - 2 ) ;
put_unaligned_le16 ( fcs , skb - > data + skb - > len - 2 ) ;
2009-08-21 05:26:02 +04:00
}
2011-04-13 01:31:57 +04:00
l2cap_do_send ( chan , skb ) ;
2009-08-21 05:26:01 +04:00
2011-03-26 01:58:34 +03:00
chan - > next_tx_seq = ( chan - > next_tx_seq + 1 ) % 64 ;
2009-08-21 05:26:01 +04:00
}
}
2011-03-26 01:43:39 +03:00
static void l2cap_retransmit_one_frame ( struct l2cap_chan * chan , u8 tx_seq )
2009-08-21 05:26:03 +04:00
{
struct sk_buff * skb , * tx_skb ;
u16 control , fcs ;
2011-04-04 23:16:44 +04:00
skb = skb_peek ( & chan - > tx_q ) ;
2010-05-01 23:15:44 +04:00
if ( ! skb )
return ;
2009-08-21 05:26:03 +04:00
2010-05-01 23:15:44 +04:00
do {
if ( bt_cb ( skb ) - > tx_seq = = tx_seq )
2009-08-21 05:26:03 +04:00
break ;
2011-04-04 23:16:44 +04:00
if ( skb_queue_is_last ( & chan - > tx_q , skb ) )
2010-05-01 23:15:44 +04:00
return ;
2009-08-21 05:26:03 +04:00
2011-04-04 23:16:44 +04:00
} while ( ( skb = skb_queue_next ( & chan - > tx_q , skb ) ) ) ;
2009-08-21 05:26:03 +04:00
2011-03-26 02:15:28 +03:00
if ( chan - > remote_max_tx & &
bt_cb ( skb ) - > retries = = chan - > remote_max_tx ) {
2011-04-14 03:23:55 +04:00
l2cap_send_disconn_req ( chan - > conn , chan , ECONNABORTED ) ;
2010-05-01 23:15:44 +04:00
return ;
}
tx_skb = skb_clone ( skb , GFP_ATOMIC ) ;
bt_cb ( skb ) - > retries + + ;
control = get_unaligned_le16 ( tx_skb - > data + L2CAP_HDR_SIZE ) ;
2011-04-18 07:04:30 +04:00
control & = L2CAP_CTRL_SAR ;
2010-05-29 09:24:35 +04:00
2011-06-11 04:28:49 +04:00
if ( test_and_clear_bit ( CONN_SEND_FBIT , & chan - > conn_state ) )
2010-05-29 09:24:35 +04:00
control | = L2CAP_CTRL_FINAL ;
2010-06-19 03:37:33 +04:00
2011-03-26 01:58:34 +03:00
control | = ( chan - > buffer_seq < < L2CAP_CTRL_REQSEQ_SHIFT )
2010-05-01 23:15:44 +04:00
| ( tx_seq < < L2CAP_CTRL_TXSEQ_SHIFT ) ;
2010-05-29 09:24:35 +04:00
2010-05-01 23:15:44 +04:00
put_unaligned_le16 ( control , tx_skb - > data + L2CAP_HDR_SIZE ) ;
2011-04-13 22:57:03 +04:00
if ( chan - > fcs = = L2CAP_FCS_CRC16 ) {
2010-05-01 23:15:44 +04:00
fcs = crc16 ( 0 , ( u8 * ) tx_skb - > data , tx_skb - > len - 2 ) ;
put_unaligned_le16 ( fcs , tx_skb - > data + tx_skb - > len - 2 ) ;
}
2011-04-13 01:31:57 +04:00
l2cap_do_send ( chan , tx_skb ) ;
2009-08-21 05:26:03 +04:00
}
2011-03-26 01:43:39 +03:00
int l2cap_ertm_send ( struct l2cap_chan * chan )
2009-08-21 05:25:57 +04:00
{
struct sk_buff * skb , * tx_skb ;
2009-08-21 05:26:02 +04:00
u16 control , fcs ;
2010-05-01 23:15:43 +04:00
int nsent = 0 ;
2009-08-21 05:25:57 +04:00
2011-06-03 07:19:47 +04:00
if ( chan - > state ! = BT_CONNECTED )
2010-05-14 03:50:12 +04:00
return - ENOTCONN ;
2009-08-21 05:26:00 +04:00
2011-04-04 23:16:44 +04:00
while ( ( skb = chan - > tx_send_head ) & & ( ! l2cap_tx_window_full ( chan ) ) ) {
2009-08-21 05:25:57 +04:00
2011-03-26 02:15:28 +03:00
if ( chan - > remote_max_tx & &
bt_cb ( skb ) - > retries = = chan - > remote_max_tx ) {
2011-04-14 03:23:55 +04:00
l2cap_send_disconn_req ( chan - > conn , chan , ECONNABORTED ) ;
2009-08-21 05:26:00 +04:00
break ;
}
2009-12-23 14:07:14 +03:00
tx_skb = skb_clone ( skb , GFP_ATOMIC ) ;
2009-08-21 05:26:00 +04:00
bt_cb ( skb ) - > retries + + ;
2009-08-21 05:25:57 +04:00
control = get_unaligned_le16 ( tx_skb - > data + L2CAP_HDR_SIZE ) ;
2010-06-19 03:37:33 +04:00
control & = L2CAP_CTRL_SAR ;
2011-06-11 04:28:49 +04:00
if ( test_and_clear_bit ( CONN_SEND_FBIT , & chan - > conn_state ) )
2010-05-01 23:15:36 +04:00
control | = L2CAP_CTRL_FINAL ;
2011-06-11 04:28:49 +04:00
2011-03-26 01:58:34 +03:00
control | = ( chan - > buffer_seq < < L2CAP_CTRL_REQSEQ_SHIFT )
| ( chan - > next_tx_seq < < L2CAP_CTRL_TXSEQ_SHIFT ) ;
2009-08-21 05:25:57 +04:00
put_unaligned_le16 ( control , tx_skb - > data + L2CAP_HDR_SIZE ) ;
2009-08-21 05:26:00 +04:00
2011-04-13 22:57:03 +04:00
if ( chan - > fcs = = L2CAP_FCS_CRC16 ) {
2009-08-21 05:26:02 +04:00
fcs = crc16 ( 0 , ( u8 * ) skb - > data , tx_skb - > len - 2 ) ;
put_unaligned_le16 ( fcs , skb - > data + tx_skb - > len - 2 ) ;
}
2011-04-13 01:31:57 +04:00
l2cap_do_send ( chan , tx_skb ) ;
2010-05-01 23:15:43 +04:00
2011-05-17 22:13:19 +04:00
__set_retrans_timer ( chan ) ;
2009-08-21 05:25:57 +04:00
2011-03-26 01:58:34 +03:00
bt_cb ( skb ) - > tx_seq = chan - > next_tx_seq ;
chan - > next_tx_seq = ( chan - > next_tx_seq + 1 ) % 64 ;
2009-08-21 05:25:57 +04:00
2011-03-09 12:14:05 +03:00
if ( bt_cb ( skb ) - > retries = = 1 )
2011-04-01 07:38:50 +04:00
chan - > unacked_frames + + ;
2011-03-09 12:14:05 +03:00
2011-04-01 07:38:50 +04:00
chan - > frames_sent + + ;
2009-08-21 05:25:57 +04:00
2011-04-04 23:16:44 +04:00
if ( skb_queue_is_last ( & chan - > tx_q , skb ) )
chan - > tx_send_head = NULL ;
2009-08-21 05:25:57 +04:00
else
2011-04-04 23:16:44 +04:00
chan - > tx_send_head = skb_queue_next ( & chan - > tx_q , skb ) ;
2010-05-01 23:15:37 +04:00
nsent + + ;
2009-08-21 05:25:57 +04:00
}
2010-05-01 23:15:37 +04:00
return nsent ;
}
2011-03-26 01:43:39 +03:00
static int l2cap_retransmit_frames ( struct l2cap_chan * chan )
2010-05-01 23:15:45 +04:00
{
int ret ;
2011-04-04 23:16:44 +04:00
if ( ! skb_queue_empty ( & chan - > tx_q ) )
chan - > tx_send_head = chan - > tx_q . next ;
2010-05-01 23:15:45 +04:00
2011-03-26 01:58:34 +03:00
chan - > next_tx_seq = chan - > expected_ack_seq ;
2011-03-26 01:43:39 +03:00
ret = l2cap_ertm_send ( chan ) ;
2010-05-01 23:15:45 +04:00
return ret ;
}
2011-03-26 01:43:39 +03:00
static void l2cap_send_ack ( struct l2cap_chan * chan )
2010-05-01 23:15:37 +04:00
{
u16 control = 0 ;
2011-03-26 01:58:34 +03:00
control | = chan - > buffer_seq < < L2CAP_CTRL_REQSEQ_SHIFT ;
2010-05-01 23:15:37 +04:00
2011-06-11 04:28:49 +04:00
if ( test_bit ( CONN_LOCAL_BUSY , & chan - > conn_state ) ) {
2010-05-01 23:15:37 +04:00
control | = L2CAP_SUPER_RCV_NOT_READY ;
2011-06-11 04:28:49 +04:00
set_bit ( CONN_RNR_SENT , & chan - > conn_state ) ;
2011-03-26 01:43:39 +03:00
l2cap_send_sframe ( chan , control ) ;
2010-05-01 23:15:43 +04:00
return ;
2010-05-01 23:15:37 +04:00
}
2010-05-01 23:15:45 +04:00
2011-03-26 01:43:39 +03:00
if ( l2cap_ertm_send ( chan ) > 0 )
2010-05-01 23:15:45 +04:00
return ;
control | = L2CAP_SUPER_RCV_READY ;
2011-03-26 01:43:39 +03:00
l2cap_send_sframe ( chan , control ) ;
2009-08-21 05:25:57 +04:00
}
2011-03-26 01:43:39 +03:00
static void l2cap_send_srejtail ( struct l2cap_chan * chan )
2010-05-01 23:15:38 +04:00
{
struct srej_list * tail ;
u16 control ;
control = L2CAP_SUPER_SELECT_REJECT ;
control | = L2CAP_CTRL_FINAL ;
2011-04-04 22:40:12 +04:00
tail = list_entry ( ( & chan - > srej_l ) - > prev , struct srej_list , list ) ;
2010-05-01 23:15:38 +04:00
control | = tail - > tx_seq < < L2CAP_CTRL_REQSEQ_SHIFT ;
2011-03-26 01:43:39 +03:00
l2cap_send_sframe ( chan , control ) ;
2010-05-01 23:15:38 +04:00
}
2009-08-21 05:25:57 +04:00
static inline int l2cap_skbuff_fromiovec ( struct sock * sk , struct msghdr * msg , int len , int count , struct sk_buff * skb )
{
2011-04-14 03:23:55 +04:00
struct l2cap_conn * conn = l2cap_pi ( sk ) - > chan - > conn ;
2009-08-21 05:25:57 +04:00
struct sk_buff * * frag ;
int err , sent = 0 ;
2005-04-17 02:20:36 +04:00
2010-05-01 23:15:43 +04:00
if ( memcpy_fromiovec ( skb_put ( skb , count ) , msg - > msg_iov , count ) )
2009-08-21 05:25:57 +04:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
sent + = count ;
len - = count ;
/* Continuation fragments (no L2CAP header) */
frag = & skb_shinfo ( skb ) - > frag_list ;
while ( len ) {
count = min_t ( unsigned int , conn - > mtu , len ) ;
* frag = bt_skb_send_alloc ( sk , count , msg - > msg_flags & MSG_DONTWAIT , & err ) ;
if ( ! * frag )
2010-09-25 03:30:57 +04:00
return err ;
2009-08-21 05:25:57 +04:00
if ( memcpy_fromiovec ( skb_put ( * frag , count ) , msg - > msg_iov , count ) )
return - EFAULT ;
2005-04-17 02:20:36 +04:00
sent + = count ;
len - = count ;
frag = & ( * frag ) - > next ;
}
return sent ;
2009-08-21 05:25:57 +04:00
}
2005-04-17 02:20:36 +04:00
2011-04-14 02:50:45 +04:00
struct sk_buff * l2cap_create_connless_pdu ( struct l2cap_chan * chan , struct msghdr * msg , size_t len )
2009-08-21 05:25:57 +04:00
{
2011-04-14 02:50:45 +04:00
struct sock * sk = chan - > sk ;
2011-04-14 03:23:55 +04:00
struct l2cap_conn * conn = chan - > conn ;
2009-08-21 05:25:57 +04:00
struct sk_buff * skb ;
int err , count , hlen = L2CAP_HDR_SIZE + 2 ;
struct l2cap_hdr * lh ;
BT_DBG ( " sk %p len %d " , sk , ( int ) len ) ;
count = min_t ( unsigned int , ( conn - > mtu - hlen ) , len ) ;
skb = bt_skb_send_alloc ( sk , count + hlen ,
msg - > msg_flags & MSG_DONTWAIT , & err ) ;
if ( ! skb )
2010-09-25 03:30:57 +04:00
return ERR_PTR ( err ) ;
2009-08-21 05:25:57 +04:00
/* Create L2CAP header */
lh = ( struct l2cap_hdr * ) skb_put ( skb , L2CAP_HDR_SIZE ) ;
2011-04-14 02:50:45 +04:00
lh - > cid = cpu_to_le16 ( chan - > dcid ) ;
2009-08-21 05:25:57 +04:00
lh - > len = cpu_to_le16 ( len + ( hlen - L2CAP_HDR_SIZE ) ) ;
2011-04-14 02:50:45 +04:00
put_unaligned_le16 ( chan - > psm , skb_put ( skb , 2 ) ) ;
2009-08-21 05:25:57 +04:00
err = l2cap_skbuff_fromiovec ( sk , msg , len , count , skb ) ;
if ( unlikely ( err < 0 ) ) {
kfree_skb ( skb ) ;
return ERR_PTR ( err ) ;
}
return skb ;
}
2011-04-14 02:50:45 +04:00
struct sk_buff * l2cap_create_basic_pdu ( struct l2cap_chan * chan , struct msghdr * msg , size_t len )
2009-08-21 05:25:57 +04:00
{
2011-04-14 02:50:45 +04:00
struct sock * sk = chan - > sk ;
2011-04-14 03:23:55 +04:00
struct l2cap_conn * conn = chan - > conn ;
2009-08-21 05:25:57 +04:00
struct sk_buff * skb ;
int err , count , hlen = L2CAP_HDR_SIZE ;
struct l2cap_hdr * lh ;
BT_DBG ( " sk %p len %d " , sk , ( int ) len ) ;
count = min_t ( unsigned int , ( conn - > mtu - hlen ) , len ) ;
skb = bt_skb_send_alloc ( sk , count + hlen ,
msg - > msg_flags & MSG_DONTWAIT , & err ) ;
if ( ! skb )
2010-09-25 03:30:57 +04:00
return ERR_PTR ( err ) ;
2009-08-21 05:25:57 +04:00
/* Create L2CAP header */
lh = ( struct l2cap_hdr * ) skb_put ( skb , L2CAP_HDR_SIZE ) ;
2011-04-14 02:50:45 +04:00
lh - > cid = cpu_to_le16 ( chan - > dcid ) ;
2009-08-21 05:25:57 +04:00
lh - > len = cpu_to_le16 ( len + ( hlen - L2CAP_HDR_SIZE ) ) ;
err = l2cap_skbuff_fromiovec ( sk , msg , len , count , skb ) ;
if ( unlikely ( err < 0 ) ) {
kfree_skb ( skb ) ;
return ERR_PTR ( err ) ;
}
return skb ;
}
2011-04-13 22:57:03 +04:00
struct sk_buff * l2cap_create_iframe_pdu ( struct l2cap_chan * chan , struct msghdr * msg , size_t len , u16 control , u16 sdulen )
2009-08-21 05:25:57 +04:00
{
2011-04-13 22:57:03 +04:00
struct sock * sk = chan - > sk ;
2011-04-14 03:23:55 +04:00
struct l2cap_conn * conn = chan - > conn ;
2009-08-21 05:25:57 +04:00
struct sk_buff * skb ;
int err , count , hlen = L2CAP_HDR_SIZE + 2 ;
struct l2cap_hdr * lh ;
BT_DBG ( " sk %p len %d " , sk , ( int ) len ) ;
2010-05-01 23:15:41 +04:00
if ( ! conn )
return ERR_PTR ( - ENOTCONN ) ;
2009-08-21 05:25:58 +04:00
if ( sdulen )
hlen + = 2 ;
2011-04-13 22:57:03 +04:00
if ( chan - > fcs = = L2CAP_FCS_CRC16 )
2009-08-21 05:26:02 +04:00
hlen + = 2 ;
2009-08-21 05:25:57 +04:00
count = min_t ( unsigned int , ( conn - > mtu - hlen ) , len ) ;
skb = bt_skb_send_alloc ( sk , count + hlen ,
msg - > msg_flags & MSG_DONTWAIT , & err ) ;
if ( ! skb )
2010-09-25 03:30:57 +04:00
return ERR_PTR ( err ) ;
2009-08-21 05:25:57 +04:00
/* Create L2CAP header */
lh = ( struct l2cap_hdr * ) skb_put ( skb , L2CAP_HDR_SIZE ) ;
2011-04-14 02:50:45 +04:00
lh - > cid = cpu_to_le16 ( chan - > dcid ) ;
2009-08-21 05:25:57 +04:00
lh - > len = cpu_to_le16 ( len + ( hlen - L2CAP_HDR_SIZE ) ) ;
put_unaligned_le16 ( control , skb_put ( skb , 2 ) ) ;
2009-08-21 05:25:58 +04:00
if ( sdulen )
put_unaligned_le16 ( sdulen , skb_put ( skb , 2 ) ) ;
2009-08-21 05:25:57 +04:00
err = l2cap_skbuff_fromiovec ( sk , msg , len , count , skb ) ;
if ( unlikely ( err < 0 ) ) {
kfree_skb ( skb ) ;
return ERR_PTR ( err ) ;
}
2009-08-21 05:26:00 +04:00
2011-04-13 22:57:03 +04:00
if ( chan - > fcs = = L2CAP_FCS_CRC16 )
2009-08-21 05:26:02 +04:00
put_unaligned_le16 ( 0 , skb_put ( skb , 2 ) ) ;
2009-08-21 05:26:00 +04:00
bt_cb ( skb ) - > retries = 0 ;
2009-08-21 05:25:57 +04:00
return skb ;
2005-04-17 02:20:36 +04:00
}
2011-03-26 02:15:28 +03:00
int l2cap_sar_segment_sdu ( struct l2cap_chan * chan , struct msghdr * msg , size_t len )
2009-08-21 05:25:58 +04:00
{
struct sk_buff * skb ;
struct sk_buff_head sar_queue ;
u16 control ;
size_t size = 0 ;
2010-05-06 05:09:15 +04:00
skb_queue_head_init ( & sar_queue ) ;
2009-08-21 05:25:58 +04:00
control = L2CAP_SDU_START ;
2011-04-13 22:57:03 +04:00
skb = l2cap_create_iframe_pdu ( chan , msg , chan - > remote_mps , control , len ) ;
2009-08-21 05:25:58 +04:00
if ( IS_ERR ( skb ) )
return PTR_ERR ( skb ) ;
__skb_queue_tail ( & sar_queue , skb ) ;
2011-03-26 02:15:28 +03:00
len - = chan - > remote_mps ;
size + = chan - > remote_mps ;
2009-08-21 05:25:58 +04:00
while ( len > 0 ) {
size_t buflen ;
2011-03-26 02:15:28 +03:00
if ( len > chan - > remote_mps ) {
2010-05-01 23:15:43 +04:00
control = L2CAP_SDU_CONTINUE ;
2011-03-26 02:15:28 +03:00
buflen = chan - > remote_mps ;
2009-08-21 05:25:58 +04:00
} else {
2010-05-01 23:15:43 +04:00
control = L2CAP_SDU_END ;
2009-08-21 05:25:58 +04:00
buflen = len ;
}
2011-04-13 22:57:03 +04:00
skb = l2cap_create_iframe_pdu ( chan , msg , buflen , control , 0 ) ;
2009-08-21 05:25:58 +04:00
if ( IS_ERR ( skb ) ) {
skb_queue_purge ( & sar_queue ) ;
return PTR_ERR ( skb ) ;
}
__skb_queue_tail ( & sar_queue , skb ) ;
len - = buflen ;
size + = buflen ;
}
2011-04-04 23:16:44 +04:00
skb_queue_splice_tail ( & sar_queue , & chan - > tx_q ) ;
if ( chan - > tx_send_head = = NULL )
chan - > tx_send_head = sar_queue . next ;
2009-08-21 05:25:58 +04:00
return size ;
}
2011-04-29 01:50:17 +04:00
int l2cap_chan_send ( struct l2cap_chan * chan , struct msghdr * msg , size_t len )
{
struct sk_buff * skb ;
u16 control ;
int err ;
/* Connectionless channel */
2011-05-03 00:13:55 +04:00
if ( chan - > chan_type = = L2CAP_CHAN_CONN_LESS ) {
2011-04-29 01:50:17 +04:00
skb = l2cap_create_connless_pdu ( chan , msg , len ) ;
if ( IS_ERR ( skb ) )
return PTR_ERR ( skb ) ;
l2cap_do_send ( chan , skb ) ;
return len ;
}
switch ( chan - > mode ) {
case L2CAP_MODE_BASIC :
/* Check outgoing MTU */
if ( len > chan - > omtu )
return - EMSGSIZE ;
/* Create a basic PDU */
skb = l2cap_create_basic_pdu ( chan , msg , len ) ;
if ( IS_ERR ( skb ) )
return PTR_ERR ( skb ) ;
l2cap_do_send ( chan , skb ) ;
err = len ;
break ;
case L2CAP_MODE_ERTM :
case L2CAP_MODE_STREAMING :
/* Entire SDU fits into one PDU */
if ( len < = chan - > remote_mps ) {
control = L2CAP_SDU_UNSEGMENTED ;
skb = l2cap_create_iframe_pdu ( chan , msg , len , control ,
0 ) ;
if ( IS_ERR ( skb ) )
return PTR_ERR ( skb ) ;
__skb_queue_tail ( & chan - > tx_q , skb ) ;
if ( chan - > tx_send_head = = NULL )
chan - > tx_send_head = skb ;
} else {
/* Segment SDU into multiples PDUs */
err = l2cap_sar_segment_sdu ( chan , msg , len ) ;
if ( err < 0 )
return err ;
}
if ( chan - > mode = = L2CAP_MODE_STREAMING ) {
l2cap_streaming_send ( chan ) ;
err = len ;
break ;
}
2011-06-11 04:28:49 +04:00
if ( test_bit ( CONN_REMOTE_BUSY , & chan - > conn_state ) & &
test_bit ( CONN_WAIT_F , & chan - > conn_state ) ) {
2011-04-29 01:50:17 +04:00
err = len ;
break ;
}
err = l2cap_ertm_send ( chan ) ;
if ( err > = 0 )
err = len ;
break ;
default :
BT_DBG ( " bad state %1.1x " , chan - > mode ) ;
err = - EBADFD ;
}
return err ;
}
2005-04-17 02:20:36 +04:00
/* Copy frame to all raw sockets on that connection */
static void l2cap_raw_recv ( struct l2cap_conn * conn , struct sk_buff * skb )
{
struct sk_buff * nskb ;
2011-03-25 06:22:30 +03:00
struct l2cap_chan * chan ;
2005-04-17 02:20:36 +04:00
BT_DBG ( " conn %p " , conn ) ;
2011-03-31 23:17:41 +04:00
read_lock ( & conn - > chan_lock ) ;
list_for_each_entry ( chan , & conn - > chan_l , list ) {
2011-03-25 06:22:30 +03:00
struct sock * sk = chan - > sk ;
2011-05-03 00:13:55 +04:00
if ( chan - > chan_type ! = L2CAP_CHAN_RAW )
2005-04-17 02:20:36 +04:00
continue ;
/* Don't send frame to the socket it came from */
if ( skb - > sk = = sk )
continue ;
2009-04-20 08:31:08 +04:00
nskb = skb_clone ( skb , GFP_ATOMIC ) ;
if ( ! nskb )
2005-04-17 02:20:36 +04:00
continue ;
2011-05-17 00:57:22 +04:00
if ( chan - > ops - > recv ( chan - > data , nskb ) )
2005-04-17 02:20:36 +04:00
kfree_skb ( nskb ) ;
}
2011-03-31 23:17:41 +04:00
read_unlock ( & conn - > chan_lock ) ;
2005-04-17 02:20:36 +04:00
}
/* ---- L2CAP signalling commands ---- */
static struct sk_buff * l2cap_build_cmd ( struct l2cap_conn * conn ,
u8 code , u8 ident , u16 dlen , void * data )
{
struct sk_buff * skb , * * frag ;
struct l2cap_cmd_hdr * cmd ;
struct l2cap_hdr * lh ;
int len , count ;
2009-04-20 08:31:08 +04:00
BT_DBG ( " conn %p, code 0x%2.2x, ident 0x%2.2x, len %d " ,
conn , code , ident , dlen ) ;
2005-04-17 02:20:36 +04:00
len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen ;
count = min_t ( unsigned int , conn - > mtu , len ) ;
skb = bt_skb_alloc ( count , GFP_ATOMIC ) ;
if ( ! skb )
return NULL ;
lh = ( struct l2cap_hdr * ) skb_put ( skb , L2CAP_HDR_SIZE ) ;
2007-03-26 07:12:50 +04:00
lh - > len = cpu_to_le16 ( L2CAP_CMD_HDR_SIZE + dlen ) ;
2011-02-12 00:28:54 +03:00
if ( conn - > hcon - > type = = LE_LINK )
lh - > cid = cpu_to_le16 ( L2CAP_CID_LE_SIGNALING ) ;
else
lh - > cid = cpu_to_le16 ( L2CAP_CID_SIGNALING ) ;
2005-04-17 02:20:36 +04:00
cmd = ( struct l2cap_cmd_hdr * ) skb_put ( skb , L2CAP_CMD_HDR_SIZE ) ;
cmd - > code = code ;
cmd - > ident = ident ;
2007-03-26 07:12:50 +04:00
cmd - > len = cpu_to_le16 ( dlen ) ;
2005-04-17 02:20:36 +04:00
if ( dlen ) {
count - = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE ;
memcpy ( skb_put ( skb , count ) , data , count ) ;
data + = count ;
}
len - = skb - > len ;
/* Continuation fragments (no L2CAP header) */
frag = & skb_shinfo ( skb ) - > frag_list ;
while ( len ) {
count = min_t ( unsigned int , conn - > mtu , len ) ;
* frag = bt_skb_alloc ( count , GFP_ATOMIC ) ;
if ( ! * frag )
goto fail ;
memcpy ( skb_put ( * frag , count ) , data , count ) ;
len - = count ;
data + = count ;
frag = & ( * frag ) - > next ;
}
return skb ;
fail :
kfree_skb ( skb ) ;
return NULL ;
}
static inline int l2cap_get_conf_opt ( void * * ptr , int * type , int * olen , unsigned long * val )
{
struct l2cap_conf_opt * opt = * ptr ;
int len ;
len = L2CAP_CONF_OPT_SIZE + opt - > len ;
* ptr + = len ;
* type = opt - > type ;
* olen = opt - > len ;
switch ( opt - > len ) {
case 1 :
* val = * ( ( u8 * ) opt - > val ) ;
break ;
case 2 :
2010-10-17 02:29:47 +04:00
* val = get_unaligned_le16 ( opt - > val ) ;
2005-04-17 02:20:36 +04:00
break ;
case 4 :
2010-10-17 02:29:47 +04:00
* val = get_unaligned_le32 ( opt - > val ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
* val = ( unsigned long ) opt - > val ;
break ;
}
BT_DBG ( " type 0x%2.2x len %d val 0x%lx " , * type , opt - > len , * val ) ;
return len ;
}
static void l2cap_add_conf_opt ( void * * ptr , u8 type , u8 len , unsigned long val )
{
struct l2cap_conf_opt * opt = * ptr ;
BT_DBG ( " type 0x%2.2x len %d val 0x%lx " , type , len , val ) ;
opt - > type = type ;
opt - > len = len ;
switch ( len ) {
case 1 :
* ( ( u8 * ) opt - > val ) = val ;
break ;
case 2 :
2010-10-18 20:25:53 +04:00
put_unaligned_le16 ( val , opt - > val ) ;
2005-04-17 02:20:36 +04:00
break ;
case 4 :
2010-10-18 20:25:53 +04:00
put_unaligned_le32 ( val , opt - > val ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
memcpy ( opt - > val , ( void * ) val , len ) ;
break ;
}
* ptr + = L2CAP_CONF_OPT_SIZE + len ;
}
2010-05-01 23:15:39 +04:00
static void l2cap_ack_timeout ( unsigned long arg )
{
2011-03-26 01:43:39 +03:00
struct l2cap_chan * chan = ( void * ) arg ;
2010-05-01 23:15:39 +04:00
2011-03-26 01:43:39 +03:00
bh_lock_sock ( chan - > sk ) ;
l2cap_send_ack ( chan ) ;
bh_unlock_sock ( chan - > sk ) ;
2010-05-01 23:15:39 +04:00
}
2011-03-26 01:43:39 +03:00
static inline void l2cap_ertm_init ( struct l2cap_chan * chan )
2009-10-03 09:34:36 +04:00
{
2011-03-26 01:43:39 +03:00
struct sock * sk = chan - > sk ;
2011-03-26 01:58:34 +03:00
chan - > expected_ack_seq = 0 ;
2011-04-01 07:38:50 +04:00
chan - > unacked_frames = 0 ;
2011-03-26 01:58:34 +03:00
chan - > buffer_seq = 0 ;
2011-04-01 07:38:50 +04:00
chan - > num_acked = 0 ;
chan - > frames_sent = 0 ;
2009-10-03 09:34:36 +04:00
2011-04-01 07:53:45 +04:00
setup_timer ( & chan - > retrans_timer , l2cap_retrans_timeout ,
( unsigned long ) chan ) ;
setup_timer ( & chan - > monitor_timer , l2cap_monitor_timeout ,
( unsigned long ) chan ) ;
setup_timer ( & chan - > ack_timer , l2cap_ack_timeout , ( unsigned long ) chan ) ;
2009-10-03 09:34:36 +04:00
2011-03-26 02:36:10 +03:00
skb_queue_head_init ( & chan - > srej_q ) ;
2010-05-01 23:15:44 +04:00
2011-04-04 22:40:12 +04:00
INIT_LIST_HEAD ( & chan - > srej_l ) ;
2010-06-22 01:53:22 +04:00
sk - > sk_backlog_rcv = l2cap_ertm_data_rcv ;
2009-10-03 09:34:36 +04:00
}
2009-07-04 22:06:24 +04:00
static inline __u8 l2cap_select_mode ( __u8 mode , __u16 remote_feat_mask )
{
switch ( mode ) {
case L2CAP_MODE_STREAMING :
case L2CAP_MODE_ERTM :
if ( l2cap_mode_supported ( mode , remote_feat_mask ) )
return mode ;
/* fall through */
default :
return L2CAP_MODE_BASIC ;
}
}
2011-03-25 20:30:37 +03:00
static int l2cap_build_conf_req ( struct l2cap_chan * chan , void * data )
2005-04-17 02:20:36 +04:00
{
struct l2cap_conf_req * req = data ;
2011-04-14 00:20:49 +04:00
struct l2cap_conf_rfc rfc = { . mode = chan - > mode } ;
2005-04-17 02:20:36 +04:00
void * ptr = req - > data ;
2011-04-04 22:59:54 +04:00
BT_DBG ( " chan %p " , chan ) ;
2005-04-17 02:20:36 +04:00
2011-03-25 20:16:54 +03:00
if ( chan - > num_conf_req | | chan - > num_conf_rsp )
2009-07-04 22:06:24 +04:00
goto done ;
2011-04-14 00:20:49 +04:00
switch ( chan - > mode ) {
2009-07-04 22:06:24 +04:00
case L2CAP_MODE_STREAMING :
case L2CAP_MODE_ERTM :
2011-06-11 00:02:12 +04:00
if ( test_bit ( CONF_STATE2_DEVICE , & chan - > conf_state ) )
2010-06-04 01:43:28 +04:00
break ;
2010-06-09 23:39:05 +04:00
/* fall through */
2009-07-04 22:06:24 +04:00
default :
2011-04-14 03:23:55 +04:00
chan - > mode = l2cap_select_mode ( rfc . mode , chan - > conn - > feat_mask ) ;
2009-07-04 22:06:24 +04:00
break ;
}
done :
2011-04-14 00:20:49 +04:00
if ( chan - > imtu ! = L2CAP_DEFAULT_MTU )
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_MTU , 2 , chan - > imtu ) ;
2011-01-24 21:01:43 +03:00
2011-04-14 00:20:49 +04:00
switch ( chan - > mode ) {
2009-05-03 10:07:53 +04:00
case L2CAP_MODE_BASIC :
2011-04-14 03:23:55 +04:00
if ( ! ( chan - > conn - > feat_mask & L2CAP_FEAT_ERTM ) & &
! ( chan - > conn - > feat_mask & L2CAP_FEAT_STREAMING ) )
2010-08-04 06:49:29 +04:00
break ;
2010-06-09 03:05:31 +04:00
rfc . mode = L2CAP_MODE_BASIC ;
rfc . txwin_size = 0 ;
rfc . max_transmit = 0 ;
rfc . retrans_timeout = 0 ;
rfc . monitor_timeout = 0 ;
rfc . max_pdu_size = 0 ;
2010-08-04 06:49:29 +04:00
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_RFC , sizeof ( rfc ) ,
( unsigned long ) & rfc ) ;
2009-05-03 10:07:53 +04:00
break ;
case L2CAP_MODE_ERTM :
rfc . mode = L2CAP_MODE_ERTM ;
2011-04-13 22:57:03 +04:00
rfc . txwin_size = chan - > tx_win ;
rfc . max_transmit = chan - > max_tx ;
2009-07-04 22:06:24 +04:00
rfc . retrans_timeout = 0 ;
rfc . monitor_timeout = 0 ;
2009-08-21 05:25:58 +04:00
rfc . max_pdu_size = cpu_to_le16 ( L2CAP_DEFAULT_MAX_PDU_SIZE ) ;
2011-04-14 03:23:55 +04:00
if ( L2CAP_DEFAULT_MAX_PDU_SIZE > chan - > conn - > mtu - 10 )
rfc . max_pdu_size = cpu_to_le16 ( chan - > conn - > mtu - 10 ) ;
2009-07-04 22:06:24 +04:00
2010-08-04 06:49:29 +04:00
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_RFC , sizeof ( rfc ) ,
( unsigned long ) & rfc ) ;
2011-04-14 03:23:55 +04:00
if ( ! ( chan - > conn - > feat_mask & L2CAP_FEAT_FCS ) )
2009-08-21 05:26:02 +04:00
break ;
2011-04-13 22:57:03 +04:00
if ( chan - > fcs = = L2CAP_FCS_NONE | |
2011-06-11 00:02:12 +04:00
test_bit ( CONF_NO_FCS_RECV , & chan - > conf_state ) ) {
2011-04-13 22:57:03 +04:00
chan - > fcs = L2CAP_FCS_NONE ;
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_FCS , 1 , chan - > fcs ) ;
2009-08-21 05:26:02 +04:00
}
2009-07-04 22:06:24 +04:00
break ;
case L2CAP_MODE_STREAMING :
rfc . mode = L2CAP_MODE_STREAMING ;
rfc . txwin_size = 0 ;
rfc . max_transmit = 0 ;
rfc . retrans_timeout = 0 ;
rfc . monitor_timeout = 0 ;
2009-08-21 05:25:58 +04:00
rfc . max_pdu_size = cpu_to_le16 ( L2CAP_DEFAULT_MAX_PDU_SIZE ) ;
2011-04-14 03:23:55 +04:00
if ( L2CAP_DEFAULT_MAX_PDU_SIZE > chan - > conn - > mtu - 10 )
rfc . max_pdu_size = cpu_to_le16 ( chan - > conn - > mtu - 10 ) ;
2009-05-03 10:07:53 +04:00
2010-08-04 06:49:29 +04:00
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_RFC , sizeof ( rfc ) ,
( unsigned long ) & rfc ) ;
2011-04-14 03:23:55 +04:00
if ( ! ( chan - > conn - > feat_mask & L2CAP_FEAT_FCS ) )
2009-08-21 05:26:02 +04:00
break ;
2011-04-13 22:57:03 +04:00
if ( chan - > fcs = = L2CAP_FCS_NONE | |
2011-06-11 00:02:12 +04:00
test_bit ( CONF_NO_FCS_RECV , & chan - > conf_state ) ) {
2011-04-13 22:57:03 +04:00
chan - > fcs = L2CAP_FCS_NONE ;
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_FCS , 1 , chan - > fcs ) ;
2009-08-21 05:26:02 +04:00
}
2009-05-03 10:07:53 +04:00
break ;
}
2005-04-17 02:20:36 +04:00
2011-04-14 02:50:45 +04:00
req - > dcid = cpu_to_le16 ( chan - > dcid ) ;
2007-03-26 07:12:50 +04:00
req - > flags = cpu_to_le16 ( 0 ) ;
2005-04-17 02:20:36 +04:00
return ptr - data ;
}
2011-03-25 20:16:54 +03:00
static int l2cap_parse_conf_req ( struct l2cap_chan * chan , void * data )
2005-04-17 02:20:36 +04:00
{
2007-05-24 16:27:19 +04:00
struct l2cap_conf_rsp * rsp = data ;
void * ptr = rsp - > data ;
2011-03-25 20:16:54 +03:00
void * req = chan - > conf_req ;
int len = chan - > conf_len ;
2007-05-24 16:27:19 +04:00
int type , hint , olen ;
unsigned long val ;
2007-10-20 15:39:51 +04:00
struct l2cap_conf_rfc rfc = { . mode = L2CAP_MODE_BASIC } ;
2007-10-20 15:37:06 +04:00
u16 mtu = L2CAP_DEFAULT_MTU ;
2007-05-24 16:27:19 +04:00
u16 result = L2CAP_CONF_SUCCESS ;
2005-04-17 02:20:36 +04:00
2011-03-25 20:16:54 +03:00
BT_DBG ( " chan %p " , chan ) ;
2006-11-19 00:15:00 +03:00
2007-05-24 16:27:19 +04:00
while ( len > = L2CAP_CONF_OPT_SIZE ) {
len - = l2cap_get_conf_opt ( & req , & type , & olen , & val ) ;
2005-04-17 02:20:36 +04:00
2009-04-20 08:31:07 +04:00
hint = type & L2CAP_CONF_HINT ;
2009-05-03 05:57:55 +04:00
type & = L2CAP_CONF_MASK ;
2007-05-24 16:27:19 +04:00
switch ( type ) {
case L2CAP_CONF_MTU :
2007-10-20 15:37:06 +04:00
mtu = val ;
2007-05-24 16:27:19 +04:00
break ;
case L2CAP_CONF_FLUSH_TO :
2011-04-14 00:20:49 +04:00
chan - > flush_to = val ;
2007-05-24 16:27:19 +04:00
break ;
case L2CAP_CONF_QOS :
break ;
2007-10-20 15:39:51 +04:00
case L2CAP_CONF_RFC :
if ( olen = = sizeof ( rfc ) )
memcpy ( & rfc , ( void * ) val , olen ) ;
break ;
2009-08-21 05:26:02 +04:00
case L2CAP_CONF_FCS :
if ( val = = L2CAP_FCS_NONE )
2011-06-11 00:02:12 +04:00
set_bit ( CONF_NO_FCS_RECV , & chan - > conf_state ) ;
2009-08-21 05:26:02 +04:00
break ;
2007-05-24 16:27:19 +04:00
default :
if ( hint )
break ;
result = L2CAP_CONF_UNKNOWN ;
* ( ( u8 * ) ptr + + ) = type ;
break ;
}
}
2011-03-25 20:16:54 +03:00
if ( chan - > num_conf_rsp | | chan - > num_conf_req > 1 )
2009-07-04 22:06:24 +04:00
goto done ;
2011-04-14 00:20:49 +04:00
switch ( chan - > mode ) {
2009-07-04 22:06:24 +04:00
case L2CAP_MODE_STREAMING :
case L2CAP_MODE_ERTM :
2011-06-11 00:02:12 +04:00
if ( ! test_bit ( CONF_STATE2_DEVICE , & chan - > conf_state ) ) {
2011-04-14 00:20:49 +04:00
chan - > mode = l2cap_select_mode ( rfc . mode ,
2011-04-14 03:23:55 +04:00
chan - > conn - > feat_mask ) ;
2010-06-04 01:43:28 +04:00
break ;
}
2011-04-14 00:20:49 +04:00
if ( chan - > mode ! = rfc . mode )
2009-07-04 22:06:24 +04:00
return - ECONNREFUSED ;
2010-06-09 02:09:48 +04:00
2009-07-04 22:06:24 +04:00
break ;
}
done :
2011-04-14 00:20:49 +04:00
if ( chan - > mode ! = rfc . mode ) {
2009-07-04 22:06:24 +04:00
result = L2CAP_CONF_UNACCEPT ;
2011-04-14 00:20:49 +04:00
rfc . mode = chan - > mode ;
2009-07-04 22:06:24 +04:00
2011-03-25 20:16:54 +03:00
if ( chan - > num_conf_rsp = = 1 )
2009-07-04 22:06:24 +04:00
return - ECONNREFUSED ;
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_RFC ,
sizeof ( rfc ) , ( unsigned long ) & rfc ) ;
}
2007-05-24 16:27:19 +04:00
if ( result = = L2CAP_CONF_SUCCESS ) {
/* Configure output options and let the other side know
* which ones we don ' t like . */
2009-07-04 22:06:24 +04:00
if ( mtu < L2CAP_DEFAULT_MIN_MTU )
result = L2CAP_CONF_UNACCEPT ;
else {
2011-04-14 00:20:49 +04:00
chan - > omtu = mtu ;
2011-06-11 00:02:12 +04:00
set_bit ( CONF_MTU_DONE , & chan - > conf_state ) ;
2009-07-04 22:06:24 +04:00
}
2011-04-14 00:20:49 +04:00
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_MTU , 2 , chan - > omtu ) ;
2007-10-20 15:39:51 +04:00
2009-07-04 22:06:24 +04:00
switch ( rfc . mode ) {
case L2CAP_MODE_BASIC :
2011-04-13 22:57:03 +04:00
chan - > fcs = L2CAP_FCS_NONE ;
2011-06-11 00:02:12 +04:00
set_bit ( CONF_MODE_DONE , & chan - > conf_state ) ;
2009-07-04 22:06:24 +04:00
break ;
case L2CAP_MODE_ERTM :
2011-03-26 02:15:28 +03:00
chan - > remote_tx_win = rfc . txwin_size ;
chan - > remote_max_tx = rfc . max_transmit ;
2010-08-06 02:54:22 +04:00
2011-04-14 03:23:55 +04:00
if ( le16_to_cpu ( rfc . max_pdu_size ) > chan - > conn - > mtu - 10 )
rfc . max_pdu_size = cpu_to_le16 ( chan - > conn - > mtu - 10 ) ;
2010-05-01 23:15:40 +04:00
2011-03-26 02:15:28 +03:00
chan - > remote_mps = le16_to_cpu ( rfc . max_pdu_size ) ;
2009-07-04 22:06:24 +04:00
2010-05-01 23:15:40 +04:00
rfc . retrans_timeout =
le16_to_cpu ( L2CAP_DEFAULT_RETRANS_TO ) ;
rfc . monitor_timeout =
le16_to_cpu ( L2CAP_DEFAULT_MONITOR_TO ) ;
2009-07-04 22:06:24 +04:00
2011-06-11 00:02:12 +04:00
set_bit ( CONF_MODE_DONE , & chan - > conf_state ) ;
2009-10-18 04:41:01 +04:00
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_RFC ,
sizeof ( rfc ) , ( unsigned long ) & rfc ) ;
2009-07-04 22:06:24 +04:00
break ;
case L2CAP_MODE_STREAMING :
2011-04-14 03:23:55 +04:00
if ( le16_to_cpu ( rfc . max_pdu_size ) > chan - > conn - > mtu - 10 )
rfc . max_pdu_size = cpu_to_le16 ( chan - > conn - > mtu - 10 ) ;
2010-05-01 23:15:40 +04:00
2011-03-26 02:15:28 +03:00
chan - > remote_mps = le16_to_cpu ( rfc . max_pdu_size ) ;
2009-07-04 22:06:24 +04:00
2011-06-11 00:02:12 +04:00
set_bit ( CONF_MODE_DONE , & chan - > conf_state ) ;
2009-10-18 04:41:01 +04:00
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_RFC ,
sizeof ( rfc ) , ( unsigned long ) & rfc ) ;
2009-07-04 22:06:24 +04:00
break ;
default :
2007-05-24 16:27:19 +04:00
result = L2CAP_CONF_UNACCEPT ;
2007-10-20 15:39:51 +04:00
memset ( & rfc , 0 , sizeof ( rfc ) ) ;
2011-04-14 00:20:49 +04:00
rfc . mode = chan - > mode ;
2009-07-04 22:06:24 +04:00
}
2007-10-20 15:39:51 +04:00
2009-07-04 22:06:24 +04:00
if ( result = = L2CAP_CONF_SUCCESS )
2011-06-11 00:02:12 +04:00
set_bit ( CONF_OUTPUT_DONE , & chan - > conf_state ) ;
2009-07-04 22:06:24 +04:00
}
2011-04-14 02:50:45 +04:00
rsp - > scid = cpu_to_le16 ( chan - > dcid ) ;
2007-05-24 16:27:19 +04:00
rsp - > result = cpu_to_le16 ( result ) ;
rsp - > flags = cpu_to_le16 ( 0x0000 ) ;
return ptr - data ;
2005-04-17 02:20:36 +04:00
}
2011-04-13 01:15:09 +04:00
static int l2cap_parse_conf_rsp ( struct l2cap_chan * chan , void * rsp , int len , void * data , u16 * result )
2009-07-04 22:06:24 +04:00
{
struct l2cap_conf_req * req = data ;
void * ptr = req - > data ;
int type , olen ;
unsigned long val ;
struct l2cap_conf_rfc rfc ;
2011-04-14 02:50:45 +04:00
BT_DBG ( " chan %p, rsp %p, len %d, req %p " , chan , rsp , len , data ) ;
2009-07-04 22:06:24 +04:00
while ( len > = L2CAP_CONF_OPT_SIZE ) {
len - = l2cap_get_conf_opt ( & rsp , & type , & olen , & val ) ;
switch ( type ) {
case L2CAP_CONF_MTU :
if ( val < L2CAP_DEFAULT_MIN_MTU ) {
* result = L2CAP_CONF_UNACCEPT ;
2011-04-14 00:20:49 +04:00
chan - > imtu = L2CAP_DEFAULT_MIN_MTU ;
2009-07-04 22:06:24 +04:00
} else
2011-04-14 00:20:49 +04:00
chan - > imtu = val ;
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_MTU , 2 , chan - > imtu ) ;
2009-07-04 22:06:24 +04:00
break ;
case L2CAP_CONF_FLUSH_TO :
2011-04-14 00:20:49 +04:00
chan - > flush_to = val ;
2009-07-04 22:06:24 +04:00
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_FLUSH_TO ,
2011-04-14 00:20:49 +04:00
2 , chan - > flush_to ) ;
2009-07-04 22:06:24 +04:00
break ;
case L2CAP_CONF_RFC :
if ( olen = = sizeof ( rfc ) )
memcpy ( & rfc , ( void * ) val , olen ) ;
2011-06-11 00:02:12 +04:00
if ( test_bit ( CONF_STATE2_DEVICE , & chan - > conf_state ) & &
2011-04-14 00:20:49 +04:00
rfc . mode ! = chan - > mode )
2009-07-04 22:06:24 +04:00
return - ECONNREFUSED ;
2011-04-13 22:57:03 +04:00
chan - > fcs = 0 ;
2009-07-04 22:06:24 +04:00
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_RFC ,
sizeof ( rfc ) , ( unsigned long ) & rfc ) ;
break ;
}
}
2011-04-14 00:20:49 +04:00
if ( chan - > mode = = L2CAP_MODE_BASIC & & chan - > mode ! = rfc . mode )
2010-06-09 03:08:49 +04:00
return - ECONNREFUSED ;
2011-04-14 00:20:49 +04:00
chan - > mode = rfc . mode ;
2010-06-09 03:08:49 +04:00
2009-07-04 22:06:24 +04:00
if ( * result = = L2CAP_CONF_SUCCESS ) {
switch ( rfc . mode ) {
case L2CAP_MODE_ERTM :
2011-04-13 22:57:03 +04:00
chan - > retrans_timeout = le16_to_cpu ( rfc . retrans_timeout ) ;
chan - > monitor_timeout = le16_to_cpu ( rfc . monitor_timeout ) ;
chan - > mps = le16_to_cpu ( rfc . max_pdu_size ) ;
2009-07-04 22:06:24 +04:00
break ;
case L2CAP_MODE_STREAMING :
2011-04-13 22:57:03 +04:00
chan - > mps = le16_to_cpu ( rfc . max_pdu_size ) ;
2009-07-04 22:06:24 +04:00
}
}
2011-04-14 02:50:45 +04:00
req - > dcid = cpu_to_le16 ( chan - > dcid ) ;
2009-07-04 22:06:24 +04:00
req - > flags = cpu_to_le16 ( 0x0000 ) ;
return ptr - data ;
}
2011-04-14 02:50:45 +04:00
static int l2cap_build_conf_rsp ( struct l2cap_chan * chan , void * data , u16 result , u16 flags )
2005-04-17 02:20:36 +04:00
{
struct l2cap_conf_rsp * rsp = data ;
void * ptr = rsp - > data ;
2011-04-14 02:50:45 +04:00
BT_DBG ( " chan %p " , chan ) ;
2005-04-17 02:20:36 +04:00
2011-04-14 02:50:45 +04:00
rsp - > scid = cpu_to_le16 ( chan - > dcid ) ;
2007-05-24 16:27:19 +04:00
rsp - > result = cpu_to_le16 ( result ) ;
2007-03-26 07:12:50 +04:00
rsp - > flags = cpu_to_le16 ( flags ) ;
2005-04-17 02:20:36 +04:00
return ptr - data ;
}
2011-04-14 03:23:55 +04:00
void __l2cap_connect_rsp_defer ( struct l2cap_chan * chan )
2011-03-25 20:30:37 +03:00
{
struct l2cap_conn_rsp rsp ;
2011-04-14 03:23:55 +04:00
struct l2cap_conn * conn = chan - > conn ;
2011-03-25 20:30:37 +03:00
u8 buf [ 128 ] ;
2011-04-14 02:50:45 +04:00
rsp . scid = cpu_to_le16 ( chan - > dcid ) ;
rsp . dcid = cpu_to_le16 ( chan - > scid ) ;
2011-03-25 20:30:37 +03:00
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 ) ;
2011-06-11 00:02:12 +04:00
if ( test_and_set_bit ( CONF_REQ_SENT , & chan - > conf_state ) )
2011-03-25 20:30:37 +03:00
return ;
l2cap_send_cmd ( conn , l2cap_get_ident ( conn ) , L2CAP_CONF_REQ ,
l2cap_build_conf_req ( chan , buf ) , buf ) ;
chan - > num_conf_req + + ;
}
2011-04-13 22:57:03 +04:00
static void l2cap_conf_rfc_get ( struct l2cap_chan * chan , void * rsp , int len )
2010-05-01 23:15:39 +04:00
{
int type , olen ;
unsigned long val ;
struct l2cap_conf_rfc rfc ;
2011-04-13 22:57:03 +04:00
BT_DBG ( " chan %p, rsp %p, len %d " , chan , rsp , len ) ;
2010-05-01 23:15:39 +04:00
2011-04-14 00:20:49 +04:00
if ( ( chan - > mode ! = L2CAP_MODE_ERTM ) & & ( chan - > mode ! = L2CAP_MODE_STREAMING ) )
2010-05-01 23:15:39 +04:00
return ;
while ( len > = L2CAP_CONF_OPT_SIZE ) {
len - = l2cap_get_conf_opt ( & rsp , & type , & olen , & val ) ;
switch ( type ) {
case L2CAP_CONF_RFC :
if ( olen = = sizeof ( rfc ) )
memcpy ( & rfc , ( void * ) val , olen ) ;
goto done ;
}
}
done :
switch ( rfc . mode ) {
case L2CAP_MODE_ERTM :
2011-04-13 22:57:03 +04:00
chan - > retrans_timeout = le16_to_cpu ( rfc . retrans_timeout ) ;
chan - > monitor_timeout = le16_to_cpu ( rfc . monitor_timeout ) ;
chan - > mps = le16_to_cpu ( rfc . max_pdu_size ) ;
2010-05-01 23:15:39 +04:00
break ;
case L2CAP_MODE_STREAMING :
2011-04-13 22:57:03 +04:00
chan - > mps = le16_to_cpu ( rfc . max_pdu_size ) ;
2010-05-01 23:15:39 +04:00
}
}
2007-10-20 15:37:56 +04:00
static inline int l2cap_command_rej ( struct l2cap_conn * conn , struct l2cap_cmd_hdr * cmd , u8 * data )
{
2011-07-10 09:47:44 +04:00
struct l2cap_cmd_rej_unk * rej = ( struct l2cap_cmd_rej_unk * ) data ;
2007-10-20 15:37:56 +04:00
2011-07-10 09:47:44 +04:00
if ( rej - > reason ! = L2CAP_REJ_NOT_UNDERSTOOD )
2007-10-20 15:37:56 +04:00
return 0 ;
if ( ( conn - > info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT ) & &
cmd - > ident = = conn - > info_ident ) {
del_timer ( & conn - > info_timer ) ;
2009-02-07 01:35:19 +03:00
conn - > info_state | = L2CAP_INFO_FEAT_MASK_REQ_DONE ;
2009-02-09 11:18:02 +03:00
conn - > info_ident = 0 ;
2009-02-07 01:35:19 +03:00
2007-10-20 15:37:56 +04:00
l2cap_conn_start ( conn ) ;
}
return 0 ;
}
2005-04-17 02:20:36 +04:00
static inline int l2cap_connect_req ( struct l2cap_conn * conn , struct l2cap_cmd_hdr * cmd , u8 * data )
{
struct l2cap_conn_req * req = ( struct l2cap_conn_req * ) data ;
struct l2cap_conn_rsp rsp ;
2011-04-28 01:26:32 +04:00
struct l2cap_chan * chan = NULL , * pchan ;
2010-10-15 19:54:02 +04:00
struct sock * parent , * sk = NULL ;
2008-09-09 09:19:20 +04:00
int result , status = L2CAP_CS_NO_INFO ;
2005-04-17 02:20:36 +04:00
u16 dcid = 0 , scid = __le16_to_cpu ( req - > scid ) ;
2008-09-09 09:19:20 +04:00
__le16 psm = req - > psm ;
2005-04-17 02:20:36 +04:00
BT_DBG ( " psm 0x%2.2x scid 0x%4.4x " , psm , scid ) ;
/* Check if we have socket listening on psm */
2011-04-28 01:26:32 +04:00
pchan = l2cap_global_chan_by_psm ( BT_LISTEN , psm , conn - > src ) ;
if ( ! pchan ) {
2005-04-17 02:20:36 +04:00
result = L2CAP_CR_BAD_PSM ;
goto sendresp ;
}
2011-04-28 01:26:32 +04:00
parent = pchan - > sk ;
2010-11-01 21:43:53 +03:00
bh_lock_sock ( parent ) ;
2008-09-09 09:19:20 +04:00
/* Check if the ACL is secure enough (if not SDP) */
if ( psm ! = cpu_to_le16 ( 0x0001 ) & &
! hci_conn_check_link_mode ( conn - > hcon ) ) {
2009-02-12 16:02:50 +03:00
conn - > disc_reason = 0x05 ;
2008-09-09 09:19:20 +04:00
result = L2CAP_CR_SEC_BLOCK ;
goto response ;
}
2005-04-17 02:20:36 +04:00
result = L2CAP_CR_NO_MEM ;
/* Check for backlog size */
if ( sk_acceptq_is_full ( parent ) ) {
2007-02-09 17:24:33 +03:00
BT_DBG ( " backlog full %d " , parent - > sk_ack_backlog ) ;
2005-04-17 02:20:36 +04:00
goto response ;
}
2011-05-17 00:24:37 +04:00
chan = pchan - > ops - > new_connection ( pchan - > data ) ;
if ( ! chan )
2005-04-17 02:20:36 +04:00
goto response ;
2011-05-17 00:24:37 +04:00
sk = chan - > sk ;
2011-03-31 23:17:41 +04:00
write_lock_bh ( & conn - > chan_lock ) ;
2005-04-17 02:20:36 +04:00
/* Check if we already have channel with that dcid */
2011-03-31 23:17:41 +04:00
if ( __l2cap_get_chan_by_dcid ( conn , scid ) ) {
write_unlock_bh ( & conn - > chan_lock ) ;
2005-04-17 02:20:36 +04:00
sock_set_flag ( sk , SOCK_ZAPPED ) ;
2011-05-17 01:23:24 +04:00
chan - > ops - > close ( chan - > data ) ;
2005-04-17 02:20:36 +04:00
goto response ;
}
hci_conn_hold ( conn - > hcon ) ;
bacpy ( & bt_sk ( sk ) - > src , conn - > src ) ;
bacpy ( & bt_sk ( sk ) - > dst , conn - > dst ) ;
2011-04-14 02:50:45 +04:00
chan - > psm = psm ;
chan - > dcid = scid ;
2005-04-17 02:20:36 +04:00
2011-03-25 06:39:48 +03:00
bt_accept_enqueue ( parent , sk ) ;
2011-03-25 06:22:30 +03:00
__l2cap_chan_add ( conn , chan ) ;
2011-04-14 02:50:45 +04:00
dcid = chan - > scid ;
2005-04-17 02:20:36 +04:00
2011-05-17 21:59:01 +04:00
__set_chan_timer ( chan , sk - > sk_sndtimeo ) ;
2005-04-17 02:20:36 +04:00
2011-03-25 19:59:37 +03:00
chan - > ident = cmd - > ident ;
2005-04-17 02:20:36 +04:00
2009-02-07 01:35:19 +03:00
if ( conn - > info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE ) {
2011-04-13 01:31:57 +04:00
if ( l2cap_check_security ( chan ) ) {
2009-01-15 23:57:00 +03:00
if ( bt_sk ( sk ) - > defer_setup ) {
2011-06-03 07:19:47 +04:00
l2cap_state_change ( chan , BT_CONNECT2 ) ;
2009-01-15 23:57:00 +03:00
result = L2CAP_CR_PEND ;
status = L2CAP_CS_AUTHOR_PEND ;
parent - > sk_data_ready ( parent , 0 ) ;
} else {
2011-06-03 07:19:47 +04:00
l2cap_state_change ( chan , BT_CONFIG ) ;
2009-01-15 23:57:00 +03:00
result = L2CAP_CR_SUCCESS ;
status = L2CAP_CS_NO_INFO ;
}
2008-07-14 22:13:44 +04:00
} else {
2011-06-03 07:19:47 +04:00
l2cap_state_change ( chan , BT_CONNECT2 ) ;
2008-07-14 22:13:44 +04:00
result = L2CAP_CR_PEND ;
status = L2CAP_CS_AUTHEN_PEND ;
}
} else {
2011-06-03 07:19:47 +04:00
l2cap_state_change ( chan , BT_CONNECT2 ) ;
2008-07-14 22:13:44 +04:00
result = L2CAP_CR_PEND ;
status = L2CAP_CS_NO_INFO ;
2005-04-17 02:20:36 +04:00
}
2011-03-31 23:17:41 +04:00
write_unlock_bh ( & conn - > chan_lock ) ;
2005-04-17 02:20:36 +04:00
response :
bh_unlock_sock ( parent ) ;
sendresp :
2007-03-26 07:12:50 +04:00
rsp . scid = cpu_to_le16 ( scid ) ;
rsp . dcid = cpu_to_le16 ( dcid ) ;
rsp . result = cpu_to_le16 ( result ) ;
rsp . status = cpu_to_le16 ( status ) ;
2005-04-17 02:20:36 +04:00
l2cap_send_cmd ( conn , cmd - > ident , L2CAP_CONN_RSP , sizeof ( rsp ) , & rsp ) ;
2008-07-14 22:13:44 +04:00
if ( result = = L2CAP_CR_PEND & & status = = L2CAP_CS_NO_INFO ) {
struct l2cap_info_req info ;
info . type = cpu_to_le16 ( L2CAP_IT_FEAT_MASK ) ;
conn - > info_state | = L2CAP_INFO_FEAT_MASK_REQ_SENT ;
conn - > info_ident = l2cap_get_ident ( conn ) ;
mod_timer ( & conn - > info_timer , jiffies +
msecs_to_jiffies ( L2CAP_INFO_TIMEOUT ) ) ;
l2cap_send_cmd ( conn , conn - > info_ident ,
L2CAP_INFO_REQ , sizeof ( info ) , & info ) ;
}
2011-06-11 00:02:12 +04:00
if ( chan & & ! test_bit ( CONF_REQ_SENT , & chan - > conf_state ) & &
2010-07-09 03:08:18 +04:00
result = = L2CAP_CR_SUCCESS ) {
u8 buf [ 128 ] ;
2011-06-11 00:02:12 +04:00
set_bit ( CONF_REQ_SENT , & chan - > conf_state ) ;
2010-07-09 03:08:18 +04:00
l2cap_send_cmd ( conn , l2cap_get_ident ( conn ) , L2CAP_CONF_REQ ,
2011-03-25 20:16:54 +03:00
l2cap_build_conf_req ( chan , buf ) , buf ) ;
chan - > num_conf_req + + ;
2010-07-09 03:08:18 +04:00
}
2005-04-17 02:20:36 +04:00
return 0 ;
}
static inline int l2cap_connect_rsp ( struct l2cap_conn * conn , struct l2cap_cmd_hdr * cmd , u8 * data )
{
struct l2cap_conn_rsp * rsp = ( struct l2cap_conn_rsp * ) data ;
u16 scid , dcid , result , status ;
2011-03-25 06:22:30 +03:00
struct l2cap_chan * chan ;
2005-04-17 02:20:36 +04:00
struct sock * sk ;
u8 req [ 128 ] ;
scid = __le16_to_cpu ( rsp - > scid ) ;
dcid = __le16_to_cpu ( rsp - > dcid ) ;
result = __le16_to_cpu ( rsp - > result ) ;
status = __le16_to_cpu ( rsp - > 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 ) {
2011-03-31 23:17:41 +04:00
chan = l2cap_get_chan_by_scid ( conn , scid ) ;
2011-03-25 06:22:30 +03:00
if ( ! chan )
2010-06-22 20:56:26 +04:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
} else {
2011-03-31 23:17:41 +04:00
chan = l2cap_get_chan_by_ident ( conn , cmd - > ident ) ;
2011-03-25 06:22:30 +03:00
if ( ! chan )
2010-06-22 20:56:26 +04:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
}
2011-03-25 06:22:30 +03:00
sk = chan - > sk ;
2005-04-17 02:20:36 +04:00
switch ( result ) {
case L2CAP_CR_SUCCESS :
2011-06-03 07:19:47 +04:00
l2cap_state_change ( chan , BT_CONFIG ) ;
2011-03-25 19:59:37 +03:00
chan - > ident = 0 ;
2011-04-14 02:50:45 +04:00
chan - > dcid = dcid ;
2011-06-11 00:02:12 +04:00
clear_bit ( CONF_CONNECT_PEND , & chan - > conf_state ) ;
2009-02-07 01:56:36 +03:00
2011-06-11 00:02:12 +04:00
if ( test_and_set_bit ( CONF_REQ_SENT , & chan - > conf_state ) )
2010-07-09 03:08:18 +04:00
break ;
2005-04-17 02:20:36 +04:00
l2cap_send_cmd ( conn , l2cap_get_ident ( conn ) , L2CAP_CONF_REQ ,
2011-03-25 20:16:54 +03:00
l2cap_build_conf_req ( chan , req ) , req ) ;
chan - > num_conf_req + + ;
2005-04-17 02:20:36 +04:00
break ;
case L2CAP_CR_PEND :
2011-06-11 00:02:12 +04:00
set_bit ( CONF_CONNECT_PEND , & chan - > conf_state ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
2010-11-03 13:32:44 +03:00
/* don't delete l2cap channel if sk is owned by user */
if ( sock_owned_by_user ( sk ) ) {
2011-06-03 07:19:47 +04:00
l2cap_state_change ( chan , BT_DISCONN ) ;
2011-05-17 21:59:01 +04:00
__clear_chan_timer ( chan ) ;
__set_chan_timer ( chan , HZ / 5 ) ;
2010-11-03 13:32:44 +03:00
break ;
}
2011-03-25 06:22:30 +03:00
l2cap_chan_del ( chan , ECONNREFUSED ) ;
2005-04-17 02:20:36 +04:00
break ;
}
bh_unlock_sock ( sk ) ;
return 0 ;
}
2011-04-13 22:57:03 +04:00
static inline void set_default_fcs ( struct l2cap_chan * chan )
2010-08-25 02:35:42 +04:00
{
/* FCS is enabled only in ERTM or streaming mode, if one or both
* sides request it .
*/
2011-04-14 00:20:49 +04:00
if ( chan - > mode ! = L2CAP_MODE_ERTM & & chan - > mode ! = L2CAP_MODE_STREAMING )
2011-04-13 22:57:03 +04:00
chan - > fcs = L2CAP_FCS_NONE ;
2011-06-11 00:02:12 +04:00
else if ( ! test_bit ( CONF_NO_FCS_RECV , & chan - > conf_state ) )
2011-04-13 22:57:03 +04:00
chan - > fcs = L2CAP_FCS_CRC16 ;
2010-08-25 02:35:42 +04:00
}
2007-07-29 11:17:25 +04:00
static inline int l2cap_config_req ( struct l2cap_conn * conn , struct l2cap_cmd_hdr * cmd , u16 cmd_len , u8 * data )
2005-04-17 02:20:36 +04:00
{
struct l2cap_conf_req * req = ( struct l2cap_conf_req * ) data ;
u16 dcid , flags ;
u8 rsp [ 64 ] ;
2011-03-25 06:22:30 +03:00
struct l2cap_chan * chan ;
2005-04-17 02:20:36 +04:00
struct sock * sk ;
2007-05-24 16:27:19 +04:00
int len ;
2005-04-17 02:20:36 +04:00
dcid = __le16_to_cpu ( req - > dcid ) ;
flags = __le16_to_cpu ( req - > flags ) ;
BT_DBG ( " dcid 0x%4.4x flags 0x%2.2x " , dcid , flags ) ;
2011-03-31 23:17:41 +04:00
chan = l2cap_get_chan_by_scid ( conn , dcid ) ;
2011-03-25 06:22:30 +03:00
if ( ! chan )
2005-04-17 02:20:36 +04:00
return - ENOENT ;
2011-03-25 06:22:30 +03:00
sk = chan - > sk ;
2011-07-22 00:38:42 +04:00
if ( chan - > state ! = BT_CONFIG & & chan - > state ! = BT_CONNECT2 ) {
2011-07-10 09:47:44 +04:00
struct l2cap_cmd_rej_cid rej ;
rej . reason = cpu_to_le16 ( L2CAP_REJ_INVALID_CID ) ;
rej . scid = cpu_to_le16 ( chan - > scid ) ;
rej . dcid = cpu_to_le16 ( chan - > dcid ) ;
2010-06-14 09:26:15 +04:00
l2cap_send_cmd ( conn , cmd - > ident , L2CAP_COMMAND_REJ ,
sizeof ( rej ) , & rej ) ;
2006-11-19 00:15:20 +03:00
goto unlock ;
2010-06-14 09:26:15 +04:00
}
2006-11-19 00:15:20 +03:00
2007-05-24 16:27:19 +04:00
/* Reject if config buffer is too small. */
2007-07-29 11:17:25 +04:00
len = cmd_len - sizeof ( * req ) ;
2011-06-24 16:38:05 +04:00
if ( len < 0 | | chan - > conf_len + len > sizeof ( chan - > conf_req ) ) {
2007-05-24 16:27:19 +04:00
l2cap_send_cmd ( conn , cmd - > ident , L2CAP_CONF_RSP ,
2011-04-14 02:50:45 +04:00
l2cap_build_conf_rsp ( chan , rsp ,
2007-05-24 16:27:19 +04:00
L2CAP_CONF_REJECT , flags ) , rsp ) ;
goto unlock ;
}
/* Store config. */
2011-03-25 20:16:54 +03:00
memcpy ( chan - > conf_req + chan - > conf_len , req - > data , len ) ;
chan - > conf_len + = len ;
2005-04-17 02:20:36 +04:00
if ( flags & 0x0001 ) {
/* Incomplete config. Send empty response. */
l2cap_send_cmd ( conn , cmd - > ident , L2CAP_CONF_RSP ,
2011-04-14 02:50:45 +04:00
l2cap_build_conf_rsp ( chan , rsp ,
2007-05-24 16:27:19 +04:00
L2CAP_CONF_SUCCESS , 0x0001 ) , rsp ) ;
2005-04-17 02:20:36 +04:00
goto unlock ;
}
/* Complete config. */
2011-03-25 20:16:54 +03:00
len = l2cap_parse_conf_req ( chan , rsp ) ;
2009-07-04 22:06:24 +04:00
if ( len < 0 ) {
2011-04-01 07:53:45 +04:00
l2cap_send_disconn_req ( conn , chan , ECONNRESET ) ;
2005-04-17 02:20:36 +04:00
goto unlock ;
2009-07-04 22:06:24 +04:00
}
2005-04-17 02:20:36 +04:00
2007-05-24 16:27:19 +04:00
l2cap_send_cmd ( conn , cmd - > ident , L2CAP_CONF_RSP , len , rsp ) ;
2011-03-25 20:16:54 +03:00
chan - > num_conf_rsp + + ;
2007-05-24 16:27:19 +04:00
/* Reset config buffer. */
2011-03-25 20:16:54 +03:00
chan - > conf_len = 0 ;
2007-05-24 16:27:19 +04:00
2011-06-11 00:02:12 +04:00
if ( ! test_bit ( CONF_OUTPUT_DONE , & chan - > conf_state ) )
2007-10-20 15:35:42 +04:00
goto unlock ;
2011-06-11 00:02:12 +04:00
if ( test_bit ( CONF_INPUT_DONE , & chan - > conf_state ) ) {
2011-04-13 22:57:03 +04:00
set_default_fcs ( chan ) ;
2009-08-21 05:26:02 +04:00
2011-06-03 07:19:47 +04:00
l2cap_state_change ( chan , BT_CONNECTED ) ;
2009-08-21 05:26:00 +04:00
2011-03-26 01:58:34 +03:00
chan - > next_tx_seq = 0 ;
chan - > expected_tx_seq = 0 ;
2011-04-04 23:16:44 +04:00
skb_queue_head_init ( & chan - > tx_q ) ;
2011-04-14 00:20:49 +04:00
if ( chan - > mode = = L2CAP_MODE_ERTM )
2011-03-26 01:43:39 +03:00
l2cap_ertm_init ( chan ) ;
2009-10-03 09:34:36 +04:00
2005-04-17 02:20:36 +04:00
l2cap_chan_ready ( sk ) ;
2007-10-20 15:35:42 +04:00
goto unlock ;
}
2011-06-11 00:02:12 +04:00
if ( ! test_and_set_bit ( CONF_REQ_SENT , & chan - > conf_state ) ) {
2008-07-14 22:13:44 +04:00
u8 buf [ 64 ] ;
2005-04-17 02:20:36 +04:00
l2cap_send_cmd ( conn , l2cap_get_ident ( conn ) , L2CAP_CONF_REQ ,
2011-03-25 20:16:54 +03:00
l2cap_build_conf_req ( chan , buf ) , buf ) ;
chan - > num_conf_req + + ;
2005-04-17 02:20:36 +04:00
}
unlock :
bh_unlock_sock ( sk ) ;
return 0 ;
}
static inline int l2cap_config_rsp ( struct l2cap_conn * conn , struct l2cap_cmd_hdr * cmd , u8 * data )
{
struct l2cap_conf_rsp * rsp = ( struct l2cap_conf_rsp * ) data ;
u16 scid , flags , result ;
2011-03-25 06:22:30 +03:00
struct l2cap_chan * chan ;
2005-04-17 02:20:36 +04:00
struct sock * sk ;
2010-05-01 23:15:39 +04:00
int len = cmd - > len - sizeof ( * rsp ) ;
2005-04-17 02:20:36 +04:00
scid = __le16_to_cpu ( rsp - > scid ) ;
flags = __le16_to_cpu ( rsp - > flags ) ;
result = __le16_to_cpu ( rsp - > result ) ;
2009-04-20 08:31:08 +04:00
BT_DBG ( " scid 0x%4.4x flags 0x%2.2x result 0x%2.2x " ,
scid , flags , result ) ;
2005-04-17 02:20:36 +04:00
2011-03-31 23:17:41 +04:00
chan = l2cap_get_chan_by_scid ( conn , scid ) ;
2011-03-25 06:22:30 +03:00
if ( ! chan )
2005-04-17 02:20:36 +04:00
return 0 ;
2011-03-25 06:22:30 +03:00
sk = chan - > sk ;
2005-04-17 02:20:36 +04:00
switch ( result ) {
case L2CAP_CONF_SUCCESS :
2011-04-13 22:57:03 +04:00
l2cap_conf_rfc_get ( chan , rsp - > data , len ) ;
2005-04-17 02:20:36 +04:00
break ;
case L2CAP_CONF_UNACCEPT :
2011-03-25 20:16:54 +03:00
if ( chan - > num_conf_rsp < = L2CAP_CONF_MAX_CONF_RSP ) {
2009-07-04 22:06:24 +04:00
char req [ 64 ] ;
2010-03-19 11:26:28 +03:00
if ( len > sizeof ( req ) - sizeof ( struct l2cap_conf_req ) ) {
2011-04-01 07:53:45 +04:00
l2cap_send_disconn_req ( conn , chan , ECONNRESET ) ;
2010-03-19 11:26:28 +03:00
goto done ;
}
2009-07-04 22:06:24 +04:00
/* throw out any old stored conf requests */
result = L2CAP_CONF_SUCCESS ;
2011-04-13 01:15:09 +04:00
len = l2cap_parse_conf_rsp ( chan , rsp - > data , len ,
req , & result ) ;
2009-07-04 22:06:24 +04:00
if ( len < 0 ) {
2011-04-01 07:53:45 +04:00
l2cap_send_disconn_req ( conn , chan , ECONNRESET ) ;
2009-07-04 22:06:24 +04:00
goto done ;
}
l2cap_send_cmd ( conn , l2cap_get_ident ( conn ) ,
L2CAP_CONF_REQ , len , req ) ;
2011-03-25 20:16:54 +03:00
chan - > num_conf_req + + ;
2009-07-04 22:06:24 +04:00
if ( result ! = L2CAP_CONF_SUCCESS )
goto done ;
break ;
2005-04-17 02:20:36 +04:00
}
2007-02-09 17:24:33 +03:00
default :
2008-07-14 22:13:54 +04:00
sk - > sk_err = ECONNRESET ;
2011-05-17 21:59:01 +04:00
__set_chan_timer ( chan , HZ * 5 ) ;
2011-04-01 07:53:45 +04:00
l2cap_send_disconn_req ( conn , chan , ECONNRESET ) ;
2005-04-17 02:20:36 +04:00
goto done ;
}
if ( flags & 0x01 )
goto done ;
2011-06-11 00:02:12 +04:00
set_bit ( CONF_INPUT_DONE , & chan - > conf_state ) ;
2005-04-17 02:20:36 +04:00
2011-06-11 00:02:12 +04:00
if ( test_bit ( CONF_OUTPUT_DONE , & chan - > conf_state ) ) {
2011-04-13 22:57:03 +04:00
set_default_fcs ( chan ) ;
2009-08-21 05:26:02 +04:00
2011-06-03 07:19:47 +04:00
l2cap_state_change ( chan , BT_CONNECTED ) ;
2011-03-26 01:58:34 +03:00
chan - > next_tx_seq = 0 ;
chan - > expected_tx_seq = 0 ;
2011-04-04 23:16:44 +04:00
skb_queue_head_init ( & chan - > tx_q ) ;
2011-04-14 00:20:49 +04:00
if ( chan - > mode = = L2CAP_MODE_ERTM )
2011-03-26 01:43:39 +03:00
l2cap_ertm_init ( chan ) ;
2009-10-03 09:34:36 +04:00
2005-04-17 02:20:36 +04:00
l2cap_chan_ready ( sk ) ;
}
done :
bh_unlock_sock ( sk ) ;
return 0 ;
}
static inline int l2cap_disconnect_req ( struct l2cap_conn * conn , struct l2cap_cmd_hdr * cmd , u8 * data )
{
struct l2cap_disconn_req * req = ( struct l2cap_disconn_req * ) data ;
struct l2cap_disconn_rsp rsp ;
u16 dcid , scid ;
2011-03-25 06:22:30 +03:00
struct l2cap_chan * chan ;
2005-04-17 02:20:36 +04:00
struct sock * sk ;
scid = __le16_to_cpu ( req - > scid ) ;
dcid = __le16_to_cpu ( req - > dcid ) ;
BT_DBG ( " scid 0x%4.4x dcid 0x%4.4x " , scid , dcid ) ;
2011-03-31 23:17:41 +04:00
chan = l2cap_get_chan_by_scid ( conn , dcid ) ;
2011-03-25 06:22:30 +03:00
if ( ! chan )
2005-04-17 02:20:36 +04:00
return 0 ;
2011-03-25 06:22:30 +03:00
sk = chan - > sk ;
2011-04-14 02:50:45 +04:00
rsp . dcid = cpu_to_le16 ( chan - > scid ) ;
rsp . scid = cpu_to_le16 ( chan - > dcid ) ;
2005-04-17 02:20:36 +04:00
l2cap_send_cmd ( conn , cmd - > ident , L2CAP_DISCONN_RSP , sizeof ( rsp ) , & rsp ) ;
sk - > sk_shutdown = SHUTDOWN_MASK ;
2010-11-03 13:32:44 +03:00
/* don't delete l2cap channel if sk is owned by user */
if ( sock_owned_by_user ( sk ) ) {
2011-06-03 07:19:47 +04:00
l2cap_state_change ( chan , BT_DISCONN ) ;
2011-05-17 21:59:01 +04:00
__clear_chan_timer ( chan ) ;
__set_chan_timer ( chan , HZ / 5 ) ;
2010-11-03 13:32:44 +03:00
bh_unlock_sock ( sk ) ;
return 0 ;
}
2011-03-25 06:22:30 +03:00
l2cap_chan_del ( chan , ECONNRESET ) ;
2005-04-17 02:20:36 +04:00
bh_unlock_sock ( sk ) ;
2011-05-17 01:23:24 +04:00
chan - > ops - > close ( chan - > data ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static inline int l2cap_disconnect_rsp ( struct l2cap_conn * conn , struct l2cap_cmd_hdr * cmd , u8 * data )
{
struct l2cap_disconn_rsp * rsp = ( struct l2cap_disconn_rsp * ) data ;
u16 dcid , scid ;
2011-03-25 06:22:30 +03:00
struct l2cap_chan * chan ;
2005-04-17 02:20:36 +04:00
struct sock * sk ;
scid = __le16_to_cpu ( rsp - > scid ) ;
dcid = __le16_to_cpu ( rsp - > dcid ) ;
BT_DBG ( " dcid 0x%4.4x scid 0x%4.4x " , dcid , scid ) ;
2011-03-31 23:17:41 +04:00
chan = l2cap_get_chan_by_scid ( conn , scid ) ;
2011-03-25 06:22:30 +03:00
if ( ! chan )
2005-04-17 02:20:36 +04:00
return 0 ;
2011-03-25 06:22:30 +03:00
sk = chan - > sk ;
2010-11-03 13:32:44 +03:00
/* don't delete l2cap channel if sk is owned by user */
if ( sock_owned_by_user ( sk ) ) {
2011-06-03 07:19:47 +04:00
l2cap_state_change ( chan , BT_DISCONN ) ;
2011-05-17 21:59:01 +04:00
__clear_chan_timer ( chan ) ;
__set_chan_timer ( chan , HZ / 5 ) ;
2010-11-03 13:32:44 +03:00
bh_unlock_sock ( sk ) ;
return 0 ;
}
2011-03-25 06:22:30 +03:00
l2cap_chan_del ( chan , 0 ) ;
2005-04-17 02:20:36 +04:00
bh_unlock_sock ( sk ) ;
2011-05-17 01:23:24 +04:00
chan - > ops - > close ( chan - > data ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static inline int l2cap_information_req ( struct l2cap_conn * conn , struct l2cap_cmd_hdr * cmd , u8 * data )
{
struct l2cap_info_req * req = ( struct l2cap_info_req * ) data ;
u16 type ;
type = __le16_to_cpu ( req - > type ) ;
BT_DBG ( " type 0x%4.4x " , type ) ;
2007-10-20 15:38:51 +04:00
if ( type = = L2CAP_IT_FEAT_MASK ) {
u8 buf [ 8 ] ;
2009-05-03 06:09:01 +04:00
u32 feat_mask = l2cap_feat_mask ;
2007-10-20 15:38:51 +04:00
struct l2cap_info_rsp * rsp = ( struct l2cap_info_rsp * ) buf ;
rsp - > type = cpu_to_le16 ( L2CAP_IT_FEAT_MASK ) ;
rsp - > result = cpu_to_le16 ( L2CAP_IR_SUCCESS ) ;
2010-07-18 23:25:54 +04:00
if ( ! disable_ertm )
2009-08-21 05:26:02 +04:00
feat_mask | = L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
| L2CAP_FEAT_FCS ;
2009-08-24 07:45:20 +04:00
put_unaligned_le32 ( feat_mask , rsp - > data ) ;
2007-10-20 15:38:51 +04:00
l2cap_send_cmd ( conn , cmd - > ident ,
L2CAP_INFO_RSP , sizeof ( buf ) , buf ) ;
2009-02-09 11:18:02 +03:00
} else if ( type = = L2CAP_IT_FIXED_CHAN ) {
u8 buf [ 12 ] ;
struct l2cap_info_rsp * rsp = ( struct l2cap_info_rsp * ) buf ;
rsp - > type = cpu_to_le16 ( L2CAP_IT_FIXED_CHAN ) ;
rsp - > result = cpu_to_le16 ( L2CAP_IR_SUCCESS ) ;
memcpy ( buf + 4 , l2cap_fixed_chan , 8 ) ;
l2cap_send_cmd ( conn , cmd - > ident ,
L2CAP_INFO_RSP , sizeof ( buf ) , buf ) ;
2007-10-20 15:38:51 +04:00
} else {
struct l2cap_info_rsp rsp ;
rsp . type = cpu_to_le16 ( type ) ;
rsp . result = cpu_to_le16 ( L2CAP_IR_NOTSUPP ) ;
l2cap_send_cmd ( conn , cmd - > ident ,
L2CAP_INFO_RSP , sizeof ( rsp ) , & rsp ) ;
}
2005-04-17 02:20:36 +04:00
return 0 ;
}
static inline int l2cap_information_rsp ( struct l2cap_conn * conn , struct l2cap_cmd_hdr * cmd , u8 * data )
{
struct l2cap_info_rsp * rsp = ( struct l2cap_info_rsp * ) data ;
u16 type , result ;
type = __le16_to_cpu ( rsp - > type ) ;
result = __le16_to_cpu ( rsp - > result ) ;
BT_DBG ( " type 0x%4.4x result 0x%2.2x " , type , result ) ;
2011-03-25 12:31:41 +03:00
/* L2CAP Info req/rsp are unbound to channels, add extra checks */
if ( cmd - > ident ! = conn - > info_ident | |
conn - > info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE )
return 0 ;
2007-10-20 15:37:56 +04:00
del_timer ( & conn - > info_timer ) ;
2010-08-04 10:43:33 +04:00
if ( result ! = L2CAP_IR_SUCCESS ) {
conn - > info_state | = L2CAP_INFO_FEAT_MASK_REQ_DONE ;
conn - > info_ident = 0 ;
l2cap_conn_start ( conn ) ;
return 0 ;
}
2009-02-07 01:35:19 +03:00
if ( type = = L2CAP_IT_FEAT_MASK ) {
2008-05-03 03:25:46 +04:00
conn - > feat_mask = get_unaligned_le32 ( rsp - > data ) ;
2007-10-20 15:37:56 +04:00
2009-05-03 05:57:55 +04:00
if ( conn - > feat_mask & L2CAP_FEAT_FIXED_CHAN ) {
2009-02-09 11:18:02 +03:00
struct l2cap_info_req req ;
req . type = cpu_to_le16 ( L2CAP_IT_FIXED_CHAN ) ;
conn - > info_ident = l2cap_get_ident ( conn ) ;
l2cap_send_cmd ( conn , conn - > info_ident ,
L2CAP_INFO_REQ , sizeof ( req ) , & req ) ;
} else {
conn - > info_state | = L2CAP_INFO_FEAT_MASK_REQ_DONE ;
conn - > info_ident = 0 ;
l2cap_conn_start ( conn ) ;
}
} else if ( type = = L2CAP_IT_FIXED_CHAN ) {
2009-02-07 01:35:19 +03:00
conn - > info_state | = L2CAP_INFO_FEAT_MASK_REQ_DONE ;
2009-02-09 11:18:02 +03:00
conn - > info_ident = 0 ;
2009-02-07 01:35:19 +03:00
l2cap_conn_start ( conn ) ;
}
2007-10-20 15:37:56 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
2011-02-18 01:16:55 +03:00
static inline int l2cap_check_conn_param ( u16 min , u16 max , u16 latency ,
2011-02-12 00:28:55 +03:00
u16 to_multiplier )
{
u16 max_latency ;
if ( min > max | | min < 6 | | max > 3200 )
return - EINVAL ;
if ( to_multiplier < 10 | | to_multiplier > 3200 )
return - EINVAL ;
if ( max > = to_multiplier * 8 )
return - EINVAL ;
max_latency = ( to_multiplier * 8 / max ) - 1 ;
if ( latency > 499 | | latency > max_latency )
return - EINVAL ;
return 0 ;
}
static inline int l2cap_conn_param_update_req ( struct l2cap_conn * conn ,
struct l2cap_cmd_hdr * cmd , u8 * data )
{
struct hci_conn * hcon = conn - > hcon ;
struct l2cap_conn_param_update_req * req ;
struct l2cap_conn_param_update_rsp rsp ;
u16 min , max , latency , to_multiplier , cmd_len ;
2011-02-17 01:44:53 +03:00
int err ;
2011-02-12 00:28:55 +03:00
if ( ! ( hcon - > link_mode & HCI_LM_MASTER ) )
return - EINVAL ;
cmd_len = __le16_to_cpu ( cmd - > len ) ;
if ( cmd_len ! = sizeof ( struct l2cap_conn_param_update_req ) )
return - EPROTO ;
req = ( struct l2cap_conn_param_update_req * ) data ;
2011-02-18 01:16:55 +03:00
min = __le16_to_cpu ( req - > min ) ;
max = __le16_to_cpu ( req - > max ) ;
2011-02-12 00:28:55 +03:00
latency = __le16_to_cpu ( req - > latency ) ;
to_multiplier = __le16_to_cpu ( req - > to_multiplier ) ;
BT_DBG ( " min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x " ,
min , max , latency , to_multiplier ) ;
memset ( & rsp , 0 , sizeof ( rsp ) ) ;
2011-02-17 01:44:53 +03:00
err = l2cap_check_conn_param ( min , max , latency , to_multiplier ) ;
if ( err )
2011-02-12 00:28:55 +03:00
rsp . result = cpu_to_le16 ( L2CAP_CONN_PARAM_REJECTED ) ;
else
rsp . result = cpu_to_le16 ( L2CAP_CONN_PARAM_ACCEPTED ) ;
l2cap_send_cmd ( conn , cmd - > ident , L2CAP_CONN_PARAM_UPDATE_RSP ,
sizeof ( rsp ) , & rsp ) ;
2011-02-17 01:44:53 +03:00
if ( ! err )
hci_le_conn_update ( hcon , min , max , latency , to_multiplier ) ;
2011-02-12 00:28:55 +03:00
return 0 ;
}
2011-02-12 00:28:54 +03:00
static inline int l2cap_bredr_sig_cmd ( struct l2cap_conn * conn ,
struct l2cap_cmd_hdr * cmd , u16 cmd_len , u8 * data )
{
int err = 0 ;
switch ( cmd - > code ) {
case L2CAP_COMMAND_REJ :
l2cap_command_rej ( conn , cmd , data ) ;
break ;
case L2CAP_CONN_REQ :
err = l2cap_connect_req ( conn , cmd , data ) ;
break ;
case L2CAP_CONN_RSP :
err = l2cap_connect_rsp ( conn , cmd , data ) ;
break ;
case L2CAP_CONF_REQ :
err = l2cap_config_req ( conn , cmd , cmd_len , data ) ;
break ;
case L2CAP_CONF_RSP :
err = l2cap_config_rsp ( conn , cmd , data ) ;
break ;
case L2CAP_DISCONN_REQ :
err = l2cap_disconnect_req ( conn , cmd , data ) ;
break ;
case L2CAP_DISCONN_RSP :
err = l2cap_disconnect_rsp ( conn , cmd , data ) ;
break ;
case L2CAP_ECHO_REQ :
l2cap_send_cmd ( conn , cmd - > ident , L2CAP_ECHO_RSP , cmd_len , data ) ;
break ;
case L2CAP_ECHO_RSP :
break ;
case L2CAP_INFO_REQ :
err = l2cap_information_req ( conn , cmd , data ) ;
break ;
case L2CAP_INFO_RSP :
err = l2cap_information_rsp ( conn , cmd , data ) ;
break ;
default :
BT_ERR ( " Unknown BR/EDR signaling command 0x%2.2x " , cmd - > code ) ;
err = - EINVAL ;
break ;
}
return err ;
}
static inline int l2cap_le_sig_cmd ( struct l2cap_conn * conn ,
struct l2cap_cmd_hdr * cmd , u8 * data )
{
switch ( cmd - > code ) {
case L2CAP_COMMAND_REJ :
return 0 ;
case L2CAP_CONN_PARAM_UPDATE_REQ :
2011-02-12 00:28:55 +03:00
return l2cap_conn_param_update_req ( conn , cmd , data ) ;
2011-02-12 00:28:54 +03:00
case L2CAP_CONN_PARAM_UPDATE_RSP :
return 0 ;
default :
BT_ERR ( " Unknown LE signaling command 0x%2.2x " , cmd - > code ) ;
return - EINVAL ;
}
}
static inline void l2cap_sig_channel ( struct l2cap_conn * conn ,
struct sk_buff * skb )
2005-04-17 02:20:36 +04:00
{
u8 * data = skb - > data ;
int len = skb - > len ;
struct l2cap_cmd_hdr cmd ;
2011-02-12 00:28:54 +03:00
int err ;
2005-04-17 02:20:36 +04:00
l2cap_raw_recv ( conn , skb ) ;
while ( len > = L2CAP_CMD_HDR_SIZE ) {
2007-07-29 11:17:25 +04:00
u16 cmd_len ;
2005-04-17 02:20:36 +04:00
memcpy ( & cmd , data , L2CAP_CMD_HDR_SIZE ) ;
data + = L2CAP_CMD_HDR_SIZE ;
len - = L2CAP_CMD_HDR_SIZE ;
2007-07-29 11:17:25 +04:00
cmd_len = le16_to_cpu ( cmd . len ) ;
2005-04-17 02:20:36 +04:00
2007-07-29 11:17:25 +04:00
BT_DBG ( " code 0x%2.2x len %d id 0x%2.2x " , cmd . code , cmd_len , cmd . ident ) ;
2005-04-17 02:20:36 +04:00
2007-07-29 11:17:25 +04:00
if ( cmd_len > len | | ! cmd . ident ) {
2005-04-17 02:20:36 +04:00
BT_DBG ( " corrupted command " ) ;
break ;
}
2011-02-12 00:28:54 +03:00
if ( conn - > hcon - > type = = LE_LINK )
err = l2cap_le_sig_cmd ( conn , & cmd , data ) ;
else
err = l2cap_bredr_sig_cmd ( conn , & cmd , cmd_len , data ) ;
2005-04-17 02:20:36 +04:00
if ( err ) {
2011-07-10 09:47:44 +04:00
struct l2cap_cmd_rej_unk rej ;
2011-03-23 20:38:32 +03:00
BT_ERR ( " Wrong link type (%d) " , err ) ;
2005-04-17 02:20:36 +04:00
/* FIXME: Map err to a valid reason */
2011-07-10 09:47:44 +04:00
rej . reason = cpu_to_le16 ( L2CAP_REJ_NOT_UNDERSTOOD ) ;
2005-04-17 02:20:36 +04:00
l2cap_send_cmd ( conn , cmd . ident , L2CAP_COMMAND_REJ , sizeof ( rej ) , & rej ) ;
}
2007-07-29 11:17:25 +04:00
data + = cmd_len ;
len - = cmd_len ;
2005-04-17 02:20:36 +04:00
}
kfree_skb ( skb ) ;
}
2011-04-13 22:57:03 +04:00
static int l2cap_check_fcs ( struct l2cap_chan * chan , struct sk_buff * skb )
2009-08-21 05:26:02 +04:00
{
u16 our_fcs , rcv_fcs ;
int hdr_size = L2CAP_HDR_SIZE + 2 ;
2011-04-13 22:57:03 +04:00
if ( chan - > fcs = = L2CAP_FCS_CRC16 ) {
2009-08-21 05:26:02 +04:00
skb_trim ( skb , skb - > len - 2 ) ;
rcv_fcs = get_unaligned_le16 ( skb - > data + skb - > len ) ;
our_fcs = crc16 ( 0 , skb - > data - hdr_size , skb - > len + hdr_size ) ;
if ( our_fcs ! = rcv_fcs )
2010-06-22 20:56:27 +04:00
return - EBADMSG ;
2009-08-21 05:26:02 +04:00
}
return 0 ;
}
2011-03-26 01:43:39 +03:00
static inline void l2cap_send_i_or_rr_or_rnr ( struct l2cap_chan * chan )
2010-05-01 23:15:36 +04:00
{
u16 control = 0 ;
2011-04-01 07:38:50 +04:00
chan - > frames_sent = 0 ;
2010-05-01 23:15:36 +04:00
2011-03-26 01:58:34 +03:00
control | = chan - > buffer_seq < < L2CAP_CTRL_REQSEQ_SHIFT ;
2010-05-01 23:15:36 +04:00
2011-06-11 04:28:49 +04:00
if ( test_bit ( CONN_LOCAL_BUSY , & chan - > conn_state ) ) {
2010-05-10 21:54:14 +04:00
control | = L2CAP_SUPER_RCV_NOT_READY ;
2011-03-26 01:43:39 +03:00
l2cap_send_sframe ( chan , control ) ;
2011-06-11 04:28:49 +04:00
set_bit ( CONN_RNR_SENT , & chan - > conn_state ) ;
2010-05-01 23:15:36 +04:00
}
2011-06-11 04:28:49 +04:00
if ( test_bit ( CONN_REMOTE_BUSY , & chan - > conn_state ) )
2011-03-26 01:43:39 +03:00
l2cap_retransmit_frames ( chan ) ;
2010-05-01 23:15:36 +04:00
2011-03-26 01:43:39 +03:00
l2cap_ertm_send ( chan ) ;
2010-05-01 23:15:36 +04:00
2011-06-11 04:28:49 +04:00
if ( ! test_bit ( CONN_LOCAL_BUSY , & chan - > conn_state ) & &
2011-04-01 07:38:50 +04:00
chan - > frames_sent = = 0 ) {
2010-05-01 23:15:36 +04:00
control | = L2CAP_SUPER_RCV_READY ;
2011-03-26 01:43:39 +03:00
l2cap_send_sframe ( chan , control ) ;
2010-05-01 23:15:36 +04:00
}
}
2011-03-26 01:58:34 +03:00
static int l2cap_add_to_srej_queue ( struct l2cap_chan * chan , struct sk_buff * skb , u8 tx_seq , u8 sar )
2009-08-21 05:26:03 +04:00
{
struct sk_buff * next_skb ;
2010-06-01 01:35:44 +04:00
int tx_seq_offset , next_tx_seq_offset ;
2009-08-21 05:26:03 +04:00
bt_cb ( skb ) - > tx_seq = tx_seq ;
bt_cb ( skb ) - > sar = sar ;
2011-03-26 02:36:10 +03:00
next_skb = skb_peek ( & chan - > srej_q ) ;
2009-08-21 05:26:03 +04:00
if ( ! next_skb ) {
2011-03-26 02:36:10 +03:00
__skb_queue_tail ( & chan - > srej_q , skb ) ;
2010-05-01 23:15:44 +04:00
return 0 ;
2009-08-21 05:26:03 +04:00
}
2011-03-26 01:58:34 +03:00
tx_seq_offset = ( tx_seq - chan - > buffer_seq ) % 64 ;
2010-06-01 01:35:44 +04:00
if ( tx_seq_offset < 0 )
tx_seq_offset + = 64 ;
2009-08-21 05:26:03 +04:00
do {
2010-05-01 23:15:44 +04:00
if ( bt_cb ( next_skb ) - > tx_seq = = tx_seq )
return - EINVAL ;
2010-06-01 01:35:44 +04:00
next_tx_seq_offset = ( bt_cb ( next_skb ) - > tx_seq -
2011-03-26 01:58:34 +03:00
chan - > buffer_seq ) % 64 ;
2010-06-01 01:35:44 +04:00
if ( next_tx_seq_offset < 0 )
next_tx_seq_offset + = 64 ;
if ( next_tx_seq_offset > tx_seq_offset ) {
2011-03-26 02:36:10 +03:00
__skb_queue_before ( & chan - > srej_q , next_skb , skb ) ;
2010-05-01 23:15:44 +04:00
return 0 ;
2009-08-21 05:26:03 +04:00
}
2011-03-26 02:36:10 +03:00
if ( skb_queue_is_last ( & chan - > srej_q , next_skb ) )
2009-08-21 05:26:03 +04:00
break ;
2011-03-26 02:36:10 +03:00
} while ( ( next_skb = skb_queue_next ( & chan - > srej_q , next_skb ) ) ) ;
2009-08-21 05:26:03 +04:00
2011-03-26 02:36:10 +03:00
__skb_queue_tail ( & chan - > srej_q , skb ) ;
2010-05-01 23:15:44 +04:00
return 0 ;
2009-08-21 05:26:03 +04:00
}
2011-03-26 01:43:39 +03:00
static int l2cap_ertm_reassembly_sdu ( struct l2cap_chan * chan , struct sk_buff * skb , u16 control )
2010-05-01 23:15:44 +04:00
{
struct sk_buff * _skb ;
2010-05-01 23:15:44 +04:00
int err ;
2010-05-01 23:15:44 +04:00
switch ( control & L2CAP_CTRL_SAR ) {
case L2CAP_SDU_UNSEGMENTED :
2011-06-11 04:28:49 +04:00
if ( test_bit ( CONN_SAR_SDU , & chan - > conn_state ) )
2010-05-01 23:15:44 +04:00
goto drop ;
2011-05-17 00:57:22 +04:00
return chan - > ops - > recv ( chan - > data , skb ) ;
2010-05-01 23:15:44 +04:00
case L2CAP_SDU_START :
2011-06-11 04:28:49 +04:00
if ( test_bit ( CONN_SAR_SDU , & chan - > conn_state ) )
2010-05-01 23:15:44 +04:00
goto drop ;
2011-03-26 02:09:37 +03:00
chan - > sdu_len = get_unaligned_le16 ( skb - > data ) ;
2010-05-01 23:15:44 +04:00
2011-04-14 00:20:49 +04:00
if ( chan - > sdu_len > chan - > imtu )
2010-05-01 23:15:44 +04:00
goto disconnect ;
2011-03-26 02:09:37 +03:00
chan - > sdu = bt_skb_alloc ( chan - > sdu_len , GFP_ATOMIC ) ;
if ( ! chan - > sdu )
2010-05-01 23:15:44 +04:00
return - ENOMEM ;
/* pull sdu_len bytes only after alloc, because of Local Busy
* condition we have to be sure that this will be executed
* only once , i . e . , when alloc does not fail */
skb_pull ( skb , 2 ) ;
2010-05-01 23:15:44 +04:00
2011-03-26 02:09:37 +03:00
memcpy ( skb_put ( chan - > sdu , skb - > len ) , skb - > data , skb - > len ) ;
2010-05-01 23:15:44 +04:00
2011-06-11 04:28:49 +04:00
set_bit ( CONN_SAR_SDU , & chan - > conn_state ) ;
2011-03-26 02:09:37 +03:00
chan - > partial_sdu_len = skb - > len ;
2010-05-01 23:15:44 +04:00
break ;
case L2CAP_SDU_CONTINUE :
2011-06-11 04:28:49 +04:00
if ( ! test_bit ( CONN_SAR_SDU , & chan - > conn_state ) )
2010-05-01 23:15:44 +04:00
goto disconnect ;
2011-03-26 02:09:37 +03:00
if ( ! chan - > sdu )
2010-05-01 23:15:44 +04:00
goto disconnect ;
2011-03-26 02:09:37 +03:00
chan - > partial_sdu_len + = skb - > len ;
if ( chan - > partial_sdu_len > chan - > sdu_len )
2010-05-01 23:15:44 +04:00
goto drop ;
2011-03-26 02:09:37 +03:00
memcpy ( skb_put ( chan - > sdu , skb - > len ) , skb - > data , skb - > len ) ;
2010-05-01 23:15:45 +04:00
2010-05-01 23:15:44 +04:00
break ;
case L2CAP_SDU_END :
2011-06-11 04:28:49 +04:00
if ( ! test_bit ( CONN_SAR_SDU , & chan - > conn_state ) )
2010-05-01 23:15:44 +04:00
goto disconnect ;
2011-03-26 02:09:37 +03:00
if ( ! chan - > sdu )
2010-05-01 23:15:44 +04:00
goto disconnect ;
2011-07-07 20:39:03 +04:00
chan - > partial_sdu_len + = skb - > len ;
2010-05-01 23:15:44 +04:00
2011-07-07 20:39:03 +04:00
if ( chan - > partial_sdu_len > chan - > imtu )
goto drop ;
2010-05-01 23:15:44 +04:00
2011-07-07 20:39:03 +04:00
if ( chan - > partial_sdu_len ! = chan - > sdu_len )
goto drop ;
2010-05-01 23:15:45 +04:00
2011-07-07 20:39:03 +04:00
memcpy ( skb_put ( chan - > sdu , skb - > len ) , skb - > data , skb - > len ) ;
2010-05-01 23:15:44 +04:00
2011-03-26 02:09:37 +03:00
_skb = skb_clone ( chan - > sdu , GFP_ATOMIC ) ;
2010-05-01 23:15:44 +04:00
if ( ! _skb ) {
return - ENOMEM ;
}
2011-05-17 00:57:22 +04:00
err = chan - > ops - > recv ( chan - > data , _skb ) ;
2010-05-01 23:15:44 +04:00
if ( err < 0 ) {
2010-05-01 23:15:44 +04:00
kfree_skb ( _skb ) ;
2010-05-01 23:15:44 +04:00
return err ;
}
2011-06-11 04:28:49 +04:00
clear_bit ( CONN_SAR_SDU , & chan - > conn_state ) ;
2010-05-01 23:15:44 +04:00
2011-03-26 02:09:37 +03:00
kfree_skb ( chan - > sdu ) ;
2010-05-01 23:15:44 +04:00
break ;
}
kfree_skb ( skb ) ;
2010-05-01 23:15:44 +04:00
return 0 ;
2010-05-01 23:15:44 +04:00
drop :
2011-03-26 02:09:37 +03:00
kfree_skb ( chan - > sdu ) ;
chan - > sdu = NULL ;
2010-05-01 23:15:44 +04:00
disconnect :
2011-04-14 03:23:55 +04:00
l2cap_send_disconn_req ( chan - > conn , chan , ECONNRESET ) ;
2010-05-01 23:15:44 +04:00
kfree_skb ( skb ) ;
return 0 ;
}
2011-07-07 20:39:01 +04:00
static void l2cap_ertm_enter_local_busy ( struct l2cap_chan * chan )
2010-06-22 02:39:50 +04:00
{
u16 control ;
2011-07-07 20:39:01 +04:00
BT_DBG ( " chan %p, Enter local busy " , chan ) ;
2010-06-22 02:39:50 +04:00
2011-07-07 20:39:01 +04:00
set_bit ( CONN_LOCAL_BUSY , & chan - > conn_state ) ;
control = chan - > buffer_seq < < L2CAP_CTRL_REQSEQ_SHIFT ;
control | = L2CAP_SUPER_RCV_NOT_READY ;
l2cap_send_sframe ( chan , control ) ;
set_bit ( CONN_RNR_SENT , & chan - > conn_state ) ;
__clear_ack_timer ( chan ) ;
}
static void l2cap_ertm_exit_local_busy ( struct l2cap_chan * chan )
{
u16 control ;
2010-06-22 02:39:50 +04:00
2011-06-11 04:28:49 +04:00
if ( ! test_bit ( CONN_RNR_SENT , & chan - > conn_state ) )
2010-06-22 02:39:50 +04:00
goto done ;
2011-03-26 01:58:34 +03:00
control = chan - > buffer_seq < < L2CAP_CTRL_REQSEQ_SHIFT ;
2010-06-22 02:39:50 +04:00
control | = L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL ;
2011-03-26 01:43:39 +03:00
l2cap_send_sframe ( chan , control ) ;
2011-04-01 07:38:50 +04:00
chan - > retry_count = 1 ;
2010-06-22 02:39:50 +04:00
2011-05-17 22:13:19 +04:00
__clear_retrans_timer ( chan ) ;
__set_monitor_timer ( chan ) ;
2010-06-22 02:39:50 +04:00
2011-06-11 04:28:49 +04:00
set_bit ( CONN_WAIT_F , & chan - > conn_state ) ;
2010-06-22 02:39:50 +04:00
done :
2011-06-11 04:28:49 +04:00
clear_bit ( CONN_LOCAL_BUSY , & chan - > conn_state ) ;
clear_bit ( CONN_RNR_SENT , & chan - > conn_state ) ;
2010-06-22 02:39:50 +04:00
2011-04-04 22:59:54 +04:00
BT_DBG ( " chan %p, Exit local busy " , chan ) ;
2010-06-22 02:39:50 +04:00
}
2011-07-07 20:39:02 +04:00
void l2cap_chan_busy ( struct l2cap_chan * chan , int busy )
2010-05-01 23:15:44 +04:00
{
2011-07-07 20:39:02 +04:00
if ( chan - > mode = = L2CAP_MODE_ERTM ) {
if ( busy )
l2cap_ertm_enter_local_busy ( chan ) ;
else
l2cap_ertm_exit_local_busy ( chan ) ;
2010-05-01 23:15:44 +04:00
}
}
2011-03-26 01:43:39 +03:00
static int l2cap_streaming_reassembly_sdu ( struct l2cap_chan * chan , struct sk_buff * skb , u16 control )
2009-08-21 05:25:58 +04:00
{
struct sk_buff * _skb ;
int err = - EINVAL ;
2010-05-01 23:15:44 +04:00
/*
* TODO : We have to notify the userland if some data is lost with the
* Streaming Mode .
*/
2009-08-21 05:25:58 +04:00
switch ( control & L2CAP_CTRL_SAR ) {
case L2CAP_SDU_UNSEGMENTED :
2011-06-11 04:28:49 +04:00
if ( test_bit ( CONN_SAR_SDU , & chan - > conn_state ) ) {
2011-03-26 02:09:37 +03:00
kfree_skb ( chan - > sdu ) ;
2009-08-21 05:25:58 +04:00
break ;
}
2011-05-17 00:57:22 +04:00
err = chan - > ops - > recv ( chan - > data , skb ) ;
2009-08-21 05:25:58 +04:00
if ( ! err )
return 0 ;
break ;
case L2CAP_SDU_START :
2011-06-11 04:28:49 +04:00
if ( test_bit ( CONN_SAR_SDU , & chan - > conn_state ) ) {
2011-03-26 02:09:37 +03:00
kfree_skb ( chan - > sdu ) ;
2009-08-21 05:25:58 +04:00
break ;
}
2011-03-26 02:09:37 +03:00
chan - > sdu_len = get_unaligned_le16 ( skb - > data ) ;
2009-08-21 05:25:58 +04:00
skb_pull ( skb , 2 ) ;
2011-04-14 00:20:49 +04:00
if ( chan - > sdu_len > chan - > imtu ) {
2010-05-01 23:15:40 +04:00
err = - EMSGSIZE ;
break ;
}
2011-03-26 02:09:37 +03:00
chan - > sdu = bt_skb_alloc ( chan - > sdu_len , GFP_ATOMIC ) ;
if ( ! chan - > sdu ) {
2009-08-21 05:25:58 +04:00
err = - ENOMEM ;
break ;
}
2011-03-26 02:09:37 +03:00
memcpy ( skb_put ( chan - > sdu , skb - > len ) , skb - > data , skb - > len ) ;
2009-08-21 05:25:58 +04:00
2011-06-11 04:28:49 +04:00
set_bit ( CONN_SAR_SDU , & chan - > conn_state ) ;
2011-03-26 02:09:37 +03:00
chan - > partial_sdu_len = skb - > len ;
2009-08-21 05:25:58 +04:00
err = 0 ;
break ;
case L2CAP_SDU_CONTINUE :
2011-06-11 04:28:49 +04:00
if ( ! test_bit ( CONN_SAR_SDU , & chan - > conn_state ) )
2009-08-21 05:25:58 +04:00
break ;
2011-03-26 02:09:37 +03:00
memcpy ( skb_put ( chan - > sdu , skb - > len ) , skb - > data , skb - > len ) ;
2009-08-21 05:25:58 +04:00
2011-03-26 02:09:37 +03:00
chan - > partial_sdu_len + = skb - > len ;
if ( chan - > partial_sdu_len > chan - > sdu_len )
kfree_skb ( chan - > sdu ) ;
2009-08-21 05:25:58 +04:00
else
err = 0 ;
break ;
case L2CAP_SDU_END :
2011-06-11 04:28:49 +04:00
if ( ! test_bit ( CONN_SAR_SDU , & chan - > conn_state ) )
2009-08-21 05:25:58 +04:00
break ;
2011-03-26 02:09:37 +03:00
memcpy ( skb_put ( chan - > sdu , skb - > len ) , skb - > data , skb - > len ) ;
2009-08-21 05:25:58 +04:00
2011-06-11 04:28:49 +04:00
clear_bit ( CONN_SAR_SDU , & chan - > conn_state ) ;
2011-03-26 02:09:37 +03:00
chan - > partial_sdu_len + = skb - > len ;
2009-08-21 05:25:58 +04:00
2011-04-14 00:20:49 +04:00
if ( chan - > partial_sdu_len > chan - > imtu )
2010-05-01 23:15:37 +04:00
goto drop ;
2011-03-26 02:09:37 +03:00
if ( chan - > partial_sdu_len = = chan - > sdu_len ) {
_skb = skb_clone ( chan - > sdu , GFP_ATOMIC ) ;
2011-05-17 00:57:22 +04:00
err = chan - > ops - > recv ( chan - > data , _skb ) ;
2009-08-21 05:25:58 +04:00
if ( err < 0 )
kfree_skb ( _skb ) ;
}
err = 0 ;
2010-05-01 23:15:37 +04:00
drop :
2011-03-26 02:09:37 +03:00
kfree_skb ( chan - > sdu ) ;
2009-08-21 05:25:58 +04:00
break ;
}
kfree_skb ( skb ) ;
return err ;
}
2011-03-26 01:43:39 +03:00
static void l2cap_check_srej_gap ( struct l2cap_chan * chan , u8 tx_seq )
2009-08-21 05:26:03 +04:00
{
struct sk_buff * skb ;
2010-05-01 23:15:43 +04:00
u16 control ;
2009-08-21 05:26:03 +04:00
2011-07-07 20:39:02 +04:00
while ( ( skb = skb_peek ( & chan - > srej_q ) ) & &
! test_bit ( CONN_LOCAL_BUSY , & chan - > conn_state ) ) {
int err ;
2009-08-21 05:26:03 +04:00
if ( bt_cb ( skb ) - > tx_seq ! = tx_seq )
break ;
2011-03-26 02:36:10 +03:00
skb = skb_dequeue ( & chan - > srej_q ) ;
2010-05-01 23:15:43 +04:00
control = bt_cb ( skb ) - > sar < < L2CAP_CTRL_SAR_SHIFT ;
2011-07-07 20:39:02 +04:00
err = l2cap_ertm_reassembly_sdu ( chan , skb , control ) ;
if ( err < 0 ) {
l2cap_send_disconn_req ( chan - > conn , chan , ECONNRESET ) ;
break ;
}
2011-03-26 01:58:34 +03:00
chan - > buffer_seq_srej =
( chan - > buffer_seq_srej + 1 ) % 64 ;
2010-05-11 02:34:11 +04:00
tx_seq = ( tx_seq + 1 ) % 64 ;
2009-08-21 05:26:03 +04:00
}
}
2011-03-26 01:43:39 +03:00
static void l2cap_resend_srejframe ( struct l2cap_chan * chan , u8 tx_seq )
2009-08-21 05:26:03 +04:00
{
struct srej_list * l , * tmp ;
u16 control ;
2011-04-04 22:40:12 +04:00
list_for_each_entry_safe ( l , tmp , & chan - > srej_l , list ) {
2009-08-21 05:26:03 +04:00
if ( l - > tx_seq = = tx_seq ) {
list_del ( & l - > list ) ;
kfree ( l ) ;
return ;
}
control = L2CAP_SUPER_SELECT_REJECT ;
control | = l - > tx_seq < < L2CAP_CTRL_REQSEQ_SHIFT ;
2011-03-26 01:43:39 +03:00
l2cap_send_sframe ( chan , control ) ;
2009-08-21 05:26:03 +04:00
list_del ( & l - > list ) ;
2011-04-04 22:40:12 +04:00
list_add_tail ( & l - > list , & chan - > srej_l ) ;
2009-08-21 05:26:03 +04:00
}
}
2011-03-26 01:43:39 +03:00
static void l2cap_send_srejframe ( struct l2cap_chan * chan , u8 tx_seq )
2009-08-21 05:26:03 +04:00
{
struct srej_list * new ;
u16 control ;
2011-03-26 01:58:34 +03:00
while ( tx_seq ! = chan - > expected_tx_seq ) {
2009-08-21 05:26:03 +04:00
control = L2CAP_SUPER_SELECT_REJECT ;
2011-03-26 01:58:34 +03:00
control | = chan - > expected_tx_seq < < L2CAP_CTRL_REQSEQ_SHIFT ;
2011-03-26 01:43:39 +03:00
l2cap_send_sframe ( chan , control ) ;
2009-08-21 05:26:03 +04:00
new = kzalloc ( sizeof ( struct srej_list ) , GFP_ATOMIC ) ;
2011-03-26 01:58:34 +03:00
new - > tx_seq = chan - > expected_tx_seq ;
chan - > expected_tx_seq = ( chan - > expected_tx_seq + 1 ) % 64 ;
2011-04-04 22:40:12 +04:00
list_add_tail ( & new - > list , & chan - > srej_l ) ;
2009-08-21 05:26:03 +04:00
}
2011-03-26 01:58:34 +03:00
chan - > expected_tx_seq = ( chan - > expected_tx_seq + 1 ) % 64 ;
2009-08-21 05:26:03 +04:00
}
2011-03-26 01:43:39 +03:00
static inline int l2cap_data_channel_iframe ( struct l2cap_chan * chan , u16 rx_control , struct sk_buff * skb )
2009-08-21 05:25:57 +04:00
{
u8 tx_seq = __get_txseq ( rx_control ) ;
2009-10-03 09:34:38 +04:00
u8 req_seq = __get_reqseq ( rx_control ) ;
2009-08-21 05:26:03 +04:00
u8 sar = rx_control > > L2CAP_CTRL_SAR_SHIFT ;
2010-05-11 01:32:04 +04:00
int tx_seq_offset , expected_tx_seq_offset ;
2011-04-13 22:57:03 +04:00
int num_to_ack = ( chan - > tx_win / 6 ) + 1 ;
2009-08-21 05:25:57 +04:00
int err = 0 ;
2011-03-26 01:43:39 +03:00
BT_DBG ( " chan %p len %d tx_seq %d rx_control 0x%4.4x " , chan , skb - > len ,
tx_seq , rx_control ) ;
2009-08-21 05:25:57 +04:00
2010-05-06 03:05:57 +04:00
if ( L2CAP_CTRL_FINAL & rx_control & &
2011-06-11 04:28:49 +04:00
test_bit ( CONN_WAIT_F , & chan - > conn_state ) ) {
2011-05-17 22:13:19 +04:00
__clear_monitor_timer ( chan ) ;
2011-04-01 07:38:50 +04:00
if ( chan - > unacked_frames > 0 )
2011-05-17 22:13:19 +04:00
__set_retrans_timer ( chan ) ;
2011-06-11 04:28:49 +04:00
clear_bit ( CONN_WAIT_F , & chan - > conn_state ) ;
2010-05-01 23:15:37 +04:00
}
2011-03-26 01:58:34 +03:00
chan - > expected_ack_seq = req_seq ;
l2cap_drop_acked_frames ( chan ) ;
2009-10-03 09:34:38 +04:00
2011-03-26 01:58:34 +03:00
tx_seq_offset = ( tx_seq - chan - > buffer_seq ) % 64 ;
2010-05-01 23:15:44 +04:00
if ( tx_seq_offset < 0 )
tx_seq_offset + = 64 ;
/* invalid tx_seq */
2011-04-13 22:57:03 +04:00
if ( tx_seq_offset > = chan - > tx_win ) {
2011-04-14 03:23:55 +04:00
l2cap_send_disconn_req ( chan - > conn , chan , ECONNRESET ) ;
2010-05-01 23:15:44 +04:00
goto drop ;
}
2011-06-11 04:28:49 +04:00
if ( test_bit ( CONN_LOCAL_BUSY , & chan - > conn_state ) )
2010-05-01 23:15:44 +04:00
goto drop ;
2011-06-30 01:35:19 +04:00
if ( tx_seq = = chan - > expected_tx_seq )
goto expected ;
2011-06-11 04:28:49 +04:00
if ( test_bit ( CONN_SREJ_SENT , & chan - > conn_state ) ) {
2009-08-21 05:26:03 +04:00
struct srej_list * first ;
2009-08-21 05:25:59 +04:00
2011-04-04 22:40:12 +04:00
first = list_first_entry ( & chan - > srej_l ,
2009-08-21 05:26:03 +04:00
struct srej_list , list ) ;
if ( tx_seq = = first - > tx_seq ) {
2011-03-26 01:58:34 +03:00
l2cap_add_to_srej_queue ( chan , skb , tx_seq , sar ) ;
2011-03-26 01:43:39 +03:00
l2cap_check_srej_gap ( chan , tx_seq ) ;
2009-08-21 05:26:03 +04:00
list_del ( & first - > list ) ;
kfree ( first ) ;
2011-04-04 22:40:12 +04:00
if ( list_empty ( & chan - > srej_l ) ) {
2011-03-26 01:58:34 +03:00
chan - > buffer_seq = chan - > buffer_seq_srej ;
2011-06-11 04:28:49 +04:00
clear_bit ( CONN_SREJ_SENT , & chan - > conn_state ) ;
2011-03-26 01:43:39 +03:00
l2cap_send_ack ( chan ) ;
2011-04-04 22:59:54 +04:00
BT_DBG ( " chan %p, Exit SREJ_SENT " , chan ) ;
2009-08-21 05:26:03 +04:00
}
} else {
struct srej_list * l ;
2010-05-01 23:15:44 +04:00
/* duplicated tx_seq */
2011-03-26 01:58:34 +03:00
if ( l2cap_add_to_srej_queue ( chan , skb , tx_seq , sar ) < 0 )
2010-05-01 23:15:44 +04:00
goto drop ;
2009-08-21 05:26:03 +04:00
2011-04-04 22:40:12 +04:00
list_for_each_entry ( l , & chan - > srej_l , list ) {
2009-08-21 05:26:03 +04:00
if ( l - > tx_seq = = tx_seq ) {
2011-03-26 01:43:39 +03:00
l2cap_resend_srejframe ( chan , tx_seq ) ;
2009-08-21 05:26:03 +04:00
return 0 ;
}
}
2011-03-26 01:43:39 +03:00
l2cap_send_srejframe ( chan , tx_seq ) ;
2009-08-21 05:25:59 +04:00
}
} else {
2010-05-01 23:15:44 +04:00
expected_tx_seq_offset =
2011-03-26 01:58:34 +03:00
( chan - > expected_tx_seq - chan - > buffer_seq ) % 64 ;
2010-05-01 23:15:44 +04:00
if ( expected_tx_seq_offset < 0 )
expected_tx_seq_offset + = 64 ;
/* duplicated tx_seq */
if ( tx_seq_offset < expected_tx_seq_offset )
goto drop ;
2011-06-11 04:28:49 +04:00
set_bit ( CONN_SREJ_SENT , & chan - > conn_state ) ;
2009-08-21 05:25:57 +04:00
2011-04-04 22:59:54 +04:00
BT_DBG ( " chan %p, Enter SREJ " , chan ) ;
2010-04-19 21:45:38 +04:00
2011-04-04 22:40:12 +04:00
INIT_LIST_HEAD ( & chan - > srej_l ) ;
2011-03-26 01:58:34 +03:00
chan - > buffer_seq_srej = chan - > buffer_seq ;
2009-08-21 05:26:03 +04:00
2011-03-26 02:36:10 +03:00
__skb_queue_head_init ( & chan - > srej_q ) ;
2011-03-26 01:58:34 +03:00
l2cap_add_to_srej_queue ( chan , skb , tx_seq , sar ) ;
2009-08-21 05:26:03 +04:00
2011-06-11 04:28:49 +04:00
set_bit ( CONN_SEND_PBIT , & chan - > conn_state ) ;
2009-08-21 05:26:04 +04:00
2011-03-26 01:43:39 +03:00
l2cap_send_srejframe ( chan , tx_seq ) ;
2010-05-13 01:32:04 +04:00
2011-05-17 22:13:19 +04:00
__clear_ack_timer ( chan ) ;
2009-08-21 05:25:57 +04:00
}
2009-08-21 05:25:59 +04:00
return 0 ;
2009-08-21 05:26:03 +04:00
expected :
2011-03-26 01:58:34 +03:00
chan - > expected_tx_seq = ( chan - > expected_tx_seq + 1 ) % 64 ;
2009-08-21 05:26:03 +04:00
2011-06-11 04:28:49 +04:00
if ( test_bit ( CONN_SREJ_SENT , & chan - > conn_state ) ) {
2010-05-01 23:15:42 +04:00
bt_cb ( skb ) - > tx_seq = tx_seq ;
bt_cb ( skb ) - > sar = sar ;
2011-03-26 02:36:10 +03:00
__skb_queue_tail ( & chan - > srej_q , skb ) ;
2009-08-21 05:26:03 +04:00
return 0 ;
}
2011-07-07 20:39:03 +04:00
err = l2cap_ertm_reassembly_sdu ( chan , skb , rx_control ) ;
chan - > buffer_seq = ( chan - > buffer_seq + 1 ) % 64 ;
2011-07-07 20:39:02 +04:00
if ( err < 0 ) {
l2cap_send_disconn_req ( chan - > conn , chan , ECONNRESET ) ;
return err ;
}
2010-06-17 00:21:44 +04:00
2009-10-03 09:34:39 +04:00
if ( rx_control & L2CAP_CTRL_FINAL ) {
2011-06-11 04:28:49 +04:00
if ( ! test_and_clear_bit ( CONN_REJ_ACT , & chan - > conn_state ) )
2011-03-26 01:43:39 +03:00
l2cap_retransmit_frames ( chan ) ;
2009-10-03 09:34:39 +04:00
}
2011-05-17 22:13:19 +04:00
__set_ack_timer ( chan ) ;
2010-05-01 23:15:39 +04:00
2011-04-01 07:38:50 +04:00
chan - > num_acked = ( chan - > num_acked + 1 ) % num_to_ack ;
if ( chan - > num_acked = = num_to_ack - 1 )
2011-03-26 01:43:39 +03:00
l2cap_send_ack ( chan ) ;
2010-05-01 23:15:37 +04:00
2009-08-21 05:26:03 +04:00
return 0 ;
2010-05-01 23:15:44 +04:00
drop :
kfree_skb ( skb ) ;
return 0 ;
2009-08-21 05:25:57 +04:00
}
2011-03-26 01:43:39 +03:00
static inline void l2cap_data_channel_rrframe ( struct l2cap_chan * chan , u16 rx_control )
2009-08-21 05:25:57 +04:00
{
2011-04-04 22:59:54 +04:00
BT_DBG ( " chan %p, req_seq %d ctrl 0x%4.4x " , chan , __get_reqseq ( rx_control ) ,
2010-04-19 21:45:38 +04:00
rx_control ) ;
2011-03-26 01:58:34 +03:00
chan - > expected_ack_seq = __get_reqseq ( rx_control ) ;
l2cap_drop_acked_frames ( chan ) ;
2009-08-21 05:25:57 +04:00
2010-05-01 23:15:38 +04:00
if ( rx_control & L2CAP_CTRL_POLL ) {
2011-06-11 04:28:49 +04:00
set_bit ( CONN_SEND_FBIT , & chan - > conn_state ) ;
if ( test_bit ( CONN_SREJ_SENT , & chan - > conn_state ) ) {
if ( test_bit ( CONN_REMOTE_BUSY , & chan - > conn_state ) & &
2011-04-01 07:38:50 +04:00
( chan - > unacked_frames > 0 ) )
2011-05-17 22:13:19 +04:00
__set_retrans_timer ( chan ) ;
2010-05-01 23:15:39 +04:00
2011-06-11 04:28:49 +04:00
clear_bit ( CONN_REMOTE_BUSY , & chan - > conn_state ) ;
2011-03-26 01:43:39 +03:00
l2cap_send_srejtail ( chan ) ;
2010-05-01 23:15:39 +04:00
} else {
2011-03-26 01:43:39 +03:00
l2cap_send_i_or_rr_or_rnr ( chan ) ;
2010-05-01 23:15:39 +04:00
}
2010-05-01 23:15:37 +04:00
2010-05-01 23:15:38 +04:00
} else if ( rx_control & L2CAP_CTRL_FINAL ) {
2011-06-11 04:28:49 +04:00
clear_bit ( CONN_REMOTE_BUSY , & chan - > conn_state ) ;
2009-10-03 09:34:39 +04:00
2011-06-11 04:28:49 +04:00
if ( ! test_and_clear_bit ( CONN_REJ_ACT , & chan - > conn_state ) )
2011-03-26 01:43:39 +03:00
l2cap_retransmit_frames ( chan ) ;
2009-08-26 11:04:02 +04:00
2010-05-01 23:15:38 +04:00
} else {
2011-06-11 04:28:49 +04:00
if ( test_bit ( CONN_REMOTE_BUSY , & chan - > conn_state ) & &
2011-04-01 07:38:50 +04:00
( chan - > unacked_frames > 0 ) )
2011-05-17 22:13:19 +04:00
__set_retrans_timer ( chan ) ;
2009-08-21 05:25:57 +04:00
2011-06-11 04:28:49 +04:00
clear_bit ( CONN_REMOTE_BUSY , & chan - > conn_state ) ;
if ( test_bit ( CONN_SREJ_SENT , & chan - > conn_state ) )
2011-03-26 01:43:39 +03:00
l2cap_send_ack ( chan ) ;
2010-12-01 17:58:24 +03:00
else
2011-03-26 01:43:39 +03:00
l2cap_ertm_send ( chan ) ;
2010-05-01 23:15:38 +04:00
}
}
2009-08-26 11:04:02 +04:00
2011-03-26 01:43:39 +03:00
static inline void l2cap_data_channel_rejframe ( struct l2cap_chan * chan , u16 rx_control )
2010-05-01 23:15:38 +04:00
{
u8 tx_seq = __get_reqseq ( rx_control ) ;
2009-08-21 05:25:59 +04:00
2011-03-26 01:43:39 +03:00
BT_DBG ( " chan %p, req_seq %d ctrl 0x%4.4x " , chan , tx_seq , rx_control ) ;
2010-04-19 21:45:38 +04:00
2011-06-11 04:28:49 +04:00
clear_bit ( CONN_REMOTE_BUSY , & chan - > conn_state ) ;
2010-05-01 23:15:38 +04:00
2011-03-26 01:58:34 +03:00
chan - > expected_ack_seq = tx_seq ;
l2cap_drop_acked_frames ( chan ) ;
2010-05-01 23:15:38 +04:00
if ( rx_control & L2CAP_CTRL_FINAL ) {
2011-06-11 04:28:49 +04:00
if ( ! test_and_clear_bit ( CONN_REJ_ACT , & chan - > conn_state ) )
2011-03-26 01:43:39 +03:00
l2cap_retransmit_frames ( chan ) ;
2010-05-01 23:15:38 +04:00
} else {
2011-03-26 01:43:39 +03:00
l2cap_retransmit_frames ( chan ) ;
2009-08-21 05:25:59 +04:00
2011-06-11 04:28:49 +04:00
if ( test_bit ( CONN_WAIT_F , & chan - > conn_state ) )
set_bit ( CONN_REJ_ACT , & chan - > conn_state ) ;
2010-05-01 23:15:38 +04:00
}
}
2011-03-26 01:43:39 +03:00
static inline void l2cap_data_channel_srejframe ( struct l2cap_chan * chan , u16 rx_control )
2010-05-01 23:15:38 +04:00
{
u8 tx_seq = __get_reqseq ( rx_control ) ;
2009-08-21 05:25:59 +04:00
2011-03-26 01:43:39 +03:00
BT_DBG ( " chan %p, req_seq %d ctrl 0x%4.4x " , chan , tx_seq , rx_control ) ;
2010-04-19 21:45:38 +04:00
2011-06-11 04:28:49 +04:00
clear_bit ( CONN_REMOTE_BUSY , & chan - > conn_state ) ;
2009-08-26 11:04:02 +04:00
2010-05-01 23:15:38 +04:00
if ( rx_control & L2CAP_CTRL_POLL ) {
2011-03-26 01:58:34 +03:00
chan - > expected_ack_seq = tx_seq ;
l2cap_drop_acked_frames ( chan ) ;
2010-05-29 09:24:35 +04:00
2011-06-11 04:28:49 +04:00
set_bit ( CONN_SEND_FBIT , & chan - > conn_state ) ;
2011-03-26 01:43:39 +03:00
l2cap_retransmit_one_frame ( chan , tx_seq ) ;
2010-05-01 23:15:45 +04:00
2011-03-26 01:43:39 +03:00
l2cap_ertm_send ( chan ) ;
2010-05-01 23:15:45 +04:00
2011-06-11 04:28:49 +04:00
if ( test_bit ( CONN_WAIT_F , & chan - > conn_state ) ) {
2011-04-01 07:38:50 +04:00
chan - > srej_save_reqseq = tx_seq ;
2011-06-11 04:28:49 +04:00
set_bit ( CONN_SREJ_ACT , & chan - > conn_state ) ;
2009-08-21 05:26:04 +04:00
}
2010-05-01 23:15:38 +04:00
} else if ( rx_control & L2CAP_CTRL_FINAL ) {
2011-06-11 04:28:49 +04:00
if ( test_bit ( CONN_SREJ_ACT , & chan - > conn_state ) & &
2011-04-01 07:38:50 +04:00
chan - > srej_save_reqseq = = tx_seq )
2011-06-11 04:28:49 +04:00
clear_bit ( CONN_SREJ_ACT , & chan - > conn_state ) ;
2010-05-01 23:15:38 +04:00
else
2011-03-26 01:43:39 +03:00
l2cap_retransmit_one_frame ( chan , tx_seq ) ;
2010-05-01 23:15:38 +04:00
} else {
2011-03-26 01:43:39 +03:00
l2cap_retransmit_one_frame ( chan , tx_seq ) ;
2011-06-11 04:28:49 +04:00
if ( test_bit ( CONN_WAIT_F , & chan - > conn_state ) ) {
2011-04-01 07:38:50 +04:00
chan - > srej_save_reqseq = tx_seq ;
2011-06-11 04:28:49 +04:00
set_bit ( CONN_SREJ_ACT , & chan - > conn_state ) ;
2009-08-21 05:26:04 +04:00
}
2010-05-01 23:15:38 +04:00
}
}
2011-03-26 01:43:39 +03:00
static inline void l2cap_data_channel_rnrframe ( struct l2cap_chan * chan , u16 rx_control )
2010-05-01 23:15:38 +04:00
{
u8 tx_seq = __get_reqseq ( rx_control ) ;
2011-03-26 01:43:39 +03:00
BT_DBG ( " chan %p, req_seq %d ctrl 0x%4.4x " , chan , tx_seq , rx_control ) ;
2010-04-19 21:45:38 +04:00
2011-06-11 04:28:49 +04:00
set_bit ( CONN_REMOTE_BUSY , & chan - > conn_state ) ;
2011-03-26 01:58:34 +03:00
chan - > expected_ack_seq = tx_seq ;
l2cap_drop_acked_frames ( chan ) ;
2010-05-01 23:15:38 +04:00
2010-05-29 09:24:35 +04:00
if ( rx_control & L2CAP_CTRL_POLL )
2011-06-11 04:28:49 +04:00
set_bit ( CONN_SEND_FBIT , & chan - > conn_state ) ;
2010-05-29 09:24:35 +04:00
2011-06-11 04:28:49 +04:00
if ( ! test_bit ( CONN_SREJ_SENT , & chan - > conn_state ) ) {
2011-05-17 22:13:19 +04:00
__clear_retrans_timer ( chan ) ;
2010-05-06 02:58:27 +04:00
if ( rx_control & L2CAP_CTRL_POLL )
2011-03-26 01:43:39 +03:00
l2cap_send_rr_or_rnr ( chan , L2CAP_CTRL_FINAL ) ;
2010-05-01 23:15:38 +04:00
return ;
2010-05-01 23:15:38 +04:00
}
2010-05-01 23:15:38 +04:00
if ( rx_control & L2CAP_CTRL_POLL )
2011-03-26 01:43:39 +03:00
l2cap_send_srejtail ( chan ) ;
2010-05-01 23:15:38 +04:00
else
2011-03-26 01:43:39 +03:00
l2cap_send_sframe ( chan , L2CAP_SUPER_RCV_READY ) ;
2010-05-01 23:15:38 +04:00
}
2011-03-26 01:43:39 +03:00
static inline int l2cap_data_channel_sframe ( struct l2cap_chan * chan , u16 rx_control , struct sk_buff * skb )
2010-05-01 23:15:38 +04:00
{
2011-03-26 01:43:39 +03:00
BT_DBG ( " chan %p rx_control 0x%4.4x len %d " , chan , rx_control , skb - > len ) ;
2010-05-01 23:15:38 +04:00
2010-05-06 03:05:57 +04:00
if ( L2CAP_CTRL_FINAL & rx_control & &
2011-06-11 04:28:49 +04:00
test_bit ( CONN_WAIT_F , & chan - > conn_state ) ) {
2011-05-17 22:13:19 +04:00
__clear_monitor_timer ( chan ) ;
2011-04-01 07:38:50 +04:00
if ( chan - > unacked_frames > 0 )
2011-05-17 22:13:19 +04:00
__set_retrans_timer ( chan ) ;
2011-06-11 04:28:49 +04:00
clear_bit ( CONN_WAIT_F , & chan - > conn_state ) ;
2010-05-01 23:15:38 +04:00
}
switch ( rx_control & L2CAP_CTRL_SUPERVISE ) {
case L2CAP_SUPER_RCV_READY :
2011-03-26 01:43:39 +03:00
l2cap_data_channel_rrframe ( chan , rx_control ) ;
2009-08-21 05:26:03 +04:00
break ;
2010-05-01 23:15:38 +04:00
case L2CAP_SUPER_REJECT :
2011-03-26 01:43:39 +03:00
l2cap_data_channel_rejframe ( chan , rx_control ) ;
2010-05-01 23:15:38 +04:00
break ;
2009-08-26 11:04:02 +04:00
2010-05-01 23:15:38 +04:00
case L2CAP_SUPER_SELECT_REJECT :
2011-03-26 01:43:39 +03:00
l2cap_data_channel_srejframe ( chan , rx_control ) ;
2010-05-01 23:15:38 +04:00
break ;
case L2CAP_SUPER_RCV_NOT_READY :
2011-03-26 01:43:39 +03:00
l2cap_data_channel_rnrframe ( chan , rx_control ) ;
2009-08-21 05:25:57 +04:00
break ;
}
2010-05-01 23:15:35 +04:00
kfree_skb ( skb ) ;
2009-08-21 05:25:57 +04:00
return 0 ;
}
2010-06-22 01:53:22 +04:00
static int l2cap_ertm_data_rcv ( struct sock * sk , struct sk_buff * skb )
{
2011-03-26 01:43:39 +03:00
struct l2cap_chan * chan = l2cap_pi ( sk ) - > chan ;
2010-06-22 01:53:22 +04:00
u16 control ;
u8 req_seq ;
int len , next_tx_seq_offset , req_seq_offset ;
control = get_unaligned_le16 ( skb - > data ) ;
skb_pull ( skb , 2 ) ;
len = skb - > len ;
/*
* We can just drop the corrupted I - frame here .
* Receiver will miss it and start proper recovery
* procedures and ask retransmission .
*/
2011-04-13 22:57:03 +04:00
if ( l2cap_check_fcs ( chan , skb ) )
2010-06-22 01:53:22 +04:00
goto drop ;
if ( __is_sar_start ( control ) & & __is_iframe ( control ) )
len - = 2 ;
2011-04-13 22:57:03 +04:00
if ( chan - > fcs = = L2CAP_FCS_CRC16 )
2010-06-22 01:53:22 +04:00
len - = 2 ;
2011-04-13 22:57:03 +04:00
if ( len > chan - > mps ) {
2011-04-14 03:23:55 +04:00
l2cap_send_disconn_req ( chan - > conn , chan , ECONNRESET ) ;
2010-06-22 01:53:22 +04:00
goto drop ;
}
req_seq = __get_reqseq ( control ) ;
2011-03-26 01:58:34 +03:00
req_seq_offset = ( req_seq - chan - > expected_ack_seq ) % 64 ;
2010-06-22 01:53:22 +04:00
if ( req_seq_offset < 0 )
req_seq_offset + = 64 ;
next_tx_seq_offset =
2011-03-26 01:58:34 +03:00
( chan - > next_tx_seq - chan - > expected_ack_seq ) % 64 ;
2010-06-22 01:53:22 +04:00
if ( next_tx_seq_offset < 0 )
next_tx_seq_offset + = 64 ;
/* check for invalid req-seq */
if ( req_seq_offset > next_tx_seq_offset ) {
2011-04-14 03:23:55 +04:00
l2cap_send_disconn_req ( chan - > conn , chan , ECONNRESET ) ;
2010-06-22 01:53:22 +04:00
goto drop ;
}
if ( __is_iframe ( control ) ) {
if ( len < 0 ) {
2011-04-14 03:23:55 +04:00
l2cap_send_disconn_req ( chan - > conn , chan , ECONNRESET ) ;
2010-06-22 01:53:22 +04:00
goto drop ;
}
2011-03-26 01:43:39 +03:00
l2cap_data_channel_iframe ( chan , control , skb ) ;
2010-06-22 01:53:22 +04:00
} else {
if ( len ! = 0 ) {
BT_ERR ( " %d " , len ) ;
2011-04-14 03:23:55 +04:00
l2cap_send_disconn_req ( chan - > conn , chan , ECONNRESET ) ;
2010-06-22 01:53:22 +04:00
goto drop ;
}
2011-03-26 01:43:39 +03:00
l2cap_data_channel_sframe ( chan , control , skb ) ;
2010-06-22 01:53:22 +04:00
}
return 0 ;
drop :
kfree_skb ( skb ) ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
static inline int l2cap_data_channel ( struct l2cap_conn * conn , u16 cid , struct sk_buff * skb )
{
2011-03-25 06:22:30 +03:00
struct l2cap_chan * chan ;
2011-04-26 00:03:02 +04:00
struct sock * sk = NULL ;
2010-06-09 23:46:25 +04:00
u16 control ;
2010-06-22 01:53:22 +04:00
u8 tx_seq ;
int len ;
2005-04-17 02:20:36 +04:00
2011-03-31 23:17:41 +04:00
chan = l2cap_get_chan_by_scid ( conn , cid ) ;
2011-03-25 06:22:30 +03:00
if ( ! chan ) {
2005-04-17 02:20:36 +04:00
BT_DBG ( " unknown cid 0x%4.4x " , cid ) ;
goto drop ;
}
2011-03-25 06:22:30 +03:00
sk = chan - > sk ;
2009-08-21 05:26:01 +04:00
2011-04-04 22:59:54 +04:00
BT_DBG ( " chan %p, len %d " , chan , skb - > len ) ;
2005-04-17 02:20:36 +04:00
2011-06-03 07:19:47 +04:00
if ( chan - > state ! = BT_CONNECTED )
2005-04-17 02:20:36 +04:00
goto drop ;
2011-04-14 00:20:49 +04:00
switch ( chan - > mode ) {
2009-08-21 05:25:57 +04:00
case L2CAP_MODE_BASIC :
/* If socket recv buffers overflows we drop data here
* which is * bad * because L2CAP has to be reliable .
* But we don ' t have any other choice . L2CAP doesn ' t
* provide flow control mechanism . */
2005-04-17 02:20:36 +04:00
2011-04-14 00:20:49 +04:00
if ( chan - > imtu < skb - > len )
2009-08-21 05:25:57 +04:00
goto drop ;
2005-04-17 02:20:36 +04:00
2011-05-17 00:57:22 +04:00
if ( ! chan - > ops - > recv ( chan - > data , skb ) )
2009-08-21 05:25:57 +04:00
goto done ;
break ;
case L2CAP_MODE_ERTM :
2010-06-22 01:53:22 +04:00
if ( ! sock_owned_by_user ( sk ) ) {
l2cap_ertm_data_rcv ( sk , skb ) ;
2010-05-01 23:15:37 +04:00
} else {
2010-06-22 01:53:22 +04:00
if ( sk_add_backlog ( sk , skb ) )
2010-05-01 23:15:37 +04:00
goto drop ;
}
2009-08-21 05:25:57 +04:00
2009-12-22 16:58:08 +03:00
goto done ;
2009-08-21 05:25:57 +04:00
2009-08-21 05:26:01 +04:00
case L2CAP_MODE_STREAMING :
control = get_unaligned_le16 ( skb - > data ) ;
skb_pull ( skb , 2 ) ;
len = skb - > len ;
2011-04-13 22:57:03 +04:00
if ( l2cap_check_fcs ( chan , skb ) )
2010-05-12 05:02:00 +04:00
goto drop ;
2009-08-21 05:26:01 +04:00
if ( __is_sar_start ( control ) )
len - = 2 ;
2011-04-13 22:57:03 +04:00
if ( chan - > fcs = = L2CAP_FCS_CRC16 )
2009-08-21 05:26:02 +04:00
len - = 2 ;
2011-04-13 22:57:03 +04:00
if ( len > chan - > mps | | len < 0 | | __is_sframe ( control ) )
2009-08-21 05:26:01 +04:00
goto drop ;
tx_seq = __get_txseq ( control ) ;
2011-03-26 01:58:34 +03:00
if ( chan - > expected_tx_seq = = tx_seq )
chan - > expected_tx_seq = ( chan - > expected_tx_seq + 1 ) % 64 ;
2009-08-21 05:26:01 +04:00
else
2011-03-26 01:58:34 +03:00
chan - > expected_tx_seq = ( tx_seq + 1 ) % 64 ;
2009-08-21 05:26:01 +04:00
2011-03-26 01:43:39 +03:00
l2cap_streaming_reassembly_sdu ( chan , skb , control ) ;
2009-08-21 05:26:01 +04:00
goto done ;
2009-08-21 05:25:57 +04:00
default :
2011-04-14 00:20:49 +04:00
BT_DBG ( " chan %p: bad mode 0x%2.2x " , chan , chan - > mode ) ;
2009-08-21 05:25:57 +04:00
break ;
}
2005-04-17 02:20:36 +04:00
drop :
kfree_skb ( skb ) ;
done :
2006-07-03 12:02:46 +04:00
if ( sk )
bh_unlock_sock ( sk ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-07-29 11:16:36 +04:00
static inline int l2cap_conless_channel ( struct l2cap_conn * conn , __le16 psm , struct sk_buff * skb )
2005-04-17 02:20:36 +04:00
{
2011-05-17 07:09:26 +04:00
struct sock * sk = NULL ;
2011-04-28 01:26:32 +04:00
struct l2cap_chan * chan ;
2005-04-17 02:20:36 +04:00
2011-04-28 01:26:32 +04:00
chan = l2cap_global_chan_by_psm ( 0 , psm , conn - > src ) ;
if ( ! chan )
2005-04-17 02:20:36 +04:00
goto drop ;
2011-04-28 01:26:32 +04:00
sk = chan - > sk ;
2010-11-01 21:43:53 +03:00
bh_lock_sock ( sk ) ;
2005-04-17 02:20:36 +04:00
BT_DBG ( " sk %p, len %d " , sk , skb - > len ) ;
2011-06-03 07:19:47 +04:00
if ( chan - > state ! = BT_BOUND & & chan - > state ! = BT_CONNECTED )
2005-04-17 02:20:36 +04:00
goto drop ;
2011-06-18 05:46:27 +04:00
if ( chan - > imtu < skb - > len )
2005-04-17 02:20:36 +04:00
goto drop ;
2011-05-17 00:57:22 +04:00
if ( ! chan - > ops - > recv ( chan - > data , skb ) )
2005-04-17 02:20:36 +04:00
goto done ;
drop :
kfree_skb ( skb ) ;
done :
2009-04-20 08:31:08 +04:00
if ( sk )
bh_unlock_sock ( sk ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2011-04-07 23:40:25 +04:00
static inline int l2cap_att_channel ( struct l2cap_conn * conn , __le16 cid , struct sk_buff * skb )
{
2011-05-17 07:09:26 +04:00
struct sock * sk = NULL ;
2011-04-28 01:26:32 +04:00
struct l2cap_chan * chan ;
2011-04-07 23:40:25 +04:00
2011-04-28 01:26:32 +04:00
chan = l2cap_global_chan_by_scid ( 0 , cid , conn - > src ) ;
if ( ! chan )
2011-04-07 23:40:25 +04:00
goto drop ;
2011-04-28 01:26:32 +04:00
sk = chan - > sk ;
2011-04-07 23:40:25 +04:00
bh_lock_sock ( sk ) ;
BT_DBG ( " sk %p, len %d " , sk , skb - > len ) ;
2011-06-03 07:19:47 +04:00
if ( chan - > state ! = BT_BOUND & & chan - > state ! = BT_CONNECTED )
2011-04-07 23:40:25 +04:00
goto drop ;
2011-06-18 05:46:27 +04:00
if ( chan - > imtu < skb - > len )
2011-04-07 23:40:25 +04:00
goto drop ;
2011-05-17 00:57:22 +04:00
if ( ! chan - > ops - > recv ( chan - > data , skb ) )
2011-04-07 23:40:25 +04:00
goto done ;
drop :
kfree_skb ( skb ) ;
done :
if ( sk )
bh_unlock_sock ( sk ) ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
static void l2cap_recv_frame ( struct l2cap_conn * conn , struct sk_buff * skb )
{
struct l2cap_hdr * lh = ( void * ) skb - > data ;
2007-07-29 11:16:36 +04:00
u16 cid , len ;
__le16 psm ;
2005-04-17 02:20:36 +04:00
skb_pull ( skb , L2CAP_HDR_SIZE ) ;
cid = __le16_to_cpu ( lh - > cid ) ;
len = __le16_to_cpu ( lh - > len ) ;
2009-08-21 05:25:57 +04:00
if ( len ! = skb - > len ) {
kfree_skb ( skb ) ;
return ;
}
2005-04-17 02:20:36 +04:00
BT_DBG ( " len %d, cid 0x%4.4x " , len , cid ) ;
switch ( cid ) {
2011-02-12 00:28:54 +03:00
case L2CAP_CID_LE_SIGNALING :
2009-04-20 08:31:05 +04:00
case L2CAP_CID_SIGNALING :
2005-04-17 02:20:36 +04:00
l2cap_sig_channel ( conn , skb ) ;
break ;
2009-04-20 08:31:05 +04:00
case L2CAP_CID_CONN_LESS :
2009-08-24 07:45:20 +04:00
psm = get_unaligned_le16 ( skb - > data ) ;
2005-04-17 02:20:36 +04:00
skb_pull ( skb , 2 ) ;
l2cap_conless_channel ( conn , psm , skb ) ;
break ;
2011-04-07 23:40:25 +04:00
case L2CAP_CID_LE_DATA :
l2cap_att_channel ( conn , cid , skb ) ;
break ;
2011-06-08 01:46:31 +04:00
case L2CAP_CID_SMP :
if ( smp_sig_channel ( conn , skb ) )
l2cap_conn_del ( conn - > hcon , EACCES ) ;
break ;
2005-04-17 02:20:36 +04:00
default :
l2cap_data_channel ( conn , cid , skb ) ;
break ;
}
}
/* ---- L2CAP interface with lower layer (HCI) ---- */
static int l2cap_connect_ind ( struct hci_dev * hdev , bdaddr_t * bdaddr , u8 type )
{
int exact = 0 , lm1 = 0 , lm2 = 0 ;
2011-04-28 01:26:32 +04:00
struct l2cap_chan * c ;
2005-04-17 02:20:36 +04:00
if ( type ! = ACL_LINK )
2010-06-22 20:56:28 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
BT_DBG ( " hdev %s, bdaddr %s " , hdev - > name , batostr ( bdaddr ) ) ;
/* Find listening sockets and check their link_mode */
2011-04-28 01:26:32 +04:00
read_lock ( & chan_list_lock ) ;
list_for_each_entry ( c , & chan_list , global_l ) {
struct sock * sk = c - > sk ;
2011-04-13 01:31:57 +04:00
2011-06-03 07:19:47 +04:00
if ( c - > state ! = BT_LISTEN )
2005-04-17 02:20:36 +04:00
continue ;
if ( ! bacmp ( & bt_sk ( sk ) - > src , & hdev - > bdaddr ) ) {
2009-01-15 23:58:38 +03:00
lm1 | = HCI_LM_ACCEPT ;
2011-04-28 01:26:32 +04:00
if ( c - > role_switch )
2009-01-15 23:58:38 +03:00
lm1 | = HCI_LM_MASTER ;
2005-04-17 02:20:36 +04:00
exact + + ;
2009-01-15 23:58:38 +03:00
} else if ( ! bacmp ( & bt_sk ( sk ) - > src , BDADDR_ANY ) ) {
lm2 | = HCI_LM_ACCEPT ;
2011-04-28 01:26:32 +04:00
if ( c - > role_switch )
2009-01-15 23:58:38 +03:00
lm2 | = HCI_LM_MASTER ;
}
2005-04-17 02:20:36 +04:00
}
2011-04-28 01:26:32 +04:00
read_unlock ( & chan_list_lock ) ;
2005-04-17 02:20:36 +04:00
return exact ? lm1 : lm2 ;
}
static int l2cap_connect_cfm ( struct hci_conn * hcon , u8 status )
{
2006-07-03 12:02:46 +04:00
struct l2cap_conn * conn ;
2005-04-17 02:20:36 +04:00
BT_DBG ( " hcon %p bdaddr %s status %d " , hcon , batostr ( & hcon - > dst ) , status ) ;
2011-02-11 04:38:49 +03:00
if ( ! ( hcon - > type = = ACL_LINK | | hcon - > type = = LE_LINK ) )
2010-06-22 20:56:28 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
if ( ! status ) {
conn = l2cap_conn_add ( hcon , status ) ;
if ( conn )
l2cap_conn_ready ( conn ) ;
2006-07-03 12:02:46 +04:00
} else
2011-06-30 05:18:29 +04:00
l2cap_conn_del ( hcon , bt_to_errno ( status ) ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2009-02-12 16:02:50 +03:00
static int l2cap_disconn_ind ( struct hci_conn * hcon )
{
struct l2cap_conn * conn = hcon - > l2cap_data ;
BT_DBG ( " hcon %p " , hcon ) ;
2011-06-09 02:09:13 +04:00
if ( ( hcon - > type ! = ACL_LINK & & hcon - > type ! = LE_LINK ) | | ! conn )
2009-02-12 16:02:50 +03:00
return 0x13 ;
return conn - > disc_reason ;
}
static int l2cap_disconn_cfm ( struct hci_conn * hcon , u8 reason )
2005-04-17 02:20:36 +04:00
{
BT_DBG ( " hcon %p reason %d " , hcon , reason ) ;
2011-02-11 04:38:49 +03:00
if ( ! ( hcon - > type = = ACL_LINK | | hcon - > type = = LE_LINK ) )
2010-06-22 20:56:28 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
2011-06-30 05:18:29 +04:00
l2cap_conn_del ( hcon , bt_to_errno ( reason ) ) ;
2006-07-03 12:02:46 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
2011-04-13 01:31:57 +04:00
static inline void l2cap_check_encryption ( struct l2cap_chan * chan , u8 encrypt )
2009-01-15 23:58:44 +03:00
{
2011-05-03 00:13:55 +04:00
if ( chan - > chan_type ! = L2CAP_CHAN_CONN_ORIENTED )
2009-02-04 23:07:19 +03:00
return ;
2009-01-15 23:58:44 +03:00
if ( encrypt = = 0x00 ) {
2011-04-13 01:31:57 +04:00
if ( chan - > sec_level = = BT_SECURITY_MEDIUM ) {
2011-05-17 21:59:01 +04:00
__clear_chan_timer ( chan ) ;
__set_chan_timer ( chan , HZ * 5 ) ;
2011-04-13 01:31:57 +04:00
} else if ( chan - > sec_level = = BT_SECURITY_HIGH )
2011-05-05 02:42:50 +04:00
l2cap_chan_close ( chan , ECONNREFUSED ) ;
2009-01-15 23:58:44 +03:00
} else {
2011-04-13 01:31:57 +04:00
if ( chan - > sec_level = = BT_SECURITY_MEDIUM )
2011-05-17 21:59:01 +04:00
__clear_chan_timer ( chan ) ;
2009-01-15 23:58:44 +03:00
}
}
2009-01-15 23:58:04 +03:00
static int l2cap_security_cfm ( struct hci_conn * hcon , u8 status , u8 encrypt )
2005-04-17 02:20:36 +04:00
{
2006-07-03 12:02:46 +04:00
struct l2cap_conn * conn = hcon - > l2cap_data ;
2011-03-25 06:22:30 +03:00
struct l2cap_chan * chan ;
2005-04-17 02:20:36 +04:00
2006-07-03 12:02:46 +04:00
if ( ! conn )
2005-04-17 02:20:36 +04:00
return 0 ;
2006-07-03 12:02:46 +04:00
2005-04-17 02:20:36 +04:00
BT_DBG ( " conn %p " , conn ) ;
2011-03-31 23:17:41 +04:00
read_lock ( & conn - > chan_lock ) ;
2005-04-17 02:20:36 +04:00
2011-03-31 23:17:41 +04:00
list_for_each_entry ( chan , & conn - > chan_l , list ) {
2011-03-25 06:22:30 +03:00
struct sock * sk = chan - > sk ;
2011-03-31 23:17:41 +04:00
2005-04-17 02:20:36 +04:00
bh_lock_sock ( sk ) ;
2011-01-27 03:42:57 +03:00
BT_DBG ( " chan->scid %d " , chan - > scid ) ;
if ( chan - > scid = = L2CAP_CID_LE_DATA ) {
if ( ! status & & encrypt ) {
chan - > sec_level = hcon - > sec_level ;
2011-06-14 20:37:41 +04:00
del_timer ( & conn - > security_timer ) ;
2011-01-27 03:42:57 +03:00
l2cap_chan_ready ( sk ) ;
2011-07-08 01:59:34 +04:00
smp_distribute_keys ( conn , 0 ) ;
2011-01-27 03:42:57 +03:00
}
bh_unlock_sock ( sk ) ;
continue ;
}
2011-06-11 00:02:12 +04:00
if ( test_bit ( CONF_CONNECT_PEND , & chan - > conf_state ) ) {
2009-02-07 01:56:36 +03:00
bh_unlock_sock ( sk ) ;
continue ;
}
2011-06-03 07:19:47 +04:00
if ( ! status & & ( chan - > state = = BT_CONNECTED | |
chan - > state = = BT_CONFIG ) ) {
2011-04-13 01:31:57 +04:00
l2cap_check_encryption ( chan , encrypt ) ;
2008-07-14 22:13:45 +04:00
bh_unlock_sock ( sk ) ;
continue ;
}
2011-06-03 07:19:47 +04:00
if ( chan - > state = = BT_CONNECT ) {
2008-07-14 22:13:54 +04:00
if ( ! status ) {
struct l2cap_conn_req req ;
2011-04-14 02:50:45 +04:00
req . scid = cpu_to_le16 ( chan - > scid ) ;
req . psm = chan - > psm ;
2005-04-17 02:20:36 +04:00
2011-03-25 19:59:37 +03:00
chan - > ident = l2cap_get_ident ( conn ) ;
2011-06-11 00:02:12 +04:00
set_bit ( CONF_CONNECT_PEND , & chan - > conf_state ) ;
2005-04-17 02:20:36 +04:00
2011-03-25 19:59:37 +03:00
l2cap_send_cmd ( conn , chan - > ident ,
2008-07-14 22:13:54 +04:00
L2CAP_CONN_REQ , sizeof ( req ) , & req ) ;
} else {
2011-05-17 21:59:01 +04:00
__clear_chan_timer ( chan ) ;
__set_chan_timer ( chan , HZ / 10 ) ;
2008-07-14 22:13:54 +04:00
}
2011-06-03 07:19:47 +04:00
} else if ( chan - > state = = BT_CONNECT2 ) {
2008-07-14 22:13:54 +04:00
struct l2cap_conn_rsp rsp ;
2011-06-14 13:48:19 +04:00
__u16 res , stat ;
2005-04-17 02:20:36 +04:00
2008-07-14 22:13:54 +04:00
if ( ! status ) {
2011-06-14 13:48:19 +04:00
if ( bt_sk ( sk ) - > defer_setup ) {
struct sock * parent = bt_sk ( sk ) - > parent ;
res = L2CAP_CR_PEND ;
stat = L2CAP_CS_AUTHOR_PEND ;
2011-07-15 22:30:21 +04:00
if ( parent )
parent - > sk_data_ready ( parent , 0 ) ;
2011-06-14 13:48:19 +04:00
} else {
2011-06-21 21:52:56 +04:00
l2cap_state_change ( chan , BT_CONFIG ) ;
2011-06-14 13:48:19 +04:00
res = L2CAP_CR_SUCCESS ;
stat = L2CAP_CS_NO_INFO ;
}
2008-07-14 22:13:54 +04:00
} else {
2011-06-03 07:19:47 +04:00
l2cap_state_change ( chan , BT_DISCONN ) ;
2011-05-17 21:59:01 +04:00
__set_chan_timer ( chan , HZ / 10 ) ;
2011-06-14 13:48:19 +04:00
res = L2CAP_CR_SEC_BLOCK ;
stat = L2CAP_CS_NO_INFO ;
2008-07-14 22:13:54 +04:00
}
2011-04-14 02:50:45 +04:00
rsp . scid = cpu_to_le16 ( chan - > dcid ) ;
rsp . dcid = cpu_to_le16 ( chan - > scid ) ;
2011-06-14 13:48:19 +04:00
rsp . result = cpu_to_le16 ( res ) ;
rsp . status = cpu_to_le16 ( stat ) ;
2011-03-25 19:59:37 +03:00
l2cap_send_cmd ( conn , chan - > ident , L2CAP_CONN_RSP ,
sizeof ( rsp ) , & rsp ) ;
2008-07-14 22:13:54 +04:00
}
2005-04-17 02:20:36 +04:00
bh_unlock_sock ( sk ) ;
}
2011-03-31 23:17:41 +04:00
read_unlock ( & conn - > chan_lock ) ;
2008-07-14 22:13:54 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int l2cap_recv_acldata ( struct hci_conn * hcon , struct sk_buff * skb , u16 flags )
{
struct l2cap_conn * conn = hcon - > l2cap_data ;
2011-01-11 18:20:20 +03:00
if ( ! conn )
conn = l2cap_conn_add ( hcon , 0 ) ;
if ( ! conn )
2005-04-17 02:20:36 +04:00
goto drop ;
BT_DBG ( " conn %p len %d flags 0x%x " , conn , skb - > len , flags ) ;
2011-01-03 12:14:36 +03:00
if ( ! ( flags & ACL_CONT ) ) {
2005-04-17 02:20:36 +04:00
struct l2cap_hdr * hdr ;
2011-03-25 06:22:30 +03:00
struct l2cap_chan * chan ;
2010-09-15 15:28:44 +04:00
u16 cid ;
2005-04-17 02:20:36 +04:00
int len ;
if ( conn - > rx_len ) {
BT_ERR ( " Unexpected start frame (len %d) " , skb - > len ) ;
kfree_skb ( conn - > rx_skb ) ;
conn - > rx_skb = NULL ;
conn - > rx_len = 0 ;
l2cap_conn_unreliable ( conn , ECOMM ) ;
}
2010-09-15 15:28:43 +04:00
/* Start fragment always begin with Basic L2CAP header */
if ( skb - > len < L2CAP_HDR_SIZE ) {
2005-04-17 02:20:36 +04:00
BT_ERR ( " Frame is too short (len %d) " , skb - > len ) ;
l2cap_conn_unreliable ( conn , ECOMM ) ;
goto drop ;
}
hdr = ( struct l2cap_hdr * ) skb - > data ;
len = __le16_to_cpu ( hdr - > len ) + L2CAP_HDR_SIZE ;
2010-09-15 15:28:44 +04:00
cid = __le16_to_cpu ( hdr - > cid ) ;
2005-04-17 02:20:36 +04:00
if ( len = = skb - > len ) {
/* Complete frame received */
l2cap_recv_frame ( conn , skb ) ;
return 0 ;
}
BT_DBG ( " Start: total len %d, frag len %d " , len , skb - > len ) ;
if ( skb - > len > len ) {
BT_ERR ( " Frame is too long (len %d, expected len %d) " ,
skb - > len , len ) ;
l2cap_conn_unreliable ( conn , ECOMM ) ;
goto drop ;
}
2011-03-31 23:17:41 +04:00
chan = l2cap_get_chan_by_scid ( conn , cid ) ;
2010-09-15 15:28:44 +04:00
2011-03-25 06:22:30 +03:00
if ( chan & & chan - > sk ) {
struct sock * sk = chan - > sk ;
2010-09-15 15:28:44 +04:00
2011-04-14 00:20:49 +04:00
if ( chan - > imtu < len - L2CAP_HDR_SIZE ) {
2011-03-25 06:22:30 +03:00
BT_ERR ( " Frame exceeding recv MTU (len %d, "
" MTU %d) " , len ,
2011-04-14 00:20:49 +04:00
chan - > imtu ) ;
2011-03-25 06:22:30 +03:00
bh_unlock_sock ( sk ) ;
l2cap_conn_unreliable ( conn , ECOMM ) ;
goto drop ;
}
2010-09-15 15:28:44 +04:00
bh_unlock_sock ( sk ) ;
2011-03-25 06:22:30 +03:00
}
2010-09-15 15:28:44 +04:00
2005-04-17 02:20:36 +04:00
/* Allocate skb for the complete frame (with header) */
2009-04-20 08:31:08 +04:00
conn - > rx_skb = bt_skb_alloc ( len , GFP_ATOMIC ) ;
if ( ! conn - > rx_skb )
2005-04-17 02:20:36 +04:00
goto drop ;
2007-03-28 01:55:52 +04:00
skb_copy_from_linear_data ( skb , skb_put ( conn - > rx_skb , skb - > len ) ,
2009-02-09 11:18:02 +03:00
skb - > len ) ;
2005-04-17 02:20:36 +04:00
conn - > rx_len = len - skb - > len ;
} else {
BT_DBG ( " Cont: frag len %d (expecting %d) " , skb - > len , conn - > rx_len ) ;
if ( ! conn - > rx_len ) {
BT_ERR ( " Unexpected continuation frame (len %d) " , skb - > len ) ;
l2cap_conn_unreliable ( conn , ECOMM ) ;
goto drop ;
}
if ( skb - > len > conn - > rx_len ) {
BT_ERR ( " Fragment is too long (len %d, expected %d) " ,
skb - > len , conn - > rx_len ) ;
kfree_skb ( conn - > rx_skb ) ;
conn - > rx_skb = NULL ;
conn - > rx_len = 0 ;
l2cap_conn_unreliable ( conn , ECOMM ) ;
goto drop ;
}
2007-03-28 01:55:52 +04:00
skb_copy_from_linear_data ( skb , skb_put ( conn - > rx_skb , skb - > len ) ,
2009-02-09 11:18:02 +03:00
skb - > len ) ;
2005-04-17 02:20:36 +04:00
conn - > rx_len - = skb - > len ;
if ( ! conn - > rx_len ) {
/* Complete frame received */
l2cap_recv_frame ( conn , conn - > rx_skb ) ;
conn - > rx_skb = NULL ;
}
}
drop :
kfree_skb ( skb ) ;
return 0 ;
}
2010-03-21 07:27:45 +03:00
static int l2cap_debugfs_show ( struct seq_file * f , void * p )
2005-04-17 02:20:36 +04:00
{
2011-04-28 01:26:32 +04:00
struct l2cap_chan * c ;
2005-04-17 02:20:36 +04:00
2011-04-28 01:26:32 +04:00
read_lock_bh ( & chan_list_lock ) ;
2005-04-17 02:20:36 +04:00
2011-04-28 01:26:32 +04:00
list_for_each_entry ( c , & chan_list , global_l ) {
struct sock * sk = c - > sk ;
2010-03-16 00:12:58 +03:00
2011-02-10 19:16:06 +03:00
seq_printf ( f , " %s %s %d %d 0x%4.4x 0x%4.4x %d %d %d %d \n " ,
2010-03-21 07:27:45 +03:00
batostr ( & bt_sk ( sk ) - > src ) ,
batostr ( & bt_sk ( sk ) - > dst ) ,
2011-06-03 07:19:47 +04:00
c - > state , __le16_to_cpu ( c - > psm ) ,
2011-04-28 01:26:32 +04:00
c - > scid , c - > dcid , c - > imtu , c - > omtu ,
c - > sec_level , c - > mode ) ;
2011-06-21 21:52:56 +04:00
}
2005-04-17 02:20:36 +04:00
2011-04-28 01:26:32 +04:00
read_unlock_bh ( & chan_list_lock ) ;
2005-04-17 02:20:36 +04:00
2010-03-21 07:27:45 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2010-03-21 07:27:45 +03:00
static int l2cap_debugfs_open ( struct inode * inode , struct file * file )
{
return single_open ( file , l2cap_debugfs_show , inode - > i_private ) ;
}
static const struct file_operations l2cap_debugfs_fops = {
. open = l2cap_debugfs_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
} ;
static struct dentry * l2cap_debugfs ;
2005-04-17 02:20:36 +04:00
static struct hci_proto l2cap_hci_proto = {
. name = " L2CAP " ,
. id = HCI_PROTO_L2CAP ,
. connect_ind = l2cap_connect_ind ,
. connect_cfm = l2cap_connect_cfm ,
. disconn_ind = l2cap_disconn_ind ,
2009-02-12 16:02:50 +03:00
. disconn_cfm = l2cap_disconn_cfm ,
2009-01-15 23:58:04 +03:00
. security_cfm = l2cap_security_cfm ,
2005-04-17 02:20:36 +04:00
. recv_acldata = l2cap_recv_acldata
} ;
2011-02-08 01:08:52 +03:00
int __init l2cap_init ( void )
2005-04-17 02:20:36 +04:00
{
int err ;
2005-11-08 20:57:38 +03:00
2011-02-04 01:50:35 +03:00
err = l2cap_init_sockets ( ) ;
2005-04-17 02:20:36 +04:00
if ( err < 0 )
return err ;
err = hci_register_proto ( & l2cap_hci_proto ) ;
if ( err < 0 ) {
BT_ERR ( " L2CAP protocol registration failed " ) ;
bt_sock_unregister ( BTPROTO_L2CAP ) ;
goto error ;
}
2010-03-21 07:27:45 +03:00
if ( bt_debugfs ) {
l2cap_debugfs = debugfs_create_file ( " l2cap " , 0444 ,
bt_debugfs , NULL , & l2cap_debugfs_fops ) ;
if ( ! l2cap_debugfs )
BT_ERR ( " Failed to create L2CAP debug file " ) ;
}
2005-04-17 02:20:36 +04:00
return 0 ;
error :
2011-02-04 01:50:35 +03:00
l2cap_cleanup_sockets ( ) ;
2005-04-17 02:20:36 +04:00
return err ;
}
2011-02-08 01:08:52 +03:00
void l2cap_exit ( void )
2005-04-17 02:20:36 +04:00
{
2010-03-21 07:27:45 +03:00
debugfs_remove ( l2cap_debugfs ) ;
2005-04-17 02:20:36 +04:00
if ( hci_unregister_proto ( & l2cap_hci_proto ) < 0 )
BT_ERR ( " L2CAP protocol unregistration failed " ) ;
2011-02-04 01:50:35 +03:00
l2cap_cleanup_sockets ( ) ;
2005-04-17 02:20:36 +04:00
}
2010-07-18 23:25:54 +04:00
module_param ( disable_ertm , bool , 0644 ) ;
MODULE_PARM_DESC ( disable_ertm , " Disable enhanced retransmission mode " ) ;