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