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