Upgrade ofono to 1.2
[profile/ivi/ofono.git] / gatchat / gsm0710.c
1 /*
2  *
3  *  AT chat library with GLib integration
4  *
5  *  Copyright (C) 2011  Intel Corporation. All rights reserved.
6  *  Copyright (C) 2009  Trolltech ASA.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License version 2 as
10  *  published by the Free Software Foundation.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  *
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <string.h>
28
29 #include <glib.h>
30
31 #include "gsm0710.h"
32
33 static const unsigned char crc_table[256] = {
34         0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75,
35         0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B,
36         0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69,
37         0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67,
38         0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D,
39         0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43,
40         0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51,
41         0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F,
42         0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05,
43         0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B,
44         0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19,
45         0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17,
46         0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D,
47         0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33,
48         0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21,
49         0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F,
50         0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95,
51         0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B,
52         0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89,
53         0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87,
54         0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD,
55         0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3,
56         0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1,
57         0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF,
58         0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5,
59         0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB,
60         0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9,
61         0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7,
62         0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD,
63         0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3,
64         0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1,
65         0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF
66 };
67
68 static inline guint8 gsm0710_crc(const guint8 *data, int len)
69 {
70         guint8 crc = 0xFF;
71         int i;
72
73         for (i = 0; i < len; i++)
74                 crc = crc_table[crc ^ data[i]];
75
76         return crc;
77 }
78
79 static inline guint8 gsm0710_fcs(const guint8 *data, int len)
80 {
81         return 0xff - gsm0710_crc(data, len);
82 }
83
84 static inline gboolean gsm0710_check_fcs(const guint8 *data, int len,
85                                                 guint8 cfcs)
86 {
87         guint8 fcs = gsm0710_crc(data, len);
88
89         fcs = crc_table[fcs ^ cfcs];
90
91         if (fcs == 0xcf)
92                 return TRUE;
93
94         return FALSE;
95 }
96
97 int gsm0710_advanced_extract_frame(guint8 *buf, int len,
98                                         guint8 *out_dlc, guint8 *out_control,
99                                         guint8 **out_frame, int *out_len)
100 {
101         int posn = 0;
102         int posn2;
103         int framelen;
104         guint8 dlc;
105         guint8 control;
106
107         while (posn < len) {
108                 if (buf[posn] != 0x7E) {
109                         posn += 1;
110                         continue;
111                 }
112
113                 /* Skip additional 0x7E bytes between frames */
114                 while ((posn + 1) < len && buf[posn + 1] == 0x7E)
115                         posn += 1;
116
117                 /* Search for the end of the packet (the next 0x7E byte) */
118                 framelen = posn + 1;
119                 while (framelen < len && buf[framelen] != 0x7E)
120                         framelen += 1;
121
122                 if (framelen >= len)
123                         break;
124
125                 if (framelen < 4) {
126                         posn = framelen;
127                         continue;
128                 }
129
130                 /* Undo control byte quoting in the packet */
131                 posn2 = 0;
132                 ++posn;
133                 while (posn < framelen) {
134                         if (buf[posn] == 0x7D) {
135                                 ++posn;
136
137                                 if (posn >= framelen)
138                                         break;
139
140                                 buf[posn2++] = buf[posn++] ^ 0x20;
141                         } else {
142                                 buf[posn2++] = buf[posn++];
143                         }
144                 }
145
146                 /* Validate the checksum on the packet header */
147                 if (!gsm0710_check_fcs(buf, 2, buf[posn2 - 1]))
148                         continue;
149
150                 /* Decode and dispatch the packet */
151                 dlc = (buf[0] >> 2) & 0x3F;
152                 control = buf[1] & 0xEF; /* Strip "PF" bit */
153
154                 if (out_frame)
155                         *out_frame = buf + 2;
156
157                 if (out_len)
158                         *out_len = posn2 - 3;
159
160                 if (out_dlc)
161                         *out_dlc = dlc;
162
163                 if (out_control)
164                         *out_control = control;
165
166                 break;
167         }
168
169         return posn;
170 }
171
172 int gsm0710_advanced_fill_frame(guint8 *frame, guint8 dlc, guint8 type,
173                                         const guint8 *data, int len)
174 {
175         int temp, crc;
176         int size;
177
178         frame[0] = 0x7E;
179         frame[1] = ((dlc << 2) | 0x03);
180         frame[2] = type;
181
182         crc = gsm0710_fcs(frame + 1, 2);
183
184         /* The Address field might need to be escaped if this is a response
185          * frame
186          */
187
188         /* Need to quote the type field now that crc has been computed */
189         if (type == 0x7E || type == 0x7D) {
190                 frame[2] = 0x7D;
191                 frame[3] = (type ^ 0x20);
192                 size = 4;
193         } else {
194                 size = 3;
195         }
196
197         while (len > 0) {
198                 temp = *data++ & 0xFF;
199                 --len;
200
201                 if (temp != 0x7E && temp != 0x7D) {
202                         frame[size++] = temp;
203                 } else {
204                         frame[size++] = 0x7D;
205                         frame[size++] = (temp ^ 0x20);
206                 }
207         }
208
209         if (crc != 0x7E && crc != 0x7D) {
210                 frame[size++] = crc;
211         } else {
212                 frame[size++] = 0x7D;
213                 frame[size++] = (crc ^ 0x20);
214         }
215
216         frame[size++] = 0x7E;
217
218         return size;
219 }
220
221 int gsm0710_basic_extract_frame(guint8 *buf, int len,
222                                         guint8 *out_dlc, guint8 *out_control,
223                                         guint8 **out_frame, int *out_len)
224 {
225         int posn = 0;
226         int framelen;
227         int header_size;
228         guint8 fcs;
229         guint8 dlc;
230         guint8 type;
231
232         while (posn < len) {
233                 if (buf[posn] != 0xF9) {
234                         posn += 1;
235                         continue;
236                 }
237
238                 /* Skip additional 0xF9 bytes between frames */
239                 while ((posn + 1) < len && buf[posn + 1] == 0xF9)
240                         posn += 1;
241
242                 /* We need at least 4 bytes for the flag + header */
243                 if ((posn + 4) > len)
244                         break;
245
246                 /* The low bit of the second byte should be 1,
247                    which indicates a short channel number.  According to
248                    27.010 Section 5.2.3, if this is not true, then
249                    the frame is invalid and should be discarded
250                 */
251                 if ((buf[posn + 1] & 0x01) == 0) {
252                         ++posn;
253                         continue;
254                 }
255
256                 /* Get the packet length and validate it */
257                 framelen = buf[posn + 3] >> 1;
258
259                 if ((buf[posn + 3] & 0x01) != 0) {
260                         /* Single-byte length indication */
261                         header_size = 3;
262                 } else {
263                         /* Double-byte length indication */
264                         if ((posn + 5) > len)
265                                 break;
266
267                         framelen |= buf[posn + 4] << 7;
268                         header_size = 4;
269                 }
270
271                 /* Total size of the packet is the flag + 3 or 4 byte header
272                  * Address Control Length followed by Information and FCS.
273                  * However, we must check the presence of the end flag
274                  * according to 27.010 Section 5.2.3
275                  */
276                 if ((posn + header_size + 3 + framelen) > len)
277                         break;
278
279                 fcs = buf[posn + 1 + header_size + framelen];
280
281                 /*
282                  * The end flag is not guaranteed to be only ours
283                  * according to 27.010 Section 5.2.6.1:
284                  * "The closing flag may also be the opening flag of the
285                  * following frame", thus we do not consume it in the following
286                  * stages
287                  */
288
289                 /*
290                  * If FCS is invalid, discard the packet in accordance to
291                  * Section 5.2.3 of 27.010
292                  */
293                 if (!gsm0710_check_fcs(buf + posn + 1, header_size, fcs)) {
294                         posn += header_size + framelen + 2;
295                         continue;
296                 }
297
298                 if (buf[posn + header_size + framelen + 2] != 0xF9) {
299                         posn += header_size + framelen + 2;
300                         continue;
301                 }
302
303                 /* Get the channel number and packet type from the header */
304                 dlc = buf[posn + 1] >> 2;
305                 type = buf[posn + 2] & 0xEF;    /* Strip "PF" bit */
306
307                 if (out_frame)
308                         *out_frame = buf + posn + 1 + header_size;
309
310                 if (out_len)
311                         *out_len = framelen;
312
313                 if (out_dlc)
314                         *out_dlc = dlc;
315
316                 if (out_control)
317                         *out_control = type;
318
319                 posn += header_size + framelen + 2;
320
321                 break;
322         }
323
324         return posn;
325 }
326
327 int gsm0710_basic_fill_frame(guint8 *frame, guint8 dlc, guint8 type,
328                                 const guint8 *data, int len)
329 {
330         int size;
331         int header_size;
332
333         frame[0] = 0xF9;
334         frame[1] = ((dlc << 2) | 0x03);
335         frame[2] = type;
336
337         if (len <= 127) {
338                 frame[3] = ((len << 1) | 0x01);
339                 header_size = 4;
340         } else {
341                 frame[3] = (len << 1);
342                 frame[4] = (len >> 7);
343                 header_size = 5;
344         }
345
346         size = header_size;
347
348         if (len > 0) {
349                 memcpy(frame + header_size, data, len);
350                 size += len;
351         }
352
353         /* Note: GSM 07.10 says that the CRC is only computed over the header */
354         frame[size++] = gsm0710_fcs(frame + 1, header_size - 1);
355         frame[size++] = 0xF9;
356
357         return size;
358 }