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 const unsigned char G_CRCTABLE[256] = {  // Refer to B.3.5 Reversed CRC table of GSM 07.10,v6.3.0
19     0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75, 0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B,
20     0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69, 0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67,
21     0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D, 0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43,
22     0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51, 0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F,
23     0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05, 0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B,
24     0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19, 0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17,
25     0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D, 0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33,
26     0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21, 0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F,
27     0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95, 0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B,
28     0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89, 0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87,
29     0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD, 0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3,
30     0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1, 0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF,
31     0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5, 0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB,
32     0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9, 0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7,
33     0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD, 0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3,
34     0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1, 0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF
35 };
36 
37 static bool RfcommIsSabmDiscValid(RfcommCheckFrameValidInfo info);
38 static bool RfcommIsUaValid(RfcommCheckFrameValidInfo info);
39 static bool RfcommIsDmValid(RfcommCheckFrameValidInfo info);
40 static bool RfcommIsUihValid(RfcommCheckFrameValidInfo info);
41 static bool RfcommCheckFcs(uint8_t len, uint8_t recvfcs, const uint8_t *p);
42 static uint8_t RfcommCalculateFcs(uint8_t len, const uint8_t *p);
43 static void RfcommParseHeaderTail(Packet *pkt, RfcommFrameHeaderTailInfo *headTailInfo);
44 static RfcommEventType RfcommParseSabm(
45     RfcommCheckFrameValidInfo checkInfo, uint8_t addrDlci, RfcommParseFrameResult output);
46 static RfcommEventType RfcommParseDisc(
47     RfcommCheckFrameValidInfo checkInfo, uint8_t addrDlci, RfcommParseFrameResult output);
48 static RfcommEventType RfcommParseUa(
49     RfcommCheckFrameValidInfo checkInfo, uint8_t addrDlci, RfcommParseFrameResult output);
50 static RfcommEventType RfcommParseDm(
51     RfcommCheckFrameValidInfo checkInfo, uint8_t addrDlci, RfcommParseFrameResult output);
52 static RfcommEventType RfcommParseUih(RfcommCheckFrameValidInfo checkInfo, uint8_t addrDlci, Packet *pkt,
53     RfcommFlowControlType fcType, RfcommParseFrameResult output);
54 static RfcommEventType RfcommParseUihCmd(Packet *pkt, RfcommParseFrameResult output);
55 static RfcommEventType RfcommSetPnInfo(Packet *pkt, uint8_t typeCr, RfcommParseFrameResult output);
56 static RfcommEventType RfcommSetMscInfo(Packet *pkt, uint8_t typeCr, RfcommParseFrameResult output);
57 static RfcommEventType RfcommSetRpnInfo(Packet *pkt, uint8_t typeCr, RfcommParseFrameResult output);
58 static RfcommEventType RfcommSetRlsInfo(Packet *pkt, uint8_t typeCr, RfcommParseFrameResult output);
59 static RfcommEventType RfcommSetTestInfo(Packet *pkt, uint8_t typeCr, RfcommParseFrameResult output);
60 static RfcommEventType RfcommSetFcOnOffInfo(Packet *pkt, uint8_t typeCr, uint8_t type, RfcommParseFrameResult output);
61 static RfcommEventType RfcommSetNscInfo(Packet *pkt, RfcommParseFrameResult output);
62 
63 /**
64  * @brief The function is used to calculate FCS.
65  *        The function is referred to B.3.3 The transmitter code of GSM 07.10,v6.3.0.
66  *
67  * @param len The number of bytes to be calculated.
68  * @param p   Pointer of the information to be calculated.
69  * @return The FCS value.
70  */
RfcommCalculateFcs(uint8_t len,const uint8_t * p)71 uint8_t RfcommCalculateFcs(uint8_t len, const uint8_t *p)
72 {
73     LOG_INFO("%{public}s", __func__);
74 
75     // Init
76     uint8_t fcs = 0xFF;
77 
78     // len is the number of bytes in the message, p points to message.
79     while (len--) {
80         fcs = G_CRCTABLE[fcs ^ *p++];
81     }
82     fcs = 0xFF - fcs;
83 
84     return fcs;
85 }
86 
87 /**
88  * @brief The function is used to check FCS.
89  *        The function is referred to B.3.4 The receiver code of GSM 07.10,v6.3.0.
90  *
91  * @param len     The number of bytes to be calculated.
92  * @param recvfcs Received fcs value.
93  * @param p       Pointer of the information to be calculated.
94  * @return Check result.true:FCS is OK,false:FCS is not OK.
95  */
RfcommCheckFcs(uint8_t len,uint8_t recvfcs,const uint8_t * p)96 bool RfcommCheckFcs(uint8_t len, uint8_t recvfcs, const uint8_t *p)
97 {
98     LOG_INFO("%{public}s", __func__);
99 
100     // Init
101     uint8_t fcs = 0xFF;
102     bool result = false;
103 
104     // len is the number of bytes in the message, p points to message.
105     while (len--) {
106         fcs = G_CRCTABLE[fcs ^ *p++];
107     }
108     fcs = G_CRCTABLE[fcs ^ recvfcs];
109     if (fcs == 0xCF) {
110         result = true;
111     } else {
112         LOG_ERROR("%{public}s Fcs check error, recvfcs is %hhu.", __func__, recvfcs);
113     }
114 
115     return result;
116 }
117 
118 /**
119  * @brief The function is used to send SABM command.
120  *
121  * @param session The pointer of the session in the session list.
122  * @param dlci    The dlci value.
123  * @return Returns <b>RFCOMM_SUCCESS</b> if the operation is successful, otherwise the operation fails.
124  */
RfcommSendSabm(const RfcommSessionInfo * session,uint8_t dlci)125 int RfcommSendSabm(const RfcommSessionInfo *session, uint8_t dlci)
126 {
127     LOG_INFO("%{public}s", __func__);
128 
129     uint8_t header[RFCOMM_SABM_HEADER_LEN] = {0};
130     uint8_t cr = (session->isInitiator) ? 1 : 0;
131 
132     // Address
133     header[RFCOMM_ADDRESS] = EA | (cr << RFCOMM_SHIFT_CR) | (dlci << RFCOMM_SHIFT_DLCI);
134     // Control
135     header[RFCOMM_CONTROL] = FRAME_TYPE_SABM | PF;
136     // Length
137     header[RFCOMM_LENGTH_1] = EA;
138     // FCS
139     uint8_t tail = RfcommCalculateFcs(RFCOMM_NOT_UIH_FSC_LEN, header);
140 
141     return RfcommSendData(session->l2capId, header, RFCOMM_SABM_HEADER_LEN, tail, NULL);
142 }
143 
144 /**
145  * @brief The function is used to send DISC command.
146  *
147  * @param session The pointer of the session in the session list.
148  * @param dlci    The dlci value.
149  * @return Returns <b>RFCOMM_SUCCESS</b> if the operation is successful, otherwise the operation fails.
150  */
RfcommSendDisc(const RfcommSessionInfo * session,uint8_t dlci)151 int RfcommSendDisc(const RfcommSessionInfo *session, uint8_t dlci)
152 {
153     LOG_INFO("%{public}s", __func__);
154 
155     uint8_t header[RFCOMM_DISC_HEADER_LEN] = {0};
156     uint8_t cr = (session->isInitiator) ? 1 : 0;
157 
158     // Address
159     header[RFCOMM_ADDRESS] = EA | (cr << RFCOMM_SHIFT_CR) | (dlci << RFCOMM_SHIFT_DLCI);
160     // Control
161     header[RFCOMM_CONTROL] = FRAME_TYPE_DISC | PF;
162     // Length
163     header[RFCOMM_LENGTH_1] = EA;
164     // FCS
165     uint8_t tail = RfcommCalculateFcs(RFCOMM_NOT_UIH_FSC_LEN, header);
166 
167     return RfcommSendData(session->l2capId, header, RFCOMM_DISC_HEADER_LEN, tail, NULL);
168 }
169 
170 /**
171  * @brief The function is used to send UA response.
172  *
173  * @param session The pointer of the session in the session list.
174  * @param dlci    The dlci value.
175  * @return Returns <b>RFCOMM_SUCCESS</b> if the operation is successful, otherwise the operation fails.
176  */
RfcommSendUa(const RfcommSessionInfo * session,uint8_t dlci)177 int RfcommSendUa(const RfcommSessionInfo *session, uint8_t dlci)
178 {
179     LOG_INFO("%{public}s", __func__);
180 
181     uint8_t header[RFCOMM_UA_HEADER_LEN] = {0};
182     uint8_t cr = (!session->isInitiator) ? 1 : 0;
183 
184     // Address
185     header[RFCOMM_ADDRESS] = EA | (cr << RFCOMM_SHIFT_CR) | (dlci << RFCOMM_SHIFT_DLCI);
186     // Control
187     header[RFCOMM_CONTROL] = FRAME_TYPE_UA | PF;
188     // Length
189     header[RFCOMM_LENGTH_1] = EA;
190     // FCS
191     uint8_t tail = RfcommCalculateFcs(RFCOMM_NOT_UIH_FSC_LEN, header);
192 
193     return RfcommSendData(session->l2capId, header, RFCOMM_UA_HEADER_LEN, tail, NULL);
194 }
195 
196 /**
197  * @brief The function is used to send DM response.
198  *
199  * @param session The pointer of the session in the session list.
200  * @param dlci    The dlci value.
201  * @param pf      Is the pf value 1.true:yes, false:no
202  * @return Returns <b>RFCOMM_SUCCESS</b> if the operation is successful, otherwise the operation fails.
203  */
RfcommSendDm(const RfcommSessionInfo * session,uint8_t dlci,bool pf)204 int RfcommSendDm(const RfcommSessionInfo *session, uint8_t dlci, bool pf)
205 {
206     LOG_INFO("%{public}s", __func__);
207 
208     uint8_t header[RFCOMM_DM_HEADER_LEN] = {0};
209     uint8_t cr = (!session->isInitiator) ? 1 : 0;
210 
211     // Address
212     header[RFCOMM_ADDRESS] = EA | (cr << RFCOMM_SHIFT_CR) | (dlci << RFCOMM_SHIFT_DLCI);
213     // Control
214     header[RFCOMM_CONTROL] = FRAME_TYPE_DM | (pf ? PF : 0);
215     // Length
216     header[RFCOMM_LENGTH_1] = EA;
217     // FCS
218     uint8_t tail = RfcommCalculateFcs(RFCOMM_NOT_UIH_FSC_LEN, header);
219 
220     return RfcommSendData(session->l2capId, header, RFCOMM_DM_HEADER_LEN, tail, NULL);
221 }
222 
223 /**
224  * @brief The function is used to send UIH(PN) command/response.
225  *
226  * @param session The pointer of the session in the session list.
227  * @param dlci    The dlci value.
228  * @param isCmd   <b>true</b> if this is a command; <b>false</b> if this is a response.
229  * @param pnInfo  The PN information to send to peer.
230  * @return Returns <b>RFCOMM_SUCCESS</b> if the operation is successful, otherwise the operation fails.
231  */
RfcommSendUihPn(const RfcommSessionInfo * session,uint8_t dlci,bool isCmd,const RfcommSendPnInfo * pnInfo)232 int RfcommSendUihPn(const RfcommSessionInfo *session, uint8_t dlci, bool isCmd, const RfcommSendPnInfo *pnInfo)
233 {
234     LOG_INFO("%{public}s", __func__);
235 
236     uint8_t header[RFCOMM_PN_HEADER_LEN] = {0};
237     uint8_t addressCR = (session->isInitiator) ? 1 : 0;
238     uint8_t infoCR = isCmd ? 1 : 0;
239 
240     // Address
241     header[RFCOMM_ADDRESS] = EA | (addressCR << RFCOMM_SHIFT_CR) | (CONTROL_DLCI << RFCOMM_SHIFT_DLCI);
242     // Control
243     header[RFCOMM_CONTROL] = FRAME_TYPE_UIH | 0;
244     // Length(info:type 1byte + len 1byte + PN info 8byte)
245     header[RFCOMM_LENGTH_1] = EA | (RFCOMM_PN_FRAME_LEN) << 1;
246     // Information(Type)
247     header[RFCOMM_INFO_TYPE] = EA | (infoCR << RFCOMM_SHIFT_CR) | (UIH_TYPE_PN << RFCOMM_SHIFT_TYPE);
248     // Information(Length)
249     header[RFCOMM_INFO_LEN] = EA | (RFCOMM_PN_INFO_LEN << 1);
250     // Information(D1~D6)
251     header[RFCOMM_PN_DLCI] = dlci;
252     // Information(I1~I4,CL1~CL4)
253     header[RFCOMM_PN_CL] = 0 | (pnInfo->cl << RFCOMM_PN_SHIFT_CL);
254     // Information(P1~P6)
255     header[RFCOMM_PN_PRIORITY] = pnInfo->priority;
256     // Information(T1~T8)
257     header[RFCOMM_PN_TIME] = 0;
258     // Information(N1~N8)
259     header[RFCOMM_PN_MTU1] = pnInfo->mtu & 0xFF;
260     // Information(N9~N16)
261     header[RFCOMM_PN_MTU2] = (pnInfo->mtu & 0xFF00) >> RFCOMM_PN_SHIFT_MTU;
262     // Information(NA1~NA8)
263     header[RFCOMM_PN_NA] = 0;
264     // Information(K1~K3)
265     header[RFCOMM_PN_CREDIT] = pnInfo->credits;
266     // FCS(For UIH frames: on Address and Control field.)
267     uint8_t tail = RfcommCalculateFcs(RFCOMM_IS_UIH_FSC_LEN, header);
268 
269     return RfcommSendData(session->l2capId, header, RFCOMM_PN_HEADER_LEN, tail, NULL);
270 }
271 
272 /**
273  * @brief The function is used to send UIH(MSC) command/response.
274  *
275  * @param session  The pointer of the session in the session list.
276  * @param dlci     The dlci value.
277  * @param isCmd    <b>true</b> if this is a command; <b>false</b> if this is a response.
278  * @param modemSts Modem status information.
279  * @return Returns <b>RFCOMM_SUCCESS</b> if the operation is successful, otherwise the operation fails.
280  */
RfcommSendUihMsc(const RfcommSessionInfo * session,uint8_t dlci,bool isCmd,const RfcommModemStatusInfo * modemSts)281 int RfcommSendUihMsc(const RfcommSessionInfo *session, uint8_t dlci, bool isCmd, const RfcommModemStatusInfo *modemSts)
282 {
283     LOG_INFO("%{public}s", __func__);
284 
285     uint8_t header[RFCOMM_MSC_HAVEBREAK_HEADER_LEN] = {0};
286     uint8_t addressCR = (session->isInitiator) ? 1 : 0;
287     uint8_t infoCR = (isCmd) ? 1 : 0;
288     uint8_t headerLength = (modemSts->breakSignal) ? RFCOMM_MSC_HAVEBREAK_HEADER_LEN : RFCOMM_MSC_NO_BREAK_HEADER_LEN;
289     uint8_t frameLength = (modemSts->breakSignal) ? RFCOMM_MSC_FRAME_HAVEBREAK_LEN : RFCOMM_MSC_FRAME_NO_BREAK_LEN;
290     uint8_t infoLength = (modemSts->breakSignal) ? RFCOMM_MSC_INFO_HAVEBREAK_LEN : RFCOMM_MSC_INFO_NO_BREAK_LEN;
291 
292     // Address
293     header[RFCOMM_ADDRESS] = EA | (addressCR << RFCOMM_SHIFT_CR) | (CONTROL_DLCI << RFCOMM_SHIFT_DLCI);
294     // Control
295     header[RFCOMM_CONTROL] = FRAME_TYPE_UIH | 0;
296     // Length(info:type 1byte + len 1byte + DLCI 1byte + V.24signals 1bytes +(breakSignal))
297     header[RFCOMM_LENGTH_1] = EA | (frameLength << 1);
298     // Information(Type)
299     header[RFCOMM_INFO_TYPE] = EA | (infoCR << RFCOMM_SHIFT_CR) | (UIH_TYPE_MSC << RFCOMM_SHIFT_TYPE);
300     // Information(Length)
301     header[RFCOMM_INFO_LEN] = EA | (infoLength << 1);
302     // Information(DLCI)
303     header[RFCOMM_MSC_DLCI] = EA | (1 << 1) | (dlci << RFCOMM_SHIFT_DLCI);
304     // Information(V.24 signals)
305     header[RFCOMM_MSC_SIGNAL] = EA | (modemSts->signals << 1);
306     // Information(Break signals)
307     if (modemSts->breakSignal) {
308         header[RFCOMM_MSC_BREAK] = EA | (modemSts->breakSignal << 1);
309     }
310     // FCS(For UIH frames: on Address and Control field.)
311     uint8_t tail = RfcommCalculateFcs(RFCOMM_IS_UIH_FSC_LEN, header);
312 
313     return RfcommSendData(session->l2capId, header, headerLength, tail, NULL);
314 }
315 
316 /**
317  * @brief The function is used to send UIH(RLS) command/response.
318  *
319  * @param session    The pointer of the session in the session list.
320  * @param dlci       The dlci value.
321  * @param isCmd      <b>true</b> if this is a command; <b>false</b> if this is a response.
322  * @param lineStatus Line status information.
323  * @return Returns <b>RFCOMM_SUCCESS</b> if the operation is successful, otherwise the operation fails.
324  */
RfcommSendUihRls(const RfcommSessionInfo * session,uint8_t dlci,bool isCmd,uint8_t lineStatus)325 int RfcommSendUihRls(const RfcommSessionInfo *session, uint8_t dlci, bool isCmd, uint8_t lineStatus)
326 {
327     LOG_INFO("%{public}s", __func__);
328 
329     uint8_t header[RFCOMM_RLS_HEADER_LEN] = {0};
330     uint8_t addressCR = (session->isInitiator) ? 1 : 0;
331     uint8_t infoCR = isCmd ? 1 : 0;
332 
333     // Address
334     header[RFCOMM_ADDRESS] = EA | (addressCR << RFCOMM_SHIFT_CR) | (CONTROL_DLCI << RFCOMM_SHIFT_DLCI);
335     // Control
336     header[RFCOMM_CONTROL] = FRAME_TYPE_UIH | 0;
337     // Length(info:type 1byte + len 1byte + DLCI 1byte + rls 1bytes)
338     header[RFCOMM_LENGTH_1] = EA | (RFCOMM_RLS_FRAME_LEN << 1);
339     // Information(Type)
340     header[RFCOMM_INFO_TYPE] = EA | (infoCR << RFCOMM_SHIFT_CR) | (UIH_TYPE_RLS << RFCOMM_SHIFT_TYPE);
341     // Information(Length)
342     header[RFCOMM_INFO_LEN] = EA | (RFCOMM_RLS_INFO_LEN << 1);
343     // Information(DLCI)
344     header[RFCOMM_RLS_DLCI] = EA | (1 << 1) | (dlci << RFCOMM_SHIFT_DLCI);
345     // Information(rls)
346     header[RFCOMM_RLS_STATUS] = lineStatus;
347     // FCS(For UIH frames: on Address and Control field.)
348     uint8_t tail = RfcommCalculateFcs(RFCOMM_IS_UIH_FSC_LEN, header);
349 
350     return RfcommSendData(session->l2capId, header, RFCOMM_RLS_HEADER_LEN, tail, NULL);
351 }
352 
353 /**
354  * @brief The function is used to send UIH(RPN) command/response.
355  *
356  * @param session    The pointer of the session in the session list.
357  * @param dlci       The dlci value.
358  * @param isCmd      <b>true</b> if this is a command; <b>false</b> if this is a response.
359  * @param portConfig Remote port setting information.
360  * @return Returns <b>RFCOMM_SUCCESS</b> if the operation is successful, otherwise the operation fails.
361  */
RfcommSendUihRpn(const RfcommSessionInfo * session,uint8_t dlci,bool isCmd,const RfcommRemotePortConfig * portConfig)362 int RfcommSendUihRpn(const RfcommSessionInfo *session, uint8_t dlci, bool isCmd,
363                      const RfcommRemotePortConfig *portConfig)
364 {
365     LOG_INFO("%{public}s", __func__);
366 
367     uint8_t header[RFCOMM_RPN_CMDHEADER_LEN] = {0};
368     uint8_t headerLength = portConfig ? RFCOMM_RPN_CMDHEADER_LEN : RFCOMM_RPN_REQHEADER_LEN;
369     uint8_t frameLength = portConfig ? RFCOMM_RPN_CMDFRAME_LEN : RFCOMM_RPN_REQFRAME_LEN;
370     uint8_t infoLength = portConfig ? RFCOMM_RPN_CMDINFO_LEN : RFCOMM_RPN_REQINFO_LEN;
371     uint8_t addressCR = (session->isInitiator) ? 1 : 0;
372     uint8_t infoCR = isCmd ? 1 : 0;
373 
374     // Address
375     header[RFCOMM_ADDRESS] = EA | (addressCR << RFCOMM_SHIFT_CR) | (CONTROL_DLCI << RFCOMM_SHIFT_DLCI);
376     // Control
377     header[RFCOMM_CONTROL] = FRAME_TYPE_UIH | 0;
378     // Length(info:type 1byte + len 1byte + DLCI 1byte + (rpn 7bytes))
379     header[RFCOMM_LENGTH_1] = EA | (frameLength << 1);
380     // Information(Type)
381     header[RFCOMM_INFO_TYPE] = EA | (infoCR << RFCOMM_SHIFT_CR) | (UIH_TYPE_RPN << RFCOMM_SHIFT_TYPE);
382     // Information(Length)
383     header[RFCOMM_INFO_LEN] = EA | (infoLength << 1);
384     // Information(DLCI)
385     header[RFCOMM_RPN_DLCI] = EA | (1 << 1) | (dlci << RFCOMM_SHIFT_DLCI);
386     // Information(rpn)
387     if (portConfig != NULL) {
388         header[RFCOMM_RPN_BAUDRATE] = portConfig->baudrate;
389         header[RFCOMM_RPN_BITINFO] = portConfig->data_bits |
390                                     ((portConfig->stop_bit) << RFCOMM_RPN_SHIFT_STOP_BIT) |
391                                     ((portConfig->parity) << RFCOMM_RPN_SHIFT_PARITY) |
392                                     ((portConfig->parity_type) << RFCOMM_RPN_SHIFT_PARITY_TYPE);
393         header[RFCOMM_RPN_FLC] = portConfig->fc;
394         header[RFCOMM_RPN_XON] = portConfig->xon_char;
395         header[RFCOMM_RPN_XOFF] = portConfig->xoff_char;
396         header[RFCOMM_RPN_MASK1] = portConfig->parameter_mask1;
397         header[RFCOMM_RPN_MASK2] = portConfig->parameter_mask2;
398     }
399     // FCS(For UIH frames: on Address and Control field.)
400     uint8_t tail = RfcommCalculateFcs(RFCOMM_IS_UIH_FSC_LEN, header);
401 
402     return RfcommSendData(session->l2capId, header, headerLength, tail, NULL);
403 }
404 
405 /**
406  * @brief The function is used to send UIH(FCon) command/response.
407  *
408  * @param session The pointer of the session in the session list.
409  * @param isCmd   <b>true</b> if this is a command; <b>false</b> if this is a response.
410  * @return Returns <b>RFCOMM_SUCCESS</b> if the operation is successful, otherwise the operation fails.
411  */
RfcommSendUihFcon(const RfcommSessionInfo * session,bool isCmd)412 int RfcommSendUihFcon(const RfcommSessionInfo *session, bool isCmd)
413 {
414     LOG_INFO("%{public}s", __func__);
415 
416     uint8_t header[RFCOMM_FCON_HEADER_LEN] = {0};
417     uint8_t addressCR = (session->isInitiator) ? 1 : 0;
418     uint8_t infoCR = isCmd ? 1 : 0;
419 
420     // Address
421     header[RFCOMM_ADDRESS] = EA | (addressCR << RFCOMM_SHIFT_CR) | (CONTROL_DLCI << RFCOMM_SHIFT_DLCI);
422     // Control
423     header[RFCOMM_CONTROL] = FRAME_TYPE_UIH | 0;
424     // Length(info:type 1byte + len 1byte + 0byte)
425     header[RFCOMM_LENGTH_1] = EA | (RFCOMM_FCON_FRAME_LEN << 1);
426     // Information(Type)
427     header[RFCOMM_INFO_TYPE] = EA | (infoCR << RFCOMM_SHIFT_CR) | (UIH_TYPE_FCON << RFCOMM_SHIFT_TYPE);
428     // Information(Length)
429     header[RFCOMM_INFO_LEN] = EA | (0 << 1);
430     // FCS(For UIH frames: on Address and Control field.)
431     uint8_t tail = RfcommCalculateFcs(RFCOMM_IS_UIH_FSC_LEN, header);
432 
433     return RfcommSendData(session->l2capId, header, RFCOMM_FCON_HEADER_LEN, tail, NULL);
434 }
435 
436 /**
437  * @brief The function is used to send UIH(FCoff) command/response.
438  *
439  * @param session The pointer of the session in the session list.
440  * @param isCmd   <b>true</b> if this is a command; <b>false</b> if this is a response.
441  * @return Returns <b>RFCOMM_SUCCESS</b> if the operation is successful, otherwise the operation fails.
442  */
RfcommSendUihFcoff(const RfcommSessionInfo * session,bool isCmd)443 int RfcommSendUihFcoff(const RfcommSessionInfo *session, bool isCmd)
444 {
445     LOG_INFO("%{public}s", __func__);
446 
447     uint8_t header[RFCOMM_FCOFF_HEADER_LEN] = {0};
448     uint8_t addressCR = (session->isInitiator) ? 1 : 0;
449     uint8_t infoCR = isCmd ? 1 : 0;
450 
451     // Address
452     header[RFCOMM_ADDRESS] = EA | (addressCR << RFCOMM_SHIFT_CR) | (CONTROL_DLCI << RFCOMM_SHIFT_DLCI);
453     // Control
454     header[RFCOMM_CONTROL] = FRAME_TYPE_UIH | 0;
455     // Length(info:type 1byte + len 1byte + 0byte)
456     header[RFCOMM_LENGTH_1] = EA | (RFCOMM_FCOFF_FRAME_LEN << 1);
457     // Information(Type)
458     header[RFCOMM_INFO_TYPE] = EA | (infoCR << RFCOMM_SHIFT_CR) | (UIH_TYPE_FCOFF << RFCOMM_SHIFT_TYPE);
459     // Information(Length)
460     header[RFCOMM_INFO_LEN] = EA | (0 << 1);
461     // FCS(For UIH frames: on Address and Control field.)
462     uint8_t tail = RfcommCalculateFcs(RFCOMM_IS_UIH_FSC_LEN, header);
463 
464     return RfcommSendData(session->l2capId, header, RFCOMM_FCOFF_HEADER_LEN, tail, NULL);
465 }
466 
467 /**
468  * @brief The function is used to send UIH(Test) command/response.
469  *
470  * @param session The pointer of the session in the session list.
471  * @param isCmd   <b>true</b> if this is a command; <b>false</b> if this is a response.
472  * @param pkt     The payload information.
473  * @return Returns <b>RFCOMM_SUCCESS</b> if the operation is successful, otherwise the operation fails.
474  */
RfcommSendUihTest(const RfcommSessionInfo * session,bool isCmd,Packet * pkt)475 int RfcommSendUihTest(const RfcommSessionInfo *session, bool isCmd, Packet *pkt)
476 {
477     LOG_INFO("%{public}s", __func__);
478 
479     size_t size = PacketPayloadSize(pkt);
480     uint8_t header[RFCOMM_TEST_HEADER_LEN_MAX] = {0};
481     uint8_t len = 0;
482     uint8_t frameLength = (size <= 0x7F) ? (RFCOMM_TEST_FRAME_LEN_MIN + size) :
483                                            (RFCOMM_TEST_FRAME_LEN_MIN + 1 + size);
484     uint8_t addressCR = (session->isInitiator) ? 1 : 0;
485     uint8_t infoCR = isCmd ? 1 : 0;
486 
487     // Address
488     header[len] = EA | (addressCR << RFCOMM_SHIFT_CR) | (CONTROL_DLCI << RFCOMM_SHIFT_DLCI);
489     len++;
490     // Control
491     header[len] = FRAME_TYPE_UIH | 0;
492     len++;
493     // Length(info:type 1byte + len 1/2byte + info)
494     if ((frameLength) <= 0x7F) {
495         header[len] = EA | ((frameLength) << 1);
496         len++;
497     } else {
498         header[len] = ((frameLength) & 0x7F) << 1;
499         len++;
500         header[len] = (frameLength) >> RFCOMM_SHIFT_LENGTH2;
501         len++;
502     }
503     // Information(Type)
504     header[len] = EA | (infoCR << RFCOMM_SHIFT_CR) | (UIH_TYPE_TEST << RFCOMM_SHIFT_TYPE);
505     len++;
506     // Information(information Length)
507     if (size <= 0x7F) {
508         header[len] = EA | (size << 1);
509         len++;
510     } else {
511         header[len] = (size & 0x7F) << 1;
512         len++;
513         header[len] = size >> RFCOMM_SHIFT_LENGTH2;
514         len++;
515     }
516     // FCS(For UIH frames: on Address and Control field.)
517     uint8_t tail = RfcommCalculateFcs(RFCOMM_IS_UIH_FSC_LEN, header);
518 
519     return RfcommSendData(session->l2capId, header, len, tail, pkt);
520 }
521 
522 /**
523  * @brief The function is used to send UIH(NSC) response.
524  *
525  * @param session The pointer of the session in the session list.
526  * @param ea      The EA bit in the type field of the not supported command frame.
527  * @param cr      The C/R bit in the type field of the not supported command frame.
528  * @param type    The not supported command type.
529  * @return Returns <b>RFCOMM_SUCCESS</b> if the operation is successful, otherwise the operation fails.
530  */
RfcommSendUihNsc(const RfcommSessionInfo * session,uint8_t ea,uint8_t cr,uint8_t type)531 int RfcommSendUihNsc(const RfcommSessionInfo *session, uint8_t ea, uint8_t cr, uint8_t type)
532 {
533     LOG_INFO("%{public}s", __func__);
534 
535     uint8_t header[RFCOMM_NSC_HEADER_LEN] = {0};
536     uint8_t addressCR = (session->isInitiator) ? 1 : 0;
537 
538     // Address
539     header[RFCOMM_ADDRESS] = EA | (addressCR << RFCOMM_SHIFT_CR) | (CONTROL_DLCI << RFCOMM_SHIFT_DLCI);
540     // Control
541     header[RFCOMM_CONTROL] = FRAME_TYPE_UIH | 0;
542     // Length(info:type 1byte + len 1byte + info 1byte)
543     header[RFCOMM_LENGTH_1] = EA | (RFCOMM_NSC_FRAME_LEN << 1);
544     // Information(Type)
545     // If the C/R bit is set to 1 the message is a command,
546     // if it is set to 0 the message is a response.
547     header[RFCOMM_INFO_TYPE] = EA | 0 | (UIH_TYPE_NSC << RFCOMM_SHIFT_TYPE);
548     // Information(Length)
549     header[RFCOMM_INFO_LEN] = EA | (RFCOMM_NSC_INFO_LEN << 1);
550     // Information(Non supported command type)
551     header[RFCOMM_NSC_TYPE] = ea | (cr << RFCOMM_SHIFT_CR) | (type << RFCOMM_SHIFT_TYPE);
552     // FCS(For UIH frames: on Address and Control field.)
553     uint8_t tail = RfcommCalculateFcs(RFCOMM_IS_UIH_FSC_LEN, header);
554 
555     return RfcommSendData(session->l2capId, header, RFCOMM_NSC_HEADER_LEN, tail, NULL);
556 }
557 
558 /**
559  * @brief The function is used to send data(or new credits) to peer.
560  *
561  * @param session    The pointer of the session in the session list.
562  * @param dlci       The dlci value.
563  * @param newCredits New credit count.
564  * @param packet     The payload.
565  * @return Returns <b>RFCOMM_SUCCESS</b> if the operation is successful, otherwise the operation fails.
566  */
RfcommSendUihData(const RfcommSessionInfo * session,uint8_t dlci,uint8_t newCredits,Packet * pkt)567 int RfcommSendUihData(const RfcommSessionInfo *session, uint8_t dlci, uint8_t newCredits, Packet *pkt)
568 {
569     LOG_INFO("%{public}s", __func__);
570 
571     size_t size = 0;
572     uint8_t pf = newCredits ? 1 : 0;
573     uint8_t addressCR = (session->isInitiator) ? 1 : 0;
574     uint8_t header[RFCOMM_DATA_HEADER_LEN_MAX] = {0};
575     uint8_t len = 0;
576 
577     if (pkt != NULL) {
578         size = PacketPayloadSize(pkt);
579     }
580 
581     // Address
582     header[len] = EA | (addressCR << RFCOMM_SHIFT_CR) | (dlci << RFCOMM_SHIFT_DLCI);
583     len++;
584     // Control
585     header[len] = FRAME_TYPE_UIH | (pf << RFCOMM_SHIFT_PF);
586     len++;
587     // Length(info:type 1byte + len 1byte + info 1byte)
588     if (size <= 0x7F) {
589         header[len] = EA | (size << 1);
590         len++;
591     } else {
592         header[len] = (size & 0x7F) << 1;
593         len++;
594         header[len] = size >> RFCOMM_SHIFT_LENGTH2;
595         len++;
596     }
597     // credits
598     if (newCredits) {
599         header[len] = newCredits;
600         len++;
601     }
602     // FCS(For UIH frames: on Address and Control field.)
603     uint8_t tail = RfcommCalculateFcs(RFCOMM_IS_UIH_FSC_LEN, header);
604 
605     return RfcommSendData(session->l2capId, header, len, tail, pkt);
606 }
607 
608 /**
609  * @brief The function is used to check if the SABM or DISC frames is valid.
610  *
611  * @param info The information to be checked validity.
612  * @return Check result.true:valid,false:invalid.
613  */
RfcommIsSabmDiscValid(RfcommCheckFrameValidInfo info)614 bool RfcommIsSabmDiscValid(RfcommCheckFrameValidInfo info)
615 {
616     LOG_INFO("%{public}s", __func__);
617 
618     if ((info.dlci != 0) && !IS_DLCI_VALID(info.dlci)) {
619         return false;
620     }
621 
622     if ((!info.pf) || !IS_CMD(info.isInitiator, info.cr) || info.length ||
623         !RfcommCheckFcs(RFCOMM_NOT_UIH_FSC_LEN, info.fcs, info.calcInfo)) {
624         return false;
625     }
626 
627     return true;
628 }
629 
630 /**
631  * @brief The function is used to check if the UA frames is valid.
632  *
633  * @param info The information to be checked validity.
634  * @return Check result.true:valid,false:invalid.
635  */
RfcommIsUaValid(RfcommCheckFrameValidInfo info)636 bool RfcommIsUaValid(RfcommCheckFrameValidInfo info)
637 {
638     LOG_INFO("%{public}s", __func__);
639 
640     if ((info.dlci != 0) && !IS_DLCI_VALID(info.dlci)) {
641         return false;
642     }
643 
644     if ((!info.pf) || !IS_RSP(info.isInitiator, info.cr) || info.length ||
645         !RfcommCheckFcs(RFCOMM_NOT_UIH_FSC_LEN, info.fcs, info.calcInfo)) {
646         return false;
647     }
648 
649     return true;
650 }
651 
652 /**
653  * @brief The function is used to check if the DM frames is valid.
654  *
655  * @param info The information to be checked validity.
656  * @return Check result.true:valid,false:invalid.
657  */
RfcommIsDmValid(RfcommCheckFrameValidInfo info)658 bool RfcommIsDmValid(RfcommCheckFrameValidInfo info)
659 {
660     LOG_INFO("%{public}s", __func__);
661 
662     if ((info.dlci != 0) && !IS_DLCI_VALID(info.dlci)) {
663         return false;
664     }
665 
666     if (!IS_RSP(info.isInitiator, info.cr) || info.length ||
667         !RfcommCheckFcs(RFCOMM_NOT_UIH_FSC_LEN, info.fcs, info.calcInfo)) {
668         return false;
669     }
670 
671     return true;
672 }
673 
674 /**
675  * @brief The function is used to check if the UIH frames is valid.
676  *
677  * @param info The information to be checked validity.
678  * @return Check result.true:valid,false:invalid.
679  */
RfcommIsUihValid(RfcommCheckFrameValidInfo info)680 bool RfcommIsUihValid(RfcommCheckFrameValidInfo info)
681 {
682     LOG_INFO("%{public}s", __func__);
683 
684     if ((info.dlci != 0) && !IS_DLCI_VALID(info.dlci)) {
685         LOG_ERROR("%{public}s Invalid dlci:%hhu.", __func__, info.dlci);
686         return false;
687     }
688 
689     if (!IS_CMD(info.isInitiator, info.cr) || !RfcommCheckFcs(RFCOMM_IS_UIH_FSC_LEN, info.fcs, info.calcInfo)) {
690         LOG_ERROR("%{public}s Uih is invalid, isInitiator:%{public}d, cr:%hhu.", __func__, info.isInitiator, info.cr);
691         return false;
692     }
693 
694     return true;
695 }
696 
697 /**
698  * @brief The function is used to analysis received data.
699  *
700  * @param session The pointer of the session in the session list.
701  * @param pkt     The data received from L2CAP.
702  * @param output  Parsed data.
703  * @return event type. @see RfcommEventType
704  */
RfcommParseFrames(const RfcommSessionInfo * session,Packet * pkt,RfcommParseFrameResult output)705 RfcommEventType RfcommParseFrames(const RfcommSessionInfo *session, Packet *pkt, RfcommParseFrameResult output)
706 {
707     LOG_INFO("%{public}s", __func__);
708 
709     RfcommEventType ret;
710     RfcommFrameHeaderTailInfo headTailInfo;
711     RfcommCheckFrameValidInfo checkInfo;
712     (void)memset_s(&headTailInfo, sizeof(RfcommFrameHeaderTailInfo), 0x00, sizeof(RfcommFrameHeaderTailInfo));
713     (void)memset_s(&checkInfo, sizeof(RfcommCheckFrameValidInfo), 0x00, sizeof(RfcommCheckFrameValidInfo));
714 
715     // Parse frames header and tail information.
716     RfcommParseHeaderTail(pkt, &headTailInfo);
717 
718     // Set ht information to be checked for validity.
719     checkInfo.isInitiator = session->isInitiator;
720     checkInfo.cr = headTailInfo.cr;
721     checkInfo.pf = headTailInfo.pf;
722     checkInfo.dlci = headTailInfo.dlci;
723     checkInfo.length = headTailInfo.length;
724     checkInfo.fcs = headTailInfo.fcs;
725     (void)memcpy_s(checkInfo.calcInfo, sizeof(checkInfo.calcInfo), headTailInfo.calcInfo, sizeof(checkInfo.calcInfo));
726 
727     switch (headTailInfo.type) {
728         case FRAME_TYPE_SABM:
729             ret = RfcommParseSabm(checkInfo, headTailInfo.dlci, output);
730             break;
731         case FRAME_TYPE_UA:
732             ret = RfcommParseUa(checkInfo, headTailInfo.dlci, output);
733             break;
734         case FRAME_TYPE_DISC:
735             ret = RfcommParseDisc(checkInfo, headTailInfo.dlci, output);
736             break;
737         case FRAME_TYPE_DM:
738             ret = RfcommParseDm(checkInfo, headTailInfo.dlci, output);
739             break;
740         case FRAME_TYPE_UIH:
741             ret = RfcommParseUih(checkInfo, headTailInfo.dlci, pkt, session->fcType, output);
742             break;
743         default:
744             ret = EVENT_FRAME_ERR;
745             break;
746     }
747 
748     return ret;
749 }
750 
751 /**
752  * @brief The function is used to analysis frames header and tail information.
753  *
754  * @param pkt           The data received from L2CAP.
755  * @param headTailInfo  Parsed data.
756  * @return event type. @see RfcommEventType
757  */
RfcommParseHeaderTail(Packet * pkt,RfcommFrameHeaderTailInfo * headTailInfo)758 void RfcommParseHeaderTail(Packet *pkt, RfcommFrameHeaderTailInfo *headTailInfo)
759 {
760     LOG_INFO("%{public}s", __func__);
761 
762     uint8_t fcs = 0;
763     uint8_t header[4] = {0};
764 
765     // Frame header
766     PacketExtractHead(pkt, header, 0x03);
767     // Address's CR
768     uint8_t cr = (header[RFCOMM_ADDRESS] >> RFCOMM_SHIFT_CR) & 1;
769     // Address's dlci
770     uint8_t dlci = header[RFCOMM_ADDRESS] >> RFCOMM_SHIFT_DLCI;
771     // Control's frame type
772     uint8_t type = header[RFCOMM_CONTROL] & (~PF);
773     // Control's PF
774     uint8_t pf = (header[RFCOMM_CONTROL] & PF) >> RFCOMM_SHIFT_PF;
775     // Info's length
776     uint8_t ea = header[RFCOMM_LENGTH_1] & EA;
777     uint16_t length = header[RFCOMM_LENGTH_1] >> 1;
778     if (!ea) {
779         PacketExtractHead(pkt, &header[RFCOMM_LENGTH_2], 0x01);
780         length += (header[RFCOMM_LENGTH_2] << RFCOMM_SHIFT_LENGTH2);
781     }
782     // fcs
783     PacketExtractTail(pkt, &fcs, 0x01);
784 
785     headTailInfo->fcs = fcs;
786     headTailInfo->cr = cr;
787     headTailInfo->dlci = dlci;
788     headTailInfo->type = type;
789     headTailInfo->pf = pf;
790     headTailInfo->length = length;
791     headTailInfo->calcInfo[RFCOMM_OFFSET_0] = header[RFCOMM_OFFSET_0];
792     headTailInfo->calcInfo[RFCOMM_OFFSET_1] = header[RFCOMM_OFFSET_1];
793     headTailInfo->calcInfo[RFCOMM_OFFSET_2] = header[RFCOMM_OFFSET_2];
794 }
795 
796 /**
797  * @brief The function is used to analysis SABM information.
798  *
799  * @param checkInfo The info to be checked validity.
800  * @param addrDlci  The dlci value.
801  * @param output    Parsed data.
802  * @return event type. @see RfcommEventType
803  */
RfcommParseSabm(RfcommCheckFrameValidInfo checkInfo,uint8_t addrDlci,RfcommParseFrameResult output)804 RfcommEventType RfcommParseSabm(RfcommCheckFrameValidInfo checkInfo, uint8_t addrDlci, RfcommParseFrameResult output)
805 {
806     LOG_INFO("%{public}s", __func__);
807 
808     if (!RfcommIsSabmDiscValid(checkInfo)) {
809         return EVENT_FRAME_ERR;
810     }
811 
812     if (addrDlci == 0) {
813         *output.event = EV_SESSION_RECV_SABM0;
814         return EVENT_SESSION;
815     }
816 
817     *output.dlci = addrDlci;
818     *output.event = EV_CHANNEL_RECV_SABM;
819 
820     return EVENT_CHANNEL;
821 }
822 
823 /**
824  * @brief The function is used to analysis DISC information.
825  *
826  * @param checkInfo The info to be checked validity.
827  * @param addrDlci  The dlci value.
828  * @param output    Parsed data.
829  * @return event type. @see RfcommEventType
830  */
RfcommParseDisc(RfcommCheckFrameValidInfo checkInfo,uint8_t addrDlci,RfcommParseFrameResult output)831 RfcommEventType RfcommParseDisc(RfcommCheckFrameValidInfo checkInfo, uint8_t addrDlci, RfcommParseFrameResult output)
832 {
833     LOG_INFO("%{public}s", __func__);
834 
835     if (!RfcommIsSabmDiscValid(checkInfo)) {
836         return EVENT_FRAME_ERR;
837     }
838 
839     if (addrDlci == 0) {
840         *output.event = EV_SESSION_RECV_DISC0;
841         return EVENT_SESSION;
842     }
843 
844     *output.dlci = addrDlci;
845     *output.event = EV_CHANNEL_RECV_DISC;
846 
847     return EVENT_CHANNEL;
848 }
849 
850 /**
851  * @brief The function is used to analysis UA information.
852  *
853  * @param checkInfo The info to be checked validity.
854  * @param addrDlci  The dlci value.
855  * @param output    Parsed data.
856  * @return event type. @see RfcommEventType
857  */
RfcommParseUa(RfcommCheckFrameValidInfo checkInfo,uint8_t addrDlci,RfcommParseFrameResult output)858 RfcommEventType RfcommParseUa(RfcommCheckFrameValidInfo checkInfo, uint8_t addrDlci, RfcommParseFrameResult output)
859 {
860     LOG_INFO("%{public}s", __func__);
861 
862     if (!RfcommIsUaValid(checkInfo)) {
863         return EVENT_FRAME_ERR;
864     }
865 
866     if (addrDlci == 0) {
867         *output.event = EV_SESSION_RECV_UA0;
868         return EVENT_SESSION;
869     }
870 
871     *output.dlci = addrDlci;
872     *output.event = EV_CHANNEL_RECV_UA;
873 
874     return EVENT_CHANNEL;
875 }
876 
877 /**
878  * @brief The function is used to analysis DM information.
879  *
880  * @param checkInfo The info to be checked validity.
881  * @param addrDlci  The dlci value.
882  * @param output    Parsed data.
883  * @return event type. @see RfcommEventType
884  */
RfcommParseDm(RfcommCheckFrameValidInfo checkInfo,uint8_t addrDlci,RfcommParseFrameResult output)885 RfcommEventType RfcommParseDm(RfcommCheckFrameValidInfo checkInfo, uint8_t addrDlci, RfcommParseFrameResult output)
886 {
887     LOG_INFO("%{public}s", __func__);
888 
889     if (!RfcommIsDmValid(checkInfo)) {
890         return EVENT_FRAME_ERR;
891     }
892 
893     if (addrDlci == 0) {
894         *output.event = EV_SESSION_RECV_DM0;
895         return EVENT_SESSION;
896     }
897 
898     *output.dlci = addrDlci;
899     *output.event = EV_CHANNEL_RECV_DM;
900 
901     return EVENT_CHANNEL;
902 }
903 
904 /**
905  * @brief The function is used to analysis UIH information.
906  *
907  * @param checkInfo The info to be checked validity.
908  * @param addrDlci  The dlci value.
909  * @param output    Parsed data.
910  * @return event type. @see RfcommEventType
911  */
RfcommParseUih(RfcommCheckFrameValidInfo checkInfo,uint8_t addrDlci,Packet * pkt,RfcommFlowControlType fcType,RfcommParseFrameResult output)912 RfcommEventType RfcommParseUih(RfcommCheckFrameValidInfo checkInfo, uint8_t addrDlci, Packet *pkt,
913     RfcommFlowControlType fcType, RfcommParseFrameResult output)
914 {
915     LOG_INFO("%{public}s", __func__);
916 
917     size_t size = 0;
918     uint8_t credit = 0;
919 
920     if (!RfcommIsUihValid(checkInfo)) {
921         return EVENT_FRAME_ERR;
922     }
923 
924     if (addrDlci == 0) {
925         return RfcommParseUihCmd(pkt, output);
926     }
927 
928     // When the DLCI in address is not 0, it is considered as data transmission.
929     // UIH frames with P/F-bit = 1 and credit based flow control used.
930     if ((checkInfo.pf == 1) && (fcType == FC_TYPE_CREDIT)) {
931         PacketExtractHead(pkt, &credit, 1);
932         output.info->data.credits = credit;
933     }
934 
935     if (pkt != NULL) {
936         size = PacketSize(pkt);
937     }
938 
939     if (checkInfo.length != size) {
940         LOG_ERROR("%{public}s Invalid length.Length is %hu,received size is %zu.", __func__, checkInfo.length, size);
941         return EVENT_FRAME_ERR;
942     }
943 
944     output.info->data.payload = pkt;
945     output.info->data.size = checkInfo.length;
946 
947     *output.dlci = addrDlci;
948     *output.event = EV_CHANNEL_RECV_DATA;
949 
950     return EVENT_CHANNEL;
951 }
952 
953 /**
954  * @brief The function is used to analysis UIH data.
955  *
956  * @param pkt    The data received from L2CAP.
957  * @param dlci   The dlci where the data is transmitted.
958  * @param event  id: @see RfcommChannelEvent, RfcommSessionEvent
959  * @param output Parsed data
960  * @return event type. @see RfcommEventType
961  */
RfcommParseUihCmd(Packet * pkt,RfcommParseFrameResult output)962 RfcommEventType RfcommParseUihCmd(Packet *pkt, RfcommParseFrameResult output)
963 {
964     LOG_INFO("%{public}s", __func__);
965 
966     uint8_t data = 0;
967     RfcommEventType ret;
968 
969     // If DLCI is 0, it is considered as control information transmission on the data link.
970     PacketExtractHead(pkt, &data, 0x01);
971     uint8_t ea = data & EA;
972     uint8_t cr = (data >> RFCOMM_SHIFT_CR) & 1;
973     uint8_t type = data >> RFCOMM_SHIFT_TYPE;
974 
975     if (!ea) {
976         return EVENT_FRAME_ERR;
977     }
978 
979     switch (type) {
980         case UIH_TYPE_PN:
981             ret = RfcommSetPnInfo(pkt, cr, output);
982             break;
983         case UIH_TYPE_MSC:
984             ret = RfcommSetMscInfo(pkt, cr, output);
985             break;
986         case UIH_TYPE_RPN:
987             ret = RfcommSetRpnInfo(pkt, cr, output);
988             break;
989         case UIH_TYPE_RLS:
990             ret = RfcommSetRlsInfo(pkt, cr, output);
991             break;
992         case UIH_TYPE_TEST:
993             ret = RfcommSetTestInfo(pkt, cr, output);
994             break;
995         case UIH_TYPE_FCON:
996             ret = RfcommSetFcOnOffInfo(pkt, cr, UIH_TYPE_FCON, output);
997             break;
998         case UIH_TYPE_FCOFF:
999             ret = RfcommSetFcOnOffInfo(pkt, cr, UIH_TYPE_FCOFF, output);
1000             break;
1001         case UIH_TYPE_NSC:
1002             ret = RfcommSetNscInfo(pkt, output);
1003             break;
1004         default:
1005             output.info->invalidCmd.ea = ea;
1006             output.info->invalidCmd.cr = cr;
1007             output.info->invalidCmd.type = type;
1008             ret = EVENT_UNSUPPORTED_CMD;
1009             break;
1010     }
1011 
1012     return ret;
1013 }
1014 
1015 /**
1016  * @brief The function is used to set PN information.
1017  *
1018  * @param pkt    The data received from L2CAP.
1019  * @param typeCr The cr value in type of the frames.
1020  * @param output Parsed data
1021  * @return event type. @see RfcommEventType
1022  */
RfcommSetPnInfo(Packet * pkt,uint8_t typeCr,RfcommParseFrameResult output)1023 RfcommEventType RfcommSetPnInfo(Packet *pkt, uint8_t typeCr, RfcommParseFrameResult output)
1024 {
1025     LOG_INFO("%{public}s", __func__);
1026 
1027     uint8_t data[8] = {0};
1028 
1029     PacketExtractHead(pkt, data, 0x01);
1030     uint8_t ea = data[RFCOMM_OFFSET_0] & EA;
1031     uint8_t len = data[RFCOMM_OFFSET_0] >> 1;
1032     if (!ea || (len != RFCOMM_PN_INFO_LEN)) {
1033         return EVENT_FRAME_ERR;
1034     }
1035     (void)memset_s(data, sizeof(data), 0x00, sizeof(data));
1036     PacketExtractHead(pkt, data, 0x08);
1037     output.info->pn.dlci = data[RFCOMM_OFFSET_0] & 0x3f;
1038     output.info->pn.cl = data[RFCOMM_OFFSET_1] >> RFCOMM_PN_SHIFT_CL;
1039     output.info->pn.priority = data[RFCOMM_OFFSET_2] & 0x3f;
1040     // T1-T8,(Acknowledgment timer T1, which is not negotiable in RFCOMM.)
1041     output.info->pn.mtu = data[RFCOMM_OFFSET_4];
1042     output.info->pn.mtu += data[RFCOMM_OFFSET_5] << RFCOMM_PN_SHIFT_MTU;
1043     output.info->pn.k = data[RFCOMM_OFFSET_7] & 0x07;
1044 
1045     if (!IS_DLCI_VALID(output.info->pn.dlci) || !IS_MTU_VALID(output.info->pn.mtu)) {
1046         return EVENT_FRAME_ERR;
1047     }
1048 
1049     *output.dlci = output.info->pn.dlci;
1050     *output.event = (typeCr == 1) ? EV_CHANNEL_RECV_PN_REQ : EV_CHANNEL_RECV_PN_RSP;
1051 
1052     return EVENT_CHANNEL;
1053 }
1054 
1055 /**
1056  * @brief The function is used to set MSC information.
1057  *
1058  * @param pkt    The data received from L2CAP.
1059  * @param typeCr The cr value in type of the frames.
1060  * @param output Parsed data
1061  * @return event type. @see RfcommEventType
1062  */
RfcommSetMscInfo(Packet * pkt,uint8_t typeCr,RfcommParseFrameResult output)1063 RfcommEventType RfcommSetMscInfo(Packet *pkt, uint8_t typeCr, RfcommParseFrameResult output)
1064 {
1065     LOG_INFO("%{public}s", __func__);
1066 
1067     uint8_t data[3] = {0};
1068 
1069     PacketExtractHead(pkt, data, 1);
1070     uint8_t ea = data[RFCOMM_OFFSET_0] & EA;
1071     uint8_t len = data[RFCOMM_OFFSET_0] >> 1;
1072     if (!ea || ((len != RFCOMM_MSC_INFO_NO_BREAK_LEN) && (len != RFCOMM_MSC_INFO_HAVEBREAK_LEN))) {
1073         return EVENT_FRAME_ERR;
1074     }
1075     (void)memset_s(data, sizeof(data), 0x00, sizeof(data));
1076     PacketExtractHead(pkt, data, 0x02);
1077     ea = data[RFCOMM_OFFSET_0] & EA;
1078     uint8_t cr = (data[RFCOMM_OFFSET_0] >> RFCOMM_SHIFT_CR) & 1;
1079     output.info->msc.dlci = data[RFCOMM_OFFSET_0] >> RFCOMM_SHIFT_DLCI;
1080     output.info->msc.signal = data[RFCOMM_OFFSET_1] >> 1;
1081     if (len == RFCOMM_MSC_INFO_HAVEBREAK_LEN) {
1082         PacketExtractHead(pkt, &data[RFCOMM_OFFSET_2], 0x01);
1083         output.info->msc.breakSignal = data[RFCOMM_OFFSET_2] >> 1;
1084     }
1085     if (!ea || !cr || !IS_DLCI_VALID(output.info->msc.dlci)) {
1086         return EVENT_FRAME_ERR;
1087     }
1088 
1089     *output.dlci = output.info->msc.dlci;
1090     *output.event = (typeCr == 1) ? EV_CHANNEL_RECV_MSC_REQ : EV_CHANNEL_RECV_MSC_RSP;
1091 
1092     return EVENT_CHANNEL;
1093 }
1094 
1095 /**
1096  * @brief The function is used to set RPN information.
1097  *
1098  * @param pkt    The data received from L2CAP.
1099  * @param typeCr The cr value in type of the frames.
1100  * @param output Parsed data
1101  * @return event type. @see RfcommEventType
1102  */
RfcommSetRpnInfo(Packet * pkt,uint8_t typeCr,RfcommParseFrameResult output)1103 RfcommEventType RfcommSetRpnInfo(Packet *pkt, uint8_t typeCr, RfcommParseFrameResult output)
1104 {
1105     LOG_INFO("%{public}s", __func__);
1106 
1107     uint8_t data[8] = {0};
1108 
1109     PacketExtractHead(pkt, data, 1);
1110     uint8_t ea = data[RFCOMM_OFFSET_0] & EA;
1111     uint8_t len = data[RFCOMM_OFFSET_0] >> 1;
1112     if (!ea || ((len != RFCOMM_RPN_REQINFO_LEN) && (len != RFCOMM_RPN_CMDINFO_LEN))) {
1113         return EVENT_FRAME_ERR;
1114     }
1115     (void)memset_s(data, sizeof(data), 0x00, sizeof(data));
1116     PacketExtractHead(pkt, data, 1);
1117     ea = data[RFCOMM_OFFSET_0] & EA;
1118     uint8_t cr = (data[RFCOMM_OFFSET_0] >> RFCOMM_SHIFT_CR) & 1;
1119     output.info->rpn.dlci = data[RFCOMM_OFFSET_0] >> RFCOMM_SHIFT_DLCI;
1120     if (!ea || !cr || !IS_DLCI_VALID(output.info->rpn.dlci)) {
1121         return EVENT_FRAME_ERR;
1122     }
1123     if (len != RFCOMM_RPN_CMDINFO_LEN) {
1124         output.info->rpn.isCmd = false;
1125     } else {
1126         PacketExtractHead(pkt, &data[RFCOMM_OFFSET_1], 0x07);
1127         output.info->rpn.isCmd = true;
1128         output.info->rpn.rpnInfo.baudrate = data[RFCOMM_OFFSET_1];
1129         output.info->rpn.rpnInfo.data_bits = data[RFCOMM_OFFSET_2] & 0x03;
1130         output.info->rpn.rpnInfo.stop_bit = (data[RFCOMM_OFFSET_2] >> RFCOMM_RPN_SHIFT_STOP_BIT) & 1;
1131         output.info->rpn.rpnInfo.parity = (data[RFCOMM_OFFSET_2] >> RFCOMM_RPN_SHIFT_PARITY) & 1;
1132         output.info->rpn.rpnInfo.parity_type = (data[RFCOMM_OFFSET_2] >> RFCOMM_RPN_SHIFT_PARITY_TYPE) & 0x03;
1133         output.info->rpn.rpnInfo.fc = data[RFCOMM_OFFSET_3] & 0x3f;
1134         output.info->rpn.rpnInfo.xon_char = data[RFCOMM_OFFSET_4];
1135         output.info->rpn.rpnInfo.xoff_char = data[RFCOMM_OFFSET_5];
1136         output.info->rpn.rpnInfo.parameter_mask1 = data[RFCOMM_OFFSET_6] & 0x7f;
1137         output.info->rpn.rpnInfo.parameter_mask2 = data[RFCOMM_OFFSET_7] & 0x3f;
1138     }
1139 
1140     *output.dlci = output.info->rpn.dlci;
1141     if (typeCr == 1) {
1142         *output.event = (output.info->rpn.isCmd) ? EV_CHANNEL_RECV_RPN_CMD : EV_CHANNEL_RECV_RPN_REQ;
1143     } else {
1144         *output.event = EV_CHANNEL_RECV_RPN_RSP;
1145     }
1146 
1147     return EVENT_CHANNEL;
1148 }
1149 
1150 /**
1151  * @brief The function is used to set RLS information.
1152  *
1153  * @param pkt    The data received from L2CAP.
1154  * @param typeCr The cr value in type of the frames.
1155  * @param output Parsed data
1156  * @return event type. @see RfcommEventType
1157  */
RfcommSetRlsInfo(Packet * pkt,uint8_t typeCr,RfcommParseFrameResult output)1158 RfcommEventType RfcommSetRlsInfo(Packet *pkt, uint8_t typeCr, RfcommParseFrameResult output)
1159 {
1160     LOG_INFO("%{public}s", __func__);
1161 
1162     uint8_t data[2] = {0};
1163 
1164     PacketExtractHead(pkt, data, 0x01);
1165     uint8_t ea = data[RFCOMM_OFFSET_0] & EA;
1166     uint8_t len = data[RFCOMM_OFFSET_0] >> 1;
1167     if (!ea || (len != RFCOMM_RLS_INFO_LEN)) {
1168         return EVENT_FRAME_ERR;
1169     }
1170     (void)memset_s(data, sizeof(data), 0x00, sizeof(data));
1171     PacketExtractHead(pkt, data, 0x02);
1172     ea = data[RFCOMM_OFFSET_0] & EA;
1173     uint8_t cr = (data[RFCOMM_OFFSET_0] >> RFCOMM_SHIFT_CR) & 1;
1174     output.info->rls.dlci = data[RFCOMM_OFFSET_0] >> RFCOMM_SHIFT_DLCI;
1175     output.info->rls.lineStatus = data[RFCOMM_OFFSET_1];
1176 
1177     if (!ea || !cr || !IS_DLCI_VALID(output.info->rls.dlci)) {
1178         return EVENT_FRAME_ERR;
1179     }
1180 
1181     *output.dlci = output.info->rls.dlci;
1182     *output.event = (typeCr == 1) ? EV_CHANNEL_RECV_RLS_REQ : EV_CHANNEL_RECV_RLS_RSP;
1183 
1184     return EVENT_CHANNEL;
1185 }
1186 
1187 /**
1188  * @brief The function is used to set NSC information.
1189  *
1190  * @param pkt     The data received from L2CAP.
1191  * @param output  Parsed data
1192  * @return event type. @see RfcommEventType
1193  */
RfcommSetNscInfo(Packet * pkt,RfcommParseFrameResult output)1194 RfcommEventType RfcommSetNscInfo(Packet *pkt, RfcommParseFrameResult output)
1195 {
1196     LOG_INFO("%{public}s", __func__);
1197 
1198     uint8_t data = 0;
1199 
1200     PacketExtractHead(pkt, &data, 0x01);
1201     uint8_t ea = data & EA;
1202     uint8_t len = data >> 1;
1203     if (!ea || (len != RFCOMM_NSC_INFO_LEN)) {
1204         return EVENT_FRAME_ERR;
1205     }
1206     PacketExtractHead(pkt, &data, 0x01);
1207     output.info->nsc.ea = data & 1;
1208     output.info->nsc.cr = (data >> RFCOMM_SHIFT_CR) & 1;
1209     output.info->nsc.type = data >> RFCOMM_SHIFT_TYPE;
1210 
1211     *output.event = EV_SESSION_RECV_NSC;
1212 
1213     return EVENT_SESSION;
1214 }
1215 
1216 /**
1217  * @brief The function is used to set FC on information.
1218  *
1219  * @param pkt    The data received from L2CAP.
1220  * @param typeCr The cr value in type of the frames.
1221  * @param type   UIH command type.
1222  * @param output Parsed data
1223  * @return event type. @see RfcommEventType
1224  */
RfcommSetFcOnOffInfo(Packet * pkt,uint8_t typeCr,uint8_t type,RfcommParseFrameResult output)1225 RfcommEventType RfcommSetFcOnOffInfo(Packet *pkt, uint8_t typeCr, uint8_t type, RfcommParseFrameResult output)
1226 {
1227     LOG_INFO("%{public}s", __func__);
1228 
1229     uint8_t data = 0;
1230 
1231     PacketExtractHead(pkt, &data, 1);
1232     uint8_t ea = data & EA;
1233     uint8_t len = data >> 1;
1234 
1235     if (!ea || (len != 0)) {
1236         return EVENT_FRAME_ERR;
1237     }
1238 
1239     if (type == UIH_TYPE_FCON) {
1240         *output.event = (typeCr == 1) ? EV_SESSION_RECV_FCON_REQ : EV_SESSION_RECV_FCON_RSP;
1241     } else if (type == UIH_TYPE_FCOFF) {
1242         *output.event = (typeCr == 1) ? EV_SESSION_RECV_FCOFF_REQ : EV_SESSION_RECV_FCOFF_RSP;
1243     } else {
1244         LOG_ERROR("%{public}s error type:%hhu.", __func__, type);
1245     }
1246 
1247     return EVENT_SESSION;
1248 }
1249 
1250 /**
1251  * @brief The function is used to set test information.
1252  *
1253  * @param pkt    The data received from L2CAP.
1254  * @param typeCr The cr value in type of the frames.
1255  * @param output Parsed data
1256  * @return event type. @see RfcommEventType
1257  */
RfcommSetTestInfo(Packet * pkt,uint8_t typeCr,RfcommParseFrameResult output)1258 RfcommEventType RfcommSetTestInfo(Packet *pkt, uint8_t typeCr, RfcommParseFrameResult output)
1259 {
1260     LOG_INFO("%{public}s", __func__);
1261 
1262     uint8_t data = 0;
1263 
1264     PacketExtractHead(pkt, &data, 0x01);
1265     uint8_t ea = data & EA;
1266     uint8_t len = data >> 1;
1267 
1268     if (!ea) {
1269         PacketExtractHead(pkt, &data, 0x01);
1270         len += (data << RFCOMM_SHIFT_LENGTH2);
1271     }
1272     output.info->test.length = len;
1273     output.info->test.pkt = pkt;
1274 
1275     *output.event = (typeCr == 1) ? EV_SESSION_RECV_TEST_REQ : EV_SESSION_RECV_TEST_RSP;
1276 
1277     return EVENT_SESSION;
1278 }
1279