1/*
2 * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
3 * All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * File: wctl.c
20 *
21 * Purpose: handle WMAC duplicate filter & defragment
22 *
23 * Author: Jerry Chen
24 *
25 * Date: Jun. 27, 2002
26 *
27 * Functions:
28 *      WCTLbIsDuplicate - Test if duplicate packet
29 *      WCTLuSearchDFCB - Search DeFragment Control Database
30 *      WCTLuInsertDFCB - Insert DeFragment Control Database
31 *      WCTLbHandleFragment - Handle received fragment packet
32 *
33 * Revision History:
34 *
35 */
36
37#include "wctl.h"
38#include "device.h"
39#include "card.h"
40
41/*---------------------  Static Definitions -------------------------*/
42
43/*---------------------  Static Classes  ----------------------------*/
44
45/*---------------------  Static Variables  --------------------------*/
46
47/*---------------------  Static Functions  --------------------------*/
48
49/*---------------------  Export Variables  --------------------------*/
50
51/*
52 * Description:
53 *      Scan Rx cache.  Return true if packet is duplicate, else
54 *      inserts in receive cache and returns false.
55 *
56 * Parameters:
57 *  In:
58 *      pCache      - Receive packets history
59 *      pMACHeader  - 802.11 MAC Header of received packet
60 *  Out:
61 *      none
62 *
63 * Return Value: true if packet duplicate; otherwise false
64 *
65 */
66
67bool WCTLbIsDuplicate(PSCache pCache, PS802_11Header pMACHeader)
68{
69	unsigned int uIndex;
70	unsigned int ii;
71	PSCacheEntry    pCacheEntry;
72
73	if (IS_FC_RETRY(pMACHeader)) {
74		uIndex = pCache->uInPtr;
75		for (ii = 0; ii < DUPLICATE_RX_CACHE_LENGTH; ii++) {
76			pCacheEntry = &(pCache->asCacheEntry[uIndex]);
77			if ((pCacheEntry->wFmSequence == pMACHeader->wSeqCtl) &&
78			    ether_addr_equal(pCacheEntry->abyAddr2,
79					     pMACHeader->abyAddr2)) {
80				/* Duplicate match */
81				return true;
82			}
83			ADD_ONE_WITH_WRAP_AROUND(uIndex, DUPLICATE_RX_CACHE_LENGTH);
84		}
85	}
86	/* Not fount in cache - insert */
87	pCacheEntry = &pCache->asCacheEntry[pCache->uInPtr];
88	pCacheEntry->wFmSequence = pMACHeader->wSeqCtl;
89	memcpy(&(pCacheEntry->abyAddr2[0]), &(pMACHeader->abyAddr2[0]), ETH_ALEN);
90	ADD_ONE_WITH_WRAP_AROUND(pCache->uInPtr, DUPLICATE_RX_CACHE_LENGTH);
91	return false;
92}
93
94/*
95 * Description:
96 *      Found if sequence number of received fragment packet in Defragment Database
97 *
98 * Parameters:
99 *  In:
100 *      pDevice     - Pointer to adapter
101 *      pMACHeader  - 802.11 MAC Header of received packet
102 *  Out:
103 *      none
104 *
105 * Return Value: index number in Defragment Database
106 *
107 */
108unsigned int WCTLuSearchDFCB(struct vnt_private *pDevice,
109			     PS802_11Header pMACHeader)
110{
111	unsigned int ii;
112
113	for (ii = 0; ii < pDevice->cbDFCB; ii++) {
114		if (pDevice->sRxDFCB[ii].bInUse &&
115		    ether_addr_equal(pDevice->sRxDFCB[ii].abyAddr2,
116				     pMACHeader->abyAddr2)) {
117			return ii;
118		}
119	}
120	return pDevice->cbDFCB;
121}
122
123/*
124 * Description:
125 *      Insert received fragment packet in Defragment Database
126 *
127 * Parameters:
128 *  In:
129 *      pDevice     - Pointer to adapter
130 *      pMACHeader  - 802.11 MAC Header of received packet
131 *  Out:
132 *      none
133 *
134 * Return Value: index number in Defragment Database
135 *
136 */
137unsigned int WCTLuInsertDFCB(struct vnt_private *pDevice, PS802_11Header pMACHeader)
138{
139	unsigned int ii;
140
141	if (pDevice->cbFreeDFCB == 0)
142		return pDevice->cbDFCB;
143	for (ii = 0; ii < pDevice->cbDFCB; ii++) {
144		if (!pDevice->sRxDFCB[ii].bInUse) {
145			pDevice->cbFreeDFCB--;
146			pDevice->sRxDFCB[ii].uLifetime = pDevice->dwMaxReceiveLifetime;
147			pDevice->sRxDFCB[ii].bInUse = true;
148			pDevice->sRxDFCB[ii].wSequence = (pMACHeader->wSeqCtl >> 4);
149			pDevice->sRxDFCB[ii].wFragNum = (pMACHeader->wSeqCtl & 0x000F);
150			memcpy(&(pDevice->sRxDFCB[ii].abyAddr2[0]), &(pMACHeader->abyAddr2[0]), ETH_ALEN);
151			return ii;
152		}
153	}
154	return pDevice->cbDFCB;
155}
156
157/*
158 * Description:
159 *      Handle received fragment packet
160 *
161 * Parameters:
162 *  In:
163 *      pDevice         - Pointer to adapter
164 *      pMACHeader      - 802.11 MAC Header of received packet
165 *      cbFrameLength   - Frame length
166 *      bWEP            - is WEP packet
167 *  Out:
168 *      none
169 *
170 * Return Value: true if it is valid fragment packet and we have resource to defragment; otherwise false
171 *
172 */
173bool WCTLbHandleFragment(struct vnt_private *pDevice, PS802_11Header pMACHeader,
174			 unsigned int cbFrameLength, bool bWEP, bool bExtIV)
175{
176	unsigned int uHeaderSize;
177
178	if (bWEP) {
179		uHeaderSize = 28;
180		if (bExtIV)
181			// ExtIV
182			uHeaderSize += 4;
183	} else {
184		uHeaderSize = 24;
185	}
186
187	if (IS_FIRST_FRAGMENT_PKT(pMACHeader)) {
188		pDevice->uCurrentDFCBIdx = WCTLuSearchDFCB(pDevice, pMACHeader);
189		if (pDevice->uCurrentDFCBIdx < pDevice->cbDFCB) {
190			// duplicate, we must flush previous DCB
191			pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].uLifetime = pDevice->dwMaxReceiveLifetime;
192			pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wSequence = (pMACHeader->wSeqCtl >> 4);
193			pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wFragNum = (pMACHeader->wSeqCtl & 0x000F);
194		} else {
195			pDevice->uCurrentDFCBIdx = WCTLuInsertDFCB(pDevice, pMACHeader);
196			if (pDevice->uCurrentDFCBIdx == pDevice->cbDFCB)
197				return false;
198		}
199		// reserve 4 byte to match MAC RX Buffer
200		pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer = (unsigned char *)(pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].skb->data + 4);
201		memcpy(pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer, pMACHeader, cbFrameLength);
202		pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].cbFrameLength = cbFrameLength;
203		pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer += cbFrameLength;
204		pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wFragNum++;
205		return false;
206	} else {
207		pDevice->uCurrentDFCBIdx = WCTLuSearchDFCB(pDevice, pMACHeader);
208		if (pDevice->uCurrentDFCBIdx != pDevice->cbDFCB) {
209			if ((pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wSequence == (pMACHeader->wSeqCtl >> 4)) &&
210			    (pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wFragNum == (pMACHeader->wSeqCtl & 0x000F)) &&
211			    ((pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].cbFrameLength + cbFrameLength - uHeaderSize) < 2346)) {
212				memcpy(pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer, ((unsigned char *)(pMACHeader) + uHeaderSize), (cbFrameLength - uHeaderSize));
213				pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].cbFrameLength += (cbFrameLength - uHeaderSize);
214				pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer += (cbFrameLength - uHeaderSize);
215				pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wFragNum++;
216			} else {
217				// seq error or frag # error flush DFCB
218				pDevice->cbFreeDFCB++;
219				pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].bInUse = false;
220				return false;
221			}
222		} else {
223			return false;
224		}
225		if (IS_LAST_FRAGMENT_PKT(pMACHeader)) {
226			//enq defragcontrolblock
227			pDevice->cbFreeDFCB++;
228			pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].bInUse = false;
229			return true;
230		}
231		return false;
232	}
233}
234