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