@@ -4916,6 +4916,13 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
49164916 goto response_unlock ;
49174917 }
49184918
4919+ /* Check if Key Size is sufficient for the security level */
4920+ if (!l2cap_check_enc_key_size (conn -> hcon , pchan )) {
4921+ result = L2CAP_CR_LE_BAD_KEY_SIZE ;
4922+ chan = NULL ;
4923+ goto response_unlock ;
4924+ }
4925+
49194926 /* Check for valid dynamic CID range */
49204927 if (scid < L2CAP_CID_DYN_START || scid > L2CAP_CID_LE_DYN_END ) {
49214928 result = L2CAP_CR_LE_INVALID_SCID ;
@@ -5051,13 +5058,15 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
50515058 struct l2cap_chan * chan , * pchan ;
50525059 u16 mtu , mps ;
50535060 __le16 psm ;
5054- u8 result , len = 0 ;
5061+ u8 result , rsp_len = 0 ;
50555062 int i , num_scid ;
50565063 bool defer = false;
50575064
50585065 if (!enable_ecred )
50595066 return - EINVAL ;
50605067
5068+ memset (pdu , 0 , sizeof (* pdu ));
5069+
50615070 if (cmd_len < sizeof (* req ) || (cmd_len - sizeof (* req )) % sizeof (u16 )) {
50625071 result = L2CAP_CR_LE_INVALID_PARAMS ;
50635072 goto response ;
@@ -5066,6 +5075,9 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
50665075 cmd_len -= sizeof (* req );
50675076 num_scid = cmd_len / sizeof (u16 );
50685077
5078+ /* Always respond with the same number of scids as in the request */
5079+ rsp_len = cmd_len ;
5080+
50695081 if (num_scid > L2CAP_ECRED_MAX_CID ) {
50705082 result = L2CAP_CR_LE_INVALID_PARAMS ;
50715083 goto response ;
@@ -5075,7 +5087,7 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
50755087 mps = __le16_to_cpu (req -> mps );
50765088
50775089 if (mtu < L2CAP_ECRED_MIN_MTU || mps < L2CAP_ECRED_MIN_MPS ) {
5078- result = L2CAP_CR_LE_UNACCEPT_PARAMS ;
5090+ result = L2CAP_CR_LE_INVALID_PARAMS ;
50795091 goto response ;
50805092 }
50815093
@@ -5095,8 +5107,6 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
50955107
50965108 BT_DBG ("psm 0x%2.2x mtu %u mps %u" , __le16_to_cpu (psm ), mtu , mps );
50975109
5098- memset (pdu , 0 , sizeof (* pdu ));
5099-
51005110 /* Check if we have socket listening on psm */
51015111 pchan = l2cap_global_chan_by_psm (BT_LISTEN , psm , & conn -> hcon -> src ,
51025112 & conn -> hcon -> dst , LE_LINK );
@@ -5109,7 +5119,16 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
51095119
51105120 if (!smp_sufficient_security (conn -> hcon , pchan -> sec_level ,
51115121 SMP_ALLOW_STK )) {
5112- result = L2CAP_CR_LE_AUTHENTICATION ;
5122+ result = pchan -> sec_level == BT_SECURITY_MEDIUM ?
5123+ L2CAP_CR_LE_ENCRYPTION : L2CAP_CR_LE_AUTHENTICATION ;
5124+ goto unlock ;
5125+ }
5126+
5127+ /* Check if the listening channel has set an output MTU then the
5128+ * requested MTU shall be less than or equal to that value.
5129+ */
5130+ if (pchan -> omtu && mtu < pchan -> omtu ) {
5131+ result = L2CAP_CR_LE_UNACCEPT_PARAMS ;
51135132 goto unlock ;
51145133 }
51155134
@@ -5121,7 +5140,6 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
51215140 BT_DBG ("scid[%d] 0x%4.4x" , i , scid );
51225141
51235142 pdu -> dcid [i ] = 0x0000 ;
5124- len += sizeof (* pdu -> dcid );
51255143
51265144 /* Check for valid dynamic CID range */
51275145 if (scid < L2CAP_CID_DYN_START || scid > L2CAP_CID_LE_DYN_END ) {
@@ -5188,7 +5206,7 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
51885206 return 0 ;
51895207
51905208 l2cap_send_cmd (conn , cmd -> ident , L2CAP_ECRED_CONN_RSP ,
5191- sizeof (* pdu ) + len , pdu );
5209+ sizeof (* pdu ) + rsp_len , pdu );
51925210
51935211 return 0 ;
51945212}
@@ -5310,14 +5328,14 @@ static inline int l2cap_ecred_reconf_req(struct l2cap_conn *conn,
53105328 struct l2cap_ecred_reconf_req * req = (void * ) data ;
53115329 struct l2cap_ecred_reconf_rsp rsp ;
53125330 u16 mtu , mps , result ;
5313- struct l2cap_chan * chan ;
5331+ struct l2cap_chan * chan [ L2CAP_ECRED_MAX_CID ] = {} ;
53145332 int i , num_scid ;
53155333
53165334 if (!enable_ecred )
53175335 return - EINVAL ;
53185336
5319- if (cmd_len < sizeof (* req ) || cmd_len - sizeof (* req ) % sizeof (u16 )) {
5320- result = L2CAP_CR_LE_INVALID_PARAMS ;
5337+ if (cmd_len < sizeof (* req ) || ( cmd_len - sizeof (* req ) ) % sizeof (u16 )) {
5338+ result = L2CAP_RECONF_INVALID_CID ;
53215339 goto respond ;
53225340 }
53235341
@@ -5327,42 +5345,69 @@ static inline int l2cap_ecred_reconf_req(struct l2cap_conn *conn,
53275345 BT_DBG ("mtu %u mps %u" , mtu , mps );
53285346
53295347 if (mtu < L2CAP_ECRED_MIN_MTU ) {
5330- result = L2CAP_RECONF_INVALID_MTU ;
5348+ result = L2CAP_RECONF_INVALID_PARAMS ;
53315349 goto respond ;
53325350 }
53335351
53345352 if (mps < L2CAP_ECRED_MIN_MPS ) {
5335- result = L2CAP_RECONF_INVALID_MPS ;
5353+ result = L2CAP_RECONF_INVALID_PARAMS ;
53365354 goto respond ;
53375355 }
53385356
53395357 cmd_len -= sizeof (* req );
53405358 num_scid = cmd_len / sizeof (u16 );
5359+
5360+ if (num_scid > L2CAP_ECRED_MAX_CID ) {
5361+ result = L2CAP_RECONF_INVALID_PARAMS ;
5362+ goto respond ;
5363+ }
5364+
53415365 result = L2CAP_RECONF_SUCCESS ;
53425366
5367+ /* Check if each SCID, MTU and MPS are valid */
53435368 for (i = 0 ; i < num_scid ; i ++ ) {
53445369 u16 scid ;
53455370
53465371 scid = __le16_to_cpu (req -> scid [i ]);
5347- if (!scid )
5348- return - EPROTO ;
5372+ if (!scid ) {
5373+ result = L2CAP_RECONF_INVALID_CID ;
5374+ goto respond ;
5375+ }
53495376
5350- chan = __l2cap_get_chan_by_dcid (conn , scid );
5351- if (!chan )
5352- continue ;
5377+ chan [i ] = __l2cap_get_chan_by_dcid (conn , scid );
5378+ if (!chan [i ]) {
5379+ result = L2CAP_RECONF_INVALID_CID ;
5380+ goto respond ;
5381+ }
53535382
5354- /* If the MTU value is decreased for any of the included
5355- * channels, then the receiver shall disconnect all
5356- * included channels.
5383+ /* The MTU field shall be greater than or equal to the greatest
5384+ * current MTU size of these channels.
53575385 */
5358- if (chan -> omtu > mtu ) {
5359- BT_ERR ("chan %p decreased MTU %u -> %u" , chan ,
5360- chan -> omtu , mtu );
5386+ if (chan [ i ] -> omtu > mtu ) {
5387+ BT_ERR ("chan %p decreased MTU %u -> %u" , chan [ i ] ,
5388+ chan [ i ] -> omtu , mtu );
53615389 result = L2CAP_RECONF_INVALID_MTU ;
5390+ goto respond ;
53625391 }
53635392
5364- chan -> omtu = mtu ;
5365- chan -> remote_mps = mps ;
5393+ /* If more than one channel is being configured, the MPS field
5394+ * shall be greater than or equal to the current MPS size of
5395+ * each of these channels. If only one channel is being
5396+ * configured, the MPS field may be less than the current MPS
5397+ * of that channel.
5398+ */
5399+ if (chan [i ]-> remote_mps >= mps && i ) {
5400+ BT_ERR ("chan %p decreased MPS %u -> %u" , chan [i ],
5401+ chan [i ]-> remote_mps , mps );
5402+ result = L2CAP_RECONF_INVALID_MPS ;
5403+ goto respond ;
5404+ }
5405+ }
5406+
5407+ /* Commit the new MTU and MPS values after checking they are valid */
5408+ for (i = 0 ; i < num_scid ; i ++ ) {
5409+ chan [i ]-> omtu = mtu ;
5410+ chan [i ]-> remote_mps = mps ;
53665411 }
53675412
53685413respond :
0 commit comments