xref: /wlan-driver/qcacld-3.0/core/dp/txrx/ol_txrx_encap.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2012-2017, 2019 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 /**
20*5113495bSYour Name  * @file ol_txrx_encap.c
21*5113495bSYour Name  * @brief Provide functions to encap/decap on txrx frames.
22*5113495bSYour Name  * @details
23*5113495bSYour Name  *  This file contains functions for data frame encap/decap:
24*5113495bSYour Name  *  ol_tx_encap: encap outgoing data frames.
25*5113495bSYour Name  *  ol_rx_decap: decap incoming data frames.
26*5113495bSYour Name  */
27*5113495bSYour Name #ifdef QCA_SUPPORT_SW_TXRX_ENCAP
28*5113495bSYour Name 
29*5113495bSYour Name #include <qdf_nbuf.h>           /* qdf_nbuf_t, etc. */
30*5113495bSYour Name #include <cds_ieee80211_common.h>   /* ieee80211_frame */
31*5113495bSYour Name #include <ol_txrx_internal.h>   /* TXRX_ASSERT1 */
32*5113495bSYour Name #include <ol_txrx_encap.h>      /* struct ol_rx_decap_info_t */
33*5113495bSYour Name 
34*5113495bSYour Name static inline A_STATUS
ol_tx_copy_native_wifi_header(qdf_nbuf_t msdu,uint8_t * hdsize,uint8_t * localbuf)35*5113495bSYour Name ol_tx_copy_native_wifi_header(qdf_nbuf_t msdu,
36*5113495bSYour Name 			      uint8_t *hdsize, uint8_t *localbuf)
37*5113495bSYour Name {
38*5113495bSYour Name 	struct ieee80211_frame *wh =
39*5113495bSYour Name 		(struct ieee80211_frame *)qdf_nbuf_data(msdu);
40*5113495bSYour Name 	if ((wh->i_fc[1] &
41*5113495bSYour Name 	     IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) {
42*5113495bSYour Name 		*hdsize = sizeof(struct ieee80211_frame_addr4);
43*5113495bSYour Name 	} else {
44*5113495bSYour Name 		*hdsize = sizeof(struct ieee80211_frame);
45*5113495bSYour Name 	}
46*5113495bSYour Name 	if (qdf_nbuf_len(msdu) < *hdsize)
47*5113495bSYour Name 		return A_ERROR;
48*5113495bSYour Name 
49*5113495bSYour Name 	qdf_mem_copy(localbuf, wh, *hdsize);
50*5113495bSYour Name 	return A_OK;
51*5113495bSYour Name }
52*5113495bSYour Name 
53*5113495bSYour Name static inline A_STATUS
ol_tx_encap_from_native_wifi(struct ol_txrx_vdev_t * vdev,struct ol_tx_desc_t * tx_desc,qdf_nbuf_t msdu,struct ol_txrx_msdu_info_t * tx_msdu_info)54*5113495bSYour Name ol_tx_encap_from_native_wifi(struct ol_txrx_vdev_t *vdev,
55*5113495bSYour Name 			     struct ol_tx_desc_t *tx_desc,
56*5113495bSYour Name 			     qdf_nbuf_t msdu,
57*5113495bSYour Name 			     struct ol_txrx_msdu_info_t *tx_msdu_info)
58*5113495bSYour Name {
59*5113495bSYour Name 	uint8_t localbuf[sizeof(struct ieee80211_qosframe_htc_addr4)];
60*5113495bSYour Name 	struct ieee80211_frame *wh;
61*5113495bSYour Name 	uint8_t hdsize, new_hdsize;
62*5113495bSYour Name 	struct ieee80211_qoscntl *qos_cntl;
63*5113495bSYour Name 	struct ol_txrx_peer_t *peer;
64*5113495bSYour Name 
65*5113495bSYour Name 	if (tx_msdu_info->htt.info.frame_type != htt_frm_type_data)
66*5113495bSYour Name 		return A_OK;
67*5113495bSYour Name 
68*5113495bSYour Name 	peer = tx_msdu_info->peer;
69*5113495bSYour Name 	/*
70*5113495bSYour Name 	 * for unicast,the peer should not be NULL.
71*5113495bSYour Name 	 * for multicast, the peer is AP.
72*5113495bSYour Name 	 */
73*5113495bSYour Name 	if (tx_msdu_info->htt.info.is_unicast && peer->qos_capable) {
74*5113495bSYour Name 		if (A_OK !=
75*5113495bSYour Name 		    ol_tx_copy_native_wifi_header(msdu, &hdsize, localbuf))
76*5113495bSYour Name 			return A_ERROR;
77*5113495bSYour Name 		wh = (struct ieee80211_frame *)localbuf;
78*5113495bSYour Name 
79*5113495bSYour Name 		/*add qos cntl */
80*5113495bSYour Name 		qos_cntl = (struct ieee80211_qoscntl *)(localbuf + hdsize);
81*5113495bSYour Name 		qos_cntl->i_qos[0] =
82*5113495bSYour Name 			tx_msdu_info->htt.info.ext_tid & IEEE80211_QOS_TID;
83*5113495bSYour Name 
84*5113495bSYour Name #ifdef NEVERDEFINED
85*5113495bSYour Name 		if (wmmParam[ac].wmep_noackPolicy)
86*5113495bSYour Name 			qos_cntl->i_qos[0] |= 1 << IEEE80211_QOS_ACKPOLICY_S;
87*5113495bSYour Name #endif
88*5113495bSYour Name 
89*5113495bSYour Name 		qos_cntl->i_qos[1] = 0;
90*5113495bSYour Name 		wh->i_fc[0] |= QDF_IEEE80211_FC0_SUBTYPE_QOS;
91*5113495bSYour Name 		/* count for qos field */
92*5113495bSYour Name 		new_hdsize =
93*5113495bSYour Name 			hdsize + sizeof(struct ieee80211_qosframe) -
94*5113495bSYour Name 			sizeof(struct ieee80211_frame);
95*5113495bSYour Name 
96*5113495bSYour Name 		/*add ht control field if needed */
97*5113495bSYour Name 
98*5113495bSYour Name 		/* copy new hd to bd */
99*5113495bSYour Name 		qdf_mem_copy((void *)
100*5113495bSYour Name 			     htt_tx_desc_mpdu_header(tx_desc->htt_tx_desc,
101*5113495bSYour Name 						     new_hdsize), localbuf,
102*5113495bSYour Name 			     new_hdsize);
103*5113495bSYour Name 		qdf_nbuf_pull_head(msdu, hdsize);
104*5113495bSYour Name 		tx_msdu_info->htt.info.l3_hdr_offset = new_hdsize;
105*5113495bSYour Name 		tx_desc->orig_l2_hdr_bytes = hdsize;
106*5113495bSYour Name 	}
107*5113495bSYour Name 	/* Set Protected Frame bit in MAC header */
108*5113495bSYour Name 	if (vdev->pdev->sw_pf_proc_enable
109*5113495bSYour Name 	    && tx_msdu_info->htt.action.do_encrypt) {
110*5113495bSYour Name 		if (tx_desc->orig_l2_hdr_bytes) {
111*5113495bSYour Name 			wh = (struct ieee80211_frame *)
112*5113495bSYour Name 			     htt_tx_desc_mpdu_header(tx_desc->htt_tx_desc,
113*5113495bSYour Name 						     tx_msdu_info->htt.info.
114*5113495bSYour Name 						     l3_hdr_offset);
115*5113495bSYour Name 		} else {
116*5113495bSYour Name 			if (A_OK !=
117*5113495bSYour Name 			    ol_tx_copy_native_wifi_header(msdu, &hdsize,
118*5113495bSYour Name 							  localbuf))
119*5113495bSYour Name 				return A_ERROR;
120*5113495bSYour Name 			wh = (struct ieee80211_frame *)
121*5113495bSYour Name 			     htt_tx_desc_mpdu_header(tx_desc->htt_tx_desc,
122*5113495bSYour Name 						     hdsize);
123*5113495bSYour Name 			qdf_mem_copy((void *)wh, localbuf, hdsize);
124*5113495bSYour Name 			qdf_nbuf_pull_head(msdu, hdsize);
125*5113495bSYour Name 			tx_msdu_info->htt.info.l3_hdr_offset = hdsize;
126*5113495bSYour Name 			tx_desc->orig_l2_hdr_bytes = hdsize;
127*5113495bSYour Name 		}
128*5113495bSYour Name 		wh->i_fc[1] |= IEEE80211_FC1_WEP;
129*5113495bSYour Name 	}
130*5113495bSYour Name 	return A_OK;
131*5113495bSYour Name }
132*5113495bSYour Name 
133*5113495bSYour Name static inline A_STATUS
ol_tx_encap_from_8023(struct ol_txrx_vdev_t * vdev,struct ol_tx_desc_t * tx_desc,qdf_nbuf_t msdu,struct ol_txrx_msdu_info_t * tx_msdu_info)134*5113495bSYour Name ol_tx_encap_from_8023(struct ol_txrx_vdev_t *vdev,
135*5113495bSYour Name 		      struct ol_tx_desc_t *tx_desc,
136*5113495bSYour Name 		      qdf_nbuf_t msdu, struct ol_txrx_msdu_info_t *tx_msdu_info)
137*5113495bSYour Name {
138*5113495bSYour Name 	uint8_t localbuf[sizeof(struct ieee80211_qosframe_htc_addr4)
139*5113495bSYour Name 			 + sizeof(struct llc_snap_hdr_t)];
140*5113495bSYour Name 	struct llc_snap_hdr_t *llc_hdr;
141*5113495bSYour Name 	struct ethernet_hdr_t *eth_hdr;
142*5113495bSYour Name 	struct ieee80211_frame *wh;
143*5113495bSYour Name 	uint8_t hdsize, new_l2_hdsize, new_hdsize;
144*5113495bSYour Name 	struct ieee80211_qoscntl *qos_cntl;
145*5113495bSYour Name 	const uint8_t ethernet_II_llc_snap_header_prefix[] = {
146*5113495bSYour Name 		0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
147*5113495bSYour Name 	struct ol_txrx_peer_t *peer;
148*5113495bSYour Name 	uint16_t ether_type;
149*5113495bSYour Name 
150*5113495bSYour Name 	if (tx_msdu_info->htt.info.frame_type != htt_frm_type_data)
151*5113495bSYour Name 		return A_OK;
152*5113495bSYour Name 
153*5113495bSYour Name 	/*
154*5113495bSYour Name 	 * for unicast,the peer should not be NULL.
155*5113495bSYour Name 	 * for multicast, the peer is AP.
156*5113495bSYour Name 	 */
157*5113495bSYour Name 	peer = tx_msdu_info->peer;
158*5113495bSYour Name 
159*5113495bSYour Name 	eth_hdr = (struct ethernet_hdr_t *)qdf_nbuf_data(msdu);
160*5113495bSYour Name 	hdsize = sizeof(struct ethernet_hdr_t);
161*5113495bSYour Name 	wh = (struct ieee80211_frame *)localbuf;
162*5113495bSYour Name 	wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA;
163*5113495bSYour Name 	*(uint16_t *) wh->i_dur = 0;
164*5113495bSYour Name 	new_hdsize = 0;
165*5113495bSYour Name 
166*5113495bSYour Name 	switch (vdev->opmode) {
167*5113495bSYour Name 	case wlan_op_mode_ap:
168*5113495bSYour Name 		/* DA , BSSID , SA */
169*5113495bSYour Name 		qdf_mem_copy(wh->i_addr1, eth_hdr->dest_addr,
170*5113495bSYour Name 			     QDF_MAC_ADDR_SIZE);
171*5113495bSYour Name 		qdf_mem_copy(wh->i_addr2, &vdev->mac_addr.raw,
172*5113495bSYour Name 			     QDF_MAC_ADDR_SIZE);
173*5113495bSYour Name 		qdf_mem_copy(wh->i_addr3, eth_hdr->src_addr,
174*5113495bSYour Name 			     QDF_MAC_ADDR_SIZE);
175*5113495bSYour Name 		wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
176*5113495bSYour Name 		new_hdsize = sizeof(struct ieee80211_frame);
177*5113495bSYour Name 		break;
178*5113495bSYour Name 	case wlan_op_mode_ibss:
179*5113495bSYour Name 		/* DA, SA, BSSID */
180*5113495bSYour Name 		qdf_mem_copy(wh->i_addr1, eth_hdr->dest_addr,
181*5113495bSYour Name 			     QDF_MAC_ADDR_SIZE);
182*5113495bSYour Name 		qdf_mem_copy(wh->i_addr2, eth_hdr->src_addr,
183*5113495bSYour Name 			     QDF_MAC_ADDR_SIZE);
184*5113495bSYour Name 		/* need to check the bssid behaviour for IBSS vdev */
185*5113495bSYour Name 		qdf_mem_copy(wh->i_addr3, &vdev->mac_addr.raw,
186*5113495bSYour Name 			     QDF_MAC_ADDR_SIZE);
187*5113495bSYour Name 		wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
188*5113495bSYour Name 		new_hdsize = sizeof(struct ieee80211_frame);
189*5113495bSYour Name 		break;
190*5113495bSYour Name 	case wlan_op_mode_sta:
191*5113495bSYour Name 		/* BSSID, SA , DA */
192*5113495bSYour Name 		qdf_mem_copy(wh->i_addr1, &peer->mac_addr.raw,
193*5113495bSYour Name 			     QDF_MAC_ADDR_SIZE);
194*5113495bSYour Name 		qdf_mem_copy(wh->i_addr2, eth_hdr->src_addr,
195*5113495bSYour Name 			     QDF_MAC_ADDR_SIZE);
196*5113495bSYour Name 		qdf_mem_copy(wh->i_addr3, eth_hdr->dest_addr,
197*5113495bSYour Name 			     QDF_MAC_ADDR_SIZE);
198*5113495bSYour Name 		wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;
199*5113495bSYour Name 		new_hdsize = sizeof(struct ieee80211_frame);
200*5113495bSYour Name 		break;
201*5113495bSYour Name 	case wlan_op_mode_monitor:
202*5113495bSYour Name 	default:
203*5113495bSYour Name 		return A_ERROR;
204*5113495bSYour Name 	}
205*5113495bSYour Name 	/*add qos cntl */
206*5113495bSYour Name 	if (tx_msdu_info->htt.info.is_unicast && peer->qos_capable) {
207*5113495bSYour Name 		qos_cntl = (struct ieee80211_qoscntl *)(localbuf + new_hdsize);
208*5113495bSYour Name 		qos_cntl->i_qos[0] =
209*5113495bSYour Name 			tx_msdu_info->htt.info.ext_tid & IEEE80211_QOS_TID;
210*5113495bSYour Name 		wh->i_fc[0] |= QDF_IEEE80211_FC0_SUBTYPE_QOS;
211*5113495bSYour Name #ifdef NEVERDEFINED
212*5113495bSYour Name 		if (wmmParam[ac].wmep_noackPolicy)
213*5113495bSYour Name 			qos_cntl->i_qos[0] |= 1 << IEEE80211_QOS_ACKPOLICY_S;
214*5113495bSYour Name #endif
215*5113495bSYour Name 		qos_cntl->i_qos[1] = 0;
216*5113495bSYour Name 		new_hdsize += sizeof(struct ieee80211_qoscntl);
217*5113495bSYour Name 
218*5113495bSYour Name 		/*add ht control field if needed */
219*5113495bSYour Name 	}
220*5113495bSYour Name 	/* Set Protected Frame bit in MAC header */
221*5113495bSYour Name 	if (vdev->pdev->sw_pf_proc_enable
222*5113495bSYour Name 	    && tx_msdu_info->htt.action.do_encrypt) {
223*5113495bSYour Name 		wh->i_fc[1] |= IEEE80211_FC1_WEP;
224*5113495bSYour Name 	}
225*5113495bSYour Name 	new_l2_hdsize = new_hdsize;
226*5113495bSYour Name 	/* add llc snap if needed */
227*5113495bSYour Name 	if (vdev->pdev->sw_tx_llc_proc_enable) {
228*5113495bSYour Name 		llc_hdr = (struct llc_snap_hdr_t *)(localbuf + new_hdsize);
229*5113495bSYour Name 		ether_type =
230*5113495bSYour Name 			(eth_hdr->ethertype[0] << 8) | (eth_hdr->ethertype[1]);
231*5113495bSYour Name 		if (ether_type >= ETH_P_802_3_MIN) {
232*5113495bSYour Name 			qdf_mem_copy(llc_hdr,
233*5113495bSYour Name 				     ethernet_II_llc_snap_header_prefix,
234*5113495bSYour Name 				     sizeof
235*5113495bSYour Name 				     (ethernet_II_llc_snap_header_prefix));
236*5113495bSYour Name 			if (ether_type == ETHERTYPE_AARP
237*5113495bSYour Name 			    || ether_type == ETHERTYPE_IPX) {
238*5113495bSYour Name 				llc_hdr->org_code[2] = BTEP_SNAP_ORGCODE_2;
239*5113495bSYour Name 				/* 0xf8; bridge tunnel header */
240*5113495bSYour Name 			}
241*5113495bSYour Name 			llc_hdr->ethertype[0] = eth_hdr->ethertype[0];
242*5113495bSYour Name 			llc_hdr->ethertype[1] = eth_hdr->ethertype[1];
243*5113495bSYour Name 			new_hdsize += sizeof(struct llc_snap_hdr_t);
244*5113495bSYour Name 		} else {
245*5113495bSYour Name 			/*
246*5113495bSYour Name 			 * llc ready, and it's in payload pdu,
247*5113495bSYour Name 			 * do we need to move to BD pdu?
248*5113495bSYour Name 			 */
249*5113495bSYour Name 		}
250*5113495bSYour Name 	}
251*5113495bSYour Name 	qdf_mem_copy((void *)
252*5113495bSYour Name 		     htt_tx_desc_mpdu_header(tx_desc->htt_tx_desc,
253*5113495bSYour Name 					     new_l2_hdsize), localbuf,
254*5113495bSYour Name 		     new_hdsize);
255*5113495bSYour Name 	qdf_nbuf_pull_head(msdu, hdsize);
256*5113495bSYour Name 	tx_msdu_info->htt.info.l3_hdr_offset = new_l2_hdsize;
257*5113495bSYour Name 	tx_desc->orig_l2_hdr_bytes = hdsize;
258*5113495bSYour Name 	return A_OK;
259*5113495bSYour Name }
260*5113495bSYour Name 
261*5113495bSYour Name A_STATUS
ol_tx_encap(struct ol_txrx_vdev_t * vdev,struct ol_tx_desc_t * tx_desc,qdf_nbuf_t msdu,struct ol_txrx_msdu_info_t * msdu_info)262*5113495bSYour Name ol_tx_encap(struct ol_txrx_vdev_t *vdev,
263*5113495bSYour Name 	    struct ol_tx_desc_t *tx_desc,
264*5113495bSYour Name 	    qdf_nbuf_t msdu, struct ol_txrx_msdu_info_t *msdu_info)
265*5113495bSYour Name {
266*5113495bSYour Name 	struct ol_txrx_pdev_t *pdev = vdev->pdev;
267*5113495bSYour Name 
268*5113495bSYour Name 	if (pdev->frame_format == wlan_frm_fmt_native_wifi) {
269*5113495bSYour Name 		return ol_tx_encap_from_native_wifi(vdev, tx_desc, msdu,
270*5113495bSYour Name 						    msdu_info);
271*5113495bSYour Name 	} else if (pdev->frame_format == wlan_frm_fmt_802_3) {
272*5113495bSYour Name 		return ol_tx_encap_from_8023(vdev, tx_desc, msdu, msdu_info);
273*5113495bSYour Name 	}
274*5113495bSYour Name 
275*5113495bSYour Name 	/* todo for other types */
276*5113495bSYour Name 	return A_ERROR;
277*5113495bSYour Name }
278*5113495bSYour Name 
279*5113495bSYour Name static inline void
ol_rx_decap_to_native_wifi(struct ol_txrx_vdev_t * vdev,qdf_nbuf_t msdu,struct ol_rx_decap_info_t * info,struct ethernet_hdr_t * ethr_hdr)280*5113495bSYour Name ol_rx_decap_to_native_wifi(struct ol_txrx_vdev_t *vdev,
281*5113495bSYour Name 			   qdf_nbuf_t msdu,
282*5113495bSYour Name 			   struct ol_rx_decap_info_t *info,
283*5113495bSYour Name 			   struct ethernet_hdr_t *ethr_hdr)
284*5113495bSYour Name {
285*5113495bSYour Name 	struct ieee80211_frame_addr4 *wh;
286*5113495bSYour Name 	uint16_t hdsize;
287*5113495bSYour Name 
288*5113495bSYour Name 	/*
289*5113495bSYour Name 	 * we need to remove Qos control field and HT control.
290*5113495bSYour Name 	 * MSFT: http://msdn.microsoft.com/en-us/library/windows/
291*5113495bSYour Name 	 * hardware/ff552608(v=vs.85).aspx
292*5113495bSYour Name 	 */
293*5113495bSYour Name 	wh = (struct ieee80211_frame_addr4 *)info->hdr;
294*5113495bSYour Name 	if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) ==
295*5113495bSYour Name 	    IEEE80211_FC1_DIR_DSTODS)
296*5113495bSYour Name 		hdsize = sizeof(struct ieee80211_frame_addr4);
297*5113495bSYour Name 	else
298*5113495bSYour Name 		hdsize = sizeof(struct ieee80211_frame);
299*5113495bSYour Name 
300*5113495bSYour Name 	wh = (struct ieee80211_frame_addr4 *)qdf_nbuf_push_head(msdu, hdsize);
301*5113495bSYour Name 	TXRX_ASSERT2(wh);
302*5113495bSYour Name 	TXRX_ASSERT2(hdsize <= info->hdr_len);
303*5113495bSYour Name 	qdf_mem_copy((uint8_t *) wh, info->hdr, hdsize);
304*5113495bSYour Name 
305*5113495bSYour Name 	/* amsdu subfrm handling if ethr_hdr is not NULL  */
306*5113495bSYour Name 	if (ethr_hdr) {
307*5113495bSYour Name 		switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
308*5113495bSYour Name 		case IEEE80211_FC1_DIR_NODS:
309*5113495bSYour Name 			qdf_mem_copy(wh->i_addr1, ethr_hdr->dest_addr,
310*5113495bSYour Name 				     QDF_MAC_ADDR_SIZE);
311*5113495bSYour Name 			qdf_mem_copy(wh->i_addr2, ethr_hdr->src_addr,
312*5113495bSYour Name 				     QDF_MAC_ADDR_SIZE);
313*5113495bSYour Name 			break;
314*5113495bSYour Name 		case IEEE80211_FC1_DIR_TODS:
315*5113495bSYour Name 			qdf_mem_copy(wh->i_addr2, ethr_hdr->src_addr,
316*5113495bSYour Name 				     QDF_MAC_ADDR_SIZE);
317*5113495bSYour Name 			qdf_mem_copy(wh->i_addr3, ethr_hdr->dest_addr,
318*5113495bSYour Name 				     QDF_MAC_ADDR_SIZE);
319*5113495bSYour Name 			break;
320*5113495bSYour Name 		case IEEE80211_FC1_DIR_FROMDS:
321*5113495bSYour Name 			qdf_mem_copy(wh->i_addr1, ethr_hdr->dest_addr,
322*5113495bSYour Name 				     QDF_MAC_ADDR_SIZE);
323*5113495bSYour Name 			qdf_mem_copy(wh->i_addr3, ethr_hdr->src_addr,
324*5113495bSYour Name 				     QDF_MAC_ADDR_SIZE);
325*5113495bSYour Name 			break;
326*5113495bSYour Name 		case IEEE80211_FC1_DIR_DSTODS:
327*5113495bSYour Name 			qdf_mem_copy(wh->i_addr3, ethr_hdr->dest_addr,
328*5113495bSYour Name 				     QDF_MAC_ADDR_SIZE);
329*5113495bSYour Name 			qdf_mem_copy(wh->i_addr4, ethr_hdr->src_addr,
330*5113495bSYour Name 				     QDF_MAC_ADDR_SIZE);
331*5113495bSYour Name 			break;
332*5113495bSYour Name 		}
333*5113495bSYour Name 	}
334*5113495bSYour Name 	if (IEEE80211_QOS_HAS_SEQ(wh)) {
335*5113495bSYour Name 		if (wh->i_fc[1] & IEEE80211_FC1_ORDER)
336*5113495bSYour Name 			wh->i_fc[1] &= ~IEEE80211_FC1_ORDER;
337*5113495bSYour Name 		wh->i_fc[0] &= ~QDF_IEEE80211_FC0_SUBTYPE_QOS;
338*5113495bSYour Name 	}
339*5113495bSYour Name }
340*5113495bSYour Name 
341*5113495bSYour Name static inline void
ol_rx_decap_to_8023(struct ol_txrx_vdev_t * vdev,qdf_nbuf_t msdu,struct ol_rx_decap_info_t * info,struct ethernet_hdr_t * ethr_hdr)342*5113495bSYour Name ol_rx_decap_to_8023(struct ol_txrx_vdev_t *vdev,
343*5113495bSYour Name 		    qdf_nbuf_t msdu,
344*5113495bSYour Name 		    struct ol_rx_decap_info_t *info,
345*5113495bSYour Name 		    struct ethernet_hdr_t *ethr_hdr)
346*5113495bSYour Name {
347*5113495bSYour Name 	struct llc_snap_hdr_t *llc_hdr;
348*5113495bSYour Name 	uint16_t ether_type;
349*5113495bSYour Name 	uint16_t l2_hdr_space;
350*5113495bSYour Name 	struct ieee80211_frame_addr4 *wh;
351*5113495bSYour Name 	uint8_t local_buf[ETHERNET_HDR_LEN];
352*5113495bSYour Name 	uint8_t *buf;
353*5113495bSYour Name 
354*5113495bSYour Name 	/*
355*5113495bSYour Name 	 * populate Ethernet header,
356*5113495bSYour Name 	 * if ethr_hdr is null, rx frame is 802.11 format(HW ft disabled)
357*5113495bSYour Name 	 * if ethr_hdr is not null, rx frame is "subfrm of amsdu".
358*5113495bSYour Name 	 */
359*5113495bSYour Name 	buf = (uint8_t *) qdf_nbuf_data(msdu);
360*5113495bSYour Name 	llc_hdr = (struct llc_snap_hdr_t *)buf;
361*5113495bSYour Name 	ether_type = (llc_hdr->ethertype[0] << 8) | llc_hdr->ethertype[1];
362*5113495bSYour Name 	/* do llc remove if needed */
363*5113495bSYour Name 	l2_hdr_space = 0;
364*5113495bSYour Name 	if (IS_SNAP(llc_hdr)) {
365*5113495bSYour Name 		if (IS_BTEP(llc_hdr)) {
366*5113495bSYour Name 			/* remove llc */
367*5113495bSYour Name 			l2_hdr_space += sizeof(struct llc_snap_hdr_t);
368*5113495bSYour Name 			llc_hdr = NULL;
369*5113495bSYour Name 		} else if (IS_RFC1042(llc_hdr)) {
370*5113495bSYour Name 			if (!(ether_type == ETHERTYPE_AARP ||
371*5113495bSYour Name 			      ether_type == ETHERTYPE_IPX)) {
372*5113495bSYour Name 				/* remove llc */
373*5113495bSYour Name 				l2_hdr_space += sizeof(struct llc_snap_hdr_t);
374*5113495bSYour Name 				llc_hdr = NULL;
375*5113495bSYour Name 			}
376*5113495bSYour Name 		}
377*5113495bSYour Name 	}
378*5113495bSYour Name 	if (l2_hdr_space > ETHERNET_HDR_LEN)
379*5113495bSYour Name 		buf = qdf_nbuf_pull_head(msdu, l2_hdr_space - ETHERNET_HDR_LEN);
380*5113495bSYour Name 	else if (l2_hdr_space < ETHERNET_HDR_LEN)
381*5113495bSYour Name 		buf = qdf_nbuf_push_head(msdu, ETHERNET_HDR_LEN - l2_hdr_space);
382*5113495bSYour Name 
383*5113495bSYour Name 	/* normal msdu(non-subfrm of A-MSDU) if ethr_hdr is null */
384*5113495bSYour Name 	if (!ethr_hdr) {
385*5113495bSYour Name 		/*
386*5113495bSYour Name 		 * mpdu hdr should be present in info,
387*5113495bSYour Name 		 * re-create ethr_hdr based on mpdu hdr
388*5113495bSYour Name 		 */
389*5113495bSYour Name 		TXRX_ASSERT2(info->hdr_len != 0);
390*5113495bSYour Name 		wh = (struct ieee80211_frame_addr4 *)info->hdr;
391*5113495bSYour Name 		ethr_hdr = (struct ethernet_hdr_t *)local_buf;
392*5113495bSYour Name 		switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
393*5113495bSYour Name 		case IEEE80211_FC1_DIR_NODS:
394*5113495bSYour Name 			qdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr1,
395*5113495bSYour Name 				     QDF_MAC_ADDR_SIZE);
396*5113495bSYour Name 			qdf_mem_copy(ethr_hdr->src_addr, wh->i_addr2,
397*5113495bSYour Name 				     QDF_MAC_ADDR_SIZE);
398*5113495bSYour Name 			break;
399*5113495bSYour Name 		case IEEE80211_FC1_DIR_TODS:
400*5113495bSYour Name 			qdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr3,
401*5113495bSYour Name 				     QDF_MAC_ADDR_SIZE);
402*5113495bSYour Name 			qdf_mem_copy(ethr_hdr->src_addr, wh->i_addr2,
403*5113495bSYour Name 				     QDF_MAC_ADDR_SIZE);
404*5113495bSYour Name 			break;
405*5113495bSYour Name 		case IEEE80211_FC1_DIR_FROMDS:
406*5113495bSYour Name 			qdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr1,
407*5113495bSYour Name 				     QDF_MAC_ADDR_SIZE);
408*5113495bSYour Name 			qdf_mem_copy(ethr_hdr->src_addr, wh->i_addr3,
409*5113495bSYour Name 				     QDF_MAC_ADDR_SIZE);
410*5113495bSYour Name 			break;
411*5113495bSYour Name 		case IEEE80211_FC1_DIR_DSTODS:
412*5113495bSYour Name 			qdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr3,
413*5113495bSYour Name 				     QDF_MAC_ADDR_SIZE);
414*5113495bSYour Name 			qdf_mem_copy(ethr_hdr->src_addr, wh->i_addr4,
415*5113495bSYour Name 				     QDF_MAC_ADDR_SIZE);
416*5113495bSYour Name 			break;
417*5113495bSYour Name 		}
418*5113495bSYour Name 	}
419*5113495bSYour Name 	if (!llc_hdr) {
420*5113495bSYour Name 		ethr_hdr->ethertype[0] = (ether_type >> 8) & 0xff;
421*5113495bSYour Name 		ethr_hdr->ethertype[1] = (ether_type) & 0xff;
422*5113495bSYour Name 	} else {
423*5113495bSYour Name 		uint32_t pktlen =
424*5113495bSYour Name 			qdf_nbuf_len(msdu) - sizeof(ethr_hdr->ethertype);
425*5113495bSYour Name 		TXRX_ASSERT2(pktlen <= ETHERNET_MTU);
426*5113495bSYour Name 		ether_type = (uint16_t) pktlen;
427*5113495bSYour Name 		ether_type = qdf_nbuf_len(msdu) - sizeof(struct ethernet_hdr_t);
428*5113495bSYour Name 		ethr_hdr->ethertype[0] = (ether_type >> 8) & 0xff;
429*5113495bSYour Name 		ethr_hdr->ethertype[1] = (ether_type) & 0xff;
430*5113495bSYour Name 	}
431*5113495bSYour Name 	qdf_mem_copy(buf, ethr_hdr, ETHERNET_HDR_LEN);
432*5113495bSYour Name }
433*5113495bSYour Name 
434*5113495bSYour Name static inline A_STATUS
ol_rx_decap_subfrm_amsdu(struct ol_txrx_vdev_t * vdev,qdf_nbuf_t msdu,struct ol_rx_decap_info_t * info)435*5113495bSYour Name ol_rx_decap_subfrm_amsdu(struct ol_txrx_vdev_t *vdev,
436*5113495bSYour Name 			 qdf_nbuf_t msdu, struct ol_rx_decap_info_t *info)
437*5113495bSYour Name {
438*5113495bSYour Name 	struct ol_txrx_pdev_t *pdev = vdev->pdev;
439*5113495bSYour Name 	uint8_t *subfrm_hdr;
440*5113495bSYour Name 	uint8_t localbuf[ETHERNET_HDR_LEN];
441*5113495bSYour Name 	struct ethernet_hdr_t *ether_hdr = (struct ethernet_hdr_t *)localbuf;
442*5113495bSYour Name 
443*5113495bSYour Name 	subfrm_hdr = (uint8_t *) qdf_nbuf_data(msdu);
444*5113495bSYour Name 	if (pdev->frame_format == wlan_frm_fmt_native_wifi) {
445*5113495bSYour Name 		/* decap to native wifi */
446*5113495bSYour Name 		qdf_mem_copy(ether_hdr, subfrm_hdr, ETHERNET_HDR_LEN);
447*5113495bSYour Name 		qdf_nbuf_pull_head(msdu, ETHERNET_HDR_LEN);
448*5113495bSYour Name 		ol_rx_decap_to_native_wifi(vdev, msdu, info, ether_hdr);
449*5113495bSYour Name 	} else if (pdev->frame_format == wlan_frm_fmt_802_3) {
450*5113495bSYour Name 		if (pdev->sw_rx_llc_proc_enable) {
451*5113495bSYour Name 			/* remove llc snap hdr if it's necessary according to
452*5113495bSYour Name 			 * 802.11 table P-3
453*5113495bSYour Name 			 */
454*5113495bSYour Name 			qdf_mem_copy(ether_hdr, subfrm_hdr, ETHERNET_HDR_LEN);
455*5113495bSYour Name 			qdf_nbuf_pull_head(msdu, ETHERNET_HDR_LEN);
456*5113495bSYour Name 			ol_rx_decap_to_8023(vdev, msdu, info, ether_hdr);
457*5113495bSYour Name 		} else {
458*5113495bSYour Name 			/* subfrm of A-MSDU is already in 802.3 format.
459*5113495bSYour Name 			 * if target HW or FW has done LLC rmv process,
460*5113495bSYour Name 			 * we do nothing here.
461*5113495bSYour Name 			 */
462*5113495bSYour Name 		}
463*5113495bSYour Name 	} else {
464*5113495bSYour Name 		/* todo for othertype */
465*5113495bSYour Name 	}
466*5113495bSYour Name 	return A_OK;
467*5113495bSYour Name 
468*5113495bSYour Name }
469*5113495bSYour Name 
470*5113495bSYour Name static inline A_STATUS
ol_rx_decap_msdu(struct ol_txrx_vdev_t * vdev,qdf_nbuf_t msdu,struct ol_rx_decap_info_t * info)471*5113495bSYour Name ol_rx_decap_msdu(struct ol_txrx_vdev_t *vdev,
472*5113495bSYour Name 		 qdf_nbuf_t msdu, struct ol_rx_decap_info_t *info)
473*5113495bSYour Name {
474*5113495bSYour Name 	struct ol_txrx_pdev_t *pdev = vdev->pdev;
475*5113495bSYour Name 	struct ieee80211_frame *wh;
476*5113495bSYour Name 
477*5113495bSYour Name 	wh = (struct ieee80211_frame *)qdf_nbuf_data(msdu);
478*5113495bSYour Name 
479*5113495bSYour Name 	if (pdev->frame_format == wlan_frm_fmt_native_wifi) {
480*5113495bSYour Name 		/* Decap to native wifi because according to MSFT(
481*5113495bSYour Name 		 * MSFT: http://msdn.microsoft.com/en-us/library/windows/
482*5113495bSYour Name 		 * hardware/ff552608(v=vs.85).aspx),
483*5113495bSYour Name 		 * we need to remove Qos and HTC field before indicate to OS.
484*5113495bSYour Name 		 */
485*5113495bSYour Name 		if (IEEE80211_QOS_HAS_SEQ(wh)) {
486*5113495bSYour Name 			info->hdr_len = ol_txrx_ieee80211_hdrsize(wh);
487*5113495bSYour Name 			TXRX_ASSERT2(info->hdr_len <= sizeof(info->hdr));
488*5113495bSYour Name 			qdf_mem_copy(info->hdr, /* use info->hdr as temp buf. */
489*5113495bSYour Name 				     wh, info->hdr_len);
490*5113495bSYour Name 			qdf_nbuf_pull_head(msdu, info->hdr_len);
491*5113495bSYour Name 			ol_rx_decap_to_native_wifi(vdev, msdu, info, NULL);
492*5113495bSYour Name 			/*                           802.11 hdr^  eth_hdr^ */
493*5113495bSYour Name 		}
494*5113495bSYour Name 	} else if (pdev->frame_format == wlan_frm_fmt_802_3) {
495*5113495bSYour Name 		if (pdev->sw_rx_llc_proc_enable) {
496*5113495bSYour Name 			info->hdr_len = ol_txrx_ieee80211_hdrsize(wh);
497*5113495bSYour Name 			TXRX_ASSERT2(info->hdr_len <= sizeof(info->hdr));
498*5113495bSYour Name 			qdf_mem_copy(info->hdr, /* use info->hdr as temp buf. */
499*5113495bSYour Name 				     wh, info->hdr_len);
500*5113495bSYour Name 			qdf_nbuf_pull_head(msdu, info->hdr_len);
501*5113495bSYour Name 			/* remove llc snap hdr if it's necessary according to
502*5113495bSYour Name 			 * 802.11 table P-3
503*5113495bSYour Name 			 */
504*5113495bSYour Name 			ol_rx_decap_to_8023(vdev, msdu, info,   /* 802.11 hdr */
505*5113495bSYour Name 					    NULL);      /* ethernet hdr */
506*5113495bSYour Name 		} else {
507*5113495bSYour Name 			/* Subfrm of A-MSDU is already in 802.3 format.
508*5113495bSYour Name 			 * And if target HW or FW has done LLC rmv process (
509*5113495bSYour Name 			 * sw_rx_lc_proc_enable == 0), we do nothing here.
510*5113495bSYour Name 			 */
511*5113495bSYour Name 		}
512*5113495bSYour Name 	} else {
513*5113495bSYour Name 		/* todo for othertype */
514*5113495bSYour Name 	}
515*5113495bSYour Name 	return A_OK;
516*5113495bSYour Name 
517*5113495bSYour Name }
518*5113495bSYour Name 
519*5113495bSYour Name A_STATUS
ol_rx_decap(struct ol_txrx_vdev_t * vdev,struct ol_txrx_peer_t * peer,qdf_nbuf_t msdu,struct ol_rx_decap_info_t * info)520*5113495bSYour Name ol_rx_decap(struct ol_txrx_vdev_t *vdev,
521*5113495bSYour Name 	    struct ol_txrx_peer_t *peer,
522*5113495bSYour Name 	    qdf_nbuf_t msdu, struct ol_rx_decap_info_t *info)
523*5113495bSYour Name {
524*5113495bSYour Name 	A_STATUS status;
525*5113495bSYour Name 	uint8_t *mpdu_hdr;
526*5113495bSYour Name 
527*5113495bSYour Name 	if (!info->is_subfrm) {
528*5113495bSYour Name 		if (info->is_msdu_cmpl_mpdu && !info->is_first_subfrm) {
529*5113495bSYour Name 			/* It's normal MSDU. */
530*5113495bSYour Name 		} else {
531*5113495bSYour Name 			/*
532*5113495bSYour Name 			 * It's a first subfrm of A-MSDU and
533*5113495bSYour Name 			 * may also be the last subfrm of A-MSDU
534*5113495bSYour Name 			 */
535*5113495bSYour Name 			info->is_subfrm = 1;
536*5113495bSYour Name 			info->hdr_len = 0;
537*5113495bSYour Name 			if (vdev->pdev->sw_subfrm_hdr_recovery_enable) {
538*5113495bSYour Name 				/* we save the first subfrm mpdu hdr for
539*5113495bSYour Name 				 * subsequent subfrm 802.11 header recovery
540*5113495bSYour Name 				 * in certain chip(such as Riva).
541*5113495bSYour Name 				 */
542*5113495bSYour Name 				mpdu_hdr = qdf_nbuf_data(msdu);
543*5113495bSYour Name 				info->hdr_len =
544*5113495bSYour Name 					ol_txrx_ieee80211_hdrsize(mpdu_hdr);
545*5113495bSYour Name 				TXRX_ASSERT2(info->hdr_len <=
546*5113495bSYour Name 					     sizeof(info->hdr));
547*5113495bSYour Name 				qdf_mem_copy(info->hdr, mpdu_hdr,
548*5113495bSYour Name 					     info->hdr_len);
549*5113495bSYour Name 				qdf_nbuf_pull_head(msdu, info->hdr_len);
550*5113495bSYour Name 			}
551*5113495bSYour Name 		}
552*5113495bSYour Name 	}
553*5113495bSYour Name 
554*5113495bSYour Name 	if (info->is_subfrm && vdev->pdev->sw_subfrm_hdr_recovery_enable) {
555*5113495bSYour Name 		/*
556*5113495bSYour Name 		 * This case is enabled for some HWs (such as Riva). The HW
557*5113495bSYour Name 		 * de-aggregate doesn't have capability to generate 802.11
558*5113495bSYour Name 		 * header for non-first subframe of A-MSDU. That means sw needs
559*5113495bSYour Name 		 * to cache the first subfrm mpdu header to generate the
560*5113495bSYour Name 		 * subsequent subfrm's 802.11 header.
561*5113495bSYour Name 		 */
562*5113495bSYour Name 		TXRX_ASSERT2(info->hdr_len != 0);
563*5113495bSYour Name 		status = ol_rx_decap_subfrm_amsdu(vdev, msdu, info);
564*5113495bSYour Name 	} else {
565*5113495bSYour Name 		status = ol_rx_decap_msdu(vdev, msdu, info);
566*5113495bSYour Name 	}
567*5113495bSYour Name 
568*5113495bSYour Name 	if (info->is_msdu_cmpl_mpdu)
569*5113495bSYour Name 		info->is_subfrm = info->is_first_subfrm = info->hdr_len = 0;
570*5113495bSYour Name 
571*5113495bSYour Name 	return status;
572*5113495bSYour Name }
573*5113495bSYour Name #endif
574