xref: /wlan-driver/qcacld-3.0/core/dp/txrx/ol_rx_defrag.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved.
3*5113495bSYour Name  * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4*5113495bSYour Name  *
5*5113495bSYour Name  * Permission to use, copy, modify, and/or distribute this software for
6*5113495bSYour Name  * any purpose with or without fee is hereby granted, provided that the
7*5113495bSYour Name  * above copyright notice and this permission notice appear in all
8*5113495bSYour Name  * copies.
9*5113495bSYour Name  *
10*5113495bSYour Name  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11*5113495bSYour Name  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12*5113495bSYour Name  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13*5113495bSYour Name  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14*5113495bSYour Name  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15*5113495bSYour Name  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16*5113495bSYour Name  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*5113495bSYour Name  * PERFORMANCE OF THIS SOFTWARE.
18*5113495bSYour Name  */
19*5113495bSYour Name 
20*5113495bSYour Name /*-
21*5113495bSYour Name  * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting
22*5113495bSYour Name  * All rights reserved.
23*5113495bSYour Name  *
24*5113495bSYour Name  * Redistribution and use in source and binary forms, with or without
25*5113495bSYour Name  * modification, are permitted provided that the following conditions
26*5113495bSYour Name  * are met:
27*5113495bSYour Name  * 1. Redistributions of source code must retain the above copyright
28*5113495bSYour Name  * notice, this list of conditions and the following disclaimer.
29*5113495bSYour Name  * 2. Redistributions in binary form must reproduce the above copyright
30*5113495bSYour Name  * notice, this list of conditions and the following disclaimer in the
31*5113495bSYour Name  * documentation and/or other materials provided with the distribution.
32*5113495bSYour Name  *
33*5113495bSYour Name  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
34*5113495bSYour Name  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35*5113495bSYour Name  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
36*5113495bSYour Name  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
37*5113495bSYour Name  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
38*5113495bSYour Name  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
39*5113495bSYour Name  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
40*5113495bSYour Name  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
41*5113495bSYour Name  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
42*5113495bSYour Name  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43*5113495bSYour Name  */
44*5113495bSYour Name #include <ol_htt_api.h>
45*5113495bSYour Name #include <ol_txrx_api.h>
46*5113495bSYour Name #include <ol_txrx_htt_api.h>
47*5113495bSYour Name #include <ol_htt_rx_api.h>
48*5113495bSYour Name #include <ol_rx_reorder.h>
49*5113495bSYour Name #include <ol_rx_pn.h>
50*5113495bSYour Name #include <ol_rx_fwd.h>
51*5113495bSYour Name #include <ol_rx.h>
52*5113495bSYour Name #include <ol_txrx_internal.h>
53*5113495bSYour Name #include <ol_ctrl_txrx_api.h>
54*5113495bSYour Name #include <ol_txrx_peer_find.h>
55*5113495bSYour Name #include <qdf_nbuf.h>
56*5113495bSYour Name #include <qdf_util.h>
57*5113495bSYour Name #include <athdefs.h>
58*5113495bSYour Name #include <qdf_mem.h>
59*5113495bSYour Name #include <ol_rx_defrag.h>
60*5113495bSYour Name #include <enet.h>
61*5113495bSYour Name #include <qdf_time.h>           /* qdf_system_time */
62*5113495bSYour Name #include <wlan_pkt_capture_ucfg_api.h>
63*5113495bSYour Name 
64*5113495bSYour Name #define DEFRAG_IEEE80211_ADDR_EQ(a1, a2) \
65*5113495bSYour Name 	(!qdf_mem_cmp(a1, a2, QDF_MAC_ADDR_SIZE))
66*5113495bSYour Name 
67*5113495bSYour Name #define DEFRAG_IEEE80211_ADDR_COPY(dst, src) \
68*5113495bSYour Name 	qdf_mem_copy(dst, src, QDF_MAC_ADDR_SIZE)
69*5113495bSYour Name 
70*5113495bSYour Name #define DEFRAG_IEEE80211_QOS_HAS_SEQ(wh) \
71*5113495bSYour Name 	(((wh)->i_fc[0] & \
72*5113495bSYour Name 	  (IEEE80211_FC0_TYPE_MASK | QDF_IEEE80211_FC0_SUBTYPE_QOS)) == \
73*5113495bSYour Name 	 (IEEE80211_FC0_TYPE_DATA | QDF_IEEE80211_FC0_SUBTYPE_QOS))
74*5113495bSYour Name 
75*5113495bSYour Name #define DEFRAG_IEEE80211_QOS_GET_TID(_x) \
76*5113495bSYour Name 	((_x)->i_qos[0] & IEEE80211_QOS_TID)
77*5113495bSYour Name 
78*5113495bSYour Name const struct ol_rx_defrag_cipher f_ccmp = {
79*5113495bSYour Name 	"AES-CCM",
80*5113495bSYour Name 	IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_EXTIVLEN,
81*5113495bSYour Name 	IEEE80211_WEP_MICLEN,
82*5113495bSYour Name 	0,
83*5113495bSYour Name };
84*5113495bSYour Name 
85*5113495bSYour Name const struct ol_rx_defrag_cipher f_tkip = {
86*5113495bSYour Name 	"TKIP",
87*5113495bSYour Name 	IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_EXTIVLEN,
88*5113495bSYour Name 	IEEE80211_WEP_CRCLEN,
89*5113495bSYour Name 	IEEE80211_WEP_MICLEN,
90*5113495bSYour Name };
91*5113495bSYour Name 
92*5113495bSYour Name const struct ol_rx_defrag_cipher f_wep = {
93*5113495bSYour Name 	"WEP",
94*5113495bSYour Name 	IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN,
95*5113495bSYour Name 	IEEE80211_WEP_CRCLEN,
96*5113495bSYour Name 	0,
97*5113495bSYour Name };
98*5113495bSYour Name 
99*5113495bSYour Name const struct ol_rx_defrag_cipher f_gcmp = {
100*5113495bSYour Name 	"AES-GCMP",
101*5113495bSYour Name 	WLAN_IEEE80211_GCMP_HEADERLEN,
102*5113495bSYour Name 	WLAN_IEEE80211_GCMP_MICLEN,
103*5113495bSYour Name 	WLAN_IEEE80211_GCMP_MICLEN,
104*5113495bSYour Name };
105*5113495bSYour Name 
106*5113495bSYour Name #if defined(CONFIG_HL_SUPPORT)
107*5113495bSYour Name 
108*5113495bSYour Name /**
109*5113495bSYour Name  * ol_rx_frag_get_mac_hdr() - retrieve mac header
110*5113495bSYour Name  * @htt_pdev: pointer to htt pdev handle
111*5113495bSYour Name  * @frag: rx fragment
112*5113495bSYour Name  *
113*5113495bSYour Name  * Return: pointer to ieee mac header of frag
114*5113495bSYour Name  */
ol_rx_frag_get_mac_hdr(htt_pdev_handle htt_pdev,qdf_nbuf_t frag)115*5113495bSYour Name static struct ieee80211_frame *ol_rx_frag_get_mac_hdr(
116*5113495bSYour Name 	htt_pdev_handle htt_pdev, qdf_nbuf_t frag)
117*5113495bSYour Name {
118*5113495bSYour Name 	void *rx_desc;
119*5113495bSYour Name 	int rx_desc_len;
120*5113495bSYour Name 
121*5113495bSYour Name 	rx_desc = htt_rx_msdu_desc_retrieve(htt_pdev, frag);
122*5113495bSYour Name 	rx_desc_len = htt_rx_msdu_rx_desc_size_hl(htt_pdev, rx_desc);
123*5113495bSYour Name 	return (struct ieee80211_frame *)(qdf_nbuf_data(frag) + rx_desc_len);
124*5113495bSYour Name }
125*5113495bSYour Name 
126*5113495bSYour Name /**
127*5113495bSYour Name  * ol_rx_frag_pull_hdr() - point to payload of rx frag
128*5113495bSYour Name  * @htt_pdev: pointer to htt pdev handle
129*5113495bSYour Name  * @frag: rx fragment
130*5113495bSYour Name  * @hdrsize: header size
131*5113495bSYour Name  *
132*5113495bSYour Name  * Return: None
133*5113495bSYour Name  */
ol_rx_frag_pull_hdr(htt_pdev_handle htt_pdev,qdf_nbuf_t frag,int hdrsize)134*5113495bSYour Name static void ol_rx_frag_pull_hdr(htt_pdev_handle htt_pdev,
135*5113495bSYour Name 	qdf_nbuf_t frag, int hdrsize)
136*5113495bSYour Name {
137*5113495bSYour Name 	void *rx_desc;
138*5113495bSYour Name 	int rx_desc_len;
139*5113495bSYour Name 
140*5113495bSYour Name 	rx_desc = htt_rx_msdu_desc_retrieve(htt_pdev, frag);
141*5113495bSYour Name 	rx_desc_len = htt_rx_msdu_rx_desc_size_hl(htt_pdev, rx_desc);
142*5113495bSYour Name 	qdf_nbuf_pull_head(frag, rx_desc_len + hdrsize);
143*5113495bSYour Name }
144*5113495bSYour Name 
145*5113495bSYour Name /**
146*5113495bSYour Name  * ol_rx_frag_desc_adjust() - adjust rx frag descriptor position
147*5113495bSYour Name  * @pdev: pointer to txrx handle
148*5113495bSYour Name  * @msdu: msdu
149*5113495bSYour Name  * @rx_desc_old_position: rx descriptor old position
150*5113495bSYour Name  * @ind_old_position:index of old position
151*5113495bSYour Name  * @rx_desc_len: rx descriptor length
152*5113495bSYour Name  *
153*5113495bSYour Name  * Return: None
154*5113495bSYour Name  */
155*5113495bSYour Name static void
ol_rx_frag_desc_adjust(ol_txrx_pdev_handle pdev,qdf_nbuf_t msdu,void ** rx_desc_old_position,void ** ind_old_position,int * rx_desc_len)156*5113495bSYour Name ol_rx_frag_desc_adjust(ol_txrx_pdev_handle pdev,
157*5113495bSYour Name 		       qdf_nbuf_t msdu,
158*5113495bSYour Name 			void **rx_desc_old_position,
159*5113495bSYour Name 			void **ind_old_position, int *rx_desc_len)
160*5113495bSYour Name {
161*5113495bSYour Name 	*rx_desc_old_position = htt_rx_msdu_desc_retrieve(pdev->htt_pdev,
162*5113495bSYour Name 									msdu);
163*5113495bSYour Name 	*ind_old_position = *rx_desc_old_position - HTT_RX_IND_HL_BYTES;
164*5113495bSYour Name 	*rx_desc_len = htt_rx_msdu_rx_desc_size_hl(pdev->htt_pdev,
165*5113495bSYour Name 			*rx_desc_old_position);
166*5113495bSYour Name }
167*5113495bSYour Name 
168*5113495bSYour Name /**
169*5113495bSYour Name  * ol_rx_frag_restructure() - point to payload for HL
170*5113495bSYour Name  * @pdev: physical device object
171*5113495bSYour Name  * @msdu: the buffer containing the MSDU payload
172*5113495bSYour Name  * @rx_desc_old_position: rx MSDU descriptor
173*5113495bSYour Name  * @ind_old_position: rx msdu indication
174*5113495bSYour Name  * @f_type: pointing to rx defrag cipher
175*5113495bSYour Name  * @rx_desc_len: length by which rx descriptor to move
176*5113495bSYour Name  *
177*5113495bSYour Name  * Return: None
178*5113495bSYour Name  */
179*5113495bSYour Name static void
ol_rx_frag_restructure(ol_txrx_pdev_handle pdev,qdf_nbuf_t msdu,void * rx_desc_old_position,void * ind_old_position,const struct ol_rx_defrag_cipher * f_type,int rx_desc_len)180*5113495bSYour Name ol_rx_frag_restructure(
181*5113495bSYour Name 	ol_txrx_pdev_handle pdev,
182*5113495bSYour Name 	qdf_nbuf_t msdu,
183*5113495bSYour Name 	void *rx_desc_old_position,
184*5113495bSYour Name 	void *ind_old_position,
185*5113495bSYour Name 	const struct ol_rx_defrag_cipher *f_type,
186*5113495bSYour Name 	int rx_desc_len)
187*5113495bSYour Name {
188*5113495bSYour Name 	if ((!ind_old_position) || (!rx_desc_old_position)) {
189*5113495bSYour Name 		ol_txrx_err("ind_old_position,rx_desc_old_position is NULL");
190*5113495bSYour Name 		ASSERT(0);
191*5113495bSYour Name 		return;
192*5113495bSYour Name 	}
193*5113495bSYour Name 	/* move rx description*/
194*5113495bSYour Name 	qdf_mem_move(rx_desc_old_position + f_type->ic_header,
195*5113495bSYour Name 		     rx_desc_old_position, rx_desc_len);
196*5113495bSYour Name 	/* move rx indication*/
197*5113495bSYour Name 	qdf_mem_move(ind_old_position + f_type->ic_header, ind_old_position,
198*5113495bSYour Name 		     HTT_RX_IND_HL_BYTES);
199*5113495bSYour Name }
200*5113495bSYour Name 
201*5113495bSYour Name /**
202*5113495bSYour Name  * ol_rx_get_desc_len() - point to payload for HL
203*5113495bSYour Name  * @htt_pdev: the HTT instance the rx data was received on
204*5113495bSYour Name  * @wbuf: buffer containing the MSDU payload
205*5113495bSYour Name  * @rx_desc_old_position: rx MSDU descriptor
206*5113495bSYour Name  *
207*5113495bSYour Name  * Return: Return the HL rx desc size
208*5113495bSYour Name  */
209*5113495bSYour Name static
ol_rx_get_desc_len(htt_pdev_handle htt_pdev,qdf_nbuf_t wbuf,void ** rx_desc_old_position)210*5113495bSYour Name int ol_rx_get_desc_len(htt_pdev_handle htt_pdev,
211*5113495bSYour Name 			qdf_nbuf_t wbuf,
212*5113495bSYour Name 			void **rx_desc_old_position)
213*5113495bSYour Name {
214*5113495bSYour Name 	int rx_desc_len = 0;
215*5113495bSYour Name 	*rx_desc_old_position = htt_rx_msdu_desc_retrieve(htt_pdev, wbuf);
216*5113495bSYour Name 	rx_desc_len = htt_rx_msdu_rx_desc_size_hl(htt_pdev,
217*5113495bSYour Name 			*rx_desc_old_position);
218*5113495bSYour Name 
219*5113495bSYour Name 	return rx_desc_len;
220*5113495bSYour Name }
221*5113495bSYour Name 
222*5113495bSYour Name /**
223*5113495bSYour Name  * ol_rx_defrag_push_rx_desc() - point to payload for HL
224*5113495bSYour Name  * @nbuf: buffer containing the MSDU payload
225*5113495bSYour Name  * @rx_desc_old_position: rx MSDU descriptor
226*5113495bSYour Name  * @ind_old_position: rx msdu indication
227*5113495bSYour Name  * @rx_desc_len: HL rx desc size
228*5113495bSYour Name  *
229*5113495bSYour Name  * Return: Return the HL rx desc size
230*5113495bSYour Name  */
231*5113495bSYour Name static
ol_rx_defrag_push_rx_desc(qdf_nbuf_t nbuf,void * rx_desc_old_position,void * ind_old_position,int rx_desc_len)232*5113495bSYour Name void ol_rx_defrag_push_rx_desc(qdf_nbuf_t nbuf,
233*5113495bSYour Name 				void *rx_desc_old_position,
234*5113495bSYour Name 				void *ind_old_position,
235*5113495bSYour Name 				int rx_desc_len)
236*5113495bSYour Name {
237*5113495bSYour Name 	qdf_nbuf_push_head(nbuf, rx_desc_len);
238*5113495bSYour Name 	qdf_mem_move(
239*5113495bSYour Name 		qdf_nbuf_data(nbuf), rx_desc_old_position, rx_desc_len);
240*5113495bSYour Name 	qdf_mem_move(
241*5113495bSYour Name 		qdf_nbuf_data(nbuf) - HTT_RX_IND_HL_BYTES, ind_old_position,
242*5113495bSYour Name 		HTT_RX_IND_HL_BYTES);
243*5113495bSYour Name }
244*5113495bSYour Name #else
245*5113495bSYour Name 
ol_rx_frag_get_mac_hdr(htt_pdev_handle htt_pdev,qdf_nbuf_t frag)246*5113495bSYour Name static inline struct ieee80211_frame *ol_rx_frag_get_mac_hdr(
247*5113495bSYour Name 	htt_pdev_handle htt_pdev,
248*5113495bSYour Name 	qdf_nbuf_t frag)
249*5113495bSYour Name {
250*5113495bSYour Name 	return
251*5113495bSYour Name 		(struct ieee80211_frame *) qdf_nbuf_data(frag);
252*5113495bSYour Name }
253*5113495bSYour Name 
ol_rx_frag_pull_hdr(htt_pdev_handle htt_pdev,qdf_nbuf_t frag,int hdrsize)254*5113495bSYour Name static inline void ol_rx_frag_pull_hdr(htt_pdev_handle htt_pdev,
255*5113495bSYour Name 	qdf_nbuf_t frag, int hdrsize)
256*5113495bSYour Name {
257*5113495bSYour Name 	qdf_nbuf_pull_head(frag, hdrsize);
258*5113495bSYour Name }
259*5113495bSYour Name 
260*5113495bSYour Name static inline void
ol_rx_frag_desc_adjust(ol_txrx_pdev_handle pdev,qdf_nbuf_t msdu,void ** rx_desc_old_position,void ** ind_old_position,int * rx_desc_len)261*5113495bSYour Name ol_rx_frag_desc_adjust(ol_txrx_pdev_handle pdev,
262*5113495bSYour Name 		       qdf_nbuf_t msdu,
263*5113495bSYour Name 		       void **rx_desc_old_position,
264*5113495bSYour Name 		       void **ind_old_position, int *rx_desc_len)
265*5113495bSYour Name {
266*5113495bSYour Name 	*rx_desc_old_position = NULL;
267*5113495bSYour Name 	*ind_old_position = NULL;
268*5113495bSYour Name 	*rx_desc_len = 0;
269*5113495bSYour Name }
270*5113495bSYour Name 
271*5113495bSYour Name static inline void
ol_rx_frag_restructure(ol_txrx_pdev_handle pdev,qdf_nbuf_t msdu,void * rx_desc_old_position,void * ind_old_position,const struct ol_rx_defrag_cipher * f_type,int rx_desc_len)272*5113495bSYour Name ol_rx_frag_restructure(
273*5113495bSYour Name 		ol_txrx_pdev_handle pdev,
274*5113495bSYour Name 		qdf_nbuf_t msdu,
275*5113495bSYour Name 		void *rx_desc_old_position,
276*5113495bSYour Name 		void *ind_old_position,
277*5113495bSYour Name 		const struct ol_rx_defrag_cipher *f_type,
278*5113495bSYour Name 		int rx_desc_len)
279*5113495bSYour Name {
280*5113495bSYour Name 	/* no op */
281*5113495bSYour Name }
282*5113495bSYour Name 
283*5113495bSYour Name static inline
ol_rx_get_desc_len(htt_pdev_handle htt_pdev,qdf_nbuf_t wbuf,void ** rx_desc_old_position)284*5113495bSYour Name int ol_rx_get_desc_len(htt_pdev_handle htt_pdev,
285*5113495bSYour Name 			qdf_nbuf_t wbuf,
286*5113495bSYour Name 			void **rx_desc_old_position)
287*5113495bSYour Name {
288*5113495bSYour Name 	return 0;
289*5113495bSYour Name }
290*5113495bSYour Name 
291*5113495bSYour Name static inline
ol_rx_defrag_push_rx_desc(qdf_nbuf_t nbuf,void * rx_desc_old_position,void * ind_old_position,int rx_desc_len)292*5113495bSYour Name void ol_rx_defrag_push_rx_desc(qdf_nbuf_t nbuf,
293*5113495bSYour Name 			void *rx_desc_old_position,
294*5113495bSYour Name 			void *ind_old_position,
295*5113495bSYour Name 			int rx_desc_len)
296*5113495bSYour Name {
297*5113495bSYour Name 	return;
298*5113495bSYour Name }
299*5113495bSYour Name #endif /* CONFIG_HL_SUPPORT */
300*5113495bSYour Name 
301*5113495bSYour Name /*
302*5113495bSYour Name  * Process incoming fragments
303*5113495bSYour Name  */
304*5113495bSYour Name void
ol_rx_frag_indication_handler(ol_txrx_pdev_handle pdev,qdf_nbuf_t rx_frag_ind_msg,uint16_t peer_id,uint8_t tid)305*5113495bSYour Name ol_rx_frag_indication_handler(ol_txrx_pdev_handle pdev,
306*5113495bSYour Name 			      qdf_nbuf_t rx_frag_ind_msg,
307*5113495bSYour Name 			      uint16_t peer_id, uint8_t tid)
308*5113495bSYour Name {
309*5113495bSYour Name 	uint16_t seq_num;
310*5113495bSYour Name 	uint16_t seq_num_start, seq_num_end;
311*5113495bSYour Name 	struct ol_txrx_peer_t *peer;
312*5113495bSYour Name 	htt_pdev_handle htt_pdev;
313*5113495bSYour Name 	qdf_nbuf_t head_msdu, tail_msdu;
314*5113495bSYour Name 	void *rx_mpdu_desc;
315*5113495bSYour Name 	uint8_t pktlog_bit;
316*5113495bSYour Name 	uint32_t msdu_count = 0;
317*5113495bSYour Name 	int ret;
318*5113495bSYour Name 	void *rx_desc;
319*5113495bSYour Name 
320*5113495bSYour Name 	if (tid >= OL_TXRX_NUM_EXT_TIDS) {
321*5113495bSYour Name 		ol_txrx_err("Invalid tid: %u", tid);
322*5113495bSYour Name 		return;
323*5113495bSYour Name 	}
324*5113495bSYour Name 
325*5113495bSYour Name 	htt_pdev = pdev->htt_pdev;
326*5113495bSYour Name 	peer = ol_txrx_peer_find_by_id(pdev, peer_id);
327*5113495bSYour Name 
328*5113495bSYour Name 	if (!ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev) &&
329*5113495bSYour Name 	    htt_rx_ind_flush(pdev->htt_pdev, rx_frag_ind_msg) && peer) {
330*5113495bSYour Name 		htt_rx_frag_ind_flush_seq_num_range(pdev->htt_pdev,
331*5113495bSYour Name 						    rx_frag_ind_msg,
332*5113495bSYour Name 						    &seq_num_start,
333*5113495bSYour Name 						    &seq_num_end);
334*5113495bSYour Name 		/*
335*5113495bSYour Name 		 * Assuming flush indication for frags sent from target is
336*5113495bSYour Name 		 * separate from normal frames
337*5113495bSYour Name 		 */
338*5113495bSYour Name 		ol_rx_reorder_flush_frag(htt_pdev, peer, tid, seq_num_start);
339*5113495bSYour Name 	} else {
340*5113495bSYour Name 		uint32_t *msg_word;
341*5113495bSYour Name 		uint8_t *rx_ind_data;
342*5113495bSYour Name 
343*5113495bSYour Name 		rx_ind_data = qdf_nbuf_data(rx_frag_ind_msg);
344*5113495bSYour Name 		msg_word = (uint32_t *)rx_ind_data;
345*5113495bSYour Name 		msdu_count = HTT_RX_IN_ORD_PADDR_IND_MSDU_CNT_GET(*(msg_word +
346*5113495bSYour Name 								    1));
347*5113495bSYour Name 	}
348*5113495bSYour Name 
349*5113495bSYour Name 	pktlog_bit =
350*5113495bSYour Name 		(htt_rx_amsdu_rx_in_order_get_pktlog(rx_frag_ind_msg) == 0x01);
351*5113495bSYour Name 	ret = htt_rx_frag_pop(htt_pdev, rx_frag_ind_msg, &head_msdu,
352*5113495bSYour Name 			      &tail_msdu, &msdu_count);
353*5113495bSYour Name 	/* Return if msdu pop fails from rx hash table, as recovery
354*5113495bSYour Name 	 * is triggered and we exit gracefully.
355*5113495bSYour Name 	 */
356*5113495bSYour Name 	if (!ret)
357*5113495bSYour Name 		return;
358*5113495bSYour Name 	if (peer) {
359*5113495bSYour Name 		qdf_assert(head_msdu == tail_msdu);
360*5113495bSYour Name 		if (ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev)) {
361*5113495bSYour Name 			rx_mpdu_desc =
362*5113495bSYour Name 				htt_rx_mpdu_desc_list_next(htt_pdev, head_msdu);
363*5113495bSYour Name 		} else {
364*5113495bSYour Name 			rx_mpdu_desc =
365*5113495bSYour Name 				htt_rx_mpdu_desc_list_next(htt_pdev,
366*5113495bSYour Name 							   rx_frag_ind_msg);
367*5113495bSYour Name 		}
368*5113495bSYour Name 		seq_num = htt_rx_mpdu_desc_seq_num(htt_pdev,
369*5113495bSYour Name 						   rx_mpdu_desc, true);
370*5113495bSYour Name 		OL_RX_ERR_STATISTICS_1(pdev, peer->vdev, peer, rx_mpdu_desc,
371*5113495bSYour Name 				       OL_RX_ERR_NONE_FRAG);
372*5113495bSYour Name 		ol_rx_send_pktlog_event(pdev, peer, head_msdu, pktlog_bit);
373*5113495bSYour Name 		rx_desc = htt_rx_msdu_desc_retrieve(pdev->htt_pdev, head_msdu);
374*5113495bSYour Name 		ol_rx_timestamp(pdev->ctrl_pdev, rx_desc, head_msdu);
375*5113495bSYour Name 		ol_rx_reorder_store_frag(pdev, peer, tid, seq_num, head_msdu);
376*5113495bSYour Name 	} else {
377*5113495bSYour Name 		/* invalid frame - discard it */
378*5113495bSYour Name 		if (ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev))
379*5113495bSYour Name 			htt_rx_msdu_desc_retrieve(htt_pdev, head_msdu);
380*5113495bSYour Name 		else
381*5113495bSYour Name 			htt_rx_mpdu_desc_list_next(htt_pdev, rx_frag_ind_msg);
382*5113495bSYour Name 
383*5113495bSYour Name 		ol_rx_send_pktlog_event(pdev, peer, head_msdu, pktlog_bit);
384*5113495bSYour Name 		htt_rx_desc_frame_free(htt_pdev, head_msdu);
385*5113495bSYour Name 	}
386*5113495bSYour Name 	/* request HTT to provide new rx MSDU buffers for the target to fill. */
387*5113495bSYour Name 	if (ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev) &&
388*5113495bSYour Name 	    !pdev->cfg.is_high_latency)
389*5113495bSYour Name 		htt_rx_msdu_buff_in_order_replenish(htt_pdev, msdu_count);
390*5113495bSYour Name 	else
391*5113495bSYour Name 		htt_rx_msdu_buff_replenish(htt_pdev);
392*5113495bSYour Name }
393*5113495bSYour Name 
394*5113495bSYour Name /*
395*5113495bSYour Name  * Flushing fragments
396*5113495bSYour Name  */
397*5113495bSYour Name void
ol_rx_reorder_flush_frag(htt_pdev_handle htt_pdev,struct ol_txrx_peer_t * peer,unsigned int tid,uint16_t seq_num)398*5113495bSYour Name ol_rx_reorder_flush_frag(htt_pdev_handle htt_pdev,
399*5113495bSYour Name 			 struct ol_txrx_peer_t *peer,
400*5113495bSYour Name 			 unsigned int tid, uint16_t seq_num)
401*5113495bSYour Name {
402*5113495bSYour Name 	struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem;
403*5113495bSYour Name 	int seq;
404*5113495bSYour Name 
405*5113495bSYour Name 	seq = seq_num & peer->tids_rx_reorder[tid].win_sz_mask;
406*5113495bSYour Name 	rx_reorder_array_elem = &peer->tids_rx_reorder[tid].array[seq];
407*5113495bSYour Name 	if (rx_reorder_array_elem->head) {
408*5113495bSYour Name 		ol_rx_frames_free(htt_pdev, rx_reorder_array_elem->head);
409*5113495bSYour Name 		rx_reorder_array_elem->head = NULL;
410*5113495bSYour Name 		rx_reorder_array_elem->tail = NULL;
411*5113495bSYour Name 	}
412*5113495bSYour Name }
413*5113495bSYour Name 
414*5113495bSYour Name /*
415*5113495bSYour Name  * Reorder and store fragments
416*5113495bSYour Name  */
417*5113495bSYour Name void
ol_rx_reorder_store_frag(ol_txrx_pdev_handle pdev,struct ol_txrx_peer_t * peer,unsigned int tid,uint16_t seq_num,qdf_nbuf_t frag)418*5113495bSYour Name ol_rx_reorder_store_frag(ol_txrx_pdev_handle pdev,
419*5113495bSYour Name 			 struct ol_txrx_peer_t *peer,
420*5113495bSYour Name 			 unsigned int tid, uint16_t seq_num, qdf_nbuf_t frag)
421*5113495bSYour Name {
422*5113495bSYour Name 	struct ieee80211_frame *fmac_hdr, *mac_hdr;
423*5113495bSYour Name 	uint8_t fragno, more_frag, all_frag_present = 0;
424*5113495bSYour Name 	struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem;
425*5113495bSYour Name 	uint16_t frxseq, rxseq, seq;
426*5113495bSYour Name 	htt_pdev_handle htt_pdev = pdev->htt_pdev;
427*5113495bSYour Name 	void *rx_desc;
428*5113495bSYour Name 	uint8_t index;
429*5113495bSYour Name 
430*5113495bSYour Name 	seq = seq_num & peer->tids_rx_reorder[tid].win_sz_mask;
431*5113495bSYour Name 	qdf_assert(seq == 0);
432*5113495bSYour Name 	rx_reorder_array_elem = &peer->tids_rx_reorder[tid].array[seq];
433*5113495bSYour Name 
434*5113495bSYour Name 	mac_hdr = (struct ieee80211_frame *)
435*5113495bSYour Name 		ol_rx_frag_get_mac_hdr(htt_pdev, frag);
436*5113495bSYour Name 	rxseq = qdf_le16_to_cpu(*(uint16_t *) mac_hdr->i_seq) >>
437*5113495bSYour Name 		IEEE80211_SEQ_SEQ_SHIFT;
438*5113495bSYour Name 	fragno = qdf_le16_to_cpu(*(uint16_t *) mac_hdr->i_seq) &
439*5113495bSYour Name 		IEEE80211_SEQ_FRAG_MASK;
440*5113495bSYour Name 	more_frag = mac_hdr->i_fc[1] & IEEE80211_FC1_MORE_FRAG;
441*5113495bSYour Name 
442*5113495bSYour Name 	rx_desc = htt_rx_msdu_desc_retrieve(htt_pdev, frag);
443*5113495bSYour Name 	qdf_assert(htt_rx_msdu_has_wlan_mcast_flag(htt_pdev, rx_desc));
444*5113495bSYour Name 	index = htt_rx_msdu_is_wlan_mcast(htt_pdev, rx_desc) ?
445*5113495bSYour Name 		txrx_sec_mcast : txrx_sec_ucast;
446*5113495bSYour Name 
447*5113495bSYour Name 	/*
448*5113495bSYour Name 	 * Multicast/Broadcast frames should not be fragmented so drop
449*5113495bSYour Name 	 * such frames.
450*5113495bSYour Name 	 */
451*5113495bSYour Name 	if (index != txrx_sec_ucast) {
452*5113495bSYour Name 		ol_rx_frames_free(htt_pdev, frag);
453*5113495bSYour Name 		return;
454*5113495bSYour Name 	}
455*5113495bSYour Name 
456*5113495bSYour Name 	if (peer->security[index].sec_type != htt_sec_type_none &&
457*5113495bSYour Name 	    !htt_rx_mpdu_is_encrypted(htt_pdev, rx_desc)) {
458*5113495bSYour Name 		ol_txrx_err("Unencrypted fragment received in security mode %d",
459*5113495bSYour Name 			    peer->security[index].sec_type);
460*5113495bSYour Name 		ol_rx_frames_free(htt_pdev, frag);
461*5113495bSYour Name 		return;
462*5113495bSYour Name 	}
463*5113495bSYour Name 
464*5113495bSYour Name 	if ((!more_frag) && (!fragno) && (!rx_reorder_array_elem->head)) {
465*5113495bSYour Name 		rx_reorder_array_elem->head = frag;
466*5113495bSYour Name 		rx_reorder_array_elem->tail = frag;
467*5113495bSYour Name 		qdf_nbuf_set_next(frag, NULL);
468*5113495bSYour Name 		ol_rx_defrag(pdev, peer, tid, rx_reorder_array_elem->head);
469*5113495bSYour Name 		rx_reorder_array_elem->head = NULL;
470*5113495bSYour Name 		rx_reorder_array_elem->tail = NULL;
471*5113495bSYour Name 		return;
472*5113495bSYour Name 	}
473*5113495bSYour Name 	if (rx_reorder_array_elem->head) {
474*5113495bSYour Name 		fmac_hdr = (struct ieee80211_frame *)
475*5113495bSYour Name 			ol_rx_frag_get_mac_hdr(htt_pdev,
476*5113495bSYour Name 					       rx_reorder_array_elem->head);
477*5113495bSYour Name 		frxseq = qdf_le16_to_cpu(*(uint16_t *) fmac_hdr->i_seq) >>
478*5113495bSYour Name 			IEEE80211_SEQ_SEQ_SHIFT;
479*5113495bSYour Name 		if (rxseq != frxseq
480*5113495bSYour Name 		    || !DEFRAG_IEEE80211_ADDR_EQ(mac_hdr->i_addr1,
481*5113495bSYour Name 						 fmac_hdr->i_addr1)
482*5113495bSYour Name 		    || !DEFRAG_IEEE80211_ADDR_EQ(mac_hdr->i_addr2,
483*5113495bSYour Name 						 fmac_hdr->i_addr2)) {
484*5113495bSYour Name 			ol_rx_frames_free(htt_pdev,
485*5113495bSYour Name 					  rx_reorder_array_elem->head);
486*5113495bSYour Name 			rx_reorder_array_elem->head = NULL;
487*5113495bSYour Name 			rx_reorder_array_elem->tail = NULL;
488*5113495bSYour Name 			ol_txrx_err("ol_rx_reorder_store:%s mismatch",
489*5113495bSYour Name 				   (rxseq == frxseq)
490*5113495bSYour Name 				   ? "address"
491*5113495bSYour Name 				   : "seq number");
492*5113495bSYour Name 		}
493*5113495bSYour Name 	}
494*5113495bSYour Name 
495*5113495bSYour Name 	ol_rx_fraglist_insert(htt_pdev, &rx_reorder_array_elem->head,
496*5113495bSYour Name 			      &rx_reorder_array_elem->tail, frag,
497*5113495bSYour Name 			      &all_frag_present);
498*5113495bSYour Name 
499*5113495bSYour Name 	if (pdev->rx.flags.defrag_timeout_check)
500*5113495bSYour Name 		ol_rx_defrag_waitlist_remove(peer, tid);
501*5113495bSYour Name 
502*5113495bSYour Name 	if (all_frag_present) {
503*5113495bSYour Name 		ol_rx_defrag(pdev, peer, tid, rx_reorder_array_elem->head);
504*5113495bSYour Name 		rx_reorder_array_elem->head = NULL;
505*5113495bSYour Name 		rx_reorder_array_elem->tail = NULL;
506*5113495bSYour Name 		peer->tids_rx_reorder[tid].defrag_timeout_ms = 0;
507*5113495bSYour Name 		peer->tids_last_seq[tid] = seq_num;
508*5113495bSYour Name 	} else if (pdev->rx.flags.defrag_timeout_check) {
509*5113495bSYour Name 		uint32_t now_ms = qdf_system_ticks_to_msecs(qdf_system_ticks());
510*5113495bSYour Name 
511*5113495bSYour Name 		peer->tids_rx_reorder[tid].defrag_timeout_ms =
512*5113495bSYour Name 			now_ms + pdev->rx.defrag.timeout_ms;
513*5113495bSYour Name 		ol_rx_defrag_waitlist_add(peer, tid);
514*5113495bSYour Name 	}
515*5113495bSYour Name }
516*5113495bSYour Name 
517*5113495bSYour Name /*
518*5113495bSYour Name  * Insert and store fragments
519*5113495bSYour Name  */
520*5113495bSYour Name void
ol_rx_fraglist_insert(htt_pdev_handle htt_pdev,qdf_nbuf_t * head_addr,qdf_nbuf_t * tail_addr,qdf_nbuf_t frag,uint8_t * all_frag_present)521*5113495bSYour Name ol_rx_fraglist_insert(htt_pdev_handle htt_pdev,
522*5113495bSYour Name 		      qdf_nbuf_t *head_addr,
523*5113495bSYour Name 		      qdf_nbuf_t *tail_addr,
524*5113495bSYour Name 		      qdf_nbuf_t frag, uint8_t *all_frag_present)
525*5113495bSYour Name {
526*5113495bSYour Name 	qdf_nbuf_t next, prev = NULL, cur = *head_addr;
527*5113495bSYour Name 	struct ieee80211_frame *mac_hdr, *cmac_hdr, *next_hdr, *lmac_hdr;
528*5113495bSYour Name 	uint8_t fragno, cur_fragno, lfragno, next_fragno;
529*5113495bSYour Name 	uint8_t last_morefrag = 1, count = 0;
530*5113495bSYour Name 
531*5113495bSYour Name 	qdf_assert(frag);
532*5113495bSYour Name 
533*5113495bSYour Name 	mac_hdr = (struct ieee80211_frame *)
534*5113495bSYour Name 		ol_rx_frag_get_mac_hdr(htt_pdev, frag);
535*5113495bSYour Name 	fragno = qdf_le16_to_cpu(*(uint16_t *) mac_hdr->i_seq) &
536*5113495bSYour Name 		IEEE80211_SEQ_FRAG_MASK;
537*5113495bSYour Name 
538*5113495bSYour Name 	if (!(*head_addr)) {
539*5113495bSYour Name 		*head_addr = frag;
540*5113495bSYour Name 		*tail_addr = frag;
541*5113495bSYour Name 		qdf_nbuf_set_next(*tail_addr, NULL);
542*5113495bSYour Name 		return;
543*5113495bSYour Name 	}
544*5113495bSYour Name 	/* For efficiency, compare with tail first */
545*5113495bSYour Name 	lmac_hdr = (struct ieee80211_frame *)
546*5113495bSYour Name 		ol_rx_frag_get_mac_hdr(htt_pdev, *tail_addr);
547*5113495bSYour Name 	lfragno = qdf_le16_to_cpu(*(uint16_t *) lmac_hdr->i_seq) &
548*5113495bSYour Name 		  IEEE80211_SEQ_FRAG_MASK;
549*5113495bSYour Name 	if (fragno > lfragno) {
550*5113495bSYour Name 		qdf_nbuf_set_next(*tail_addr, frag);
551*5113495bSYour Name 		*tail_addr = frag;
552*5113495bSYour Name 		qdf_nbuf_set_next(*tail_addr, NULL);
553*5113495bSYour Name 	} else {
554*5113495bSYour Name 		do {
555*5113495bSYour Name 			cmac_hdr = (struct ieee80211_frame *)
556*5113495bSYour Name 				ol_rx_frag_get_mac_hdr(htt_pdev, cur);
557*5113495bSYour Name 			cur_fragno =
558*5113495bSYour Name 				qdf_le16_to_cpu(*(uint16_t *) cmac_hdr->i_seq) &
559*5113495bSYour Name 				IEEE80211_SEQ_FRAG_MASK;
560*5113495bSYour Name 			prev = cur;
561*5113495bSYour Name 			cur = qdf_nbuf_next(cur);
562*5113495bSYour Name 		} while (fragno > cur_fragno);
563*5113495bSYour Name 
564*5113495bSYour Name 		if (fragno == cur_fragno) {
565*5113495bSYour Name 			htt_rx_desc_frame_free(htt_pdev, frag);
566*5113495bSYour Name 			*all_frag_present = 0;
567*5113495bSYour Name 			return;
568*5113495bSYour Name 		}
569*5113495bSYour Name 
570*5113495bSYour Name 		qdf_nbuf_set_next(prev, frag);
571*5113495bSYour Name 		qdf_nbuf_set_next(frag, cur);
572*5113495bSYour Name 	}
573*5113495bSYour Name 	next = qdf_nbuf_next(*head_addr);
574*5113495bSYour Name 	lmac_hdr = (struct ieee80211_frame *)ol_rx_frag_get_mac_hdr(htt_pdev,
575*5113495bSYour Name 								    *tail_addr);
576*5113495bSYour Name 	last_morefrag = lmac_hdr->i_fc[1] & IEEE80211_FC1_MORE_FRAG;
577*5113495bSYour Name 	if (!last_morefrag) {
578*5113495bSYour Name 		do {
579*5113495bSYour Name 			next_hdr =
580*5113495bSYour Name 				(struct ieee80211_frame *)
581*5113495bSYour Name 				ol_rx_frag_get_mac_hdr(htt_pdev, next);
582*5113495bSYour Name 			next_fragno =
583*5113495bSYour Name 				qdf_le16_to_cpu(*(uint16_t *) next_hdr->i_seq) &
584*5113495bSYour Name 				IEEE80211_SEQ_FRAG_MASK;
585*5113495bSYour Name 			count++;
586*5113495bSYour Name 			if (next_fragno != count)
587*5113495bSYour Name 				break;
588*5113495bSYour Name 
589*5113495bSYour Name 			next = qdf_nbuf_next(next);
590*5113495bSYour Name 		} while (next);
591*5113495bSYour Name 
592*5113495bSYour Name 		if (!next) {
593*5113495bSYour Name 			*all_frag_present = 1;
594*5113495bSYour Name 			return;
595*5113495bSYour Name 		}
596*5113495bSYour Name 	}
597*5113495bSYour Name 	*all_frag_present = 0;
598*5113495bSYour Name }
599*5113495bSYour Name 
600*5113495bSYour Name /*
601*5113495bSYour Name  * add tid to pending fragment wait list
602*5113495bSYour Name  */
ol_rx_defrag_waitlist_add(struct ol_txrx_peer_t * peer,unsigned int tid)603*5113495bSYour Name void ol_rx_defrag_waitlist_add(struct ol_txrx_peer_t *peer, unsigned int tid)
604*5113495bSYour Name {
605*5113495bSYour Name 	struct ol_txrx_pdev_t *pdev = peer->vdev->pdev;
606*5113495bSYour Name 	struct ol_rx_reorder_t *rx_reorder = &peer->tids_rx_reorder[tid];
607*5113495bSYour Name 
608*5113495bSYour Name 	TAILQ_INSERT_TAIL(&pdev->rx.defrag.waitlist, rx_reorder,
609*5113495bSYour Name 			  defrag_waitlist_elem);
610*5113495bSYour Name }
611*5113495bSYour Name 
612*5113495bSYour Name /*
613*5113495bSYour Name  * remove tid from pending fragment wait list
614*5113495bSYour Name  */
ol_rx_defrag_waitlist_remove(struct ol_txrx_peer_t * peer,unsigned int tid)615*5113495bSYour Name void ol_rx_defrag_waitlist_remove(struct ol_txrx_peer_t *peer, unsigned int tid)
616*5113495bSYour Name {
617*5113495bSYour Name 	struct ol_txrx_pdev_t *pdev = peer->vdev->pdev;
618*5113495bSYour Name 	struct ol_rx_reorder_t *rx_reorder = &peer->tids_rx_reorder[tid];
619*5113495bSYour Name 
620*5113495bSYour Name 	if (rx_reorder->defrag_waitlist_elem.tqe_next) {
621*5113495bSYour Name 
622*5113495bSYour Name 		TAILQ_REMOVE(&pdev->rx.defrag.waitlist, rx_reorder,
623*5113495bSYour Name 			     defrag_waitlist_elem);
624*5113495bSYour Name 
625*5113495bSYour Name 		rx_reorder->defrag_waitlist_elem.tqe_next = NULL;
626*5113495bSYour Name 		rx_reorder->defrag_waitlist_elem.tqe_prev = NULL;
627*5113495bSYour Name 	} else if (rx_reorder->defrag_waitlist_elem.tqe_next) {
628*5113495bSYour Name 		ol_txrx_alert("waitlist->tqe_prv = NULL");
629*5113495bSYour Name 		QDF_ASSERT(0);
630*5113495bSYour Name 		rx_reorder->defrag_waitlist_elem.tqe_next = NULL;
631*5113495bSYour Name 	}
632*5113495bSYour Name }
633*5113495bSYour Name 
634*5113495bSYour Name #ifndef container_of
635*5113495bSYour Name #define container_of(ptr, type, member) \
636*5113495bSYour Name 	((type *)((char *)(ptr) - (char *)(&((type *)0)->member)))
637*5113495bSYour Name #endif
638*5113495bSYour Name 
639*5113495bSYour Name /*
640*5113495bSYour Name  * flush stale fragments from the waitlist
641*5113495bSYour Name  */
ol_rx_defrag_waitlist_flush(struct ol_txrx_pdev_t * pdev)642*5113495bSYour Name void ol_rx_defrag_waitlist_flush(struct ol_txrx_pdev_t *pdev)
643*5113495bSYour Name {
644*5113495bSYour Name 	struct ol_rx_reorder_t *rx_reorder, *tmp;
645*5113495bSYour Name 	uint32_t now_ms = qdf_system_ticks_to_msecs(qdf_system_ticks());
646*5113495bSYour Name 
647*5113495bSYour Name 	TAILQ_FOREACH_SAFE(rx_reorder, &pdev->rx.defrag.waitlist,
648*5113495bSYour Name 			   defrag_waitlist_elem, tmp) {
649*5113495bSYour Name 		struct ol_txrx_peer_t *peer;
650*5113495bSYour Name 		struct ol_rx_reorder_t *rx_reorder_base;
651*5113495bSYour Name 		unsigned int tid;
652*5113495bSYour Name 
653*5113495bSYour Name 		if (rx_reorder->defrag_timeout_ms > now_ms)
654*5113495bSYour Name 			break;
655*5113495bSYour Name 
656*5113495bSYour Name 		tid = rx_reorder->tid;
657*5113495bSYour Name 		if (tid >= OL_TXRX_NUM_EXT_TIDS) {
658*5113495bSYour Name 			ol_txrx_err("Invalid tid: %u", tid);
659*5113495bSYour Name 			WARN_ON(1);
660*5113495bSYour Name 			continue;
661*5113495bSYour Name 		}
662*5113495bSYour Name 		/* get index 0 of the rx_reorder array */
663*5113495bSYour Name 		rx_reorder_base = rx_reorder - tid;
664*5113495bSYour Name 		peer =
665*5113495bSYour Name 			container_of(rx_reorder_base, struct ol_txrx_peer_t,
666*5113495bSYour Name 				     tids_rx_reorder[0]);
667*5113495bSYour Name 
668*5113495bSYour Name 		ol_rx_defrag_waitlist_remove(peer, tid);
669*5113495bSYour Name 		ol_rx_reorder_flush_frag(pdev->htt_pdev, peer, tid,
670*5113495bSYour Name 					 0 /* frags always stored at seq 0 */);
671*5113495bSYour Name 	}
672*5113495bSYour Name }
673*5113495bSYour Name 
674*5113495bSYour Name /**
675*5113495bSYour Name  * ol_rx_frag_gcmp_decap() - Remove GCMP header from fragment
676*5113495bSYour Name  * @pdev : data path pdev handle
677*5113495bSYour Name  * @nbuf : network buffer
678*5113495bSYour Name  * @hdrlen : MAC header len
679*5113495bSYour Name  *
680*5113495bSYour Name  * Return: OL_RX_DEFRAG_OK on success else failure code
681*5113495bSYour Name  */
682*5113495bSYour Name static int
ol_rx_frag_gcmp_decap(ol_txrx_pdev_handle pdev,qdf_nbuf_t nbuf,uint16_t hdrlen)683*5113495bSYour Name ol_rx_frag_gcmp_decap(ol_txrx_pdev_handle pdev,
684*5113495bSYour Name 		      qdf_nbuf_t nbuf, uint16_t hdrlen)
685*5113495bSYour Name {
686*5113495bSYour Name 	uint8_t *ivp, *orig_hdr;
687*5113495bSYour Name 	void *rx_desc_old_position = NULL;
688*5113495bSYour Name 	void *ind_old_position = NULL;
689*5113495bSYour Name 	int rx_desc_len = 0;
690*5113495bSYour Name 
691*5113495bSYour Name 	ol_rx_frag_desc_adjust(pdev,
692*5113495bSYour Name 			       nbuf,
693*5113495bSYour Name 			       &rx_desc_old_position,
694*5113495bSYour Name 			       &ind_old_position, &rx_desc_len);
695*5113495bSYour Name 
696*5113495bSYour Name 	orig_hdr = (uint8_t *)(qdf_nbuf_data(nbuf) + rx_desc_len);
697*5113495bSYour Name 	ivp = orig_hdr + hdrlen;
698*5113495bSYour Name 	if (!(ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV))
699*5113495bSYour Name 		return OL_RX_DEFRAG_ERR;
700*5113495bSYour Name 
701*5113495bSYour Name 	qdf_mem_move(orig_hdr + f_gcmp.ic_header, orig_hdr, hdrlen);
702*5113495bSYour Name 	ol_rx_frag_restructure(
703*5113495bSYour Name 			pdev,
704*5113495bSYour Name 			nbuf,
705*5113495bSYour Name 			rx_desc_old_position,
706*5113495bSYour Name 			ind_old_position,
707*5113495bSYour Name 			&f_gcmp,
708*5113495bSYour Name 			rx_desc_len);
709*5113495bSYour Name 	qdf_nbuf_pull_head(nbuf, f_gcmp.ic_header);
710*5113495bSYour Name 
711*5113495bSYour Name 	return OL_RX_DEFRAG_OK;
712*5113495bSYour Name }
713*5113495bSYour Name 
714*5113495bSYour Name /**
715*5113495bSYour Name  * ol_rx_frag_gcmp_demic() - Remove MIC info from GCMP fragment
716*5113495bSYour Name  * @pdev : data path pdev handle
717*5113495bSYour Name  * @nbuf : network buffer
718*5113495bSYour Name  * @hdrlen : MAC header len
719*5113495bSYour Name  *
720*5113495bSYour Name  * Return: OL_RX_DEFRAG_OK on success else failure code
721*5113495bSYour Name  */
722*5113495bSYour Name static int
ol_rx_frag_gcmp_demic(ol_txrx_pdev_handle pdev,qdf_nbuf_t wbuf,uint16_t hdrlen)723*5113495bSYour Name ol_rx_frag_gcmp_demic(ol_txrx_pdev_handle pdev,
724*5113495bSYour Name 		      qdf_nbuf_t wbuf, uint16_t hdrlen)
725*5113495bSYour Name {
726*5113495bSYour Name 	uint8_t *ivp, *orig_hdr;
727*5113495bSYour Name 	void *rx_desc_old_position = NULL;
728*5113495bSYour Name 	void *ind_old_position = NULL;
729*5113495bSYour Name 	int rx_desc_len = 0;
730*5113495bSYour Name 
731*5113495bSYour Name 	ol_rx_frag_desc_adjust(pdev,
732*5113495bSYour Name 			       wbuf,
733*5113495bSYour Name 			       &rx_desc_old_position,
734*5113495bSYour Name 			       &ind_old_position, &rx_desc_len);
735*5113495bSYour Name 
736*5113495bSYour Name 	orig_hdr = (uint8_t *)(qdf_nbuf_data(wbuf) + rx_desc_len);
737*5113495bSYour Name 
738*5113495bSYour Name 	ivp = orig_hdr + hdrlen;
739*5113495bSYour Name 	if (!(ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV))
740*5113495bSYour Name 		return OL_RX_DEFRAG_ERR;
741*5113495bSYour Name 
742*5113495bSYour Name 	qdf_nbuf_trim_tail(wbuf, f_gcmp.ic_trailer);
743*5113495bSYour Name 
744*5113495bSYour Name 	return OL_RX_DEFRAG_OK;
745*5113495bSYour Name }
746*5113495bSYour Name 
747*5113495bSYour Name /*
748*5113495bSYour Name  * Handling security checking and processing fragments
749*5113495bSYour Name  */
750*5113495bSYour Name void
ol_rx_defrag(ol_txrx_pdev_handle pdev,struct ol_txrx_peer_t * peer,unsigned int tid,qdf_nbuf_t frag_list)751*5113495bSYour Name ol_rx_defrag(ol_txrx_pdev_handle pdev,
752*5113495bSYour Name 	     struct ol_txrx_peer_t *peer, unsigned int tid,
753*5113495bSYour Name 	     qdf_nbuf_t frag_list)
754*5113495bSYour Name {
755*5113495bSYour Name 	struct ol_txrx_vdev_t *vdev = NULL;
756*5113495bSYour Name 	qdf_nbuf_t tmp_next, msdu, prev = NULL, cur = frag_list;
757*5113495bSYour Name 	uint8_t index, tkip_demic = 0;
758*5113495bSYour Name 	uint16_t hdr_space;
759*5113495bSYour Name 	void *rx_desc;
760*5113495bSYour Name 	struct ieee80211_frame *wh;
761*5113495bSYour Name 	uint8_t key[DEFRAG_IEEE80211_KEY_LEN];
762*5113495bSYour Name 	htt_pdev_handle htt_pdev = pdev->htt_pdev;
763*5113495bSYour Name 	struct ol_txrx_peer_t *peer_head = NULL;
764*5113495bSYour Name 	uint8_t bssid[QDF_MAC_ADDR_SIZE];
765*5113495bSYour Name 	struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC);
766*5113495bSYour Name 
767*5113495bSYour Name 	if (qdf_unlikely(!soc))
768*5113495bSYour Name 		return;
769*5113495bSYour Name 
770*5113495bSYour Name 	vdev = peer->vdev;
771*5113495bSYour Name 
772*5113495bSYour Name 	/* bypass defrag for safe mode */
773*5113495bSYour Name 	if (vdev->safemode) {
774*5113495bSYour Name 		if (ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev))
775*5113495bSYour Name 			ol_rx_in_order_deliver(vdev, peer, tid, frag_list);
776*5113495bSYour Name 		else
777*5113495bSYour Name 			ol_rx_deliver(vdev, peer, tid, frag_list);
778*5113495bSYour Name 		return;
779*5113495bSYour Name 	}
780*5113495bSYour Name 
781*5113495bSYour Name 	while (cur) {
782*5113495bSYour Name 		tmp_next = qdf_nbuf_next(cur);
783*5113495bSYour Name 		qdf_nbuf_set_next(cur, NULL);
784*5113495bSYour Name 		/*
785*5113495bSYour Name 		 * Strict PN check between the first fragment of the current
786*5113495bSYour Name 		 * frame and the last fragment of the previous frame is not
787*5113495bSYour Name 		 * necessary.
788*5113495bSYour Name 		 */
789*5113495bSYour Name 		if (!ol_rx_pn_check_base(vdev, peer, tid, cur,
790*5113495bSYour Name 					 (cur == frag_list) ? false : true)) {
791*5113495bSYour Name 			/* PN check failed,discard frags */
792*5113495bSYour Name 			if (prev) {
793*5113495bSYour Name 				qdf_nbuf_set_next(prev, NULL);
794*5113495bSYour Name 				ol_rx_frames_free(htt_pdev, frag_list);
795*5113495bSYour Name 			}
796*5113495bSYour Name 			ol_rx_frames_free(htt_pdev, tmp_next);
797*5113495bSYour Name 			ol_txrx_err("PN Check failed");
798*5113495bSYour Name 			return;
799*5113495bSYour Name 		}
800*5113495bSYour Name 		/* remove FCS from each fragment */
801*5113495bSYour Name 		qdf_nbuf_trim_tail(cur, DEFRAG_IEEE80211_FCS_LEN);
802*5113495bSYour Name 		prev = cur;
803*5113495bSYour Name 		qdf_nbuf_set_next(cur, tmp_next);
804*5113495bSYour Name 		cur = tmp_next;
805*5113495bSYour Name 	}
806*5113495bSYour Name 	cur = frag_list;
807*5113495bSYour Name 	wh = (struct ieee80211_frame *)ol_rx_frag_get_mac_hdr(htt_pdev, cur);
808*5113495bSYour Name 	hdr_space = ol_rx_frag_hdrsize(wh);
809*5113495bSYour Name 	rx_desc = htt_rx_msdu_desc_retrieve(htt_pdev, frag_list);
810*5113495bSYour Name 	qdf_assert(htt_rx_msdu_has_wlan_mcast_flag(htt_pdev, rx_desc));
811*5113495bSYour Name 	index = htt_rx_msdu_is_wlan_mcast(htt_pdev, rx_desc) ?
812*5113495bSYour Name 		txrx_sec_mcast : txrx_sec_ucast;
813*5113495bSYour Name 
814*5113495bSYour Name 	switch (peer->security[index].sec_type) {
815*5113495bSYour Name 	case htt_sec_type_tkip:
816*5113495bSYour Name 		tkip_demic = 1;
817*5113495bSYour Name 		fallthrough;
818*5113495bSYour Name 	/* fall-through to rest of tkip ops */
819*5113495bSYour Name 	case htt_sec_type_tkip_nomic:
820*5113495bSYour Name 		while (cur) {
821*5113495bSYour Name 			tmp_next = qdf_nbuf_next(cur);
822*5113495bSYour Name 			if (!ol_rx_frag_tkip_decap(pdev, cur, hdr_space)) {
823*5113495bSYour Name 				/* TKIP decap failed, discard frags */
824*5113495bSYour Name 				ol_rx_frames_free(htt_pdev, frag_list);
825*5113495bSYour Name 				ol_txrx_err("TKIP decap failed");
826*5113495bSYour Name 				return;
827*5113495bSYour Name 			}
828*5113495bSYour Name 			cur = tmp_next;
829*5113495bSYour Name 		}
830*5113495bSYour Name 		break;
831*5113495bSYour Name 
832*5113495bSYour Name 	case htt_sec_type_aes_ccmp:
833*5113495bSYour Name 		while (cur) {
834*5113495bSYour Name 			tmp_next = qdf_nbuf_next(cur);
835*5113495bSYour Name 			if (!ol_rx_frag_ccmp_demic(pdev, cur, hdr_space)) {
836*5113495bSYour Name 				/* CCMP demic failed, discard frags */
837*5113495bSYour Name 				ol_rx_frames_free(htt_pdev, frag_list);
838*5113495bSYour Name 				ol_txrx_err("CCMP demic failed");
839*5113495bSYour Name 				return;
840*5113495bSYour Name 			}
841*5113495bSYour Name 			if (!ol_rx_frag_ccmp_decap(pdev, cur, hdr_space)) {
842*5113495bSYour Name 				/* CCMP decap failed, discard frags */
843*5113495bSYour Name 				ol_rx_frames_free(htt_pdev, frag_list);
844*5113495bSYour Name 				ol_txrx_err("CCMP decap failed");
845*5113495bSYour Name 				return;
846*5113495bSYour Name 			}
847*5113495bSYour Name 			cur = tmp_next;
848*5113495bSYour Name 		}
849*5113495bSYour Name 		break;
850*5113495bSYour Name 
851*5113495bSYour Name 	case htt_sec_type_wep40:
852*5113495bSYour Name 	case htt_sec_type_wep104:
853*5113495bSYour Name 	case htt_sec_type_wep128:
854*5113495bSYour Name 		while (cur) {
855*5113495bSYour Name 			tmp_next = qdf_nbuf_next(cur);
856*5113495bSYour Name 			if (!ol_rx_frag_wep_decap(pdev, cur, hdr_space)) {
857*5113495bSYour Name 				/* wep decap failed, discard frags */
858*5113495bSYour Name 				ol_rx_frames_free(htt_pdev, frag_list);
859*5113495bSYour Name 				ol_txrx_err("wep decap failed");
860*5113495bSYour Name 				return;
861*5113495bSYour Name 			}
862*5113495bSYour Name 			cur = tmp_next;
863*5113495bSYour Name 		}
864*5113495bSYour Name 		break;
865*5113495bSYour Name 	case htt_sec_type_aes_gcmp:
866*5113495bSYour Name 	case htt_sec_type_aes_gcmp_256:
867*5113495bSYour Name 		while (cur) {
868*5113495bSYour Name 			tmp_next = qdf_nbuf_next(cur);
869*5113495bSYour Name 			if (!ol_rx_frag_gcmp_demic(pdev, cur, hdr_space)) {
870*5113495bSYour Name 				ol_rx_frames_free(htt_pdev, frag_list);
871*5113495bSYour Name 				ol_txrx_err("GCMP demic failed");
872*5113495bSYour Name 				return;
873*5113495bSYour Name 			}
874*5113495bSYour Name 			if (!ol_rx_frag_gcmp_decap(pdev, cur, hdr_space)) {
875*5113495bSYour Name 				ol_rx_frames_free(htt_pdev, frag_list);
876*5113495bSYour Name 				ol_txrx_err("GCMP decap failed");
877*5113495bSYour Name 				return;
878*5113495bSYour Name 			}
879*5113495bSYour Name 			cur = tmp_next;
880*5113495bSYour Name 		}
881*5113495bSYour Name 
882*5113495bSYour Name 		break;
883*5113495bSYour Name 	default:
884*5113495bSYour Name 		break;
885*5113495bSYour Name 	}
886*5113495bSYour Name 
887*5113495bSYour Name 	msdu = ol_rx_defrag_decap_recombine(htt_pdev, frag_list, hdr_space);
888*5113495bSYour Name 	if (!msdu)
889*5113495bSYour Name 		return;
890*5113495bSYour Name 
891*5113495bSYour Name 	if (tkip_demic) {
892*5113495bSYour Name 		qdf_mem_copy(key,
893*5113495bSYour Name 			     peer->security[index].michael_key,
894*5113495bSYour Name 			     sizeof(peer->security[index].michael_key));
895*5113495bSYour Name 		if (!ol_rx_frag_tkip_demic(pdev, key, msdu, hdr_space)) {
896*5113495bSYour Name 			uint64_t pn = 0;
897*5113495bSYour Name 			ol_rx_err(pdev->ctrl_pdev,
898*5113495bSYour Name 				  vdev->vdev_id, peer->mac_addr.raw, tid, 0,
899*5113495bSYour Name 				  OL_RX_ERR_TKIP_MIC, msdu, &pn, 0);
900*5113495bSYour Name 			htt_rx_desc_frame_free(htt_pdev, msdu);
901*5113495bSYour Name 			ol_txrx_err("TKIP demic failed");
902*5113495bSYour Name 			return;
903*5113495bSYour Name 		}
904*5113495bSYour Name 	}
905*5113495bSYour Name 	wh = (struct ieee80211_frame *)ol_rx_frag_get_mac_hdr(htt_pdev, msdu);
906*5113495bSYour Name 	if (DEFRAG_IEEE80211_QOS_HAS_SEQ(wh))
907*5113495bSYour Name 		ol_rx_defrag_qos_decap(pdev, msdu, hdr_space);
908*5113495bSYour Name 	if (ol_cfg_frame_type(pdev->ctrl_pdev) == wlan_frm_fmt_802_3)
909*5113495bSYour Name 		ol_rx_defrag_nwifi_to_8023(pdev, msdu);
910*5113495bSYour Name 
911*5113495bSYour Name 	/* Packet Capture Mode */
912*5113495bSYour Name 
913*5113495bSYour Name 	if ((ucfg_pkt_capture_get_pktcap_mode((void *)soc->psoc) &
914*5113495bSYour Name 	      PKT_CAPTURE_MODE_DATA_ONLY)) {
915*5113495bSYour Name 		if (peer) {
916*5113495bSYour Name 			if (peer->vdev) {
917*5113495bSYour Name 				qdf_spin_lock_bh(&pdev->peer_ref_mutex);
918*5113495bSYour Name 				peer_head = TAILQ_FIRST(&vdev->peer_list);
919*5113495bSYour Name 				qdf_spin_unlock_bh(&pdev->peer_ref_mutex);
920*5113495bSYour Name 				if (peer_head) {
921*5113495bSYour Name 					qdf_spin_lock_bh(
922*5113495bSYour Name 						&peer_head->peer_info_lock);
923*5113495bSYour Name 					qdf_mem_copy(bssid,
924*5113495bSYour Name 						     &peer_head->mac_addr.raw,
925*5113495bSYour Name 						     QDF_MAC_ADDR_SIZE);
926*5113495bSYour Name 					qdf_spin_unlock_bh(
927*5113495bSYour Name 						&peer_head->peer_info_lock);
928*5113495bSYour Name 
929*5113495bSYour Name 					ucfg_pkt_capture_rx_msdu_process(
930*5113495bSYour Name 								bssid, msdu,
931*5113495bSYour Name 								vdev->vdev_id,
932*5113495bSYour Name 								htt_pdev);
933*5113495bSYour Name 				}
934*5113495bSYour Name 			}
935*5113495bSYour Name 		}
936*5113495bSYour Name 	}
937*5113495bSYour Name 
938*5113495bSYour Name 	ol_rx_fwd_check(vdev, peer, tid, msdu);
939*5113495bSYour Name }
940*5113495bSYour Name 
941*5113495bSYour Name /*
942*5113495bSYour Name  * Handling TKIP processing for defragmentation
943*5113495bSYour Name  */
944*5113495bSYour Name int
ol_rx_frag_tkip_decap(ol_txrx_pdev_handle pdev,qdf_nbuf_t msdu,uint16_t hdrlen)945*5113495bSYour Name ol_rx_frag_tkip_decap(ol_txrx_pdev_handle pdev,
946*5113495bSYour Name 		      qdf_nbuf_t msdu, uint16_t hdrlen)
947*5113495bSYour Name {
948*5113495bSYour Name 	uint8_t *ivp, *origHdr;
949*5113495bSYour Name 
950*5113495bSYour Name 	void *rx_desc_old_position = NULL;
951*5113495bSYour Name 	void *ind_old_position = NULL;
952*5113495bSYour Name 	int rx_desc_len = 0;
953*5113495bSYour Name 
954*5113495bSYour Name 	ol_rx_frag_desc_adjust(pdev,
955*5113495bSYour Name 			       msdu,
956*5113495bSYour Name 			       &rx_desc_old_position,
957*5113495bSYour Name 			       &ind_old_position, &rx_desc_len);
958*5113495bSYour Name 	/* Header should have extended IV */
959*5113495bSYour Name 	origHdr = (uint8_t *) (qdf_nbuf_data(msdu) + rx_desc_len);
960*5113495bSYour Name 
961*5113495bSYour Name 	ivp = origHdr + hdrlen;
962*5113495bSYour Name 	if (!(ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV))
963*5113495bSYour Name 		return OL_RX_DEFRAG_ERR;
964*5113495bSYour Name 
965*5113495bSYour Name 	qdf_mem_move(origHdr + f_tkip.ic_header, origHdr, hdrlen);
966*5113495bSYour Name 	ol_rx_frag_restructure(
967*5113495bSYour Name 			pdev,
968*5113495bSYour Name 			msdu,
969*5113495bSYour Name 			rx_desc_old_position,
970*5113495bSYour Name 			ind_old_position,
971*5113495bSYour Name 			&f_tkip,
972*5113495bSYour Name 			rx_desc_len);
973*5113495bSYour Name 	qdf_nbuf_pull_head(msdu, f_tkip.ic_header);
974*5113495bSYour Name 	qdf_nbuf_trim_tail(msdu, f_tkip.ic_trailer);
975*5113495bSYour Name 	return OL_RX_DEFRAG_OK;
976*5113495bSYour Name }
977*5113495bSYour Name 
978*5113495bSYour Name /*
979*5113495bSYour Name  * Handling WEP processing for defragmentation
980*5113495bSYour Name  */
981*5113495bSYour Name int
ol_rx_frag_wep_decap(ol_txrx_pdev_handle pdev,qdf_nbuf_t msdu,uint16_t hdrlen)982*5113495bSYour Name ol_rx_frag_wep_decap(ol_txrx_pdev_handle pdev, qdf_nbuf_t msdu, uint16_t hdrlen)
983*5113495bSYour Name {
984*5113495bSYour Name 	uint8_t *origHdr;
985*5113495bSYour Name 	void *rx_desc_old_position = NULL;
986*5113495bSYour Name 	void *ind_old_position = NULL;
987*5113495bSYour Name 	int rx_desc_len = 0;
988*5113495bSYour Name 
989*5113495bSYour Name 	ol_rx_frag_desc_adjust(pdev,
990*5113495bSYour Name 			       msdu,
991*5113495bSYour Name 			       &rx_desc_old_position,
992*5113495bSYour Name 			       &ind_old_position, &rx_desc_len);
993*5113495bSYour Name 	origHdr = (uint8_t *) (qdf_nbuf_data(msdu) + rx_desc_len);
994*5113495bSYour Name 	qdf_mem_move(origHdr + f_wep.ic_header, origHdr, hdrlen);
995*5113495bSYour Name 	ol_rx_frag_restructure(
996*5113495bSYour Name 			pdev,
997*5113495bSYour Name 			msdu,
998*5113495bSYour Name 			rx_desc_old_position,
999*5113495bSYour Name 			ind_old_position,
1000*5113495bSYour Name 			&f_wep,
1001*5113495bSYour Name 			rx_desc_len);
1002*5113495bSYour Name 	qdf_nbuf_pull_head(msdu, f_wep.ic_header);
1003*5113495bSYour Name 	qdf_nbuf_trim_tail(msdu, f_wep.ic_trailer);
1004*5113495bSYour Name 	return OL_RX_DEFRAG_OK;
1005*5113495bSYour Name }
1006*5113495bSYour Name 
1007*5113495bSYour Name /*
1008*5113495bSYour Name  * Verify and strip MIC from the frame.
1009*5113495bSYour Name  */
1010*5113495bSYour Name int
ol_rx_frag_tkip_demic(ol_txrx_pdev_handle pdev,const uint8_t * key,qdf_nbuf_t msdu,uint16_t hdrlen)1011*5113495bSYour Name ol_rx_frag_tkip_demic(ol_txrx_pdev_handle pdev, const uint8_t *key,
1012*5113495bSYour Name 		      qdf_nbuf_t msdu, uint16_t hdrlen)
1013*5113495bSYour Name {
1014*5113495bSYour Name 	int status;
1015*5113495bSYour Name 	uint32_t pktlen;
1016*5113495bSYour Name 	uint8_t mic[IEEE80211_WEP_MICLEN];
1017*5113495bSYour Name 	uint8_t mic0[IEEE80211_WEP_MICLEN];
1018*5113495bSYour Name 	void *rx_desc_old_position = NULL;
1019*5113495bSYour Name 	void *ind_old_position = NULL;
1020*5113495bSYour Name 	int rx_desc_len = 0;
1021*5113495bSYour Name 
1022*5113495bSYour Name 	ol_rx_frag_desc_adjust(pdev,
1023*5113495bSYour Name 			       msdu,
1024*5113495bSYour Name 			       &rx_desc_old_position,
1025*5113495bSYour Name 			       &ind_old_position, &rx_desc_len);
1026*5113495bSYour Name 
1027*5113495bSYour Name 	pktlen = ol_rx_defrag_len(msdu) - rx_desc_len;
1028*5113495bSYour Name 
1029*5113495bSYour Name 	status = ol_rx_defrag_mic(pdev, key, msdu, hdrlen,
1030*5113495bSYour Name 				  pktlen - (hdrlen + f_tkip.ic_miclen), mic);
1031*5113495bSYour Name 	if (status != OL_RX_DEFRAG_OK)
1032*5113495bSYour Name 		return OL_RX_DEFRAG_ERR;
1033*5113495bSYour Name 
1034*5113495bSYour Name 	ol_rx_defrag_copydata(msdu, pktlen - f_tkip.ic_miclen + rx_desc_len,
1035*5113495bSYour Name 			      f_tkip.ic_miclen, (caddr_t) mic0);
1036*5113495bSYour Name 	if (qdf_mem_cmp(mic, mic0, f_tkip.ic_miclen))
1037*5113495bSYour Name 		return OL_RX_DEFRAG_ERR;
1038*5113495bSYour Name 
1039*5113495bSYour Name 	qdf_nbuf_trim_tail(msdu, f_tkip.ic_miclen);
1040*5113495bSYour Name 	return OL_RX_DEFRAG_OK;
1041*5113495bSYour Name }
1042*5113495bSYour Name 
1043*5113495bSYour Name /*
1044*5113495bSYour Name  * Handling CCMP processing for defragmentation
1045*5113495bSYour Name  */
1046*5113495bSYour Name int
ol_rx_frag_ccmp_decap(ol_txrx_pdev_handle pdev,qdf_nbuf_t nbuf,uint16_t hdrlen)1047*5113495bSYour Name ol_rx_frag_ccmp_decap(ol_txrx_pdev_handle pdev,
1048*5113495bSYour Name 		      qdf_nbuf_t nbuf, uint16_t hdrlen)
1049*5113495bSYour Name {
1050*5113495bSYour Name 	uint8_t *ivp, *origHdr;
1051*5113495bSYour Name 	void *rx_desc_old_position = NULL;
1052*5113495bSYour Name 	void *ind_old_position = NULL;
1053*5113495bSYour Name 	int rx_desc_len = 0;
1054*5113495bSYour Name 
1055*5113495bSYour Name 	ol_rx_frag_desc_adjust(pdev,
1056*5113495bSYour Name 			       nbuf,
1057*5113495bSYour Name 			       &rx_desc_old_position,
1058*5113495bSYour Name 			       &ind_old_position, &rx_desc_len);
1059*5113495bSYour Name 
1060*5113495bSYour Name 	origHdr = (uint8_t *) (qdf_nbuf_data(nbuf) + rx_desc_len);
1061*5113495bSYour Name 	ivp = origHdr + hdrlen;
1062*5113495bSYour Name 	if (!(ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV))
1063*5113495bSYour Name 		return OL_RX_DEFRAG_ERR;
1064*5113495bSYour Name 
1065*5113495bSYour Name 	qdf_mem_move(origHdr + f_ccmp.ic_header, origHdr, hdrlen);
1066*5113495bSYour Name 	ol_rx_frag_restructure(
1067*5113495bSYour Name 			pdev,
1068*5113495bSYour Name 			nbuf,
1069*5113495bSYour Name 			rx_desc_old_position,
1070*5113495bSYour Name 			ind_old_position,
1071*5113495bSYour Name 			&f_ccmp,
1072*5113495bSYour Name 			rx_desc_len);
1073*5113495bSYour Name 	qdf_nbuf_pull_head(nbuf, f_ccmp.ic_header);
1074*5113495bSYour Name 
1075*5113495bSYour Name 	return OL_RX_DEFRAG_OK;
1076*5113495bSYour Name }
1077*5113495bSYour Name 
1078*5113495bSYour Name /*
1079*5113495bSYour Name  * Verify and strip MIC from the frame.
1080*5113495bSYour Name  */
1081*5113495bSYour Name int
ol_rx_frag_ccmp_demic(ol_txrx_pdev_handle pdev,qdf_nbuf_t wbuf,uint16_t hdrlen)1082*5113495bSYour Name ol_rx_frag_ccmp_demic(ol_txrx_pdev_handle pdev,
1083*5113495bSYour Name 		      qdf_nbuf_t wbuf, uint16_t hdrlen)
1084*5113495bSYour Name {
1085*5113495bSYour Name 	uint8_t *ivp, *origHdr;
1086*5113495bSYour Name 	void *rx_desc_old_position = NULL;
1087*5113495bSYour Name 	void *ind_old_position = NULL;
1088*5113495bSYour Name 	int rx_desc_len = 0;
1089*5113495bSYour Name 
1090*5113495bSYour Name 	ol_rx_frag_desc_adjust(pdev,
1091*5113495bSYour Name 			       wbuf,
1092*5113495bSYour Name 			       &rx_desc_old_position,
1093*5113495bSYour Name 			       &ind_old_position, &rx_desc_len);
1094*5113495bSYour Name 
1095*5113495bSYour Name 	origHdr = (uint8_t *) (qdf_nbuf_data(wbuf) + rx_desc_len);
1096*5113495bSYour Name 
1097*5113495bSYour Name 	ivp = origHdr + hdrlen;
1098*5113495bSYour Name 	if (!(ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV))
1099*5113495bSYour Name 		return OL_RX_DEFRAG_ERR;
1100*5113495bSYour Name 
1101*5113495bSYour Name 	qdf_nbuf_trim_tail(wbuf, f_ccmp.ic_trailer);
1102*5113495bSYour Name 
1103*5113495bSYour Name 	return OL_RX_DEFRAG_OK;
1104*5113495bSYour Name }
1105*5113495bSYour Name 
1106*5113495bSYour Name /*
1107*5113495bSYour Name  * Craft pseudo header used to calculate the MIC.
1108*5113495bSYour Name  */
ol_rx_defrag_michdr(const struct ieee80211_frame * wh0,uint8_t hdr[])1109*5113495bSYour Name void ol_rx_defrag_michdr(const struct ieee80211_frame *wh0, uint8_t hdr[])
1110*5113495bSYour Name {
1111*5113495bSYour Name 	const struct ieee80211_frame_addr4 *wh =
1112*5113495bSYour Name 		(const struct ieee80211_frame_addr4 *)wh0;
1113*5113495bSYour Name 
1114*5113495bSYour Name 	switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
1115*5113495bSYour Name 	case IEEE80211_FC1_DIR_NODS:
1116*5113495bSYour Name 		DEFRAG_IEEE80211_ADDR_COPY(hdr, wh->i_addr1);   /* DA */
1117*5113495bSYour Name 		DEFRAG_IEEE80211_ADDR_COPY(hdr + QDF_MAC_ADDR_SIZE,
1118*5113495bSYour Name 					   wh->i_addr2);
1119*5113495bSYour Name 		break;
1120*5113495bSYour Name 	case IEEE80211_FC1_DIR_TODS:
1121*5113495bSYour Name 		DEFRAG_IEEE80211_ADDR_COPY(hdr, wh->i_addr3);   /* DA */
1122*5113495bSYour Name 		DEFRAG_IEEE80211_ADDR_COPY(hdr + QDF_MAC_ADDR_SIZE,
1123*5113495bSYour Name 					   wh->i_addr2);
1124*5113495bSYour Name 		break;
1125*5113495bSYour Name 	case IEEE80211_FC1_DIR_FROMDS:
1126*5113495bSYour Name 		DEFRAG_IEEE80211_ADDR_COPY(hdr, wh->i_addr1);   /* DA */
1127*5113495bSYour Name 		DEFRAG_IEEE80211_ADDR_COPY(hdr + QDF_MAC_ADDR_SIZE,
1128*5113495bSYour Name 					   wh->i_addr3);
1129*5113495bSYour Name 		break;
1130*5113495bSYour Name 	case IEEE80211_FC1_DIR_DSTODS:
1131*5113495bSYour Name 		DEFRAG_IEEE80211_ADDR_COPY(hdr, wh->i_addr3);   /* DA */
1132*5113495bSYour Name 		DEFRAG_IEEE80211_ADDR_COPY(hdr + QDF_MAC_ADDR_SIZE,
1133*5113495bSYour Name 					   wh->i_addr4);
1134*5113495bSYour Name 		break;
1135*5113495bSYour Name 	}
1136*5113495bSYour Name 	/*
1137*5113495bSYour Name 	 * Bit 7 is QDF_IEEE80211_FC0_SUBTYPE_QOS for data frame, but
1138*5113495bSYour Name 	 * it could also be set for deauth, disassoc, action, etc. for
1139*5113495bSYour Name 	 * a mgt type frame. It comes into picture for MFP.
1140*5113495bSYour Name 	 */
1141*5113495bSYour Name 	if (wh->i_fc[0] & QDF_IEEE80211_FC0_SUBTYPE_QOS) {
1142*5113495bSYour Name 		const struct ieee80211_qosframe *qwh =
1143*5113495bSYour Name 			(const struct ieee80211_qosframe *)wh;
1144*5113495bSYour Name 		hdr[12] = qwh->i_qos[0] & IEEE80211_QOS_TID;
1145*5113495bSYour Name 	} else {
1146*5113495bSYour Name 		hdr[12] = 0;
1147*5113495bSYour Name 	}
1148*5113495bSYour Name 	hdr[13] = hdr[14] = hdr[15] = 0;        /* reserved */
1149*5113495bSYour Name }
1150*5113495bSYour Name 
1151*5113495bSYour Name /*
1152*5113495bSYour Name  * Michael_mic for defragmentation
1153*5113495bSYour Name  */
1154*5113495bSYour Name int
ol_rx_defrag_mic(ol_txrx_pdev_handle pdev,const uint8_t * key,qdf_nbuf_t wbuf,uint16_t off,uint16_t data_len,uint8_t mic[])1155*5113495bSYour Name ol_rx_defrag_mic(ol_txrx_pdev_handle pdev,
1156*5113495bSYour Name 		 const uint8_t *key,
1157*5113495bSYour Name 		 qdf_nbuf_t wbuf,
1158*5113495bSYour Name 		 uint16_t off, uint16_t data_len, uint8_t mic[])
1159*5113495bSYour Name {
1160*5113495bSYour Name 	uint8_t hdr[16] = { 0, };
1161*5113495bSYour Name 	uint32_t l, r;
1162*5113495bSYour Name 	const uint8_t *data;
1163*5113495bSYour Name 	uint32_t space;
1164*5113495bSYour Name 	void *rx_desc_old_position = NULL;
1165*5113495bSYour Name 	void *ind_old_position = NULL;
1166*5113495bSYour Name 	int rx_desc_len = 0;
1167*5113495bSYour Name 	htt_pdev_handle htt_pdev = pdev->htt_pdev;
1168*5113495bSYour Name 
1169*5113495bSYour Name 	ol_rx_frag_desc_adjust(pdev,
1170*5113495bSYour Name 			       wbuf,
1171*5113495bSYour Name 			       &rx_desc_old_position,
1172*5113495bSYour Name 			       &ind_old_position, &rx_desc_len);
1173*5113495bSYour Name 
1174*5113495bSYour Name 	ol_rx_defrag_michdr((struct ieee80211_frame *)(qdf_nbuf_data(wbuf) +
1175*5113495bSYour Name 						       rx_desc_len), hdr);
1176*5113495bSYour Name 	l = get_le32(key);
1177*5113495bSYour Name 	r = get_le32(key + 4);
1178*5113495bSYour Name 
1179*5113495bSYour Name 	/* Michael MIC pseudo header: DA, SA, 3 x 0, Priority */
1180*5113495bSYour Name 	l ^= get_le32(hdr);
1181*5113495bSYour Name 	michael_block(l, r);
1182*5113495bSYour Name 	l ^= get_le32(&hdr[4]);
1183*5113495bSYour Name 	michael_block(l, r);
1184*5113495bSYour Name 	l ^= get_le32(&hdr[8]);
1185*5113495bSYour Name 	michael_block(l, r);
1186*5113495bSYour Name 	l ^= get_le32(&hdr[12]);
1187*5113495bSYour Name 	michael_block(l, r);
1188*5113495bSYour Name 
1189*5113495bSYour Name 	/* first buffer has special handling */
1190*5113495bSYour Name 	data = (uint8_t *) qdf_nbuf_data(wbuf) + rx_desc_len + off;
1191*5113495bSYour Name 	space = ol_rx_defrag_len(wbuf) - rx_desc_len - off;
1192*5113495bSYour Name 	for (;; ) {
1193*5113495bSYour Name 		if (space > data_len)
1194*5113495bSYour Name 			space = data_len;
1195*5113495bSYour Name 
1196*5113495bSYour Name 		/* collect 32-bit blocks from current buffer */
1197*5113495bSYour Name 		while (space >= sizeof(uint32_t)) {
1198*5113495bSYour Name 			l ^= get_le32(data);
1199*5113495bSYour Name 			michael_block(l, r);
1200*5113495bSYour Name 			data += sizeof(uint32_t);
1201*5113495bSYour Name 			space -= sizeof(uint32_t);
1202*5113495bSYour Name 			data_len -= sizeof(uint32_t);
1203*5113495bSYour Name 		}
1204*5113495bSYour Name 		if (data_len < sizeof(uint32_t))
1205*5113495bSYour Name 			break;
1206*5113495bSYour Name 
1207*5113495bSYour Name 		wbuf = qdf_nbuf_next(wbuf);
1208*5113495bSYour Name 		if (!wbuf)
1209*5113495bSYour Name 			return OL_RX_DEFRAG_ERR;
1210*5113495bSYour Name 
1211*5113495bSYour Name 		rx_desc_len = ol_rx_get_desc_len(htt_pdev, wbuf,
1212*5113495bSYour Name 						 &rx_desc_old_position);
1213*5113495bSYour Name 
1214*5113495bSYour Name 		if (space != 0) {
1215*5113495bSYour Name 			const uint8_t *data_next;
1216*5113495bSYour Name 			/*
1217*5113495bSYour Name 			 * Block straddles buffers, split references.
1218*5113495bSYour Name 			 */
1219*5113495bSYour Name 			data_next =
1220*5113495bSYour Name 				(uint8_t *) qdf_nbuf_data(wbuf) + rx_desc_len;
1221*5113495bSYour Name 			if ((ol_rx_defrag_len(wbuf) - rx_desc_len) <
1222*5113495bSYour Name 			    sizeof(uint32_t) - space) {
1223*5113495bSYour Name 				return OL_RX_DEFRAG_ERR;
1224*5113495bSYour Name 			}
1225*5113495bSYour Name 			switch (space) {
1226*5113495bSYour Name 			case 1:
1227*5113495bSYour Name 				l ^= get_le32_split(data[0], data_next[0],
1228*5113495bSYour Name 						    data_next[1], data_next[2]);
1229*5113495bSYour Name 				data = data_next + 3;
1230*5113495bSYour Name 				space = (ol_rx_defrag_len(wbuf) - rx_desc_len)
1231*5113495bSYour Name 					- 3;
1232*5113495bSYour Name 				break;
1233*5113495bSYour Name 			case 2:
1234*5113495bSYour Name 				l ^= get_le32_split(data[0], data[1],
1235*5113495bSYour Name 						    data_next[0], data_next[1]);
1236*5113495bSYour Name 				data = data_next + 2;
1237*5113495bSYour Name 				space = (ol_rx_defrag_len(wbuf) - rx_desc_len)
1238*5113495bSYour Name 					- 2;
1239*5113495bSYour Name 				break;
1240*5113495bSYour Name 			case 3:
1241*5113495bSYour Name 				l ^= get_le32_split(data[0], data[1], data[2],
1242*5113495bSYour Name 						    data_next[0]);
1243*5113495bSYour Name 				data = data_next + 1;
1244*5113495bSYour Name 				space = (ol_rx_defrag_len(wbuf) - rx_desc_len)
1245*5113495bSYour Name 					- 1;
1246*5113495bSYour Name 				break;
1247*5113495bSYour Name 			}
1248*5113495bSYour Name 			michael_block(l, r);
1249*5113495bSYour Name 			data_len -= sizeof(uint32_t);
1250*5113495bSYour Name 		} else {
1251*5113495bSYour Name 			/*
1252*5113495bSYour Name 			 * Setup for next buffer.
1253*5113495bSYour Name 			 */
1254*5113495bSYour Name 			data = (uint8_t *) qdf_nbuf_data(wbuf) + rx_desc_len;
1255*5113495bSYour Name 			space = ol_rx_defrag_len(wbuf) - rx_desc_len;
1256*5113495bSYour Name 		}
1257*5113495bSYour Name 	}
1258*5113495bSYour Name 	/* Last block and padding (0x5a, 4..7 x 0) */
1259*5113495bSYour Name 	switch (data_len) {
1260*5113495bSYour Name 	case 0:
1261*5113495bSYour Name 		l ^= get_le32_split(0x5a, 0, 0, 0);
1262*5113495bSYour Name 		break;
1263*5113495bSYour Name 	case 1:
1264*5113495bSYour Name 		l ^= get_le32_split(data[0], 0x5a, 0, 0);
1265*5113495bSYour Name 		break;
1266*5113495bSYour Name 	case 2:
1267*5113495bSYour Name 		l ^= get_le32_split(data[0], data[1], 0x5a, 0);
1268*5113495bSYour Name 		break;
1269*5113495bSYour Name 	case 3:
1270*5113495bSYour Name 		l ^= get_le32_split(data[0], data[1], data[2], 0x5a);
1271*5113495bSYour Name 		break;
1272*5113495bSYour Name 	}
1273*5113495bSYour Name 	michael_block(l, r);
1274*5113495bSYour Name 	michael_block(l, r);
1275*5113495bSYour Name 	put_le32(mic, l);
1276*5113495bSYour Name 	put_le32(mic + 4, r);
1277*5113495bSYour Name 
1278*5113495bSYour Name 	return OL_RX_DEFRAG_OK;
1279*5113495bSYour Name }
1280*5113495bSYour Name 
1281*5113495bSYour Name /*
1282*5113495bSYour Name  * Calculate headersize
1283*5113495bSYour Name  */
ol_rx_frag_hdrsize(const void * data)1284*5113495bSYour Name uint16_t ol_rx_frag_hdrsize(const void *data)
1285*5113495bSYour Name {
1286*5113495bSYour Name 	const struct ieee80211_frame *wh = (const struct ieee80211_frame *)data;
1287*5113495bSYour Name 	uint16_t size = sizeof(struct ieee80211_frame);
1288*5113495bSYour Name 
1289*5113495bSYour Name 	if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS)
1290*5113495bSYour Name 		size += QDF_MAC_ADDR_SIZE;
1291*5113495bSYour Name 
1292*5113495bSYour Name 	if (DEFRAG_IEEE80211_QOS_HAS_SEQ(wh)) {
1293*5113495bSYour Name 		size += sizeof(uint16_t);
1294*5113495bSYour Name 		if (wh->i_fc[1] & IEEE80211_FC1_ORDER)
1295*5113495bSYour Name 			size += sizeof(struct ieee80211_htc);
1296*5113495bSYour Name 	}
1297*5113495bSYour Name 	return size;
1298*5113495bSYour Name }
1299*5113495bSYour Name 
1300*5113495bSYour Name /*
1301*5113495bSYour Name  * Recombine and decap fragments
1302*5113495bSYour Name  */
1303*5113495bSYour Name qdf_nbuf_t
ol_rx_defrag_decap_recombine(htt_pdev_handle htt_pdev,qdf_nbuf_t frag_list,uint16_t hdrsize)1304*5113495bSYour Name ol_rx_defrag_decap_recombine(htt_pdev_handle htt_pdev,
1305*5113495bSYour Name 			     qdf_nbuf_t frag_list, uint16_t hdrsize)
1306*5113495bSYour Name {
1307*5113495bSYour Name 	qdf_nbuf_t tmp;
1308*5113495bSYour Name 	qdf_nbuf_t msdu = frag_list;
1309*5113495bSYour Name 	qdf_nbuf_t rx_nbuf = frag_list;
1310*5113495bSYour Name 	struct ieee80211_frame *wh;
1311*5113495bSYour Name 
1312*5113495bSYour Name 	msdu = qdf_nbuf_next(msdu);
1313*5113495bSYour Name 	qdf_nbuf_set_next(rx_nbuf, NULL);
1314*5113495bSYour Name 	while (msdu) {
1315*5113495bSYour Name 		htt_rx_msdu_desc_free(htt_pdev, msdu);
1316*5113495bSYour Name 		tmp = qdf_nbuf_next(msdu);
1317*5113495bSYour Name 		qdf_nbuf_set_next(msdu, NULL);
1318*5113495bSYour Name 		ol_rx_frag_pull_hdr(htt_pdev, msdu, hdrsize);
1319*5113495bSYour Name 		if (!ol_rx_defrag_concat(rx_nbuf, msdu)) {
1320*5113495bSYour Name 			ol_rx_frames_free(htt_pdev, tmp);
1321*5113495bSYour Name 			htt_rx_desc_frame_free(htt_pdev, rx_nbuf);
1322*5113495bSYour Name 			qdf_nbuf_free(msdu);
1323*5113495bSYour Name 			/* msdu rx desc already freed above */
1324*5113495bSYour Name 			return NULL;
1325*5113495bSYour Name 		}
1326*5113495bSYour Name 		msdu = tmp;
1327*5113495bSYour Name 	}
1328*5113495bSYour Name 	wh = (struct ieee80211_frame *)ol_rx_frag_get_mac_hdr(htt_pdev,
1329*5113495bSYour Name 							      rx_nbuf);
1330*5113495bSYour Name 	wh->i_fc[1] &= ~IEEE80211_FC1_MORE_FRAG;
1331*5113495bSYour Name 	*(uint16_t *) wh->i_seq &= ~IEEE80211_SEQ_FRAG_MASK;
1332*5113495bSYour Name 
1333*5113495bSYour Name 	return rx_nbuf;
1334*5113495bSYour Name }
1335*5113495bSYour Name 
ol_rx_defrag_nwifi_to_8023(ol_txrx_pdev_handle pdev,qdf_nbuf_t msdu)1336*5113495bSYour Name void ol_rx_defrag_nwifi_to_8023(ol_txrx_pdev_handle pdev, qdf_nbuf_t msdu)
1337*5113495bSYour Name {
1338*5113495bSYour Name 	struct ieee80211_frame wh;
1339*5113495bSYour Name 	uint32_t hdrsize;
1340*5113495bSYour Name 	struct llc_snap_hdr_t llchdr;
1341*5113495bSYour Name 	struct ethernet_hdr_t *eth_hdr;
1342*5113495bSYour Name 	void *rx_desc_old_position = NULL;
1343*5113495bSYour Name 	void *ind_old_position = NULL;
1344*5113495bSYour Name 	int rx_desc_len = 0;
1345*5113495bSYour Name 	struct ieee80211_frame *wh_ptr;
1346*5113495bSYour Name 
1347*5113495bSYour Name 	ol_rx_frag_desc_adjust(pdev,
1348*5113495bSYour Name 			       msdu,
1349*5113495bSYour Name 			       &rx_desc_old_position,
1350*5113495bSYour Name 			       &ind_old_position, &rx_desc_len);
1351*5113495bSYour Name 
1352*5113495bSYour Name 	wh_ptr = (struct ieee80211_frame *)(qdf_nbuf_data(msdu) + rx_desc_len);
1353*5113495bSYour Name 	qdf_mem_copy(&wh, wh_ptr, sizeof(wh));
1354*5113495bSYour Name 	hdrsize = sizeof(struct ieee80211_frame);
1355*5113495bSYour Name 	qdf_mem_copy(&llchdr, ((uint8_t *) (qdf_nbuf_data(msdu) +
1356*5113495bSYour Name 					    rx_desc_len)) + hdrsize,
1357*5113495bSYour Name 		     sizeof(struct llc_snap_hdr_t));
1358*5113495bSYour Name 
1359*5113495bSYour Name 	/*
1360*5113495bSYour Name 	 * Now move the data pointer to the beginning of the mac header :
1361*5113495bSYour Name 	 * new-header = old-hdr + (wifhdrsize + llchdrsize - ethhdrsize)
1362*5113495bSYour Name 	 */
1363*5113495bSYour Name 	qdf_nbuf_pull_head(msdu, (rx_desc_len + hdrsize +
1364*5113495bSYour Name 				  sizeof(struct llc_snap_hdr_t) -
1365*5113495bSYour Name 				  sizeof(struct ethernet_hdr_t)));
1366*5113495bSYour Name 	eth_hdr = (struct ethernet_hdr_t *)(qdf_nbuf_data(msdu));
1367*5113495bSYour Name 	switch (wh.i_fc[1] & IEEE80211_FC1_DIR_MASK) {
1368*5113495bSYour Name 	case IEEE80211_FC1_DIR_NODS:
1369*5113495bSYour Name 		qdf_mem_copy(eth_hdr->dest_addr, wh.i_addr1,
1370*5113495bSYour Name 			     QDF_MAC_ADDR_SIZE);
1371*5113495bSYour Name 		qdf_mem_copy(eth_hdr->src_addr, wh.i_addr2, QDF_MAC_ADDR_SIZE);
1372*5113495bSYour Name 		break;
1373*5113495bSYour Name 	case IEEE80211_FC1_DIR_TODS:
1374*5113495bSYour Name 		qdf_mem_copy(eth_hdr->dest_addr, wh.i_addr3,
1375*5113495bSYour Name 			     QDF_MAC_ADDR_SIZE);
1376*5113495bSYour Name 		qdf_mem_copy(eth_hdr->src_addr, wh.i_addr2, QDF_MAC_ADDR_SIZE);
1377*5113495bSYour Name 		break;
1378*5113495bSYour Name 	case IEEE80211_FC1_DIR_FROMDS:
1379*5113495bSYour Name 		qdf_mem_copy(eth_hdr->dest_addr, wh.i_addr1,
1380*5113495bSYour Name 			     QDF_MAC_ADDR_SIZE);
1381*5113495bSYour Name 		qdf_mem_copy(eth_hdr->src_addr, wh.i_addr3, QDF_MAC_ADDR_SIZE);
1382*5113495bSYour Name 		break;
1383*5113495bSYour Name 	case IEEE80211_FC1_DIR_DSTODS:
1384*5113495bSYour Name 		break;
1385*5113495bSYour Name 	}
1386*5113495bSYour Name 
1387*5113495bSYour Name 	qdf_mem_copy(eth_hdr->ethertype, llchdr.ethertype,
1388*5113495bSYour Name 		     sizeof(llchdr.ethertype));
1389*5113495bSYour Name 
1390*5113495bSYour Name 	ol_rx_defrag_push_rx_desc(msdu, rx_desc_old_position,
1391*5113495bSYour Name 					  ind_old_position, rx_desc_len);
1392*5113495bSYour Name }
1393*5113495bSYour Name 
1394*5113495bSYour Name /*
1395*5113495bSYour Name  * Handling QOS for defragmentation
1396*5113495bSYour Name  */
1397*5113495bSYour Name void
ol_rx_defrag_qos_decap(ol_txrx_pdev_handle pdev,qdf_nbuf_t nbuf,uint16_t hdrlen)1398*5113495bSYour Name ol_rx_defrag_qos_decap(ol_txrx_pdev_handle pdev,
1399*5113495bSYour Name 		       qdf_nbuf_t nbuf, uint16_t hdrlen)
1400*5113495bSYour Name {
1401*5113495bSYour Name 	struct ieee80211_frame *wh;
1402*5113495bSYour Name 	uint16_t qoslen;
1403*5113495bSYour Name 	void *rx_desc_old_position = NULL;
1404*5113495bSYour Name 	void *ind_old_position = NULL;
1405*5113495bSYour Name 	int rx_desc_len = 0;
1406*5113495bSYour Name 
1407*5113495bSYour Name 	ol_rx_frag_desc_adjust(pdev,
1408*5113495bSYour Name 			       nbuf,
1409*5113495bSYour Name 			       &rx_desc_old_position,
1410*5113495bSYour Name 			       &ind_old_position, &rx_desc_len);
1411*5113495bSYour Name 
1412*5113495bSYour Name 	wh = (struct ieee80211_frame *)(qdf_nbuf_data(nbuf) + rx_desc_len);
1413*5113495bSYour Name 	if (DEFRAG_IEEE80211_QOS_HAS_SEQ(wh)) {
1414*5113495bSYour Name 		qoslen = sizeof(struct ieee80211_qoscntl);
1415*5113495bSYour Name 		/* Qos frame with Order bit set indicates a HTC frame */
1416*5113495bSYour Name 		if (wh->i_fc[1] & IEEE80211_FC1_ORDER)
1417*5113495bSYour Name 			qoslen += sizeof(struct ieee80211_htc);
1418*5113495bSYour Name 
1419*5113495bSYour Name 		/* remove QoS filed from header */
1420*5113495bSYour Name 		hdrlen -= qoslen;
1421*5113495bSYour Name 		qdf_mem_move((uint8_t *) wh + qoslen, wh, hdrlen);
1422*5113495bSYour Name 		wh = (struct ieee80211_frame *)qdf_nbuf_pull_head(nbuf,
1423*5113495bSYour Name 								  rx_desc_len +
1424*5113495bSYour Name 								  qoslen);
1425*5113495bSYour Name 		/* clear QoS bit */
1426*5113495bSYour Name 		/*
1427*5113495bSYour Name 		 * KW# 6154 'qdf_nbuf_pull_head' in turn calls
1428*5113495bSYour Name 		 * __qdf_nbuf_pull_head,
1429*5113495bSYour Name 		 * which returns NULL if there is not sufficient data to pull.
1430*5113495bSYour Name 		 * It's guaranteed that qdf_nbuf_pull_head will succeed rather
1431*5113495bSYour Name 		 * than returning NULL, since the entire rx frame is already
1432*5113495bSYour Name 		 * present in the rx buffer.
1433*5113495bSYour Name 		 * However, to make it obvious to static analyzers that this
1434*5113495bSYour Name 		 * code is safe, add an explicit check that qdf_nbuf_pull_head
1435*5113495bSYour Name 		 * returns a non-NULL value.
1436*5113495bSYour Name 		 * Since this part of the code is not performance-critical,
1437*5113495bSYour Name 		 * adding this explicit check is okay.
1438*5113495bSYour Name 		 */
1439*5113495bSYour Name 		if (wh)
1440*5113495bSYour Name 			wh->i_fc[0] &= ~QDF_IEEE80211_FC0_SUBTYPE_QOS;
1441*5113495bSYour Name 
1442*5113495bSYour Name 		ol_rx_defrag_push_rx_desc(nbuf, rx_desc_old_position,
1443*5113495bSYour Name 					  ind_old_position, rx_desc_len);
1444*5113495bSYour Name 
1445*5113495bSYour Name 	}
1446*5113495bSYour Name }
1447