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