1 /******************************************************************************
2 *
3 * Copyright 1999-2012 Broadcom Corporation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 /*****************************************************************************
20 *
21 * This file contains functions callable by an application
22 * running on top of RFCOMM
23 *
24 *****************************************************************************/
25
26 #define LOG_TAG "rfcomm"
27
28 #include <bluetooth/log.h>
29 #include <com_android_bluetooth_flags.h>
30
31 #include <cstdint>
32 #include <unordered_map>
33
34 #include "stack/include/bt_hdr.h"
35 #include "stack/rfcomm/port_int.h"
36 #include "stack/rfcomm/rfc_int.h"
37 #include "stack/rfcomm/rfc_state.h"
38
39 using namespace bluetooth;
40
41 tRFC_CB rfc_cb;
42 std::unordered_map<uint16_t /* sci */, tRFC_MCB*> rfc_lcid_mcb;
43
44 /*******************************************************************************
45 *
46 * Function RFCOMM_StartReq
47 *
48 * Description This function handles Start Request from the upper layer.
49 * If RFCOMM multiplexer channel can not be allocated
50 * send start not accepted confirmation. Otherwise dispatch
51 * start event to the state machine.
52 *
53 ******************************************************************************/
RFCOMM_StartReq(tRFC_MCB * p_mcb)54 void RFCOMM_StartReq(tRFC_MCB* p_mcb) { rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_START_REQ, nullptr); }
55
56 /*******************************************************************************
57 *
58 * Function RFCOMM_StartRsp
59 *
60 * Description This function handles Start Response from the upper layer.
61 * Save upper layer handle and result of the Start Indication
62 * in the control block and dispatch event to the FSM.
63 *
64 ******************************************************************************/
RFCOMM_StartRsp(tRFC_MCB * p_mcb,uint16_t result)65 void RFCOMM_StartRsp(tRFC_MCB* p_mcb, uint16_t result) {
66 rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_START_RSP, &result);
67 }
68
69 /*******************************************************************************
70 *
71 * Function RFCOMM_DlcEstablishReq
72 *
73 * Description This function is called by the user app to establish
74 * connection with the specific dlci on a specific bd device.
75 * It will allocate RFCOMM connection control block if not
76 * allocated before and dispatch open event to the state
77 * machine.
78 *
79 ******************************************************************************/
RFCOMM_DlcEstablishReq(tRFC_MCB * p_mcb,uint8_t dlci,uint16_t)80 void RFCOMM_DlcEstablishReq(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t /* mtu */) {
81 if (p_mcb->state != RFC_MX_STATE_CONNECTED) {
82 PORT_DlcEstablishCnf(p_mcb, dlci, 0, RFCOMM_ERROR);
83 return;
84 }
85
86 tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
87 if (p_port == nullptr) {
88 log::warn("Unable to find DLCI port dlci:{}", dlci);
89 return;
90 }
91
92 rfc_port_sm_execute(p_port, RFC_PORT_EVENT_OPEN, nullptr);
93 }
94
95 /*******************************************************************************
96 *
97 * Function RFCOMM_DlcEstablishRsp
98 *
99 * Description This function is called by the port emulation entity
100 * acks Establish Indication.
101 *
102 ******************************************************************************/
RFCOMM_DlcEstablishRsp(tRFC_MCB * p_mcb,uint8_t dlci,uint16_t,uint16_t result)103 void RFCOMM_DlcEstablishRsp(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t /* mtu */, uint16_t result) {
104 if ((p_mcb->state != RFC_MX_STATE_CONNECTED) && (result == RFCOMM_SUCCESS)) {
105 PORT_DlcReleaseInd(p_mcb, dlci);
106 return;
107 }
108
109 tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
110 if (p_port == nullptr) {
111 log::warn("Unable to find DLCI port dlci:{}", dlci);
112 return;
113 }
114 rfc_port_sm_execute(p_port, RFC_PORT_EVENT_ESTABLISH_RSP, &result);
115 }
116
117 /*******************************************************************************
118 *
119 * Function RFCOMM_ParameterNegotiationRequest
120 *
121 * Description This function is called by the user app to start
122 * DLC parameter negotiation. Port emulation can send this
123 * request before actually establishing the DLC. In this
124 * case the function will allocate RFCOMM connection control
125 * block.
126 *
127 ******************************************************************************/
RFCOMM_ParameterNegotiationRequest(tRFC_MCB * p_mcb,uint8_t dlci,uint16_t mtu)128 void RFCOMM_ParameterNegotiationRequest(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu) {
129 uint8_t flow;
130 uint8_t cl;
131 uint8_t k;
132
133 tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
134 if (p_port == nullptr) {
135 log::warn("Unable to find DLCI port dlci:{}", dlci);
136 return;
137 }
138
139 if (p_mcb->state != RFC_MX_STATE_CONNECTED) {
140 log::warn("Multiplexer is in unexpected dlci:{} state:{}", dlci,
141 rfcomm_mx_state_text(p_mcb->state).c_str());
142 return;
143 }
144
145 /* Negotiate the flow control mechanism. If flow control mechanism for the
146 * mux has not been set yet, use credits. If it has been set, use that value.
147 */
148 flow = (p_mcb->flow == PORT_FC_UNDEFINED) ? PORT_FC_CREDIT : p_mcb->flow;
149
150 /* Set convergence layer and number of credits (k) */
151 if (flow == PORT_FC_CREDIT) {
152 cl = RFCOMM_PN_CONV_LAYER_CBFC_I;
153
154 if (com::android::bluetooth::flags::socket_settings_api()) {
155 k = (p_port->rfc_cfg_info.init_credit_present) ? p_port->rfc_cfg_info.init_credit
156 : (p_port->credit_rx_max < RFCOMM_K_MAX) ? p_port->credit_rx_max
157 : RFCOMM_K_MAX;
158 } else {
159 k = (p_port->credit_rx_max < RFCOMM_K_MAX) ? p_port->credit_rx_max : RFCOMM_K_MAX;
160 }
161 p_port->credit_rx = k;
162 } else {
163 cl = RFCOMM_PN_CONV_LAYER_TYPE_1;
164 k = 0;
165 }
166
167 /* Send Parameter Negotiation Command UIH frame */
168 p_port->rfc.expected_rsp |= RFC_RSP_PN;
169
170 rfc_send_pn(p_mcb, dlci, true, mtu, cl, k);
171
172 rfc_port_timer_start(p_port, RFC_T2_TIMEOUT);
173 }
174
175 /*******************************************************************************
176 *
177 * Function RFCOMM_ParameterNegotiationResponse
178 *
179 * Description This function is called by the user app to acknowledge
180 * DLC parameter negotiation.
181 *
182 ******************************************************************************/
RFCOMM_ParameterNegotiationResponse(tRFC_MCB * p_mcb,uint8_t dlci,uint16_t mtu,uint8_t cl,uint8_t k)183 void RFCOMM_ParameterNegotiationResponse(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu, uint8_t cl,
184 uint8_t k) {
185 if (p_mcb->state != RFC_MX_STATE_CONNECTED) {
186 return;
187 }
188
189 /* Send Parameter Negotiation Response UIH frame */
190 rfc_send_pn(p_mcb, dlci, false, mtu, cl, k);
191 }
192
193 /*******************************************************************************
194 *
195 * Function RFCOMM_PortParameterNegotiationRequest
196 *
197 * Description This function is called by the user app to start
198 * Remote Port parameter negotiation. Port emulation can
199 * send this request before actually establishing the DLC.
200 * In this case the function will allocate RFCOMM connection
201 * control block.
202 *
203 ******************************************************************************/
RFCOMM_PortParameterNegotiationRequest(tRFC_MCB * p_mcb,uint8_t dlci,PortSettings * p_settings)204 void RFCOMM_PortParameterNegotiationRequest(tRFC_MCB* p_mcb, uint8_t dlci,
205 PortSettings* p_settings) {
206 if (p_mcb->state != RFC_MX_STATE_CONNECTED) {
207 PORT_PortNegCnf(p_mcb, dlci, nullptr, RFCOMM_ERROR);
208 return;
209 }
210
211 tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
212 if (p_port == nullptr) {
213 log::warn("Unable to find DLCI port dlci:{}", dlci);
214 return;
215 }
216
217 /* Send Parameter Negotiation Command UIH frame */
218 if (!p_settings) {
219 p_port->rfc.expected_rsp |= RFC_RSP_RPN_REPLY;
220 } else {
221 p_port->rfc.expected_rsp |= RFC_RSP_RPN;
222 }
223
224 rfc_send_rpn(p_mcb, dlci, true, p_settings, RFCOMM_RPN_PM_MASK);
225 rfc_port_timer_start(p_port, RFC_T2_TIMEOUT);
226 }
227
228 /*******************************************************************************
229 *
230 * Function RFCOMM_PortParameterNegotiationResponse
231 *
232 * Description This function is called by the user app to acknowledge
233 * Port parameters negotiation.
234 *
235 ******************************************************************************/
RFCOMM_PortParameterNegotiationResponse(tRFC_MCB * p_mcb,uint8_t dlci,PortSettings * p_settings,uint16_t param_mask)236 void RFCOMM_PortParameterNegotiationResponse(tRFC_MCB* p_mcb, uint8_t dlci,
237 PortSettings* p_settings, uint16_t param_mask) {
238 if (p_mcb->state != RFC_MX_STATE_CONNECTED) {
239 return;
240 }
241
242 rfc_send_rpn(p_mcb, dlci, false, p_settings, param_mask);
243 }
244
245 /*******************************************************************************
246 *
247 * Function RFCOMM_ControlReq
248 *
249 * Description This function is called by the port entity to send control
250 * parameters to remote port emulation entity.
251 *
252 ******************************************************************************/
RFCOMM_ControlReq(tRFC_MCB * p_mcb,uint8_t dlci,tPORT_CTRL * p_pars)253 void RFCOMM_ControlReq(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_CTRL* p_pars) {
254 tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
255 if (p_port == nullptr) {
256 log::warn("Unable to find DLCI port dlci:{}", dlci);
257 return;
258 }
259
260 if ((p_port->state != PORT_CONNECTION_STATE_OPENED) ||
261 (p_port->rfc.sm_cb.state != RFC_STATE_OPENED)) {
262 return;
263 }
264
265 p_port->port_ctrl |= PORT_CTRL_REQ_SENT;
266
267 p_port->rfc.expected_rsp |= RFC_RSP_MSC;
268
269 rfc_send_msc(p_mcb, dlci, true, p_pars);
270 rfc_port_timer_start(p_port, RFC_T2_TIMEOUT);
271 }
272
273 /*******************************************************************************
274 *
275 * Function RFCOMM_FlowReq
276 *
277 * Description This function is called by the port entity when flow
278 * control state has changed. Enable flag passed shows if
279 * port can accept more data.
280 *
281 ******************************************************************************/
RFCOMM_FlowReq(tRFC_MCB * p_mcb,uint8_t dlci,bool enable)282 void RFCOMM_FlowReq(tRFC_MCB* p_mcb, uint8_t dlci, bool enable) {
283 tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
284 if (p_port == nullptr) {
285 log::warn("Unable to find DLCI port dlci:{}", dlci);
286 return;
287 }
288
289 if ((p_port->state != PORT_CONNECTION_STATE_OPENED) ||
290 (p_port->rfc.sm_cb.state != RFC_STATE_OPENED)) {
291 return;
292 }
293
294 p_port->local_ctrl.fc = !enable;
295
296 p_port->rfc.expected_rsp |= RFC_RSP_MSC;
297
298 rfc_send_msc(p_mcb, dlci, true, &p_port->local_ctrl);
299 rfc_port_timer_start(p_port, RFC_T2_TIMEOUT);
300 }
301
302 /*******************************************************************************
303 *
304 * Function RFCOMM_LineStatusReq
305 *
306 * Description This function is called by the port entity when line
307 * status should be delivered to the peer.
308 *
309 ******************************************************************************/
RFCOMM_LineStatusReq(tRFC_MCB * p_mcb,uint8_t dlci,uint8_t status)310 void RFCOMM_LineStatusReq(tRFC_MCB* p_mcb, uint8_t dlci, uint8_t status) {
311 tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
312 if (p_port == nullptr) {
313 log::warn("Unable to find DLCI port dlci:{}", dlci);
314 return;
315 }
316
317 if ((p_port->state != PORT_CONNECTION_STATE_OPENED) ||
318 (p_port->rfc.sm_cb.state != RFC_STATE_OPENED)) {
319 return;
320 }
321
322 p_port->rfc.expected_rsp |= RFC_RSP_RLS;
323
324 rfc_send_rls(p_mcb, dlci, true, status);
325 rfc_port_timer_start(p_port, RFC_T2_TIMEOUT);
326 }
327
328 /*******************************************************************************
329 *
330 * Function RFCOMM_DlcReleaseReq
331 *
332 * Description This function is called by the PORT unit to close DLC
333 *
334 ******************************************************************************/
RFCOMM_DlcReleaseReq(tRFC_MCB * p_mcb,uint8_t dlci)335 void RFCOMM_DlcReleaseReq(tRFC_MCB* p_mcb, uint8_t dlci) {
336 tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
337 if (p_port == nullptr) {
338 log::warn("Unable to find DLCI port dlci:{}", dlci);
339 return;
340 }
341 rfc_port_sm_execute(p_port, RFC_PORT_EVENT_CLOSE, nullptr);
342 }
343
344 /*******************************************************************************
345 *
346 * Function RFCOMM_DataReq
347 *
348 * Description This function is called by the user app to send data buffer
349 *
350 ******************************************************************************/
RFCOMM_DataReq(tRFC_MCB * p_mcb,uint8_t dlci,BT_HDR * p_buf)351 void RFCOMM_DataReq(tRFC_MCB* p_mcb, uint8_t dlci, BT_HDR* p_buf) {
352 rfc_port_sm_execute(port_find_mcb_dlci_port(p_mcb, dlci), RFC_PORT_EVENT_DATA, p_buf);
353 }
354