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 #include <com_android_bluetooth_flags.h>
23 
24 #include <cstdint>
25 
26 #include "bta/jv/bta_jv_int.h"      // tBTA_JV_CB
27 #include "stack/include/rfcdefs.h"  // RFCOMM_MAX_SCN
28 
29 using namespace bluetooth;
30 
31 extern tBTA_JV_CB bta_jv_cb;
32 
33 /*******************************************************************************
34  *
35  * Function         BTA_AllocateSCN
36  *
37  * Description      Look through the Server Channel Numbers for a free one.
38  *
39  * Returns          Allocated SCN or 0 if none.
40  *
41  ******************************************************************************/
BTA_AllocateSCN(void)42 uint8_t BTA_AllocateSCN(void) {
43   // SCN can be allocated in the range of [1, RFCOMM_MAX_SCN]
44   // btm_scn uses indexes 0 to RFCOMM_MAX_SCN-1 to track RFC ports
45   for (uint8_t i = bta_jv_cb.scn_search_index; i < RFCOMM_MAX_SCN; ++i) {
46     if (!bta_jv_cb.scn_in_use[i]) {
47       bta_jv_cb.scn_in_use[i] = true;
48       bta_jv_cb.scn_search_index = (i + 1);
49       log::debug("Allocating scn: {}", i + 1);
50       return i + 1;  // allocated scn is index + 1
51     }
52   }
53 
54   // In order to avoid OOB, scn_search_index must be no more than
55   // RFCOMM_MAX_SCN.
56   bta_jv_cb.scn_search_index = 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::warn("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)) {
87     return false;
88   }
89 
90   /* check if this scn is available */
91   if (!bta_jv_cb.scn_in_use[scn - 1]) {
92     bta_jv_cb.scn_in_use[scn - 1] = true;
93     log::debug("Allocating scn: {}", scn);
94     return true;
95   }
96   log::debug("Unable to allocate scn {}", scn);
97   return false; /* scn was busy */
98 }
99 
100 /*******************************************************************************
101  *
102  * Function         BTA_FreeSCN
103  *
104  * Description      Free the specified SCN.
105  *
106  * Returns          true if SCN was freed, false if SCN was invalid
107  *
108  ******************************************************************************/
BTA_FreeSCN(uint8_t scn)109 bool BTA_FreeSCN(uint8_t scn) {
110   /* Since this isn't used by HFP, this function will only free valid SCNs
111    * that aren't reserved for HFP, which is range [2, RFCOMM_MAX_SCN].
112    */
113 
114   if (com::android::bluetooth::flags::allow_free_last_scn()) {
115     if (scn <= RFCOMM_MAX_SCN && scn > 1) {
116       bta_jv_cb.scn_in_use[scn - 1] = false;
117       log::debug("Freed SCN: {}", scn);
118       return true;
119     }
120   } else {
121     if (scn < RFCOMM_MAX_SCN && scn > 1) {
122       bta_jv_cb.scn_in_use[scn - 1] = false;
123       log::debug("Freed SCN: {}", scn);
124       return true;
125     }
126   }
127 
128   log::warn("Invalid SCN: {}", scn);
129   return false; /* Illegal SCN passed in */
130 }
131