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