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 }