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_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 == 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_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, nullptr, RFCOMM_ERROR);
197     return;
198   }
199 
200   tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
201   if (p_port == nullptr) {
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 == nullptr) {
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,bool enable)267 void RFCOMM_FlowReq(tRFC_MCB* p_mcb, uint8_t dlci, bool enable) {
268   tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
269   if (p_port == nullptr) {
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 == nullptr) {
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,
320                       nullptr);
321 }
322 
323 /*******************************************************************************
324  *
325  * Function         RFCOMM_DataReq
326  *
327  * Description      This function is called by the user app to send data buffer
328  *
329  ******************************************************************************/
RFCOMM_DataReq(tRFC_MCB * p_mcb,uint8_t dlci,BT_HDR * p_buf)330 void RFCOMM_DataReq(tRFC_MCB* p_mcb, uint8_t dlci, BT_HDR* p_buf) {
331   rfc_port_sm_execute(port_find_mcb_dlci_port(p_mcb, dlci), RFC_EVENT_DATA,
332                       p_buf);
333 }
334