1 /*
2  * Copyright 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "bta/include/bta_rfcomm_scn.h"
18 
19 #define LOG_TAG "bta"
20 
21 #include <bluetooth/log.h>
22 
23 #include <cstdint>
24 
25 #include "bta/jv/bta_jv_int.h"      // tBTA_JV_CB
26 #include "stack/include/rfcdefs.h"  // RFCOMM_MAX_SCN
27 
28 using namespace bluetooth;
29 
30 extern tBTA_JV_CB bta_jv_cb;
31 
32 /*******************************************************************************
33  *
34  * Function         BTA_AllocateSCN
35  *
36  * Description      Look through the Server Channel Numbers for a free one.
37  *
38  * Returns          Allocated SCN or 0 if none.
39  *
40  ******************************************************************************/
BTA_AllocateSCN(void)41 uint8_t BTA_AllocateSCN(void) {
42   // SCN can be allocated in the range of [1, RFCOMM_MAX_SCN]
43   // btm_scn uses indexes 0 to RFCOMM_MAX_SCN-1 to track RFC ports
44   for (uint8_t i = bta_jv_cb.scn_search_index; i < RFCOMM_MAX_SCN; ++i) {
45     if (!bta_jv_cb.scn_in_use[i]) {
46       bta_jv_cb.scn_in_use[i] = true;
47       bta_jv_cb.scn_search_index = (i + 1);
48       log::debug("Allocating scn: {}", i + 1);
49       return (i + 1);  // allocated scn is index + 1
50     }
51   }
52 
53   // In order to avoid OOB, scn_search_index must be no more than
54   // RFCOMM_MAX_SCN.
55   bta_jv_cb.scn_search_index =
56       std::min(bta_jv_cb.scn_search_index, (uint8_t)(RFCOMM_MAX_SCN));
57 
58   // If there's no empty SCN from scn_search_index to RFCOMM_MAX_SCN
59   // Start from index 1 because index 0 (scn 1) is reserved for HFP
60   for (uint8_t i = 1; i < bta_jv_cb.scn_search_index; ++i) {
61     if (!bta_jv_cb.scn_in_use[i]) {
62       bta_jv_cb.scn_in_use[i] = true;
63       bta_jv_cb.scn_search_index = (i + 1);
64       log::debug("Allocating scn: {}", i + 1);
65       return (i + 1);  // allocated scn is index + 1
66     }
67   }
68   log::debug("Unable to allocate an scn");
69   return (0); /* No free ports */
70 }
71 
72 /*******************************************************************************
73  *
74  * Function         BTA_TryAllocateSCN
75  *
76  * Description      Try to allocate a fixed server channel
77  *
78  * Returns          true if SCN was available, false otherwise
79  *
80  ******************************************************************************/
81 
BTA_TryAllocateSCN(uint8_t scn)82 bool BTA_TryAllocateSCN(uint8_t scn) {
83   /* Make sure we don't exceed max scn range.
84    * Stack reserves scn 1 for HFP and HSP
85    */
86   if ((scn > RFCOMM_MAX_SCN) || (scn == 1) || (scn == 0)) return false;
87 
88   /* check if this scn is available */
89   if (!bta_jv_cb.scn_in_use[scn - 1]) {
90     bta_jv_cb.scn_in_use[scn - 1] = true;
91     log::debug("Allocating scn: {}", scn);
92     return true;
93   }
94   log::debug("Unable to allocate scn {}", scn);
95   return (false); /* scn was busy */
96 }
97 
98 /*******************************************************************************
99  *
100  * Function         BTA_FreeSCN
101  *
102  * Description      Free the specified SCN.
103  *
104  * Returns          true if SCN was freed, false if SCN was invalid
105  *
106  ******************************************************************************/
BTA_FreeSCN(uint8_t scn)107 bool BTA_FreeSCN(uint8_t scn) {
108   /* Since this isn't used by HFP, this function will only free valid SCNs
109    * that aren't reserved for HFP, which is range [2, RFCOMM_MAX_SCN].
110    */
111   if (scn < RFCOMM_MAX_SCN && scn > 1) {
112     bta_jv_cb.scn_in_use[scn - 1] = false;
113     log::debug("Freed SCN: {}", scn);
114     return (true);
115   } else {
116     log::warn("Invalid SCN: {}", scn);
117     return (false); /* Illegal SCN passed in */
118   }
119 }
120