@ -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 + + ;
}
@ -2977,12 +2977,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 ;
@ -3007,7 +3010,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 ;
@ -3035,7 +3038,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 )
@ -3181,11 +3184,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 ) ;
@ -3210,7 +3214,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 :
@ -3229,7 +3233,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 :
@ -3249,21 +3253,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 ;
@ -3281,17 +3285,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 ;
}
@ -3302,10 +3306,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 ;
@ -3407,7 +3412,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 ) {
@ -3420,7 +3425,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 & &
@ -3434,7 +3439,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 ;
@ -3467,7 +3472,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 ;
@ -3481,7 +3486,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 ;
@ -3495,7 +3500,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 ;
@ -3517,10 +3522,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 } ;
@ -3538,13 +3544,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 :
@ -3558,13 +3564,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 :
@ -3577,7 +3583,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 :
@ -3682,7 +3688,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 + + ;
}
@ -3890,7 +3896,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 + + ;
}
@ -3968,7 +3974,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 ;
@ -4080,7 +4086,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 ;
@ -4114,7 +4120,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 + + ;
}
@ -4174,7 +4180,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 ;
@ -4204,7 +4210,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 ;
@ -4781,7 +4787,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 + + ;
}
}
@ -7457,7 +7463,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 + + ;
}