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) { rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_START_REQ, nullptr); }
54 
55 /*******************************************************************************
56  *
57  * Function         RFCOMM_StartRsp
58  *
59  * Description      This function handles Start Response from the upper layer.
60  *                  Save upper layer handle and result of the Start Indication
61  *                  in the control block and dispatch event to the FSM.
62  *
63  ******************************************************************************/
RFCOMM_StartRsp(tRFC_MCB * p_mcb,uint16_t result)64 void RFCOMM_StartRsp(tRFC_MCB* p_mcb, uint16_t result) {
65   rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_START_RSP, &result);
66 }
67 
68 /*******************************************************************************
69  *
70  * Function         RFCOMM_DlcEstablishReq
71  *
72  * Description      This function is called by the user app to establish
73  *                  connection with the specific dlci on a specific bd device.
74  *                  It will allocate RFCOMM connection control block if not
75  *                  allocated before and dispatch open event to the state
76  *                  machine.
77  *
78  ******************************************************************************/
RFCOMM_DlcEstablishReq(tRFC_MCB * p_mcb,uint8_t dlci,uint16_t)79 void RFCOMM_DlcEstablishReq(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t /* mtu */) {
80   if (p_mcb->state != RFC_MX_STATE_CONNECTED) {
81     PORT_DlcEstablishCnf(p_mcb, dlci, 0, RFCOMM_ERROR);
82     return;
83   }
84 
85   tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
86   if (p_port == nullptr) {
87     log::warn("Unable to find DLCI port dlci:{}", dlci);
88     return;
89   }
90 
91   rfc_port_sm_execute(p_port, RFC_PORT_EVENT_OPEN, nullptr);
92 }
93 
94 /*******************************************************************************
95  *
96  * Function         RFCOMM_DlcEstablishRsp
97  *
98  * Description      This function is called by the port emulation entity
99  *                  acks Establish Indication.
100  *
101  ******************************************************************************/
RFCOMM_DlcEstablishRsp(tRFC_MCB * p_mcb,uint8_t dlci,uint16_t,uint16_t result)102 void RFCOMM_DlcEstablishRsp(tRFC_MCB* p_mcb, uint8_t dlci, 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     log::warn("Unable to find DLCI port dlci:{}", dlci);
111     return;
112   }
113   rfc_port_sm_execute(p_port, RFC_PORT_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, 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     log::warn("Unable to find DLCI port dlci:{}", dlci);
135     return;
136   }
137 
138   if (p_mcb->state != RFC_MX_STATE_CONNECTED) {
139     log::warn("Multiplexer is in unexpected dlci:{} state:{}", dlci,
140               rfcomm_mx_state_text(p_mcb->state).c_str());
141     return;
142   }
143 
144   /* Negotiate the flow control mechanism.  If flow control mechanism for the
145    * mux has not been set yet, use credits.  If it has been set, use that value.
146    */
147   flow = (p_mcb->flow == PORT_FC_UNDEFINED) ? PORT_FC_CREDIT : 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 : 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_ParameterNegotiationResponse
170  *
171  * Description      This function is called by the user app to acknowledge
172  *                  DLC parameter negotiation.
173  *
174  ******************************************************************************/
RFCOMM_ParameterNegotiationResponse(tRFC_MCB * p_mcb,uint8_t dlci,uint16_t mtu,uint8_t cl,uint8_t k)175 void RFCOMM_ParameterNegotiationResponse(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) {
178     return;
179   }
180 
181   /* Send Parameter Negotiation Response UIH frame */
182   rfc_send_pn(p_mcb, dlci, false, mtu, cl, k);
183 }
184 
185 /*******************************************************************************
186  *
187  * Function         RFCOMM_PortParameterNegotiationRequest
188  *
189  * Description      This function is called by the user app to start
190  *                  Remote Port parameter negotiation.  Port emulation can
191  *                  send this request before actually establishing the DLC.
192  *                  In this case the function will allocate RFCOMM connection
193  *                  control block.
194  *
195  ******************************************************************************/
RFCOMM_PortParameterNegotiationRequest(tRFC_MCB * p_mcb,uint8_t dlci,PortSettings * p_settings)196 void RFCOMM_PortParameterNegotiationRequest(tRFC_MCB* p_mcb, uint8_t dlci,
197                                             PortSettings* p_settings) {
198   if (p_mcb->state != RFC_MX_STATE_CONNECTED) {
199     PORT_PortNegCnf(p_mcb, dlci, nullptr, RFCOMM_ERROR);
200     return;
201   }
202 
203   tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
204   if (p_port == nullptr) {
205     log::warn("Unable to find DLCI port dlci:{}", dlci);
206     return;
207   }
208 
209   /* Send Parameter Negotiation Command UIH frame */
210   if (!p_settings) {
211     p_port->rfc.expected_rsp |= RFC_RSP_RPN_REPLY;
212   } else {
213     p_port->rfc.expected_rsp |= RFC_RSP_RPN;
214   }
215 
216   rfc_send_rpn(p_mcb, dlci, true, p_settings, RFCOMM_RPN_PM_MASK);
217   rfc_port_timer_start(p_port, RFC_T2_TIMEOUT);
218 }
219 
220 /*******************************************************************************
221  *
222  * Function         RFCOMM_PortParameterNegotiationResponse
223  *
224  * Description      This function is called by the user app to acknowledge
225  *                  Port parameters negotiation.
226  *
227  ******************************************************************************/
RFCOMM_PortParameterNegotiationResponse(tRFC_MCB * p_mcb,uint8_t dlci,PortSettings * p_settings,uint16_t param_mask)228 void RFCOMM_PortParameterNegotiationResponse(tRFC_MCB* p_mcb, uint8_t dlci,
229                                              PortSettings* p_settings, uint16_t param_mask) {
230   if (p_mcb->state != RFC_MX_STATE_CONNECTED) {
231     return;
232   }
233 
234   rfc_send_rpn(p_mcb, dlci, false, p_settings, param_mask);
235 }
236 
237 /*******************************************************************************
238  *
239  * Function         RFCOMM_ControlReq
240  *
241  * Description      This function is called by the port entity to send control
242  *                  parameters to remote port emulation entity.
243  *
244  ******************************************************************************/
RFCOMM_ControlReq(tRFC_MCB * p_mcb,uint8_t dlci,tPORT_CTRL * p_pars)245 void RFCOMM_ControlReq(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_CTRL* p_pars) {
246   tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
247   if (p_port == nullptr) {
248     log::warn("Unable to find DLCI port dlci:{}", dlci);
249     return;
250   }
251 
252   if ((p_port->state != PORT_CONNECTION_STATE_OPENED) || (p_port->rfc.state != RFC_STATE_OPENED)) {
253     return;
254   }
255 
256   p_port->port_ctrl |= PORT_CTRL_REQ_SENT;
257 
258   p_port->rfc.expected_rsp |= RFC_RSP_MSC;
259 
260   rfc_send_msc(p_mcb, dlci, true, p_pars);
261   rfc_port_timer_start(p_port, RFC_T2_TIMEOUT);
262 }
263 
264 /*******************************************************************************
265  *
266  * Function         RFCOMM_FlowReq
267  *
268  * Description      This function is called by the port entity when flow
269  *                  control state has changed.  Enable flag passed shows if
270  *                  port can accept more data.
271  *
272  ******************************************************************************/
RFCOMM_FlowReq(tRFC_MCB * p_mcb,uint8_t dlci,bool enable)273 void RFCOMM_FlowReq(tRFC_MCB* p_mcb, uint8_t dlci, bool enable) {
274   tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
275   if (p_port == nullptr) {
276     log::warn("Unable to find DLCI port dlci:{}", dlci);
277     return;
278   }
279 
280   if ((p_port->state != PORT_CONNECTION_STATE_OPENED) || (p_port->rfc.state != RFC_STATE_OPENED)) {
281     return;
282   }
283 
284   p_port->local_ctrl.fc = !enable;
285 
286   p_port->rfc.expected_rsp |= RFC_RSP_MSC;
287 
288   rfc_send_msc(p_mcb, dlci, true, &p_port->local_ctrl);
289   rfc_port_timer_start(p_port, RFC_T2_TIMEOUT);
290 }
291 
292 /*******************************************************************************
293  *
294  * Function         RFCOMM_LineStatusReq
295  *
296  * Description      This function is called by the port entity when line
297  *                  status should be delivered to the peer.
298  *
299  ******************************************************************************/
RFCOMM_LineStatusReq(tRFC_MCB * p_mcb,uint8_t dlci,uint8_t status)300 void RFCOMM_LineStatusReq(tRFC_MCB* p_mcb, uint8_t dlci, uint8_t status) {
301   tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
302   if (p_port == nullptr) {
303     log::warn("Unable to find DLCI port dlci:{}", dlci);
304     return;
305   }
306 
307   if ((p_port->state != PORT_CONNECTION_STATE_OPENED) || (p_port->rfc.state != RFC_STATE_OPENED)) {
308     return;
309   }
310 
311   p_port->rfc.expected_rsp |= RFC_RSP_RLS;
312 
313   rfc_send_rls(p_mcb, dlci, true, status);
314   rfc_port_timer_start(p_port, RFC_T2_TIMEOUT);
315 }
316 
317 /*******************************************************************************
318  *
319  * Function         RFCOMM_DlcReleaseReq
320  *
321  * Description      This function is called by the PORT unit to close DLC
322  *
323  ******************************************************************************/
RFCOMM_DlcReleaseReq(tRFC_MCB * p_mcb,uint8_t dlci)324 void RFCOMM_DlcReleaseReq(tRFC_MCB* p_mcb, uint8_t dlci) {
325   rfc_port_sm_execute(port_find_mcb_dlci_port(p_mcb, dlci), RFC_PORT_EVENT_CLOSE, nullptr);
326 }
327 
328 /*******************************************************************************
329  *
330  * Function         RFCOMM_DataReq
331  *
332  * Description      This function is called by the user app to send data buffer
333  *
334  ******************************************************************************/
RFCOMM_DataReq(tRFC_MCB * p_mcb,uint8_t dlci,BT_HDR * p_buf)335 void RFCOMM_DataReq(tRFC_MCB* p_mcb, uint8_t dlci, BT_HDR* p_buf) {
336   rfc_port_sm_execute(port_find_mcb_dlci_port(p_mcb, dlci), RFC_PORT_EVENT_DATA, p_buf);
337 }
338