blob: a3485cd528c8f2a3529420dfbdb7e6a49eb4adde [file] [log] [blame]
oliverschmidt3396e9a2004-08-20 12:29:54 +00001/* www.mycal.com
2 *---------------------------------------------------------------------------
3 * ahdlc.c - Ahdlc receive and transmit processor for PPP engine.
4 *
5 *---------------------------------------------------------------------------
6 * Version
7 * 0.1 Original Version Jan 11, 1998
8 *
9 *---------------------------------------------------------------------------
10 *
11 * Copyright (C) 1998, Mycal Labs www.mycal.com
12 *
13 *---------------------------------------------------------------------------
14 */
15/*
16 * Copyright (c) 2003, Mike Johnson, Mycal Labs, www.mycal.net
17 * All rights reserved.
18 *
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions
21 * are met:
22 * 1. Redistributions of source code must retain the above copyright
23 * notice, this list of conditions and the following disclaimer.
24 * 2. Redistributions in binary form must reproduce the above copyright
25 * notice, this list of conditions and the following disclaimer in the
26 * documentation and/or other materials provided with the distribution.
27 * 3. All advertising materials mentioning features or use of this software
28 * must display the following acknowledgement:
29 * This product includes software developed by Mike Johnson/Mycal Labs
30 * www.mycal.net.
31 * 4. The name of the author may not be used to endorse or promote
32 * products derived from this software without specific prior
33 * written permission.
34 *
35 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
36 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
37 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
39 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
41 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
42 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
43 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
44 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
45 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46 *
47 * This file is part of the Mycal Modified uIP TCP/IP stack.
48 *
oliverschmidt85729cb2005-01-26 23:36:22 +000049 * $Id: ahdlc.c,v 1.3 2005/01/26 23:36:22 oliverschmidt Exp $
oliverschmidt3396e9a2004-08-20 12:29:54 +000050 *
51 */
52
53/* */
54/* include files */
55/* */
56
57#include "uip.h"
58#include "ppp.h"
59
oliverschmidt85729cb2005-01-26 23:36:22 +000060#if 0
oliverschmidtacc63952004-08-29 15:11:45 +000061#define DEBUG1(x)
62#else
63#include <stdio.h>
oliverschmidt85729cb2005-01-26 23:36:22 +000064#define DEBUG1(x) debug_printf x
oliverschmidtacc63952004-08-29 15:11:45 +000065#endif
oliverschmidt3396e9a2004-08-20 12:29:54 +000066
oliverschmidt85729cb2005-01-26 23:36:22 +000067#define PACKET_TX_DEBUG 1
68
oliverschmidt3396e9a2004-08-20 12:29:54 +000069/*---------------------------------------------------------------------------
70 * ahdlc flags bit defins, for ahdlc_flags variable
71 ---------------------------------------------------------------------------*/
72/* Escaped mode bit */
73#define AHDLC_ESCAPED 0x1
74/* Frame is ready bit */
75#define AHDLC_RX_READY 0x2
76#define AHDLC_RX_ASYNC_MAP 0x4
77#define AHDLC_TX_ASYNC_MAP 0x8
78#define AHDLC_PFC 0x10
79#define AHDLC_ACFC 0x20
80
81/*---------------------------------------------------------------------------
82 * Private Local Globals
83 * 10 bytes - standard
84 * - with counters
85 ---------------------------------------------------------------------------*/
86/* running tx CRC */
87u16_t ahdlc_tx_crc;
88/* running rx CRC */
89u16_t ahdlc_rx_crc;
90/* number of rx bytes processed, cur frame */
91u16_t ahdlc_rx_count;
92/* ahdlc state flags, see above */
93u8_t ahdlc_flags;
94
95/*
96 * The following can be optimized out
97 */
98u8_t *ahdlc_rx_buffer; /* What to do here? +++ */
99u16_t ahdlc_max_rx_buffer_size;
100
101/*
102 * Optional statistics counters.
103 */
104#ifdef AHDLC_COUNTERS
105u8_t ahdlc_rx_tobig_error;
106#endif
107
108/*---------------------------------------------------------------------------*/
109/* Simple and fast CRC16 routine for embedded processors.
110 * Just slightly slower than the table lookup method but consumes
111 * almost no space. Much faster and smaller than the loop and
112 * shift method that is widely used in the embedded space.
113 * Can be optimized even more in .ASM
114 *
115 * data = (crcvalue ^ inputchar) & 0xff;
116 * data = (data ^ (data << 4)) & 0xff;
117 * crc = (crc >> 8) ^ ((data << 8) ^ (data <<3) ^ (data >> 4))
118 */
119/*---------------------------------------------------------------------------*/
120static u16_t
121crcadd(u16_t crcvalue, u8_t c)
122{
123 u16_t b;
124
125 b = (crcvalue ^ c) & 0xFF;
126 b = (b ^ (b << 4) & 0xFF);
127 b = (b << 8) ^ (b << 3) ^ (b >> 4);
128
129 return ((crcvalue >> 8) ^ b);
130}
131/*---------------------------------------------------------------------------*/
132/* ahdlc_init(buffer, buffersize) - this initializes the ahdlc engine to
133 * allow for rx frames.
134 */
135/*---------------------------------------------------------------------------*/
136void
137ahdlc_init(u8_t *buffer, u16_t maxrxbuffersize)
138{
139 ahdlc_flags = 0;
140 ahdlc_rx_buffer = buffer;
141 ahdlc_max_rx_buffer_size = maxrxbuffersize;
142 /* ahdlc_async_map = 0; */
143#ifdef AHDLC_COUNTERS
144 ahdlc_rx_tobig_error = 0;
145#endif
146}
147/*---------------------------------------------------------------------------*/
148/* ahdlc_rx_ready() - resets the ahdlc engine to the beginning of frame
149 * state.
150 */
151/*---------------------------------------------------------------------------*/
152void
153ahdlc_rx_ready(void)
154{
155 ahdlc_rx_count = 0;
156 ahdlc_rx_crc = 0xffff;
157 ahdlc_flags |= AHDLC_RX_READY;
158}
159/*---------------------------------------------------------------------------*/
160/* ahdlc receive function - This routine processes incoming bytes and tries
161 * to build a PPP frame.
162 *
163 * Two possible reasons that ahdlc_rx will not process characters:
164 * o Buffer is locked - in this case ahdlc_rx returns 1, char
165 * sending routing should retry.
166 */
167/*---------------------------------------------------------------------------*/
168u8_t
169ahdlc_rx(u8_t c)
170{
171 static u16_t protocol;
172
173 /* check to see if PPP packet is useable, we should have hardware
174 flow control set, but if host ignores it and sends us a char when
175 the PPP Receive packet is in use, discard the character. +++ */
176
177 if(ahdlc_flags & AHDLC_RX_READY) {
178 /* check to see if character is less than 0x20 hex we really
179 should set AHDLC_RX_ASYNC_MAP on by default and only turn it
180 off when it is negotiated off to handle some buggy stacks. */
181 if((c < 0x20) &&
182 ((ahdlc_flags & AHDLC_RX_ASYNC_MAP) == 0)) {
183 /* discard character */
184 DEBUG1(("Discard because char is < 0x20 hex and asysnc map is 0\n"));
185 return 0;
186 }
187 /* are we in escaped mode? */
188 if(ahdlc_flags & AHDLC_ESCAPED) {
189 /* set escaped to FALSE */
190 ahdlc_flags &= ~AHDLC_ESCAPED;
191
192 /* if value is 0x7e then silently discard and reset receive packet */
193 if(c == 0x7e) {
194 ahdlc_rx_ready();
195 return 0;
196 }
197 /* incomming char = itself xor 20 */
198 c = c ^ 0x20;
199 } else if(c == 0x7e) {
200 /* handle frame end */
201 if(ahdlc_rx_crc == CRC_GOOD_VALUE) {
oliverschmidt85729cb2005-01-26 23:36:22 +0000202 DEBUG1(("\nReceiving packet with good crc value, len %d\n",ahdlc_rx_count));
oliverschmidt3396e9a2004-08-20 12:29:54 +0000203 /* we hae a good packet, turn off CTS until we are done with
204 this packet */
205 /*CTS_OFF();*/
206 /* remove CRC bytes from packet */
207 ahdlc_rx_count -= 2;
208
209 /* lock PPP buffer */
210 ahdlc_flags &= ~AHDLC_RX_READY;
211 /*
212 * upcall routine must fully process frame before return
213 * as returning signifies that buffer belongs to AHDLC again.
214 */
215 if((c & 0x1) && (ahdlc_flags & PPP_PFC)) {
216 /* Send up packet */
217 ppp_upcall((u16_t)ahdlc_rx_buffer[0],
218 (u8_t *)&ahdlc_rx_buffer[1],
219 (u16_t)(ahdlc_rx_count - 1));
220 } else {
221 /* Send up packet */
222 ppp_upcall((u16_t)(ahdlc_rx_buffer[0] << 8 | ahdlc_rx_buffer[1]),
223 (u8_t *)&ahdlc_rx_buffer[2], (u16_t)(ahdlc_rx_count - 2));
224 }
225 ahdlc_rx_ready();
226 return 0;
227 } else if(ahdlc_rx_count > 3) {
oliverschmidt85729cb2005-01-26 23:36:22 +0000228 DEBUG1(("\nReceiving packet with bad crc value, was 0x%04x len %d\n",ahdlc_rx_crc, ahdlc_rx_count));
oliverschmidt3396e9a2004-08-20 12:29:54 +0000229#ifdef AHDLC_COUNTERS
230 ++ahdlc_crc_error;
231#endif
232 /* Shouldn't we dump the packet and not pass it up? */
233 /*ppp_upcall((u16_t)ahdlc_rx_buffer[0],
234 (u8_t *)&ahdlc_rx_buffer[0], (u16_t)(ahdlc_rx_count+2));
235 dump_ppp_packet(&ahdlc_rx_buffer[0],ahdlc_rx_count);*/
236
237 }
238 ahdlc_rx_ready();
239 return 0;
240 } else if(c == 0x7d) {
241 /* handle escaped chars*/
242 ahdlc_flags |= PPP_ESCAPED;
243 return 0;
244 }
245
246 /* try to store char if not to big */
247 if(ahdlc_rx_count >= ahdlc_max_rx_buffer_size /*PPP_RX_BUFFER_SIZE*/) {
248#ifdef AHDLC_COUNTERS
249 ++ahdlc_rx_tobig_error;
250#endif
251 ahdlc_rx_ready();
252 } else {
253 /* Add CRC in */
254 ahdlc_rx_crc = crcadd(ahdlc_rx_crc, c);
255 /* do auto ACFC, if packet len is zero discard 0xff and 0x03 */
256 if(ahdlc_rx_count == 0) {
257 if((c == 0xff) || (c == 0x03))
258 return 0;
259 }
260 /* Store char */
261 ppp_rx_buffer[ahdlc_rx_count++] = c;
262 }
263 } else {
264 /* we are busy and didn't process the character. */
oliverschmidt85729cb2005-01-26 23:36:22 +0000265 DEBUG1(("Busy/not active\n"));
oliverschmidt3396e9a2004-08-20 12:29:54 +0000266 return 1;
267 }
268 return 0;
269}
270/*---------------------------------------------------------------------------*/
271/* ahdlc_tx_char(char) - write a character to the serial device,
272 * escape if necessary.
273 *
274 * Relies on local global vars : ahdlc_tx_crc, ahdlc_flags.
275 * Modifies local global vars : ahdlc_tx_crc.
276 */
277/*---------------------------------------------------------------------------*/
278void
279ahdlc_tx_char(u16_t protocol, u8_t c)
280{
281 /* add in crc */
282 ahdlc_tx_crc = crcadd(ahdlc_tx_crc, c);
283 /*
284 * See if we need to escape char, we always escape 0x7d and 0x7e, in the case
285 * of char < 0x20 we only support async map of default or none, so escape if
286 * ASYNC map is not set. We may want to modify this to support a bitmap set
287 * ASYNC map.
288 */
289 if((c == 0x7d) || (c == 0x7e) ||
290 ((c < 0x20) && ((protocol == LCP) ||
291 (ahdlc_flags & PPP_TX_ASYNC_MAP) == 0))) {
292 /* send escape char and xor byte by 0x20 */
293 ppp_arch_putchar(0x7d);
294 c ^= 0x20;
295 }
296 ppp_arch_putchar(c);
297}
298/*---------------------------------------------------------------------------*/
299/* ahdlc_tx(protocol,buffer,len) - Transmit a PPP frame.
300 * Buffer contains protocol data, ahdlc_tx addes address, control and
301 * protocol data.
302 *
303 * Relies on local global vars : ahdlc_tx_crc, ahdlc_flags.
304 * Modifies local global vars : ahdlc_tx_crc.
305 */
306/*---------------------------------------------------------------------------*/
307u8_t
308ahdlc_tx(u16_t protocol, u8_t *header, u8_t *buffer,
309 u16_t headerlen, u16_t datalen)
310{
311 u16_t i;
312 u8_t c;
313
oliverschmidt85729cb2005-01-26 23:36:22 +0000314 DEBUG1(("\nAHDLC_TX - transmit frame, protocol 0x%04x, length %d\n",protocol,datalen+headerlen));
oliverschmidt3396e9a2004-08-20 12:29:54 +0000315
oliverschmidt85729cb2005-01-26 23:36:22 +0000316#if PACKET_TX_DEBUG
317 DEBUG1(("\n"));
318 for(i = 0; i < headerlen; ++i) {
319 DEBUG1(("0x%02x ", header[i]));
320 }
321 for(i = 0; i < datalen; ++i) {
322 DEBUG1(("0x%02x ", buffer[i]));
323 }
324 DEBUG1(("\n\n"));
325#endif
326
oliverschmidt3396e9a2004-08-20 12:29:54 +0000327 /* Check to see that physical layer is up, we can assume is some
328 cases */
329
330 /* write leading 0x7e */
331 ppp_arch_putchar(0x7e);
332
333 /* set initial CRC value */
334 ahdlc_tx_crc = 0xffff;
oliverschmidt85729cb2005-01-26 23:36:22 +0000335 /* send HDLC control and address if not disabled or of LCP frame type */
oliverschmidt3396e9a2004-08-20 12:29:54 +0000336 /*if((0==(ahdlc_flags & PPP_ACFC)) || ((0xc0==buffer[0]) && (0x21==buffer[1]))) */
337 if((0 == (ahdlc_flags & PPP_ACFC)) || (protocol == LCP)) {
338 ahdlc_tx_char(protocol, 0xff);
339 ahdlc_tx_char(protocol, 0x03);
340 }
341
342 /* Write Protocol */
343 ahdlc_tx_char(protocol,(u8_t)(protocol >> 8));
344 ahdlc_tx_char(protocol,(u8_t)(protocol & 0xff));
345
346 /* write header if it exists */
347 for(i = 0; i < headerlen; ++i) {
348 /* Get next byte from buffer */
349 c = header[i];
350 /* Write it...*/
351 ahdlc_tx_char(protocol, c);
352 }
353
354 /* Write frame bytes */
355 for(i = 0; i < datalen; ++i) {
356 /* Get next byte from buffer */
357 c = buffer[i];
358 /* Write it...*/
359 ahdlc_tx_char(protocol, c);
360 }
361
362 /* send crc, lsb then msb */
363 i = ahdlc_tx_crc ^ 0xffff;
364 ahdlc_tx_char(protocol, (u8_t)(i & 0xff));
365 ahdlc_tx_char(protocol, (u8_t)((i >> 8) & 0xff));
366
367 /* write trailing 0x7e, probably not needed but it doesn't hurt*/
368 ppp_arch_putchar(0x7e);
369 return 0;
370}
371/*---------------------------------------------------------------------------*/