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