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 }