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