1 /******************************************************************************
2 *
3 * Copyright (C) 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 <string.h>
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, NULL);
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 == NULL) {
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, NULL);
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 == NULL) {
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_ParNegReq
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_ParNegReq(tRFC_MCB * p_mcb,uint8_t dlci,uint16_t mtu)127 void RFCOMM_ParNegReq(tRFC_MCB* p_mcb, uint8_t dlci, 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 == NULL) {
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_ParNegRsp
170 *
171 * Description This function is called by the user app to acknowledge
172 * DLC parameter negotiation.
173 *
174 ******************************************************************************/
RFCOMM_ParNegRsp(tRFC_MCB * p_mcb,uint8_t dlci,uint16_t mtu,uint8_t cl,uint8_t k)175 void RFCOMM_ParNegRsp(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu, uint8_t cl,
176 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_PortNegReq
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_PortNegReq(tRFC_MCB * p_mcb,uint8_t dlci,tPORT_STATE * p_pars)194 void RFCOMM_PortNegReq(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_STATE* p_pars) {
195 if (p_mcb->state != RFC_MX_STATE_CONNECTED) {
196 PORT_PortNegCnf(p_mcb, dlci, NULL, RFCOMM_ERROR);
197 return;
198 }
199
200 tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
201 if (p_port == NULL) {
202 RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
203 return;
204 }
205
206 /* Send Parameter Negotiation Command UIH frame */
207 if (!p_pars)
208 p_port->rfc.expected_rsp |= RFC_RSP_RPN_REPLY;
209 else
210 p_port->rfc.expected_rsp |= RFC_RSP_RPN;
211
212 rfc_send_rpn(p_mcb, dlci, true, p_pars, RFCOMM_RPN_PM_MASK);
213 rfc_port_timer_start(p_port, RFC_T2_TIMEOUT);
214 }
215
216 /*******************************************************************************
217 *
218 * Function RFCOMM_PortNegRsp
219 *
220 * Description This function is called by the user app to acknowledge
221 * Port parameters negotiation.
222 *
223 ******************************************************************************/
RFCOMM_PortNegRsp(tRFC_MCB * p_mcb,uint8_t dlci,tPORT_STATE * p_pars,uint16_t param_mask)224 void RFCOMM_PortNegRsp(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_STATE* p_pars,
225 uint16_t param_mask) {
226 if (p_mcb->state != RFC_MX_STATE_CONNECTED) return;
227
228 rfc_send_rpn(p_mcb, dlci, false, p_pars, param_mask);
229 }
230
231 /*******************************************************************************
232 *
233 * Function RFCOMM_ControlReq
234 *
235 * Description This function is called by the port entity to send control
236 * parameters to remote port emulation entity.
237 *
238 ******************************************************************************/
RFCOMM_ControlReq(tRFC_MCB * p_mcb,uint8_t dlci,tPORT_CTRL * p_pars)239 void RFCOMM_ControlReq(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_CTRL* p_pars) {
240 tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
241 if (p_port == NULL) {
242 RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
243 return;
244 }
245
246 if ((p_port->state != PORT_STATE_OPENED) ||
247 (p_port->rfc.state != RFC_STATE_OPENED))
248 return;
249
250 p_port->port_ctrl |= PORT_CTRL_REQ_SENT;
251
252 p_port->rfc.expected_rsp |= RFC_RSP_MSC;
253
254 rfc_send_msc(p_mcb, dlci, true, p_pars);
255 rfc_port_timer_start(p_port, RFC_T2_TIMEOUT);
256 }
257
258 /*******************************************************************************
259 *
260 * Function RFCOMM_FlowReq
261 *
262 * Description This function is called by the port entity when flow
263 * control state has changed. Enable flag passed shows if
264 * port can accept more data.
265 *
266 ******************************************************************************/
RFCOMM_FlowReq(tRFC_MCB * p_mcb,uint8_t dlci,uint8_t enable)267 void RFCOMM_FlowReq(tRFC_MCB* p_mcb, uint8_t dlci, uint8_t enable) {
268 tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
269 if (p_port == NULL) {
270 RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
271 return;
272 }
273
274 if ((p_port->state != PORT_STATE_OPENED) ||
275 (p_port->rfc.state != RFC_STATE_OPENED))
276 return;
277
278 p_port->local_ctrl.fc = !enable;
279
280 p_port->rfc.expected_rsp |= RFC_RSP_MSC;
281
282 rfc_send_msc(p_mcb, dlci, true, &p_port->local_ctrl);
283 rfc_port_timer_start(p_port, RFC_T2_TIMEOUT);
284 }
285
286 /*******************************************************************************
287 *
288 * Function RFCOMM_LineStatusReq
289 *
290 * Description This function is called by the port entity when line
291 * status should be delivered to the peer.
292 *
293 ******************************************************************************/
RFCOMM_LineStatusReq(tRFC_MCB * p_mcb,uint8_t dlci,uint8_t status)294 void RFCOMM_LineStatusReq(tRFC_MCB* p_mcb, uint8_t dlci, uint8_t status) {
295 tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
296 if (p_port == NULL) {
297 RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
298 return;
299 }
300
301 if ((p_port->state != PORT_STATE_OPENED) ||
302 (p_port->rfc.state != RFC_STATE_OPENED))
303 return;
304
305 p_port->rfc.expected_rsp |= RFC_RSP_RLS;
306
307 rfc_send_rls(p_mcb, dlci, true, status);
308 rfc_port_timer_start(p_port, RFC_T2_TIMEOUT);
309 }
310
311 /*******************************************************************************
312 *
313 * Function RFCOMM_DlcReleaseReq
314 *
315 * Description This function is called by the PORT unit to close DLC
316 *
317 ******************************************************************************/
RFCOMM_DlcReleaseReq(tRFC_MCB * p_mcb,uint8_t dlci)318 void RFCOMM_DlcReleaseReq(tRFC_MCB* p_mcb, uint8_t dlci) {
319 rfc_port_sm_execute(port_find_mcb_dlci_port(p_mcb, dlci), RFC_EVENT_CLOSE, 0);
320 }
321
322 /*******************************************************************************
323 *
324 * Function RFCOMM_DataReq
325 *
326 * Description This function is called by the user app to send data buffer
327 *
328 ******************************************************************************/
RFCOMM_DataReq(tRFC_MCB * p_mcb,uint8_t dlci,BT_HDR * p_buf)329 void RFCOMM_DataReq(tRFC_MCB* p_mcb, uint8_t dlci, BT_HDR* p_buf) {
330 rfc_port_sm_execute(port_find_mcb_dlci_port(p_mcb, dlci), RFC_EVENT_DATA,
331 p_buf);
332 }
333