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 static List *g_sessionList;
19
20 /**
21 * @brief Create session list when RFCOMM initialize.
22 *
23 */
RfcommCreateSessionList()24 void RfcommCreateSessionList()
25 {
26 LOG_INFO("%{public}s", __func__);
27
28 g_sessionList = ListCreate(NULL);
29 }
30
31 /**
32 * @brief Free session list when RFCOMM finalize.
33 *
34 */
RfcommDestroySessionList()35 void RfcommDestroySessionList()
36 {
37 LOG_INFO("%{public}s", __func__);
38
39 ListNode *node = NULL;
40 RfcommSessionInfo *session = NULL;
41
42 if (g_sessionList == NULL) {
43 LOG_DEBUG("%{public}s Session list is NULL.", __func__);
44 return;
45 }
46
47 // Release server information.
48 node = ListGetFirstNode(g_sessionList);
49 while (node != NULL) {
50 session = ListGetNodeData(node);
51 if (session->timer != NULL) {
52 AlarmDelete(session->timer);
53 session->timer = NULL;
54 }
55 free(session);
56 node = ListGetNextNode(node);
57 }
58
59 // Free server list.
60 ListDelete(g_sessionList);
61 g_sessionList = NULL;
62 }
63
64 /**
65 * @brief The timeout callback function registered to alarm.
66 *
67 * @param parameter The parametr info registered to alarm.
68 */
RfcommSessionTimeoutCallback(void * context)69 static void RfcommSessionTimeoutCallback(void *context)
70 {
71 LOG_INFO("%{public}s", __func__);
72
73 if (context == NULL) {
74 LOG_ERROR("%{public}s:Session is closed.", __func__);
75 return;
76 }
77
78 BTM_RunTaskInProcessingQueue(PROCESSING_QUEUE_ID_RFCOMM, RfcommSessionTimeout, context);
79
80 return;
81 }
82
RfcommSessionTimeout(void * parameter)83 void RfcommSessionTimeout(void *parameter)
84 {
85 LOG_INFO("%{public}s", __func__);
86
87 bool isSessionValid = RfcommIsSessionValid((RfcommSessionInfo *)parameter);
88 if (!isSessionValid) {
89 LOG_ERROR("%{public}s:Session is closed.", __func__);
90 return;
91 }
92
93 RfcommSessionEvtFsm((RfcommSessionInfo *)parameter, EV_SESSION_TIMEOUT, NULL);
94 }
95
96 /**
97 * @brief Start session's timer.
98 *
99 * @param session The pointer of the session in the session list.
100 * @param timeout Timeout value.
101 */
RfcommStartSessionTimer(RfcommSessionInfo * session,uint8_t timeout)102 void RfcommStartSessionTimer(RfcommSessionInfo *session, uint8_t timeout)
103 {
104 LOG_INFO("%{public}s", __func__);
105
106 if (session->timer == NULL) {
107 LOG_ERROR("%{public}s Session's timer is NULL.", __func__);
108 return;
109 }
110
111 AlarmSet(session->timer, timeout * RFCOMM_PER_SEC, RfcommSessionTimeoutCallback, session);
112 }
113
114 /**
115 * @brief Stop session's timer.
116 *
117 * @param session The pointer of the session in the session list.
118 */
RfcommStopSessionTimer(RfcommSessionInfo * session)119 void RfcommStopSessionTimer(RfcommSessionInfo *session)
120 {
121 LOG_INFO("%{public}s", __func__);
122
123 if (session->timer == NULL) {
124 LOG_ERROR("%{public}s Session's timer is NULL.", __func__);
125 return;
126 }
127
128 AlarmCancel(session->timer);
129 }
130
131 /**
132 * @brief This function is used to register session information.
133 *
134 * @param addr The peer's BT address.
135 * @param lcid L2CAP channel id.
136 * @param id sequence id(Only used in L2CIF_ConnectRsp).
137 * @param isInitiator Whether it is the initiator. true: initiator, false: non-initiator.
138 * @return The pointer of the new session in the session list.
139 */
RfcommCreateSession(const BtAddr * addr,uint16_t lcid,uint8_t id,bool isInitiator)140 RfcommSessionInfo *RfcommCreateSession(const BtAddr *addr, uint16_t lcid, uint8_t id, bool isInitiator)
141 {
142 LOG_INFO("%{public}s", __func__);
143
144 if (g_sessionList == NULL) {
145 LOG_ERROR("%{public}s Session list is NULL.", __func__);
146 return NULL;
147 }
148
149 int32_t listCount = ListGetSize(g_sessionList);
150 // If sessionlist's size exceeds 6, there is no resource to establish a new session connection,
151 // and NULL is returned
152 if (listCount >= MAX_SESSION_COUNT) {
153 LOG_ERROR("%{public}s Session is over Max count.", __func__);
154 return NULL;
155 }
156 // Malloc a new session resource.
157 RfcommSessionInfo *session = malloc(sizeof(RfcommSessionInfo));
158 if (session == NULL) {
159 return NULL;
160 }
161 session->isInitiator = isInitiator;
162 (void)memcpy_s(&(session->btAddr), sizeof(BtAddr), addr, sizeof(BtAddr));
163 session->l2capId = lcid;
164 session->id = id;
165 session->pendingL2capId = 0;
166 session->pendingId = 0;
167 session->fcType = FC_TYPE_UNKNOWN;
168 session->sessionState = ST_SESSION_CLOSED;
169 session->l2capLocalMtu = RFCOMM_L2CAP_MTU;
170 session->l2capPeerMtu = RFCOMM_L2CAP_DEFAUT_MTU;
171 session->timer = AlarmCreate(NULL, false);
172 session->peerSessionFc = false;
173 // Add the new session info to the session list.
174 ListAddLast(g_sessionList, session);
175
176 // Return a session pointer.
177 return session;
178 }
179
180 /**
181 * @brief During the session disconnection process, the upper layer sends a DLC connection request,
182 * reset part of session data.
183 *
184 * @param session The pointer of the session in the session list.
185 */
RfcommResetSessionInfo(RfcommSessionInfo * session)186 void RfcommResetSessionInfo(RfcommSessionInfo *session)
187 {
188 LOG_INFO("%{public}s", __func__);
189
190 RfcommStopSessionTimer(session);
191 session->isInitiator = false;
192 session->l2capId = 0;
193 session->id = 0;
194 session->pendingL2capId = 0;
195 session->pendingId = 0;
196 session->peerSessionFc = false;
197 session->fcType = FC_TYPE_UNKNOWN;
198 session->sessionState = ST_SESSION_CLOSED;
199 session->l2capLocalMtu = RFCOMM_L2CAP_MTU;
200 session->l2capPeerMtu = RFCOMM_L2CAP_DEFAUT_MTU;
201 }
202
203 /**
204 * @brief Set flown control type of the session.
205 *
206 * @param session The pointer of the session in the session list.
207 * @param isPnReq true:Pn request, false:Pn response.
208 * @param cl cl value.
209 */
RfcommSetFlowControlType(RfcommSessionInfo * session,bool isPnReq,uint8_t cl)210 void RfcommSetFlowControlType(RfcommSessionInfo *session, bool isPnReq, uint8_t cl)
211 {
212 LOG_INFO("%{public}s", __func__);
213
214 if (session->fcType != FC_TYPE_UNKNOWN) {
215 LOG_INFO("%{public}s flow control type is confirmed.", __func__);
216 return;
217 }
218
219 // A responding implementation shall set this field in the PN response to 14 (0xE),
220 // if (and only if) the value in the PN request was 15.Ref-RFCOMM_SPEC_V12(5.5.3).
221 if (isPnReq) {
222 if (cl == CL_REQ_SUPPORT_CREDIT) {
223 session->fcType = FC_TYPE_CREDIT;
224 } else {
225 session->fcType = FC_TYPE_NORMAL;
226 }
227 } else {
228 if (cl == CL_RSP_SUPPORT_CREDIT) {
229 session->fcType = FC_TYPE_CREDIT;
230 } else {
231 session->fcType = FC_TYPE_NORMAL;
232 }
233 }
234 }
235
236 /**
237 * @brief Remove session node from session list and free the session resources.
238 *
239 * @param session The pointer of the session in the session list.
240 */
RfcommRemoveSession(RfcommSessionInfo * session)241 void RfcommRemoveSession(RfcommSessionInfo *session)
242 {
243 LOG_INFO("%{public}s", __func__);
244
245 ListRemoveNode(g_sessionList, session);
246
247 if (session->timer != NULL) {
248 AlarmDelete(session->timer);
249 session->timer = NULL;
250 }
251
252 free(session);
253 }
254
255 /**
256 * @brief This function is used to find the specified session using lcid.
257 *
258 * @param lcid The lcid value.
259 * @return The pointer of the session in the session list.
260 */
RfcommGetSessionByLcid(uint16_t lcid)261 RfcommSessionInfo *RfcommGetSessionByLcid(uint16_t lcid)
262 {
263 LOG_INFO("%{public}s lcid:%hu", __func__, lcid);
264
265 RfcommSessionInfo *session = NULL;
266 ListNode *node = NULL;
267
268 if (g_sessionList == NULL) {
269 LOG_ERROR("%{public}s Session list is NULL.", __func__);
270 return NULL;
271 }
272
273 node = ListGetFirstNode(g_sessionList);
274 while (node != NULL) {
275 session = ListGetNodeData(node);
276 if (session->l2capId == lcid) {
277 return session;
278 }
279 node = ListGetNextNode(node);
280 }
281
282 return NULL;
283 }
284
285 /**
286 * @brief This function is used to find the specified session using BT address.
287 *
288 * @param addr BT address.
289 * @return The pointer of the session in the session list.
290 */
RfcommGetSessionByAddr(const BtAddr * addr)291 RfcommSessionInfo *RfcommGetSessionByAddr(const BtAddr *addr)
292 {
293 LOG_INFO("%{public}s", __func__);
294
295 RfcommSessionInfo *session = NULL;
296 ListNode *node = NULL;
297
298 if (g_sessionList == NULL) {
299 LOG_ERROR("%{public}s Session list is NULL.", __func__);
300 return NULL;
301 }
302
303 node = ListGetFirstNode(g_sessionList);
304 while (node != NULL) {
305 session = ListGetNodeData(node);
306 if (!memcmp(&session->btAddr, addr, sizeof(BtAddr))) {
307 return session;
308 }
309 node = ListGetNextNode(node);
310 }
311
312 return NULL;
313 }
314
315 /**
316 * @brief Check if the session is valid.
317 *
318 * @param session The pointer of the session.
319 * @return True if the session exists,false if the session doesn't exist.
320 */
RfcommIsSessionValid(RfcommSessionInfo * session)321 bool RfcommIsSessionValid(RfcommSessionInfo *session)
322 {
323 LOG_INFO("%{public}s", __func__);
324
325 RfcommSessionInfo *sessionInfo = NULL;
326 ListNode *node = NULL;
327
328 if (g_sessionList == NULL) {
329 LOG_ERROR("%{public}s Session list is NULL.", __func__);
330 return NULL;
331 }
332
333 // Check if there is a channel on the session.
334 node = ListGetFirstNode(g_sessionList);
335 while (node != NULL) {
336 sessionInfo = ListGetNodeData(node);
337 if (sessionInfo == session) {
338 LOG_DEBUG("%{public}s The session is valid.", __func__);
339 return true;
340 }
341 node = ListGetNextNode(node);
342 }
343
344 return false;
345 }