blob: 2369c4d1c8d42835a220506f9f2c137a3355f5ff [file] [log] [blame]
Dixon Petersonb4f84242013-02-27 18:46:56 -08001/* Copyright (c) 2008-2009, 2012-2013, The Linux Foundation.
2 * All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003 *
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
15#include <linux/init.h>
16#include <linux/module.h>
17#include <linux/cdev.h>
18#include <linux/fs.h>
19#include <linux/device.h>
20#include <linux/uaccess.h>
21#include <linux/crc-ccitt.h>
22#include "diagchar_hdlc.h"
Shalabh Jain1c99e4c2012-03-26 18:47:59 -070023#include "diagchar.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070024
25
26MODULE_LICENSE("GPL v2");
27
28#define CRC_16_L_SEED 0xFFFF
29
30#define CRC_16_L_STEP(xx_crc, xx_c) \
31 crc_ccitt_byte(xx_crc, xx_c)
32
33void diag_hdlc_encode(struct diag_send_desc_type *src_desc,
34 struct diag_hdlc_dest_type *enc)
35{
36 uint8_t *dest;
37 uint8_t *dest_last;
38 const uint8_t *src;
39 const uint8_t *src_last;
40 uint16_t crc;
41 unsigned char src_byte = 0;
42 enum diag_send_state_enum_type state;
43 unsigned int used = 0;
44
45 if (src_desc && enc) {
46
47 /* Copy parts to local variables. */
48 src = src_desc->pkt;
49 src_last = src_desc->last;
50 state = src_desc->state;
51 dest = enc->dest;
52 dest_last = enc->dest_last;
53
54 if (state == DIAG_STATE_START) {
55 crc = CRC_16_L_SEED;
56 state++;
57 } else {
58 /* Get a local copy of the CRC */
59 crc = enc->crc;
60 }
61
62 /* dest or dest_last may be NULL to trigger a
63 state transition only */
64 if (dest && dest_last) {
65 /* This condition needs to include the possibility
66 of 2 dest bytes for an escaped byte */
67 while (src <= src_last && dest <= dest_last) {
68
69 src_byte = *src++;
70
71 if ((src_byte == CONTROL_CHAR) ||
72 (src_byte == ESC_CHAR)) {
73
74 /* If the escape character is not the
75 last byte */
76 if (dest != dest_last) {
77 crc = CRC_16_L_STEP(crc,
78 src_byte);
79
80 *dest++ = ESC_CHAR;
81 used++;
82
83 *dest++ = src_byte
84 ^ ESC_MASK;
85 used++;
86 } else {
87
88 src--;
89 break;
90 }
91
92 } else {
93 crc = CRC_16_L_STEP(crc, src_byte);
94 *dest++ = src_byte;
95 used++;
96 }
97 }
98
99 if (src > src_last) {
100
101 if (state == DIAG_STATE_BUSY) {
102 if (src_desc->terminate) {
103 crc = ~crc;
104 state++;
105 } else {
106 /* Done with fragment */
107 state = DIAG_STATE_COMPLETE;
108 }
109 }
110
111 while (dest <= dest_last &&
112 state >= DIAG_STATE_CRC1 &&
113 state < DIAG_STATE_TERM) {
114 /* Encode a byte of the CRC next */
115 src_byte = crc & 0xFF;
116
117 if ((src_byte == CONTROL_CHAR)
118 || (src_byte == ESC_CHAR)) {
119
120 if (dest != dest_last) {
121
122 *dest++ = ESC_CHAR;
123 used++;
124 *dest++ = src_byte ^
125 ESC_MASK;
126 used++;
127
128 crc >>= 8;
129 } else {
130
131 break;
132 }
133 } else {
134
135 crc >>= 8;
136 *dest++ = src_byte;
137 used++;
138 }
139
140 state++;
141 }
142
143 if (state == DIAG_STATE_TERM) {
144 if (dest_last >= dest) {
145 *dest++ = CONTROL_CHAR;
146 used++;
147 state++; /* Complete */
148 }
149 }
150 }
151 }
152 /* Copy local variables back into the encode structure. */
153
154 enc->dest = dest;
155 enc->dest_last = dest_last;
156 enc->crc = crc;
157 src_desc->pkt = src;
158 src_desc->last = src_last;
159 src_desc->state = state;
160 }
161
162 return;
163}
164
165
166int diag_hdlc_decode(struct diag_hdlc_decode_type *hdlc)
167{
168 uint8_t *src_ptr = NULL, *dest_ptr = NULL;
169 unsigned int src_length = 0, dest_length = 0;
170
171 unsigned int len = 0;
172 unsigned int i;
173 uint8_t src_byte;
174
175 int pkt_bnd = 0;
Dixon Petersonb4f84242013-02-27 18:46:56 -0800176 int msg_start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700177
178 if (hdlc && hdlc->src_ptr && hdlc->dest_ptr &&
179 (hdlc->src_size - hdlc->src_idx > 0) &&
180 (hdlc->dest_size - hdlc->dest_idx > 0)) {
181
Dixon Petersonb4f84242013-02-27 18:46:56 -0800182 msg_start = (hdlc->src_idx == 0) ? 1 : 0;
183
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700184 src_ptr = hdlc->src_ptr;
185 src_ptr = &src_ptr[hdlc->src_idx];
186 src_length = hdlc->src_size - hdlc->src_idx;
187
188 dest_ptr = hdlc->dest_ptr;
189 dest_ptr = &dest_ptr[hdlc->dest_idx];
190 dest_length = hdlc->dest_size - hdlc->dest_idx;
191
192 for (i = 0; i < src_length; i++) {
193
194 src_byte = src_ptr[i];
195
196 if (hdlc->escaping) {
197 dest_ptr[len++] = src_byte ^ ESC_MASK;
198 hdlc->escaping = 0;
199 } else if (src_byte == ESC_CHAR) {
200 if (i == (src_length - 1)) {
201 hdlc->escaping = 1;
202 i++;
203 break;
204 } else {
205 dest_ptr[len++] = src_ptr[++i]
206 ^ ESC_MASK;
207 }
208 } else if (src_byte == CONTROL_CHAR) {
209 dest_ptr[len++] = src_byte;
Dixon Petersonb4f84242013-02-27 18:46:56 -0800210 /*
211 * If this is the first byte in the message,
212 * then it is part of the command. Otherwise,
213 * consider it as the last byte of the
214 * message.
215 */
216 if (msg_start && i == 0 && src_length > 1)
217 continue;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700218 i++;
Dixon Petersonb4f84242013-02-27 18:46:56 -0800219 pkt_bnd = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700220 break;
221 } else {
222 dest_ptr[len++] = src_byte;
223 }
224
225 if (len >= dest_length) {
226 i++;
227 break;
228 }
229 }
230
231 hdlc->src_idx += i;
232 hdlc->dest_idx += len;
233 }
234
235 return pkt_bnd;
236}