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 #include <cstring>
27 #include "bt_common.h"
28 #include "bt_target.h"
29 #include "bt_utils.h"
30 #include "l2c_api.h"
31 #include "osi/include/osi.h"
32 #include "port_api.h"
33 #include "port_int.h"
34 #include "rfc_int.h"
35 #include "rfcdefs.h"
36
37 tRFC_CB rfc_cb;
38 std::unordered_map<uint32_t, uint16_t> rfcomm_security_records;
39 std::unordered_map<uint16_t /* sci */, tRFC_MCB*> rfc_lcid_mcb;
40
41 /*******************************************************************************
42 *
43 * Function RFCOMM_StartReq
44 *
45 * Description This function handles Start Request from the upper layer.
46 * If RFCOMM multiplexer channel can not be allocated
47 * send start not accepted confirmation. Otherwise dispatch
48 * start event to the state machine.
49 *
50 ******************************************************************************/
RFCOMM_StartReq(tRFC_MCB * p_mcb)51 void RFCOMM_StartReq(tRFC_MCB* p_mcb) {
52 rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_START_REQ, nullptr);
53 }
54
55 /*******************************************************************************
56 *
57 * Function RFCOMM_StartRsp
58 *
59 * Description This function handles Start Response from the upper layer.
60 * Save upper layer handle and result of the Start Indication
61 * in the control block and dispatch event to the FSM.
62 *
63 ******************************************************************************/
RFCOMM_StartRsp(tRFC_MCB * p_mcb,uint16_t result)64 void RFCOMM_StartRsp(tRFC_MCB* p_mcb, uint16_t result) {
65 rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_START_RSP, &result);
66 }
67
68 /*******************************************************************************
69 *
70 * Function RFCOMM_DlcEstablishReq
71 *
72 * Description This function is called by the user app to establish
73 * connection with the specific dlci on a specific bd device.
74 * It will allocate RFCOMM connection control block if not
75 * allocated before and dispatch open event to the state
76 * machine.
77 *
78 ******************************************************************************/
RFCOMM_DlcEstablishReq(tRFC_MCB * p_mcb,uint8_t dlci,UNUSED_ATTR uint16_t mtu)79 void RFCOMM_DlcEstablishReq(tRFC_MCB* p_mcb, uint8_t dlci,
80 UNUSED_ATTR 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 RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
89 return;
90 }
91
92 rfc_port_sm_execute(p_port, RFC_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,UNUSED_ATTR uint16_t mtu,uint16_t result)103 void RFCOMM_DlcEstablishRsp(tRFC_MCB* p_mcb, uint8_t dlci,
104 UNUSED_ATTR uint16_t mtu, uint16_t result) {
105 if ((p_mcb->state != RFC_MX_STATE_CONNECTED) && (result == RFCOMM_SUCCESS)) {
106 PORT_DlcReleaseInd(p_mcb, dlci);
107 return;
108 }
109
110 tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
111 if (p_port == nullptr) {
112 RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
113 return;
114 }
115 rfc_port_sm_execute(p_port, RFC_EVENT_ESTABLISH_RSP, &result);
116 }
117
118 /*******************************************************************************
119 *
120 * Function RFCOMM_ParameterNegotiationRequest
121 *
122 * Description This function is called by the user app to start
123 * DLC parameter negotiation. Port emulation can send this
124 * request before actually establishing the DLC. In this
125 * case the function will allocate RFCOMM connection control
126 * block.
127 *
128 ******************************************************************************/
RFCOMM_ParameterNegotiationRequest(tRFC_MCB * p_mcb,uint8_t dlci,uint16_t mtu)129 void RFCOMM_ParameterNegotiationRequest(tRFC_MCB* p_mcb, uint8_t dlci,
130 uint16_t mtu) {
131 uint8_t flow;
132 uint8_t cl;
133 uint8_t k;
134
135 tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
136 if (p_port == nullptr) {
137 RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
138 return;
139 }
140
141 if (p_mcb->state != RFC_MX_STATE_CONNECTED) {
142 p_port->error = PORT_PAR_NEG_FAILED;
143 return;
144 }
145
146 /* Negotiate the flow control mechanism. If flow control mechanism for */
147 /* mux has not been set yet, use our default value. If it has been set, */
148 /* use that value. */
149 flow = (p_mcb->flow == PORT_FC_UNDEFINED) ? PORT_FC_DEFAULT : p_mcb->flow;
150
151 /* Set convergence layer and number of credits (k) */
152 if (flow == PORT_FC_CREDIT) {
153 cl = RFCOMM_PN_CONV_LAYER_CBFC_I;
154 k = (p_port->credit_rx_max < RFCOMM_K_MAX) ? p_port->credit_rx_max
155 : RFCOMM_K_MAX;
156 p_port->credit_rx = k;
157 } else {
158 cl = RFCOMM_PN_CONV_LAYER_TYPE_1;
159 k = 0;
160 }
161
162 /* Send Parameter Negotiation Command UIH frame */
163 p_port->rfc.expected_rsp |= RFC_RSP_PN;
164
165 rfc_send_pn(p_mcb, dlci, true, mtu, cl, k);
166
167 rfc_port_timer_start(p_port, RFC_T2_TIMEOUT);
168 }
169
170 /*******************************************************************************
171 *
172 * Function RFCOMM_ParameterNegotiationResponse
173 *
174 * Description This function is called by the user app to acknowledge
175 * DLC parameter negotiation.
176 *
177 ******************************************************************************/
RFCOMM_ParameterNegotiationResponse(tRFC_MCB * p_mcb,uint8_t dlci,uint16_t mtu,uint8_t cl,uint8_t k)178 void RFCOMM_ParameterNegotiationResponse(tRFC_MCB* p_mcb, uint8_t dlci,
179 uint16_t mtu, uint8_t cl, uint8_t k) {
180 if (p_mcb->state != RFC_MX_STATE_CONNECTED) return;
181
182 /* Send Parameter Negotiation Response UIH frame */
183 rfc_send_pn(p_mcb, dlci, false, mtu, cl, k);
184 }
185
186 /*******************************************************************************
187 *
188 * Function RFCOMM_PortParameterNegotiationRequest
189 *
190 * Description This function is called by the user app to start
191 * Remote Port parameter negotiation. Port emulation can
192 * send this request before actually establishing the DLC.
193 * In this case the function will allocate RFCOMM connection
194 * control block.
195 *
196 ******************************************************************************/
RFCOMM_PortParameterNegotiationRequest(tRFC_MCB * p_mcb,uint8_t dlci,tPORT_STATE * p_pars)197 void RFCOMM_PortParameterNegotiationRequest(tRFC_MCB* p_mcb, uint8_t dlci,
198 tPORT_STATE* p_pars) {
199 if (p_mcb->state != RFC_MX_STATE_CONNECTED) {
200 PORT_PortNegCnf(p_mcb, dlci, nullptr, RFCOMM_ERROR);
201 return;
202 }
203
204 tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
205 if (p_port == nullptr) {
206 RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
207 return;
208 }
209
210 /* Send Parameter Negotiation Command UIH frame */
211 if (!p_pars)
212 p_port->rfc.expected_rsp |= RFC_RSP_RPN_REPLY;
213 else
214 p_port->rfc.expected_rsp |= RFC_RSP_RPN;
215
216 rfc_send_rpn(p_mcb, dlci, true, p_pars, RFCOMM_RPN_PM_MASK);
217 rfc_port_timer_start(p_port, RFC_T2_TIMEOUT);
218 }
219
220 /*******************************************************************************
221 *
222 * Function RFCOMM_PortParameterNegotiationResponse
223 *
224 * Description This function is called by the user app to acknowledge
225 * Port parameters negotiation.
226 *
227 ******************************************************************************/
RFCOMM_PortParameterNegotiationResponse(tRFC_MCB * p_mcb,uint8_t dlci,tPORT_STATE * p_pars,uint16_t param_mask)228 void RFCOMM_PortParameterNegotiationResponse(tRFC_MCB* p_mcb, uint8_t dlci,
229 tPORT_STATE* p_pars,
230 uint16_t param_mask) {
231 if (p_mcb->state != RFC_MX_STATE_CONNECTED) return;
232
233 rfc_send_rpn(p_mcb, dlci, false, p_pars, param_mask);
234 }
235
236 /*******************************************************************************
237 *
238 * Function RFCOMM_ControlReq
239 *
240 * Description This function is called by the port entity to send control
241 * parameters to remote port emulation entity.
242 *
243 ******************************************************************************/
RFCOMM_ControlReq(tRFC_MCB * p_mcb,uint8_t dlci,tPORT_CTRL * p_pars)244 void RFCOMM_ControlReq(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_CTRL* p_pars) {
245 tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
246 if (p_port == nullptr) {
247 RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
248 return;
249 }
250
251 if ((p_port->state != PORT_STATE_OPENED) ||
252 (p_port->rfc.state != RFC_STATE_OPENED))
253 return;
254
255 p_port->port_ctrl |= PORT_CTRL_REQ_SENT;
256
257 p_port->rfc.expected_rsp |= RFC_RSP_MSC;
258
259 rfc_send_msc(p_mcb, dlci, true, p_pars);
260 rfc_port_timer_start(p_port, RFC_T2_TIMEOUT);
261 }
262
263 /*******************************************************************************
264 *
265 * Function RFCOMM_FlowReq
266 *
267 * Description This function is called by the port entity when flow
268 * control state has changed. Enable flag passed shows if
269 * port can accept more data.
270 *
271 ******************************************************************************/
RFCOMM_FlowReq(tRFC_MCB * p_mcb,uint8_t dlci,bool enable)272 void RFCOMM_FlowReq(tRFC_MCB* p_mcb, uint8_t dlci, bool enable) {
273 tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
274 if (p_port == nullptr) {
275 RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
276 return;
277 }
278
279 if ((p_port->state != PORT_STATE_OPENED) ||
280 (p_port->rfc.state != RFC_STATE_OPENED))
281 return;
282
283 p_port->local_ctrl.fc = !enable;
284
285 p_port->rfc.expected_rsp |= RFC_RSP_MSC;
286
287 rfc_send_msc(p_mcb, dlci, true, &p_port->local_ctrl);
288 rfc_port_timer_start(p_port, RFC_T2_TIMEOUT);
289 }
290
291 /*******************************************************************************
292 *
293 * Function RFCOMM_LineStatusReq
294 *
295 * Description This function is called by the port entity when line
296 * status should be delivered to the peer.
297 *
298 ******************************************************************************/
RFCOMM_LineStatusReq(tRFC_MCB * p_mcb,uint8_t dlci,uint8_t status)299 void RFCOMM_LineStatusReq(tRFC_MCB* p_mcb, uint8_t dlci, uint8_t status) {
300 tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
301 if (p_port == nullptr) {
302 RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
303 return;
304 }
305
306 if ((p_port->state != PORT_STATE_OPENED) ||
307 (p_port->rfc.state != RFC_STATE_OPENED))
308 return;
309
310 p_port->rfc.expected_rsp |= RFC_RSP_RLS;
311
312 rfc_send_rls(p_mcb, dlci, true, status);
313 rfc_port_timer_start(p_port, RFC_T2_TIMEOUT);
314 }
315
316 /*******************************************************************************
317 *
318 * Function RFCOMM_DlcReleaseReq
319 *
320 * Description This function is called by the PORT unit to close DLC
321 *
322 ******************************************************************************/
RFCOMM_DlcReleaseReq(tRFC_MCB * p_mcb,uint8_t dlci)323 void RFCOMM_DlcReleaseReq(tRFC_MCB* p_mcb, uint8_t dlci) {
324 rfc_port_sm_execute(port_find_mcb_dlci_port(p_mcb, dlci), RFC_EVENT_CLOSE,
325 nullptr);
326 }
327
328 /*******************************************************************************
329 *
330 * Function RFCOMM_DataReq
331 *
332 * Description This function is called by the user app to send data buffer
333 *
334 ******************************************************************************/
RFCOMM_DataReq(tRFC_MCB * p_mcb,uint8_t dlci,BT_HDR * p_buf)335 void RFCOMM_DataReq(tRFC_MCB* p_mcb, uint8_t dlci, BT_HDR* p_buf) {
336 rfc_port_sm_execute(port_find_mcb_dlci_port(p_mcb, dlci), RFC_EVENT_DATA,
337 p_buf);
338 }
339