1 /*
2 * Copyright (C) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "rfcomm_defs.h"
17
18 /**
19 * @brief L2CAP calls this function to notify RFCOMM connected requirements.
20 * After receiving the request, RFCOMM creates session information and calls the state machine.
21 *
22 * @param aclHandle ACL handle.
23 * @param lcid L2CAP channel id.
24 * @param id L2CAP's id information.
25 * @param psm psm value.
26 */
RfcommRecvConnectReqCback(uint16_t lcid,uint8_t id,const L2capConnectionInfo * info,uint16_t lpsm)27 void RfcommRecvConnectReqCback(uint16_t lcid, uint8_t id, const L2capConnectionInfo *info, uint16_t lpsm)
28 {
29 LOG_INFO("%{public}s lcid:%hu, lpsm:%hu", __func__, lcid, lpsm);
30
31 RfcommSessionInfo *session = NULL;
32 RfcommRecvConnectedInfo connectedInfo;
33 BtAddr addr;
34 (void)memset_s(&addr, sizeof(addr), 0x00, sizeof(addr));
35
36 if (info == NULL) {
37 LOG_ERROR("%{public}s info is NULL.", __func__);
38 return;
39 }
40
41 (void)memcpy_s(&addr, sizeof(BtAddr), &(info->addr), sizeof(BtAddr));
42 session = RfcommGetSessionByAddr(&addr);
43 if (session == NULL) {
44 session = RfcommCreateSession(&addr, lcid, id, false);
45 }
46
47 if (session != NULL) {
48 connectedInfo.id = id;
49 connectedInfo.lcid = lcid;
50 // Established session Successfully.
51 RfcommSessionEvtFsm(session, EV_SESSION_RECV_CONNECT_REQ, (void*)&connectedInfo);
52 } else {
53 LOG_ERROR("%{public}s No session resources.", __func__);
54 RfcommSendConnectRsp(lcid, id, L2CAP_NO_RESOURCES_AVAILABLE, 0);
55 }
56 }
57
58 /**
59 * @brief L2CAP calls this function to notify RFCOMM the connection response from peer.
60 * After receiving the response, calls the state machine.
61 *
62 * @param aclHandle ACL handle.
63 * @param lcid L2CAP channel id.
64 * @param result The result of the response.
65 * @param status status value.
66 */
RfcommRecvConnectRspCback(uint16_t lcid,const L2capConnectionInfo * info,uint16_t result,uint16_t status)67 void RfcommRecvConnectRspCback(uint16_t lcid, const L2capConnectionInfo *info, uint16_t result, uint16_t status)
68 {
69 LOG_INFO("%{public}s lcid:%hu, result:%hu", __func__, lcid, result);
70
71 RfcommSessionInfo *session = NULL;
72
73 if (result == L2CAP_CONNECTION_PENDING) {
74 LOG_INFO("%{public}s:L2CAP pending.", __func__);
75 return;
76 }
77
78 session = RfcommGetSessionByLcid(lcid);
79 if (session != NULL) {
80 // Session exists.
81 RfcommSessionEvtFsm(session, EV_SESSION_RECV_CONNECT_RSP, &result);
82 }
83 }
84
85 /**
86 * @brief L2CAP calls this function to notify RFCOMM config requirements.
87 * After receiving the request, RFCOMM calls the state machine.
88 *
89 * @param lcid L2CAP channel id.
90 * @param id L2CAP's id information.
91 * @param cfg Config information.
92 */
RfcommRecvConfigReqCback(uint16_t lcid,uint8_t id,const L2capConfigInfo * cfg)93 void RfcommRecvConfigReqCback(uint16_t lcid, uint8_t id, const L2capConfigInfo *cfg)
94 {
95 LOG_INFO("%{public}s lcid:%hu", __func__, lcid);
96
97 RfcommSessionInfo *session = RfcommGetSessionByLcid(lcid);
98 RfcommConfigReqInfo reqInfo;
99 (void)memset_s(&reqInfo, sizeof(RfcommConfigReqInfo), 0x00, sizeof(RfcommConfigReqInfo));
100
101 reqInfo.id = id;
102 (void)memcpy_s(&reqInfo.cfg, sizeof(L2capConfigInfo), cfg, sizeof(L2capConfigInfo));
103
104 if (session != NULL) {
105 // Session exists.
106 RfcommSessionEvtFsm(session, EV_SESSION_RECV_CONFIG_REQ, &reqInfo);
107 }
108 }
109
110 /**
111 * @brief L2CAP calls this function to notify RFCOMM config response from peer.
112 * After receiving the response, RFCOMM calls the state machine.
113 *
114 * @param lcid L2CAP channel id.
115 * @param cfg Config information.
116 * @param result The result of the response.
117 */
RfcommRecvConfigRspCback(uint16_t lcid,const L2capConfigInfo * cfg,uint16_t result)118 void RfcommRecvConfigRspCback(uint16_t lcid, const L2capConfigInfo *cfg, uint16_t result)
119 {
120 LOG_INFO("%{public}s lcid:%hu, result:%hu", __func__, lcid, result);
121
122 RfcommSessionInfo *session = NULL;
123 RfcommConfigRspInfo configResult;
124
125 if (result == L2CAP_PENDING) {
126 LOG_INFO("%{public}s:L2CAP pending.", __func__);
127 return;
128 }
129
130 if (cfg == NULL) {
131 return;
132 }
133
134 (void)memset_s(&configResult, sizeof(RfcommConfigRspInfo), 0x00, sizeof(RfcommConfigRspInfo));
135 (void)memcpy_s(&configResult.cfg, sizeof(L2capConfigInfo), cfg, sizeof(L2capConfigInfo));
136 configResult.result = result;
137
138 session = RfcommGetSessionByLcid(lcid);
139 if (session != NULL) {
140 // Session exists.
141 RfcommSessionEvtFsm(session, EV_SESSION_RECV_CONFIG_RSP, &configResult);
142 }
143 }
144
145 /**
146 * @brief L2CAP calls this function to notify RFCOMM disconnect requirements.
147 * After receiving the request, RFCOMM calls the state machine.
148 *
149 * @param lcid L2CAP channel id.
150 * @param id L2CAP's id information.
151 */
RfcommRecvDisconnectReqCback(uint16_t lcid,uint8_t id)152 void RfcommRecvDisconnectReqCback(uint16_t lcid, uint8_t id)
153 {
154 LOG_INFO("%{public}s lcid:%hu", __func__, lcid);
155
156 RfcommSessionInfo *session = RfcommGetSessionByLcid(lcid);
157
158 RfcommSendDisconnectRsp(lcid, id);
159
160 if (session != NULL) {
161 RfcommSessionEvtFsm(session, EV_SESSION_RECV_DISCONNECT_REQ, NULL);
162 }
163 }
164
165 /**
166 * @brief When an abnormal disconnection event occurs,
167 * such as link loss, connection timeout, etc., L2CAP calls this function to notify RFCOMM.
168 * After receiving the notification, RFCOMM calls the state machine.
169 *
170 * @param lcid L2CAP channel id.
171 * @param reason Abnormal disconnection's reason.
172 */
RfcommDisconnectAbnormalCback(uint16_t lcid,uint8_t reason)173 void RfcommDisconnectAbnormalCback(uint16_t lcid, uint8_t reason)
174 {
175 LOG_INFO("%{public}s lcid:%hu", __func__, lcid);
176
177 RfcommSessionInfo *session = RfcommGetSessionByLcid(lcid);
178
179 if (session != NULL) {
180 // Session exists.
181 RfcommSessionEvtFsm(session, EV_SESSION_RECV_LINK_LOSS, &reason);
182 }
183 }
184
185 /**
186 * @brief When receiving RFCOMM Frame, L2CAP calls this function to notify RFCOMM.
187 * RFCOMM analyzes the data and determines whether it is a session event or a channel event,
188 * and calls the corresponding state machine to continue processing.
189 *
190 * @param lcid L2CAP channel id.
191 * @param pkt The RFCOMM frame information.
192 */
RfcommRecvDataCback(uint16_t lcid,Packet * pkt)193 void RfcommRecvDataCback(uint16_t lcid, Packet *pkt)
194 {
195 LOG_INFO("%{public}s lcid:%hu", __func__, lcid);
196
197 int event = -1;
198 uint8_t dlci = 0;
199 RfcommUihInfo info;
200 RfcommSessionInfo *session = RfcommGetSessionByLcid(lcid);
201 RfcommChannelInfo *channel = NULL;
202 RfcommParseFrameResult parseRslt;
203 (void)memset_s(&info, sizeof(RfcommUihInfo), 0x00, sizeof(RfcommUihInfo));
204
205 if (session == NULL) {
206 LOG_ERROR("%{public}s:Session does not exist.", __func__);
207 return;
208 }
209
210 parseRslt.dlci = &dlci;
211 parseRslt.event = &event;
212 parseRslt.info = &info;
213
214 RfcommEventType eventType = RfcommParseFrames(session, pkt, parseRslt);
215 switch (eventType) {
216 case EVENT_SESSION:
217 RfcommSessionEvtFsm(session, event, &info);
218 break;
219 case EVENT_CHANNEL:
220 channel = RfcommGetChannelByDlci(session, dlci);
221 if (channel == NULL) {
222 // If the channel does not exist, it means that the server is currently connected.
223 // In this case, find the server and create a channel associated with the server.
224 channel = RfcommCreateChannelOfServer(session, dlci, event);
225 }
226 if (channel != NULL) {
227 RfcommChannelEvtFsm(channel, event, &info);
228 }
229 break;
230 case EVENT_UNSUPPORTED_CMD:
231 RfcommSendUihNsc(session, info.invalidCmd.ea, info.invalidCmd.cr, info.invalidCmd.type);
232 break;
233 case EVENT_FRAME_ERR:
234 LOG_ERROR("%{public}s:RFCOMM frame error.", __func__);
235 break;
236 default:
237 break;
238 }
239 }
240
RfcommSendConnectReqCback(const BtAddr * addr,uint16_t lcid,int result)241 void RfcommSendConnectReqCback(const BtAddr *addr, uint16_t lcid, int result)
242 {
243 LOG_INFO("%{public}s lcid is %hu, result is %{public}d.", __func__, lcid, result);
244
245 RfcommReqConnectRslt connectRslt;
246 RfcommSessionInfo *session = RfcommGetSessionByAddr(addr);
247
248 (void)memset_s(&connectRslt, sizeof(RfcommReqConnectRslt), 0x00, sizeof(RfcommReqConnectRslt));
249 connectRslt.lcid = lcid;
250 connectRslt.result = result;
251
252 if (session != NULL) {
253 // Session exists.
254 RfcommSessionEvtFsm(session, EV_SESSION_RECV_REQ_CONNECT_RESULT, &connectRslt);
255 }
256 }