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