blob: 9e84c2f2ce866cb33a4bbd5f81493e56632e8059 [file] [log] [blame]
Harald Welte99ac1f32016-12-23 22:07:51 +01001/* Copyright (c) 2008-2009, 2012-2014, The Linux Foundation.
2 * All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 */
14
Harald Welte6a50b962016-12-23 22:54:30 +010015#include <stdint.h>
16#include <stdlib.h>
17#include <stdio.h>
18#include <string.h>
19#include <errno.h>
20#include <sys/types.h>
21
22#include <osmocom/core/crc16.h>
Harald Welte99ac1f32016-12-23 22:07:51 +010023#include "diagchar_hdlc.h"
Harald Welte99ac1f32016-12-23 22:07:51 +010024
Harald Welte6a50b962016-12-23 22:54:30 +010025#define CONTROL_CHAR 0x7E
Harald Welte99ac1f32016-12-23 22:07:51 +010026
27#define CRC_16_L_SEED 0xFFFF
28
29#define CRC_16_L_STEP(xx_crc, xx_c) \
Harald Welte6a50b962016-12-23 22:54:30 +010030 osmo_crc16_ccitt_byte(xx_crc, xx_c)
Harald Welte99ac1f32016-12-23 22:07:51 +010031
32void diag_hdlc_encode(struct diag_send_desc_type *src_desc,
33 struct diag_hdlc_dest_type *enc)
34{
35 uint8_t *dest;
36 uint8_t *dest_last;
37 const uint8_t *src;
38 const uint8_t *src_last;
39 uint16_t crc;
40 unsigned char src_byte = 0;
41 enum diag_send_state_enum_type state;
42 unsigned int used = 0;
43
44 if (src_desc && enc) {
45
46 /* Copy parts to local variables. */
47 src = src_desc->pkt;
48 src_last = src_desc->last;
49 state = src_desc->state;
50 dest = enc->dest;
51 dest_last = enc->dest_last;
52
53 if (state == DIAG_STATE_START) {
54 crc = CRC_16_L_SEED;
55 state++;
56 } else {
57 /* Get a local copy of the CRC */
58 crc = enc->crc;
59 }
60
61 /* dest or dest_last may be NULL to trigger a
62 state transition only */
63 if (dest && dest_last) {
64 /* This condition needs to include the possibility
65 of 2 dest bytes for an escaped byte */
66 while (src <= src_last && dest <= dest_last) {
67
68 src_byte = *src++;
69
70 if ((src_byte == CONTROL_CHAR) ||
71 (src_byte == ESC_CHAR)) {
72
73 /* If the escape character is not the
74 last byte */
75 if (dest != dest_last) {
76 crc = CRC_16_L_STEP(crc,
77 src_byte);
78
79 *dest++ = ESC_CHAR;
80 used++;
81
82 *dest++ = src_byte
83 ^ ESC_MASK;
84 used++;
85 } else {
86
87 src--;
88 break;
89 }
90
91 } else {
92 crc = CRC_16_L_STEP(crc, src_byte);
93 *dest++ = src_byte;
94 used++;
95 }
96 }
97
98 if (src > src_last) {
99
100 if (state == DIAG_STATE_BUSY) {
101 if (src_desc->terminate) {
102 crc = ~crc;
103 state++;
104 } else {
105 /* Done with fragment */
106 state = DIAG_STATE_COMPLETE;
107 }
108 }
109
110 while (dest <= dest_last &&
111 state >= DIAG_STATE_CRC1 &&
112 state < DIAG_STATE_TERM) {
113 /* Encode a byte of the CRC next */
114 src_byte = crc & 0xFF;
115
116 if ((src_byte == CONTROL_CHAR)
117 || (src_byte == ESC_CHAR)) {
118
119 if (dest != dest_last) {
120
121 *dest++ = ESC_CHAR;
122 used++;
123 *dest++ = src_byte ^
124 ESC_MASK;
125 used++;
126
127 crc >>= 8;
128 } else {
129
130 break;
131 }
132 } else {
133
134 crc >>= 8;
135 *dest++ = src_byte;
136 used++;
137 }
138
139 state++;
140 }
141
142 if (state == DIAG_STATE_TERM) {
143 if (dest_last >= dest) {
144 *dest++ = CONTROL_CHAR;
145 used++;
146 state++; /* Complete */
147 }
148 }
149 }
150 }
151 /* Copy local variables back into the encode structure. */
152
153 enc->dest = dest;
154 enc->dest_last = dest_last;
155 enc->crc = crc;
156 src_desc->pkt = src;
157 src_desc->last = src_last;
158 src_desc->state = state;
159 }
160
161 return;
162}
163
164
165int diag_hdlc_decode(struct diag_hdlc_decode_type *hdlc)
166{
167 uint8_t *src_ptr = NULL, *dest_ptr = NULL;
168 unsigned int src_length = 0, dest_length = 0;
169
170 unsigned int len = 0;
171 unsigned int i;
172 uint8_t src_byte;
173
174 int pkt_bnd = HDLC_INCOMPLETE;
175 int msg_start;
176
177 if (hdlc && hdlc->src_ptr && hdlc->dest_ptr &&
178 (hdlc->src_size > hdlc->src_idx) &&
179 (hdlc->dest_size > hdlc->dest_idx)) {
180
181 msg_start = (hdlc->src_idx == 0) ? 1 : 0;
182
183 src_ptr = hdlc->src_ptr;
184 src_ptr = &src_ptr[hdlc->src_idx];
185 src_length = hdlc->src_size - hdlc->src_idx;
186
187 dest_ptr = hdlc->dest_ptr;
188 dest_ptr = &dest_ptr[hdlc->dest_idx];
189 dest_length = hdlc->dest_size - hdlc->dest_idx;
190
191 for (i = 0; i < src_length; i++) {
192
193 src_byte = src_ptr[i];
194
195 if (hdlc->escaping) {
196 dest_ptr[len++] = src_byte ^ ESC_MASK;
197 hdlc->escaping = 0;
198 } else if (src_byte == ESC_CHAR) {
199 if (i == (src_length - 1)) {
200 hdlc->escaping = 1;
201 i++;
202 break;
203 } else {
204 dest_ptr[len++] = src_ptr[++i]
205 ^ ESC_MASK;
206 }
207 } else if (src_byte == CONTROL_CHAR) {
208 if (msg_start && i == 0 && src_length > 1)
209 continue;
210 /* Byte 0x7E will be considered
211 as end of packet */
212 dest_ptr[len++] = src_byte;
213 i++;
214 pkt_bnd = HDLC_COMPLETE;
215 break;
216 } else {
217 dest_ptr[len++] = src_byte;
218 }
219
220 if (len >= dest_length) {
221 i++;
222 break;
223 }
224 }
225
226 hdlc->src_idx += i;
227 hdlc->dest_idx += len;
228 }
229
230 return pkt_bnd;
231}
232
233int crc_check(uint8_t *buf, uint16_t len)
234{
235 uint16_t crc = CRC_16_L_SEED;
236 uint8_t sent_crc[2] = {0, 0};
237
238 /*
239 * The minimum length of a valid incoming packet is 4. 1 byte
240 * of data and 3 bytes for CRC
241 */
242 if (!buf || len < 4) {
Harald Welte6a50b962016-12-23 22:54:30 +0100243 fprintf(stderr, "diag: In %s, invalid packet or length, buf: 0x%p, len: %d",
Harald Welte99ac1f32016-12-23 22:07:51 +0100244 __func__, buf, len);
245 return -EIO;
246 }
247
248 /*
249 * Run CRC check for the original input. Skip the last 3 CRC
250 * bytes
251 */
Harald Welte6a50b962016-12-23 22:54:30 +0100252 crc = osmo_crc16_ccitt(crc, buf, len-3);
Harald Welte99ac1f32016-12-23 22:07:51 +0100253 crc ^= CRC_16_L_SEED;
254
255 /* Check the computed CRC against the original CRC bytes. */
256 sent_crc[0] = buf[len-3];
257 sent_crc[1] = buf[len-2];
258 if (crc != *((uint16_t *)sent_crc)) {
Harald Welte6a50b962016-12-23 22:54:30 +0100259 fprintf(stderr, "diag: In %s, crc mismatch. expected: %x, sent %x.\n",
Harald Welte99ac1f32016-12-23 22:07:51 +0100260 __func__, crc, *((uint16_t *)sent_crc));
261 return -EIO;
262 }
263
264 return 0;
265}