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