1/*
2 *   Copyright (c) 2011, 2012, Atheros Communications Inc.
3 *   Copyright (c) 2014, I2SE GmbH
4 *
5 *   Permission to use, copy, modify, and/or distribute this software
6 *   for any purpose with or without fee is hereby granted, provided
7 *   that the above copyright notice and this permission notice appear
8 *   in all copies.
9 *
10 *   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 *   WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 *   WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
13 *   THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
14 *   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 *   LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
16 *   NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
17 *   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20/*   Atheros ethernet framing. Every Ethernet frame is surrounded
21 *   by an atheros frame while transmitted over a serial channel;
22 */
23
24#include <linux/kernel.h>
25
26#include "qca_framing.h"
27
28u16
29qcafrm_create_header(u8 *buf, u16 length)
30{
31	__le16 len;
32
33	if (!buf)
34		return 0;
35
36	len = cpu_to_le16(length);
37
38	buf[0] = 0xAA;
39	buf[1] = 0xAA;
40	buf[2] = 0xAA;
41	buf[3] = 0xAA;
42	buf[4] = len & 0xff;
43	buf[5] = (len >> 8) & 0xff;
44	buf[6] = 0;
45	buf[7] = 0;
46
47	return QCAFRM_HEADER_LEN;
48}
49
50u16
51qcafrm_create_footer(u8 *buf)
52{
53	if (!buf)
54		return 0;
55
56	buf[0] = 0x55;
57	buf[1] = 0x55;
58	return QCAFRM_FOOTER_LEN;
59}
60
61/*   Gather received bytes and try to extract a full ethernet frame by
62 *   following a simple state machine.
63 *
64 * Return:   QCAFRM_GATHER       No ethernet frame fully received yet.
65 *           QCAFRM_NOHEAD       Header expected but not found.
66 *           QCAFRM_INVLEN       Atheros frame length is invalid
67 *           QCAFRM_NOTAIL       Footer expected but not found.
68 *           > 0                 Number of byte in the fully received
69 *                               Ethernet frame
70 */
71
72s32
73qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_byte)
74{
75	s32 ret = QCAFRM_GATHER;
76	u16 len;
77
78	switch (handle->state) {
79	case QCAFRM_HW_LEN0:
80	case QCAFRM_HW_LEN1:
81		/* by default, just go to next state */
82		handle->state--;
83
84		if (recv_byte != 0x00) {
85			/* first two bytes of length must be 0 */
86			handle->state = QCAFRM_HW_LEN0;
87		}
88		break;
89	case QCAFRM_HW_LEN2:
90	case QCAFRM_HW_LEN3:
91		handle->state--;
92		break;
93	/* 4 bytes header pattern */
94	case QCAFRM_WAIT_AA1:
95	case QCAFRM_WAIT_AA2:
96	case QCAFRM_WAIT_AA3:
97	case QCAFRM_WAIT_AA4:
98		if (recv_byte != 0xAA) {
99			ret = QCAFRM_NOHEAD;
100			handle->state = QCAFRM_HW_LEN0;
101		} else {
102			handle->state--;
103		}
104		break;
105		/* 2 bytes length. */
106		/* Borrow offset field to hold length for now. */
107	case QCAFRM_WAIT_LEN_BYTE0:
108		handle->offset = recv_byte;
109		handle->state = QCAFRM_WAIT_LEN_BYTE1;
110		break;
111	case QCAFRM_WAIT_LEN_BYTE1:
112		handle->offset = handle->offset | (recv_byte << 8);
113		handle->state = QCAFRM_WAIT_RSVD_BYTE1;
114		break;
115	case QCAFRM_WAIT_RSVD_BYTE1:
116		handle->state = QCAFRM_WAIT_RSVD_BYTE2;
117		break;
118	case QCAFRM_WAIT_RSVD_BYTE2:
119		len = handle->offset;
120		if (len > buf_len || len < QCAFRM_ETHMINLEN) {
121			ret = QCAFRM_INVLEN;
122			handle->state = QCAFRM_HW_LEN0;
123		} else {
124			handle->state = (enum qcafrm_state)(len + 1);
125			/* Remaining number of bytes. */
126			handle->offset = 0;
127		}
128		break;
129	default:
130		/* Receiving Ethernet frame itself. */
131		buf[handle->offset] = recv_byte;
132		handle->offset++;
133		handle->state--;
134		break;
135	case QCAFRM_WAIT_551:
136		if (recv_byte != 0x55) {
137			ret = QCAFRM_NOTAIL;
138			handle->state = QCAFRM_HW_LEN0;
139		} else {
140			handle->state = QCAFRM_WAIT_552;
141		}
142		break;
143	case QCAFRM_WAIT_552:
144		if (recv_byte != 0x55) {
145			ret = QCAFRM_NOTAIL;
146			handle->state = QCAFRM_HW_LEN0;
147		} else {
148			ret = handle->offset;
149			/* Frame is fully received. */
150			handle->state = QCAFRM_HW_LEN0;
151		}
152		break;
153	}
154
155	return ret;
156}
157