@ -58,7 +58,7 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
u8 code , u8 ident , u16 dlen , void * data ) ;
static void l2cap_send_cmd ( struct l2cap_conn * conn , u8 ident , u8 code , u16 len ,
void * data ) ;
static int l2cap_build_conf_req ( struct l2cap_chan * chan , void * data );
static int l2cap_build_conf_req ( struct l2cap_chan * chan , void * data , size_t data_size );
static void l2cap_send_disconn_req ( struct l2cap_chan * chan , int err ) ;
static void l2cap_tx ( struct l2cap_chan * chan , struct l2cap_ctrl * control ,
@ -1473,7 +1473,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
set_bit ( CONF_REQ_SENT , & chan - > conf_state ) ;
l2cap_send_cmd ( conn , l2cap_get_ident ( conn ) , L2CAP_CONF_REQ ,
l2cap_build_conf_req ( chan , buf ), buf ) ;
l2cap_build_conf_req ( chan , buf , sizeof ( buf ) ), buf ) ;
chan - > num_conf_req + + ;
}
@ -2987,12 +2987,15 @@ static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen,
return len ;
}
static void l2cap_add_conf_opt ( void * * ptr , u8 type , u8 len , unsigned long val )
static void l2cap_add_conf_opt ( void * * ptr , u8 type , u8 len , unsigned long val , size_t size )
{
struct l2cap_conf_opt * opt = * ptr ;
BT_DBG ( " type 0x%2.2x len %u val 0x%lx " , type , len , val ) ;
if ( size < L2CAP_CONF_OPT_SIZE + len )
return ;
opt - > type = type ;
opt - > len = len ;
@ -3017,7 +3020,7 @@ static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
* ptr + = L2CAP_CONF_OPT_SIZE + len ;
}
static void l2cap_add_opt_efs ( void * * ptr , struct l2cap_chan * chan )
static void l2cap_add_opt_efs ( void * * ptr , struct l2cap_chan * chan , size_t size )
{
struct l2cap_conf_efs efs ;
@ -3045,7 +3048,7 @@ static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
}
l2cap_add_conf_opt ( ptr , L2CAP_CONF_EFS , sizeof ( efs ) ,
( unsigned long ) & efs );
( unsigned long ) & efs , size );
}
static void l2cap_ack_timeout ( struct work_struct * work )
@ -3191,11 +3194,12 @@ static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
chan - > ack_win = chan - > tx_win ;
}
static int l2cap_build_conf_req ( struct l2cap_chan * chan , void * data )
static int l2cap_build_conf_req ( struct l2cap_chan * chan , void * data , size_t data_size )
{
struct l2cap_conf_req * req = data ;
struct l2cap_conf_rfc rfc = { . mode = chan - > mode } ;
void * ptr = req - > data ;
void * endptr = data + data_size ;
u16 size ;
BT_DBG ( " chan %p " , chan ) ;
@ -3220,7 +3224,7 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
done :
if ( chan - > imtu ! = L2CAP_DEFAULT_MTU )
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_MTU , 2 , chan - > imtu );
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_MTU , 2 , chan - > imtu , endptr - ptr );
switch ( chan - > mode ) {
case L2CAP_MODE_BASIC :
@ -3239,7 +3243,7 @@ done:
rfc . max_pdu_size = 0 ;
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_RFC , sizeof ( rfc ) ,
( unsigned long ) & rfc );
( unsigned long ) & rfc , endptr - ptr );
break ;
case L2CAP_MODE_ERTM :
@ -3259,21 +3263,21 @@ done:
L2CAP_DEFAULT_TX_WINDOW ) ;
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_RFC , sizeof ( rfc ) ,
( unsigned long ) & rfc );
( unsigned long ) & rfc , endptr - ptr );
if ( test_bit ( FLAG_EFS_ENABLE , & chan - > flags ) )
l2cap_add_opt_efs ( & ptr , chan );
l2cap_add_opt_efs ( & ptr , chan , endptr - ptr );
if ( test_bit ( FLAG_EXT_CTRL , & chan - > flags ) )
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_EWS , 2 ,
chan - > tx_win );
chan - > tx_win , endptr - ptr );
if ( chan - > conn - > feat_mask & L2CAP_FEAT_FCS )
if ( chan - > fcs = = L2CAP_FCS_NONE | |
test_bit ( CONF_RECV_NO_FCS , & chan - > conf_state ) ) {
chan - > fcs = L2CAP_FCS_NONE ;
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_FCS , 1 ,
chan - > fcs );
chan - > fcs , endptr - ptr );
}
break ;
@ -3291,17 +3295,17 @@ done:
rfc . max_pdu_size = cpu_to_le16 ( size ) ;
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_RFC , sizeof ( rfc ) ,
( unsigned long ) & rfc );
( unsigned long ) & rfc , endptr - ptr );
if ( test_bit ( FLAG_EFS_ENABLE , & chan - > flags ) )
l2cap_add_opt_efs ( & ptr , chan );
l2cap_add_opt_efs ( & ptr , chan , endptr - ptr );
if ( chan - > conn - > feat_mask & L2CAP_FEAT_FCS )
if ( chan - > fcs = = L2CAP_FCS_NONE | |
test_bit ( CONF_RECV_NO_FCS , & chan - > conf_state ) ) {
chan - > fcs = L2CAP_FCS_NONE ;
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_FCS , 1 ,
chan - > fcs );
chan - > fcs , endptr - ptr );
}
break ;
}
@ -3312,10 +3316,11 @@ done:
return ptr - data ;
}
static int l2cap_parse_conf_req ( struct l2cap_chan * chan , void * data )
static int l2cap_parse_conf_req ( struct l2cap_chan * chan , void * data , size_t data_size )
{
struct l2cap_conf_rsp * rsp = data ;
void * ptr = rsp - > data ;
void * endptr = data + data_size ;
void * req = chan - > conf_req ;
int len = chan - > conf_len ;
int type , hint , olen ;
@ -3417,7 +3422,7 @@ done:
return - ECONNREFUSED ;
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_RFC , sizeof ( rfc ) ,
( unsigned long ) & rfc );
( unsigned long ) & rfc , endptr - ptr );
}
if ( result = = L2CAP_CONF_SUCCESS ) {
@ -3430,7 +3435,7 @@ done:
chan - > omtu = mtu ;
set_bit ( CONF_MTU_DONE , & chan - > conf_state ) ;
}
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_MTU , 2 , chan - > omtu );
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_MTU , 2 , chan - > omtu , endptr - ptr );
if ( remote_efs ) {
if ( chan - > local_stype ! = L2CAP_SERV_NOTRAFIC & &
@ -3444,7 +3449,7 @@ done:
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_EFS ,
sizeof ( efs ) ,
( unsigned long ) & efs );
( unsigned long ) & efs , endptr - ptr );
} else {
/* Send PENDING Conf Rsp */
result = L2CAP_CONF_PENDING ;
@ -3477,7 +3482,7 @@ done:
set_bit ( CONF_MODE_DONE , & chan - > conf_state ) ;
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_RFC ,
sizeof ( rfc ) , ( unsigned long ) & rfc );
sizeof ( rfc ) , ( unsigned long ) & rfc , endptr - ptr );
if ( test_bit ( FLAG_EFS_ENABLE , & chan - > flags ) ) {
chan - > remote_id = efs . id ;
@ -3491,7 +3496,7 @@ done:
le32_to_cpu ( efs . sdu_itime ) ;
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_EFS ,
sizeof ( efs ) ,
( unsigned long ) & efs );
( unsigned long ) & efs , endptr - ptr );
}
break ;
@ -3505,7 +3510,7 @@ done:
set_bit ( CONF_MODE_DONE , & chan - > conf_state ) ;
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_RFC , sizeof ( rfc ) ,
( unsigned long ) & rfc );
( unsigned long ) & rfc , endptr - ptr );
break ;
@ -3527,10 +3532,11 @@ done:
}
static int l2cap_parse_conf_rsp ( struct l2cap_chan * chan , void * rsp , int len ,
void * data , u16 * result )
void * data , size_t size , u16 * result )
{
struct l2cap_conf_req * req = data ;
void * ptr = req - > data ;
void * endptr = data + size ;
int type , olen ;
unsigned long val ;
struct l2cap_conf_rfc rfc = { . mode = L2CAP_MODE_BASIC } ;
@ -3548,13 +3554,13 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
chan - > imtu = L2CAP_DEFAULT_MIN_MTU ;
} else
chan - > imtu = val ;
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_MTU , 2 , chan - > imtu );
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_MTU , 2 , chan - > imtu , endptr - ptr );
break ;
case L2CAP_CONF_FLUSH_TO :
chan - > flush_to = val ;
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_FLUSH_TO ,
2 , chan - > flush_to );
2 , chan - > flush_to , endptr - ptr );
break ;
case L2CAP_CONF_RFC :
@ -3568,13 +3574,13 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
chan - > fcs = 0 ;
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_RFC ,
sizeof ( rfc ) , ( unsigned long ) & rfc );
sizeof ( rfc ) , ( unsigned long ) & rfc , endptr - ptr );
break ;
case L2CAP_CONF_EWS :
chan - > ack_win = min_t ( u16 , val , chan - > ack_win ) ;
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_EWS , 2 ,
chan - > tx_win );
chan - > tx_win , endptr - ptr );
break ;
case L2CAP_CONF_EFS :
@ -3587,7 +3593,7 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
return - ECONNREFUSED ;
l2cap_add_conf_opt ( & ptr , L2CAP_CONF_EFS , sizeof ( efs ) ,
( unsigned long ) & efs );
( unsigned long ) & efs , endptr - ptr );
break ;
case L2CAP_CONF_FCS :
@ -3692,7 +3698,7 @@ void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
return ;
l2cap_send_cmd ( conn , l2cap_get_ident ( conn ) , L2CAP_CONF_REQ ,
l2cap_build_conf_req ( chan , buf ), buf ) ;
l2cap_build_conf_req ( chan , buf , sizeof ( buf ) ), buf ) ;
chan - > num_conf_req + + ;
}
@ -3900,7 +3906,7 @@ sendresp:
u8 buf [ 128 ] ;
set_bit ( CONF_REQ_SENT , & chan - > conf_state ) ;
l2cap_send_cmd ( conn , l2cap_get_ident ( conn ) , L2CAP_CONF_REQ ,
l2cap_build_conf_req ( chan , buf ), buf ) ;
l2cap_build_conf_req ( chan , buf , sizeof ( buf ) ), buf ) ;
chan - > num_conf_req + + ;
}
@ -3978,7 +3984,7 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
break ;
l2cap_send_cmd ( conn , l2cap_get_ident ( conn ) , L2CAP_CONF_REQ ,
l2cap_build_conf_req ( chan , req ), req ) ;
l2cap_build_conf_req ( chan , req , sizeof ( req ) ), req ) ;
chan - > num_conf_req + + ;
break ;
@ -4090,7 +4096,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
}
/* Complete config. */
len = l2cap_parse_conf_req ( chan , rsp );
len = l2cap_parse_conf_req ( chan , rsp , sizeof ( rsp ) );
if ( len < 0 ) {
l2cap_send_disconn_req ( chan , ECONNRESET ) ;
goto unlock ;
@ -4124,7 +4130,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
if ( ! test_and_set_bit ( CONF_REQ_SENT , & chan - > conf_state ) ) {
u8 buf [ 64 ] ;
l2cap_send_cmd ( conn , l2cap_get_ident ( conn ) , L2CAP_CONF_REQ ,
l2cap_build_conf_req ( chan , buf ), buf ) ;
l2cap_build_conf_req ( chan , buf , sizeof ( buf ) ), buf ) ;
chan - > num_conf_req + + ;
}
@ -4184,7 +4190,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
char buf [ 64 ] ;
len = l2cap_parse_conf_rsp ( chan , rsp - > data , len ,
buf , & result ) ;
buf , sizeof ( buf ) , & result ) ;
if ( len < 0 ) {
l2cap_send_disconn_req ( chan , ECONNRESET ) ;
goto done ;
@ -4214,7 +4220,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
/* throw out any old stored conf requests */
result = L2CAP_CONF_SUCCESS ;
len = l2cap_parse_conf_rsp ( chan , rsp - > data , len ,
req , & result ) ;
req , sizeof ( req ) , & result ) ;
if ( len < 0 ) {
l2cap_send_disconn_req ( chan , ECONNRESET ) ;
goto done ;
@ -4791,7 +4797,7 @@ static void l2cap_do_create(struct l2cap_chan *chan, int result,
set_bit ( CONF_REQ_SENT , & chan - > conf_state ) ;
l2cap_send_cmd ( chan - > conn , l2cap_get_ident ( chan - > conn ) ,
L2CAP_CONF_REQ ,
l2cap_build_conf_req ( chan , buf ), buf ) ;
l2cap_build_conf_req ( chan , buf , sizeof ( buf ) ), buf ) ;
chan - > num_conf_req + + ;
}
}
@ -7465,7 +7471,7 @@ static void l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
set_bit ( CONF_REQ_SENT , & chan - > conf_state ) ;
l2cap_send_cmd ( conn , l2cap_get_ident ( conn ) ,
L2CAP_CONF_REQ ,
l2cap_build_conf_req ( chan , buf ),
l2cap_build_conf_req ( chan , buf , sizeof ( buf ) ),
buf ) ;
chan - > num_conf_req + + ;
}