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