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