xref: /wlan-driver/qcacld-3.0/core/dp/txrx/ol_rx_pn.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2011, 2013-2017, 2019-2021 The Linux Foundation. All rights reserved.
3*5113495bSYour Name  *
4*5113495bSYour Name  * Permission to use, copy, modify, and/or distribute this software for
5*5113495bSYour Name  * any purpose with or without fee is hereby granted, provided that the
6*5113495bSYour Name  * above copyright notice and this permission notice appear in all
7*5113495bSYour Name  * copies.
8*5113495bSYour Name  *
9*5113495bSYour Name  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10*5113495bSYour Name  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11*5113495bSYour Name  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12*5113495bSYour Name  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13*5113495bSYour Name  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14*5113495bSYour Name  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15*5113495bSYour Name  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16*5113495bSYour Name  * PERFORMANCE OF THIS SOFTWARE.
17*5113495bSYour Name  */
18*5113495bSYour Name 
19*5113495bSYour Name #include <qdf_nbuf.h>           /* qdf_nbuf_t */
20*5113495bSYour Name 
21*5113495bSYour Name #include <ol_htt_rx_api.h>      /* htt_rx_pn_t, etc. */
22*5113495bSYour Name #include <ol_ctrl_txrx_api.h>   /* ol_rx_err */
23*5113495bSYour Name 
24*5113495bSYour Name #include <ol_txrx_internal.h>   /* ol_rx_mpdu_list_next */
25*5113495bSYour Name #include <ol_rx_pn.h>           /* our own defs */
26*5113495bSYour Name #include <ol_rx_fwd.h>          /* ol_rx_fwd_check */
27*5113495bSYour Name #include <ol_rx.h>              /* ol_rx_deliver */
28*5113495bSYour Name 
29*5113495bSYour Name /* add the MSDUs from this MPDU to the list of good frames */
30*5113495bSYour Name #define ADD_MPDU_TO_LIST(head, tail, mpdu, mpdu_tail) do {		\
31*5113495bSYour Name 		if (!head) {						\
32*5113495bSYour Name 			head = mpdu;					\
33*5113495bSYour Name 		} else {						\
34*5113495bSYour Name 			qdf_nbuf_set_next(tail, mpdu);			\
35*5113495bSYour Name 		}							\
36*5113495bSYour Name 		tail = mpdu_tail;					\
37*5113495bSYour Name 	} while (0)
38*5113495bSYour Name 
ol_rx_pn_cmp24(union htt_rx_pn_t * new_pn,union htt_rx_pn_t * old_pn,int is_unicast,int opmode,bool strict_chk)39*5113495bSYour Name int ol_rx_pn_cmp24(union htt_rx_pn_t *new_pn,
40*5113495bSYour Name 		   union htt_rx_pn_t *old_pn, int is_unicast, int opmode,
41*5113495bSYour Name 		   bool strict_chk)
42*5113495bSYour Name {
43*5113495bSYour Name 	if (strict_chk)
44*5113495bSYour Name 		return ((new_pn->pn24 & 0xffffff) - (old_pn->pn24 & 0xffffff)
45*5113495bSYour Name 			!= 1);
46*5113495bSYour Name 	else
47*5113495bSYour Name 		return ((new_pn->pn24 & 0xffffff) <= (old_pn->pn24 & 0xffffff));
48*5113495bSYour Name }
49*5113495bSYour Name 
ol_rx_pn_cmp48(union htt_rx_pn_t * new_pn,union htt_rx_pn_t * old_pn,int is_unicast,int opmode,bool strict_chk)50*5113495bSYour Name int ol_rx_pn_cmp48(union htt_rx_pn_t *new_pn,
51*5113495bSYour Name 		   union htt_rx_pn_t *old_pn, int is_unicast, int opmode,
52*5113495bSYour Name 		   bool strict_chk)
53*5113495bSYour Name {
54*5113495bSYour Name 	if (strict_chk)
55*5113495bSYour Name 		return ((new_pn->pn48 & 0xffffffffffffULL) -
56*5113495bSYour Name 			(old_pn->pn48 & 0xffffffffffffULL) != 1);
57*5113495bSYour Name 	else
58*5113495bSYour Name 		return ((new_pn->pn48 & 0xffffffffffffULL) <=
59*5113495bSYour Name 			(old_pn->pn48 & 0xffffffffffffULL));
60*5113495bSYour Name }
61*5113495bSYour Name 
ol_rx_pn_wapi_cmp(union htt_rx_pn_t * new_pn,union htt_rx_pn_t * old_pn,int is_unicast,int opmode,bool strict_chk)62*5113495bSYour Name int ol_rx_pn_wapi_cmp(union htt_rx_pn_t *new_pn,
63*5113495bSYour Name 		      union htt_rx_pn_t *old_pn, int is_unicast, int opmode,
64*5113495bSYour Name 		      bool strict_chk)
65*5113495bSYour Name {
66*5113495bSYour Name 	int pn_is_replay = 0;
67*5113495bSYour Name 
68*5113495bSYour Name 	/* TODO Strick check for WAPI is not implemented*/
69*5113495bSYour Name 
70*5113495bSYour Name 	if (new_pn->pn128[1] == old_pn->pn128[1])
71*5113495bSYour Name 		pn_is_replay = (new_pn->pn128[0] <= old_pn->pn128[0]);
72*5113495bSYour Name 	else
73*5113495bSYour Name 		pn_is_replay = (new_pn->pn128[1] < old_pn->pn128[1]);
74*5113495bSYour Name 
75*5113495bSYour Name 	if (is_unicast) {
76*5113495bSYour Name 		if (opmode == wlan_op_mode_ap)
77*5113495bSYour Name 			pn_is_replay |= ((new_pn->pn128[0] & 0x1ULL) != 0);
78*5113495bSYour Name 		else
79*5113495bSYour Name 			pn_is_replay |= ((new_pn->pn128[0] & 0x1ULL) != 1);
80*5113495bSYour Name 	}
81*5113495bSYour Name 	return pn_is_replay;
82*5113495bSYour Name }
83*5113495bSYour Name 
84*5113495bSYour Name qdf_nbuf_t
ol_rx_pn_check_base(struct ol_txrx_vdev_t * vdev,struct ol_txrx_peer_t * peer,unsigned int tid,qdf_nbuf_t msdu_list,bool strict_chk)85*5113495bSYour Name ol_rx_pn_check_base(struct ol_txrx_vdev_t *vdev,
86*5113495bSYour Name 		    struct ol_txrx_peer_t *peer,
87*5113495bSYour Name 		    unsigned int tid, qdf_nbuf_t msdu_list, bool strict_chk)
88*5113495bSYour Name {
89*5113495bSYour Name 	struct ol_txrx_pdev_t *pdev = vdev->pdev;
90*5113495bSYour Name 	union htt_rx_pn_t *last_pn;
91*5113495bSYour Name 	qdf_nbuf_t out_list_head = NULL;
92*5113495bSYour Name 	qdf_nbuf_t out_list_tail = NULL;
93*5113495bSYour Name 	qdf_nbuf_t mpdu;
94*5113495bSYour Name 	int index;              /* unicast vs. multicast */
95*5113495bSYour Name 	int pn_len;
96*5113495bSYour Name 	void *rx_desc;
97*5113495bSYour Name 	int last_pn_valid;
98*5113495bSYour Name 
99*5113495bSYour Name 	/* Make sure host pn check is not redundant */
100*5113495bSYour Name 	if ((qdf_atomic_read(&peer->fw_pn_check)) ||
101*5113495bSYour Name 		(vdev->opmode == wlan_op_mode_ibss)) {
102*5113495bSYour Name 		return msdu_list;
103*5113495bSYour Name 	}
104*5113495bSYour Name 
105*5113495bSYour Name 	/* First, check whether the PN check applies */
106*5113495bSYour Name 	rx_desc = htt_rx_msdu_desc_retrieve(pdev->htt_pdev, msdu_list);
107*5113495bSYour Name 	qdf_assert(htt_rx_msdu_has_wlan_mcast_flag(pdev->htt_pdev, rx_desc));
108*5113495bSYour Name 	index = htt_rx_msdu_is_wlan_mcast(pdev->htt_pdev, rx_desc) ?
109*5113495bSYour Name 		txrx_sec_mcast : txrx_sec_ucast;
110*5113495bSYour Name 	pn_len = pdev->rx_pn[peer->security[index].sec_type].len;
111*5113495bSYour Name 	if (pn_len == 0)
112*5113495bSYour Name 		return msdu_list;
113*5113495bSYour Name 
114*5113495bSYour Name 	last_pn_valid = peer->tids_last_pn_valid[tid];
115*5113495bSYour Name 	last_pn = &peer->tids_last_pn[tid];
116*5113495bSYour Name 	mpdu = msdu_list;
117*5113495bSYour Name 	while (mpdu) {
118*5113495bSYour Name 		qdf_nbuf_t mpdu_tail, next_mpdu;
119*5113495bSYour Name 		union htt_rx_pn_t new_pn;
120*5113495bSYour Name 		int pn_is_replay = 0;
121*5113495bSYour Name 
122*5113495bSYour Name 		rx_desc = htt_rx_msdu_desc_retrieve(pdev->htt_pdev, mpdu);
123*5113495bSYour Name 
124*5113495bSYour Name 		/*
125*5113495bSYour Name 		 * Find the last MSDU within this MPDU, and
126*5113495bSYour Name 		 * the find the first MSDU within the next MPDU.
127*5113495bSYour Name 		 */
128*5113495bSYour Name 		ol_rx_mpdu_list_next(pdev, mpdu, &mpdu_tail, &next_mpdu);
129*5113495bSYour Name 
130*5113495bSYour Name 		/* Don't check the PN replay for non-encrypted frames */
131*5113495bSYour Name 		if (!htt_rx_mpdu_is_encrypted(pdev->htt_pdev, rx_desc)) {
132*5113495bSYour Name 			ADD_MPDU_TO_LIST(out_list_head, out_list_tail,
133*5113495bSYour Name 					       mpdu, mpdu_tail);
134*5113495bSYour Name 			mpdu = next_mpdu;
135*5113495bSYour Name 			continue;
136*5113495bSYour Name 		}
137*5113495bSYour Name 
138*5113495bSYour Name 		/* retrieve PN from rx descriptor */
139*5113495bSYour Name 		htt_rx_mpdu_desc_pn(pdev->htt_pdev, rx_desc, &new_pn, pn_len);
140*5113495bSYour Name 
141*5113495bSYour Name 		/* if there was no prior PN, there's nothing to check */
142*5113495bSYour Name 		if (last_pn_valid) {
143*5113495bSYour Name 			pn_is_replay =
144*5113495bSYour Name 				pdev->rx_pn[peer->security[index].sec_type].
145*5113495bSYour Name 				cmp(&new_pn, last_pn, index == txrx_sec_ucast,
146*5113495bSYour Name 				    vdev->opmode, strict_chk);
147*5113495bSYour Name 		} else {
148*5113495bSYour Name 			last_pn_valid = peer->tids_last_pn_valid[tid] = 1;
149*5113495bSYour Name 		}
150*5113495bSYour Name 
151*5113495bSYour Name 		if (pn_is_replay) {
152*5113495bSYour Name 			qdf_nbuf_t msdu;
153*5113495bSYour Name 			static uint32_t last_pncheck_print_time /* = 0 */;
154*5113495bSYour Name 			uint32_t current_time_ms;
155*5113495bSYour Name 
156*5113495bSYour Name 			/*
157*5113495bSYour Name 			 * This MPDU failed the PN check:
158*5113495bSYour Name 			 * 1.  notify the control SW of the PN failure
159*5113495bSYour Name 			 *     (so countermeasures can be taken, if necessary)
160*5113495bSYour Name 			 * 2.  Discard all the MSDUs from this MPDU.
161*5113495bSYour Name 			 */
162*5113495bSYour Name 			msdu = mpdu;
163*5113495bSYour Name 			current_time_ms =
164*5113495bSYour Name 				qdf_system_ticks_to_msecs(qdf_system_ticks());
165*5113495bSYour Name 			if (TXRX_PN_CHECK_FAILURE_PRINT_PERIOD_MS <
166*5113495bSYour Name 			    (current_time_ms - last_pncheck_print_time)) {
167*5113495bSYour Name 				last_pncheck_print_time = current_time_ms;
168*5113495bSYour Name 				ol_txrx_warn(
169*5113495bSYour Name 				   "PN check failed - TID %d, peer %pK "
170*5113495bSYour Name 				   "("QDF_MAC_ADDR_FMT") %s\n"
171*5113495bSYour Name 				   "    old PN (u64 x2)= 0x%08llx %08llx (LSBs = %lld)\n"
172*5113495bSYour Name 				   "    new PN (u64 x2)= 0x%08llx %08llx (LSBs = %lld)\n"
173*5113495bSYour Name 				   "    new seq num = %d\n",
174*5113495bSYour Name 				   tid, peer,
175*5113495bSYour Name 				   QDF_MAC_ADDR_REF(peer->mac_addr.raw),
176*5113495bSYour Name 				   (index ==
177*5113495bSYour Name 				    txrx_sec_ucast) ? "ucast" : "mcast",
178*5113495bSYour Name 				   last_pn->pn128[1], last_pn->pn128[0],
179*5113495bSYour Name 				   last_pn->pn128[0] & 0xffffffffffffULL,
180*5113495bSYour Name 				   new_pn.pn128[1], new_pn.pn128[0],
181*5113495bSYour Name 				   new_pn.pn128[0] & 0xffffffffffffULL,
182*5113495bSYour Name 				   htt_rx_mpdu_desc_seq_num(pdev->htt_pdev,
183*5113495bSYour Name 							    rx_desc, false));
184*5113495bSYour Name 			} else {
185*5113495bSYour Name 				ol_txrx_dbg(
186*5113495bSYour Name 				   "PN check failed - TID %d, peer %pK "
187*5113495bSYour Name 				   "("QDF_MAC_ADDR_FMT") %s\n"
188*5113495bSYour Name 				   "    old PN (u64 x2)= 0x%08llx %08llx (LSBs = %lld)\n"
189*5113495bSYour Name 				   "    new PN (u64 x2)= 0x%08llx %08llx (LSBs = %lld)\n"
190*5113495bSYour Name 				   "    new seq num = %d\n",
191*5113495bSYour Name 				   tid, peer,
192*5113495bSYour Name 				   QDF_MAC_ADDR_REF(peer->mac_addr.raw),
193*5113495bSYour Name 				   (index ==
194*5113495bSYour Name 				    txrx_sec_ucast) ? "ucast" : "mcast",
195*5113495bSYour Name 				   last_pn->pn128[1], last_pn->pn128[0],
196*5113495bSYour Name 				   last_pn->pn128[0] & 0xffffffffffffULL,
197*5113495bSYour Name 				   new_pn.pn128[1], new_pn.pn128[0],
198*5113495bSYour Name 				   new_pn.pn128[0] & 0xffffffffffffULL,
199*5113495bSYour Name 				   htt_rx_mpdu_desc_seq_num(pdev->htt_pdev,
200*5113495bSYour Name 							    rx_desc, false));
201*5113495bSYour Name 			}
202*5113495bSYour Name #if defined(ENABLE_RX_PN_TRACE)
203*5113495bSYour Name 			ol_rx_pn_trace_display(pdev, 1);
204*5113495bSYour Name #endif /* ENABLE_RX_PN_TRACE */
205*5113495bSYour Name 			ol_rx_err(pdev->ctrl_pdev,
206*5113495bSYour Name 				  vdev->vdev_id, peer->mac_addr.raw, tid,
207*5113495bSYour Name 				  htt_rx_mpdu_desc_tsf32(pdev->htt_pdev,
208*5113495bSYour Name 							 rx_desc), OL_RX_ERR_PN,
209*5113495bSYour Name 				  mpdu, NULL, 0);
210*5113495bSYour Name 			/* free all MSDUs within this MPDU */
211*5113495bSYour Name 			do {
212*5113495bSYour Name 				qdf_nbuf_t next_msdu;
213*5113495bSYour Name 
214*5113495bSYour Name 				OL_RX_ERR_STATISTICS_1(pdev, vdev, peer,
215*5113495bSYour Name 						       rx_desc, OL_RX_ERR_PN);
216*5113495bSYour Name 				next_msdu = qdf_nbuf_next(msdu);
217*5113495bSYour Name 				htt_rx_desc_frame_free(pdev->htt_pdev, msdu);
218*5113495bSYour Name 				if (msdu == mpdu_tail)
219*5113495bSYour Name 					break;
220*5113495bSYour Name 				msdu = next_msdu;
221*5113495bSYour Name 			} while (1);
222*5113495bSYour Name 		} else {
223*5113495bSYour Name 			ADD_MPDU_TO_LIST(out_list_head, out_list_tail,
224*5113495bSYour Name 					       mpdu, mpdu_tail);
225*5113495bSYour Name 			/*
226*5113495bSYour Name 			 * Remember the new PN.
227*5113495bSYour Name 			 * For simplicity, just do 2 64-bit word copies to
228*5113495bSYour Name 			 * cover the worst case (WAPI), regardless of the length
229*5113495bSYour Name 			 * of the PN.
230*5113495bSYour Name 			 * This is more efficient than doing a conditional
231*5113495bSYour Name 			 * branch to copy only the relevant portion.
232*5113495bSYour Name 
233*5113495bSYour Name 			 * IWNCOM AP will send 1 packet with old PN after USK
234*5113495bSYour Name 			 * rekey, don't update last_pn when recv the packet, or
235*5113495bSYour Name 			 * PN check failed for later packets
236*5113495bSYour Name 			 */
237*5113495bSYour Name 			if ((peer->security[index].sec_type
238*5113495bSYour Name 				== htt_sec_type_wapi) &&
239*5113495bSYour Name 			    (peer->tids_rekey_flag[tid] == 1) &&
240*5113495bSYour Name 			    (index == txrx_sec_ucast)) {
241*5113495bSYour Name 				peer->tids_rekey_flag[tid] = 0;
242*5113495bSYour Name 			} else {
243*5113495bSYour Name 				last_pn->pn128[0] = new_pn.pn128[0];
244*5113495bSYour Name 				last_pn->pn128[1] = new_pn.pn128[1];
245*5113495bSYour Name 				OL_RX_PN_TRACE_ADD(pdev, peer, tid, rx_desc);
246*5113495bSYour Name 			}
247*5113495bSYour Name 		}
248*5113495bSYour Name 
249*5113495bSYour Name 		mpdu = next_mpdu;
250*5113495bSYour Name 	}
251*5113495bSYour Name 	/* make sure the list is null-terminated */
252*5113495bSYour Name 	if (out_list_tail)
253*5113495bSYour Name 		qdf_nbuf_set_next(out_list_tail, NULL);
254*5113495bSYour Name 
255*5113495bSYour Name 	return out_list_head;
256*5113495bSYour Name }
257*5113495bSYour Name 
258*5113495bSYour Name void
ol_rx_pn_check(struct ol_txrx_vdev_t * vdev,struct ol_txrx_peer_t * peer,unsigned int tid,qdf_nbuf_t msdu_list)259*5113495bSYour Name ol_rx_pn_check(struct ol_txrx_vdev_t *vdev,
260*5113495bSYour Name 	       struct ol_txrx_peer_t *peer, unsigned int tid,
261*5113495bSYour Name 	       qdf_nbuf_t msdu_list)
262*5113495bSYour Name {
263*5113495bSYour Name 	msdu_list = ol_rx_pn_check_base(vdev, peer, tid, msdu_list, false);
264*5113495bSYour Name 	ol_rx_fwd_check(vdev, peer, tid, msdu_list);
265*5113495bSYour Name }
266*5113495bSYour Name 
267*5113495bSYour Name void
ol_rx_pn_check_only(struct ol_txrx_vdev_t * vdev,struct ol_txrx_peer_t * peer,unsigned int tid,qdf_nbuf_t msdu_list)268*5113495bSYour Name ol_rx_pn_check_only(struct ol_txrx_vdev_t *vdev,
269*5113495bSYour Name 		    struct ol_txrx_peer_t *peer,
270*5113495bSYour Name 		    unsigned int tid, qdf_nbuf_t msdu_list)
271*5113495bSYour Name {
272*5113495bSYour Name 	msdu_list = ol_rx_pn_check_base(vdev, peer, tid, msdu_list, false);
273*5113495bSYour Name 	ol_rx_deliver(vdev, peer, tid, msdu_list);
274*5113495bSYour Name }
275*5113495bSYour Name 
276*5113495bSYour Name #if defined(ENABLE_RX_PN_TRACE)
277*5113495bSYour Name 
ol_rx_pn_trace_attach(ol_txrx_pdev_handle pdev)278*5113495bSYour Name A_STATUS ol_rx_pn_trace_attach(ol_txrx_pdev_handle pdev)
279*5113495bSYour Name {
280*5113495bSYour Name 	int num_elems;
281*5113495bSYour Name 
282*5113495bSYour Name 	num_elems = 1 << TXRX_RX_PN_TRACE_SIZE_LOG2;
283*5113495bSYour Name 	pdev->rx_pn_trace.idx = 0;
284*5113495bSYour Name 	pdev->rx_pn_trace.cnt = 0;
285*5113495bSYour Name 	pdev->rx_pn_trace.mask = num_elems - 1;
286*5113495bSYour Name 	pdev->rx_pn_trace.data =
287*5113495bSYour Name 		qdf_mem_malloc(sizeof(*pdev->rx_pn_trace.data) * num_elems);
288*5113495bSYour Name 	if (!pdev->rx_pn_trace.data)
289*5113495bSYour Name 		return A_NO_MEMORY;
290*5113495bSYour Name 	return A_OK;
291*5113495bSYour Name }
292*5113495bSYour Name 
ol_rx_pn_trace_detach(ol_txrx_pdev_handle pdev)293*5113495bSYour Name void ol_rx_pn_trace_detach(ol_txrx_pdev_handle pdev)
294*5113495bSYour Name {
295*5113495bSYour Name 	qdf_mem_free(pdev->rx_pn_trace.data);
296*5113495bSYour Name }
297*5113495bSYour Name 
298*5113495bSYour Name void
ol_rx_pn_trace_add(struct ol_txrx_pdev_t * pdev,struct ol_txrx_peer_t * peer,uint16_t tid,void * rx_desc)299*5113495bSYour Name ol_rx_pn_trace_add(struct ol_txrx_pdev_t *pdev,
300*5113495bSYour Name 		   struct ol_txrx_peer_t *peer, uint16_t tid, void *rx_desc)
301*5113495bSYour Name {
302*5113495bSYour Name 	uint32_t idx = pdev->rx_pn_trace.idx;
303*5113495bSYour Name 	union htt_rx_pn_t pn;
304*5113495bSYour Name 	uint32_t pn32;
305*5113495bSYour Name 	uint16_t seq_num;
306*5113495bSYour Name 	uint8_t unicast;
307*5113495bSYour Name 
308*5113495bSYour Name 	htt_rx_mpdu_desc_pn(pdev->htt_pdev, rx_desc, &pn, 48);
309*5113495bSYour Name 	pn32 = pn.pn48 & 0xffffffff;
310*5113495bSYour Name 	seq_num = htt_rx_mpdu_desc_seq_num(pdev->htt_pdev, rx_desc, false);
311*5113495bSYour Name 	unicast = !htt_rx_msdu_is_wlan_mcast(pdev->htt_pdev, rx_desc);
312*5113495bSYour Name 
313*5113495bSYour Name 	pdev->rx_pn_trace.data[idx].peer = peer;
314*5113495bSYour Name 	pdev->rx_pn_trace.data[idx].tid = tid;
315*5113495bSYour Name 	pdev->rx_pn_trace.data[idx].seq_num = seq_num;
316*5113495bSYour Name 	pdev->rx_pn_trace.data[idx].unicast = unicast;
317*5113495bSYour Name 	pdev->rx_pn_trace.data[idx].pn32 = pn32;
318*5113495bSYour Name 	pdev->rx_pn_trace.cnt++;
319*5113495bSYour Name 	idx++;
320*5113495bSYour Name 	pdev->rx_pn_trace.idx = idx & pdev->rx_pn_trace.mask;
321*5113495bSYour Name }
322*5113495bSYour Name 
ol_rx_pn_trace_display(ol_txrx_pdev_handle pdev,int just_once)323*5113495bSYour Name void ol_rx_pn_trace_display(ol_txrx_pdev_handle pdev, int just_once)
324*5113495bSYour Name {
325*5113495bSYour Name 	static int print_count /* = 0 */;
326*5113495bSYour Name 	uint32_t i, start, end;
327*5113495bSYour Name 	uint64_t cnt;
328*5113495bSYour Name 	int elems;
329*5113495bSYour Name 	int limit = 0;          /* move this to the arg list? */
330*5113495bSYour Name 
331*5113495bSYour Name 	if (print_count != 0 && just_once)
332*5113495bSYour Name 		return;
333*5113495bSYour Name 
334*5113495bSYour Name 	print_count++;
335*5113495bSYour Name 
336*5113495bSYour Name 	end = pdev->rx_pn_trace.idx;
337*5113495bSYour Name 	if (pdev->rx_pn_trace.cnt <= pdev->rx_pn_trace.mask) {
338*5113495bSYour Name 		/* trace log has not yet wrapped around - start at the top */
339*5113495bSYour Name 		start = 0;
340*5113495bSYour Name 		cnt = 0;
341*5113495bSYour Name 	} else {
342*5113495bSYour Name 		start = end;
343*5113495bSYour Name 		cnt = pdev->rx_pn_trace.cnt - (pdev->rx_pn_trace.mask + 1);
344*5113495bSYour Name 	}
345*5113495bSYour Name 	elems = (end - 1 - start) & pdev->rx_pn_trace.mask;
346*5113495bSYour Name 	if (limit > 0 && elems > limit) {
347*5113495bSYour Name 		int delta;
348*5113495bSYour Name 
349*5113495bSYour Name 		delta = elems - limit;
350*5113495bSYour Name 		start += delta;
351*5113495bSYour Name 		start &= pdev->rx_pn_trace.mask;
352*5113495bSYour Name 		cnt += delta;
353*5113495bSYour Name 	}
354*5113495bSYour Name 
355*5113495bSYour Name 	i = start;
356*5113495bSYour Name 	QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO,
357*5113495bSYour Name 		  "                                 seq     PN");
358*5113495bSYour Name 	QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO,
359*5113495bSYour Name 		  "   count  idx    peer   tid uni  num    LSBs");
360*5113495bSYour Name 	do {
361*5113495bSYour Name 		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO,
362*5113495bSYour Name 			  "  %6lld %4d  %pK %2d   %d %4d %8d",
363*5113495bSYour Name 			  cnt, i,
364*5113495bSYour Name 			  pdev->rx_pn_trace.data[i].peer,
365*5113495bSYour Name 			  pdev->rx_pn_trace.data[i].tid,
366*5113495bSYour Name 			  pdev->rx_pn_trace.data[i].unicast,
367*5113495bSYour Name 			  pdev->rx_pn_trace.data[i].seq_num,
368*5113495bSYour Name 			  pdev->rx_pn_trace.data[i].pn32);
369*5113495bSYour Name 		cnt++;
370*5113495bSYour Name 		i++;
371*5113495bSYour Name 		i &= pdev->rx_pn_trace.mask;
372*5113495bSYour Name 	} while (i != end);
373*5113495bSYour Name }
374*5113495bSYour Name #endif /* ENABLE_RX_PN_TRACE */
375