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
37tRFC_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 ******************************************************************************/
49void 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 ******************************************************************************/
62void 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 ******************************************************************************/
77void 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 ******************************************************************************/
101void 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 ******************************************************************************/
127void 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 ******************************************************************************/
175void 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 ******************************************************************************/
194void 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 ******************************************************************************/
224void 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 ******************************************************************************/
239void 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 ******************************************************************************/
267void 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 ******************************************************************************/
294void 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 ******************************************************************************/
318void 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 ******************************************************************************/
329void 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