/**
 *  @brief Packet receive completion callback handler
 *
 *  @param pmlan_adapter	A pointer to mlan_adapter structure
 *  @param pmbuf		A pointer to mlan_buffer structure
 *  @param status		Callback status
 *
 *  @return			MLAN_STATUS_SUCCESS
 */
mlan_status
mlan_recv_packet_complete(IN t_void * pmlan_adapter,
                          IN pmlan_buffer pmbuf, IN mlan_status status)
{
    mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter;

    ENTER();
    wlan_recv_packet_complete(pmadapter, pmbuf, status);
    LEAVE();
    return MLAN_STATUS_SUCCESS;
}
/**
 *  @brief Deaggregate the received AMSDU packet
 *
 *  @param priv		A pointer to mlan_private structure
 *  @param pmbuf	A pointer to aggregated data packet
 *
 *  @return		MLAN_STATUS_SUCCESS --success, otherwise fail
 */
mlan_status
wlan_11n_deaggregate_pkt(mlan_private * priv, pmlan_buffer pmbuf)
{
	t_u16 pkt_len;
	int total_pkt_len;
	t_u8 *data;
	t_u32 max_rx_data_size = MLAN_RX_DATA_BUF_SIZE;
	int pad;
	mlan_status ret = MLAN_STATUS_FAILURE;
	RxPacketHdr_t *prx_pkt;
	mlan_buffer *daggr_mbuf = MNULL;
	mlan_adapter *pmadapter = priv->adapter;
	t_u8 rfc1042_eth_hdr[MLAN_MAC_ADDR_LENGTH] = { 0xaa, 0xaa, 0x03,
		0x00, 0x00, 0x00
	};
	t_u8 hdr_len = sizeof(Eth803Hdr_t);

	ENTER();

	data = (t_u8 *) (pmbuf->pbuf + pmbuf->data_offset);
	total_pkt_len = pmbuf->data_len;

	/* Sanity test */
	if (total_pkt_len > max_rx_data_size) {
		PRINTM(MERROR, "Total packet length greater than tx buffer"
		       " size %d\n", total_pkt_len);
		goto done;
	}

	pmbuf->use_count = wlan_11n_get_num_aggrpkts(data, total_pkt_len);

	while (total_pkt_len >= hdr_len) {
		prx_pkt = (RxPacketHdr_t *) data;
		/* Length will be in network format, change it to host */
		pkt_len = mlan_ntohs((*(t_u16 *) (data + (2 *
							  MLAN_MAC_ADDR_LENGTH))));
		if (pkt_len > total_pkt_len) {
			PRINTM(MERROR,
			       "Error in packet length: total_pkt_len = %d, pkt_len = %d\n",
			       total_pkt_len, pkt_len);
			break;
		}

		pad = (((pkt_len + sizeof(Eth803Hdr_t)) & 3)) ?
			(4 - ((pkt_len + sizeof(Eth803Hdr_t)) & 3)) : 0;

		total_pkt_len -= pkt_len + pad + sizeof(Eth803Hdr_t);

		if (memcmp(pmadapter, &prx_pkt->rfc1042_hdr,
			   rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) {
			memmove(pmadapter, data + LLC_SNAP_LEN, data, (2 *
								       MLAN_MAC_ADDR_LENGTH));
			data += LLC_SNAP_LEN;
			pkt_len += sizeof(Eth803Hdr_t) - LLC_SNAP_LEN;
		} else {
			*(t_u16 *) (data + (2 * MLAN_MAC_ADDR_LENGTH))
				= (t_u16) 0;
			pkt_len += sizeof(Eth803Hdr_t);
		}
		daggr_mbuf =
			wlan_alloc_mlan_buffer(pmadapter, pkt_len, 0,
					       MOAL_ALLOC_MLAN_BUFFER);
		if (daggr_mbuf == MNULL) {
			PRINTM(MERROR, "Error allocating daggr mlan_buffer\n");
			LEAVE();
			return MLAN_STATUS_FAILURE;
		}
		daggr_mbuf->bss_index = pmbuf->bss_index;
		daggr_mbuf->buf_type = pmbuf->buf_type;
		daggr_mbuf->data_len = pkt_len;
		daggr_mbuf->in_ts_sec = pmbuf->in_ts_sec;
		daggr_mbuf->in_ts_usec = pmbuf->in_ts_usec;
		daggr_mbuf->pparent = pmbuf;
		daggr_mbuf->priority = pmbuf->priority;
		memcpy(pmadapter, daggr_mbuf->pbuf + daggr_mbuf->data_offset,
		       data, pkt_len);

#ifdef UAP_SUPPORT
		if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
			ret = wlan_uap_recv_packet(priv, daggr_mbuf);
		} else {
#endif /* UAP_SUPPORT */
			ret = pmadapter->callbacks.moal_recv_packet(pmadapter->
								    pmoal_handle,
								    daggr_mbuf);
#ifdef UAP_SUPPORT
		}
#endif /* UAP_SUPPORT */
		switch (ret) {
		case MLAN_STATUS_PENDING:
			break;
		case MLAN_STATUS_FAILURE:
			PRINTM(MERROR, "Deaggr, send to moal failed\n");
			daggr_mbuf->status_code = MLAN_ERROR_PKT_INVALID;
		case MLAN_STATUS_SUCCESS:
			wlan_recv_packet_complete(pmadapter, daggr_mbuf, ret);
			break;
		default:
			break;
		}

		data += pkt_len + pad;
	}

done:
	LEAVE();
	return ret;
}